From afb6d5185d486e5e9ddea98ce04ed8c816c44e1e Mon Sep 17 00:00:00 2001 From: Katon Minhas Date: Mon, 26 Jan 2026 16:52:55 +0000 Subject: [PATCH] Merged in feature/lesser-table-caching-refactor-hybrid (pull request #847) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Feature/lesser table caching refactor hybrid * chore: Remove unused duplicate main.py from shared pipeline * fix: Correct crosswalk paths in aarete_derived.py * chore: Remove unused documentation files from fieldExtraction * docs: Add documentation files to documentation folder * docs: Update README with uv setup, expanded project structure, and branching conventions * docs: Add uv installation steps with Ubuntu/WSL emphasis * Enable prompt caching for all remaining LLM calls - Add _INSTRUCTION() functions for: EXHIBIT_HEADER, EXHIBIT_LINKAGE, EXHIBIT_TITLE_MATCH, DATE_FIX, DERIVED_TERM_DATE, CHECK_PROVIDER_NAME_MATCH, SPECIAL_CASE_ASSIGNMENT - Update all invoke_claude() calls in saas and clover pipelines to use cache=True with corresponding _INSTRUCTION() functions - Add new instructions to get_cacheable_instructions() for cache warming - Update tests for new instruction functions Functions now using caching: - prompt_exhibit_level - prompt_exhibit_lesser (EXHIBIT_LEVEL_LESSER_OF) - prompt_fee_schedule_breakout - prompt_grouper_breakout - prompt_special_case_assignment - prompt_exhibit_linkage - prompt_exhibit_header - prompt_smart_chunked (ONE_TO_ONE templates) - prompt_date_fix - prompt_derived_term_date - prompt_exhibit_title_match - provider_name_match_check 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Reorder * feat: Add bcbs_promise client pipeline with OFFSET_TERM extraction - Add new bcbs_promise client with HSC-based OFFSET_TERM field extraction - Extract full paragraph text of offset/recoupment provisions from contracts - Derive OFFSET_INDICATOR (Y/N) from OFFSET_TERM presence - Fix reorder_columns to preserve extra columns not in COLUMN_ORDER - Update QC/QA output path to outputs/qc_qa/ * fix: Update dev deps and test assertions for QC/QA output path - Add pytest/pytest-mock to dev dependencies for mypy type checking - Update test assertions to expect outputs/qc_qa instead of qa_qc_output * style: Apply black formatting to prompt_templates.py * Merge main, move scripts * Archive some scripts * update py version * remove .py version file * Remove ASCII characters * Restore testbed code * restore tracking * Update testbed metrics * Enable prompt caching for CODE_LAST_CHECK, FILL_BILL_TYPE, DUAL_LOB_CHECK, and GROUPER_BREAKOUT - Add CODE_LAST_CHECK_INSTRUCTION() for service specificity classification - Add FILL_BILL_TYPE_INSTRUCTION() for bill type code determination - Add DUAL_LOB_CHECK_INSTRUCTION() for Medicare/Medicaid classification - Update code_funcs.py to use caching for CODE_LAST_CHECK, FILL_BILL_TYPE, GROUPER_BREAKOUT - Update postprocessing_funcs.py to use caching for DUAL_LOB_CHECK - Add new instructions to get_cacheable_instructions() for cache warming - Add unit tests for new instruction functions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * Fix postprocessing_funcs to remove invalid columns * Merge branch 'main' into feature/lesser-table-caching-refactor-hybrid * Revert prompt caching changes from aed1b73c * update formatting * Update imports Approved-by: Sha Brown Approved-by: Praneel Panchigar --- .dockerignore | 38 +- .gitignore | 144 +- .../Doczy.AI_Automation}/.dockerignore | 0 .../Doczy.AI_Automation}/.python-version | 0 .../Doczy.AI_Automation}/README.md | 0 .../Doczy.AI_Automation}/config/aws_conn.py | 0 .../Doczy.AI_Automation}/config/env.yaml | 0 .../Doczy.AI_Automation}/data/data.xlsx | Bin .../Doczy.AI_Automation}/elements/__init__.py | 0 .../elements/interface_0_elements.py | 0 .../elements/interface_1_elements.py | 0 .../elements/interface_2_elements.py | 0 .../pages/Email_sign_in_page.py | 0 .../pages/Password_sign_in_page.py | 0 .../pages/Pre_sign_in_page.py | 0 .../pages/Remember_sign_in_page.py | 0 .../Doczy.AI_Automation}/pages/__init__.py | 0 .../pages/interface_0_page_objects.py | 0 .../pages/interface_1_page_objects.py | 0 .../pages/interface_2_page_objects.py | 0 .../Doczy.AI_Automation}/poetry.lock | 0 .../Doczy.AI_Automation}/pyproject.toml | 0 .../Doczy.AI_Automation}/pytest.ini | 0 .../reports/assets/style.css | 0 .../reports/test_report.html | 0 .../reports/test_report.json | 0 .../tests copy/example_test.py | 0 .../Doczy.AI_Automation}/tests/__init__.py | 0 .../Doczy.AI_Automation}/tests/conftest.py | 0 .../tests/reports/assets/style.css | 0 .../tests/reports/test_report.html | 0 .../tests/reports/test_report.json | 0 .../tests/reports/test_report_05_55.json | 0 .../tests/test_end_to_end.py | 0 .../tests/test_interface_0.py | 0 .../tests/test_interface_1.py | 0 .../tests/test_interface_2.py | 0 .../utils/CustomException.py | 0 .../Doczy.AI_Automation}/utils/__init__.py | 0 .../utils/common_methods.py | 0 .../utils/element_related_methods.py | 0 .../Doczy.AI_Automation}/utils/logger.py | 0 .../Doczy.AI_Automation}/utils/reader.py | 0 .../Doczy.AI_Automation}/utils/report.py | 0 {airflow => archive/airflow}/.dockerignore | 0 .../airflow/.python-version | 0 {airflow => archive/airflow}/README.md | 0 {airflow => archive/airflow}/dags/Qa_Dag.py | 0 .../airflow}/dags/cicd_test_dag.py | 0 .../airflow}/dags/client_name_dag.py | 0 .../airflow}/dags/config_interface_dag.py | 0 .../dags/pipeline_processed_outputs_dag.py | 0 .../airflow}/dags/raw_training_data_dag.py | 0 .../airflow}/dags/training_results_dag.py | 0 .../airflow}/dags/uat_Qa_Dag.py | 0 .../dags/uat_config_interface_dag .py | 0 .../dags/uat_raw_training_data_dag.py | 0 {airflow => archive/airflow}/poetry.lock | 0 {airflow => archive/airflow}/pyproject.toml | 0 .../airflow}/tests/example_test.py | 0 .../other-resources/locals.tf | 0 .../devops-pipeline}/other-resources/main.tf | 0 .../other-resources/outputs.tf | 0 .../other-resources/variables.tf | 0 .../other-resources/vars-dev.tfvars | 0 .../other-resources/vars-prod.tfvars | 0 .../other-resources/vars-uat.tfvars | 0 .../terraform-backend-resources/main.tf | 0 .../aws-terraform-remote-backend/locals.tf | 0 .../aws-terraform-remote-backend/main.tf | 0 .../aws-terraform-remote-backend/outputs.tf | 0 .../aws-terraform-remote-backend/variables.tf | 0 .../terraform-backend-resources/outputs.tf | 0 .../terraform-backend-resources/variables.tf | 0 .../vars-dev.tfvars | 0 .../vars-prod.tfvars | 0 .../vars-uat.tfvars | 0 .../git_diff_changes.py | 0 .../CNC/de_duplication_script.ipynb | 0 .../CNC/diff_checker_universal.py | 0 .../ops_scripts}/CNC/local_pdf_files_info.py | 0 .../CNC/local_search_files_from_csv.py | 0 .../ops_scripts}/CNC/misc_scripts.ipynb | 0 .../CNC/s3_move_files_with_extension.py | 0 .../CNC/s3_search_and_copy_bucket.ipynb | 0 .../CNC/s3_search_and_copy_bucket.py | 0 .../CNC/s3_search_and_copy_prefix.py | 0 .../ops_scripts}/CNC/s3_txt_files_info.py | 0 .../Centene Texas/list_files_in_s3_prefix.py | 0 .../normalize_filenames_and_copy_to_s3.py | 0 .../cost_analysis/aws_cost_automation.py | 0 .../generic/archiving_s3_cli.ipynb | 0 .../generic/complex_tables_files_movement.py | 0 .../ops_scripts}/generic/excel_s3_diff.py | 0 .../new_textract_file_reconciliation.py | 0 .../generic/s3_prefix_search_and_copy.py | 0 .../ops_scripts}/generic/scheduler.py | 0 .../ops_scripts}/generic/t_drive_search.py | 0 .../generic/textract_file_reconciliation.py | 0 .../scripts/adhoc/cnc_adhoc_stitching_1.py | 0 .../scripts/adhoc/cnc_adhoc_stitching_2.py | 0 .../scripts/adhoc/cnc_adhoc_stitching_3.py | 0 .../scripts/adhoc/cnc_prov2_effdate.py | 0 .../scripts/adhoc/combine_ac2_and_b.py | 0 .../scripts/adhoc/consolidate_ac2.py | 0 .../scripts/adhoc/tx_ac_no_reimbursement.py | 0 .../scripts/adhoc/unit_test.py | 0 .../scripts/cnc_hotfixes/apply_cnc_hotfix.py | 0 .../scripts/cnc_hotfixes/cnc_hotfix.py | 4 +- .../cnc_hotfix_effective_date_utils.py | 4 +- .../cnc_hotfixes/hotfix_helper_funcs.py | 0 .../scripts/cnc_hotfixes/hotfix_stitch.py | 0 .../scripts/cnc_hotfixes/hotfix_stitch_1A.py | 0 .../scripts/cnc_hotfixes/hotfix_stitch_1B.py | 0 .../snowflake}/DEV/R__001_LOG_AUDIT.sql | 0 .../snowflake}/DEV/R__002_LOG_AUDIT_TABLE.sql | 0 .../R__001_PROMPT_CONFIG_TABLE.sql | 0 .../R__002_CONTRACT_CONFIG_TABLE.sql | 0 .../R__003_REQUEST_SUBMISSION_TABLE.sql | 0 .../R__004_LOAD_CONTRACT_CONFIG_SP.sql | 0 .../R__005_LOAD_REQUEST_SUBMISSION_SP.sql | 0 .../R__006_PIPELINE_OUTPUT.sql | 0 ...__007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql | 0 .../R__008_PIPELINE_PROCESSED_OUTPUT.sql | 0 ...009_LOAD_PIPELINE_PROCESSED_OUTPUTS_SP.sql | 0 .../R__001_SERVERLESS_LOGS_TABLE.sql | 0 .../training_interface/R__001_INIT_OBJS.sql | 0 .../R__002_LOAD_TRAINING_RESULTS_SP.SQL | 0 .../R__003_LOAD_ATTEMPTS_SP.sql | 0 .../R__004_CREATE_TRAINING_DATA_TABLE_SP.sql | 0 .../R__005_LOAD_COLUMN_CONFIG_SP.sql | 0 .../R__006_LOAD_TRAINING_DATA_RAW_SP.sql | 0 .../R__007_CREATE_BUSINESS_CONFIG_objects.sql | 0 .../R__008_LOAD_BUSINESS_CONFIG_SP.sql | 0 .../R__001_CLIENT_CONFIG_TABLE.sql | 0 .../R__002_LOAD_CLIENT_CONFIG_SP.sql | 0 .../R__003_CONTRACT_UPLOAD_LOGS.sql | 0 .../snowflake}/PROD/R__2001_LOG_AUDIT.sql | 0 .../PROD/R__2002_LOG_AUDIT_TABLE.sql | 0 .../R__2001_UAT_PROMPT_CONFIG_TABLE.sql | 0 .../R__2002_UAT_CONTRACT_CONFIG_TABLE.sql | 0 .../R__2003_REQUEST_SUBMISSION_TABLE.sql | 0 .../R__2004_LOAD_CONTRACT_CONFIG_SP.sql | 0 .../R__2005_LOAD_REQUEST_SUBMISSION_SP.sql | 0 .../R__2006_PIPELINE_OUTPUT.sql | 0 ..._2007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql | 0 .../R__2008_PIPELINE_OUTPUT_B_FIELDS.sql | 0 ...2009_LOAD_B_FIELDS_PIPELINE_RAW_OUTPUT.sql | 0 .../R__2001_SERVERLESS_LOGS_TABLE.sql | 0 .../training_interface/R__2001_INIT_OBJS.sql | 0 .../R__2002_LOAD_TRAINING_RESULTS_SP.SQL | 0 .../R__2003_LOAD_ATTEMPTS_SP.sql | 0 .../R__2004_CREATE_TRAINING_DATA_TABLE_SP.sql | 0 .../R__2005_LOAD_COLUMN_CONFIG_SP.sql | 0 .../R__2006_LOAD_TRAINING_DATA_RAW_SP.sql | 0 ...R__2007_CREATE_BUSINESS_CONFIG_objects.sql | 0 .../R__2008_LOAD_BUSINESS_CONFIG_SP.sql | 0 .../R__2001_CLIENT_CONFIG_TABLE.sql | 0 .../R__2002_LOAD_CLIENT_CONFIG_SP.sql | 0 .../R__2003_CONTRACT_UPLOAD_LOGS.sql | 0 .../snowflake}/UAT/R__1001_LOG_AUDIT.sql | 0 .../UAT/R__1002_LOG_AUDIT_TABLE.sql | 0 .../R__1001_UAT_PROMPT_CONFIG_TABLE.sql | 0 .../R__1002_UAT_CONTRACT_CONFIG_TABLE.sql | 0 .../R__1003_REQUEST_SUBMISSION_TABLE.sql | 0 .../R__1004_LOAD_CONTRACT_CONFIG_SP.sql | 0 .../R__1005_LOAD_REQUEST_SUBMISSION_SP.sql | 0 .../R__1006_PIPELINE_OUTPUT.sql | 0 ..._1007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql | 0 .../R__1008_PIPELINE_OUTPUT_B_FIELDS.sql | 0 ...1009_LOAD_B_FIELDS_PIPELINE_RAW_OUTPUT.sql | 0 .../R__1001_SERVERLESS_LOGS_TABLE.sql | 0 .../training_interface/R__1001_INIT_OBJS.sql | 0 .../R__1002_LOAD_TRAINING_RESULTS_SP.SQL | 0 .../R__1003_LOAD_ATTEMPTS_SP.sql | 0 .../R__1004_CREATE_TRAINING_DATA_TABLE_SP.sql | 0 .../R__1005_LOAD_COLUMN_CONFIG_SP.sql | 0 .../R__1006_LOAD_TRAINING_DATA_RAW_SP.sql | 0 ...R__1007_CREATE_BUSINESS_CONFIG_objects.sql | 0 .../R__1008_LOAD_BUSINESS_CONFIG_SP.sql | 0 .../R__1001_CLIENT_CONFIG_TABLE.sql | 0 .../R__1002_LOAD_CLIENT_CONFIG_SP.sql | 0 .../R__1003_CONTRACT_UPLOAD_LOGS.sql | 0 .../streamlit-server}/alb.tf | 0 .../streamlit-server}/alb_sg.tf | 0 .../streamlit-server}/iam.tf | 0 .../streamlit-server}/main.tf | 0 .../streamlit-server}/requirements.txt | 0 .../streamlit-server}/user_data.sh | 0 .../streamlit-server}/variables.tf | 0 .../streamlit-server}/vars-dev.tfvars | 0 .../streamlit-server}/vars-prod.tfvars | 0 .../streamlit-server}/vars-uat.tfvars | 0 .../streamlit}/.dockerignore | 0 .../streamlit}/.python-version | 0 {streamlit => archive/streamlit}/README.md | 0 .../streamlit}/__init__.py | 0 .../streamlit}/aaretelogo.png | Bin {streamlit => archive/streamlit}/constants.py | 0 .../streamlit}/contract_field_values.csv | 0 .../streamlit}/contract_fields.csv | 0 {streamlit => archive/streamlit}/ingest.py | 0 .../streamlit}/interface_0.py | 0 .../streamlit}/interface_1.py | 0 .../streamlit}/interface_2.py | 0 .../streamlit}/interface_2_rag.py | 0 .../streamlit}/interface_3.py | 0 .../streamlit}/interface_3_rag.py | 0 .../streamlit}/local/local_interface_0.py | 0 .../streamlit}/local/local_interface_1.py | 0 .../streamlit}/local/local_interface_2.py | 0 .../streamlit}/multipage/Interface_0.py | 0 .../streamlit}/multipage/aaretelogo.png | Bin .../streamlit}/multipage/constants.py | 0 .../streamlit}/multipage/contract_fields.csv | 0 .../multipage/pages/1_Interface_1.py | 0 .../multipage/pages/2_Interface_2.py | 0 .../multipage/pages/3_Data_Dictionary.py | 0 .../streamlit}/multipage/security.py | 0 .../streamlit}/multipage/sf_conn.py | 0 .../streamlit}/multipage/util.py | 0 {streamlit => archive/streamlit}/poetry.lock | 0 .../streamlit}/pyproject.toml | 0 .../streamlit}/runs-dashboard.py | 0 {streamlit => archive/streamlit}/security.py | 0 {streamlit => archive/streamlit}/sf_conn.py | 0 .../streamlit}/tests/example_test.py | 0 {streamlit => archive/streamlit}/util.py | 0 .../streamlit_multipage}/.dockerignore | 0 .../streamlit_multipage}/.python-version | 0 .../streamlit_multipage}/Demo_Test_data.csv | 0 .../streamlit_multipage}/Demo_Test_data.xlsx | Bin .../streamlit_multipage}/Interface_1.py | 0 .../streamlit_multipage}/README.md | 0 .../streamlit_multipage}/aaretelogo.png | Bin .../streamlit_multipage}/constants.py | 0 .../streamlit_multipage}/contract_fields.csv | 0 .../pages/1_Interface_2.py | 0 .../streamlit_multipage}/poetry.lock | 0 .../streamlit_multipage}/pyproject.toml | 0 ...poration-ICMProviderAgreement_318243_1.Pdf | Bin ...poration-ICMProviderAgreement_318243_1.csv | 0 ...rporation-ICMProviderAgreement_92767_3.Pdf | Bin ...rporation-ICMProviderAgreement_92767_3.csv | 0 ...ices Inc-ICMProviderAgreement_265803_3.Pdf | Bin ...ices Inc-ICMProviderAgreement_265803_3.csv | 0 .../streamlit_multipage}/temp1.csv | 0 .../streamlit_multipage}/temp2.csv | 0 .../tests/example_test.py | 0 terminal.py => archive/terminal.py | 0 terraform.py => archive/terraform.py | 0 .../anthropic-snowflake/anthropic-sf-310.zip | Bin .../brotli-layer/brotlipy-layer.zip | Bin .../src/lambda-layer/libre-office/lo.tar.br | Bin .../src/lambda-layer/pandas-np-310/pd_np.zip | Bin .../lambda-layer/pydantic-218/pydantic.zip | Bin .../pypdf2-layer-new/requirements.txt | 0 .../src/lambda-layer/pypdf2-layer/PyPDF2.zip | Bin .../snowflake-connector-39-verified.zip | Bin .../src/lambda/batch-creation/.dockerignore | 0 .../lambda/batch-creation}/.python-version | 0 .../src/lambda/batch-creation/README.md | 0 .../src/lambda/batch-creation/index.py | 0 .../src/lambda/batch-creation/poetry.lock | 0 .../src/lambda/batch-creation/pyproject.toml | 0 .../batch-creation/tests/example_test.py | 0 .../src/lambda/call-bedrock/.dockerignore | 0 .../src/lambda/call-bedrock}/.python-version | 0 .../src/lambda/call-bedrock/README.md | 0 .../src/lambda/call-bedrock/index.py | 0 .../src/lambda/call-bedrock/poetry.lock | 0 .../src/lambda/call-bedrock/pyproject.toml | 0 .../lambda/call-bedrock/tests/example_test.py | 0 .../database-interface-get/.dockerignore | 0 .../database-interface-get/.python-version | 0 .../lambda/database-interface-get/README.md | 0 .../lambda/database-interface-get/index.py | 0 .../lambda/database-interface-get/poetry.lock | 0 .../database-interface-get/pyproject.toml | 0 .../tests/example_test.py | 0 .../lambda/database-interface/.dockerignore | 0 .../lambda/database-interface/.python-version | 0 .../src/lambda/database-interface/README.md | 0 .../src/lambda/database-interface/index.py | 0 .../src/lambda/database-interface/poetry.lock | 0 .../lambda/database-interface/pyproject.toml | 0 .../database-interface/tests/example_test.py | 0 .../src/lambda/docx-to-pdf/.dockerignore | 0 .../src/lambda/docx-to-pdf}/.python-version | 0 .../src/lambda/docx-to-pdf/README.md | 0 .../src/lambda/docx-to-pdf/index.py | 0 .../src/lambda/docx-to-pdf/poetry.lock | 0 .../src/lambda/docx-to-pdf/pyproject.toml | 0 .../lambda/docx-to-pdf/tests/example_test.py | 0 .../src/lambda/insert-record/.dockerignore | 0 .../src/lambda/insert-record}/.python-version | 0 .../src/lambda/insert-record/README.md | 0 .../src/lambda/insert-record/index.py | 0 .../src/lambda/insert-record/poetry.lock | 0 .../src/lambda/insert-record/pyproject.toml | 0 .../insert-record/tests/example_test.py | 0 .../src/lambda/pdf-validation/.dockerignore | 0 .../lambda/pdf-validation}/.python-version | 0 .../src/lambda/pdf-validation/README.md | 0 .../src/lambda/pdf-validation/index.py | 0 .../src/lambda/pdf-validation/poetry.lock | 0 .../src/lambda/pdf-validation/pyproject.toml | 0 .../pdf-validation/tests/example_test.py | 0 .../src/lambda/prompt-processor/.dockerignore | 0 .../lambda/prompt-processor}/.python-version | 0 .../src/lambda/prompt-processor/README.md | 0 .../src/lambda/prompt-processor/index.py | 0 .../src/lambda/prompt-processor/poetry.lock | 0 .../lambda/prompt-processor/pyproject.toml | 0 .../prompt-processor/tests/example_test.py | 0 .../lambda/s3-folder-details/.dockerignore | 0 .../lambda/s3-folder-details}/.python-version | 0 .../src/lambda/s3-folder-details/README.md | 0 .../src/lambda/s3-folder-details/index.py | 0 .../src/lambda/s3-folder-details/poetry.lock | 0 .../lambda/s3-folder-details/pyproject.toml | 0 .../s3-folder-details/tests/example_test.py | 0 .../src/lambda/text-creation/.dockerignore | 0 .../src/lambda/text-creation}/.python-version | 0 .../src/lambda/text-creation/README.md | 0 .../src/lambda/text-creation/index.py | 0 .../src/lambda/text-creation/poetry.lock | 0 .../src/lambda/text-creation/pyproject.toml | 0 .../text-creation/tests/example_test.py | 0 .../lambda/textract-receiver/.dockerignore | 0 .../lambda/textract-receiver}/.python-version | 0 .../src/lambda/textract-receiver/README.md | 0 .../src/lambda/textract-receiver/index.py | 0 .../src/lambda/textract-receiver/poetry.lock | 0 .../lambda/textract-receiver/pyproject.toml | 0 .../textract-receiver/tests/example_test.py | 0 .../src/lambda/textract-sender/.dockerignore | 0 .../lambda/textract-sender}/.python-version | 0 .../src/lambda/textract-sender/README.md | 0 .../src/lambda/textract-sender/index.py | 0 .../src/lambda/textract-sender/poetry.lock | 0 .../src/lambda/textract-sender/pyproject.toml | 0 .../textract-sender/tests/example_test.py | 0 .../src/lambda/tiff-to-pdf/.dockerignore | 0 .../src/lambda/tiff-to-pdf}/.python-version | 0 .../src/lambda/tiff-to-pdf/README.md | 0 .../src/lambda/tiff-to-pdf/index.py | 0 .../src/lambda/tiff-to-pdf/poetry.lock | 0 .../src/lambda/tiff-to-pdf/pyproject.toml | 0 .../lambda/tiff-to-pdf/tests/example_test.py | 0 .../src/lambda/trigger-pipeline/.dockerignore | 0 .../lambda/trigger-pipeline}/.python-version | 0 .../src/lambda/trigger-pipeline/README.md | 0 .../src/lambda/trigger-pipeline/index.py | 0 .../src/lambda/trigger-pipeline/poetry.lock | 0 .../lambda/trigger-pipeline/pyproject.toml | 0 .../trigger-pipeline/tests/example_test.py | 0 .../src/s3-files/config.properties | 0 .../textract-pipeline}/terraform/main.tf | 0 .../aws-textract-pipeline-part1/main.tf | 0 .../aws-textract-pipeline-part1/outputs.tf | 0 .../aws-textract-pipeline-part1/variables.tf | 0 .../aws-textract-pipeline-part3/main.tf | 0 .../aws-textract-pipeline-part3/outputs.tf | 0 .../aws-textract-pipeline-part3/variables.tf | 0 .../modules/aws-textract-pipeline/main.tf | 0 .../modules/aws-textract-pipeline/outputs.tf | 0 .../aws-textract-pipeline/variables.tf | 0 .../textract-pipeline}/terraform/outputs.tf | 0 .../terraform/snowsql-cicd.sh | 0 .../textract-pipeline}/terraform/variables.tf | 0 .../terraform/vars-dev.tfvars | 0 .../terraform/vars-prod.tfvars | 0 .../terraform/vars-uat.tfvars | 0 bitbucket-pipelines.yml | 952 +- .../EXTRACTION_FLOW_VISUAL.md | 0 .../FIELD_EXTRACTION_GUIDE.md | 0 .../PERFORMANCE_ANALYSIS_GUIDE.md | 0 fieldExtraction/.gitignore | 95 - fieldExtraction/README.md | 50 - fieldExtraction/nltk_data/README.md | 26 - .../nltk_data/tokenizers/punkt_tab/README | 98 - .../punkt_tab/english/abbrev_types.txt | 156 - .../punkt_tab/english/collocations.tab | 37 - .../punkt_tab/english/ortho_context.tab | 20366 ---------------- .../punkt_tab/english/sent_starters.txt | 39 - fieldExtraction/poetry.lock | 6532 ----- fieldExtraction/pyproject.toml | 62 - fieldExtraction/release/Dockerfile | 30 - .../src/investment/exhibit_funcs.py | 143 - .../src/investment/preprocessing_funcs.py | 319 - fieldExtraction/tests/test_exhibit_funcs.py | 29 - fieldExtraction/tests/test_one_to_n.py | 698 - poetry.lock | 1421 -- pyproject.toml | 74 +- readme.md | 134 +- src/__init__.py | 2 + .../src => src}/codes/code_funcs.py | 97 +- {fieldExtraction/src => src}/codes/main.py | 15 +- {fieldExtraction/src => src}/config.py | 51 +- .../src => src/constants}/__init__.py | 0 .../constants/constants.py | 91 +- .../constants/delimiters.py | 0 src/constants/embedding.py | 26 + .../constants/investment_columns.py | 0 .../constants/lists/compound_indicators.json | 0 .../constants/lists/do_not_run.json | 0 .../lists/exhibit_header_markers.json | 0 .../constants/lists/stop_words.json | 0 .../constants/lists/valid_fee_schedule.json | 0 .../lists/valid_fee_schedule_version.json | 0 .../constants/lists/valid_prov_type.json | 0 .../lists/valid_reimb_methodology.json | 0 .../lists/valid_unit_of_measure.json | 0 .../admit_type_cd/admit_mapping.csv | 0 .../constants/mapping_csvs/diag_cd/diag.csv | 0 .../grouper_cd/drg_mapping_apr-drg.csv | 0 .../grouper_cd/drg_mapping_ms-drg.csv | 0 .../constants/mapping_csvs/proc_cd/cpt.csv | 0 .../mapping_csvs/proc_cd/cpt_level1.csv | 0 .../mapping_csvs/proc_cd/cpt_level2.csv | 0 .../mapping_csvs/proc_cd/cpt_level3.csv | 0 .../constants/mapping_csvs/proc_cd/hcpcs.csv | 0 .../mapping_csvs/proc_cd/hcpcs_level1.csv | 0 .../mapping_csvs/proc_cd/hcpcs_level2.csv | 0 .../constants/mapping_csvs/rev_cd/rev.csv | 0 .../mapping_csvs/rev_cd/rev_level1.csv | 0 .../taxonomy_cd/taxonomy_mapping.csv | 0 .../mappings/crosswalk_bill_type.json | 0 .../mappings/crosswalk_claim_type.json | 0 .../constants/mappings/crosswalk_lob.json | 0 .../constants/mappings/crosswalk_network.json | 0 .../mappings/crosswalk_place_of_service.json | 0 .../mappings/crosswalk_product_lob.json | 0 .../constants/mappings/crosswalk_program.json | 0 .../mappings/crosswalk_program_lob.json | 0 .../crosswalk_provider_specialty.json | 0 .../mappings/exclude_keywords_for_pc.json | 0 .../constants/mappings/numeric_mappigs.json | 0 .../mappings/stop_words_for_pc_cleanup.json | 0 .../constants/mappings/synonym_map.json | 0 .../constants/mappings/valid_carveouts.json | 0 .../constants/regex_patterns.py | 0 src/core/__init__.py | 21 + src/core/base_pipeline.py | 271 + .../constants => src/core}/embedding.py | 11 +- .../src/prompts => src/core}/fieldset.py | 12 +- src/core/registry.py | 170 + .../src => src}/crosswalk/README.md | 0 .../crosswalk/crosswalk_builder.py | 0 .../src => src}/crosswalk/list_builder.py | 0 .../document_classification/main.py | 4 +- .../embeddings/cpt_level1/choices.pkl | Bin .../embeddings/cpt_level1/embeddings.npy | Bin .../embeddings/cpt_level1/faiss_index.bin | Bin .../embeddings/cpt_level2/choices.pkl | Bin .../embeddings/cpt_level2/embeddings.npy | Bin .../embeddings/cpt_level2/faiss_index.bin | Bin .../embeddings/cpt_level3/choices.pkl | Bin .../embeddings/cpt_level3/embeddings.npy | Bin .../embeddings/cpt_level3/faiss_index.bin | Bin .../embeddings/hcpcs_level1/choices.pkl | Bin .../embeddings/hcpcs_level1/embeddings.npy | Bin .../embeddings/hcpcs_level1/faiss_index.bin | Bin .../embeddings/hcpcs_level2/choices.pkl | Bin .../embeddings/hcpcs_level2/embeddings.npy | Bin .../embeddings/hcpcs_level2/faiss_index.bin | Bin .../embeddings/rev/choices.pkl | Bin .../embeddings/rev/embeddings.npy | Bin .../embeddings/rev/faiss_index.bin | Bin .../embeddings/rev_level1/choices.pkl | Bin .../embeddings/rev_level1/embeddings.npy | Bin .../embeddings/rev_level1/faiss_index.bin | Bin .../parent_child}/__init__.py | 0 .../src => src}/parent_child/main.py | 0 .../parent_child/parent_child_mapping.py | 0 .../parent_child_preprocessing.py | 3 +- .../src => src/pipelines}/.gitignore | 0 src/pipelines/__init__.py | 2 + src/pipelines/clients/__init__.py | 1 + .../clients/bcbs_promise}/__init__.py | 0 .../clients/bcbs_promise/file_processing.py | 537 + .../pipelines/clients/bcbs_promise}/main.py | 67 +- .../clients/bcbs_promise/prompts/__init__.py | 1 + .../bcbs_promise/prompts}/prompt_calls.py | 405 +- .../pipelines/clients/clover}/__init__.py | 0 .../clients/clover/file_processing.py | 539 + .../clients/clover/prompts/__init__.py | 1 + .../clients/clover/prompts/prompt_calls.py | 1153 + src/pipelines/runner.py | 269 + .../utils => src/pipelines/saas}/__init__.py | 0 .../pipelines/saas}/file_processing.py | 305 +- src/pipelines/saas/main.py | 298 + src/pipelines/saas/prompts/__init__.py | 1 + src/pipelines/saas/prompts/prompt_calls.py | 1134 + src/pipelines/shared/__init__.py | 20 + src/pipelines/shared/extraction/__init__.py | 1 + .../shared/extraction}/dynamic_funcs.py | 93 +- .../shared/extraction/exhibit_funcs.py | 455 + .../shared/extraction}/one_to_n_funcs.py | 309 +- .../shared/extraction}/one_to_one_funcs.py | 96 +- src/pipelines/shared/extraction/page_funcs.py | 365 + .../pipelines/shared/extraction}/row_funcs.py | 41 +- .../shared/extraction}/tin_npi_funcs.py | 106 +- .../shared/extraction}/vision_funcs.py | 0 .../shared/postprocessing/__init__.py | 1 + .../shared/postprocessing}/aarete_derived.py | 76 +- .../shared/postprocessing}/postprocess.py | 16 +- .../postprocessing}/postprocessing_funcs.py | 137 +- .../shared/preprocessing/__init__.py | 1 + .../hybrid_smart_chunking_funcs.py | 76 +- .../hybrid_smart_chunking_preprocessing.py | 2 +- .../shared/preprocessing}/preprocess.py | 96 +- .../preprocessing/preprocessing_funcs.py | 579 + src/prompts/bcbs_promise_prompts.json | 31 + src/prompts/clover_prompts.json | 74 + .../document_classification_prompts.json | 0 src/prompts/fieldset.py | 380 + .../prompts/investment_prompts.json | 0 .../src => src}/prompts/prompt_templates.py | 723 +- .../src => src}/qc_qa/__init__.py | 0 .../src => src}/qc_qa/__main__.py | 6 +- .../src => src}/qc_qa/pipeline.py | 19 +- .../scripts/compare_output.py | 0 .../scripts/create_code_embeddings.py | 19 +- .../scripts/detect_complex.py | 0 .../scripts/file_counting.py | 0 .../investment_field_testing/testing.ipynb | 8 +- .../scripts/merge_issue_regex.py | 0 .../scripts/missingness_analysis.py | 140 +- .../scripts/postprocess_existing_output.py | 6 - {fieldExtraction => src}/scripts/prerun.py | 0 {fieldExtraction => src}/scripts/qa_qc.py | 19 +- .../scripts/table_analysis.py | 0 .../scripts/textract_template.py | 2 +- {fieldExtraction => src}/scripts/tin_pull.py | 0 .../testbed/add_reimb_id_to_testbed.py | 8 +- .../src => src}/testbed/model_evaluation.py | 179 +- .../testbed/model_evaluation_utils.py | 138 +- .../testbed/one_to_n_comparison.py | 0 .../testbed/one_to_one_comparison.py | 2 +- .../src => src}/testbed/testbed_metrics.py | 6 +- .../testbed/testbed_postprocess.py | 0 .../src => src}/testbed/testbed_utils.py | 12 +- .../tests/test_calculate_progress_stats.py | 2 +- .../tests/test_code_funcs.py | 8 +- .../tests/test_crosswalk_utils.py | 0 .../tests/test_document_classification.py | 403 +- .../tests/test_dynamic.py | 27 +- src/tests/test_exhibit_funcs.py | 467 + .../tests/test_fieldset.py | 5 +- .../tests/test_hybrid_smart_chunking_funcs.py | 129 +- ...est_hybrid_smart_chunking_preprocessing.py | 86 +- .../tests/test_io_utils.py | 50 +- .../tests/test_llm_utils.py | 197 +- src/tests/test_one_to_n.py | 1068 + src/tests/test_page_funcs.py | 731 + src/tests/test_phase5_integration.py | 280 + .../tests/test_postprocess.py | 223 +- .../tests/test_preprocessing_funcs.py | 110 +- src/tests/test_prompt_caching.py | 274 + .../tests/test_qc_qa_pipeline.py | 321 +- .../tests/test_rag_utils.py | 104 +- .../tests/test_string_utils.py | 155 +- .../tests/test_timing_utils.py | 0 .../tests/test_tin_npi_funcs.py | 58 +- .../tests/test_usage_tracking.py | 163 +- {streamlit => src/tracking}/__init__.py | 0 .../src => src}/tracking/batch_tracking.py | 0 src/utils/__init__.py | 0 .../src => src}/utils/crosswalk_utils.py | 2 +- .../src => src}/utils/embedding_utils.py | 0 .../src => src}/utils/io_utils.py | 29 +- .../src => src}/utils/llm_utils.py | 90 +- .../src => src}/utils/logging_utils.py | 2 +- .../src => src}/utils/qa_qc_utils.py | 23 +- .../src => src}/utils/rag_utils.py | 4 +- .../src => src}/utils/string_utils.py | 76 +- .../src => src}/utils/timing_utils.py | 29 +- .../tracking => src/utils}/tracking_utils.py | 70 +- .../src => src}/utils/usage_tracking.py | 135 +- .../src/lambda/tiff-to-pdf/.python-version | 1 - .../lambda/trigger-pipeline/.python-version | 1 - uv.lock | 4253 ++++ 584 files changed, 17548 insertions(+), 33208 deletions(-) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/.dockerignore (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/.python-version (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/README.md (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/config/aws_conn.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/config/env.yaml (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/data/data.xlsx (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/elements/__init__.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/elements/interface_0_elements.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/elements/interface_1_elements.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/elements/interface_2_elements.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/pages/Email_sign_in_page.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/pages/Password_sign_in_page.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/pages/Pre_sign_in_page.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/pages/Remember_sign_in_page.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/pages/__init__.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/pages/interface_0_page_objects.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/pages/interface_1_page_objects.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/pages/interface_2_page_objects.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/poetry.lock (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/pyproject.toml (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/pytest.ini (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/reports/assets/style.css (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/reports/test_report.html (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/reports/test_report.json (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/tests copy/example_test.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/tests/__init__.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/tests/conftest.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/tests/reports/assets/style.css (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/tests/reports/test_report.html (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/tests/reports/test_report.json (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/tests/reports/test_report_05_55.json (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/tests/test_end_to_end.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/tests/test_interface_0.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/tests/test_interface_1.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/tests/test_interface_2.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/utils/CustomException.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/utils/__init__.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/utils/common_methods.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/utils/element_related_methods.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/utils/logger.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/utils/reader.py (100%) rename {Doczy.AI_Automation => archive/Doczy.AI_Automation}/utils/report.py (100%) rename {airflow => archive/airflow}/.dockerignore (100%) rename .python-version => archive/airflow/.python-version (100%) rename {airflow => archive/airflow}/README.md (100%) rename {airflow => archive/airflow}/dags/Qa_Dag.py (100%) rename {airflow => archive/airflow}/dags/cicd_test_dag.py (100%) rename {airflow => archive/airflow}/dags/client_name_dag.py (100%) rename {airflow => archive/airflow}/dags/config_interface_dag.py (100%) rename {airflow => archive/airflow}/dags/pipeline_processed_outputs_dag.py (100%) rename {airflow => archive/airflow}/dags/raw_training_data_dag.py (100%) rename {airflow => archive/airflow}/dags/training_results_dag.py (100%) rename {airflow => archive/airflow}/dags/uat_Qa_Dag.py (100%) rename {airflow => archive/airflow}/dags/uat_config_interface_dag .py (100%) rename {airflow => archive/airflow}/dags/uat_raw_training_data_dag.py (100%) rename {airflow => archive/airflow}/poetry.lock (100%) rename {airflow => archive/airflow}/pyproject.toml (100%) rename {airflow => archive/airflow}/tests/example_test.py (100%) rename {devops-pipeline => archive/devops-pipeline}/other-resources/locals.tf (100%) rename {devops-pipeline => archive/devops-pipeline}/other-resources/main.tf (100%) rename {devops-pipeline => archive/devops-pipeline}/other-resources/outputs.tf (100%) rename {devops-pipeline => archive/devops-pipeline}/other-resources/variables.tf (100%) rename {devops-pipeline => archive/devops-pipeline}/other-resources/vars-dev.tfvars (100%) rename {devops-pipeline => archive/devops-pipeline}/other-resources/vars-prod.tfvars (100%) rename {devops-pipeline => archive/devops-pipeline}/other-resources/vars-uat.tfvars (100%) rename {devops-pipeline => archive/devops-pipeline}/terraform-backend-resources/main.tf (100%) rename {devops-pipeline => archive/devops-pipeline}/terraform-backend-resources/modules/aws-terraform-remote-backend/locals.tf (100%) rename {devops-pipeline => archive/devops-pipeline}/terraform-backend-resources/modules/aws-terraform-remote-backend/main.tf (100%) rename {devops-pipeline => archive/devops-pipeline}/terraform-backend-resources/modules/aws-terraform-remote-backend/outputs.tf (100%) rename {devops-pipeline => archive/devops-pipeline}/terraform-backend-resources/modules/aws-terraform-remote-backend/variables.tf (100%) rename {devops-pipeline => archive/devops-pipeline}/terraform-backend-resources/outputs.tf (100%) rename {devops-pipeline => archive/devops-pipeline}/terraform-backend-resources/variables.tf (100%) rename {devops-pipeline => archive/devops-pipeline}/terraform-backend-resources/vars-dev.tfvars (100%) rename {devops-pipeline => archive/devops-pipeline}/terraform-backend-resources/vars-prod.tfvars (100%) rename {devops-pipeline => archive/devops-pipeline}/terraform-backend-resources/vars-uat.tfvars (100%) rename git_diff_changes.py => archive/git_diff_changes.py (100%) rename {ops_scripts => archive/ops_scripts}/CNC/de_duplication_script.ipynb (100%) rename {ops_scripts => archive/ops_scripts}/CNC/diff_checker_universal.py (100%) rename {ops_scripts => archive/ops_scripts}/CNC/local_pdf_files_info.py (100%) rename {ops_scripts => archive/ops_scripts}/CNC/local_search_files_from_csv.py (100%) rename {ops_scripts => archive/ops_scripts}/CNC/misc_scripts.ipynb (100%) rename {ops_scripts => archive/ops_scripts}/CNC/s3_move_files_with_extension.py (100%) rename {ops_scripts => archive/ops_scripts}/CNC/s3_search_and_copy_bucket.ipynb (100%) rename {ops_scripts => archive/ops_scripts}/CNC/s3_search_and_copy_bucket.py (100%) rename {ops_scripts => archive/ops_scripts}/CNC/s3_search_and_copy_prefix.py (100%) rename {ops_scripts => archive/ops_scripts}/CNC/s3_txt_files_info.py (100%) rename {ops_scripts => archive/ops_scripts}/Centene Texas/list_files_in_s3_prefix.py (100%) rename {ops_scripts => archive/ops_scripts}/Centene Texas/normalize_filenames_and_copy_to_s3.py (100%) rename {ops_scripts => archive/ops_scripts}/cost_analysis/aws_cost_automation.py (100%) rename {ops_scripts => archive/ops_scripts}/generic/archiving_s3_cli.ipynb (100%) rename {ops_scripts => archive/ops_scripts}/generic/complex_tables_files_movement.py (100%) rename {ops_scripts => archive/ops_scripts}/generic/excel_s3_diff.py (100%) rename {ops_scripts => archive/ops_scripts}/generic/new_textract_file_reconciliation.py (100%) rename {ops_scripts => archive/ops_scripts}/generic/s3_prefix_search_and_copy.py (100%) rename {ops_scripts => archive/ops_scripts}/generic/scheduler.py (100%) rename {ops_scripts => archive/ops_scripts}/generic/t_drive_search.py (100%) rename {ops_scripts => archive/ops_scripts}/generic/textract_file_reconciliation.py (100%) rename {fieldExtraction => archive}/scripts/adhoc/cnc_adhoc_stitching_1.py (100%) rename {fieldExtraction => archive}/scripts/adhoc/cnc_adhoc_stitching_2.py (100%) rename {fieldExtraction => archive}/scripts/adhoc/cnc_adhoc_stitching_3.py (100%) rename {fieldExtraction => archive}/scripts/adhoc/cnc_prov2_effdate.py (100%) rename {fieldExtraction => archive}/scripts/adhoc/combine_ac2_and_b.py (100%) rename {fieldExtraction => archive}/scripts/adhoc/consolidate_ac2.py (100%) rename {fieldExtraction => archive}/scripts/adhoc/tx_ac_no_reimbursement.py (100%) rename {fieldExtraction => archive}/scripts/adhoc/unit_test.py (100%) rename {fieldExtraction => archive}/scripts/cnc_hotfixes/apply_cnc_hotfix.py (100%) rename {fieldExtraction => archive}/scripts/cnc_hotfixes/cnc_hotfix.py (99%) rename {fieldExtraction => archive}/scripts/cnc_hotfixes/cnc_hotfix_effective_date_utils.py (97%) rename {fieldExtraction => archive}/scripts/cnc_hotfixes/hotfix_helper_funcs.py (100%) rename {fieldExtraction => archive}/scripts/cnc_hotfixes/hotfix_stitch.py (100%) rename {fieldExtraction => archive}/scripts/cnc_hotfixes/hotfix_stitch_1A.py (100%) rename {fieldExtraction => archive}/scripts/cnc_hotfixes/hotfix_stitch_1B.py (100%) rename {snowflake => archive/snowflake}/DEV/R__001_LOG_AUDIT.sql (100%) rename {snowflake => archive/snowflake}/DEV/R__002_LOG_AUDIT_TABLE.sql (100%) rename {snowflake => archive/snowflake}/DEV/config_interface/R__001_PROMPT_CONFIG_TABLE.sql (100%) rename {snowflake => archive/snowflake}/DEV/config_interface/R__002_CONTRACT_CONFIG_TABLE.sql (100%) rename {snowflake => archive/snowflake}/DEV/config_interface/R__003_REQUEST_SUBMISSION_TABLE.sql (100%) rename {snowflake => archive/snowflake}/DEV/config_interface/R__004_LOAD_CONTRACT_CONFIG_SP.sql (100%) rename {snowflake => archive/snowflake}/DEV/config_interface/R__005_LOAD_REQUEST_SUBMISSION_SP.sql (100%) rename {snowflake => archive/snowflake}/DEV/config_interface/R__006_PIPELINE_OUTPUT.sql (100%) rename {snowflake => archive/snowflake}/DEV/config_interface/R__007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql (100%) rename {snowflake => archive/snowflake}/DEV/config_interface/R__008_PIPELINE_PROCESSED_OUTPUT.sql (100%) rename {snowflake => archive/snowflake}/DEV/config_interface/R__009_LOAD_PIPELINE_PROCESSED_OUTPUTS_SP.sql (100%) rename {snowflake => archive/snowflake}/DEV/system_wide/R__001_SERVERLESS_LOGS_TABLE.sql (100%) rename {snowflake => archive/snowflake}/DEV/training_interface/R__001_INIT_OBJS.sql (100%) rename {snowflake => archive/snowflake}/DEV/training_interface/R__002_LOAD_TRAINING_RESULTS_SP.SQL (100%) rename {snowflake => archive/snowflake}/DEV/training_interface/R__003_LOAD_ATTEMPTS_SP.sql (100%) rename {snowflake => archive/snowflake}/DEV/training_interface/R__004_CREATE_TRAINING_DATA_TABLE_SP.sql (100%) rename {snowflake => archive/snowflake}/DEV/training_interface/R__005_LOAD_COLUMN_CONFIG_SP.sql (100%) rename {snowflake => archive/snowflake}/DEV/training_interface/R__006_LOAD_TRAINING_DATA_RAW_SP.sql (100%) rename {snowflake => archive/snowflake}/DEV/training_interface/R__007_CREATE_BUSINESS_CONFIG_objects.sql (100%) rename {snowflake => archive/snowflake}/DEV/training_interface/R__008_LOAD_BUSINESS_CONFIG_SP.sql (100%) rename {snowflake => archive/snowflake}/DEV/upload_interface/R__001_CLIENT_CONFIG_TABLE.sql (100%) rename {snowflake => archive/snowflake}/DEV/upload_interface/R__002_LOAD_CLIENT_CONFIG_SP.sql (100%) rename {snowflake => archive/snowflake}/DEV/upload_interface/R__003_CONTRACT_UPLOAD_LOGS.sql (100%) rename {snowflake => archive/snowflake}/PROD/R__2001_LOG_AUDIT.sql (100%) rename {snowflake => archive/snowflake}/PROD/R__2002_LOG_AUDIT_TABLE.sql (100%) rename {snowflake => archive/snowflake}/PROD/config_interface/R__2001_UAT_PROMPT_CONFIG_TABLE.sql (100%) rename {snowflake => archive/snowflake}/PROD/config_interface/R__2002_UAT_CONTRACT_CONFIG_TABLE.sql (100%) rename {snowflake => archive/snowflake}/PROD/config_interface/R__2003_REQUEST_SUBMISSION_TABLE.sql (100%) rename {snowflake => archive/snowflake}/PROD/config_interface/R__2004_LOAD_CONTRACT_CONFIG_SP.sql (100%) rename {snowflake => archive/snowflake}/PROD/config_interface/R__2005_LOAD_REQUEST_SUBMISSION_SP.sql (100%) rename {snowflake => archive/snowflake}/PROD/config_interface/R__2006_PIPELINE_OUTPUT.sql (100%) rename {snowflake => archive/snowflake}/PROD/config_interface/R__2007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql (100%) rename {snowflake => archive/snowflake}/PROD/config_interface/R__2008_PIPELINE_OUTPUT_B_FIELDS.sql (100%) rename {snowflake => archive/snowflake}/PROD/config_interface/R__2009_LOAD_B_FIELDS_PIPELINE_RAW_OUTPUT.sql (100%) rename {snowflake => archive/snowflake}/PROD/system_wide/R__2001_SERVERLESS_LOGS_TABLE.sql (100%) rename {snowflake => archive/snowflake}/PROD/training_interface/R__2001_INIT_OBJS.sql (100%) rename {snowflake => archive/snowflake}/PROD/training_interface/R__2002_LOAD_TRAINING_RESULTS_SP.SQL (100%) rename {snowflake => archive/snowflake}/PROD/training_interface/R__2003_LOAD_ATTEMPTS_SP.sql (100%) rename {snowflake => archive/snowflake}/PROD/training_interface/R__2004_CREATE_TRAINING_DATA_TABLE_SP.sql (100%) rename {snowflake => archive/snowflake}/PROD/training_interface/R__2005_LOAD_COLUMN_CONFIG_SP.sql (100%) rename {snowflake => archive/snowflake}/PROD/training_interface/R__2006_LOAD_TRAINING_DATA_RAW_SP.sql (100%) rename {snowflake => archive/snowflake}/PROD/training_interface/R__2007_CREATE_BUSINESS_CONFIG_objects.sql (100%) rename {snowflake => archive/snowflake}/PROD/training_interface/R__2008_LOAD_BUSINESS_CONFIG_SP.sql (100%) rename {snowflake => archive/snowflake}/PROD/upload_interface/R__2001_CLIENT_CONFIG_TABLE.sql (100%) rename {snowflake => archive/snowflake}/PROD/upload_interface/R__2002_LOAD_CLIENT_CONFIG_SP.sql (100%) rename {snowflake => archive/snowflake}/PROD/upload_interface/R__2003_CONTRACT_UPLOAD_LOGS.sql (100%) rename {snowflake => archive/snowflake}/UAT/R__1001_LOG_AUDIT.sql (100%) rename {snowflake => archive/snowflake}/UAT/R__1002_LOG_AUDIT_TABLE.sql (100%) rename {snowflake => archive/snowflake}/UAT/config_interface/R__1001_UAT_PROMPT_CONFIG_TABLE.sql (100%) rename {snowflake => archive/snowflake}/UAT/config_interface/R__1002_UAT_CONTRACT_CONFIG_TABLE.sql (100%) rename {snowflake => archive/snowflake}/UAT/config_interface/R__1003_REQUEST_SUBMISSION_TABLE.sql (100%) rename {snowflake => archive/snowflake}/UAT/config_interface/R__1004_LOAD_CONTRACT_CONFIG_SP.sql (100%) rename {snowflake => archive/snowflake}/UAT/config_interface/R__1005_LOAD_REQUEST_SUBMISSION_SP.sql (100%) rename {snowflake => archive/snowflake}/UAT/config_interface/R__1006_PIPELINE_OUTPUT.sql (100%) rename {snowflake => archive/snowflake}/UAT/config_interface/R__1007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql (100%) rename {snowflake => archive/snowflake}/UAT/config_interface/R__1008_PIPELINE_OUTPUT_B_FIELDS.sql (100%) rename {snowflake => archive/snowflake}/UAT/config_interface/R__1009_LOAD_B_FIELDS_PIPELINE_RAW_OUTPUT.sql (100%) rename {snowflake => archive/snowflake}/UAT/system_wide/R__1001_SERVERLESS_LOGS_TABLE.sql (100%) rename {snowflake => archive/snowflake}/UAT/training_interface/R__1001_INIT_OBJS.sql (100%) rename {snowflake => archive/snowflake}/UAT/training_interface/R__1002_LOAD_TRAINING_RESULTS_SP.SQL (100%) rename {snowflake => archive/snowflake}/UAT/training_interface/R__1003_LOAD_ATTEMPTS_SP.sql (100%) rename {snowflake => archive/snowflake}/UAT/training_interface/R__1004_CREATE_TRAINING_DATA_TABLE_SP.sql (100%) rename {snowflake => archive/snowflake}/UAT/training_interface/R__1005_LOAD_COLUMN_CONFIG_SP.sql (100%) rename {snowflake => archive/snowflake}/UAT/training_interface/R__1006_LOAD_TRAINING_DATA_RAW_SP.sql (100%) rename {snowflake => archive/snowflake}/UAT/training_interface/R__1007_CREATE_BUSINESS_CONFIG_objects.sql (100%) rename {snowflake => archive/snowflake}/UAT/training_interface/R__1008_LOAD_BUSINESS_CONFIG_SP.sql (100%) rename {snowflake => archive/snowflake}/UAT/upload_interface/R__1001_CLIENT_CONFIG_TABLE.sql (100%) rename {snowflake => archive/snowflake}/UAT/upload_interface/R__1002_LOAD_CLIENT_CONFIG_SP.sql (100%) rename {snowflake => archive/snowflake}/UAT/upload_interface/R__1003_CONTRACT_UPLOAD_LOGS.sql (100%) rename {streamlit-server => archive/streamlit-server}/alb.tf (100%) rename {streamlit-server => archive/streamlit-server}/alb_sg.tf (100%) rename {streamlit-server => archive/streamlit-server}/iam.tf (100%) rename {streamlit-server => archive/streamlit-server}/main.tf (100%) rename {streamlit-server => archive/streamlit-server}/requirements.txt (100%) rename {streamlit-server => archive/streamlit-server}/user_data.sh (100%) rename {streamlit-server => archive/streamlit-server}/variables.tf (100%) rename {streamlit-server => archive/streamlit-server}/vars-dev.tfvars (100%) rename {streamlit-server => archive/streamlit-server}/vars-prod.tfvars (100%) rename {streamlit-server => archive/streamlit-server}/vars-uat.tfvars (100%) rename {streamlit => archive/streamlit}/.dockerignore (100%) rename {streamlit => archive/streamlit}/.python-version (100%) rename {streamlit => archive/streamlit}/README.md (100%) rename {fieldExtraction/constants => archive/streamlit}/__init__.py (100%) rename {streamlit => archive/streamlit}/aaretelogo.png (100%) rename {streamlit => archive/streamlit}/constants.py (100%) rename {streamlit => archive/streamlit}/contract_field_values.csv (100%) rename {streamlit => archive/streamlit}/contract_fields.csv (100%) rename {streamlit => archive/streamlit}/ingest.py (100%) rename {streamlit => archive/streamlit}/interface_0.py (100%) rename {streamlit => archive/streamlit}/interface_1.py (100%) rename {streamlit => archive/streamlit}/interface_2.py (100%) rename {streamlit => archive/streamlit}/interface_2_rag.py (100%) rename {streamlit => archive/streamlit}/interface_3.py (100%) rename {streamlit => archive/streamlit}/interface_3_rag.py (100%) rename {streamlit => archive/streamlit}/local/local_interface_0.py (100%) rename {streamlit => archive/streamlit}/local/local_interface_1.py (100%) rename {streamlit => archive/streamlit}/local/local_interface_2.py (100%) rename {streamlit => archive/streamlit}/multipage/Interface_0.py (100%) rename {streamlit => archive/streamlit}/multipage/aaretelogo.png (100%) rename {streamlit => archive/streamlit}/multipage/constants.py (100%) rename {streamlit => archive/streamlit}/multipage/contract_fields.csv (100%) rename {streamlit => archive/streamlit}/multipage/pages/1_Interface_1.py (100%) rename {streamlit => archive/streamlit}/multipage/pages/2_Interface_2.py (100%) rename {streamlit => archive/streamlit}/multipage/pages/3_Data_Dictionary.py (100%) rename {streamlit => archive/streamlit}/multipage/security.py (100%) rename {streamlit => archive/streamlit}/multipage/sf_conn.py (100%) rename {streamlit => archive/streamlit}/multipage/util.py (100%) rename {streamlit => archive/streamlit}/poetry.lock (100%) rename {streamlit => archive/streamlit}/pyproject.toml (100%) rename {streamlit => archive/streamlit}/runs-dashboard.py (100%) rename {streamlit => archive/streamlit}/security.py (100%) rename {streamlit => archive/streamlit}/sf_conn.py (100%) rename {streamlit => archive/streamlit}/tests/example_test.py (100%) rename {streamlit => archive/streamlit}/util.py (100%) rename {streamlit_multipage => archive/streamlit_multipage}/.dockerignore (100%) rename {airflow => archive/streamlit_multipage}/.python-version (100%) rename {streamlit_multipage => archive/streamlit_multipage}/Demo_Test_data.csv (100%) rename {streamlit_multipage => archive/streamlit_multipage}/Demo_Test_data.xlsx (100%) rename {streamlit_multipage => archive/streamlit_multipage}/Interface_1.py (100%) rename {streamlit_multipage => archive/streamlit_multipage}/README.md (100%) rename {streamlit_multipage => archive/streamlit_multipage}/aaretelogo.png (100%) rename {streamlit_multipage => archive/streamlit_multipage}/constants.py (100%) rename {streamlit_multipage => archive/streamlit_multipage}/contract_fields.csv (100%) rename {streamlit_multipage => archive/streamlit_multipage}/pages/1_Interface_2.py (100%) rename {streamlit_multipage => archive/streamlit_multipage}/poetry.lock (100%) rename {streamlit_multipage => archive/streamlit_multipage}/pyproject.toml (100%) rename {streamlit_multipage => archive/streamlit_multipage}/temp/Prime Care/13-2655001-New York City Health and Hospitals Corporation-ICMProviderAgreement_318243_1.Pdf (100%) rename {streamlit_multipage => archive/streamlit_multipage}/temp/Prime Care/13-2655001-New York City Health and Hospitals Corporation-ICMProviderAgreement_318243_1.csv (100%) rename {streamlit_multipage => archive/streamlit_multipage}/temp/Prime Care/43-0654872-Saint Louis University dba SLUCare, a Missouri benevolent corporation-ICMProviderAgreement_92767_3.Pdf (100%) rename {streamlit_multipage => archive/streamlit_multipage}/temp/Prime Care/43-0654872-Saint Louis University dba SLUCare, a Missouri benevolent corporation-ICMProviderAgreement_92767_3.csv (100%) rename {streamlit_multipage => archive/streamlit_multipage}/temp/Prime Care/52-1590951-Maxim Healthcare Services Inc-ICMProviderAgreement_265803_3.Pdf (100%) rename {streamlit_multipage => archive/streamlit_multipage}/temp/Prime Care/52-1590951-Maxim Healthcare Services Inc-ICMProviderAgreement_265803_3.csv (100%) rename {streamlit_multipage => archive/streamlit_multipage}/temp1.csv (100%) rename {streamlit_multipage => archive/streamlit_multipage}/temp2.csv (100%) rename {streamlit_multipage => archive/streamlit_multipage}/tests/example_test.py (100%) rename terminal.py => archive/terminal.py (100%) rename terraform.py => archive/terraform.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda-layer/anthropic-snowflake/anthropic-sf-310.zip (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda-layer/brotli-layer/brotlipy-layer.zip (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda-layer/libre-office/lo.tar.br (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda-layer/pandas-np-310/pd_np.zip (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda-layer/pydantic-218/pydantic.zip (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda-layer/pypdf2-layer-new/requirements.txt (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda-layer/pypdf2-layer/PyPDF2.zip (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda-layer/snowflake-connector/snowflake-connector-39-verified.zip (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/batch-creation/.dockerignore (100%) rename {fieldExtraction => archive/textract-pipeline/src/lambda/batch-creation}/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/batch-creation/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/batch-creation/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/batch-creation/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/batch-creation/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/batch-creation/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/call-bedrock/.dockerignore (100%) rename {streamlit_multipage => archive/textract-pipeline/src/lambda/call-bedrock}/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/call-bedrock/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/call-bedrock/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/call-bedrock/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/call-bedrock/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/call-bedrock/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface-get/.dockerignore (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface-get/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface-get/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface-get/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface-get/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface-get/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface-get/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface/.dockerignore (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/database-interface/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/docx-to-pdf/.dockerignore (100%) rename {textract-pipeline/src/lambda/batch-creation => archive/textract-pipeline/src/lambda/docx-to-pdf}/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/docx-to-pdf/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/docx-to-pdf/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/docx-to-pdf/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/docx-to-pdf/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/docx-to-pdf/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/insert-record/.dockerignore (100%) rename {textract-pipeline/src/lambda/call-bedrock => archive/textract-pipeline/src/lambda/insert-record}/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/insert-record/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/insert-record/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/insert-record/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/insert-record/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/insert-record/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/pdf-validation/.dockerignore (100%) rename {textract-pipeline/src/lambda/docx-to-pdf => archive/textract-pipeline/src/lambda/pdf-validation}/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/pdf-validation/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/pdf-validation/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/pdf-validation/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/pdf-validation/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/pdf-validation/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/prompt-processor/.dockerignore (100%) rename {textract-pipeline/src/lambda/insert-record => archive/textract-pipeline/src/lambda/prompt-processor}/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/prompt-processor/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/prompt-processor/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/prompt-processor/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/prompt-processor/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/prompt-processor/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/s3-folder-details/.dockerignore (100%) rename {textract-pipeline/src/lambda/pdf-validation => archive/textract-pipeline/src/lambda/s3-folder-details}/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/s3-folder-details/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/s3-folder-details/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/s3-folder-details/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/s3-folder-details/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/s3-folder-details/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/text-creation/.dockerignore (100%) rename {textract-pipeline/src/lambda/prompt-processor => archive/textract-pipeline/src/lambda/text-creation}/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/text-creation/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/text-creation/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/text-creation/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/text-creation/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/text-creation/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/textract-receiver/.dockerignore (100%) rename {textract-pipeline/src/lambda/s3-folder-details => archive/textract-pipeline/src/lambda/textract-receiver}/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/textract-receiver/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/textract-receiver/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/textract-receiver/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/textract-receiver/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/textract-receiver/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/textract-sender/.dockerignore (100%) rename {textract-pipeline/src/lambda/text-creation => archive/textract-pipeline/src/lambda/textract-sender}/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/textract-sender/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/textract-sender/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/textract-sender/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/textract-sender/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/textract-sender/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/tiff-to-pdf/.dockerignore (100%) rename {textract-pipeline/src/lambda/textract-receiver => archive/textract-pipeline/src/lambda/tiff-to-pdf}/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/tiff-to-pdf/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/tiff-to-pdf/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/tiff-to-pdf/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/tiff-to-pdf/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/tiff-to-pdf/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/trigger-pipeline/.dockerignore (100%) rename {textract-pipeline/src/lambda/textract-sender => archive/textract-pipeline/src/lambda/trigger-pipeline}/.python-version (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/trigger-pipeline/README.md (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/trigger-pipeline/index.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/trigger-pipeline/poetry.lock (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/trigger-pipeline/pyproject.toml (100%) rename {textract-pipeline => archive/textract-pipeline}/src/lambda/trigger-pipeline/tests/example_test.py (100%) rename {textract-pipeline => archive/textract-pipeline}/src/s3-files/config.properties (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/main.tf (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/modules/aws-textract-pipeline-part1/main.tf (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/modules/aws-textract-pipeline-part1/outputs.tf (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/modules/aws-textract-pipeline-part1/variables.tf (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/modules/aws-textract-pipeline-part3/main.tf (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/modules/aws-textract-pipeline-part3/outputs.tf (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/modules/aws-textract-pipeline-part3/variables.tf (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/modules/aws-textract-pipeline/main.tf (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/modules/aws-textract-pipeline/outputs.tf (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/modules/aws-textract-pipeline/variables.tf (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/outputs.tf (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/snowsql-cicd.sh (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/variables.tf (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/vars-dev.tfvars (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/vars-prod.tfvars (100%) rename {textract-pipeline => archive/textract-pipeline}/terraform/vars-uat.tfvars (100%) rename {fieldExtraction/documentation => documentation}/EXTRACTION_FLOW_VISUAL.md (100%) rename {fieldExtraction/documentation => documentation}/FIELD_EXTRACTION_GUIDE.md (100%) rename {fieldExtraction/documentation => documentation}/PERFORMANCE_ANALYSIS_GUIDE.md (100%) delete mode 100644 fieldExtraction/.gitignore delete mode 100644 fieldExtraction/README.md delete mode 100644 fieldExtraction/nltk_data/README.md delete mode 100644 fieldExtraction/nltk_data/tokenizers/punkt_tab/README delete mode 100644 fieldExtraction/nltk_data/tokenizers/punkt_tab/english/abbrev_types.txt delete mode 100644 fieldExtraction/nltk_data/tokenizers/punkt_tab/english/collocations.tab delete mode 100644 fieldExtraction/nltk_data/tokenizers/punkt_tab/english/ortho_context.tab delete mode 100644 fieldExtraction/nltk_data/tokenizers/punkt_tab/english/sent_starters.txt delete mode 100644 fieldExtraction/poetry.lock delete mode 100644 fieldExtraction/pyproject.toml delete mode 100644 fieldExtraction/release/Dockerfile delete mode 100644 fieldExtraction/src/investment/exhibit_funcs.py delete mode 100644 fieldExtraction/src/investment/preprocessing_funcs.py delete mode 100644 fieldExtraction/tests/test_exhibit_funcs.py delete mode 100644 fieldExtraction/tests/test_one_to_n.py delete mode 100644 poetry.lock create mode 100644 src/__init__.py rename {fieldExtraction/src => src}/codes/code_funcs.py (94%) rename {fieldExtraction/src => src}/codes/main.py (92%) rename {fieldExtraction/src => src}/config.py (84%) rename {fieldExtraction/src => src/constants}/__init__.py (100%) rename {fieldExtraction => src}/constants/constants.py (71%) rename {fieldExtraction => src}/constants/delimiters.py (100%) create mode 100644 src/constants/embedding.py rename {fieldExtraction => src}/constants/investment_columns.py (100%) rename {fieldExtraction => src}/constants/lists/compound_indicators.json (100%) rename {fieldExtraction => src}/constants/lists/do_not_run.json (100%) rename {fieldExtraction => src}/constants/lists/exhibit_header_markers.json (100%) rename {fieldExtraction => src}/constants/lists/stop_words.json (100%) rename {fieldExtraction => src}/constants/lists/valid_fee_schedule.json (100%) rename {fieldExtraction => src}/constants/lists/valid_fee_schedule_version.json (100%) rename {fieldExtraction => src}/constants/lists/valid_prov_type.json (100%) rename {fieldExtraction => src}/constants/lists/valid_reimb_methodology.json (100%) rename {fieldExtraction => src}/constants/lists/valid_unit_of_measure.json (100%) rename {fieldExtraction => src}/constants/mapping_csvs/admit_type_cd/admit_mapping.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/diag_cd/diag.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/grouper_cd/drg_mapping_apr-drg.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/grouper_cd/drg_mapping_ms-drg.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/proc_cd/cpt.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/proc_cd/cpt_level1.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/proc_cd/cpt_level2.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/proc_cd/cpt_level3.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/proc_cd/hcpcs.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/proc_cd/hcpcs_level1.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/proc_cd/hcpcs_level2.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/rev_cd/rev.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/rev_cd/rev_level1.csv (100%) rename {fieldExtraction => src}/constants/mapping_csvs/taxonomy_cd/taxonomy_mapping.csv (100%) rename {fieldExtraction => src}/constants/mappings/crosswalk_bill_type.json (100%) rename {fieldExtraction => src}/constants/mappings/crosswalk_claim_type.json (100%) rename {fieldExtraction => src}/constants/mappings/crosswalk_lob.json (100%) rename {fieldExtraction => src}/constants/mappings/crosswalk_network.json (100%) rename {fieldExtraction => src}/constants/mappings/crosswalk_place_of_service.json (100%) rename {fieldExtraction => src}/constants/mappings/crosswalk_product_lob.json (100%) rename {fieldExtraction => src}/constants/mappings/crosswalk_program.json (100%) rename {fieldExtraction => src}/constants/mappings/crosswalk_program_lob.json (100%) rename {fieldExtraction => src}/constants/mappings/crosswalk_provider_specialty.json (100%) rename {fieldExtraction => src}/constants/mappings/exclude_keywords_for_pc.json (100%) rename {fieldExtraction => src}/constants/mappings/numeric_mappigs.json (100%) rename {fieldExtraction => src}/constants/mappings/stop_words_for_pc_cleanup.json (100%) rename {fieldExtraction => src}/constants/mappings/synonym_map.json (100%) rename {fieldExtraction => src}/constants/mappings/valid_carveouts.json (100%) rename {fieldExtraction => src}/constants/regex_patterns.py (100%) create mode 100644 src/core/__init__.py create mode 100644 src/core/base_pipeline.py rename {fieldExtraction/constants => src/core}/embedding.py (50%) rename {fieldExtraction/src/prompts => src/core}/fieldset.py (99%) create mode 100644 src/core/registry.py rename {fieldExtraction/src => src}/crosswalk/README.md (100%) rename {fieldExtraction/src => src}/crosswalk/crosswalk_builder.py (100%) rename {fieldExtraction/src => src}/crosswalk/list_builder.py (100%) rename {fieldExtraction/src => src}/document_classification/main.py (98%) rename {fieldExtraction => src}/embeddings/cpt_level1/choices.pkl (100%) rename {fieldExtraction => src}/embeddings/cpt_level1/embeddings.npy (100%) rename {fieldExtraction => src}/embeddings/cpt_level1/faiss_index.bin (100%) rename {fieldExtraction => src}/embeddings/cpt_level2/choices.pkl (100%) rename {fieldExtraction => src}/embeddings/cpt_level2/embeddings.npy (100%) rename {fieldExtraction => src}/embeddings/cpt_level2/faiss_index.bin (100%) rename {fieldExtraction => src}/embeddings/cpt_level3/choices.pkl (100%) rename {fieldExtraction => src}/embeddings/cpt_level3/embeddings.npy (100%) rename {fieldExtraction => src}/embeddings/cpt_level3/faiss_index.bin (100%) rename {fieldExtraction => src}/embeddings/hcpcs_level1/choices.pkl (100%) rename {fieldExtraction => src}/embeddings/hcpcs_level1/embeddings.npy (100%) rename {fieldExtraction => src}/embeddings/hcpcs_level1/faiss_index.bin (100%) rename {fieldExtraction => src}/embeddings/hcpcs_level2/choices.pkl (100%) rename {fieldExtraction => src}/embeddings/hcpcs_level2/embeddings.npy (100%) rename {fieldExtraction => src}/embeddings/hcpcs_level2/faiss_index.bin (100%) rename {fieldExtraction => src}/embeddings/rev/choices.pkl (100%) rename {fieldExtraction => src}/embeddings/rev/embeddings.npy (100%) rename {fieldExtraction => src}/embeddings/rev/faiss_index.bin (100%) rename {fieldExtraction => src}/embeddings/rev_level1/choices.pkl (100%) rename {fieldExtraction => src}/embeddings/rev_level1/embeddings.npy (100%) rename {fieldExtraction => src}/embeddings/rev_level1/faiss_index.bin (100%) rename {fieldExtraction/src/investment => src/parent_child}/__init__.py (100%) rename {fieldExtraction/src => src}/parent_child/main.py (100%) rename {fieldExtraction/src => src}/parent_child/parent_child_mapping.py (100%) rename {fieldExtraction/src => src}/parent_child/parent_child_preprocessing.py (99%) rename {fieldExtraction/src => src/pipelines}/.gitignore (100%) create mode 100644 src/pipelines/__init__.py create mode 100644 src/pipelines/clients/__init__.py rename {fieldExtraction/src/parent_child => src/pipelines/clients/bcbs_promise}/__init__.py (100%) create mode 100644 src/pipelines/clients/bcbs_promise/file_processing.py rename {fieldExtraction/src/investment => src/pipelines/clients/bcbs_promise}/main.py (83%) create mode 100644 src/pipelines/clients/bcbs_promise/prompts/__init__.py rename {fieldExtraction/src/investment => src/pipelines/clients/bcbs_promise/prompts}/prompt_calls.py (72%) rename {fieldExtraction/src/tracking => src/pipelines/clients/clover}/__init__.py (100%) create mode 100644 src/pipelines/clients/clover/file_processing.py create mode 100644 src/pipelines/clients/clover/prompts/__init__.py create mode 100644 src/pipelines/clients/clover/prompts/prompt_calls.py create mode 100644 src/pipelines/runner.py rename {fieldExtraction/src/utils => src/pipelines/saas}/__init__.py (100%) rename {fieldExtraction/src/investment => src/pipelines/saas}/file_processing.py (55%) create mode 100644 src/pipelines/saas/main.py create mode 100644 src/pipelines/saas/prompts/__init__.py create mode 100644 src/pipelines/saas/prompts/prompt_calls.py create mode 100644 src/pipelines/shared/__init__.py create mode 100644 src/pipelines/shared/extraction/__init__.py rename {fieldExtraction/src/investment => src/pipelines/shared/extraction}/dynamic_funcs.py (80%) create mode 100644 src/pipelines/shared/extraction/exhibit_funcs.py rename {fieldExtraction/src/investment => src/pipelines/shared/extraction}/one_to_n_funcs.py (78%) rename {fieldExtraction/src/investment => src/pipelines/shared/extraction}/one_to_one_funcs.py (91%) create mode 100644 src/pipelines/shared/extraction/page_funcs.py rename {fieldExtraction/src/investment => src/pipelines/shared/extraction}/row_funcs.py (88%) rename {fieldExtraction/src/investment => src/pipelines/shared/extraction}/tin_npi_funcs.py (92%) rename {fieldExtraction/src/investment => src/pipelines/shared/extraction}/vision_funcs.py (100%) create mode 100644 src/pipelines/shared/postprocessing/__init__.py rename {fieldExtraction/src/investment => src/pipelines/shared/postprocessing}/aarete_derived.py (76%) rename {fieldExtraction/src/investment => src/pipelines/shared/postprocessing}/postprocess.py (92%) rename {fieldExtraction/src/investment => src/pipelines/shared/postprocessing}/postprocessing_funcs.py (93%) create mode 100644 src/pipelines/shared/preprocessing/__init__.py rename {fieldExtraction/src/investment => src/pipelines/shared/preprocessing}/hybrid_smart_chunking_funcs.py (83%) rename {fieldExtraction/src/investment => src/pipelines/shared/preprocessing}/hybrid_smart_chunking_preprocessing.py (99%) rename {fieldExtraction/src/investment => src/pipelines/shared/preprocessing}/preprocess.py (60%) create mode 100644 src/pipelines/shared/preprocessing/preprocessing_funcs.py create mode 100644 src/prompts/bcbs_promise_prompts.json create mode 100644 src/prompts/clover_prompts.json rename {fieldExtraction/src => src}/prompts/document_classification_prompts.json (100%) create mode 100644 src/prompts/fieldset.py rename {fieldExtraction/src => src}/prompts/investment_prompts.json (100%) rename {fieldExtraction/src => src}/prompts/prompt_templates.py (80%) rename {fieldExtraction/src => src}/qc_qa/__init__.py (100%) rename {fieldExtraction/src => src}/qc_qa/__main__.py (95%) rename {fieldExtraction/src => src}/qc_qa/pipeline.py (96%) rename {fieldExtraction => src}/scripts/compare_output.py (100%) rename {fieldExtraction => src}/scripts/create_code_embeddings.py (53%) rename {fieldExtraction => src}/scripts/detect_complex.py (100%) rename {fieldExtraction => src}/scripts/file_counting.py (100%) rename {fieldExtraction => src}/scripts/investment_field_testing/testing.ipynb (97%) rename {fieldExtraction => src}/scripts/merge_issue_regex.py (100%) rename {fieldExtraction => src}/scripts/missingness_analysis.py (79%) rename {fieldExtraction => src}/scripts/postprocess_existing_output.py (99%) rename {fieldExtraction => src}/scripts/prerun.py (100%) rename {fieldExtraction => src}/scripts/qa_qc.py (91%) rename {fieldExtraction => src}/scripts/table_analysis.py (100%) rename {fieldExtraction => src}/scripts/textract_template.py (99%) rename {fieldExtraction => src}/scripts/tin_pull.py (100%) rename {fieldExtraction/src => src}/testbed/add_reimb_id_to_testbed.py (79%) rename {fieldExtraction/src => src}/testbed/model_evaluation.py (62%) rename {fieldExtraction/src => src}/testbed/model_evaluation_utils.py (69%) rename {fieldExtraction/src => src}/testbed/one_to_n_comparison.py (100%) rename {fieldExtraction/src => src}/testbed/one_to_one_comparison.py (99%) rename {fieldExtraction/src => src}/testbed/testbed_metrics.py (91%) rename {fieldExtraction/src => src}/testbed/testbed_postprocess.py (100%) rename {fieldExtraction/src => src}/testbed/testbed_utils.py (99%) rename {fieldExtraction => src}/tests/test_calculate_progress_stats.py (93%) rename {fieldExtraction => src}/tests/test_code_funcs.py (98%) rename {fieldExtraction => src}/tests/test_crosswalk_utils.py (100%) rename {fieldExtraction => src}/tests/test_document_classification.py (54%) rename {fieldExtraction => src}/tests/test_dynamic.py (93%) create mode 100644 src/tests/test_exhibit_funcs.py rename {fieldExtraction => src}/tests/test_fieldset.py (99%) rename {fieldExtraction => src}/tests/test_hybrid_smart_chunking_funcs.py (81%) rename {fieldExtraction => src}/tests/test_hybrid_smart_chunking_preprocessing.py (80%) rename {fieldExtraction => src}/tests/test_io_utils.py (94%) rename {fieldExtraction => src}/tests/test_llm_utils.py (84%) create mode 100644 src/tests/test_one_to_n.py create mode 100644 src/tests/test_page_funcs.py create mode 100644 src/tests/test_phase5_integration.py rename {fieldExtraction => src}/tests/test_postprocess.py (81%) rename {fieldExtraction => src}/tests/test_preprocessing_funcs.py (83%) create mode 100644 src/tests/test_prompt_caching.py rename {fieldExtraction => src}/tests/test_qc_qa_pipeline.py (85%) rename {fieldExtraction => src}/tests/test_rag_utils.py (79%) rename {fieldExtraction => src}/tests/test_string_utils.py (68%) rename {fieldExtraction => src}/tests/test_timing_utils.py (100%) rename {fieldExtraction => src}/tests/test_tin_npi_funcs.py (91%) rename {fieldExtraction => src}/tests/test_usage_tracking.py (93%) rename {streamlit => src/tracking}/__init__.py (100%) rename {fieldExtraction/src => src}/tracking/batch_tracking.py (100%) create mode 100644 src/utils/__init__.py rename {fieldExtraction/src => src}/utils/crosswalk_utils.py (99%) rename {fieldExtraction/src => src}/utils/embedding_utils.py (100%) rename {fieldExtraction/src => src}/utils/io_utils.py (97%) rename {fieldExtraction/src => src}/utils/llm_utils.py (95%) rename {fieldExtraction/src => src}/utils/logging_utils.py (99%) rename {fieldExtraction/src => src}/utils/qa_qc_utils.py (98%) rename {fieldExtraction/src => src}/utils/rag_utils.py (97%) rename {fieldExtraction/src => src}/utils/string_utils.py (95%) rename {fieldExtraction/src => src}/utils/timing_utils.py (90%) rename {fieldExtraction/src/tracking => src/utils}/tracking_utils.py (93%) rename {fieldExtraction/src => src}/utils/usage_tracking.py (86%) delete mode 100644 textract-pipeline/src/lambda/tiff-to-pdf/.python-version delete mode 100644 textract-pipeline/src/lambda/trigger-pipeline/.python-version create mode 100644 uv.lock diff --git a/.dockerignore b/.dockerignore index 6fdd640..780c304 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,37 @@ -.mypy_cache \ No newline at end of file +# Git +.git/ +.gitignore + +# Python +__pycache__/ +*.py[cod] +*.pyo +.mypy_cache/ +.pytest_cache/ + +# IDE +.idea/ +.cursor/ +.vscode/ + +# Outputs +outputs/ +output/ +*.log + +# Environment +.env +*.env +myenv/ + +# Tests +src/tests/ + +# Docs +docs/ +*.md + +# Data files (usually loaded from S3) +*.csv +*.xlsx +data/ diff --git a/.gitignore b/.gitignore index e5362a5..b09252d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,45 +1,55 @@ -# These are some examples of commonly ignored file patterns. -# You should customize this list as applicable to your project. -# Learn more about .gitignore: -# https://www.atlassian.com/git/tutorials/saving-changes/gitignore - -# Node artifact files -node_modules/ -dist/ - -# Compiled Java class files -*.class - -# Compiled Python bytecode +# Python *.py[cod] +*.pyo +__pycache__/ +.mypy_cache/ +.pytest_cache/ +myenv/ +*.egg-info/ -# Log files -*.log - -# Package files -*.jar -*.png -# Maven -target/ -dist/ - -# IDE files +# IDE .idea/ .cursor/ +.vscode/ -# Unit test reports -TEST*.xml - -# Generated by MacOS +# OS .DS_Store - -# Generated by Windows Thumbs.db +*:Zone.Identifier -# Applications +# Logs +*.log + +# Environment +.env +*.env + +# Data files (general exclusion) +*.csv +*.xlsx +*.xlsb +*.zip +*.json +*.txt +*.pdf +*.PDF +*.TXT + +# Allow tracked data files in src/ +!src/constants/**/*.csv +!src/constants/**/*.json +!src/prompts/*.json +!requirements.txt + +# Build artifacts +dist/ +build/ +target/ +*.class +*.jar +*.war *.app *.exe -*.war # Large media files *.mp4 @@ -49,15 +59,28 @@ Thumbs.db *.mov *.wmv -# Terraform files +# Terraform .terraform/ -terraform.tfstate.backup -terraform.tfstate +terraform.tfstate* .terraform.lock.hcl -build/ +*.tfplan +*.pem textract-pipeline/terraform/builds/ -# Data Files +# Outputs +output/ +outputs/ + +# Local/temporary +subset/ +docs/ +local_scripts/ +untracked_tests/ +new/ +textfiles/ +texts/ + +# Streamlit (legacy) streamlit/history.csv streamlit/RESULTS streamlit/DB/ @@ -66,47 +89,22 @@ streamlit/SOURCE_DOCUMENTS/ streamlit/contract_field_values.csv streamlit/contract_fields.csv streamlit/sample.csv -streamlit/temp1.csv -streamlit/temp2.csv +streamlit/temp*.csv streamlit/results.csv - -# env streamlit/venv -*.pdf -*.PDF -*.TXT -*.txt -*:Zone.Identifier -*.tfplan -*.pem -textfiles/ -texts/ -*.csv -*.xlsx -*.zip -*.json -myenv/ -*.env -subset/ -output/ -docs/ -local_scripts/ -untracked_tests/ -.mypy_cache/ -.pytest_cache/ -__pycache__/ - -.env -new/ - -# Embeddings +# Legacy paths fieldExtraction/embeddings/ -# Output reports -fieldExtraction/output_reports/ +# Node (if any) +node_modules/ -# PRD Documents (local only, living documents) +# Test reports +TEST*.xml + +# Shell scripts (debugging/utility) +*.sh + +# PRD Documents *.prd *prd.md -usage-cost-monitoring-prd.md \ No newline at end of file diff --git a/Doczy.AI_Automation/.dockerignore b/archive/Doczy.AI_Automation/.dockerignore similarity index 100% rename from Doczy.AI_Automation/.dockerignore rename to archive/Doczy.AI_Automation/.dockerignore diff --git a/Doczy.AI_Automation/.python-version b/archive/Doczy.AI_Automation/.python-version similarity index 100% rename from Doczy.AI_Automation/.python-version rename to archive/Doczy.AI_Automation/.python-version diff --git a/Doczy.AI_Automation/README.md b/archive/Doczy.AI_Automation/README.md similarity index 100% rename from Doczy.AI_Automation/README.md rename to archive/Doczy.AI_Automation/README.md diff --git a/Doczy.AI_Automation/config/aws_conn.py b/archive/Doczy.AI_Automation/config/aws_conn.py similarity index 100% rename from Doczy.AI_Automation/config/aws_conn.py rename to archive/Doczy.AI_Automation/config/aws_conn.py diff --git a/Doczy.AI_Automation/config/env.yaml b/archive/Doczy.AI_Automation/config/env.yaml similarity index 100% rename from Doczy.AI_Automation/config/env.yaml rename to archive/Doczy.AI_Automation/config/env.yaml diff --git a/Doczy.AI_Automation/data/data.xlsx b/archive/Doczy.AI_Automation/data/data.xlsx similarity index 100% rename from Doczy.AI_Automation/data/data.xlsx rename to archive/Doczy.AI_Automation/data/data.xlsx diff --git a/Doczy.AI_Automation/elements/__init__.py b/archive/Doczy.AI_Automation/elements/__init__.py similarity index 100% rename from Doczy.AI_Automation/elements/__init__.py rename to archive/Doczy.AI_Automation/elements/__init__.py diff --git a/Doczy.AI_Automation/elements/interface_0_elements.py b/archive/Doczy.AI_Automation/elements/interface_0_elements.py similarity index 100% rename from Doczy.AI_Automation/elements/interface_0_elements.py rename to archive/Doczy.AI_Automation/elements/interface_0_elements.py diff --git a/Doczy.AI_Automation/elements/interface_1_elements.py b/archive/Doczy.AI_Automation/elements/interface_1_elements.py similarity index 100% rename from Doczy.AI_Automation/elements/interface_1_elements.py rename to archive/Doczy.AI_Automation/elements/interface_1_elements.py diff --git a/Doczy.AI_Automation/elements/interface_2_elements.py b/archive/Doczy.AI_Automation/elements/interface_2_elements.py similarity index 100% rename from Doczy.AI_Automation/elements/interface_2_elements.py rename to archive/Doczy.AI_Automation/elements/interface_2_elements.py diff --git a/Doczy.AI_Automation/pages/Email_sign_in_page.py b/archive/Doczy.AI_Automation/pages/Email_sign_in_page.py similarity index 100% rename from Doczy.AI_Automation/pages/Email_sign_in_page.py rename to archive/Doczy.AI_Automation/pages/Email_sign_in_page.py diff --git a/Doczy.AI_Automation/pages/Password_sign_in_page.py b/archive/Doczy.AI_Automation/pages/Password_sign_in_page.py similarity index 100% rename from Doczy.AI_Automation/pages/Password_sign_in_page.py rename to archive/Doczy.AI_Automation/pages/Password_sign_in_page.py diff --git a/Doczy.AI_Automation/pages/Pre_sign_in_page.py b/archive/Doczy.AI_Automation/pages/Pre_sign_in_page.py similarity index 100% rename from Doczy.AI_Automation/pages/Pre_sign_in_page.py rename to archive/Doczy.AI_Automation/pages/Pre_sign_in_page.py diff --git a/Doczy.AI_Automation/pages/Remember_sign_in_page.py b/archive/Doczy.AI_Automation/pages/Remember_sign_in_page.py similarity index 100% rename from Doczy.AI_Automation/pages/Remember_sign_in_page.py rename to archive/Doczy.AI_Automation/pages/Remember_sign_in_page.py diff --git a/Doczy.AI_Automation/pages/__init__.py b/archive/Doczy.AI_Automation/pages/__init__.py similarity index 100% rename from Doczy.AI_Automation/pages/__init__.py rename to archive/Doczy.AI_Automation/pages/__init__.py diff --git a/Doczy.AI_Automation/pages/interface_0_page_objects.py b/archive/Doczy.AI_Automation/pages/interface_0_page_objects.py similarity index 100% rename from Doczy.AI_Automation/pages/interface_0_page_objects.py rename to archive/Doczy.AI_Automation/pages/interface_0_page_objects.py diff --git a/Doczy.AI_Automation/pages/interface_1_page_objects.py b/archive/Doczy.AI_Automation/pages/interface_1_page_objects.py similarity index 100% rename from Doczy.AI_Automation/pages/interface_1_page_objects.py rename to archive/Doczy.AI_Automation/pages/interface_1_page_objects.py diff --git a/Doczy.AI_Automation/pages/interface_2_page_objects.py b/archive/Doczy.AI_Automation/pages/interface_2_page_objects.py similarity index 100% rename from Doczy.AI_Automation/pages/interface_2_page_objects.py rename to archive/Doczy.AI_Automation/pages/interface_2_page_objects.py diff --git a/Doczy.AI_Automation/poetry.lock b/archive/Doczy.AI_Automation/poetry.lock similarity index 100% rename from Doczy.AI_Automation/poetry.lock rename to archive/Doczy.AI_Automation/poetry.lock diff --git a/Doczy.AI_Automation/pyproject.toml b/archive/Doczy.AI_Automation/pyproject.toml similarity index 100% rename from Doczy.AI_Automation/pyproject.toml rename to archive/Doczy.AI_Automation/pyproject.toml diff --git a/Doczy.AI_Automation/pytest.ini b/archive/Doczy.AI_Automation/pytest.ini similarity index 100% rename from Doczy.AI_Automation/pytest.ini rename to archive/Doczy.AI_Automation/pytest.ini diff --git a/Doczy.AI_Automation/reports/assets/style.css b/archive/Doczy.AI_Automation/reports/assets/style.css similarity index 100% rename from Doczy.AI_Automation/reports/assets/style.css rename to archive/Doczy.AI_Automation/reports/assets/style.css diff --git a/Doczy.AI_Automation/reports/test_report.html b/archive/Doczy.AI_Automation/reports/test_report.html similarity index 100% rename from Doczy.AI_Automation/reports/test_report.html rename to archive/Doczy.AI_Automation/reports/test_report.html diff --git a/Doczy.AI_Automation/reports/test_report.json b/archive/Doczy.AI_Automation/reports/test_report.json similarity index 100% rename from Doczy.AI_Automation/reports/test_report.json rename to archive/Doczy.AI_Automation/reports/test_report.json diff --git a/Doczy.AI_Automation/tests copy/example_test.py b/archive/Doczy.AI_Automation/tests copy/example_test.py similarity index 100% rename from Doczy.AI_Automation/tests copy/example_test.py rename to archive/Doczy.AI_Automation/tests copy/example_test.py diff --git a/Doczy.AI_Automation/tests/__init__.py b/archive/Doczy.AI_Automation/tests/__init__.py similarity index 100% rename from Doczy.AI_Automation/tests/__init__.py rename to archive/Doczy.AI_Automation/tests/__init__.py diff --git a/Doczy.AI_Automation/tests/conftest.py b/archive/Doczy.AI_Automation/tests/conftest.py similarity index 100% rename from Doczy.AI_Automation/tests/conftest.py rename to archive/Doczy.AI_Automation/tests/conftest.py diff --git a/Doczy.AI_Automation/tests/reports/assets/style.css b/archive/Doczy.AI_Automation/tests/reports/assets/style.css similarity index 100% rename from Doczy.AI_Automation/tests/reports/assets/style.css rename to archive/Doczy.AI_Automation/tests/reports/assets/style.css diff --git a/Doczy.AI_Automation/tests/reports/test_report.html b/archive/Doczy.AI_Automation/tests/reports/test_report.html similarity index 100% rename from Doczy.AI_Automation/tests/reports/test_report.html rename to archive/Doczy.AI_Automation/tests/reports/test_report.html diff --git a/Doczy.AI_Automation/tests/reports/test_report.json b/archive/Doczy.AI_Automation/tests/reports/test_report.json similarity index 100% rename from Doczy.AI_Automation/tests/reports/test_report.json rename to archive/Doczy.AI_Automation/tests/reports/test_report.json diff --git a/Doczy.AI_Automation/tests/reports/test_report_05_55.json b/archive/Doczy.AI_Automation/tests/reports/test_report_05_55.json similarity index 100% rename from Doczy.AI_Automation/tests/reports/test_report_05_55.json rename to archive/Doczy.AI_Automation/tests/reports/test_report_05_55.json diff --git a/Doczy.AI_Automation/tests/test_end_to_end.py b/archive/Doczy.AI_Automation/tests/test_end_to_end.py similarity index 100% rename from Doczy.AI_Automation/tests/test_end_to_end.py rename to archive/Doczy.AI_Automation/tests/test_end_to_end.py diff --git a/Doczy.AI_Automation/tests/test_interface_0.py b/archive/Doczy.AI_Automation/tests/test_interface_0.py similarity index 100% rename from Doczy.AI_Automation/tests/test_interface_0.py rename to archive/Doczy.AI_Automation/tests/test_interface_0.py diff --git a/Doczy.AI_Automation/tests/test_interface_1.py b/archive/Doczy.AI_Automation/tests/test_interface_1.py similarity index 100% rename from Doczy.AI_Automation/tests/test_interface_1.py rename to archive/Doczy.AI_Automation/tests/test_interface_1.py diff --git a/Doczy.AI_Automation/tests/test_interface_2.py b/archive/Doczy.AI_Automation/tests/test_interface_2.py similarity index 100% rename from Doczy.AI_Automation/tests/test_interface_2.py rename to archive/Doczy.AI_Automation/tests/test_interface_2.py diff --git a/Doczy.AI_Automation/utils/CustomException.py b/archive/Doczy.AI_Automation/utils/CustomException.py similarity index 100% rename from Doczy.AI_Automation/utils/CustomException.py rename to archive/Doczy.AI_Automation/utils/CustomException.py diff --git a/Doczy.AI_Automation/utils/__init__.py b/archive/Doczy.AI_Automation/utils/__init__.py similarity index 100% rename from Doczy.AI_Automation/utils/__init__.py rename to archive/Doczy.AI_Automation/utils/__init__.py diff --git a/Doczy.AI_Automation/utils/common_methods.py b/archive/Doczy.AI_Automation/utils/common_methods.py similarity index 100% rename from Doczy.AI_Automation/utils/common_methods.py rename to archive/Doczy.AI_Automation/utils/common_methods.py diff --git a/Doczy.AI_Automation/utils/element_related_methods.py b/archive/Doczy.AI_Automation/utils/element_related_methods.py similarity index 100% rename from Doczy.AI_Automation/utils/element_related_methods.py rename to archive/Doczy.AI_Automation/utils/element_related_methods.py diff --git a/Doczy.AI_Automation/utils/logger.py b/archive/Doczy.AI_Automation/utils/logger.py similarity index 100% rename from Doczy.AI_Automation/utils/logger.py rename to archive/Doczy.AI_Automation/utils/logger.py diff --git a/Doczy.AI_Automation/utils/reader.py b/archive/Doczy.AI_Automation/utils/reader.py similarity index 100% rename from Doczy.AI_Automation/utils/reader.py rename to archive/Doczy.AI_Automation/utils/reader.py diff --git a/Doczy.AI_Automation/utils/report.py b/archive/Doczy.AI_Automation/utils/report.py similarity index 100% rename from Doczy.AI_Automation/utils/report.py rename to archive/Doczy.AI_Automation/utils/report.py diff --git a/airflow/.dockerignore b/archive/airflow/.dockerignore similarity index 100% rename from airflow/.dockerignore rename to archive/airflow/.dockerignore diff --git a/.python-version b/archive/airflow/.python-version similarity index 100% rename from .python-version rename to archive/airflow/.python-version diff --git a/airflow/README.md b/archive/airflow/README.md similarity index 100% rename from airflow/README.md rename to archive/airflow/README.md diff --git a/airflow/dags/Qa_Dag.py b/archive/airflow/dags/Qa_Dag.py similarity index 100% rename from airflow/dags/Qa_Dag.py rename to archive/airflow/dags/Qa_Dag.py diff --git a/airflow/dags/cicd_test_dag.py b/archive/airflow/dags/cicd_test_dag.py similarity index 100% rename from airflow/dags/cicd_test_dag.py rename to archive/airflow/dags/cicd_test_dag.py diff --git a/airflow/dags/client_name_dag.py b/archive/airflow/dags/client_name_dag.py similarity index 100% rename from airflow/dags/client_name_dag.py rename to archive/airflow/dags/client_name_dag.py diff --git a/airflow/dags/config_interface_dag.py b/archive/airflow/dags/config_interface_dag.py similarity index 100% rename from airflow/dags/config_interface_dag.py rename to archive/airflow/dags/config_interface_dag.py diff --git a/airflow/dags/pipeline_processed_outputs_dag.py b/archive/airflow/dags/pipeline_processed_outputs_dag.py similarity index 100% rename from airflow/dags/pipeline_processed_outputs_dag.py rename to archive/airflow/dags/pipeline_processed_outputs_dag.py diff --git a/airflow/dags/raw_training_data_dag.py b/archive/airflow/dags/raw_training_data_dag.py similarity index 100% rename from airflow/dags/raw_training_data_dag.py rename to archive/airflow/dags/raw_training_data_dag.py diff --git a/airflow/dags/training_results_dag.py b/archive/airflow/dags/training_results_dag.py similarity index 100% rename from airflow/dags/training_results_dag.py rename to archive/airflow/dags/training_results_dag.py diff --git a/airflow/dags/uat_Qa_Dag.py b/archive/airflow/dags/uat_Qa_Dag.py similarity index 100% rename from airflow/dags/uat_Qa_Dag.py rename to archive/airflow/dags/uat_Qa_Dag.py diff --git a/airflow/dags/uat_config_interface_dag .py b/archive/airflow/dags/uat_config_interface_dag .py similarity index 100% rename from airflow/dags/uat_config_interface_dag .py rename to archive/airflow/dags/uat_config_interface_dag .py diff --git a/airflow/dags/uat_raw_training_data_dag.py b/archive/airflow/dags/uat_raw_training_data_dag.py similarity index 100% rename from airflow/dags/uat_raw_training_data_dag.py rename to archive/airflow/dags/uat_raw_training_data_dag.py diff --git a/airflow/poetry.lock b/archive/airflow/poetry.lock similarity index 100% rename from airflow/poetry.lock rename to archive/airflow/poetry.lock diff --git a/airflow/pyproject.toml b/archive/airflow/pyproject.toml similarity index 100% rename from airflow/pyproject.toml rename to archive/airflow/pyproject.toml diff --git a/airflow/tests/example_test.py b/archive/airflow/tests/example_test.py similarity index 100% rename from airflow/tests/example_test.py rename to archive/airflow/tests/example_test.py diff --git a/devops-pipeline/other-resources/locals.tf b/archive/devops-pipeline/other-resources/locals.tf similarity index 100% rename from devops-pipeline/other-resources/locals.tf rename to archive/devops-pipeline/other-resources/locals.tf diff --git a/devops-pipeline/other-resources/main.tf b/archive/devops-pipeline/other-resources/main.tf similarity index 100% rename from devops-pipeline/other-resources/main.tf rename to archive/devops-pipeline/other-resources/main.tf diff --git a/devops-pipeline/other-resources/outputs.tf b/archive/devops-pipeline/other-resources/outputs.tf similarity index 100% rename from devops-pipeline/other-resources/outputs.tf rename to archive/devops-pipeline/other-resources/outputs.tf diff --git a/devops-pipeline/other-resources/variables.tf b/archive/devops-pipeline/other-resources/variables.tf similarity index 100% rename from devops-pipeline/other-resources/variables.tf rename to archive/devops-pipeline/other-resources/variables.tf diff --git a/devops-pipeline/other-resources/vars-dev.tfvars b/archive/devops-pipeline/other-resources/vars-dev.tfvars similarity index 100% rename from devops-pipeline/other-resources/vars-dev.tfvars rename to archive/devops-pipeline/other-resources/vars-dev.tfvars diff --git a/devops-pipeline/other-resources/vars-prod.tfvars b/archive/devops-pipeline/other-resources/vars-prod.tfvars similarity index 100% rename from devops-pipeline/other-resources/vars-prod.tfvars rename to archive/devops-pipeline/other-resources/vars-prod.tfvars diff --git a/devops-pipeline/other-resources/vars-uat.tfvars b/archive/devops-pipeline/other-resources/vars-uat.tfvars similarity index 100% rename from devops-pipeline/other-resources/vars-uat.tfvars rename to archive/devops-pipeline/other-resources/vars-uat.tfvars diff --git a/devops-pipeline/terraform-backend-resources/main.tf b/archive/devops-pipeline/terraform-backend-resources/main.tf similarity index 100% rename from devops-pipeline/terraform-backend-resources/main.tf rename to archive/devops-pipeline/terraform-backend-resources/main.tf diff --git a/devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/locals.tf b/archive/devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/locals.tf similarity index 100% rename from devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/locals.tf rename to archive/devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/locals.tf diff --git a/devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/main.tf b/archive/devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/main.tf similarity index 100% rename from devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/main.tf rename to archive/devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/main.tf diff --git a/devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/outputs.tf b/archive/devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/outputs.tf similarity index 100% rename from devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/outputs.tf rename to archive/devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/outputs.tf diff --git a/devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/variables.tf b/archive/devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/variables.tf similarity index 100% rename from devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/variables.tf rename to archive/devops-pipeline/terraform-backend-resources/modules/aws-terraform-remote-backend/variables.tf diff --git a/devops-pipeline/terraform-backend-resources/outputs.tf b/archive/devops-pipeline/terraform-backend-resources/outputs.tf similarity index 100% rename from devops-pipeline/terraform-backend-resources/outputs.tf rename to archive/devops-pipeline/terraform-backend-resources/outputs.tf diff --git a/devops-pipeline/terraform-backend-resources/variables.tf b/archive/devops-pipeline/terraform-backend-resources/variables.tf similarity index 100% rename from devops-pipeline/terraform-backend-resources/variables.tf rename to archive/devops-pipeline/terraform-backend-resources/variables.tf diff --git a/devops-pipeline/terraform-backend-resources/vars-dev.tfvars b/archive/devops-pipeline/terraform-backend-resources/vars-dev.tfvars similarity index 100% rename from devops-pipeline/terraform-backend-resources/vars-dev.tfvars rename to archive/devops-pipeline/terraform-backend-resources/vars-dev.tfvars diff --git a/devops-pipeline/terraform-backend-resources/vars-prod.tfvars b/archive/devops-pipeline/terraform-backend-resources/vars-prod.tfvars similarity index 100% rename from devops-pipeline/terraform-backend-resources/vars-prod.tfvars rename to archive/devops-pipeline/terraform-backend-resources/vars-prod.tfvars diff --git a/devops-pipeline/terraform-backend-resources/vars-uat.tfvars b/archive/devops-pipeline/terraform-backend-resources/vars-uat.tfvars similarity index 100% rename from devops-pipeline/terraform-backend-resources/vars-uat.tfvars rename to archive/devops-pipeline/terraform-backend-resources/vars-uat.tfvars diff --git a/git_diff_changes.py b/archive/git_diff_changes.py similarity index 100% rename from git_diff_changes.py rename to archive/git_diff_changes.py diff --git a/ops_scripts/CNC/de_duplication_script.ipynb b/archive/ops_scripts/CNC/de_duplication_script.ipynb similarity index 100% rename from ops_scripts/CNC/de_duplication_script.ipynb rename to archive/ops_scripts/CNC/de_duplication_script.ipynb diff --git a/ops_scripts/CNC/diff_checker_universal.py b/archive/ops_scripts/CNC/diff_checker_universal.py similarity index 100% rename from ops_scripts/CNC/diff_checker_universal.py rename to archive/ops_scripts/CNC/diff_checker_universal.py diff --git a/ops_scripts/CNC/local_pdf_files_info.py b/archive/ops_scripts/CNC/local_pdf_files_info.py similarity index 100% rename from ops_scripts/CNC/local_pdf_files_info.py rename to archive/ops_scripts/CNC/local_pdf_files_info.py diff --git a/ops_scripts/CNC/local_search_files_from_csv.py b/archive/ops_scripts/CNC/local_search_files_from_csv.py similarity index 100% rename from ops_scripts/CNC/local_search_files_from_csv.py rename to archive/ops_scripts/CNC/local_search_files_from_csv.py diff --git a/ops_scripts/CNC/misc_scripts.ipynb b/archive/ops_scripts/CNC/misc_scripts.ipynb similarity index 100% rename from ops_scripts/CNC/misc_scripts.ipynb rename to archive/ops_scripts/CNC/misc_scripts.ipynb diff --git a/ops_scripts/CNC/s3_move_files_with_extension.py b/archive/ops_scripts/CNC/s3_move_files_with_extension.py similarity index 100% rename from ops_scripts/CNC/s3_move_files_with_extension.py rename to archive/ops_scripts/CNC/s3_move_files_with_extension.py diff --git a/ops_scripts/CNC/s3_search_and_copy_bucket.ipynb b/archive/ops_scripts/CNC/s3_search_and_copy_bucket.ipynb similarity index 100% rename from ops_scripts/CNC/s3_search_and_copy_bucket.ipynb rename to archive/ops_scripts/CNC/s3_search_and_copy_bucket.ipynb diff --git a/ops_scripts/CNC/s3_search_and_copy_bucket.py b/archive/ops_scripts/CNC/s3_search_and_copy_bucket.py similarity index 100% rename from ops_scripts/CNC/s3_search_and_copy_bucket.py rename to archive/ops_scripts/CNC/s3_search_and_copy_bucket.py diff --git a/ops_scripts/CNC/s3_search_and_copy_prefix.py b/archive/ops_scripts/CNC/s3_search_and_copy_prefix.py similarity index 100% rename from ops_scripts/CNC/s3_search_and_copy_prefix.py rename to archive/ops_scripts/CNC/s3_search_and_copy_prefix.py diff --git a/ops_scripts/CNC/s3_txt_files_info.py b/archive/ops_scripts/CNC/s3_txt_files_info.py similarity index 100% rename from ops_scripts/CNC/s3_txt_files_info.py rename to archive/ops_scripts/CNC/s3_txt_files_info.py diff --git a/ops_scripts/Centene Texas/list_files_in_s3_prefix.py b/archive/ops_scripts/Centene Texas/list_files_in_s3_prefix.py similarity index 100% rename from ops_scripts/Centene Texas/list_files_in_s3_prefix.py rename to archive/ops_scripts/Centene Texas/list_files_in_s3_prefix.py diff --git a/ops_scripts/Centene Texas/normalize_filenames_and_copy_to_s3.py b/archive/ops_scripts/Centene Texas/normalize_filenames_and_copy_to_s3.py similarity index 100% rename from ops_scripts/Centene Texas/normalize_filenames_and_copy_to_s3.py rename to archive/ops_scripts/Centene Texas/normalize_filenames_and_copy_to_s3.py diff --git a/ops_scripts/cost_analysis/aws_cost_automation.py b/archive/ops_scripts/cost_analysis/aws_cost_automation.py similarity index 100% rename from ops_scripts/cost_analysis/aws_cost_automation.py rename to archive/ops_scripts/cost_analysis/aws_cost_automation.py diff --git a/ops_scripts/generic/archiving_s3_cli.ipynb b/archive/ops_scripts/generic/archiving_s3_cli.ipynb similarity index 100% rename from ops_scripts/generic/archiving_s3_cli.ipynb rename to archive/ops_scripts/generic/archiving_s3_cli.ipynb diff --git a/ops_scripts/generic/complex_tables_files_movement.py b/archive/ops_scripts/generic/complex_tables_files_movement.py similarity index 100% rename from ops_scripts/generic/complex_tables_files_movement.py rename to archive/ops_scripts/generic/complex_tables_files_movement.py diff --git a/ops_scripts/generic/excel_s3_diff.py b/archive/ops_scripts/generic/excel_s3_diff.py similarity index 100% rename from ops_scripts/generic/excel_s3_diff.py rename to archive/ops_scripts/generic/excel_s3_diff.py diff --git a/ops_scripts/generic/new_textract_file_reconciliation.py b/archive/ops_scripts/generic/new_textract_file_reconciliation.py similarity index 100% rename from ops_scripts/generic/new_textract_file_reconciliation.py rename to archive/ops_scripts/generic/new_textract_file_reconciliation.py diff --git a/ops_scripts/generic/s3_prefix_search_and_copy.py b/archive/ops_scripts/generic/s3_prefix_search_and_copy.py similarity index 100% rename from ops_scripts/generic/s3_prefix_search_and_copy.py rename to archive/ops_scripts/generic/s3_prefix_search_and_copy.py diff --git a/ops_scripts/generic/scheduler.py b/archive/ops_scripts/generic/scheduler.py similarity index 100% rename from ops_scripts/generic/scheduler.py rename to archive/ops_scripts/generic/scheduler.py diff --git a/ops_scripts/generic/t_drive_search.py b/archive/ops_scripts/generic/t_drive_search.py similarity index 100% rename from ops_scripts/generic/t_drive_search.py rename to archive/ops_scripts/generic/t_drive_search.py diff --git a/ops_scripts/generic/textract_file_reconciliation.py b/archive/ops_scripts/generic/textract_file_reconciliation.py similarity index 100% rename from ops_scripts/generic/textract_file_reconciliation.py rename to archive/ops_scripts/generic/textract_file_reconciliation.py diff --git a/fieldExtraction/scripts/adhoc/cnc_adhoc_stitching_1.py b/archive/scripts/adhoc/cnc_adhoc_stitching_1.py similarity index 100% rename from fieldExtraction/scripts/adhoc/cnc_adhoc_stitching_1.py rename to archive/scripts/adhoc/cnc_adhoc_stitching_1.py diff --git a/fieldExtraction/scripts/adhoc/cnc_adhoc_stitching_2.py b/archive/scripts/adhoc/cnc_adhoc_stitching_2.py similarity index 100% rename from fieldExtraction/scripts/adhoc/cnc_adhoc_stitching_2.py rename to archive/scripts/adhoc/cnc_adhoc_stitching_2.py diff --git a/fieldExtraction/scripts/adhoc/cnc_adhoc_stitching_3.py b/archive/scripts/adhoc/cnc_adhoc_stitching_3.py similarity index 100% rename from fieldExtraction/scripts/adhoc/cnc_adhoc_stitching_3.py rename to archive/scripts/adhoc/cnc_adhoc_stitching_3.py diff --git a/fieldExtraction/scripts/adhoc/cnc_prov2_effdate.py b/archive/scripts/adhoc/cnc_prov2_effdate.py similarity index 100% rename from fieldExtraction/scripts/adhoc/cnc_prov2_effdate.py rename to archive/scripts/adhoc/cnc_prov2_effdate.py diff --git a/fieldExtraction/scripts/adhoc/combine_ac2_and_b.py b/archive/scripts/adhoc/combine_ac2_and_b.py similarity index 100% rename from fieldExtraction/scripts/adhoc/combine_ac2_and_b.py rename to archive/scripts/adhoc/combine_ac2_and_b.py diff --git a/fieldExtraction/scripts/adhoc/consolidate_ac2.py b/archive/scripts/adhoc/consolidate_ac2.py similarity index 100% rename from fieldExtraction/scripts/adhoc/consolidate_ac2.py rename to archive/scripts/adhoc/consolidate_ac2.py diff --git a/fieldExtraction/scripts/adhoc/tx_ac_no_reimbursement.py b/archive/scripts/adhoc/tx_ac_no_reimbursement.py similarity index 100% rename from fieldExtraction/scripts/adhoc/tx_ac_no_reimbursement.py rename to archive/scripts/adhoc/tx_ac_no_reimbursement.py diff --git a/fieldExtraction/scripts/adhoc/unit_test.py b/archive/scripts/adhoc/unit_test.py similarity index 100% rename from fieldExtraction/scripts/adhoc/unit_test.py rename to archive/scripts/adhoc/unit_test.py diff --git a/fieldExtraction/scripts/cnc_hotfixes/apply_cnc_hotfix.py b/archive/scripts/cnc_hotfixes/apply_cnc_hotfix.py similarity index 100% rename from fieldExtraction/scripts/cnc_hotfixes/apply_cnc_hotfix.py rename to archive/scripts/cnc_hotfixes/apply_cnc_hotfix.py diff --git a/fieldExtraction/scripts/cnc_hotfixes/cnc_hotfix.py b/archive/scripts/cnc_hotfixes/cnc_hotfix.py similarity index 99% rename from fieldExtraction/scripts/cnc_hotfixes/cnc_hotfix.py rename to archive/scripts/cnc_hotfixes/cnc_hotfix.py index 2c227fe..5e2c109 100644 --- a/fieldExtraction/scripts/cnc_hotfixes/cnc_hotfix.py +++ b/archive/scripts/cnc_hotfixes/cnc_hotfix.py @@ -22,7 +22,7 @@ import config import keywords import postprocessing_funcs import prompts -import smart_chunking_funcs +import hybrid_smart_chunking_funcs import string_funcs import valid from hotfix_helper_funcs import (check_field_for_matches, @@ -755,7 +755,7 @@ def clean_agreement_name(df: pd.DataFrame, if prompt_answer_raw == "N/A": agreement_keywords = ["AGREEMENT", "AMENDMENT", "ADDENDUM", "PROVIDER", "CONTRACT", "MEMORANDUM", "LETTER", "REQUEST", "EFFECTIVE"] - page_list = smart_chunking_funcs.chunk_hierarchical( + page_list = hybrid_smart_chunking_funcs.chunk_hierarchical( text_dict, agreement_keywords, False ) context = "\n".join( diff --git a/fieldExtraction/scripts/cnc_hotfixes/cnc_hotfix_effective_date_utils.py b/archive/scripts/cnc_hotfixes/cnc_hotfix_effective_date_utils.py similarity index 97% rename from fieldExtraction/scripts/cnc_hotfixes/cnc_hotfix_effective_date_utils.py rename to archive/scripts/cnc_hotfixes/cnc_hotfix_effective_date_utils.py index f40c046..7ec8ea5 100644 --- a/fieldExtraction/scripts/cnc_hotfixes/cnc_hotfix_effective_date_utils.py +++ b/archive/scripts/cnc_hotfixes/cnc_hotfix_effective_date_utils.py @@ -1,6 +1,6 @@ import re -import smart_chunking_funcs +import hybrid_smart_chunking_funcs regex_backticks = r"\|([^|]+)\|" @@ -66,7 +66,7 @@ def chunk_with_include_exclude_keywords( pages_containing_date = set() for page_num, page_content in text_dict.items(): - dates_list = re.findall(smart_chunking_funcs.DATE_PATTERN, page_content) + dates_list = re.findall(hybrid_smart_chunking_funcs.DATE_PATTERN, page_content) if len(dates_list) > 0: pages_containing_date.add(page_num) diff --git a/fieldExtraction/scripts/cnc_hotfixes/hotfix_helper_funcs.py b/archive/scripts/cnc_hotfixes/hotfix_helper_funcs.py similarity index 100% rename from fieldExtraction/scripts/cnc_hotfixes/hotfix_helper_funcs.py rename to archive/scripts/cnc_hotfixes/hotfix_helper_funcs.py diff --git a/fieldExtraction/scripts/cnc_hotfixes/hotfix_stitch.py b/archive/scripts/cnc_hotfixes/hotfix_stitch.py similarity index 100% rename from fieldExtraction/scripts/cnc_hotfixes/hotfix_stitch.py rename to archive/scripts/cnc_hotfixes/hotfix_stitch.py diff --git a/fieldExtraction/scripts/cnc_hotfixes/hotfix_stitch_1A.py b/archive/scripts/cnc_hotfixes/hotfix_stitch_1A.py similarity index 100% rename from fieldExtraction/scripts/cnc_hotfixes/hotfix_stitch_1A.py rename to archive/scripts/cnc_hotfixes/hotfix_stitch_1A.py diff --git a/fieldExtraction/scripts/cnc_hotfixes/hotfix_stitch_1B.py b/archive/scripts/cnc_hotfixes/hotfix_stitch_1B.py similarity index 100% rename from fieldExtraction/scripts/cnc_hotfixes/hotfix_stitch_1B.py rename to archive/scripts/cnc_hotfixes/hotfix_stitch_1B.py diff --git a/snowflake/DEV/R__001_LOG_AUDIT.sql b/archive/snowflake/DEV/R__001_LOG_AUDIT.sql similarity index 100% rename from snowflake/DEV/R__001_LOG_AUDIT.sql rename to archive/snowflake/DEV/R__001_LOG_AUDIT.sql diff --git a/snowflake/DEV/R__002_LOG_AUDIT_TABLE.sql b/archive/snowflake/DEV/R__002_LOG_AUDIT_TABLE.sql similarity index 100% rename from snowflake/DEV/R__002_LOG_AUDIT_TABLE.sql rename to archive/snowflake/DEV/R__002_LOG_AUDIT_TABLE.sql diff --git a/snowflake/DEV/config_interface/R__001_PROMPT_CONFIG_TABLE.sql b/archive/snowflake/DEV/config_interface/R__001_PROMPT_CONFIG_TABLE.sql similarity index 100% rename from snowflake/DEV/config_interface/R__001_PROMPT_CONFIG_TABLE.sql rename to archive/snowflake/DEV/config_interface/R__001_PROMPT_CONFIG_TABLE.sql diff --git a/snowflake/DEV/config_interface/R__002_CONTRACT_CONFIG_TABLE.sql b/archive/snowflake/DEV/config_interface/R__002_CONTRACT_CONFIG_TABLE.sql similarity index 100% rename from snowflake/DEV/config_interface/R__002_CONTRACT_CONFIG_TABLE.sql rename to archive/snowflake/DEV/config_interface/R__002_CONTRACT_CONFIG_TABLE.sql diff --git a/snowflake/DEV/config_interface/R__003_REQUEST_SUBMISSION_TABLE.sql b/archive/snowflake/DEV/config_interface/R__003_REQUEST_SUBMISSION_TABLE.sql similarity index 100% rename from snowflake/DEV/config_interface/R__003_REQUEST_SUBMISSION_TABLE.sql rename to archive/snowflake/DEV/config_interface/R__003_REQUEST_SUBMISSION_TABLE.sql diff --git a/snowflake/DEV/config_interface/R__004_LOAD_CONTRACT_CONFIG_SP.sql b/archive/snowflake/DEV/config_interface/R__004_LOAD_CONTRACT_CONFIG_SP.sql similarity index 100% rename from snowflake/DEV/config_interface/R__004_LOAD_CONTRACT_CONFIG_SP.sql rename to archive/snowflake/DEV/config_interface/R__004_LOAD_CONTRACT_CONFIG_SP.sql diff --git a/snowflake/DEV/config_interface/R__005_LOAD_REQUEST_SUBMISSION_SP.sql b/archive/snowflake/DEV/config_interface/R__005_LOAD_REQUEST_SUBMISSION_SP.sql similarity index 100% rename from snowflake/DEV/config_interface/R__005_LOAD_REQUEST_SUBMISSION_SP.sql rename to archive/snowflake/DEV/config_interface/R__005_LOAD_REQUEST_SUBMISSION_SP.sql diff --git a/snowflake/DEV/config_interface/R__006_PIPELINE_OUTPUT.sql b/archive/snowflake/DEV/config_interface/R__006_PIPELINE_OUTPUT.sql similarity index 100% rename from snowflake/DEV/config_interface/R__006_PIPELINE_OUTPUT.sql rename to archive/snowflake/DEV/config_interface/R__006_PIPELINE_OUTPUT.sql diff --git a/snowflake/DEV/config_interface/R__007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql b/archive/snowflake/DEV/config_interface/R__007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql similarity index 100% rename from snowflake/DEV/config_interface/R__007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql rename to archive/snowflake/DEV/config_interface/R__007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql diff --git a/snowflake/DEV/config_interface/R__008_PIPELINE_PROCESSED_OUTPUT.sql b/archive/snowflake/DEV/config_interface/R__008_PIPELINE_PROCESSED_OUTPUT.sql similarity index 100% rename from snowflake/DEV/config_interface/R__008_PIPELINE_PROCESSED_OUTPUT.sql rename to archive/snowflake/DEV/config_interface/R__008_PIPELINE_PROCESSED_OUTPUT.sql diff --git a/snowflake/DEV/config_interface/R__009_LOAD_PIPELINE_PROCESSED_OUTPUTS_SP.sql b/archive/snowflake/DEV/config_interface/R__009_LOAD_PIPELINE_PROCESSED_OUTPUTS_SP.sql similarity index 100% rename from snowflake/DEV/config_interface/R__009_LOAD_PIPELINE_PROCESSED_OUTPUTS_SP.sql rename to archive/snowflake/DEV/config_interface/R__009_LOAD_PIPELINE_PROCESSED_OUTPUTS_SP.sql diff --git a/snowflake/DEV/system_wide/R__001_SERVERLESS_LOGS_TABLE.sql b/archive/snowflake/DEV/system_wide/R__001_SERVERLESS_LOGS_TABLE.sql similarity index 100% rename from snowflake/DEV/system_wide/R__001_SERVERLESS_LOGS_TABLE.sql rename to archive/snowflake/DEV/system_wide/R__001_SERVERLESS_LOGS_TABLE.sql diff --git a/snowflake/DEV/training_interface/R__001_INIT_OBJS.sql b/archive/snowflake/DEV/training_interface/R__001_INIT_OBJS.sql similarity index 100% rename from snowflake/DEV/training_interface/R__001_INIT_OBJS.sql rename to archive/snowflake/DEV/training_interface/R__001_INIT_OBJS.sql diff --git a/snowflake/DEV/training_interface/R__002_LOAD_TRAINING_RESULTS_SP.SQL b/archive/snowflake/DEV/training_interface/R__002_LOAD_TRAINING_RESULTS_SP.SQL similarity index 100% rename from snowflake/DEV/training_interface/R__002_LOAD_TRAINING_RESULTS_SP.SQL rename to archive/snowflake/DEV/training_interface/R__002_LOAD_TRAINING_RESULTS_SP.SQL diff --git a/snowflake/DEV/training_interface/R__003_LOAD_ATTEMPTS_SP.sql b/archive/snowflake/DEV/training_interface/R__003_LOAD_ATTEMPTS_SP.sql similarity index 100% rename from snowflake/DEV/training_interface/R__003_LOAD_ATTEMPTS_SP.sql rename to archive/snowflake/DEV/training_interface/R__003_LOAD_ATTEMPTS_SP.sql diff --git a/snowflake/DEV/training_interface/R__004_CREATE_TRAINING_DATA_TABLE_SP.sql b/archive/snowflake/DEV/training_interface/R__004_CREATE_TRAINING_DATA_TABLE_SP.sql similarity index 100% rename from snowflake/DEV/training_interface/R__004_CREATE_TRAINING_DATA_TABLE_SP.sql rename to archive/snowflake/DEV/training_interface/R__004_CREATE_TRAINING_DATA_TABLE_SP.sql diff --git a/snowflake/DEV/training_interface/R__005_LOAD_COLUMN_CONFIG_SP.sql b/archive/snowflake/DEV/training_interface/R__005_LOAD_COLUMN_CONFIG_SP.sql similarity index 100% rename from snowflake/DEV/training_interface/R__005_LOAD_COLUMN_CONFIG_SP.sql rename to archive/snowflake/DEV/training_interface/R__005_LOAD_COLUMN_CONFIG_SP.sql diff --git a/snowflake/DEV/training_interface/R__006_LOAD_TRAINING_DATA_RAW_SP.sql b/archive/snowflake/DEV/training_interface/R__006_LOAD_TRAINING_DATA_RAW_SP.sql similarity index 100% rename from snowflake/DEV/training_interface/R__006_LOAD_TRAINING_DATA_RAW_SP.sql rename to archive/snowflake/DEV/training_interface/R__006_LOAD_TRAINING_DATA_RAW_SP.sql diff --git a/snowflake/DEV/training_interface/R__007_CREATE_BUSINESS_CONFIG_objects.sql b/archive/snowflake/DEV/training_interface/R__007_CREATE_BUSINESS_CONFIG_objects.sql similarity index 100% rename from snowflake/DEV/training_interface/R__007_CREATE_BUSINESS_CONFIG_objects.sql rename to archive/snowflake/DEV/training_interface/R__007_CREATE_BUSINESS_CONFIG_objects.sql diff --git a/snowflake/DEV/training_interface/R__008_LOAD_BUSINESS_CONFIG_SP.sql b/archive/snowflake/DEV/training_interface/R__008_LOAD_BUSINESS_CONFIG_SP.sql similarity index 100% rename from snowflake/DEV/training_interface/R__008_LOAD_BUSINESS_CONFIG_SP.sql rename to archive/snowflake/DEV/training_interface/R__008_LOAD_BUSINESS_CONFIG_SP.sql diff --git a/snowflake/DEV/upload_interface/R__001_CLIENT_CONFIG_TABLE.sql b/archive/snowflake/DEV/upload_interface/R__001_CLIENT_CONFIG_TABLE.sql similarity index 100% rename from snowflake/DEV/upload_interface/R__001_CLIENT_CONFIG_TABLE.sql rename to archive/snowflake/DEV/upload_interface/R__001_CLIENT_CONFIG_TABLE.sql diff --git a/snowflake/DEV/upload_interface/R__002_LOAD_CLIENT_CONFIG_SP.sql b/archive/snowflake/DEV/upload_interface/R__002_LOAD_CLIENT_CONFIG_SP.sql similarity index 100% rename from snowflake/DEV/upload_interface/R__002_LOAD_CLIENT_CONFIG_SP.sql rename to archive/snowflake/DEV/upload_interface/R__002_LOAD_CLIENT_CONFIG_SP.sql diff --git a/snowflake/DEV/upload_interface/R__003_CONTRACT_UPLOAD_LOGS.sql b/archive/snowflake/DEV/upload_interface/R__003_CONTRACT_UPLOAD_LOGS.sql similarity index 100% rename from snowflake/DEV/upload_interface/R__003_CONTRACT_UPLOAD_LOGS.sql rename to archive/snowflake/DEV/upload_interface/R__003_CONTRACT_UPLOAD_LOGS.sql diff --git a/snowflake/PROD/R__2001_LOG_AUDIT.sql b/archive/snowflake/PROD/R__2001_LOG_AUDIT.sql similarity index 100% rename from snowflake/PROD/R__2001_LOG_AUDIT.sql rename to archive/snowflake/PROD/R__2001_LOG_AUDIT.sql diff --git a/snowflake/PROD/R__2002_LOG_AUDIT_TABLE.sql b/archive/snowflake/PROD/R__2002_LOG_AUDIT_TABLE.sql similarity index 100% rename from snowflake/PROD/R__2002_LOG_AUDIT_TABLE.sql rename to archive/snowflake/PROD/R__2002_LOG_AUDIT_TABLE.sql diff --git a/snowflake/PROD/config_interface/R__2001_UAT_PROMPT_CONFIG_TABLE.sql b/archive/snowflake/PROD/config_interface/R__2001_UAT_PROMPT_CONFIG_TABLE.sql similarity index 100% rename from snowflake/PROD/config_interface/R__2001_UAT_PROMPT_CONFIG_TABLE.sql rename to archive/snowflake/PROD/config_interface/R__2001_UAT_PROMPT_CONFIG_TABLE.sql diff --git a/snowflake/PROD/config_interface/R__2002_UAT_CONTRACT_CONFIG_TABLE.sql b/archive/snowflake/PROD/config_interface/R__2002_UAT_CONTRACT_CONFIG_TABLE.sql similarity index 100% rename from snowflake/PROD/config_interface/R__2002_UAT_CONTRACT_CONFIG_TABLE.sql rename to archive/snowflake/PROD/config_interface/R__2002_UAT_CONTRACT_CONFIG_TABLE.sql diff --git a/snowflake/PROD/config_interface/R__2003_REQUEST_SUBMISSION_TABLE.sql b/archive/snowflake/PROD/config_interface/R__2003_REQUEST_SUBMISSION_TABLE.sql similarity index 100% rename from snowflake/PROD/config_interface/R__2003_REQUEST_SUBMISSION_TABLE.sql rename to archive/snowflake/PROD/config_interface/R__2003_REQUEST_SUBMISSION_TABLE.sql diff --git a/snowflake/PROD/config_interface/R__2004_LOAD_CONTRACT_CONFIG_SP.sql b/archive/snowflake/PROD/config_interface/R__2004_LOAD_CONTRACT_CONFIG_SP.sql similarity index 100% rename from snowflake/PROD/config_interface/R__2004_LOAD_CONTRACT_CONFIG_SP.sql rename to archive/snowflake/PROD/config_interface/R__2004_LOAD_CONTRACT_CONFIG_SP.sql diff --git a/snowflake/PROD/config_interface/R__2005_LOAD_REQUEST_SUBMISSION_SP.sql b/archive/snowflake/PROD/config_interface/R__2005_LOAD_REQUEST_SUBMISSION_SP.sql similarity index 100% rename from snowflake/PROD/config_interface/R__2005_LOAD_REQUEST_SUBMISSION_SP.sql rename to archive/snowflake/PROD/config_interface/R__2005_LOAD_REQUEST_SUBMISSION_SP.sql diff --git a/snowflake/PROD/config_interface/R__2006_PIPELINE_OUTPUT.sql b/archive/snowflake/PROD/config_interface/R__2006_PIPELINE_OUTPUT.sql similarity index 100% rename from snowflake/PROD/config_interface/R__2006_PIPELINE_OUTPUT.sql rename to archive/snowflake/PROD/config_interface/R__2006_PIPELINE_OUTPUT.sql diff --git a/snowflake/PROD/config_interface/R__2007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql b/archive/snowflake/PROD/config_interface/R__2007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql similarity index 100% rename from snowflake/PROD/config_interface/R__2007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql rename to archive/snowflake/PROD/config_interface/R__2007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql diff --git a/snowflake/PROD/config_interface/R__2008_PIPELINE_OUTPUT_B_FIELDS.sql b/archive/snowflake/PROD/config_interface/R__2008_PIPELINE_OUTPUT_B_FIELDS.sql similarity index 100% rename from snowflake/PROD/config_interface/R__2008_PIPELINE_OUTPUT_B_FIELDS.sql rename to archive/snowflake/PROD/config_interface/R__2008_PIPELINE_OUTPUT_B_FIELDS.sql diff --git a/snowflake/PROD/config_interface/R__2009_LOAD_B_FIELDS_PIPELINE_RAW_OUTPUT.sql b/archive/snowflake/PROD/config_interface/R__2009_LOAD_B_FIELDS_PIPELINE_RAW_OUTPUT.sql similarity index 100% rename from snowflake/PROD/config_interface/R__2009_LOAD_B_FIELDS_PIPELINE_RAW_OUTPUT.sql rename to archive/snowflake/PROD/config_interface/R__2009_LOAD_B_FIELDS_PIPELINE_RAW_OUTPUT.sql diff --git a/snowflake/PROD/system_wide/R__2001_SERVERLESS_LOGS_TABLE.sql b/archive/snowflake/PROD/system_wide/R__2001_SERVERLESS_LOGS_TABLE.sql similarity index 100% rename from snowflake/PROD/system_wide/R__2001_SERVERLESS_LOGS_TABLE.sql rename to archive/snowflake/PROD/system_wide/R__2001_SERVERLESS_LOGS_TABLE.sql diff --git a/snowflake/PROD/training_interface/R__2001_INIT_OBJS.sql b/archive/snowflake/PROD/training_interface/R__2001_INIT_OBJS.sql similarity index 100% rename from snowflake/PROD/training_interface/R__2001_INIT_OBJS.sql rename to archive/snowflake/PROD/training_interface/R__2001_INIT_OBJS.sql diff --git a/snowflake/PROD/training_interface/R__2002_LOAD_TRAINING_RESULTS_SP.SQL b/archive/snowflake/PROD/training_interface/R__2002_LOAD_TRAINING_RESULTS_SP.SQL similarity index 100% rename from snowflake/PROD/training_interface/R__2002_LOAD_TRAINING_RESULTS_SP.SQL rename to archive/snowflake/PROD/training_interface/R__2002_LOAD_TRAINING_RESULTS_SP.SQL diff --git a/snowflake/PROD/training_interface/R__2003_LOAD_ATTEMPTS_SP.sql b/archive/snowflake/PROD/training_interface/R__2003_LOAD_ATTEMPTS_SP.sql similarity index 100% rename from snowflake/PROD/training_interface/R__2003_LOAD_ATTEMPTS_SP.sql rename to archive/snowflake/PROD/training_interface/R__2003_LOAD_ATTEMPTS_SP.sql diff --git a/snowflake/PROD/training_interface/R__2004_CREATE_TRAINING_DATA_TABLE_SP.sql b/archive/snowflake/PROD/training_interface/R__2004_CREATE_TRAINING_DATA_TABLE_SP.sql similarity index 100% rename from snowflake/PROD/training_interface/R__2004_CREATE_TRAINING_DATA_TABLE_SP.sql rename to archive/snowflake/PROD/training_interface/R__2004_CREATE_TRAINING_DATA_TABLE_SP.sql diff --git a/snowflake/PROD/training_interface/R__2005_LOAD_COLUMN_CONFIG_SP.sql b/archive/snowflake/PROD/training_interface/R__2005_LOAD_COLUMN_CONFIG_SP.sql similarity index 100% rename from snowflake/PROD/training_interface/R__2005_LOAD_COLUMN_CONFIG_SP.sql rename to archive/snowflake/PROD/training_interface/R__2005_LOAD_COLUMN_CONFIG_SP.sql diff --git a/snowflake/PROD/training_interface/R__2006_LOAD_TRAINING_DATA_RAW_SP.sql b/archive/snowflake/PROD/training_interface/R__2006_LOAD_TRAINING_DATA_RAW_SP.sql similarity index 100% rename from snowflake/PROD/training_interface/R__2006_LOAD_TRAINING_DATA_RAW_SP.sql rename to archive/snowflake/PROD/training_interface/R__2006_LOAD_TRAINING_DATA_RAW_SP.sql diff --git a/snowflake/PROD/training_interface/R__2007_CREATE_BUSINESS_CONFIG_objects.sql b/archive/snowflake/PROD/training_interface/R__2007_CREATE_BUSINESS_CONFIG_objects.sql similarity index 100% rename from snowflake/PROD/training_interface/R__2007_CREATE_BUSINESS_CONFIG_objects.sql rename to archive/snowflake/PROD/training_interface/R__2007_CREATE_BUSINESS_CONFIG_objects.sql diff --git a/snowflake/PROD/training_interface/R__2008_LOAD_BUSINESS_CONFIG_SP.sql b/archive/snowflake/PROD/training_interface/R__2008_LOAD_BUSINESS_CONFIG_SP.sql similarity index 100% rename from snowflake/PROD/training_interface/R__2008_LOAD_BUSINESS_CONFIG_SP.sql rename to archive/snowflake/PROD/training_interface/R__2008_LOAD_BUSINESS_CONFIG_SP.sql diff --git a/snowflake/PROD/upload_interface/R__2001_CLIENT_CONFIG_TABLE.sql b/archive/snowflake/PROD/upload_interface/R__2001_CLIENT_CONFIG_TABLE.sql similarity index 100% rename from snowflake/PROD/upload_interface/R__2001_CLIENT_CONFIG_TABLE.sql rename to archive/snowflake/PROD/upload_interface/R__2001_CLIENT_CONFIG_TABLE.sql diff --git a/snowflake/PROD/upload_interface/R__2002_LOAD_CLIENT_CONFIG_SP.sql b/archive/snowflake/PROD/upload_interface/R__2002_LOAD_CLIENT_CONFIG_SP.sql similarity index 100% rename from snowflake/PROD/upload_interface/R__2002_LOAD_CLIENT_CONFIG_SP.sql rename to archive/snowflake/PROD/upload_interface/R__2002_LOAD_CLIENT_CONFIG_SP.sql diff --git a/snowflake/PROD/upload_interface/R__2003_CONTRACT_UPLOAD_LOGS.sql b/archive/snowflake/PROD/upload_interface/R__2003_CONTRACT_UPLOAD_LOGS.sql similarity index 100% rename from snowflake/PROD/upload_interface/R__2003_CONTRACT_UPLOAD_LOGS.sql rename to archive/snowflake/PROD/upload_interface/R__2003_CONTRACT_UPLOAD_LOGS.sql diff --git a/snowflake/UAT/R__1001_LOG_AUDIT.sql b/archive/snowflake/UAT/R__1001_LOG_AUDIT.sql similarity index 100% rename from snowflake/UAT/R__1001_LOG_AUDIT.sql rename to archive/snowflake/UAT/R__1001_LOG_AUDIT.sql diff --git a/snowflake/UAT/R__1002_LOG_AUDIT_TABLE.sql b/archive/snowflake/UAT/R__1002_LOG_AUDIT_TABLE.sql similarity index 100% rename from snowflake/UAT/R__1002_LOG_AUDIT_TABLE.sql rename to archive/snowflake/UAT/R__1002_LOG_AUDIT_TABLE.sql diff --git a/snowflake/UAT/config_interface/R__1001_UAT_PROMPT_CONFIG_TABLE.sql b/archive/snowflake/UAT/config_interface/R__1001_UAT_PROMPT_CONFIG_TABLE.sql similarity index 100% rename from snowflake/UAT/config_interface/R__1001_UAT_PROMPT_CONFIG_TABLE.sql rename to archive/snowflake/UAT/config_interface/R__1001_UAT_PROMPT_CONFIG_TABLE.sql diff --git a/snowflake/UAT/config_interface/R__1002_UAT_CONTRACT_CONFIG_TABLE.sql b/archive/snowflake/UAT/config_interface/R__1002_UAT_CONTRACT_CONFIG_TABLE.sql similarity index 100% rename from snowflake/UAT/config_interface/R__1002_UAT_CONTRACT_CONFIG_TABLE.sql rename to archive/snowflake/UAT/config_interface/R__1002_UAT_CONTRACT_CONFIG_TABLE.sql diff --git a/snowflake/UAT/config_interface/R__1003_REQUEST_SUBMISSION_TABLE.sql b/archive/snowflake/UAT/config_interface/R__1003_REQUEST_SUBMISSION_TABLE.sql similarity index 100% rename from snowflake/UAT/config_interface/R__1003_REQUEST_SUBMISSION_TABLE.sql rename to archive/snowflake/UAT/config_interface/R__1003_REQUEST_SUBMISSION_TABLE.sql diff --git a/snowflake/UAT/config_interface/R__1004_LOAD_CONTRACT_CONFIG_SP.sql b/archive/snowflake/UAT/config_interface/R__1004_LOAD_CONTRACT_CONFIG_SP.sql similarity index 100% rename from snowflake/UAT/config_interface/R__1004_LOAD_CONTRACT_CONFIG_SP.sql rename to archive/snowflake/UAT/config_interface/R__1004_LOAD_CONTRACT_CONFIG_SP.sql diff --git a/snowflake/UAT/config_interface/R__1005_LOAD_REQUEST_SUBMISSION_SP.sql b/archive/snowflake/UAT/config_interface/R__1005_LOAD_REQUEST_SUBMISSION_SP.sql similarity index 100% rename from snowflake/UAT/config_interface/R__1005_LOAD_REQUEST_SUBMISSION_SP.sql rename to archive/snowflake/UAT/config_interface/R__1005_LOAD_REQUEST_SUBMISSION_SP.sql diff --git a/snowflake/UAT/config_interface/R__1006_PIPELINE_OUTPUT.sql b/archive/snowflake/UAT/config_interface/R__1006_PIPELINE_OUTPUT.sql similarity index 100% rename from snowflake/UAT/config_interface/R__1006_PIPELINE_OUTPUT.sql rename to archive/snowflake/UAT/config_interface/R__1006_PIPELINE_OUTPUT.sql diff --git a/snowflake/UAT/config_interface/R__1007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql b/archive/snowflake/UAT/config_interface/R__1007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql similarity index 100% rename from snowflake/UAT/config_interface/R__1007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql rename to archive/snowflake/UAT/config_interface/R__1007_LOAD_DOCZY_PIPELINE_RAW_OPUTPUTS.sql diff --git a/snowflake/UAT/config_interface/R__1008_PIPELINE_OUTPUT_B_FIELDS.sql b/archive/snowflake/UAT/config_interface/R__1008_PIPELINE_OUTPUT_B_FIELDS.sql similarity index 100% rename from snowflake/UAT/config_interface/R__1008_PIPELINE_OUTPUT_B_FIELDS.sql rename to archive/snowflake/UAT/config_interface/R__1008_PIPELINE_OUTPUT_B_FIELDS.sql diff --git a/snowflake/UAT/config_interface/R__1009_LOAD_B_FIELDS_PIPELINE_RAW_OUTPUT.sql b/archive/snowflake/UAT/config_interface/R__1009_LOAD_B_FIELDS_PIPELINE_RAW_OUTPUT.sql similarity index 100% rename from snowflake/UAT/config_interface/R__1009_LOAD_B_FIELDS_PIPELINE_RAW_OUTPUT.sql rename to archive/snowflake/UAT/config_interface/R__1009_LOAD_B_FIELDS_PIPELINE_RAW_OUTPUT.sql diff --git a/snowflake/UAT/system_wide/R__1001_SERVERLESS_LOGS_TABLE.sql b/archive/snowflake/UAT/system_wide/R__1001_SERVERLESS_LOGS_TABLE.sql similarity index 100% rename from snowflake/UAT/system_wide/R__1001_SERVERLESS_LOGS_TABLE.sql rename to archive/snowflake/UAT/system_wide/R__1001_SERVERLESS_LOGS_TABLE.sql diff --git a/snowflake/UAT/training_interface/R__1001_INIT_OBJS.sql b/archive/snowflake/UAT/training_interface/R__1001_INIT_OBJS.sql similarity index 100% rename from snowflake/UAT/training_interface/R__1001_INIT_OBJS.sql rename to archive/snowflake/UAT/training_interface/R__1001_INIT_OBJS.sql diff --git a/snowflake/UAT/training_interface/R__1002_LOAD_TRAINING_RESULTS_SP.SQL b/archive/snowflake/UAT/training_interface/R__1002_LOAD_TRAINING_RESULTS_SP.SQL similarity index 100% rename from snowflake/UAT/training_interface/R__1002_LOAD_TRAINING_RESULTS_SP.SQL rename to archive/snowflake/UAT/training_interface/R__1002_LOAD_TRAINING_RESULTS_SP.SQL diff --git a/snowflake/UAT/training_interface/R__1003_LOAD_ATTEMPTS_SP.sql b/archive/snowflake/UAT/training_interface/R__1003_LOAD_ATTEMPTS_SP.sql similarity index 100% rename from snowflake/UAT/training_interface/R__1003_LOAD_ATTEMPTS_SP.sql rename to archive/snowflake/UAT/training_interface/R__1003_LOAD_ATTEMPTS_SP.sql diff --git a/snowflake/UAT/training_interface/R__1004_CREATE_TRAINING_DATA_TABLE_SP.sql b/archive/snowflake/UAT/training_interface/R__1004_CREATE_TRAINING_DATA_TABLE_SP.sql similarity index 100% rename from snowflake/UAT/training_interface/R__1004_CREATE_TRAINING_DATA_TABLE_SP.sql rename to archive/snowflake/UAT/training_interface/R__1004_CREATE_TRAINING_DATA_TABLE_SP.sql diff --git a/snowflake/UAT/training_interface/R__1005_LOAD_COLUMN_CONFIG_SP.sql b/archive/snowflake/UAT/training_interface/R__1005_LOAD_COLUMN_CONFIG_SP.sql similarity index 100% rename from snowflake/UAT/training_interface/R__1005_LOAD_COLUMN_CONFIG_SP.sql rename to archive/snowflake/UAT/training_interface/R__1005_LOAD_COLUMN_CONFIG_SP.sql diff --git a/snowflake/UAT/training_interface/R__1006_LOAD_TRAINING_DATA_RAW_SP.sql b/archive/snowflake/UAT/training_interface/R__1006_LOAD_TRAINING_DATA_RAW_SP.sql similarity index 100% rename from snowflake/UAT/training_interface/R__1006_LOAD_TRAINING_DATA_RAW_SP.sql rename to archive/snowflake/UAT/training_interface/R__1006_LOAD_TRAINING_DATA_RAW_SP.sql diff --git a/snowflake/UAT/training_interface/R__1007_CREATE_BUSINESS_CONFIG_objects.sql b/archive/snowflake/UAT/training_interface/R__1007_CREATE_BUSINESS_CONFIG_objects.sql similarity index 100% rename from snowflake/UAT/training_interface/R__1007_CREATE_BUSINESS_CONFIG_objects.sql rename to archive/snowflake/UAT/training_interface/R__1007_CREATE_BUSINESS_CONFIG_objects.sql diff --git a/snowflake/UAT/training_interface/R__1008_LOAD_BUSINESS_CONFIG_SP.sql b/archive/snowflake/UAT/training_interface/R__1008_LOAD_BUSINESS_CONFIG_SP.sql similarity index 100% rename from snowflake/UAT/training_interface/R__1008_LOAD_BUSINESS_CONFIG_SP.sql rename to archive/snowflake/UAT/training_interface/R__1008_LOAD_BUSINESS_CONFIG_SP.sql diff --git a/snowflake/UAT/upload_interface/R__1001_CLIENT_CONFIG_TABLE.sql b/archive/snowflake/UAT/upload_interface/R__1001_CLIENT_CONFIG_TABLE.sql similarity index 100% rename from snowflake/UAT/upload_interface/R__1001_CLIENT_CONFIG_TABLE.sql rename to archive/snowflake/UAT/upload_interface/R__1001_CLIENT_CONFIG_TABLE.sql diff --git a/snowflake/UAT/upload_interface/R__1002_LOAD_CLIENT_CONFIG_SP.sql b/archive/snowflake/UAT/upload_interface/R__1002_LOAD_CLIENT_CONFIG_SP.sql similarity index 100% rename from snowflake/UAT/upload_interface/R__1002_LOAD_CLIENT_CONFIG_SP.sql rename to archive/snowflake/UAT/upload_interface/R__1002_LOAD_CLIENT_CONFIG_SP.sql diff --git a/snowflake/UAT/upload_interface/R__1003_CONTRACT_UPLOAD_LOGS.sql b/archive/snowflake/UAT/upload_interface/R__1003_CONTRACT_UPLOAD_LOGS.sql similarity index 100% rename from snowflake/UAT/upload_interface/R__1003_CONTRACT_UPLOAD_LOGS.sql rename to archive/snowflake/UAT/upload_interface/R__1003_CONTRACT_UPLOAD_LOGS.sql diff --git a/streamlit-server/alb.tf b/archive/streamlit-server/alb.tf similarity index 100% rename from streamlit-server/alb.tf rename to archive/streamlit-server/alb.tf diff --git a/streamlit-server/alb_sg.tf b/archive/streamlit-server/alb_sg.tf similarity index 100% rename from streamlit-server/alb_sg.tf rename to archive/streamlit-server/alb_sg.tf diff --git a/streamlit-server/iam.tf b/archive/streamlit-server/iam.tf similarity index 100% rename from streamlit-server/iam.tf rename to archive/streamlit-server/iam.tf diff --git a/streamlit-server/main.tf b/archive/streamlit-server/main.tf similarity index 100% rename from streamlit-server/main.tf rename to archive/streamlit-server/main.tf diff --git a/streamlit-server/requirements.txt b/archive/streamlit-server/requirements.txt similarity index 100% rename from streamlit-server/requirements.txt rename to archive/streamlit-server/requirements.txt diff --git a/streamlit-server/user_data.sh b/archive/streamlit-server/user_data.sh similarity index 100% rename from streamlit-server/user_data.sh rename to archive/streamlit-server/user_data.sh diff --git a/streamlit-server/variables.tf b/archive/streamlit-server/variables.tf similarity index 100% rename from streamlit-server/variables.tf rename to archive/streamlit-server/variables.tf diff --git a/streamlit-server/vars-dev.tfvars b/archive/streamlit-server/vars-dev.tfvars similarity index 100% rename from streamlit-server/vars-dev.tfvars rename to archive/streamlit-server/vars-dev.tfvars diff --git a/streamlit-server/vars-prod.tfvars b/archive/streamlit-server/vars-prod.tfvars similarity index 100% rename from streamlit-server/vars-prod.tfvars rename to archive/streamlit-server/vars-prod.tfvars diff --git a/streamlit-server/vars-uat.tfvars b/archive/streamlit-server/vars-uat.tfvars similarity index 100% rename from streamlit-server/vars-uat.tfvars rename to archive/streamlit-server/vars-uat.tfvars diff --git a/streamlit/.dockerignore b/archive/streamlit/.dockerignore similarity index 100% rename from streamlit/.dockerignore rename to archive/streamlit/.dockerignore diff --git a/streamlit/.python-version b/archive/streamlit/.python-version similarity index 100% rename from streamlit/.python-version rename to archive/streamlit/.python-version diff --git a/streamlit/README.md b/archive/streamlit/README.md similarity index 100% rename from streamlit/README.md rename to archive/streamlit/README.md diff --git a/fieldExtraction/constants/__init__.py b/archive/streamlit/__init__.py similarity index 100% rename from fieldExtraction/constants/__init__.py rename to archive/streamlit/__init__.py diff --git a/streamlit/aaretelogo.png b/archive/streamlit/aaretelogo.png similarity index 100% rename from streamlit/aaretelogo.png rename to archive/streamlit/aaretelogo.png diff --git a/streamlit/constants.py b/archive/streamlit/constants.py similarity index 100% rename from streamlit/constants.py rename to archive/streamlit/constants.py diff --git a/streamlit/contract_field_values.csv b/archive/streamlit/contract_field_values.csv similarity index 100% rename from streamlit/contract_field_values.csv rename to archive/streamlit/contract_field_values.csv diff --git a/streamlit/contract_fields.csv b/archive/streamlit/contract_fields.csv similarity index 100% rename from streamlit/contract_fields.csv rename to archive/streamlit/contract_fields.csv diff --git a/streamlit/ingest.py b/archive/streamlit/ingest.py similarity index 100% rename from streamlit/ingest.py rename to archive/streamlit/ingest.py diff --git a/streamlit/interface_0.py b/archive/streamlit/interface_0.py similarity index 100% rename from streamlit/interface_0.py rename to archive/streamlit/interface_0.py diff --git a/streamlit/interface_1.py b/archive/streamlit/interface_1.py similarity index 100% rename from streamlit/interface_1.py rename to archive/streamlit/interface_1.py diff --git a/streamlit/interface_2.py b/archive/streamlit/interface_2.py similarity index 100% rename from streamlit/interface_2.py rename to archive/streamlit/interface_2.py diff --git a/streamlit/interface_2_rag.py b/archive/streamlit/interface_2_rag.py similarity index 100% rename from streamlit/interface_2_rag.py rename to archive/streamlit/interface_2_rag.py diff --git a/streamlit/interface_3.py b/archive/streamlit/interface_3.py similarity index 100% rename from streamlit/interface_3.py rename to archive/streamlit/interface_3.py diff --git a/streamlit/interface_3_rag.py b/archive/streamlit/interface_3_rag.py similarity index 100% rename from streamlit/interface_3_rag.py rename to archive/streamlit/interface_3_rag.py diff --git a/streamlit/local/local_interface_0.py b/archive/streamlit/local/local_interface_0.py similarity index 100% rename from streamlit/local/local_interface_0.py rename to archive/streamlit/local/local_interface_0.py diff --git a/streamlit/local/local_interface_1.py b/archive/streamlit/local/local_interface_1.py similarity index 100% rename from streamlit/local/local_interface_1.py rename to archive/streamlit/local/local_interface_1.py diff --git a/streamlit/local/local_interface_2.py b/archive/streamlit/local/local_interface_2.py similarity index 100% rename from streamlit/local/local_interface_2.py rename to archive/streamlit/local/local_interface_2.py diff --git a/streamlit/multipage/Interface_0.py b/archive/streamlit/multipage/Interface_0.py similarity index 100% rename from streamlit/multipage/Interface_0.py rename to archive/streamlit/multipage/Interface_0.py diff --git a/streamlit/multipage/aaretelogo.png b/archive/streamlit/multipage/aaretelogo.png similarity index 100% rename from streamlit/multipage/aaretelogo.png rename to archive/streamlit/multipage/aaretelogo.png diff --git a/streamlit/multipage/constants.py b/archive/streamlit/multipage/constants.py similarity index 100% rename from streamlit/multipage/constants.py rename to archive/streamlit/multipage/constants.py diff --git a/streamlit/multipage/contract_fields.csv b/archive/streamlit/multipage/contract_fields.csv similarity index 100% rename from streamlit/multipage/contract_fields.csv rename to archive/streamlit/multipage/contract_fields.csv diff --git a/streamlit/multipage/pages/1_Interface_1.py b/archive/streamlit/multipage/pages/1_Interface_1.py similarity index 100% rename from streamlit/multipage/pages/1_Interface_1.py rename to archive/streamlit/multipage/pages/1_Interface_1.py diff --git a/streamlit/multipage/pages/2_Interface_2.py b/archive/streamlit/multipage/pages/2_Interface_2.py similarity index 100% rename from streamlit/multipage/pages/2_Interface_2.py rename to archive/streamlit/multipage/pages/2_Interface_2.py diff --git a/streamlit/multipage/pages/3_Data_Dictionary.py b/archive/streamlit/multipage/pages/3_Data_Dictionary.py similarity index 100% rename from streamlit/multipage/pages/3_Data_Dictionary.py rename to archive/streamlit/multipage/pages/3_Data_Dictionary.py diff --git a/streamlit/multipage/security.py b/archive/streamlit/multipage/security.py similarity index 100% rename from streamlit/multipage/security.py rename to archive/streamlit/multipage/security.py diff --git a/streamlit/multipage/sf_conn.py b/archive/streamlit/multipage/sf_conn.py similarity index 100% rename from streamlit/multipage/sf_conn.py rename to archive/streamlit/multipage/sf_conn.py diff --git a/streamlit/multipage/util.py b/archive/streamlit/multipage/util.py similarity index 100% rename from streamlit/multipage/util.py rename to archive/streamlit/multipage/util.py diff --git a/streamlit/poetry.lock b/archive/streamlit/poetry.lock similarity index 100% rename from streamlit/poetry.lock rename to archive/streamlit/poetry.lock diff --git a/streamlit/pyproject.toml b/archive/streamlit/pyproject.toml similarity index 100% rename from streamlit/pyproject.toml rename to archive/streamlit/pyproject.toml diff --git a/streamlit/runs-dashboard.py b/archive/streamlit/runs-dashboard.py similarity index 100% rename from streamlit/runs-dashboard.py rename to archive/streamlit/runs-dashboard.py diff --git a/streamlit/security.py b/archive/streamlit/security.py similarity index 100% rename from streamlit/security.py rename to archive/streamlit/security.py diff --git a/streamlit/sf_conn.py b/archive/streamlit/sf_conn.py similarity index 100% rename from streamlit/sf_conn.py rename to archive/streamlit/sf_conn.py diff --git a/streamlit/tests/example_test.py b/archive/streamlit/tests/example_test.py similarity index 100% rename from streamlit/tests/example_test.py rename to archive/streamlit/tests/example_test.py diff --git a/streamlit/util.py b/archive/streamlit/util.py similarity index 100% rename from streamlit/util.py rename to archive/streamlit/util.py diff --git a/streamlit_multipage/.dockerignore b/archive/streamlit_multipage/.dockerignore similarity index 100% rename from streamlit_multipage/.dockerignore rename to archive/streamlit_multipage/.dockerignore diff --git a/airflow/.python-version b/archive/streamlit_multipage/.python-version similarity index 100% rename from airflow/.python-version rename to archive/streamlit_multipage/.python-version diff --git a/streamlit_multipage/Demo_Test_data.csv b/archive/streamlit_multipage/Demo_Test_data.csv similarity index 100% rename from streamlit_multipage/Demo_Test_data.csv rename to archive/streamlit_multipage/Demo_Test_data.csv diff --git a/streamlit_multipage/Demo_Test_data.xlsx b/archive/streamlit_multipage/Demo_Test_data.xlsx similarity index 100% rename from streamlit_multipage/Demo_Test_data.xlsx rename to archive/streamlit_multipage/Demo_Test_data.xlsx diff --git a/streamlit_multipage/Interface_1.py b/archive/streamlit_multipage/Interface_1.py similarity index 100% rename from streamlit_multipage/Interface_1.py rename to archive/streamlit_multipage/Interface_1.py diff --git a/streamlit_multipage/README.md b/archive/streamlit_multipage/README.md similarity index 100% rename from streamlit_multipage/README.md rename to archive/streamlit_multipage/README.md diff --git a/streamlit_multipage/aaretelogo.png b/archive/streamlit_multipage/aaretelogo.png similarity index 100% rename from streamlit_multipage/aaretelogo.png rename to archive/streamlit_multipage/aaretelogo.png diff --git a/streamlit_multipage/constants.py b/archive/streamlit_multipage/constants.py similarity index 100% rename from streamlit_multipage/constants.py rename to archive/streamlit_multipage/constants.py diff --git a/streamlit_multipage/contract_fields.csv b/archive/streamlit_multipage/contract_fields.csv similarity index 100% rename from streamlit_multipage/contract_fields.csv rename to archive/streamlit_multipage/contract_fields.csv diff --git a/streamlit_multipage/pages/1_Interface_2.py b/archive/streamlit_multipage/pages/1_Interface_2.py similarity index 100% rename from streamlit_multipage/pages/1_Interface_2.py rename to archive/streamlit_multipage/pages/1_Interface_2.py diff --git a/streamlit_multipage/poetry.lock b/archive/streamlit_multipage/poetry.lock similarity index 100% rename from streamlit_multipage/poetry.lock rename to archive/streamlit_multipage/poetry.lock diff --git a/streamlit_multipage/pyproject.toml b/archive/streamlit_multipage/pyproject.toml similarity index 100% rename from streamlit_multipage/pyproject.toml rename to archive/streamlit_multipage/pyproject.toml diff --git a/streamlit_multipage/temp/Prime Care/13-2655001-New York City Health and Hospitals Corporation-ICMProviderAgreement_318243_1.Pdf b/archive/streamlit_multipage/temp/Prime Care/13-2655001-New York City Health and Hospitals Corporation-ICMProviderAgreement_318243_1.Pdf similarity index 100% rename from streamlit_multipage/temp/Prime Care/13-2655001-New York City Health and Hospitals Corporation-ICMProviderAgreement_318243_1.Pdf rename to archive/streamlit_multipage/temp/Prime Care/13-2655001-New York City Health and Hospitals Corporation-ICMProviderAgreement_318243_1.Pdf diff --git a/streamlit_multipage/temp/Prime Care/13-2655001-New York City Health and Hospitals Corporation-ICMProviderAgreement_318243_1.csv b/archive/streamlit_multipage/temp/Prime Care/13-2655001-New York City Health and Hospitals Corporation-ICMProviderAgreement_318243_1.csv similarity index 100% rename from streamlit_multipage/temp/Prime Care/13-2655001-New York City Health and Hospitals Corporation-ICMProviderAgreement_318243_1.csv rename to archive/streamlit_multipage/temp/Prime Care/13-2655001-New York City Health and Hospitals Corporation-ICMProviderAgreement_318243_1.csv diff --git a/streamlit_multipage/temp/Prime Care/43-0654872-Saint Louis University dba SLUCare, a Missouri benevolent corporation-ICMProviderAgreement_92767_3.Pdf b/archive/streamlit_multipage/temp/Prime Care/43-0654872-Saint Louis University dba SLUCare, a Missouri benevolent corporation-ICMProviderAgreement_92767_3.Pdf similarity index 100% rename from streamlit_multipage/temp/Prime Care/43-0654872-Saint Louis University dba SLUCare, a Missouri benevolent corporation-ICMProviderAgreement_92767_3.Pdf rename to archive/streamlit_multipage/temp/Prime Care/43-0654872-Saint Louis University dba SLUCare, a Missouri benevolent corporation-ICMProviderAgreement_92767_3.Pdf diff --git a/streamlit_multipage/temp/Prime Care/43-0654872-Saint Louis University dba SLUCare, a Missouri benevolent corporation-ICMProviderAgreement_92767_3.csv b/archive/streamlit_multipage/temp/Prime Care/43-0654872-Saint Louis University dba SLUCare, a Missouri benevolent corporation-ICMProviderAgreement_92767_3.csv similarity index 100% rename from streamlit_multipage/temp/Prime Care/43-0654872-Saint Louis University dba SLUCare, a Missouri benevolent corporation-ICMProviderAgreement_92767_3.csv rename to archive/streamlit_multipage/temp/Prime Care/43-0654872-Saint Louis University dba SLUCare, a Missouri benevolent corporation-ICMProviderAgreement_92767_3.csv diff --git a/streamlit_multipage/temp/Prime Care/52-1590951-Maxim Healthcare Services Inc-ICMProviderAgreement_265803_3.Pdf b/archive/streamlit_multipage/temp/Prime Care/52-1590951-Maxim Healthcare Services Inc-ICMProviderAgreement_265803_3.Pdf similarity index 100% rename from streamlit_multipage/temp/Prime Care/52-1590951-Maxim Healthcare Services Inc-ICMProviderAgreement_265803_3.Pdf rename to archive/streamlit_multipage/temp/Prime Care/52-1590951-Maxim Healthcare Services Inc-ICMProviderAgreement_265803_3.Pdf diff --git a/streamlit_multipage/temp/Prime Care/52-1590951-Maxim Healthcare Services Inc-ICMProviderAgreement_265803_3.csv b/archive/streamlit_multipage/temp/Prime Care/52-1590951-Maxim Healthcare Services Inc-ICMProviderAgreement_265803_3.csv similarity index 100% rename from streamlit_multipage/temp/Prime Care/52-1590951-Maxim Healthcare Services Inc-ICMProviderAgreement_265803_3.csv rename to archive/streamlit_multipage/temp/Prime Care/52-1590951-Maxim Healthcare Services Inc-ICMProviderAgreement_265803_3.csv diff --git a/streamlit_multipage/temp1.csv b/archive/streamlit_multipage/temp1.csv similarity index 100% rename from streamlit_multipage/temp1.csv rename to archive/streamlit_multipage/temp1.csv diff --git a/streamlit_multipage/temp2.csv b/archive/streamlit_multipage/temp2.csv similarity index 100% rename from streamlit_multipage/temp2.csv rename to archive/streamlit_multipage/temp2.csv diff --git a/streamlit_multipage/tests/example_test.py b/archive/streamlit_multipage/tests/example_test.py similarity index 100% rename from streamlit_multipage/tests/example_test.py rename to archive/streamlit_multipage/tests/example_test.py diff --git a/terminal.py b/archive/terminal.py similarity index 100% rename from terminal.py rename to archive/terminal.py diff --git a/terraform.py b/archive/terraform.py similarity index 100% rename from terraform.py rename to archive/terraform.py diff --git a/textract-pipeline/src/lambda-layer/anthropic-snowflake/anthropic-sf-310.zip b/archive/textract-pipeline/src/lambda-layer/anthropic-snowflake/anthropic-sf-310.zip similarity index 100% rename from textract-pipeline/src/lambda-layer/anthropic-snowflake/anthropic-sf-310.zip rename to archive/textract-pipeline/src/lambda-layer/anthropic-snowflake/anthropic-sf-310.zip diff --git a/textract-pipeline/src/lambda-layer/brotli-layer/brotlipy-layer.zip b/archive/textract-pipeline/src/lambda-layer/brotli-layer/brotlipy-layer.zip similarity index 100% rename from textract-pipeline/src/lambda-layer/brotli-layer/brotlipy-layer.zip rename to archive/textract-pipeline/src/lambda-layer/brotli-layer/brotlipy-layer.zip diff --git a/textract-pipeline/src/lambda-layer/libre-office/lo.tar.br b/archive/textract-pipeline/src/lambda-layer/libre-office/lo.tar.br similarity index 100% rename from textract-pipeline/src/lambda-layer/libre-office/lo.tar.br rename to archive/textract-pipeline/src/lambda-layer/libre-office/lo.tar.br diff --git a/textract-pipeline/src/lambda-layer/pandas-np-310/pd_np.zip b/archive/textract-pipeline/src/lambda-layer/pandas-np-310/pd_np.zip similarity index 100% rename from textract-pipeline/src/lambda-layer/pandas-np-310/pd_np.zip rename to archive/textract-pipeline/src/lambda-layer/pandas-np-310/pd_np.zip diff --git a/textract-pipeline/src/lambda-layer/pydantic-218/pydantic.zip b/archive/textract-pipeline/src/lambda-layer/pydantic-218/pydantic.zip similarity index 100% rename from textract-pipeline/src/lambda-layer/pydantic-218/pydantic.zip rename to archive/textract-pipeline/src/lambda-layer/pydantic-218/pydantic.zip diff --git a/textract-pipeline/src/lambda-layer/pypdf2-layer-new/requirements.txt b/archive/textract-pipeline/src/lambda-layer/pypdf2-layer-new/requirements.txt similarity index 100% rename from textract-pipeline/src/lambda-layer/pypdf2-layer-new/requirements.txt rename to archive/textract-pipeline/src/lambda-layer/pypdf2-layer-new/requirements.txt diff --git a/textract-pipeline/src/lambda-layer/pypdf2-layer/PyPDF2.zip b/archive/textract-pipeline/src/lambda-layer/pypdf2-layer/PyPDF2.zip similarity index 100% rename from textract-pipeline/src/lambda-layer/pypdf2-layer/PyPDF2.zip rename to archive/textract-pipeline/src/lambda-layer/pypdf2-layer/PyPDF2.zip diff --git a/textract-pipeline/src/lambda-layer/snowflake-connector/snowflake-connector-39-verified.zip b/archive/textract-pipeline/src/lambda-layer/snowflake-connector/snowflake-connector-39-verified.zip similarity index 100% rename from textract-pipeline/src/lambda-layer/snowflake-connector/snowflake-connector-39-verified.zip rename to archive/textract-pipeline/src/lambda-layer/snowflake-connector/snowflake-connector-39-verified.zip diff --git a/textract-pipeline/src/lambda/batch-creation/.dockerignore b/archive/textract-pipeline/src/lambda/batch-creation/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/batch-creation/.dockerignore rename to archive/textract-pipeline/src/lambda/batch-creation/.dockerignore diff --git a/fieldExtraction/.python-version b/archive/textract-pipeline/src/lambda/batch-creation/.python-version similarity index 100% rename from fieldExtraction/.python-version rename to archive/textract-pipeline/src/lambda/batch-creation/.python-version diff --git a/textract-pipeline/src/lambda/batch-creation/README.md b/archive/textract-pipeline/src/lambda/batch-creation/README.md similarity index 100% rename from textract-pipeline/src/lambda/batch-creation/README.md rename to archive/textract-pipeline/src/lambda/batch-creation/README.md diff --git a/textract-pipeline/src/lambda/batch-creation/index.py b/archive/textract-pipeline/src/lambda/batch-creation/index.py similarity index 100% rename from textract-pipeline/src/lambda/batch-creation/index.py rename to archive/textract-pipeline/src/lambda/batch-creation/index.py diff --git a/textract-pipeline/src/lambda/batch-creation/poetry.lock b/archive/textract-pipeline/src/lambda/batch-creation/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/batch-creation/poetry.lock rename to archive/textract-pipeline/src/lambda/batch-creation/poetry.lock diff --git a/textract-pipeline/src/lambda/batch-creation/pyproject.toml b/archive/textract-pipeline/src/lambda/batch-creation/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/batch-creation/pyproject.toml rename to archive/textract-pipeline/src/lambda/batch-creation/pyproject.toml diff --git a/textract-pipeline/src/lambda/batch-creation/tests/example_test.py b/archive/textract-pipeline/src/lambda/batch-creation/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/batch-creation/tests/example_test.py rename to archive/textract-pipeline/src/lambda/batch-creation/tests/example_test.py diff --git a/textract-pipeline/src/lambda/call-bedrock/.dockerignore b/archive/textract-pipeline/src/lambda/call-bedrock/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/call-bedrock/.dockerignore rename to archive/textract-pipeline/src/lambda/call-bedrock/.dockerignore diff --git a/streamlit_multipage/.python-version b/archive/textract-pipeline/src/lambda/call-bedrock/.python-version similarity index 100% rename from streamlit_multipage/.python-version rename to archive/textract-pipeline/src/lambda/call-bedrock/.python-version diff --git a/textract-pipeline/src/lambda/call-bedrock/README.md b/archive/textract-pipeline/src/lambda/call-bedrock/README.md similarity index 100% rename from textract-pipeline/src/lambda/call-bedrock/README.md rename to archive/textract-pipeline/src/lambda/call-bedrock/README.md diff --git a/textract-pipeline/src/lambda/call-bedrock/index.py b/archive/textract-pipeline/src/lambda/call-bedrock/index.py similarity index 100% rename from textract-pipeline/src/lambda/call-bedrock/index.py rename to archive/textract-pipeline/src/lambda/call-bedrock/index.py diff --git a/textract-pipeline/src/lambda/call-bedrock/poetry.lock b/archive/textract-pipeline/src/lambda/call-bedrock/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/call-bedrock/poetry.lock rename to archive/textract-pipeline/src/lambda/call-bedrock/poetry.lock diff --git a/textract-pipeline/src/lambda/call-bedrock/pyproject.toml b/archive/textract-pipeline/src/lambda/call-bedrock/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/call-bedrock/pyproject.toml rename to archive/textract-pipeline/src/lambda/call-bedrock/pyproject.toml diff --git a/textract-pipeline/src/lambda/call-bedrock/tests/example_test.py b/archive/textract-pipeline/src/lambda/call-bedrock/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/call-bedrock/tests/example_test.py rename to archive/textract-pipeline/src/lambda/call-bedrock/tests/example_test.py diff --git a/textract-pipeline/src/lambda/database-interface-get/.dockerignore b/archive/textract-pipeline/src/lambda/database-interface-get/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/database-interface-get/.dockerignore rename to archive/textract-pipeline/src/lambda/database-interface-get/.dockerignore diff --git a/textract-pipeline/src/lambda/database-interface-get/.python-version b/archive/textract-pipeline/src/lambda/database-interface-get/.python-version similarity index 100% rename from textract-pipeline/src/lambda/database-interface-get/.python-version rename to archive/textract-pipeline/src/lambda/database-interface-get/.python-version diff --git a/textract-pipeline/src/lambda/database-interface-get/README.md b/archive/textract-pipeline/src/lambda/database-interface-get/README.md similarity index 100% rename from textract-pipeline/src/lambda/database-interface-get/README.md rename to archive/textract-pipeline/src/lambda/database-interface-get/README.md diff --git a/textract-pipeline/src/lambda/database-interface-get/index.py b/archive/textract-pipeline/src/lambda/database-interface-get/index.py similarity index 100% rename from textract-pipeline/src/lambda/database-interface-get/index.py rename to archive/textract-pipeline/src/lambda/database-interface-get/index.py diff --git a/textract-pipeline/src/lambda/database-interface-get/poetry.lock b/archive/textract-pipeline/src/lambda/database-interface-get/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/database-interface-get/poetry.lock rename to archive/textract-pipeline/src/lambda/database-interface-get/poetry.lock diff --git a/textract-pipeline/src/lambda/database-interface-get/pyproject.toml b/archive/textract-pipeline/src/lambda/database-interface-get/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/database-interface-get/pyproject.toml rename to archive/textract-pipeline/src/lambda/database-interface-get/pyproject.toml diff --git a/textract-pipeline/src/lambda/database-interface-get/tests/example_test.py b/archive/textract-pipeline/src/lambda/database-interface-get/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/database-interface-get/tests/example_test.py rename to archive/textract-pipeline/src/lambda/database-interface-get/tests/example_test.py diff --git a/textract-pipeline/src/lambda/database-interface/.dockerignore b/archive/textract-pipeline/src/lambda/database-interface/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/database-interface/.dockerignore rename to archive/textract-pipeline/src/lambda/database-interface/.dockerignore diff --git a/textract-pipeline/src/lambda/database-interface/.python-version b/archive/textract-pipeline/src/lambda/database-interface/.python-version similarity index 100% rename from textract-pipeline/src/lambda/database-interface/.python-version rename to archive/textract-pipeline/src/lambda/database-interface/.python-version diff --git a/textract-pipeline/src/lambda/database-interface/README.md b/archive/textract-pipeline/src/lambda/database-interface/README.md similarity index 100% rename from textract-pipeline/src/lambda/database-interface/README.md rename to archive/textract-pipeline/src/lambda/database-interface/README.md diff --git a/textract-pipeline/src/lambda/database-interface/index.py b/archive/textract-pipeline/src/lambda/database-interface/index.py similarity index 100% rename from textract-pipeline/src/lambda/database-interface/index.py rename to archive/textract-pipeline/src/lambda/database-interface/index.py diff --git a/textract-pipeline/src/lambda/database-interface/poetry.lock b/archive/textract-pipeline/src/lambda/database-interface/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/database-interface/poetry.lock rename to archive/textract-pipeline/src/lambda/database-interface/poetry.lock diff --git a/textract-pipeline/src/lambda/database-interface/pyproject.toml b/archive/textract-pipeline/src/lambda/database-interface/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/database-interface/pyproject.toml rename to archive/textract-pipeline/src/lambda/database-interface/pyproject.toml diff --git a/textract-pipeline/src/lambda/database-interface/tests/example_test.py b/archive/textract-pipeline/src/lambda/database-interface/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/database-interface/tests/example_test.py rename to archive/textract-pipeline/src/lambda/database-interface/tests/example_test.py diff --git a/textract-pipeline/src/lambda/docx-to-pdf/.dockerignore b/archive/textract-pipeline/src/lambda/docx-to-pdf/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/docx-to-pdf/.dockerignore rename to archive/textract-pipeline/src/lambda/docx-to-pdf/.dockerignore diff --git a/textract-pipeline/src/lambda/batch-creation/.python-version b/archive/textract-pipeline/src/lambda/docx-to-pdf/.python-version similarity index 100% rename from textract-pipeline/src/lambda/batch-creation/.python-version rename to archive/textract-pipeline/src/lambda/docx-to-pdf/.python-version diff --git a/textract-pipeline/src/lambda/docx-to-pdf/README.md b/archive/textract-pipeline/src/lambda/docx-to-pdf/README.md similarity index 100% rename from textract-pipeline/src/lambda/docx-to-pdf/README.md rename to archive/textract-pipeline/src/lambda/docx-to-pdf/README.md diff --git a/textract-pipeline/src/lambda/docx-to-pdf/index.py b/archive/textract-pipeline/src/lambda/docx-to-pdf/index.py similarity index 100% rename from textract-pipeline/src/lambda/docx-to-pdf/index.py rename to archive/textract-pipeline/src/lambda/docx-to-pdf/index.py diff --git a/textract-pipeline/src/lambda/docx-to-pdf/poetry.lock b/archive/textract-pipeline/src/lambda/docx-to-pdf/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/docx-to-pdf/poetry.lock rename to archive/textract-pipeline/src/lambda/docx-to-pdf/poetry.lock diff --git a/textract-pipeline/src/lambda/docx-to-pdf/pyproject.toml b/archive/textract-pipeline/src/lambda/docx-to-pdf/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/docx-to-pdf/pyproject.toml rename to archive/textract-pipeline/src/lambda/docx-to-pdf/pyproject.toml diff --git a/textract-pipeline/src/lambda/docx-to-pdf/tests/example_test.py b/archive/textract-pipeline/src/lambda/docx-to-pdf/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/docx-to-pdf/tests/example_test.py rename to archive/textract-pipeline/src/lambda/docx-to-pdf/tests/example_test.py diff --git a/textract-pipeline/src/lambda/insert-record/.dockerignore b/archive/textract-pipeline/src/lambda/insert-record/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/insert-record/.dockerignore rename to archive/textract-pipeline/src/lambda/insert-record/.dockerignore diff --git a/textract-pipeline/src/lambda/call-bedrock/.python-version b/archive/textract-pipeline/src/lambda/insert-record/.python-version similarity index 100% rename from textract-pipeline/src/lambda/call-bedrock/.python-version rename to archive/textract-pipeline/src/lambda/insert-record/.python-version diff --git a/textract-pipeline/src/lambda/insert-record/README.md b/archive/textract-pipeline/src/lambda/insert-record/README.md similarity index 100% rename from textract-pipeline/src/lambda/insert-record/README.md rename to archive/textract-pipeline/src/lambda/insert-record/README.md diff --git a/textract-pipeline/src/lambda/insert-record/index.py b/archive/textract-pipeline/src/lambda/insert-record/index.py similarity index 100% rename from textract-pipeline/src/lambda/insert-record/index.py rename to archive/textract-pipeline/src/lambda/insert-record/index.py diff --git a/textract-pipeline/src/lambda/insert-record/poetry.lock b/archive/textract-pipeline/src/lambda/insert-record/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/insert-record/poetry.lock rename to archive/textract-pipeline/src/lambda/insert-record/poetry.lock diff --git a/textract-pipeline/src/lambda/insert-record/pyproject.toml b/archive/textract-pipeline/src/lambda/insert-record/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/insert-record/pyproject.toml rename to archive/textract-pipeline/src/lambda/insert-record/pyproject.toml diff --git a/textract-pipeline/src/lambda/insert-record/tests/example_test.py b/archive/textract-pipeline/src/lambda/insert-record/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/insert-record/tests/example_test.py rename to archive/textract-pipeline/src/lambda/insert-record/tests/example_test.py diff --git a/textract-pipeline/src/lambda/pdf-validation/.dockerignore b/archive/textract-pipeline/src/lambda/pdf-validation/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/pdf-validation/.dockerignore rename to archive/textract-pipeline/src/lambda/pdf-validation/.dockerignore diff --git a/textract-pipeline/src/lambda/docx-to-pdf/.python-version b/archive/textract-pipeline/src/lambda/pdf-validation/.python-version similarity index 100% rename from textract-pipeline/src/lambda/docx-to-pdf/.python-version rename to archive/textract-pipeline/src/lambda/pdf-validation/.python-version diff --git a/textract-pipeline/src/lambda/pdf-validation/README.md b/archive/textract-pipeline/src/lambda/pdf-validation/README.md similarity index 100% rename from textract-pipeline/src/lambda/pdf-validation/README.md rename to archive/textract-pipeline/src/lambda/pdf-validation/README.md diff --git a/textract-pipeline/src/lambda/pdf-validation/index.py b/archive/textract-pipeline/src/lambda/pdf-validation/index.py similarity index 100% rename from textract-pipeline/src/lambda/pdf-validation/index.py rename to archive/textract-pipeline/src/lambda/pdf-validation/index.py diff --git a/textract-pipeline/src/lambda/pdf-validation/poetry.lock b/archive/textract-pipeline/src/lambda/pdf-validation/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/pdf-validation/poetry.lock rename to archive/textract-pipeline/src/lambda/pdf-validation/poetry.lock diff --git a/textract-pipeline/src/lambda/pdf-validation/pyproject.toml b/archive/textract-pipeline/src/lambda/pdf-validation/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/pdf-validation/pyproject.toml rename to archive/textract-pipeline/src/lambda/pdf-validation/pyproject.toml diff --git a/textract-pipeline/src/lambda/pdf-validation/tests/example_test.py b/archive/textract-pipeline/src/lambda/pdf-validation/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/pdf-validation/tests/example_test.py rename to archive/textract-pipeline/src/lambda/pdf-validation/tests/example_test.py diff --git a/textract-pipeline/src/lambda/prompt-processor/.dockerignore b/archive/textract-pipeline/src/lambda/prompt-processor/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/prompt-processor/.dockerignore rename to archive/textract-pipeline/src/lambda/prompt-processor/.dockerignore diff --git a/textract-pipeline/src/lambda/insert-record/.python-version b/archive/textract-pipeline/src/lambda/prompt-processor/.python-version similarity index 100% rename from textract-pipeline/src/lambda/insert-record/.python-version rename to archive/textract-pipeline/src/lambda/prompt-processor/.python-version diff --git a/textract-pipeline/src/lambda/prompt-processor/README.md b/archive/textract-pipeline/src/lambda/prompt-processor/README.md similarity index 100% rename from textract-pipeline/src/lambda/prompt-processor/README.md rename to archive/textract-pipeline/src/lambda/prompt-processor/README.md diff --git a/textract-pipeline/src/lambda/prompt-processor/index.py b/archive/textract-pipeline/src/lambda/prompt-processor/index.py similarity index 100% rename from textract-pipeline/src/lambda/prompt-processor/index.py rename to archive/textract-pipeline/src/lambda/prompt-processor/index.py diff --git a/textract-pipeline/src/lambda/prompt-processor/poetry.lock b/archive/textract-pipeline/src/lambda/prompt-processor/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/prompt-processor/poetry.lock rename to archive/textract-pipeline/src/lambda/prompt-processor/poetry.lock diff --git a/textract-pipeline/src/lambda/prompt-processor/pyproject.toml b/archive/textract-pipeline/src/lambda/prompt-processor/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/prompt-processor/pyproject.toml rename to archive/textract-pipeline/src/lambda/prompt-processor/pyproject.toml diff --git a/textract-pipeline/src/lambda/prompt-processor/tests/example_test.py b/archive/textract-pipeline/src/lambda/prompt-processor/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/prompt-processor/tests/example_test.py rename to archive/textract-pipeline/src/lambda/prompt-processor/tests/example_test.py diff --git a/textract-pipeline/src/lambda/s3-folder-details/.dockerignore b/archive/textract-pipeline/src/lambda/s3-folder-details/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/s3-folder-details/.dockerignore rename to archive/textract-pipeline/src/lambda/s3-folder-details/.dockerignore diff --git a/textract-pipeline/src/lambda/pdf-validation/.python-version b/archive/textract-pipeline/src/lambda/s3-folder-details/.python-version similarity index 100% rename from textract-pipeline/src/lambda/pdf-validation/.python-version rename to archive/textract-pipeline/src/lambda/s3-folder-details/.python-version diff --git a/textract-pipeline/src/lambda/s3-folder-details/README.md b/archive/textract-pipeline/src/lambda/s3-folder-details/README.md similarity index 100% rename from textract-pipeline/src/lambda/s3-folder-details/README.md rename to archive/textract-pipeline/src/lambda/s3-folder-details/README.md diff --git a/textract-pipeline/src/lambda/s3-folder-details/index.py b/archive/textract-pipeline/src/lambda/s3-folder-details/index.py similarity index 100% rename from textract-pipeline/src/lambda/s3-folder-details/index.py rename to archive/textract-pipeline/src/lambda/s3-folder-details/index.py diff --git a/textract-pipeline/src/lambda/s3-folder-details/poetry.lock b/archive/textract-pipeline/src/lambda/s3-folder-details/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/s3-folder-details/poetry.lock rename to archive/textract-pipeline/src/lambda/s3-folder-details/poetry.lock diff --git a/textract-pipeline/src/lambda/s3-folder-details/pyproject.toml b/archive/textract-pipeline/src/lambda/s3-folder-details/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/s3-folder-details/pyproject.toml rename to archive/textract-pipeline/src/lambda/s3-folder-details/pyproject.toml diff --git a/textract-pipeline/src/lambda/s3-folder-details/tests/example_test.py b/archive/textract-pipeline/src/lambda/s3-folder-details/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/s3-folder-details/tests/example_test.py rename to archive/textract-pipeline/src/lambda/s3-folder-details/tests/example_test.py diff --git a/textract-pipeline/src/lambda/text-creation/.dockerignore b/archive/textract-pipeline/src/lambda/text-creation/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/text-creation/.dockerignore rename to archive/textract-pipeline/src/lambda/text-creation/.dockerignore diff --git a/textract-pipeline/src/lambda/prompt-processor/.python-version b/archive/textract-pipeline/src/lambda/text-creation/.python-version similarity index 100% rename from textract-pipeline/src/lambda/prompt-processor/.python-version rename to archive/textract-pipeline/src/lambda/text-creation/.python-version diff --git a/textract-pipeline/src/lambda/text-creation/README.md b/archive/textract-pipeline/src/lambda/text-creation/README.md similarity index 100% rename from textract-pipeline/src/lambda/text-creation/README.md rename to archive/textract-pipeline/src/lambda/text-creation/README.md diff --git a/textract-pipeline/src/lambda/text-creation/index.py b/archive/textract-pipeline/src/lambda/text-creation/index.py similarity index 100% rename from textract-pipeline/src/lambda/text-creation/index.py rename to archive/textract-pipeline/src/lambda/text-creation/index.py diff --git a/textract-pipeline/src/lambda/text-creation/poetry.lock b/archive/textract-pipeline/src/lambda/text-creation/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/text-creation/poetry.lock rename to archive/textract-pipeline/src/lambda/text-creation/poetry.lock diff --git a/textract-pipeline/src/lambda/text-creation/pyproject.toml b/archive/textract-pipeline/src/lambda/text-creation/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/text-creation/pyproject.toml rename to archive/textract-pipeline/src/lambda/text-creation/pyproject.toml diff --git a/textract-pipeline/src/lambda/text-creation/tests/example_test.py b/archive/textract-pipeline/src/lambda/text-creation/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/text-creation/tests/example_test.py rename to archive/textract-pipeline/src/lambda/text-creation/tests/example_test.py diff --git a/textract-pipeline/src/lambda/textract-receiver/.dockerignore b/archive/textract-pipeline/src/lambda/textract-receiver/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/textract-receiver/.dockerignore rename to archive/textract-pipeline/src/lambda/textract-receiver/.dockerignore diff --git a/textract-pipeline/src/lambda/s3-folder-details/.python-version b/archive/textract-pipeline/src/lambda/textract-receiver/.python-version similarity index 100% rename from textract-pipeline/src/lambda/s3-folder-details/.python-version rename to archive/textract-pipeline/src/lambda/textract-receiver/.python-version diff --git a/textract-pipeline/src/lambda/textract-receiver/README.md b/archive/textract-pipeline/src/lambda/textract-receiver/README.md similarity index 100% rename from textract-pipeline/src/lambda/textract-receiver/README.md rename to archive/textract-pipeline/src/lambda/textract-receiver/README.md diff --git a/textract-pipeline/src/lambda/textract-receiver/index.py b/archive/textract-pipeline/src/lambda/textract-receiver/index.py similarity index 100% rename from textract-pipeline/src/lambda/textract-receiver/index.py rename to archive/textract-pipeline/src/lambda/textract-receiver/index.py diff --git a/textract-pipeline/src/lambda/textract-receiver/poetry.lock b/archive/textract-pipeline/src/lambda/textract-receiver/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/textract-receiver/poetry.lock rename to archive/textract-pipeline/src/lambda/textract-receiver/poetry.lock diff --git a/textract-pipeline/src/lambda/textract-receiver/pyproject.toml b/archive/textract-pipeline/src/lambda/textract-receiver/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/textract-receiver/pyproject.toml rename to archive/textract-pipeline/src/lambda/textract-receiver/pyproject.toml diff --git a/textract-pipeline/src/lambda/textract-receiver/tests/example_test.py b/archive/textract-pipeline/src/lambda/textract-receiver/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/textract-receiver/tests/example_test.py rename to archive/textract-pipeline/src/lambda/textract-receiver/tests/example_test.py diff --git a/textract-pipeline/src/lambda/textract-sender/.dockerignore b/archive/textract-pipeline/src/lambda/textract-sender/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/textract-sender/.dockerignore rename to archive/textract-pipeline/src/lambda/textract-sender/.dockerignore diff --git a/textract-pipeline/src/lambda/text-creation/.python-version b/archive/textract-pipeline/src/lambda/textract-sender/.python-version similarity index 100% rename from textract-pipeline/src/lambda/text-creation/.python-version rename to archive/textract-pipeline/src/lambda/textract-sender/.python-version diff --git a/textract-pipeline/src/lambda/textract-sender/README.md b/archive/textract-pipeline/src/lambda/textract-sender/README.md similarity index 100% rename from textract-pipeline/src/lambda/textract-sender/README.md rename to archive/textract-pipeline/src/lambda/textract-sender/README.md diff --git a/textract-pipeline/src/lambda/textract-sender/index.py b/archive/textract-pipeline/src/lambda/textract-sender/index.py similarity index 100% rename from textract-pipeline/src/lambda/textract-sender/index.py rename to archive/textract-pipeline/src/lambda/textract-sender/index.py diff --git a/textract-pipeline/src/lambda/textract-sender/poetry.lock b/archive/textract-pipeline/src/lambda/textract-sender/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/textract-sender/poetry.lock rename to archive/textract-pipeline/src/lambda/textract-sender/poetry.lock diff --git a/textract-pipeline/src/lambda/textract-sender/pyproject.toml b/archive/textract-pipeline/src/lambda/textract-sender/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/textract-sender/pyproject.toml rename to archive/textract-pipeline/src/lambda/textract-sender/pyproject.toml diff --git a/textract-pipeline/src/lambda/textract-sender/tests/example_test.py b/archive/textract-pipeline/src/lambda/textract-sender/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/textract-sender/tests/example_test.py rename to archive/textract-pipeline/src/lambda/textract-sender/tests/example_test.py diff --git a/textract-pipeline/src/lambda/tiff-to-pdf/.dockerignore b/archive/textract-pipeline/src/lambda/tiff-to-pdf/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/tiff-to-pdf/.dockerignore rename to archive/textract-pipeline/src/lambda/tiff-to-pdf/.dockerignore diff --git a/textract-pipeline/src/lambda/textract-receiver/.python-version b/archive/textract-pipeline/src/lambda/tiff-to-pdf/.python-version similarity index 100% rename from textract-pipeline/src/lambda/textract-receiver/.python-version rename to archive/textract-pipeline/src/lambda/tiff-to-pdf/.python-version diff --git a/textract-pipeline/src/lambda/tiff-to-pdf/README.md b/archive/textract-pipeline/src/lambda/tiff-to-pdf/README.md similarity index 100% rename from textract-pipeline/src/lambda/tiff-to-pdf/README.md rename to archive/textract-pipeline/src/lambda/tiff-to-pdf/README.md diff --git a/textract-pipeline/src/lambda/tiff-to-pdf/index.py b/archive/textract-pipeline/src/lambda/tiff-to-pdf/index.py similarity index 100% rename from textract-pipeline/src/lambda/tiff-to-pdf/index.py rename to archive/textract-pipeline/src/lambda/tiff-to-pdf/index.py diff --git a/textract-pipeline/src/lambda/tiff-to-pdf/poetry.lock b/archive/textract-pipeline/src/lambda/tiff-to-pdf/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/tiff-to-pdf/poetry.lock rename to archive/textract-pipeline/src/lambda/tiff-to-pdf/poetry.lock diff --git a/textract-pipeline/src/lambda/tiff-to-pdf/pyproject.toml b/archive/textract-pipeline/src/lambda/tiff-to-pdf/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/tiff-to-pdf/pyproject.toml rename to archive/textract-pipeline/src/lambda/tiff-to-pdf/pyproject.toml diff --git a/textract-pipeline/src/lambda/tiff-to-pdf/tests/example_test.py b/archive/textract-pipeline/src/lambda/tiff-to-pdf/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/tiff-to-pdf/tests/example_test.py rename to archive/textract-pipeline/src/lambda/tiff-to-pdf/tests/example_test.py diff --git a/textract-pipeline/src/lambda/trigger-pipeline/.dockerignore b/archive/textract-pipeline/src/lambda/trigger-pipeline/.dockerignore similarity index 100% rename from textract-pipeline/src/lambda/trigger-pipeline/.dockerignore rename to archive/textract-pipeline/src/lambda/trigger-pipeline/.dockerignore diff --git a/textract-pipeline/src/lambda/textract-sender/.python-version b/archive/textract-pipeline/src/lambda/trigger-pipeline/.python-version similarity index 100% rename from textract-pipeline/src/lambda/textract-sender/.python-version rename to archive/textract-pipeline/src/lambda/trigger-pipeline/.python-version diff --git a/textract-pipeline/src/lambda/trigger-pipeline/README.md b/archive/textract-pipeline/src/lambda/trigger-pipeline/README.md similarity index 100% rename from textract-pipeline/src/lambda/trigger-pipeline/README.md rename to archive/textract-pipeline/src/lambda/trigger-pipeline/README.md diff --git a/textract-pipeline/src/lambda/trigger-pipeline/index.py b/archive/textract-pipeline/src/lambda/trigger-pipeline/index.py similarity index 100% rename from textract-pipeline/src/lambda/trigger-pipeline/index.py rename to archive/textract-pipeline/src/lambda/trigger-pipeline/index.py diff --git a/textract-pipeline/src/lambda/trigger-pipeline/poetry.lock b/archive/textract-pipeline/src/lambda/trigger-pipeline/poetry.lock similarity index 100% rename from textract-pipeline/src/lambda/trigger-pipeline/poetry.lock rename to archive/textract-pipeline/src/lambda/trigger-pipeline/poetry.lock diff --git a/textract-pipeline/src/lambda/trigger-pipeline/pyproject.toml b/archive/textract-pipeline/src/lambda/trigger-pipeline/pyproject.toml similarity index 100% rename from textract-pipeline/src/lambda/trigger-pipeline/pyproject.toml rename to archive/textract-pipeline/src/lambda/trigger-pipeline/pyproject.toml diff --git a/textract-pipeline/src/lambda/trigger-pipeline/tests/example_test.py b/archive/textract-pipeline/src/lambda/trigger-pipeline/tests/example_test.py similarity index 100% rename from textract-pipeline/src/lambda/trigger-pipeline/tests/example_test.py rename to archive/textract-pipeline/src/lambda/trigger-pipeline/tests/example_test.py diff --git a/textract-pipeline/src/s3-files/config.properties b/archive/textract-pipeline/src/s3-files/config.properties similarity index 100% rename from textract-pipeline/src/s3-files/config.properties rename to archive/textract-pipeline/src/s3-files/config.properties diff --git a/textract-pipeline/terraform/main.tf b/archive/textract-pipeline/terraform/main.tf similarity index 100% rename from textract-pipeline/terraform/main.tf rename to archive/textract-pipeline/terraform/main.tf diff --git a/textract-pipeline/terraform/modules/aws-textract-pipeline-part1/main.tf b/archive/textract-pipeline/terraform/modules/aws-textract-pipeline-part1/main.tf similarity index 100% rename from textract-pipeline/terraform/modules/aws-textract-pipeline-part1/main.tf rename to archive/textract-pipeline/terraform/modules/aws-textract-pipeline-part1/main.tf diff --git a/textract-pipeline/terraform/modules/aws-textract-pipeline-part1/outputs.tf b/archive/textract-pipeline/terraform/modules/aws-textract-pipeline-part1/outputs.tf similarity index 100% rename from textract-pipeline/terraform/modules/aws-textract-pipeline-part1/outputs.tf rename to archive/textract-pipeline/terraform/modules/aws-textract-pipeline-part1/outputs.tf diff --git a/textract-pipeline/terraform/modules/aws-textract-pipeline-part1/variables.tf b/archive/textract-pipeline/terraform/modules/aws-textract-pipeline-part1/variables.tf similarity index 100% rename from textract-pipeline/terraform/modules/aws-textract-pipeline-part1/variables.tf rename to archive/textract-pipeline/terraform/modules/aws-textract-pipeline-part1/variables.tf diff --git a/textract-pipeline/terraform/modules/aws-textract-pipeline-part3/main.tf b/archive/textract-pipeline/terraform/modules/aws-textract-pipeline-part3/main.tf similarity index 100% rename from textract-pipeline/terraform/modules/aws-textract-pipeline-part3/main.tf rename to archive/textract-pipeline/terraform/modules/aws-textract-pipeline-part3/main.tf diff --git a/textract-pipeline/terraform/modules/aws-textract-pipeline-part3/outputs.tf b/archive/textract-pipeline/terraform/modules/aws-textract-pipeline-part3/outputs.tf similarity index 100% rename from textract-pipeline/terraform/modules/aws-textract-pipeline-part3/outputs.tf rename to archive/textract-pipeline/terraform/modules/aws-textract-pipeline-part3/outputs.tf diff --git a/textract-pipeline/terraform/modules/aws-textract-pipeline-part3/variables.tf b/archive/textract-pipeline/terraform/modules/aws-textract-pipeline-part3/variables.tf similarity index 100% rename from textract-pipeline/terraform/modules/aws-textract-pipeline-part3/variables.tf rename to archive/textract-pipeline/terraform/modules/aws-textract-pipeline-part3/variables.tf diff --git a/textract-pipeline/terraform/modules/aws-textract-pipeline/main.tf b/archive/textract-pipeline/terraform/modules/aws-textract-pipeline/main.tf similarity index 100% rename from textract-pipeline/terraform/modules/aws-textract-pipeline/main.tf rename to archive/textract-pipeline/terraform/modules/aws-textract-pipeline/main.tf diff --git a/textract-pipeline/terraform/modules/aws-textract-pipeline/outputs.tf b/archive/textract-pipeline/terraform/modules/aws-textract-pipeline/outputs.tf similarity index 100% rename from textract-pipeline/terraform/modules/aws-textract-pipeline/outputs.tf rename to archive/textract-pipeline/terraform/modules/aws-textract-pipeline/outputs.tf diff --git a/textract-pipeline/terraform/modules/aws-textract-pipeline/variables.tf b/archive/textract-pipeline/terraform/modules/aws-textract-pipeline/variables.tf similarity index 100% rename from textract-pipeline/terraform/modules/aws-textract-pipeline/variables.tf rename to archive/textract-pipeline/terraform/modules/aws-textract-pipeline/variables.tf diff --git a/textract-pipeline/terraform/outputs.tf b/archive/textract-pipeline/terraform/outputs.tf similarity index 100% rename from textract-pipeline/terraform/outputs.tf rename to archive/textract-pipeline/terraform/outputs.tf diff --git a/textract-pipeline/terraform/snowsql-cicd.sh b/archive/textract-pipeline/terraform/snowsql-cicd.sh similarity index 100% rename from textract-pipeline/terraform/snowsql-cicd.sh rename to archive/textract-pipeline/terraform/snowsql-cicd.sh diff --git a/textract-pipeline/terraform/variables.tf b/archive/textract-pipeline/terraform/variables.tf similarity index 100% rename from textract-pipeline/terraform/variables.tf rename to archive/textract-pipeline/terraform/variables.tf diff --git a/textract-pipeline/terraform/vars-dev.tfvars b/archive/textract-pipeline/terraform/vars-dev.tfvars similarity index 100% rename from textract-pipeline/terraform/vars-dev.tfvars rename to archive/textract-pipeline/terraform/vars-dev.tfvars diff --git a/textract-pipeline/terraform/vars-prod.tfvars b/archive/textract-pipeline/terraform/vars-prod.tfvars similarity index 100% rename from textract-pipeline/terraform/vars-prod.tfvars rename to archive/textract-pipeline/terraform/vars-prod.tfvars diff --git a/textract-pipeline/terraform/vars-uat.tfvars b/archive/textract-pipeline/terraform/vars-uat.tfvars similarity index 100% rename from textract-pipeline/terraform/vars-uat.tfvars rename to archive/textract-pipeline/terraform/vars-uat.tfvars diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index 4d88471..e2d5dd3 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -1,962 +1,40 @@ definitions: scripts: - - script: &prep-dir - DIR=${DIR:=.}; - cd $DIR; - pip install poetry; - poetry install; - - script: &lint - poetry run black . - - script: &validate-static - poetry run mypy . - - script: &unit-test - poetry run pytest - - script: &aws-context - apt-get update; - apt-get install -y jq; - pip install awscli; - export AWS_ROLE_ARN=arn:aws:iam::$AWS_ACCOUNT_NO:role/$OIDC_ROLE; - export AWS_ROLE_SESSION_NAME=$OIDC_ROLE; - export AWS_WEB_IDENTITY_TOKEN_FILE=$(pwd)/web-identity-token; - echo $BITBUCKET_STEP_OIDC_TOKEN > $(pwd)/web-identity-token; - export AWS_ACCESS_KEY_ID=$(echo $STS_OUTPUT | jq -r '.Credentials.AccessKeyId'); - export AWS_SECRET_ACCESS_KEY=$(echo $STS_OUTPUT | jq -r '.Credentials.SecretAccessKey'); - export AWS_SECURITY_TOKEN=$(echo $STS_OUTPUT | jq -r '.Credentials.SessionToken'); - export AWS_REGION='us-east-2'; - aws sts get-caller-identity; - export IS_DEPLOY_ALL=true; - steps: &deployment-plan-steps - - step: - name: Plan devops-pipeline - image: hugree/bitbucket-aws-python38-tf154:latest - oidc: true - script: - - *prep-dir - - *aws-context - - python terraform.py plan --environment=$ENVIRONMENT --module=devops-pipeline/other-resources - caches: - - pip - - step: - name: Plan textract-pipeline - image: hugree/terraform-with-snowsql:latest - oidc: true - script: - - *prep-dir - - *aws-context - - python terraform.py plan --environment=$ENVIRONMENT --module=textract-pipeline/terraform - caches: - - pip - - step: - name: Plan streamlit-server - image: hugree/bitbucket-aws-python38-tf154:latest - oidc: true - script: - - *prep-dir - - *aws-context - - python terraform.py plan --environment=$ENVIRONMENT --module=streamlit-server - caches: - - pip - - step: - name: Plan Snowflake Changes - image: python:3.7 - size: 2x - script: - - pip install snowflake-connector-python - - pip install schemachange --upgrade - - | - schemachange -a $SNOWFLAKE_ACCOUNT -u $SNOWFLAKE_USER \ - -f snowflake/ \ - -r $SNOWFLAKE_ROLE -w $SNOWFLAKE_WAREHOUSE \ - -d $SNOWFLAKE_DATABASE -c $SNOWFLAKE_DATABASE.SCHEMACHANGE.CHANGE_HISTORY \ - --create-change-history-table -v \ - --dry-run - caches: - - pip - - step: - image: hugree/terraform-with-snowsql:latest - name: Plan Snowsql - oidc: true - script: - - *prep-dir - - *aws-context - - python terraform.py plan --environment=$ENVIRONMENT --module=textract-pipeline/terraform --apply-extra-args="-target=null_resource.snowsql_client_create" - caches: - - pip - - step: - image: python:3.8 - name: Plan streamlit to EC2 - oidc: true - script: - - *aws-context - - apt-get install -y git - - >- - aws ssm send-command --document-name "AWS-RunShellScript" --instance-ids $INSTANCE_ID_TF --region $AWS_DEFAULT_REGION --parameters commands='[ - "sudo -u ubuntu -i <- - aws ssm send-command --document-name "AWS-RunShellScript" --instance-ids $INSTANCE_ID_TF --region $AWS_DEFAULT_REGION --parameters commands='[ - "sudo -u ubuntu -i <=3.3.0)", "backports.zstd ; platform_python_implementation == \"CPython\" and python_version < \"3.14\"", "brotlicffi ; platform_python_implementation != \"CPython\""] - -[[package]] -name = "aiosignal" -version = "1.4.0" -description = "aiosignal: a list of registered asynchronous callbacks" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e"}, - {file = "aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7"}, -] - -[package.dependencies] -frozenlist = ">=1.1.0" -typing-extensions = {version = ">=4.2", markers = "python_version < \"3.13\""} - -[[package]] -name = "annotated-types" -version = "0.7.0" -description = "Reusable constraint types to use with typing.Annotated" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, - {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, -] - -[[package]] -name = "anthropic" -version = "0.36.2" -description = "The official Python library for the anthropic API" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "anthropic-0.36.2-py3-none-any.whl", hash = "sha256:308ddc6c538de03c081552e456bc0b387b6f7c7d1dea0c20122cc11c7cdbaf6a"}, - {file = "anthropic-0.36.2.tar.gz", hash = "sha256:d5a3fa56d1c82a51944f9dc7b0dc72048deb89f8df5ebfd09e2d1b59c62eb8eb"}, -] - -[package.dependencies] -anyio = ">=3.5.0,<5" -distro = ">=1.7.0,<2" -httpx = ">=0.23.0,<1" -jiter = ">=0.4.0,<1" -pydantic = ">=1.9.0,<3" -sniffio = "*" -tokenizers = ">=0.13.0" -typing-extensions = ">=4.7,<5" - -[package.extras] -bedrock = ["boto3 (>=1.28.57)", "botocore (>=1.31.57)"] -vertex = ["google-auth (>=2,<3)"] - -[[package]] -name = "anyio" -version = "4.11.0" -description = "High-level concurrency and networking framework on top of asyncio or Trio" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc"}, - {file = "anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4"}, -] - -[package.dependencies] -idna = ">=2.8" -sniffio = ">=1.1" -typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} - -[package.extras] -trio = ["trio (>=0.31.0)"] - -[[package]] -name = "appnope" -version = "0.1.4" -description = "Disable App Nap on macOS >= 10.9" -optional = false -python-versions = ">=3.6" -groups = ["dev"] -markers = "platform_system == \"Darwin\"" -files = [ - {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, - {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, -] - -[[package]] -name = "argon2-cffi" -version = "25.1.0" -description = "Argon2 for Python" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741"}, - {file = "argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1"}, -] - -[package.dependencies] -argon2-cffi-bindings = "*" - -[[package]] -name = "argon2-cffi-bindings" -version = "25.1.0" -description = "Low-level CFFI bindings for Argon2" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:3d3f05610594151994ca9ccb3c771115bdb4daef161976a266f0dd8aa9996b8f"}, - {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8b8efee945193e667a396cbc7b4fb7d357297d6234d30a489905d96caabde56b"}, - {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3c6702abc36bf3ccba3f802b799505def420a1b7039862014a65db3205967f5a"}, - {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1c70058c6ab1e352304ac7e3b52554daadacd8d453c1752e547c76e9c99ac44"}, - {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2fd3bfbff3c5d74fef31a722f729bf93500910db650c925c2d6ef879a7e51cb"}, - {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4f9665de60b1b0e99bcd6be4f17d90339698ce954cfd8d9cf4f91c995165a92"}, - {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ba92837e4a9aa6a508c8d2d7883ed5a8f6c308c89a4790e1e447a220deb79a85"}, - {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-win32.whl", hash = "sha256:84a461d4d84ae1295871329b346a97f68eade8c53b6ed9a7ca2d7467f3c8ff6f"}, - {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b55aec3565b65f56455eebc9b9f34130440404f27fe21c3b375bf1ea4d8fbae6"}, - {file = "argon2_cffi_bindings-25.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:87c33a52407e4c41f3b70a9c2d3f6056d88b10dad7695be708c5021673f55623"}, - {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500"}, - {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44"}, - {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0"}, - {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6"}, - {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a"}, - {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d"}, - {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99"}, - {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2"}, - {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98"}, - {file = "argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94"}, - {file = "argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e"}, - {file = "argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d"}, - {file = "argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584"}, - {file = "argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690"}, - {file = "argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520"}, - {file = "argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d"}, -] - -[package.dependencies] -cffi = [ - {version = ">=1.0.1", markers = "python_version < \"3.14\""}, - {version = ">=2.0.0b1", markers = "python_version >= \"3.14\""}, -] - -[[package]] -name = "arrow" -version = "1.4.0" -description = "Better dates & times for Python" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205"}, - {file = "arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7"}, -] - -[package.dependencies] -python-dateutil = ">=2.7.0" -tzdata = {version = "*", markers = "python_version >= \"3.9\""} - -[package.extras] -doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"] -test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2025.2)", "simplejson (==3.*)"] - -[[package]] -name = "asttokens" -version = "3.0.0" -description = "Annotate AST trees with source code positions" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"}, - {file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"}, -] - -[package.extras] -astroid = ["astroid (>=2,<4)"] -test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"] - -[[package]] -name = "async-lru" -version = "2.0.5" -description = "Simple LRU cache for asyncio" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943"}, - {file = "async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb"}, -] - -[[package]] -name = "attrs" -version = "25.4.0" -description = "Classes Without Boilerplate" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373"}, - {file = "attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11"}, -] - -[[package]] -name = "babel" -version = "2.17.0" -description = "Internationalization utilities" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"}, - {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"}, -] - -[package.extras] -dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] - -[[package]] -name = "beautifulsoup4" -version = "4.14.2" -description = "Screen-scraping library" -optional = false -python-versions = ">=3.7.0" -groups = ["dev"] -files = [ - {file = "beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515"}, - {file = "beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e"}, -] - -[package.dependencies] -soupsieve = ">1.2" -typing-extensions = ">=4.0.0" - -[package.extras] -cchardet = ["cchardet"] -chardet = ["chardet"] -charset-normalizer = ["charset-normalizer"] -html5lib = ["html5lib"] -lxml = ["lxml"] - -[[package]] -name = "black" -version = "24.10.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, - {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, - {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, - {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, - {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, - {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, - {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, - {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, - {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, - {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, - {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, - {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, - {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, - {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, - {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, - {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, - {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, - {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, - {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, - {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, - {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, - {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.10)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "bleach" -version = "6.3.0" -description = "An easy safelist-based HTML-sanitizing tool." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6"}, - {file = "bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22"}, -] - -[package.dependencies] -tinycss2 = {version = ">=1.1.0,<1.5", optional = true, markers = "extra == \"css\""} -webencodings = "*" - -[package.extras] -css = ["tinycss2 (>=1.1.0,<1.5)"] - -[[package]] -name = "boto3" -version = "1.40.63" -description = "The AWS SDK for Python" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "boto3-1.40.63-py3-none-any.whl", hash = "sha256:f15d4abf1a6283887c336f660cdfc2162a210d2d8f4d98dbcbcef983371c284d"}, - {file = "boto3-1.40.63.tar.gz", hash = "sha256:3bf4b034900c87a6a9b3b3b44c4aec26e96fc73bff2505f0766224b7295178ce"}, -] - -[package.dependencies] -botocore = ">=1.40.63,<1.41.0" -jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.14.0,<0.15.0" - -[package.extras] -crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] - -[[package]] -name = "botocore" -version = "1.40.63" -description = "Low-level, data-driven core of boto 3." -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "botocore-1.40.63-py3-none-any.whl", hash = "sha256:83657b3ee487268fccc9ba022cba572ba657b9ece8cddd1fa241e2c6a49c8c14"}, - {file = "botocore-1.40.63.tar.gz", hash = "sha256:0324552c3c800e258cbcb8c22b495a2e2e0260a7408d08016196e46fa0d1b587"}, -] - -[package.dependencies] -jmespath = ">=0.7.1,<2.0.0" -python-dateutil = ">=2.1,<3.0.0" -urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} - -[package.extras] -crt = ["awscrt (==0.27.6)"] - -[[package]] -name = "certifi" -version = "2025.10.5" -description = "Python package for providing Mozilla's CA Bundle." -optional = false -python-versions = ">=3.7" -groups = ["main", "dev"] -files = [ - {file = "certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de"}, - {file = "certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43"}, -] - -[[package]] -name = "cffi" -version = "2.0.0" -description = "Foreign Function Interface for Python calling C code." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, - {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, - {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, - {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, - {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, - {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, - {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, - {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, - {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, - {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, - {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, - {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, - {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, - {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, - {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, - {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, - {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, - {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, - {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, - {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, - {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, - {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, - {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, - {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, - {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, - {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, - {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, - {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, - {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, - {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, - {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, - {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, - {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, - {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, - {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, - {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, - {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, - {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, - {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, - {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, - {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, - {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, - {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, - {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, - {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, - {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, - {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, - {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, - {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, - {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, - {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, -] - -[package.dependencies] -pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} - -[[package]] -name = "charset-normalizer" -version = "3.4.4" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.7" -groups = ["main", "dev"] -files = [ - {file = "charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d"}, - {file = "charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016"}, - {file = "charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525"}, - {file = "charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14"}, - {file = "charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c"}, - {file = "charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ce8a0633f41a967713a59c4139d29110c07e826d131a316b50ce11b1d79b4f84"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaabd426fe94daf8fd157c32e571c85cb12e66692f15516a83a03264b08d06c3"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c4ef880e27901b6cc782f1b95f82da9313c0eb95c3af699103088fa0ac3ce9ac"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aaba3b0819274cc41757a1da876f810a3e4d7b6eb25699253a4effef9e8e4af"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:778d2e08eda00f4256d7f672ca9fef386071c9202f5e4607920b86d7803387f2"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f155a433c2ec037d4e8df17d18922c3a0d9b3232a396690f17175d2946f0218d"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8bf8d0f749c5757af2142fe7903a9df1d2e8aa3841559b2bad34b08d0e2bcf3"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:194f08cbb32dc406d6e1aea671a68be0823673db2832b38405deba2fb0d88f63"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:6aee717dcfead04c6eb1ce3bd29ac1e22663cdea57f943c87d1eab9a025438d7"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cd4b7ca9984e5e7985c12bc60a6f173f3c958eae74f3ef6624bb6b26e2abbae4"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:b7cf1017d601aa35e6bb650b6ad28652c9cd78ee6caff19f3c28d03e1c80acbf"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e912091979546adf63357d7e2ccff9b44f026c075aeaf25a52d0e95ad2281074"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5cb4d72eea50c8868f5288b7f7f33ed276118325c1dfd3957089f6b519e1382a"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-win32.whl", hash = "sha256:837c2ce8c5a65a2035be9b3569c684358dfbf109fd3b6969630a87535495ceaa"}, - {file = "charset_normalizer-3.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:44c2a8734b333e0578090c4cd6b16f275e07aa6614ca8715e6c038e865e70576"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-win32.whl", hash = "sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966"}, - {file = "charset_normalizer-3.4.4-cp39-cp39-win_arm64.whl", hash = "sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50"}, - {file = "charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f"}, - {file = "charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a"}, -] - -[[package]] -name = "click" -version = "8.3.0" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.10" -groups = ["main", "dev"] -files = [ - {file = "click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc"}, - {file = "click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev", "test"] -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] -markers = {main = "platform_system == \"Windows\" or sys_platform == \"win32\"", dev = "platform_system == \"Windows\" or sys_platform == \"win32\"", test = "sys_platform == \"win32\""} - -[[package]] -name = "comm" -version = "0.2.3" -description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417"}, - {file = "comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971"}, -] - -[package.extras] -test = ["pytest"] - -[[package]] -name = "coverage" -version = "7.11.0" -description = "Code coverage measurement for Python" -optional = false -python-versions = ">=3.10" -groups = ["test"] -files = [ - {file = "coverage-7.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eb53f1e8adeeb2e78962bade0c08bfdc461853c7969706ed901821e009b35e31"}, - {file = "coverage-7.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9a03ec6cb9f40a5c360f138b88266fd8f58408d71e89f536b4f91d85721d075"}, - {file = "coverage-7.11.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0d7f0616c557cbc3d1c2090334eddcbb70e1ae3a40b07222d62b3aa47f608fab"}, - {file = "coverage-7.11.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e44a86a47bbdf83b0a3ea4d7df5410d6b1a0de984fbd805fa5101f3624b9abe0"}, - {file = "coverage-7.11.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:596763d2f9a0ee7eec6e643e29660def2eef297e1de0d334c78c08706f1cb785"}, - {file = "coverage-7.11.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ef55537ff511b5e0a43edb4c50a7bf7ba1c3eea20b4f49b1490f1e8e0e42c591"}, - {file = "coverage-7.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cbabd8f4d0d3dc571d77ae5bdbfa6afe5061e679a9d74b6797c48d143307088"}, - {file = "coverage-7.11.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e24045453384e0ae2a587d562df2a04d852672eb63051d16096d3f08aa4c7c2f"}, - {file = "coverage-7.11.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:7161edd3426c8d19bdccde7d49e6f27f748f3c31cc350c5de7c633fea445d866"}, - {file = "coverage-7.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d4ed4de17e692ba6415b0587bc7f12bc80915031fc9db46a23ce70fc88c9841"}, - {file = "coverage-7.11.0-cp310-cp310-win32.whl", hash = "sha256:765c0bc8fe46f48e341ef737c91c715bd2a53a12792592296a095f0c237e09cf"}, - {file = "coverage-7.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:24d6f3128f1b2d20d84b24f4074475457faedc3d4613a7e66b5e769939c7d969"}, - {file = "coverage-7.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d58ecaa865c5b9fa56e35efc51d1014d4c0d22838815b9fce57a27dd9576847"}, - {file = "coverage-7.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b679e171f1c104a5668550ada700e3c4937110dbdd153b7ef9055c4f1a1ee3cc"}, - {file = "coverage-7.11.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ca61691ba8c5b6797deb221a0d09d7470364733ea9c69425a640f1f01b7c5bf0"}, - {file = "coverage-7.11.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:aef1747ede4bd8ca9cfc04cc3011516500c6891f1b33a94add3253f6f876b7b7"}, - {file = "coverage-7.11.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1839d08406e4cba2953dcc0ffb312252f14d7c4c96919f70167611f4dee2623"}, - {file = "coverage-7.11.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e0eb0a2dcc62478eb5b4cbb80b97bdee852d7e280b90e81f11b407d0b81c4287"}, - {file = "coverage-7.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fbea96343b53f65d5351d8fd3b34fd415a2670d7c300b06d3e14a5af4f552"}, - {file = "coverage-7.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:214b622259dd0cf435f10241f1333d32caa64dbc27f8790ab693428a141723de"}, - {file = "coverage-7.11.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:258d9967520cca899695d4eb7ea38be03f06951d6ca2f21fb48b1235f791e601"}, - {file = "coverage-7.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cf9e6ff4ca908ca15c157c409d608da77a56a09877b97c889b98fb2c32b6465e"}, - {file = "coverage-7.11.0-cp311-cp311-win32.whl", hash = "sha256:fcc15fc462707b0680cff6242c48625da7f9a16a28a41bb8fd7a4280920e676c"}, - {file = "coverage-7.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:865965bf955d92790f1facd64fe7ff73551bd2c1e7e6b26443934e9701ba30b9"}, - {file = "coverage-7.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:5693e57a065760dcbeb292d60cc4d0231a6d4b6b6f6a3191561e1d5e8820b745"}, - {file = "coverage-7.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9c49e77811cf9d024b95faf86c3f059b11c0c9be0b0d61bc598f453703bd6fd1"}, - {file = "coverage-7.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a61e37a403a778e2cda2a6a39abcc895f1d984071942a41074b5c7ee31642007"}, - {file = "coverage-7.11.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c79cae102bb3b1801e2ef1511fb50e91ec83a1ce466b2c7c25010d884336de46"}, - {file = "coverage-7.11.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:16ce17ceb5d211f320b62df002fa7016b7442ea0fd260c11cec8ce7730954893"}, - {file = "coverage-7.11.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80027673e9d0bd6aef86134b0771845e2da85755cf686e7c7c59566cf5a89115"}, - {file = "coverage-7.11.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4d3ffa07a08657306cd2215b0da53761c4d73cb54d9143b9303a6481ec0cd415"}, - {file = "coverage-7.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a3b6a5f8b2524fd6c1066bc85bfd97e78709bb5e37b5b94911a6506b65f47186"}, - {file = "coverage-7.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fcc0a4aa589de34bc56e1a80a740ee0f8c47611bdfb28cd1849de60660f3799d"}, - {file = "coverage-7.11.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dba82204769d78c3fd31b35c3d5f46e06511936c5019c39f98320e05b08f794d"}, - {file = "coverage-7.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:81b335f03ba67309a95210caf3eb43bd6fe75a4e22ba653ef97b4696c56c7ec2"}, - {file = "coverage-7.11.0-cp312-cp312-win32.whl", hash = "sha256:037b2d064c2f8cc8716fe4d39cb705779af3fbf1ba318dc96a1af858888c7bb5"}, - {file = "coverage-7.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:d66c0104aec3b75e5fd897e7940188ea1892ca1d0235316bf89286d6a22568c0"}, - {file = "coverage-7.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:d91ebeac603812a09cf6a886ba6e464f3bbb367411904ae3790dfe28311b15ad"}, - {file = "coverage-7.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cc3f49e65ea6e0d5d9bd60368684fe52a704d46f9e7fc413918f18d046ec40e1"}, - {file = "coverage-7.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f39ae2f63f37472c17b4990f794035c9890418b1b8cca75c01193f3c8d3e01be"}, - {file = "coverage-7.11.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7db53b5cdd2917b6eaadd0b1251cf4e7d96f4a8d24e174bdbdf2f65b5ea7994d"}, - {file = "coverage-7.11.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10ad04ac3a122048688387828b4537bc9cf60c0bf4869c1e9989c46e45690b82"}, - {file = "coverage-7.11.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4036cc9c7983a2b1f2556d574d2eb2154ac6ed55114761685657e38782b23f52"}, - {file = "coverage-7.11.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7ab934dd13b1c5e94b692b1e01bd87e4488cb746e3a50f798cb9464fd128374b"}, - {file = "coverage-7.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59a6e5a265f7cfc05f76e3bb53eca2e0dfe90f05e07e849930fecd6abb8f40b4"}, - {file = "coverage-7.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:df01d6c4c81e15a7c88337b795bb7595a8596e92310266b5072c7e301168efbd"}, - {file = "coverage-7.11.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:8c934bd088eed6174210942761e38ee81d28c46de0132ebb1801dbe36a390dcc"}, - {file = "coverage-7.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a03eaf7ec24078ad64a07f02e30060aaf22b91dedf31a6b24d0d98d2bba7f48"}, - {file = "coverage-7.11.0-cp313-cp313-win32.whl", hash = "sha256:695340f698a5f56f795b2836abe6fb576e7c53d48cd155ad2f80fd24bc63a040"}, - {file = "coverage-7.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:2727d47fce3ee2bac648528e41455d1b0c46395a087a229deac75e9f88ba5a05"}, - {file = "coverage-7.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:0efa742f431529699712b92ecdf22de8ff198df41e43aeaaadf69973eb93f17a"}, - {file = "coverage-7.11.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:587c38849b853b157706407e9ebdca8fd12f45869edb56defbef2daa5fb0812b"}, - {file = "coverage-7.11.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b971bdefdd75096163dd4261c74be813c4508477e39ff7b92191dea19f24cd37"}, - {file = "coverage-7.11.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:269bfe913b7d5be12ab13a95f3a76da23cf147be7fa043933320ba5625f0a8de"}, - {file = "coverage-7.11.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:dadbcce51a10c07b7c72b0ce4a25e4b6dcb0c0372846afb8e5b6307a121eb99f"}, - {file = "coverage-7.11.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9ed43fa22c6436f7957df036331f8fe4efa7af132054e1844918866cd228af6c"}, - {file = "coverage-7.11.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9516add7256b6713ec08359b7b05aeff8850c98d357784c7205b2e60aa2513fa"}, - {file = "coverage-7.11.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb92e47c92fcbcdc692f428da67db33337fa213756f7adb6a011f7b5a7a20740"}, - {file = "coverage-7.11.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d06f4fc7acf3cabd6d74941d53329e06bab00a8fe10e4df2714f0b134bfc64ef"}, - {file = "coverage-7.11.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:6fbcee1a8f056af07ecd344482f711f563a9eb1c2cad192e87df00338ec3cdb0"}, - {file = "coverage-7.11.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dbbf012be5f32533a490709ad597ad8a8ff80c582a95adc8d62af664e532f9ca"}, - {file = "coverage-7.11.0-cp313-cp313t-win32.whl", hash = "sha256:cee6291bb4fed184f1c2b663606a115c743df98a537c969c3c64b49989da96c2"}, - {file = "coverage-7.11.0-cp313-cp313t-win_amd64.whl", hash = "sha256:a386c1061bf98e7ea4758e4313c0ab5ecf57af341ef0f43a0bf26c2477b5c268"}, - {file = "coverage-7.11.0-cp313-cp313t-win_arm64.whl", hash = "sha256:f9ea02ef40bb83823b2b04964459d281688fe173e20643870bb5d2edf68bc836"}, - {file = "coverage-7.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c770885b28fb399aaf2a65bbd1c12bf6f307ffd112d6a76c5231a94276f0c497"}, - {file = "coverage-7.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a3d0e2087dba64c86a6b254f43e12d264b636a39e88c5cc0a01a7c71bcfdab7e"}, - {file = "coverage-7.11.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:73feb83bb41c32811973b8565f3705caf01d928d972b72042b44e97c71fd70d1"}, - {file = "coverage-7.11.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c6f31f281012235ad08f9a560976cc2fc9c95c17604ff3ab20120fe480169bca"}, - {file = "coverage-7.11.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9570ad567f880ef675673992222746a124b9595506826b210fbe0ce3f0499cd"}, - {file = "coverage-7.11.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8badf70446042553a773547a61fecaa734b55dc738cacf20c56ab04b77425e43"}, - {file = "coverage-7.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a09c1211959903a479e389685b7feb8a17f59ec5a4ef9afde7650bd5eabc2777"}, - {file = "coverage-7.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:5ef83b107f50db3f9ae40f69e34b3bd9337456c5a7fe3461c7abf8b75dd666a2"}, - {file = "coverage-7.11.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f91f927a3215b8907e214af77200250bb6aae36eca3f760f89780d13e495388d"}, - {file = "coverage-7.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cdbcd376716d6b7fbfeedd687a6c4be019c5a5671b35f804ba76a4c0a778cba4"}, - {file = "coverage-7.11.0-cp314-cp314-win32.whl", hash = "sha256:bab7ec4bb501743edc63609320aaec8cd9188b396354f482f4de4d40a9d10721"}, - {file = "coverage-7.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:3d4ba9a449e9364a936a27322b20d32d8b166553bfe63059bd21527e681e2fad"}, - {file = "coverage-7.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:ce37f215223af94ef0f75ac68ea096f9f8e8c8ec7d6e8c346ee45c0d363f0479"}, - {file = "coverage-7.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:f413ce6e07e0d0dc9c433228727b619871532674b45165abafe201f200cc215f"}, - {file = "coverage-7.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:05791e528a18f7072bf5998ba772fe29db4da1234c45c2087866b5ba4dea710e"}, - {file = "coverage-7.11.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cacb29f420cfeb9283b803263c3b9a068924474ff19ca126ba9103e1278dfa44"}, - {file = "coverage-7.11.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:314c24e700d7027ae3ab0d95fbf8d53544fca1f20345fd30cd219b737c6e58d3"}, - {file = "coverage-7.11.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:630d0bd7a293ad2fc8b4b94e5758c8b2536fdf36c05f1681270203e463cbfa9b"}, - {file = "coverage-7.11.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e89641f5175d65e2dbb44db15fe4ea48fade5d5bbb9868fdc2b4fce22f4a469d"}, - {file = "coverage-7.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c9f08ea03114a637dab06cedb2e914da9dc67fa52c6015c018ff43fdde25b9c2"}, - {file = "coverage-7.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce9f3bde4e9b031eaf1eb61df95c1401427029ea1bfddb8621c1161dcb0fa02e"}, - {file = "coverage-7.11.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:e4dc07e95495923d6fd4d6c27bf70769425b71c89053083843fd78f378558996"}, - {file = "coverage-7.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:424538266794db2861db4922b05d729ade0940ee69dcf0591ce8f69784db0e11"}, - {file = "coverage-7.11.0-cp314-cp314t-win32.whl", hash = "sha256:4c1eeb3fb8eb9e0190bebafd0462936f75717687117339f708f395fe455acc73"}, - {file = "coverage-7.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b56efee146c98dbf2cf5cffc61b9829d1e94442df4d7398b26892a53992d3547"}, - {file = "coverage-7.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:b5c2705afa83f49bd91962a4094b6b082f94aef7626365ab3f8f4bd159c5acf3"}, - {file = "coverage-7.11.0-py3-none-any.whl", hash = "sha256:4b7589765348d78fb4e5fb6ea35d07564e387da2fc5efff62e0222971f155f68"}, - {file = "coverage-7.11.0.tar.gz", hash = "sha256:167bd504ac1ca2af7ff3b81d245dfea0292c5032ebef9d66cc08a7d28c1b8050"}, -] - -[package.extras] -toml = ["tomli ; python_full_version <= \"3.11.0a6\""] - -[[package]] -name = "dataclasses-json" -version = "0.6.7" -description = "Easily serialize dataclasses to and from JSON." -optional = false -python-versions = "<4.0,>=3.7" -groups = ["main"] -files = [ - {file = "dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a"}, - {file = "dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0"}, -] - -[package.dependencies] -marshmallow = ">=3.18.0,<4.0.0" -typing-inspect = ">=0.4.0,<1" - -[[package]] -name = "debugpy" -version = "1.8.17" -description = "An implementation of the Debug Adapter Protocol for Python" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "debugpy-1.8.17-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:c41d2ce8bbaddcc0009cc73f65318eedfa3dbc88a8298081deb05389f1ab5542"}, - {file = "debugpy-1.8.17-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:1440fd514e1b815edd5861ca394786f90eb24960eb26d6f7200994333b1d79e3"}, - {file = "debugpy-1.8.17-cp310-cp310-win32.whl", hash = "sha256:3a32c0af575749083d7492dc79f6ab69f21b2d2ad4cd977a958a07d5865316e4"}, - {file = "debugpy-1.8.17-cp310-cp310-win_amd64.whl", hash = "sha256:a3aad0537cf4d9c1996434be68c6c9a6d233ac6f76c2a482c7803295b4e4f99a"}, - {file = "debugpy-1.8.17-cp311-cp311-macosx_15_0_universal2.whl", hash = "sha256:d3fce3f0e3de262a3b67e69916d001f3e767661c6e1ee42553009d445d1cd840"}, - {file = "debugpy-1.8.17-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:c6bdf134457ae0cac6fb68205776be635d31174eeac9541e1d0c062165c6461f"}, - {file = "debugpy-1.8.17-cp311-cp311-win32.whl", hash = "sha256:e79a195f9e059edfe5d8bf6f3749b2599452d3e9380484cd261f6b7cd2c7c4da"}, - {file = "debugpy-1.8.17-cp311-cp311-win_amd64.whl", hash = "sha256:b532282ad4eca958b1b2d7dbcb2b7218e02cb934165859b918e3b6ba7772d3f4"}, - {file = "debugpy-1.8.17-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:f14467edef672195c6f6b8e27ce5005313cb5d03c9239059bc7182b60c176e2d"}, - {file = "debugpy-1.8.17-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:24693179ef9dfa20dca8605905a42b392be56d410c333af82f1c5dff807a64cc"}, - {file = "debugpy-1.8.17-cp312-cp312-win32.whl", hash = "sha256:6a4e9dacf2cbb60d2514ff7b04b4534b0139facbf2abdffe0639ddb6088e59cf"}, - {file = "debugpy-1.8.17-cp312-cp312-win_amd64.whl", hash = "sha256:e8f8f61c518952fb15f74a302e068b48d9c4691768ade433e4adeea961993464"}, - {file = "debugpy-1.8.17-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:857c1dd5d70042502aef1c6d1c2801211f3ea7e56f75e9c335f434afb403e464"}, - {file = "debugpy-1.8.17-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:3bea3b0b12f3946e098cce9b43c3c46e317b567f79570c3f43f0b96d00788088"}, - {file = "debugpy-1.8.17-cp313-cp313-win32.whl", hash = "sha256:e34ee844c2f17b18556b5bbe59e1e2ff4e86a00282d2a46edab73fd7f18f4a83"}, - {file = "debugpy-1.8.17-cp313-cp313-win_amd64.whl", hash = "sha256:6c5cd6f009ad4fca8e33e5238210dc1e5f42db07d4b6ab21ac7ffa904a196420"}, - {file = "debugpy-1.8.17-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:045290c010bcd2d82bc97aa2daf6837443cd52f6328592698809b4549babcee1"}, - {file = "debugpy-1.8.17-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:b69b6bd9dba6a03632534cdf67c760625760a215ae289f7489a452af1031fe1f"}, - {file = "debugpy-1.8.17-cp314-cp314-win32.whl", hash = "sha256:5c59b74aa5630f3a5194467100c3b3d1c77898f9ab27e3f7dc5d40fc2f122670"}, - {file = "debugpy-1.8.17-cp314-cp314-win_amd64.whl", hash = "sha256:893cba7bb0f55161de4365584b025f7064e1f88913551bcd23be3260b231429c"}, - {file = "debugpy-1.8.17-cp38-cp38-macosx_15_0_x86_64.whl", hash = "sha256:8deb4e31cd575c9f9370042876e078ca118117c1b5e1f22c32befcfbb6955f0c"}, - {file = "debugpy-1.8.17-cp38-cp38-manylinux_2_34_x86_64.whl", hash = "sha256:b75868b675949a96ab51abc114c7163f40ff0d8f7d6d5fd63f8932fd38e9c6d7"}, - {file = "debugpy-1.8.17-cp38-cp38-win32.whl", hash = "sha256:17e456da14848d618662354e1dccfd5e5fb75deec3d1d48dc0aa0baacda55860"}, - {file = "debugpy-1.8.17-cp38-cp38-win_amd64.whl", hash = "sha256:e851beb536a427b5df8aa7d0c7835b29a13812f41e46292ff80b2ef77327355a"}, - {file = "debugpy-1.8.17-cp39-cp39-macosx_15_0_x86_64.whl", hash = "sha256:f2ac8055a0c4a09b30b931100996ba49ef334c6947e7ae365cdd870416d7513e"}, - {file = "debugpy-1.8.17-cp39-cp39-manylinux_2_34_x86_64.whl", hash = "sha256:eaa85bce251feca8e4c87ce3b954aba84b8c645b90f0e6a515c00394a9f5c0e7"}, - {file = "debugpy-1.8.17-cp39-cp39-win32.whl", hash = "sha256:b13eea5587e44f27f6c48588b5ad56dcb74a4f3a5f89250443c94587f3eb2ea1"}, - {file = "debugpy-1.8.17-cp39-cp39-win_amd64.whl", hash = "sha256:bb1bbf92317e1f35afcf3ef0450219efb3afe00be79d8664b250ac0933b9015f"}, - {file = "debugpy-1.8.17-py2.py3-none-any.whl", hash = "sha256:60c7dca6571efe660ccb7a9508d73ca14b8796c4ed484c2002abba714226cfef"}, - {file = "debugpy-1.8.17.tar.gz", hash = "sha256:fd723b47a8c08892b1a16b2c6239a8b96637c62a59b94bb5dab4bac592a58a8e"}, -] - -[[package]] -name = "decorator" -version = "5.2.1" -description = "Decorators for Humans" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"}, - {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"}, -] - -[[package]] -name = "defusedxml" -version = "0.7.1" -description = "XML bomb protection for Python stdlib modules" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -groups = ["dev"] -files = [ - {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, - {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, -] - -[[package]] -name = "distro" -version = "1.9.0" -description = "Distro - an OS platform information API" -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, - {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, -] - -[[package]] -name = "et-xmlfile" -version = "2.0.0" -description = "An implementation of lxml.xmlfile for the standard library" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa"}, - {file = "et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54"}, -] - -[[package]] -name = "executing" -version = "2.2.1" -description = "Get the currently executing AST node of a frame, and other information" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017"}, - {file = "executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4"}, -] - -[package.extras] -tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""] - -[[package]] -name = "faiss-cpu" -version = "1.11.0.post1" -description = "A library for efficient similarity search and clustering of dense vectors." -optional = false -python-versions = ">=3.9" -groups = ["main"] -markers = "python_version >= \"3.14\"" -files = [ - {file = "faiss_cpu-1.11.0.post1-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:e079d44ea22919f6477fea553b05854c68838ab553e1c6b1237437a8becdf89d"}, - {file = "faiss_cpu-1.11.0.post1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:4ded0c91cb67f462ae00a4d339718ea2fbb23eedbf260c3a07de77c32c23205a"}, - {file = "faiss_cpu-1.11.0.post1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78812f4d7ff9d3773f50009efcf294f3da787cd8c835c1fc41d997a58100f7b5"}, - {file = "faiss_cpu-1.11.0.post1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:76b133d746ddb3e6d39e6de62ff717cf4d45110d4af101a62d6a4fed4cd1d4d1"}, - {file = "faiss_cpu-1.11.0.post1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9443bc89447f9988f2288477584d2f1c59424a5e9f9a202e4ada8708df816db1"}, - {file = "faiss_cpu-1.11.0.post1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6acc20021b69bd30d3cb5cadb4f8dc1c338aec887cd5411b0982e8a3e48b3d7f"}, - {file = "faiss_cpu-1.11.0.post1-cp310-cp310-win_amd64.whl", hash = "sha256:9dccf67d4087f9b0f937d4dccd1183929ebb6fe7622b75cba51b53e4f0055a0c"}, - {file = "faiss_cpu-1.11.0.post1-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:2c8c384e65cc1b118d2903d9f3a27cd35f6c45337696fc0437f71e05f732dbc0"}, - {file = "faiss_cpu-1.11.0.post1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:36af46945274ed14751b788673125a8a4900408e4837a92371b0cad5708619ea"}, - {file = "faiss_cpu-1.11.0.post1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b15412b22a05865433aecfdebf7664b9565bd49b600d23a0a27c74a5526893e"}, - {file = "faiss_cpu-1.11.0.post1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:81c169ea74213b2c055b8240befe7e9b42a1f3d97cda5238b3b401035ce1a18b"}, - {file = "faiss_cpu-1.11.0.post1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0794eb035c6075e931996cf2b2703fbb3f47c8c34bc2d727819ddc3e5e486a31"}, - {file = "faiss_cpu-1.11.0.post1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18d2221014813dc9a4236e47f9c4097a71273fbf17c3fe66243e724e2018a67a"}, - {file = "faiss_cpu-1.11.0.post1-cp311-cp311-win_amd64.whl", hash = "sha256:3ce8a8984a7dcc689fd192c69a476ecd0b2611c61f96fe0799ff432aa73ff79c"}, - {file = "faiss_cpu-1.11.0.post1-cp311-cp311-win_arm64.whl", hash = "sha256:8384e05afb7c7968e93b81566759f862e744c0667b175086efb3d8b20949b39f"}, - {file = "faiss_cpu-1.11.0.post1-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:68f6ce2d9c510a5765af2f5711bd76c2c37bd598af747f3300224bdccf45378c"}, - {file = "faiss_cpu-1.11.0.post1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b940c530a8236cc0b9fd9d6e87b3d70b9c6c216bc2baf2649356c908902e52c9"}, - {file = "faiss_cpu-1.11.0.post1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fafae1dcbcba3856a0bb82ffb0c3cae5922bdd6566fdd3b7feb2425cf4fca247"}, - {file = "faiss_cpu-1.11.0.post1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5d1262702c19aba2d23144b73f4b5730ca988c1f4e43ecec87edf25171cafe3d"}, - {file = "faiss_cpu-1.11.0.post1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:925feb69c06bfcc7f28869c99ab172f123e4b9d97a7e1353316fcc2748696f5b"}, - {file = "faiss_cpu-1.11.0.post1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:00a837581b675f099c80c8c46908648dcf944a8992dd21e3887c61c6b110fe5f"}, - {file = "faiss_cpu-1.11.0.post1-cp312-cp312-win_amd64.whl", hash = "sha256:8bbaef5b56d1b0c01357ee6449d464ea4e52732fdb53a40bb5b9d77923af905f"}, - {file = "faiss_cpu-1.11.0.post1-cp312-cp312-win_arm64.whl", hash = "sha256:57f85dbefe590f8399a95c07e839ee64373cfcc6db5dd35232a41137e3deefeb"}, - {file = "faiss_cpu-1.11.0.post1-cp313-cp313-macosx_13_0_x86_64.whl", hash = "sha256:caedaddfbfe365e3f1a57d5151cf94ea7b73c0e4789caf68eae05e0e10ca9fbf"}, - {file = "faiss_cpu-1.11.0.post1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:202d11f1d973224ca0bde13e7ee8b862b6de74287e626f9f8820b360e6253d12"}, - {file = "faiss_cpu-1.11.0.post1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f6086e25ef680301350d6db72db7315e3531582cf896a7ee3f26295b1da73c44"}, - {file = "faiss_cpu-1.11.0.post1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b93131842996efbbf76f07dba1775d3a5f355f74b9ba34334f1149aef046b37f"}, - {file = "faiss_cpu-1.11.0.post1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f26e3e93f537b2e1633212a1b0a7dab74d77825366ed575ca434dac2fa14cea6"}, - {file = "faiss_cpu-1.11.0.post1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7f4b0e03cd758d03012d88aa4a70e673d10b66f31f7c122adc0c8c323cad2e33"}, - {file = "faiss_cpu-1.11.0.post1-cp313-cp313-win_amd64.whl", hash = "sha256:bc53fe59b546dbab63144dc19dcee534ad7a213db617b37aa4d0e33c26f9bbaf"}, - {file = "faiss_cpu-1.11.0.post1-cp313-cp313-win_arm64.whl", hash = "sha256:9cebb720cd57afdbe9dd7ed8a689c65dc5cf1bad475c5aa6fa0d0daea890beb6"}, - {file = "faiss_cpu-1.11.0.post1-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:3663059682589a42e3c4da0f3915492c466c886954cf9280273f92257bcfa0b4"}, - {file = "faiss_cpu-1.11.0.post1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:0348794ae91fb1454f2cddf7a9c7de23510f2a63e60c0fba0ae73bc7bf23a060"}, - {file = "faiss_cpu-1.11.0.post1-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8baf46be73b4fce99f4620d99a52cdb01f7823a849f00064f02802f554d8b59f"}, - {file = "faiss_cpu-1.11.0.post1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:388a590ab2847e421ba2702ff2774835287f137fb77e24e679f0063c1c10a96f"}, - {file = "faiss_cpu-1.11.0.post1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dc12b3f89cf48be3f2a20b37f310c3f1a7a5708fdf705f88d639339a24bb590b"}, - {file = "faiss_cpu-1.11.0.post1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:773fa45aa98a210ab4e2c17c1b5fb45f6d7e9acb4979c9a0b320b678984428ac"}, - {file = "faiss_cpu-1.11.0.post1-cp39-cp39-win_amd64.whl", hash = "sha256:6240c4b1551eedc07e76813c2e14a1583a1db6c319a92a3934bf212d0e4c7791"}, -] - -[package.dependencies] -numpy = ">=1.25.0,<3.0" -packaging = "*" - -[[package]] -name = "faiss-cpu" -version = "1.12.0" -description = "A library for efficient similarity search and clustering of dense vectors." -optional = false -python-versions = "<3.15,>=3.9" -groups = ["main"] -markers = "python_version <= \"3.13\"" -files = [ - {file = "faiss_cpu-1.12.0-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:be96f9290edd13d56fb3c69b8dd6be487552b4401f2e95b437cabf5309c424ad"}, - {file = "faiss_cpu-1.12.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:0834c547c39d5e5d0b769c90ac5d5ca42e00bcdbba491f3440d2d458058b19d6"}, - {file = "faiss_cpu-1.12.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a40830a16d8718b14a462e1a1efaa26660eb3bb8ada22e0712a6ac181092750e"}, - {file = "faiss_cpu-1.12.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7f8732796e3f730556e99327861066ead0ae7e66b5cbf6c0f217be48074e41e"}, - {file = "faiss_cpu-1.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ded5063e13c3bb6b1b463827f838ae45a0aea4c9aeaf6c938e7e87f3f6ea4126"}, - {file = "faiss_cpu-1.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8e74e71249165757a12fb02feee67ea95df542bcafa21b449fbd2ed0c31b48b4"}, - {file = "faiss_cpu-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:d04d1cae2a9b66083cd8f48ff391731d81e0a1fdf67ab5c33ae10b3a22a0caae"}, - {file = "faiss_cpu-1.12.0-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:fbb63595c7ad43c0d9caaf4d554a38a30ea4edda5e7c3ed38845562776992ba9"}, - {file = "faiss_cpu-1.12.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:83e74cbde6fa5caceec5bc103c82053d50fde163e3ceabaa58c91508e984142b"}, - {file = "faiss_cpu-1.12.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6155a5138604b702a32f8f0a63948a539eb7468898554a9911f9ab8c899284fb"}, - {file = "faiss_cpu-1.12.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1bf4b5f0e9b6bb5a566b1a31e84a93b283f26c2b0155fb2eb5970c32a540a906"}, - {file = "faiss_cpu-1.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60a535b79d3d6225c7c21d7277fb0c6fde80c46a9c1e33632b1b293c1d177f30"}, - {file = "faiss_cpu-1.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0d1b243468a24564f85a41166f2ca4c92f8f6755da096ffbdcf551675ca739c5"}, - {file = "faiss_cpu-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:84510079a2efe954e6b89fe5e62f23a98c1ef999756565e056f95f835ff43c5e"}, - {file = "faiss_cpu-1.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:2283f1014f7f86dd56b53bf0ea0d7f848eb4c9c6704b8f4f99a0af02e994e479"}, - {file = "faiss_cpu-1.12.0-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:9b54990fcbcf90e37393909d4033520237194263c93ab6dbfae0616ef9af242b"}, - {file = "faiss_cpu-1.12.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a5f5bca7e1a3e0a98480d1e2748fc86d12c28d506173e460e6746886ff0e08de"}, - {file = "faiss_cpu-1.12.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:016e391f49933875b8d60d47f282f2e93d8ea9f9ffbda82467aa771b11a237db"}, - {file = "faiss_cpu-1.12.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2e4963c7188f57cfba248f09ebd8a14c76b5ffb87382603ccd4576f2da39d74"}, - {file = "faiss_cpu-1.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:88bfe134f8c7cd2dda7df34f2619448906624962c8207efdd6eb1647e2f5338b"}, - {file = "faiss_cpu-1.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9243ee4c224a0d74419040503f22bf067462a040281bf6f3f107ab205c97d438"}, - {file = "faiss_cpu-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:6b8012353d50d9bc81bcfe35b226d0e5bfad345fdebe0da31848395ebc83816d"}, - {file = "faiss_cpu-1.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:8b4f5b18cbe335322a51d2785bb044036609c35bfac5915bff95eadc10e89ef1"}, - {file = "faiss_cpu-1.12.0-cp313-cp313-macosx_13_0_x86_64.whl", hash = "sha256:c9c79b5f28dcf9b2e2557ce51b938b21b7a9d508e008dc1ffea7b8249e7bd443"}, - {file = "faiss_cpu-1.12.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:0db6485bc9f32b69aaccf9ad520782371a79904dcfe20b6da5cbfd61a712e85f"}, - {file = "faiss_cpu-1.12.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f6db5532831791d7bac089fc580e741e99869122946bb6a5f120016c83b95d10"}, - {file = "faiss_cpu-1.12.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d57ed7aac048b18809af70350c31acc0fb9f00e6c03b6ed1651fd58b174882d"}, - {file = "faiss_cpu-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:26c29290e7d1c5938e5886594dc0a2272b30728351ca5f855d4ae30704d5a6cc"}, - {file = "faiss_cpu-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9b43d0c295e93a8e5f1dd30325caaf34d4ecb51f1e3d461c7b0e71bff3a8944b"}, - {file = "faiss_cpu-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:a7c6156f1309bb969480280906e8865c3c4378eebb0f840c55c924bf06efd8d3"}, - {file = "faiss_cpu-1.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:0b5fac98a350774a98b904f7a7c6689eb5cf0a593d63c552e705a80c55636d15"}, - {file = "faiss_cpu-1.12.0-cp314-cp314-macosx_13_0_x86_64.whl", hash = "sha256:ff7db774968210d08cd0331287f3f66a6ffef955a7aa9a7fcd3eb4432a4ce5f5"}, - {file = "faiss_cpu-1.12.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:220b5bb5439c64e417b35f9ade4c7dc3bf7df683d6123901ba84d6d764ecd486"}, - {file = "faiss_cpu-1.12.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:693d0bf16f79e8d16a1baaeda459f3375f37da0354e97dc032806b48a2a54151"}, - {file = "faiss_cpu-1.12.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bcc6587dee21e17430fb49ddc5200625d6f5e1de2bdf436f14827bad4ca78d19"}, - {file = "faiss_cpu-1.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b80e5965f001822cc99ec65c715169af1b70bdae72eccd573520a2dec485b3ee"}, - {file = "faiss_cpu-1.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98279f1b4876ef9902695a329b81a99002782ab6e26def472022009df6f1ac68"}, - {file = "faiss_cpu-1.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:11670337f9f5ee9ff3490e30683eea80add060c300cf6f6cb0e8faf3155fd20e"}, - {file = "faiss_cpu-1.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:7ac1c8b53609b5c722ab60f1749260a7cb3c72fdfb720a0e3033067e73591da5"}, - {file = "faiss_cpu-1.12.0-cp314-cp314t-macosx_13_0_x86_64.whl", hash = "sha256:110b21b7bb4c93c4f1a5eb2ffb8ef99dcdb4725f8ab2e5cd161324e4d981f204"}, - {file = "faiss_cpu-1.12.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:82eb5515ce72be9a43f4cf74447a0d090e014231981df91aff7251204b506fbf"}, - {file = "faiss_cpu-1.12.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:754eef89cdf2b35643df6b0923a5a098bdfecf63b5f4bd86c385042ee511b287"}, - {file = "faiss_cpu-1.12.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7285c71c8f5e9c58b55175f5f74c78c518c52c421a88a430263f34e3e31f719c"}, - {file = "faiss_cpu-1.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:84a50d7a2f711f79cc8b65aa28956dba6435e47b71a38b2daea44c94c9b8e458"}, - {file = "faiss_cpu-1.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7f3e0a14e4edec6a3959a9f51afccb89e863138f184ff2cc24c13f9ad788740b"}, - {file = "faiss_cpu-1.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8b3239cc371df6826ac43c62ac04eec7cc497bedb43f681fcd8ea494f520ddbb"}, - {file = "faiss_cpu-1.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:58b23456db725ee1bd605a6135d2ef55b2ac3e0b6fe873fd99a909e8ef4bd0ff"}, - {file = "faiss_cpu-1.12.0-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:564c1b707fa9e68e4551cd78cbc6dc89810d740cccfc3076c34a0ba6627119ef"}, - {file = "faiss_cpu-1.12.0-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:6a80f9223f1f5eea42a853355520ff0efd38d00923dd9e581195b9ecf1095f0e"}, - {file = "faiss_cpu-1.12.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4b9d38691646da1ba12e3c0be8eb910ac52e2bcb0e553b54590c1c7aded9d5a3"}, - {file = "faiss_cpu-1.12.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:433ddfd09f5ef3cd2593b03a39f37e6957b25a91792b17132d3414c99d5ba5dd"}, - {file = "faiss_cpu-1.12.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fc98084076d0ceffcc3e306fd77ee22f91cc6143953e471c31c84cf2ddf68bb2"}, - {file = "faiss_cpu-1.12.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c5867ee3132cdc9f279951b8514ab51fd121acfbea120c9948b06bd1a1e43053"}, - {file = "faiss_cpu-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:9bcc6e9eb111fc5b06f1623f4073b5acdae25a5baee1eea32b347a2d810deb35"}, - {file = "faiss_cpu-1.12.0.tar.gz", hash = "sha256:2f87cbcd603f3ed464ebceb857971fdebc318de938566c9ae2b82beda8e953c0"}, -] - -[package.dependencies] -numpy = ">=1.25.0,<3.0" -packaging = "*" - -[[package]] -name = "fastjsonschema" -version = "2.21.2" -description = "Fastest Python implementation of JSON schema" -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463"}, - {file = "fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de"}, -] - -[package.extras] -devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] - -[[package]] -name = "filelock" -version = "3.20.0" -description = "A platform independent file lock." -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2"}, - {file = "filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4"}, -] - -[[package]] -name = "fqdn" -version = "1.5.1" -description = "Validates fully-qualified domain names against RFC 1123, so that they are acceptable to modern bowsers" -optional = false -python-versions = ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4, <4" -groups = ["dev"] -files = [ - {file = "fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014"}, - {file = "fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f"}, -] - -[[package]] -name = "frozenlist" -version = "1.8.0" -description = "A list-like structure which implements collections.abc.MutableSequence" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011"}, - {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565"}, - {file = "frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad"}, - {file = "frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2"}, - {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186"}, - {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e"}, - {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450"}, - {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef"}, - {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4"}, - {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff"}, - {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c"}, - {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f"}, - {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7"}, - {file = "frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a"}, - {file = "frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6"}, - {file = "frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e"}, - {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84"}, - {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9"}, - {file = "frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93"}, - {file = "frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f"}, - {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695"}, - {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52"}, - {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581"}, - {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567"}, - {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b"}, - {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92"}, - {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d"}, - {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd"}, - {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967"}, - {file = "frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25"}, - {file = "frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b"}, - {file = "frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a"}, - {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1"}, - {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b"}, - {file = "frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4"}, - {file = "frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383"}, - {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4"}, - {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8"}, - {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b"}, - {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52"}, - {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29"}, - {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3"}, - {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143"}, - {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608"}, - {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa"}, - {file = "frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf"}, - {file = "frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746"}, - {file = "frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd"}, - {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a"}, - {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7"}, - {file = "frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40"}, - {file = "frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027"}, - {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822"}, - {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121"}, - {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5"}, - {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e"}, - {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11"}, - {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1"}, - {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1"}, - {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8"}, - {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed"}, - {file = "frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496"}, - {file = "frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231"}, - {file = "frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62"}, - {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94"}, - {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c"}, - {file = "frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52"}, - {file = "frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51"}, - {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65"}, - {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82"}, - {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714"}, - {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d"}, - {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506"}, - {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51"}, - {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e"}, - {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0"}, - {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41"}, - {file = "frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b"}, - {file = "frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888"}, - {file = "frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042"}, - {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0"}, - {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f"}, - {file = "frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c"}, - {file = "frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2"}, - {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8"}, - {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686"}, - {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e"}, - {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a"}, - {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128"}, - {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f"}, - {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7"}, - {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30"}, - {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7"}, - {file = "frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806"}, - {file = "frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0"}, - {file = "frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b"}, - {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d"}, - {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed"}, - {file = "frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930"}, - {file = "frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c"}, - {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24"}, - {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37"}, - {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a"}, - {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2"}, - {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef"}, - {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe"}, - {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8"}, - {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a"}, - {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e"}, - {file = "frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df"}, - {file = "frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd"}, - {file = "frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79"}, - {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8b7138e5cd0647e4523d6685b0eac5d4be9a184ae9634492f25c6eb38c12a47"}, - {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6483e309ca809f1efd154b4d37dc6d9f61037d6c6a81c2dc7a15cb22c8c5dca"}, - {file = "frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b9290cf81e95e93fdf90548ce9d3c1211cf574b8e3f4b3b7cb0537cf2227068"}, - {file = "frozenlist-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59a6a5876ca59d1b63af8cd5e7ffffb024c3dc1e9cf9301b21a2e76286505c95"}, - {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc4126390929823e2d2d9dc79ab4046ed74680360fc5f38b585c12c66cdf459"}, - {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:332db6b2563333c5671fecacd085141b5800cb866be16d5e3eb15a2086476675"}, - {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ff15928d62a0b80bb875655c39bf517938c7d589554cbd2669be42d97c2cb61"}, - {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bf6cdf8e07c8151fba6fe85735441240ec7f619f935a5205953d58009aef8c6"}, - {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:48e6d3f4ec5c7273dfe83ff27c91083c6c9065af655dc2684d2c200c94308bb5"}, - {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1a7607e17ad33361677adcd1443edf6f5da0ce5e5377b798fba20fae194825f3"}, - {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3a935c3a4e89c733303a2d5a7c257ea44af3a56c8202df486b7f5de40f37e1"}, - {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:940d4a017dbfed9daf46a3b086e1d2167e7012ee297fef9e1c545c4d022f5178"}, - {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b9be22a69a014bc47e78072d0ecae716f5eb56c15238acca0f43d6eb8e4a5bda"}, - {file = "frozenlist-1.8.0-cp39-cp39-win32.whl", hash = "sha256:1aa77cb5697069af47472e39612976ed05343ff2e84a3dcf15437b232cbfd087"}, - {file = "frozenlist-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:7398c222d1d405e796970320036b1b563892b65809d9e5261487bb2c7f7b5c6a"}, - {file = "frozenlist-1.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f3b365f31c6cd4af24545ca0a244a53688cad8834e32f56831c4923b50a103"}, - {file = "frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d"}, - {file = "frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad"}, -] - -[[package]] -name = "fsspec" -version = "2025.10.0" -description = "File-system specification" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d"}, - {file = "fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59"}, -] - -[package.extras] -abfs = ["adlfs"] -adl = ["adlfs"] -arrow = ["pyarrow (>=1)"] -dask = ["dask", "distributed"] -dev = ["pre-commit", "ruff (>=0.5)"] -doc = ["numpydoc", "sphinx", "sphinx-design", "sphinx-rtd-theme", "yarl"] -dropbox = ["dropbox", "dropboxdrivefs", "requests"] -full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"] -fuse = ["fusepy"] -gcs = ["gcsfs"] -git = ["pygit2"] -github = ["requests"] -gs = ["gcsfs"] -gui = ["panel"] -hdfs = ["pyarrow (>=1)"] -http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"] -libarchive = ["libarchive-c"] -oci = ["ocifs"] -s3 = ["s3fs"] -sftp = ["paramiko"] -smb = ["smbprotocol"] -ssh = ["paramiko"] -test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"] -test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"] -test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard ; python_version < \"3.14\""] -tqdm = ["tqdm"] - -[[package]] -name = "greenlet" -version = "3.2.4" -description = "Lightweight in-process concurrent programming" -optional = false -python-versions = ">=3.9" -groups = ["main"] -markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\"" -files = [ - {file = "greenlet-3.2.4-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c"}, - {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590"}, - {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c"}, - {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b"}, - {file = "greenlet-3.2.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31"}, - {file = "greenlet-3.2.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d"}, - {file = "greenlet-3.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5"}, - {file = "greenlet-3.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f"}, - {file = "greenlet-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c"}, - {file = "greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2"}, - {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246"}, - {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3"}, - {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633"}, - {file = "greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079"}, - {file = "greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8"}, - {file = "greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52"}, - {file = "greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa"}, - {file = "greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9"}, - {file = "greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd"}, - {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb"}, - {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968"}, - {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9"}, - {file = "greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6"}, - {file = "greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0"}, - {file = "greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0"}, - {file = "greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f"}, - {file = "greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02"}, - {file = "greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31"}, - {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945"}, - {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc"}, - {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a"}, - {file = "greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504"}, - {file = "greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671"}, - {file = "greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b"}, - {file = "greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae"}, - {file = "greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b"}, - {file = "greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0"}, - {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f"}, - {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5"}, - {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1"}, - {file = "greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735"}, - {file = "greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337"}, - {file = "greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01"}, - {file = "greenlet-3.2.4-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:b6a7c19cf0d2742d0809a4c05975db036fdff50cd294a93632d6a310bf9ac02c"}, - {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:27890167f55d2387576d1f41d9487ef171849ea0359ce1510ca6e06c8bece11d"}, - {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:18d9260df2b5fbf41ae5139e1be4e796d99655f023a636cd0e11e6406cca7d58"}, - {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:671df96c1f23c4a0d4077a325483c1503c96a1b7d9db26592ae770daa41233d4"}, - {file = "greenlet-3.2.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:16458c245a38991aa19676900d48bd1a6f2ce3e16595051a4db9d012154e8433"}, - {file = "greenlet-3.2.4-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9913f1a30e4526f432991f89ae263459b1c64d1608c0d22a5c79c287b3c70df"}, - {file = "greenlet-3.2.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b90654e092f928f110e0007f572007c9727b5265f7632c2fa7415b4689351594"}, - {file = "greenlet-3.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81701fd84f26330f0d5f4944d4e92e61afe6319dcd9775e39396e39d7c3e5f98"}, - {file = "greenlet-3.2.4-cp39-cp39-win32.whl", hash = "sha256:65458b409c1ed459ea899e939f0e1cdb14f58dbc803f2f93c5eab5694d32671b"}, - {file = "greenlet-3.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:d2e685ade4dafd447ede19c31277a224a239a0a1a4eca4e6390efedf20260cfb"}, - {file = "greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d"}, -] - -[package.extras] -docs = ["Sphinx", "furo"] -test = ["objgraph", "psutil", "setuptools"] - -[[package]] -name = "h11" -version = "0.16.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, - {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, -] - -[[package]] -name = "hf-xet" -version = "1.2.0" -description = "Fast transfer of large files with the Hugging Face Hub." -optional = false -python-versions = ">=3.8" -groups = ["main"] -markers = "platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"arm64\" or platform_machine == \"aarch64\"" -files = [ - {file = "hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649"}, - {file = "hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813"}, - {file = "hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc"}, - {file = "hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5"}, - {file = "hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f"}, - {file = "hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832"}, - {file = "hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382"}, - {file = "hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e"}, - {file = "hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8"}, - {file = "hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0"}, - {file = "hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090"}, - {file = "hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a"}, - {file = "hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f"}, - {file = "hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc"}, - {file = "hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848"}, - {file = "hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4"}, - {file = "hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd"}, - {file = "hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c"}, - {file = "hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737"}, - {file = "hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865"}, - {file = "hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69"}, - {file = "hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f"}, -] - -[package.extras] -tests = ["pytest"] - -[[package]] -name = "httpcore" -version = "1.0.9" -description = "A minimal low-level HTTP client." -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, - {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, -] - -[package.dependencies] -certifi = "*" -h11 = ">=0.16" - -[package.extras] -asyncio = ["anyio (>=4.0,<5.0)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<1.0)"] - -[[package]] -name = "httpx" -version = "0.28.1" -description = "The next generation HTTP client." -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, - {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, -] - -[package.dependencies] -anyio = "*" -certifi = "*" -httpcore = "==1.*" -idna = "*" - -[package.extras] -brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "httpx-sse" -version = "0.4.3" -description = "Consume Server-Sent Event (SSE) messages with HTTPX." -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc"}, - {file = "httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d"}, -] - -[[package]] -name = "huggingface-hub" -version = "0.36.0" -description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" -optional = false -python-versions = ">=3.8.0" -groups = ["main"] -files = [ - {file = "huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d"}, - {file = "huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25"}, -] - -[package.dependencies] -filelock = "*" -fsspec = ">=2023.5.0" -hf-xet = {version = ">=1.1.3,<2.0.0", markers = "platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"arm64\" or platform_machine == \"aarch64\""} -packaging = ">=20.9" -pyyaml = ">=5.1" -requests = "*" -tqdm = ">=4.42.1" -typing-extensions = ">=3.7.4.3" - -[package.extras] -all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "libcst (>=1.4.0)", "mypy (==1.15.0) ; python_version >= \"3.9\"", "mypy (>=1.14.1,<1.15.0) ; python_version == \"3.8\"", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures (<16.0)", "pytest-vcr", "pytest-xdist", "ruff (>=0.9.0)", "soundfile", "ty", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] -cli = ["InquirerPy (==0.3.4)"] -dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "libcst (>=1.4.0)", "mypy (==1.15.0) ; python_version >= \"3.9\"", "mypy (>=1.14.1,<1.15.0) ; python_version == \"3.8\"", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures (<16.0)", "pytest-vcr", "pytest-xdist", "ruff (>=0.9.0)", "soundfile", "ty", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] -fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] -hf-transfer = ["hf-transfer (>=0.1.4)"] -hf-xet = ["hf-xet (>=1.1.2,<2.0.0)"] -inference = ["aiohttp"] -mcp = ["aiohttp", "mcp (>=1.8.0)", "typer"] -oauth = ["authlib (>=1.3.2)", "fastapi", "httpx", "itsdangerous"] -quality = ["libcst (>=1.4.0)", "mypy (==1.15.0) ; python_version >= \"3.9\"", "mypy (>=1.14.1,<1.15.0) ; python_version == \"3.8\"", "ruff (>=0.9.0)", "ty"] -tensorflow = ["graphviz", "pydot", "tensorflow"] -tensorflow-testing = ["keras (<3.0)", "tensorflow"] -testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures (<16.0)", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] -torch = ["safetensors[torch]", "torch"] -typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] - -[[package]] -name = "idna" -version = "3.11" -description = "Internationalized Domain Names in Applications (IDNA)" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, - {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, -] - -[package.extras] -all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] - -[[package]] -name = "iniconfig" -version = "2.3.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.10" -groups = ["main", "test"] -files = [ - {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, - {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, -] - -[[package]] -name = "ipykernel" -version = "7.1.0" -description = "IPython Kernel for Jupyter" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c"}, - {file = "ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db"}, -] - -[package.dependencies] -appnope = {version = ">=0.1.2", markers = "platform_system == \"Darwin\""} -comm = ">=0.1.1" -debugpy = ">=1.6.5" -ipython = ">=7.23.1" -jupyter-client = ">=8.0.0" -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -matplotlib-inline = ">=0.1" -nest-asyncio = ">=1.4" -packaging = ">=22" -psutil = ">=5.7" -pyzmq = ">=25" -tornado = ">=6.2" -traitlets = ">=5.4.0" - -[package.extras] -cov = ["coverage[toml]", "matplotlib", "pytest-cov", "trio"] -docs = ["intersphinx-registry", "myst-parser", "pydata-sphinx-theme", "sphinx (<8.2.0)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] -pyqt5 = ["pyqt5"] -pyside6 = ["pyside6"] -test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0,<9)", "pytest-asyncio (>=0.23.5)", "pytest-cov", "pytest-timeout"] - -[[package]] -name = "ipython" -version = "9.6.0" -description = "IPython: Productive Interactive Computing" -optional = false -python-versions = ">=3.11" -groups = ["dev"] -files = [ - {file = "ipython-9.6.0-py3-none-any.whl", hash = "sha256:5f77efafc886d2f023442479b8149e7d86547ad0a979e9da9f045d252f648196"}, - {file = "ipython-9.6.0.tar.gz", hash = "sha256:5603d6d5d356378be5043e69441a072b50a5b33b4503428c77b04cb8ce7bc731"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -decorator = "*" -ipython-pygments-lexers = "*" -jedi = ">=0.16" -matplotlib-inline = "*" -pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} -prompt_toolkit = ">=3.0.41,<3.1.0" -pygments = ">=2.4.0" -stack_data = "*" -traitlets = ">=5.13.0" - -[package.extras] -all = ["ipython[doc,matplotlib,test,test-extra]"] -black = ["black"] -doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[matplotlib,test]", "setuptools (>=61.2)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinx_toml (==0.0.4)", "typing_extensions"] -matplotlib = ["matplotlib (>3.7)"] -test = ["packaging", "pytest", "pytest-asyncio", "testpath"] -test-extra = ["curio", "ipykernel", "ipython[matplotlib]", "ipython[test]", "jupyter_ai", "nbclient", "nbformat", "numpy (>=1.25)", "pandas (>2.0)", "trio"] - -[[package]] -name = "ipython-pygments-lexers" -version = "1.1.1" -description = "Defines a variety of Pygments lexers for highlighting IPython code." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c"}, - {file = "ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81"}, -] - -[package.dependencies] -pygments = "*" - -[[package]] -name = "ipywidgets" -version = "8.1.7" -description = "Jupyter interactive widgets" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "ipywidgets-8.1.7-py3-none-any.whl", hash = "sha256:764f2602d25471c213919b8a1997df04bef869251db4ca8efba1b76b1bd9f7bb"}, - {file = "ipywidgets-8.1.7.tar.gz", hash = "sha256:15f1ac050b9ccbefd45dccfbb2ef6bed0029d8278682d569d71b8dd96bee0376"}, -] - -[package.dependencies] -comm = ">=0.1.3" -ipython = ">=6.1.0" -jupyterlab_widgets = ">=3.0.15,<3.1.0" -traitlets = ">=4.3.1" -widgetsnbextension = ">=4.0.14,<4.1.0" - -[package.extras] -test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] - -[[package]] -name = "isoduration" -version = "20.11.0" -description = "Operations with ISO 8601 durations" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042"}, - {file = "isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9"}, -] - -[package.dependencies] -arrow = ">=0.15.0" - -[[package]] -name = "isort" -version = "5.13.2" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -groups = ["dev"] -files = [ - {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, - {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, -] - -[package.extras] -colors = ["colorama (>=0.4.6)"] - -[[package]] -name = "jedi" -version = "0.19.2" -description = "An autocompletion tool for Python that can be used for text editors." -optional = false -python-versions = ">=3.6" -groups = ["dev"] -files = [ - {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, - {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, -] - -[package.dependencies] -parso = ">=0.8.4,<0.9.0" - -[package.extras] -docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] -qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"] - -[[package]] -name = "jinja2" -version = "3.1.6" -description = "A very fast and expressive template engine." -optional = false -python-versions = ">=3.7" -groups = ["main", "dev"] -files = [ - {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, - {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, -] - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "jiter" -version = "0.11.1" -description = "Fast iterable JSON parser." -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "jiter-0.11.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ed58841a491bbbf3f7c55a6b68fff568439ab73b2cce27ace0e169057b5851df"}, - {file = "jiter-0.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:499beb9b2d7e51d61095a8de39ebcab1d1778f2a74085f8305a969f6cee9f3e4"}, - {file = "jiter-0.11.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b87b2821795e28cc990939b68ce7a038edea680a24910bd68a79d54ff3f03c02"}, - {file = "jiter-0.11.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:83f6fa494d8bba14ab100417c80e70d32d737e805cb85be2052d771c76fcd1f8"}, - {file = "jiter-0.11.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fbc6aea1daa2ec6f5ed465f0c5e7b0607175062ceebbea5ca70dd5ddab58083"}, - {file = "jiter-0.11.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:302288e2edc43174bb2db838e94688d724f9aad26c5fb9a74f7a5fb427452a6a"}, - {file = "jiter-0.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85db563fe3b367bb568af5d29dea4d4066d923b8e01f3417d25ebecd958de815"}, - {file = "jiter-0.11.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f1c1ba2b6b22f775444ef53bc2d5778396d3520abc7b2e1da8eb0c27cb3ffb10"}, - {file = "jiter-0.11.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:523be464b14f8fd0cc78da6964b87b5515a056427a2579f9085ce30197a1b54a"}, - {file = "jiter-0.11.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:25b99b3f04cd2a38fefb22e822e35eb203a2cd37d680dbbc0c0ba966918af336"}, - {file = "jiter-0.11.1-cp310-cp310-win32.whl", hash = "sha256:47a79e90545a596bb9104109777894033347b11180d4751a216afef14072dbe7"}, - {file = "jiter-0.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:cace75621ae9bd66878bf69fbd4dfc1a28ef8661e0c2d0eb72d3d6f1268eddf5"}, - {file = "jiter-0.11.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9b0088ff3c374ce8ce0168523ec8e97122ebb788f950cf7bb8e39c7dc6a876a2"}, - {file = "jiter-0.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74433962dd3c3090655e02e461267095d6c84f0741c7827de11022ef8d7ff661"}, - {file = "jiter-0.11.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d98030e345e6546df2cc2c08309c502466c66c4747b043f1a0d415fada862b8"}, - {file = "jiter-0.11.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d6db0b2e788db46bec2cf729a88b6dd36959af2abd9fa2312dfba5acdd96dcb"}, - {file = "jiter-0.11.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55678fbbda261eafe7289165dd2ddd0e922df5f9a1ae46d7c79a5a15242bd7d1"}, - {file = "jiter-0.11.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a6b74fae8e40497653b52ce6ca0f1b13457af769af6fb9c1113efc8b5b4d9be"}, - {file = "jiter-0.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a55a453f8b035eb4f7852a79a065d616b7971a17f5e37a9296b4b38d3b619e4"}, - {file = "jiter-0.11.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2638148099022e6bdb3f42904289cd2e403609356fb06eb36ddec2d50958bc29"}, - {file = "jiter-0.11.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:252490567a5d990986f83b95a5f1ca1bf205ebd27b3e9e93bb7c2592380e29b9"}, - {file = "jiter-0.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d431d52b0ca2436eea6195f0f48528202100c7deda354cb7aac0a302167594d5"}, - {file = "jiter-0.11.1-cp311-cp311-win32.whl", hash = "sha256:db6f41e40f8bae20c86cb574b48c4fd9f28ee1c71cb044e9ec12e78ab757ba3a"}, - {file = "jiter-0.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0cc407b8e6cdff01b06bb80f61225c8b090c3df108ebade5e0c3c10993735b19"}, - {file = "jiter-0.11.1-cp311-cp311-win_arm64.whl", hash = "sha256:fe04ea475392a91896d1936367854d346724a1045a247e5d1c196410473b8869"}, - {file = "jiter-0.11.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c92148eec91052538ce6823dfca9525f5cfc8b622d7f07e9891a280f61b8c96c"}, - {file = "jiter-0.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ecd4da91b5415f183a6be8f7158d127bdd9e6a3174138293c0d48d6ea2f2009d"}, - {file = "jiter-0.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7e3ac25c00b9275684d47aa42febaa90a9958e19fd1726c4ecf755fbe5e553b"}, - {file = "jiter-0.11.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:57d7305c0a841858f866cd459cd9303f73883fb5e097257f3d4a3920722c69d4"}, - {file = "jiter-0.11.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e86fa10e117dce22c547f31dd6d2a9a222707d54853d8de4e9a2279d2c97f239"}, - {file = "jiter-0.11.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ae5ef1d48aec7e01ee8420155d901bb1d192998fa811a65ebb82c043ee186711"}, - {file = "jiter-0.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb68e7bf65c990531ad8715e57d50195daf7c8e6f1509e617b4e692af1108939"}, - {file = "jiter-0.11.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43b30c8154ded5845fa454ef954ee67bfccce629b2dea7d01f795b42bc2bda54"}, - {file = "jiter-0.11.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:586cafbd9dd1f3ce6a22b4a085eaa6be578e47ba9b18e198d4333e598a91db2d"}, - {file = "jiter-0.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:677cc2517d437a83bb30019fd4cf7cad74b465914c56ecac3440d597ac135250"}, - {file = "jiter-0.11.1-cp312-cp312-win32.whl", hash = "sha256:fa992af648fcee2b850a3286a35f62bbbaeddbb6dbda19a00d8fbc846a947b6e"}, - {file = "jiter-0.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:88b5cae9fa51efeb3d4bd4e52bfd4c85ccc9cac44282e2a9640893a042ba4d87"}, - {file = "jiter-0.11.1-cp312-cp312-win_arm64.whl", hash = "sha256:9a6cae1ab335551917f882f2c3c1efe7617b71b4c02381e4382a8fc80a02588c"}, - {file = "jiter-0.11.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:71b6a920a5550f057d49d0e8bcc60945a8da998019e83f01adf110e226267663"}, - {file = "jiter-0.11.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b3de72e925388453a5171be83379549300db01284f04d2a6f244d1d8de36f94"}, - {file = "jiter-0.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc19dd65a2bd3d9c044c5b4ebf657ca1e6003a97c0fc10f555aa4f7fb9821c00"}, - {file = "jiter-0.11.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d58faaa936743cd1464540562f60b7ce4fd927e695e8bc31b3da5b914baa9abd"}, - {file = "jiter-0.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:902640c3103625317291cb73773413b4d71847cdf9383ba65528745ff89f1d14"}, - {file = "jiter-0.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:30405f726e4c2ed487b176c09f8b877a957f535d60c1bf194abb8dadedb5836f"}, - {file = "jiter-0.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3217f61728b0baadd2551844870f65219ac4a1285d5e1a4abddff3d51fdabe96"}, - {file = "jiter-0.11.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b1364cc90c03a8196f35f396f84029f12abe925415049204446db86598c8b72c"}, - {file = "jiter-0.11.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:53a54bf8e873820ab186b2dca9f6c3303f00d65ae5e7b7d6bda1b95aa472d646"}, - {file = "jiter-0.11.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7e29aca023627b0e0c2392d4248f6414d566ff3974fa08ff2ac8dbb96dfee92a"}, - {file = "jiter-0.11.1-cp313-cp313-win32.whl", hash = "sha256:f153e31d8bca11363751e875c0a70b3d25160ecbaee7b51e457f14498fb39d8b"}, - {file = "jiter-0.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:f773f84080b667c69c4ea0403fc67bb08b07e2b7ce1ef335dea5868451e60fed"}, - {file = "jiter-0.11.1-cp313-cp313-win_arm64.whl", hash = "sha256:635ecd45c04e4c340d2187bcb1cea204c7cc9d32c1364d251564bf42e0e39c2d"}, - {file = "jiter-0.11.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d892b184da4d94d94ddb4031296931c74ec8b325513a541ebfd6dfb9ae89904b"}, - {file = "jiter-0.11.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa22c223a3041dacb2fcd37c70dfd648b44662b4a48e242592f95bda5ab09d58"}, - {file = "jiter-0.11.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:330e8e6a11ad4980cd66a0f4a3e0e2e0f646c911ce047014f984841924729789"}, - {file = "jiter-0.11.1-cp313-cp313t-win_amd64.whl", hash = "sha256:09e2e386ebf298547ca3a3704b729471f7ec666c2906c5c26c1a915ea24741ec"}, - {file = "jiter-0.11.1-cp313-cp313t-win_arm64.whl", hash = "sha256:fe4a431c291157e11cee7c34627990ea75e8d153894365a3bc84b7a959d23ca8"}, - {file = "jiter-0.11.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:0fa1f70da7a8a9713ff8e5f75ec3f90c0c870be6d526aa95e7c906f6a1c8c676"}, - {file = "jiter-0.11.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:569ee559e5046a42feb6828c55307cf20fe43308e3ae0d8e9e4f8d8634d99944"}, - {file = "jiter-0.11.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f69955fa1d92e81987f092b233f0be49d4c937da107b7f7dcf56306f1d3fcce9"}, - {file = "jiter-0.11.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:090f4c9d4a825e0fcbd0a2647c9a88a0f366b75654d982d95a9590745ff0c48d"}, - {file = "jiter-0.11.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbf3d8cedf9e9d825233e0dcac28ff15c47b7c5512fdfe2e25fd5bbb6e6b0cee"}, - {file = "jiter-0.11.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2aa9b1958f9c30d3d1a558b75f0626733c60eb9b7774a86b34d88060be1e67fe"}, - {file = "jiter-0.11.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e42d1ca16590b768c5e7d723055acd2633908baacb3628dd430842e2e035aa90"}, - {file = "jiter-0.11.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5db4c2486a023820b701a17aec9c5a6173c5ba4393f26662f032f2de9c848b0f"}, - {file = "jiter-0.11.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:4573b78777ccfac954859a6eff45cbd9d281d80c8af049d0f1a3d9fc323d5c3a"}, - {file = "jiter-0.11.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:7593ac6f40831d7961cb67633c39b9fef6689a211d7919e958f45710504f52d3"}, - {file = "jiter-0.11.1-cp314-cp314-win32.whl", hash = "sha256:87202ec6ff9626ff5f9351507def98fcf0df60e9a146308e8ab221432228f4ea"}, - {file = "jiter-0.11.1-cp314-cp314-win_amd64.whl", hash = "sha256:a5dd268f6531a182c89d0dd9a3f8848e86e92dfff4201b77a18e6b98aa59798c"}, - {file = "jiter-0.11.1-cp314-cp314-win_arm64.whl", hash = "sha256:5d761f863f912a44748a21b5c4979c04252588ded8d1d2760976d2e42cd8d991"}, - {file = "jiter-0.11.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2cc5a3965285ddc33e0cab933e96b640bc9ba5940cea27ebbbf6695e72d6511c"}, - {file = "jiter-0.11.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b572b3636a784c2768b2342f36a23078c8d3aa6d8a30745398b1bab58a6f1a8"}, - {file = "jiter-0.11.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ad93e3d67a981f96596d65d2298fe8d1aa649deb5374a2fb6a434410ee11915e"}, - {file = "jiter-0.11.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a83097ce379e202dcc3fe3fc71a16d523d1ee9192c8e4e854158f96b3efe3f2f"}, - {file = "jiter-0.11.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7042c51e7fbeca65631eb0c332f90c0c082eab04334e7ccc28a8588e8e2804d9"}, - {file = "jiter-0.11.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a68d679c0e47649a61df591660507608adc2652442de7ec8276538ac46abe08"}, - {file = "jiter-0.11.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1b0da75dbf4b6ec0b3c9e604d1ee8beaf15bc046fff7180f7d89e3cdbd3bb51"}, - {file = "jiter-0.11.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:69dd514bf0fa31c62147d6002e5ca2b3e7ef5894f5ac6f0a19752385f4e89437"}, - {file = "jiter-0.11.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:bb31ac0b339efa24c0ca606febd8b77ef11c58d09af1b5f2be4c99e907b11111"}, - {file = "jiter-0.11.1-cp314-cp314t-win32.whl", hash = "sha256:b2ce0d6156a1d3ad41da3eec63b17e03e296b78b0e0da660876fccfada86d2f7"}, - {file = "jiter-0.11.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f4db07d127b54c4a2d43b4cf05ff0193e4f73e0dd90c74037e16df0b29f666e1"}, - {file = "jiter-0.11.1-cp314-cp314t-win_arm64.whl", hash = "sha256:28e4fdf2d7ebfc935523e50d1efa3970043cfaa161674fe66f9642409d001dfe"}, - {file = "jiter-0.11.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:baa99c8db49467527658bb479857344daf0a14dff909b7f6714579ac439d1253"}, - {file = "jiter-0.11.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:860fe55fa3b01ad0edf2adde1098247ff5c303d0121f9ce028c03d4f88c69502"}, - {file = "jiter-0.11.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:173dd349d99b6feaf5a25a6fbcaf3489a6f947708d808240587a23df711c67db"}, - {file = "jiter-0.11.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:14ac1dca837514cc946a6ac2c4995d9695303ecc754af70a3163d057d1a444ab"}, - {file = "jiter-0.11.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69af47de5f93a231d5b85f7372d3284a5be8edb4cc758f006ec5a1406965ac5e"}, - {file = "jiter-0.11.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:685f8b3abd3bbd3e06e4dfe2429ff87fd5d7a782701151af99b1fcbd80e31b2b"}, - {file = "jiter-0.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d04afa2d4e5526e54ae8a58feea953b1844bf6e3526bc589f9de68e86d0ea01"}, - {file = "jiter-0.11.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e92b927259035b50d8e11a8fdfe0ebd014d883e4552d37881643fa289a4bcf1"}, - {file = "jiter-0.11.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e7bd8be4fad8d4c5558b7801770cd2da6c072919c6f247cc5336edb143f25304"}, - {file = "jiter-0.11.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:121381a77a3c85987f3eba0d30ceaca9116f7463bedeec2fa79b2e7286b89b60"}, - {file = "jiter-0.11.1-cp39-cp39-win32.whl", hash = "sha256:160225407f6dfabdf9be1b44e22f06bc293a78a28ffa4347054698bd712dad06"}, - {file = "jiter-0.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:028e0d59bcdfa1079f8df886cdaefc6f515c27a5288dec956999260c7e4a7cfd"}, - {file = "jiter-0.11.1-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:e642b5270e61dd02265866398707f90e365b5db2eb65a4f30c789d826682e1f6"}, - {file = "jiter-0.11.1-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:464ba6d000585e4e2fd1e891f31f1231f497273414f5019e27c00a4b8f7a24ad"}, - {file = "jiter-0.11.1-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:055568693ab35e0bf3a171b03bb40b2dcb10352359e0ab9b5ed0da2bf1eb6f6f"}, - {file = "jiter-0.11.1-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0c69ea798d08a915ba4478113efa9e694971e410056392f4526d796f136d3fa"}, - {file = "jiter-0.11.1-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:0d4d6993edc83cf75e8c6828a8d6ce40a09ee87e38c7bfba6924f39e1337e21d"}, - {file = "jiter-0.11.1-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f78d151c83a87a6cf5461d5ee55bc730dd9ae227377ac6f115b922989b95f838"}, - {file = "jiter-0.11.1-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9022974781155cd5521d5cb10997a03ee5e31e8454c9d999dcdccd253f2353f"}, - {file = "jiter-0.11.1-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18c77aaa9117510d5bdc6a946baf21b1f0cfa58ef04d31c8d016f206f2118960"}, - {file = "jiter-0.11.1.tar.gz", hash = "sha256:849dcfc76481c0ea0099391235b7ca97d7279e0fa4c86005457ac7c88e8b76dc"}, -] - -[[package]] -name = "jmespath" -version = "1.0.1" -description = "JSON Matching Expressions" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, - {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, -] - -[[package]] -name = "joblib" -version = "1.5.2" -description = "Lightweight pipelining with Python functions" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241"}, - {file = "joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55"}, -] - -[[package]] -name = "json5" -version = "0.12.1" -description = "A Python implementation of the JSON5 data format." -optional = false -python-versions = ">=3.8.0" -groups = ["dev"] -files = [ - {file = "json5-0.12.1-py3-none-any.whl", hash = "sha256:d9c9b3bc34a5f54d43c35e11ef7cb87d8bdd098c6ace87117a7b7e83e705c1d5"}, - {file = "json5-0.12.1.tar.gz", hash = "sha256:b2743e77b3242f8d03c143dd975a6ec7c52e2f2afe76ed934e53503dd4ad4990"}, -] - -[package.extras] -dev = ["build (==1.2.2.post1)", "coverage (==7.5.4) ; python_version < \"3.9\"", "coverage (==7.8.0) ; python_version >= \"3.9\"", "mypy (==1.14.1) ; python_version < \"3.9\"", "mypy (==1.15.0) ; python_version >= \"3.9\"", "pip (==25.0.1)", "pylint (==3.2.7) ; python_version < \"3.9\"", "pylint (==3.3.6) ; python_version >= \"3.9\"", "ruff (==0.11.2)", "twine (==6.1.0)", "uv (==0.6.11)"] - -[[package]] -name = "jsonpatch" -version = "1.33" -description = "Apply JSON-Patches (RFC 6902)" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" -groups = ["main"] -files = [ - {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"}, - {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"}, -] - -[package.dependencies] -jsonpointer = ">=1.9" - -[[package]] -name = "jsonpointer" -version = "3.0.0" -description = "Identify specific nodes in a JSON document (RFC 6901)" -optional = false -python-versions = ">=3.7" -groups = ["main", "dev"] -files = [ - {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"}, - {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"}, -] - -[[package]] -name = "jsonschema" -version = "4.25.1" -description = "An implementation of JSON Schema validation for Python" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63"}, - {file = "jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85"}, -] - -[package.dependencies] -attrs = ">=22.2.0" -fqdn = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} -idna = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} -isoduration = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} -jsonpointer = {version = ">1.13", optional = true, markers = "extra == \"format-nongpl\""} -jsonschema-specifications = ">=2023.03.6" -referencing = ">=0.28.4" -rfc3339-validator = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} -rfc3986-validator = {version = ">0.1.0", optional = true, markers = "extra == \"format-nongpl\""} -rfc3987-syntax = {version = ">=1.1.0", optional = true, markers = "extra == \"format-nongpl\""} -rpds-py = ">=0.7.1" -uri-template = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} -webcolors = {version = ">=24.6.0", optional = true, markers = "extra == \"format-nongpl\""} - -[package.extras] -format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "rfc3987-syntax (>=1.1.0)", "uri-template", "webcolors (>=24.6.0)"] - -[[package]] -name = "jsonschema-specifications" -version = "2025.9.1" -description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe"}, - {file = "jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d"}, -] - -[package.dependencies] -referencing = ">=0.31.0" - -[[package]] -name = "jupyter" -version = "1.1.1" -description = "Jupyter metapackage. Install all the Jupyter components in one go." -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83"}, - {file = "jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a"}, -] - -[package.dependencies] -ipykernel = "*" -ipywidgets = "*" -jupyter-console = "*" -jupyterlab = "*" -nbconvert = "*" -notebook = "*" - -[[package]] -name = "jupyter-client" -version = "8.6.3" -description = "Jupyter protocol implementation and client libraries" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f"}, - {file = "jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419"}, -] - -[package.dependencies] -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -python-dateutil = ">=2.8.2" -pyzmq = ">=23.0" -tornado = ">=6.2" -traitlets = ">=5.3" - -[package.extras] -docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko ; sys_platform == \"win32\"", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] - -[[package]] -name = "jupyter-console" -version = "6.6.3" -description = "Jupyter terminal console" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485"}, - {file = "jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539"}, -] - -[package.dependencies] -ipykernel = ">=6.14" -ipython = "*" -jupyter-client = ">=7.0.0" -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -prompt-toolkit = ">=3.0.30" -pygments = "*" -pyzmq = ">=17" -traitlets = ">=5.4" - -[package.extras] -test = ["flaky", "pexpect", "pytest"] - -[[package]] -name = "jupyter-core" -version = "5.9.1" -description = "Jupyter core package. A base package on which Jupyter projects rely." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407"}, - {file = "jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508"}, -] - -[package.dependencies] -platformdirs = ">=2.5" -traitlets = ">=5.3" - -[package.extras] -docs = ["intersphinx-registry", "myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-spelling", "traitlets"] -test = ["ipykernel", "pre-commit", "pytest (<9)", "pytest-cov", "pytest-timeout"] - -[[package]] -name = "jupyter-events" -version = "0.12.0" -description = "Jupyter Event System library" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb"}, - {file = "jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b"}, -] - -[package.dependencies] -jsonschema = {version = ">=4.18.0", extras = ["format-nongpl"]} -packaging = "*" -python-json-logger = ">=2.0.4" -pyyaml = ">=5.3" -referencing = "*" -rfc3339-validator = "*" -rfc3986-validator = ">=0.1.1" -traitlets = ">=5.3" - -[package.extras] -cli = ["click", "rich"] -docs = ["jupyterlite-sphinx", "myst-parser", "pydata-sphinx-theme (>=0.16)", "sphinx (>=8)", "sphinxcontrib-spelling"] -test = ["click", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.19.0)", "pytest-console-scripts", "rich"] - -[[package]] -name = "jupyter-lsp" -version = "2.3.0" -description = "Multi-Language Server WebSocket proxy for Jupyter Notebook/Lab server" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f"}, - {file = "jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245"}, -] - -[package.dependencies] -jupyter_server = ">=1.1.2" - -[[package]] -name = "jupyter-server" -version = "2.17.0" -description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f"}, - {file = "jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5"}, -] - -[package.dependencies] -anyio = ">=3.1.0" -argon2-cffi = ">=21.1" -jinja2 = ">=3.0.3" -jupyter-client = ">=7.4.4" -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -jupyter-events = ">=0.11.0" -jupyter-server-terminals = ">=0.4.4" -nbconvert = ">=6.4.4" -nbformat = ">=5.3.0" -packaging = ">=22.0" -prometheus-client = ">=0.9" -pywinpty = {version = ">=2.0.1", markers = "os_name == \"nt\""} -pyzmq = ">=24" -send2trash = ">=1.8.2" -terminado = ">=0.8.3" -tornado = ">=6.2.0" -traitlets = ">=5.6.0" -websocket-client = ">=1.7" - -[package.extras] -docs = ["ipykernel", "jinja2", "jupyter-client", "myst-parser", "nbformat", "prometheus-client", "pydata-sphinx-theme", "send2trash", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-openapi (>=0.8.0)", "sphinxcontrib-spelling", "sphinxemoji", "tornado", "typing-extensions"] -test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0,<9)", "pytest-console-scripts", "pytest-jupyter[server] (>=0.7)", "pytest-timeout", "requests"] - -[[package]] -name = "jupyter-server-terminals" -version = "0.5.3" -description = "A Jupyter Server Extension Providing Terminals." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa"}, - {file = "jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269"}, -] - -[package.dependencies] -pywinpty = {version = ">=2.0.3", markers = "os_name == \"nt\""} -terminado = ">=0.8.3" - -[package.extras] -docs = ["jinja2", "jupyter-server", "mistune (<4.0)", "myst-parser", "nbformat", "packaging", "pydata-sphinx-theme", "sphinxcontrib-github-alt", "sphinxcontrib-openapi", "sphinxcontrib-spelling", "sphinxemoji", "tornado"] -test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (>=0.5.3)", "pytest-timeout"] - -[[package]] -name = "jupyterlab" -version = "4.4.10" -description = "JupyterLab computational environment" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "jupyterlab-4.4.10-py3-none-any.whl", hash = "sha256:65939ab4c8dcd0c42185c2d0d1a9d60b254dc8c46fc4fdb286b63c51e9358e07"}, - {file = "jupyterlab-4.4.10.tar.gz", hash = "sha256:521c017508af4e1d6d9d8a9d90f47a11c61197ad63b2178342489de42540a615"}, -] - -[package.dependencies] -async-lru = ">=1.0.0" -httpx = ">=0.25.0,<1" -ipykernel = ">=6.5.0,<6.30.0 || >6.30.0" -jinja2 = ">=3.0.3" -jupyter-core = "*" -jupyter-lsp = ">=2.0.0" -jupyter-server = ">=2.4.0,<3" -jupyterlab-server = ">=2.27.1,<3" -notebook-shim = ">=0.2" -packaging = "*" -setuptools = ">=41.1.0" -tornado = ">=6.2.0" -traitlets = "*" - -[package.extras] -dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.11.4)"] -docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-jupyter", "sphinx (>=1.8,<8.2.0)", "sphinx-copybutton"] -docs-screenshots = ["altair (==5.5.0)", "ipython (==8.16.1)", "ipywidgets (==8.1.5)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.3.post1)", "matplotlib (==3.10.0)", "nbconvert (>=7.0.0)", "pandas (==2.2.3)", "scipy (==1.15.1)", "vega-datasets (==0.9.0)"] -test = ["coverage", "pytest (>=7.0)", "pytest-check-links (>=0.7)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter (>=0.5.3)", "pytest-timeout", "pytest-tornasync", "requests", "requests-cache", "virtualenv"] -upgrade-extension = ["copier (>=9,<10)", "jinja2-time (<0.3)", "pydantic (<3.0)", "pyyaml-include (<3.0)", "tomli-w (<2.0)"] - -[[package]] -name = "jupyterlab-pygments" -version = "0.3.0" -description = "Pygments theme using JupyterLab CSS variables" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"}, - {file = "jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d"}, -] - -[[package]] -name = "jupyterlab-server" -version = "2.28.0" -description = "A set of server components for JupyterLab and JupyterLab like applications." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968"}, - {file = "jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c"}, -] - -[package.dependencies] -babel = ">=2.10" -jinja2 = ">=3.0.3" -json5 = ">=0.9.0" -jsonschema = ">=4.18.0" -jupyter-server = ">=1.21,<3" -packaging = ">=21.3" -requests = ">=2.31" - -[package.extras] -docs = ["autodoc-traits", "jinja2 (<3.2.0)", "mistune (<4)", "myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-copybutton", "sphinxcontrib-openapi (>0.8)"] -openapi = ["openapi-core (>=0.18.0,<0.19.0)", "ruamel-yaml"] -test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-validator (>=0.6.0,<0.8.0)", "pytest (>=7.0,<8)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter[server] (>=0.6.2)", "pytest-timeout", "requests-mock", "ruamel-yaml", "sphinxcontrib-spelling", "strict-rfc3339", "werkzeug"] - -[[package]] -name = "jupyterlab-widgets" -version = "3.0.15" -description = "Jupyter interactive widgets for JupyterLab" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "jupyterlab_widgets-3.0.15-py3-none-any.whl", hash = "sha256:d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c"}, - {file = "jupyterlab_widgets-3.0.15.tar.gz", hash = "sha256:2920888a0c2922351a9202817957a68c07d99673504d6cd37345299e971bb08b"}, -] - -[[package]] -name = "langchain" -version = "0.3.27" -description = "Building applications with LLMs through composability" -optional = false -python-versions = "<4.0,>=3.9" -groups = ["main"] -files = [ - {file = "langchain-0.3.27-py3-none-any.whl", hash = "sha256:7b20c4f338826acb148d885b20a73a16e410ede9ee4f19bb02011852d5f98798"}, - {file = "langchain-0.3.27.tar.gz", hash = "sha256:aa6f1e6274ff055d0fd36254176770f356ed0a8994297d1df47df341953cec62"}, -] - -[package.dependencies] -langchain-core = ">=0.3.72,<1.0.0" -langchain-text-splitters = ">=0.3.9,<1.0.0" -langsmith = ">=0.1.17" -pydantic = ">=2.7.4,<3.0.0" -PyYAML = ">=5.3" -requests = ">=2,<3" -SQLAlchemy = ">=1.4,<3" - -[package.extras] -anthropic = ["langchain-anthropic"] -aws = ["langchain-aws"] -azure-ai = ["langchain-azure-ai"] -cohere = ["langchain-cohere"] -community = ["langchain-community"] -deepseek = ["langchain-deepseek"] -fireworks = ["langchain-fireworks"] -google-genai = ["langchain-google-genai"] -google-vertexai = ["langchain-google-vertexai"] -groq = ["langchain-groq"] -huggingface = ["langchain-huggingface"] -mistralai = ["langchain-mistralai"] -ollama = ["langchain-ollama"] -openai = ["langchain-openai"] -perplexity = ["langchain-perplexity"] -together = ["langchain-together"] -xai = ["langchain-xai"] - -[[package]] -name = "langchain-aws" -version = "0.2.35" -description = "An integration package connecting AWS and LangChain" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "langchain_aws-0.2.35-py3-none-any.whl", hash = "sha256:8ddb10f3c29f6d52bcbaa4d7f4f56462acf01f608adc7c70f41e5a476899a6bc"}, - {file = "langchain_aws-0.2.35.tar.gz", hash = "sha256:45793a34fe45d365f4292cc768db74669ca24601d2c5da1ac6f44403750d70af"}, -] - -[package.dependencies] -boto3 = ">=1.39.7" -langchain-core = ">=0.3.76,<0.4.0" -numpy = {version = ">=1.26.0,<3", markers = "python_version >= \"3.12\""} -pydantic = ">=2.10.0,<3" - -[package.extras] -tools = ["beautifulsoup4 (>=4.13.4)", "bedrock-agentcore (>=0.1.0) ; python_version >= \"3.10\"", "playwright (>=1.53.0)"] - -[[package]] -name = "langchain-community" -version = "0.3.31" -description = "Community contributed LangChain integrations." -optional = false -python-versions = "<4.0.0,>=3.9.0" -groups = ["main"] -files = [ - {file = "langchain_community-0.3.31-py3-none-any.whl", hash = "sha256:1c727e3ebbacd4d891b07bd440647668001cea3e39cbe732499ad655ec5cb569"}, - {file = "langchain_community-0.3.31.tar.gz", hash = "sha256:250e4c1041539130f6d6ac6f9386cb018354eafccd917b01a4cff1950b80fd81"}, -] - -[package.dependencies] -aiohttp = ">=3.8.3,<4.0.0" -dataclasses-json = ">=0.6.7,<0.7.0" -httpx-sse = ">=0.4.0,<1.0.0" -langchain = ">=0.3.27,<2.0.0" -langchain-core = ">=0.3.78,<2.0.0" -langsmith = ">=0.1.125,<1.0.0" -numpy = [ - {version = ">=1.26.2", markers = "python_version < \"3.13\""}, - {version = ">=2.1.0", markers = "python_version >= \"3.13\""}, -] -pydantic-settings = ">=2.10.1,<3.0.0" -PyYAML = ">=5.3.0,<7.0.0" -requests = ">=2.32.5,<3.0.0" -SQLAlchemy = ">=1.4.0,<3.0.0" -tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10.0.0" - -[[package]] -name = "langchain-core" -version = "0.3.79" -description = "Building applications with LLMs through composability" -optional = false -python-versions = "<4.0.0,>=3.9.0" -groups = ["main"] -files = [ - {file = "langchain_core-0.3.79-py3-none-any.whl", hash = "sha256:92045bfda3e741f8018e1356f83be203ec601561c6a7becfefe85be5ddc58fdb"}, - {file = "langchain_core-0.3.79.tar.gz", hash = "sha256:024ba54a346dd9b13fb8b2342e0c83d0111e7f26fa01f545ada23ad772b55a60"}, -] - -[package.dependencies] -jsonpatch = ">=1.33.0,<2.0.0" -langsmith = ">=0.3.45,<1.0.0" -packaging = ">=23.2.0,<26.0.0" -pydantic = ">=2.7.4,<3.0.0" -PyYAML = ">=5.3.0,<7.0.0" -tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10.0.0" -typing-extensions = ">=4.7.0,<5.0.0" - -[[package]] -name = "langchain-text-splitters" -version = "0.3.11" -description = "LangChain text splitting utilities" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "langchain_text_splitters-0.3.11-py3-none-any.whl", hash = "sha256:cf079131166a487f1372c8ab5d0bfaa6c0a4291733d9c43a34a16ac9bcd6a393"}, - {file = "langchain_text_splitters-0.3.11.tar.gz", hash = "sha256:7a50a04ada9a133bbabb80731df7f6ddac51bc9f1b9cab7fa09304d71d38a6cc"}, -] - -[package.dependencies] -langchain-core = ">=0.3.75,<2.0.0" - -[[package]] -name = "langchainhub" -version = "0.1.21" -description = "The LangChain Hub API client" -optional = false -python-versions = "<4.0,>=3.8.1" -groups = ["main"] -files = [ - {file = "langchainhub-0.1.21-py3-none-any.whl", hash = "sha256:1cc002dc31e0d132a776afd044361e2b698743df5202618cf2bad399246b895f"}, - {file = "langchainhub-0.1.21.tar.gz", hash = "sha256:723383b3964a47dbaea6ad5d0ef728accefbc9d2c07480e800bdec43510a8c10"}, -] - -[package.dependencies] -packaging = ">=23.2,<25" -requests = ">=2,<3" -types-requests = ">=2.31.0.2,<3.0.0.0" - -[[package]] -name = "langsmith" -version = "0.4.38" -description = "Client library to connect to the LangSmith Observability and Evaluation Platform." -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "langsmith-0.4.38-py3-none-any.whl", hash = "sha256:326232a24b1c6dd308a3188557cc023adf8fb14144263b2982c115a6be5141e7"}, - {file = "langsmith-0.4.38.tar.gz", hash = "sha256:3aa57f9c16a5880256cd1eab0452533c1fb5ee14ec5250e23ed919cc2b07f6d3"}, -] - -[package.dependencies] -httpx = ">=0.23.0,<1" -orjson = {version = ">=3.9.14", markers = "platform_python_implementation != \"PyPy\""} -packaging = ">=23.2" -pydantic = ">=1,<3" -requests = ">=2.0.0" -requests-toolbelt = ">=1.0.0" -zstandard = ">=0.23.0" - -[package.extras] -claude-agent-sdk = ["claude-agent-sdk (>=0.1.0) ; python_version >= \"3.10\""] -langsmith-pyo3 = ["langsmith-pyo3 (>=0.1.0rc2)"] -openai-agents = ["openai-agents (>=0.0.3)"] -otel = ["opentelemetry-api (>=1.30.0)", "opentelemetry-exporter-otlp-proto-http (>=1.30.0)", "opentelemetry-sdk (>=1.30.0)"] -pytest = ["pytest (>=7.0.0)", "rich (>=13.9.4)", "vcrpy (>=7.0.0)"] -vcr = ["vcrpy (>=7.0.0)"] - -[[package]] -name = "lark" -version = "1.3.1" -description = "a modern parsing library" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12"}, - {file = "lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905"}, -] - -[package.extras] -atomic-cache = ["atomicwrites"] -interegular = ["interegular (>=0.3.1,<0.4.0)"] -nearley = ["js2py"] -regex = ["regex"] - -[[package]] -name = "markupsafe" -version = "3.0.3" -description = "Safely add untrusted strings to HTML/XML markup." -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, - {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, - {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, - {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, - {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, - {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, - {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, - {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, - {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, - {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, - {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, - {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, - {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, - {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, - {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, - {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, - {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, - {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, - {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, - {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, - {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, - {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, - {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, - {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, - {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, - {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, - {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, - {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, - {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, - {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, - {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, - {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, - {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, - {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, - {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, - {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, - {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, - {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, - {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, - {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, - {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, - {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, - {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, - {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, - {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, - {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, - {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, - {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, - {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, - {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, - {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, - {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, - {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, - {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, - {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, - {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, - {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, - {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, - {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, - {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, - {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, - {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, - {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, - {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, - {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, - {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, - {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, - {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, - {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, - {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, - {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, - {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, - {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, - {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, - {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, - {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, - {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, - {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, - {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, - {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, - {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, - {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, - {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, - {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, - {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, - {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, - {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, - {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, - {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, -] - -[[package]] -name = "marshmallow" -version = "3.26.1" -description = "A lightweight library for converting complex datatypes to and from native Python datatypes." -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c"}, - {file = "marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6"}, -] - -[package.dependencies] -packaging = ">=17.0" - -[package.extras] -dev = ["marshmallow[tests]", "pre-commit (>=3.5,<5.0)", "tox"] -docs = ["autodocsumm (==0.2.14)", "furo (==2024.8.6)", "sphinx (==8.1.3)", "sphinx-copybutton (==0.5.2)", "sphinx-issues (==5.0.0)", "sphinxext-opengraph (==0.9.1)"] -tests = ["pytest", "simplejson"] - -[[package]] -name = "matplotlib-inline" -version = "0.2.1" -description = "Inline Matplotlib backend for Jupyter" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76"}, - {file = "matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe"}, -] - -[package.dependencies] -traitlets = "*" - -[package.extras] -test = ["flake8", "nbdime", "nbval", "notebook", "pytest"] - -[[package]] -name = "mistune" -version = "3.1.4" -description = "A sane and fast Markdown parser with useful plugins and renderers" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "mistune-3.1.4-py3-none-any.whl", hash = "sha256:93691da911e5d9d2e23bc54472892aff676df27a75274962ff9edc210364266d"}, - {file = "mistune-3.1.4.tar.gz", hash = "sha256:b5a7f801d389f724ec702840c11d8fc48f2b33519102fc7ee739e8177b672164"}, -] - -[[package]] -name = "mpmath" -version = "1.3.0" -description = "Python library for arbitrary-precision floating-point arithmetic" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, - {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, -] - -[package.extras] -develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"] -docs = ["sphinx"] -gmpy = ["gmpy2 (>=2.1.0a4) ; platform_python_implementation != \"PyPy\""] -tests = ["pytest (>=4.6)"] - -[[package]] -name = "multidict" -version = "6.7.0" -description = "multidict implementation" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349"}, - {file = "multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e"}, - {file = "multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3"}, - {file = "multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046"}, - {file = "multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32"}, - {file = "multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73"}, - {file = "multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc"}, - {file = "multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62"}, - {file = "multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84"}, - {file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0"}, - {file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e"}, - {file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4"}, - {file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648"}, - {file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111"}, - {file = "multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36"}, - {file = "multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85"}, - {file = "multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7"}, - {file = "multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0"}, - {file = "multidict-6.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4d409aa42a94c0b3fa617708ef5276dfe81012ba6753a0370fcc9d0195d0a1fc"}, - {file = "multidict-6.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14c9e076eede3b54c636f8ce1c9c252b5f057c62131211f0ceeec273810c9721"}, - {file = "multidict-6.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c09703000a9d0fa3c3404b27041e574cc7f4df4c6563873246d0e11812a94b6"}, - {file = "multidict-6.7.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a265acbb7bb33a3a2d626afbe756371dce0279e7b17f4f4eda406459c2b5ff1c"}, - {file = "multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51cb455de290ae462593e5b1cb1118c5c22ea7f0d3620d9940bf695cea5a4bd7"}, - {file = "multidict-6.7.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:db99677b4457c7a5c5a949353e125ba72d62b35f74e26da141530fbb012218a7"}, - {file = "multidict-6.7.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f470f68adc395e0183b92a2f4689264d1ea4b40504a24d9882c27375e6662bb9"}, - {file = "multidict-6.7.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0db4956f82723cc1c270de9c6e799b4c341d327762ec78ef82bb962f79cc07d8"}, - {file = "multidict-6.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e56d780c238f9e1ae66a22d2adf8d16f485381878250db8d496623cd38b22bd"}, - {file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d14baca2ee12c1a64740d4531356ba50b82543017f3ad6de0deb943c5979abb"}, - {file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:295a92a76188917c7f99cda95858c822f9e4aae5824246bba9b6b44004ddd0a6"}, - {file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39f1719f57adbb767ef592a50ae5ebb794220d1188f9ca93de471336401c34d2"}, - {file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0a13fb8e748dfc94749f622de065dd5c1def7e0d2216dba72b1d8069a389c6ff"}, - {file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e3aa16de190d29a0ea1b48253c57d99a68492c8dd8948638073ab9e74dc9410b"}, - {file = "multidict-6.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a048ce45dcdaaf1defb76b2e684f997fb5abf74437b6cb7b22ddad934a964e34"}, - {file = "multidict-6.7.0-cp311-cp311-win32.whl", hash = "sha256:a90af66facec4cebe4181b9e62a68be65e45ac9b52b67de9eec118701856e7ff"}, - {file = "multidict-6.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:95b5ffa4349df2887518bb839409bcf22caa72d82beec453216802f475b23c81"}, - {file = "multidict-6.7.0-cp311-cp311-win_arm64.whl", hash = "sha256:329aa225b085b6f004a4955271a7ba9f1087e39dcb7e65f6284a988264a63912"}, - {file = "multidict-6.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8a3862568a36d26e650a19bb5cbbba14b71789032aebc0423f8cc5f150730184"}, - {file = "multidict-6.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:960c60b5849b9b4f9dcc9bea6e3626143c252c74113df2c1540aebce70209b45"}, - {file = "multidict-6.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2049be98fb57a31b4ccf870bf377af2504d4ae35646a19037ec271e4c07998aa"}, - {file = "multidict-6.7.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0934f3843a1860dd465d38895c17fce1f1cb37295149ab05cd1b9a03afacb2a7"}, - {file = "multidict-6.7.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3e34f3a1b8131ba06f1a73adab24f30934d148afcd5f5de9a73565a4404384e"}, - {file = "multidict-6.7.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:efbb54e98446892590dc2458c19c10344ee9a883a79b5cec4bc34d6656e8d546"}, - {file = "multidict-6.7.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a35c5fc61d4f51eb045061e7967cfe3123d622cd500e8868e7c0c592a09fedc4"}, - {file = "multidict-6.7.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29fe6740ebccba4175af1b9b87bf553e9c15cd5868ee967e010efcf94e4fd0f1"}, - {file = "multidict-6.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:123e2a72e20537add2f33a79e605f6191fba2afda4cbb876e35c1a7074298a7d"}, - {file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b284e319754366c1aee2267a2036248b24eeb17ecd5dc16022095e747f2f4304"}, - {file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:803d685de7be4303b5a657b76e2f6d1240e7e0a8aa2968ad5811fa2285553a12"}, - {file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c04a328260dfd5db8c39538f999f02779012268f54614902d0afc775d44e0a62"}, - {file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8a19cdb57cd3df4cd865849d93ee14920fb97224300c88501f16ecfa2604b4e0"}, - {file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b2fd74c52accced7e75de26023b7dccee62511a600e62311b918ec5c168fc2a"}, - {file = "multidict-6.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e8bfdd0e487acf992407a140d2589fe598238eaeffa3da8448d63a63cd363f8"}, - {file = "multidict-6.7.0-cp312-cp312-win32.whl", hash = "sha256:dd32a49400a2c3d52088e120ee00c1e3576cbff7e10b98467962c74fdb762ed4"}, - {file = "multidict-6.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:92abb658ef2d7ef22ac9f8bb88e8b6c3e571671534e029359b6d9e845923eb1b"}, - {file = "multidict-6.7.0-cp312-cp312-win_arm64.whl", hash = "sha256:490dab541a6a642ce1a9d61a4781656b346a55c13038f0b1244653828e3a83ec"}, - {file = "multidict-6.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bee7c0588aa0076ce77c0ea5d19a68d76ad81fcd9fe8501003b9a24f9d4000f6"}, - {file = "multidict-6.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7ef6b61cad77091056ce0e7ce69814ef72afacb150b7ac6a3e9470def2198159"}, - {file = "multidict-6.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c0359b1ec12b1d6849c59f9d319610b7f20ef990a6d454ab151aa0e3b9f78ca"}, - {file = "multidict-6.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cd240939f71c64bd658f186330603aac1a9a81bf6273f523fca63673cb7378a8"}, - {file = "multidict-6.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60a4d75718a5efa473ebd5ab685786ba0c67b8381f781d1be14da49f1a2dc60"}, - {file = "multidict-6.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53a42d364f323275126aff81fb67c5ca1b7a04fda0546245730a55c8c5f24bc4"}, - {file = "multidict-6.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3b29b980d0ddbecb736735ee5bef69bb2ddca56eff603c86f3f29a1128299b4f"}, - {file = "multidict-6.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8a93b1c0ed2d04b97a5e9336fd2d33371b9a6e29ab7dd6503d63407c20ffbaf"}, - {file = "multidict-6.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ff96e8815eecacc6645da76c413eb3b3d34cfca256c70b16b286a687d013c32"}, - {file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7516c579652f6a6be0e266aec0acd0db80829ca305c3d771ed898538804c2036"}, - {file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:040f393368e63fb0f3330e70c26bfd336656bed925e5cbe17c9da839a6ab13ec"}, - {file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b3bc26a951007b1057a1c543af845f1c7e3e71cc240ed1ace7bf4484aa99196e"}, - {file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7b022717c748dd1992a83e219587aabe45980d88969f01b316e78683e6285f64"}, - {file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9600082733859f00d79dee64effc7aef1beb26adb297416a4ad2116fd61374bd"}, - {file = "multidict-6.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94218fcec4d72bc61df51c198d098ce2b378e0ccbac41ddbed5ef44092913288"}, - {file = "multidict-6.7.0-cp313-cp313-win32.whl", hash = "sha256:a37bd74c3fa9d00be2d7b8eca074dc56bd8077ddd2917a839bd989612671ed17"}, - {file = "multidict-6.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:30d193c6cc6d559db42b6bcec8a5d395d34d60c9877a0b71ecd7c204fcf15390"}, - {file = "multidict-6.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:ea3334cabe4d41b7ccd01e4d349828678794edbc2d3ae97fc162a3312095092e"}, - {file = "multidict-6.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ad9ce259f50abd98a1ca0aa6e490b58c316a0fce0617f609723e40804add2c00"}, - {file = "multidict-6.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07f5594ac6d084cbb5de2df218d78baf55ef150b91f0ff8a21cc7a2e3a5a58eb"}, - {file = "multidict-6.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0591b48acf279821a579282444814a2d8d0af624ae0bc600aa4d1b920b6e924b"}, - {file = "multidict-6.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:749a72584761531d2b9467cfbdfd29487ee21124c304c4b6cb760d8777b27f9c"}, - {file = "multidict-6.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b4c3d199f953acd5b446bf7c0de1fe25d94e09e79086f8dc2f48a11a129cdf1"}, - {file = "multidict-6.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9fb0211dfc3b51efea2f349ec92c114d7754dd62c01f81c3e32b765b70c45c9b"}, - {file = "multidict-6.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a027ec240fe73a8d6281872690b988eed307cd7d91b23998ff35ff577ca688b5"}, - {file = "multidict-6.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1d964afecdf3a8288789df2f5751dc0a8261138c3768d9af117ed384e538fad"}, - {file = "multidict-6.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caf53b15b1b7df9fbd0709aa01409000a2b4dd03a5f6f5cc548183c7c8f8b63c"}, - {file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:654030da3197d927f05a536a66186070e98765aa5142794c9904555d3a9d8fb5"}, - {file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2090d3718829d1e484706a2f525e50c892237b2bf9b17a79b059cb98cddc2f10"}, - {file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d2cfeec3f6f45651b3d408c4acec0ebf3daa9bc8a112a084206f5db5d05b754"}, - {file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ef089f985b8c194d341eb2c24ae6e7408c9a0e2e5658699c92f497437d88c3c"}, - {file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e93a0617cd16998784bf4414c7e40f17a35d2350e5c6f0bd900d3a8e02bd3762"}, - {file = "multidict-6.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0feece2ef8ebc42ed9e2e8c78fc4aa3cf455733b507c09ef7406364c94376c6"}, - {file = "multidict-6.7.0-cp313-cp313t-win32.whl", hash = "sha256:19a1d55338ec1be74ef62440ca9e04a2f001a04d0cc49a4983dc320ff0f3212d"}, - {file = "multidict-6.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3da4fb467498df97e986af166b12d01f05d2e04f978a9c1c680ea1988e0bc4b6"}, - {file = "multidict-6.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b4121773c49a0776461f4a904cdf6264c88e42218aaa8407e803ca8025872792"}, - {file = "multidict-6.7.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bab1e4aff7adaa34410f93b1f8e57c4b36b9af0426a76003f441ee1d3c7e842"}, - {file = "multidict-6.7.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b8512bac933afc3e45fb2b18da8e59b78d4f408399a960339598374d4ae3b56b"}, - {file = "multidict-6.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:79dcf9e477bc65414ebfea98ffd013cb39552b5ecd62908752e0e413d6d06e38"}, - {file = "multidict-6.7.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:31bae522710064b5cbeddaf2e9f32b1abab70ac6ac91d42572502299e9953128"}, - {file = "multidict-6.7.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a0df7ff02397bb63e2fd22af2c87dfa39e8c7f12947bc524dbdc528282c7e34"}, - {file = "multidict-6.7.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a0222514e8e4c514660e182d5156a415c13ef0aabbd71682fc714e327b95e99"}, - {file = "multidict-6.7.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2397ab4daaf2698eb51a76721e98db21ce4f52339e535725de03ea962b5a3202"}, - {file = "multidict-6.7.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8891681594162635948a636c9fe0ff21746aeb3dd5463f6e25d9bea3a8a39ca1"}, - {file = "multidict-6.7.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18706cc31dbf402a7945916dd5cddf160251b6dab8a2c5f3d6d5a55949f676b3"}, - {file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f844a1bbf1d207dd311a56f383f7eda2d0e134921d45751842d8235e7778965d"}, - {file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4393e3581e84e5645506923816b9cc81f5609a778c7e7534054091acc64d1c6"}, - {file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fbd18dc82d7bf274b37aa48d664534330af744e03bccf696d6f4c6042e7d19e7"}, - {file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b6234e14f9314731ec45c42fc4554b88133ad53a09092cc48a88e771c125dadb"}, - {file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:08d4379f9744d8f78d98c8673c06e202ffa88296f009c71bbafe8a6bf847d01f"}, - {file = "multidict-6.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fe04da3f79387f450fd0061d4dd2e45a72749d31bf634aecc9e27f24fdc4b3f"}, - {file = "multidict-6.7.0-cp314-cp314-win32.whl", hash = "sha256:fbafe31d191dfa7c4c51f7a6149c9fb7e914dcf9ffead27dcfd9f1ae382b3885"}, - {file = "multidict-6.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:2f67396ec0310764b9222a1728ced1ab638f61aadc6226f17a71dd9324f9a99c"}, - {file = "multidict-6.7.0-cp314-cp314-win_arm64.whl", hash = "sha256:ba672b26069957ee369cfa7fc180dde1fc6f176eaf1e6beaf61fbebbd3d9c000"}, - {file = "multidict-6.7.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:c1dcc7524066fa918c6a27d61444d4ee7900ec635779058571f70d042d86ed63"}, - {file = "multidict-6.7.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:27e0b36c2d388dc7b6ced3406671b401e84ad7eb0656b8f3a2f46ed0ce483718"}, - {file = "multidict-6.7.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a7baa46a22e77f0988e3b23d4ede5513ebec1929e34ee9495be535662c0dfe2"}, - {file = "multidict-6.7.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bf77f54997a9166a2f5675d1201520586439424c2511723a7312bdb4bcc034e"}, - {file = "multidict-6.7.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e011555abada53f1578d63389610ac8a5400fc70ce71156b0aa30d326f1a5064"}, - {file = "multidict-6.7.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:28b37063541b897fd6a318007373930a75ca6d6ac7c940dbe14731ffdd8d498e"}, - {file = "multidict-6.7.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05047ada7a2fde2631a0ed706f1fd68b169a681dfe5e4cf0f8e4cb6618bbc2cd"}, - {file = "multidict-6.7.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:716133f7d1d946a4e1b91b1756b23c088881e70ff180c24e864c26192ad7534a"}, - {file = "multidict-6.7.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1bed1b467ef657f2a0ae62844a607909ef1c6889562de5e1d505f74457d0b96"}, - {file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ca43bdfa5d37bd6aee89d85e1d0831fb86e25541be7e9d376ead1b28974f8e5e"}, - {file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:44b546bd3eb645fd26fb949e43c02a25a2e632e2ca21a35e2e132c8105dc8599"}, - {file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6ef16328011d3f468e7ebc326f24c1445f001ca1dec335b2f8e66bed3006394"}, - {file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5aa873cbc8e593d361ae65c68f85faadd755c3295ea2c12040ee146802f23b38"}, - {file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3d7b6ccce016e29df4b7ca819659f516f0bc7a4b3efa3bb2012ba06431b044f9"}, - {file = "multidict-6.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:171b73bd4ee683d307599b66793ac80981b06f069b62eea1c9e29c9241aa66b0"}, - {file = "multidict-6.7.0-cp314-cp314t-win32.whl", hash = "sha256:b2d7f80c4e1fd010b07cb26820aae86b7e73b681ee4889684fb8d2d4537aab13"}, - {file = "multidict-6.7.0-cp314-cp314t-win_amd64.whl", hash = "sha256:09929cab6fcb68122776d575e03c6cc64ee0b8fca48d17e135474b042ce515cd"}, - {file = "multidict-6.7.0-cp314-cp314t-win_arm64.whl", hash = "sha256:cc41db090ed742f32bd2d2c721861725e6109681eddf835d0a82bd3a5c382827"}, - {file = "multidict-6.7.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:363eb68a0a59bd2303216d2346e6c441ba10d36d1f9969fcb6f1ba700de7bb5c"}, - {file = "multidict-6.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d874eb056410ca05fed180b6642e680373688efafc7f077b2a2f61811e873a40"}, - {file = "multidict-6.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b55d5497b51afdfde55925e04a022f1de14d4f4f25cdfd4f5d9b0aa96166851"}, - {file = "multidict-6.7.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f8e5c0031b90ca9ce555e2e8fd5c3b02a25f14989cbc310701823832c99eb687"}, - {file = "multidict-6.7.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cf41880c991716f3c7cec48e2f19ae4045fc9db5fc9cff27347ada24d710bb5"}, - {file = "multidict-6.7.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8cfc12a8630a29d601f48d47787bd7eb730e475e83edb5d6c5084317463373eb"}, - {file = "multidict-6.7.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3996b50c3237c4aec17459217c1e7bbdead9a22a0fcd3c365564fbd16439dde6"}, - {file = "multidict-6.7.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7f5170993a0dd3ab871c74f45c0a21a4e2c37a2f2b01b5f722a2ad9c6650469e"}, - {file = "multidict-6.7.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ec81878ddf0e98817def1e77d4f50dae5ef5b0e4fe796fae3bd674304172416e"}, - {file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9281bf5b34f59afbc6b1e477a372e9526b66ca446f4bf62592839c195a718b32"}, - {file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:68af405971779d8b37198726f2b6fe3955db846fee42db7a4286fc542203934c"}, - {file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3ba3ef510467abb0667421a286dc906e30eb08569365f5cdb131d7aff7c2dd84"}, - {file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b61189b29081a20c7e4e0b49b44d5d44bb0dc92be3c6d06a11cc043f81bf9329"}, - {file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fb287618b9c7aa3bf8d825f02d9201b2f13078a5ed3b293c8f4d953917d84d5e"}, - {file = "multidict-6.7.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:521f33e377ff64b96c4c556b81c55d0cfffb96a11c194fd0c3f1e56f3d8dd5a4"}, - {file = "multidict-6.7.0-cp39-cp39-win32.whl", hash = "sha256:ce8fdc2dca699f8dbf055a61d73eaa10482569ad20ee3c36ef9641f69afa8c91"}, - {file = "multidict-6.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:7e73299c99939f089dd9b2120a04a516b95cdf8c1cd2b18c53ebf0de80b1f18f"}, - {file = "multidict-6.7.0-cp39-cp39-win_arm64.whl", hash = "sha256:6bdce131e14b04fd34a809b6380dbfd826065c3e2fe8a50dbae659fa0c390546"}, - {file = "multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3"}, - {file = "multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5"}, -] - -[[package]] -name = "mypy" -version = "1.18.2" -description = "Optional static typing for Python" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c"}, - {file = "mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e"}, - {file = "mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b"}, - {file = "mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66"}, - {file = "mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428"}, - {file = "mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed"}, - {file = "mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f"}, - {file = "mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341"}, - {file = "mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d"}, - {file = "mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86"}, - {file = "mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37"}, - {file = "mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8"}, - {file = "mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34"}, - {file = "mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764"}, - {file = "mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893"}, - {file = "mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914"}, - {file = "mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8"}, - {file = "mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074"}, - {file = "mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc"}, - {file = "mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e"}, - {file = "mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986"}, - {file = "mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d"}, - {file = "mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba"}, - {file = "mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544"}, - {file = "mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce"}, - {file = "mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d"}, - {file = "mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c"}, - {file = "mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb"}, - {file = "mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075"}, - {file = "mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf"}, - {file = "mypy-1.18.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25a9c8fb67b00599f839cf472713f54249a62efd53a54b565eb61956a7e3296b"}, - {file = "mypy-1.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2b9c7e284ee20e7598d6f42e13ca40b4928e6957ed6813d1ab6348aa3f47133"}, - {file = "mypy-1.18.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6985ed057513e344e43a26cc1cd815c7a94602fb6a3130a34798625bc2f07b6"}, - {file = "mypy-1.18.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22f27105f1525ec024b5c630c0b9f36d5c1cc4d447d61fe51ff4bd60633f47ac"}, - {file = "mypy-1.18.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:030c52d0ea8144e721e49b1f68391e39553d7451f0c3f8a7565b59e19fcb608b"}, - {file = "mypy-1.18.2-cp39-cp39-win_amd64.whl", hash = "sha256:aa5e07ac1a60a253445797e42b8b2963c9675563a94f11291ab40718b016a7a0"}, - {file = "mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e"}, - {file = "mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b"}, -] - -[package.dependencies] -mypy_extensions = ">=1.0.0" -pathspec = ">=0.9.0" -typing_extensions = ">=4.6.0" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -faster-cache = ["orjson"] -install-types = ["pip"] -mypyc = ["setuptools (>=50)"] -reports = ["lxml"] - -[[package]] -name = "mypy-extensions" -version = "1.1.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, - {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, -] - -[[package]] -name = "nbclient" -version = "0.10.2" -description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." -optional = false -python-versions = ">=3.9.0" -groups = ["dev"] -files = [ - {file = "nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d"}, - {file = "nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193"}, -] - -[package.dependencies] -jupyter-client = ">=6.1.12" -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -nbformat = ">=5.1" -traitlets = ">=5.4" - -[package.extras] -dev = ["pre-commit"] -docs = ["autodoc-traits", "flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "mock", "moto", "myst-parser", "nbconvert (>=7.1.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling", "testpath", "xmltodict"] -test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.1.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] - -[[package]] -name = "nbconvert" -version = "7.16.6" -description = "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`)." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b"}, - {file = "nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582"}, -] - -[package.dependencies] -beautifulsoup4 = "*" -bleach = {version = "!=5.0.0", extras = ["css"]} -defusedxml = "*" -jinja2 = ">=3.0" -jupyter-core = ">=4.7" -jupyterlab-pygments = "*" -markupsafe = ">=2.0" -mistune = ">=2.0.3,<4" -nbclient = ">=0.5.0" -nbformat = ">=5.7" -packaging = "*" -pandocfilters = ">=1.4.1" -pygments = ">=2.4.1" -traitlets = ">=5.1" - -[package.extras] -all = ["flaky", "ipykernel", "ipython", "ipywidgets (>=7.5)", "myst-parser", "nbsphinx (>=0.2.12)", "playwright", "pydata-sphinx-theme", "pyqtwebengine (>=5.15)", "pytest (>=7)", "sphinx (==5.0.2)", "sphinxcontrib-spelling", "tornado (>=6.1)"] -docs = ["ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sphinx-theme", "sphinx (==5.0.2)", "sphinxcontrib-spelling"] -qtpdf = ["pyqtwebengine (>=5.15)"] -qtpng = ["pyqtwebengine (>=5.15)"] -serve = ["tornado (>=6.1)"] -test = ["flaky", "ipykernel", "ipywidgets (>=7.5)", "pytest (>=7)"] -webpdf = ["playwright"] - -[[package]] -name = "nbformat" -version = "5.10.4" -description = "The Jupyter Notebook format" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"}, - {file = "nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a"}, -] - -[package.dependencies] -fastjsonschema = ">=2.15" -jsonschema = ">=2.6" -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -traitlets = ">=5.1" - -[package.extras] -docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["pep440", "pre-commit", "pytest", "testpath"] - -[[package]] -name = "nest-asyncio" -version = "1.6.0" -description = "Patch asyncio to allow nested event loops" -optional = false -python-versions = ">=3.5" -groups = ["dev"] -files = [ - {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, - {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, -] - -[[package]] -name = "networkx" -version = "3.5" -description = "Python package for creating and manipulating graphs and networks" -optional = false -python-versions = ">=3.11" -groups = ["main"] -files = [ - {file = "networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec"}, - {file = "networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037"}, -] - -[package.extras] -default = ["matplotlib (>=3.8)", "numpy (>=1.25)", "pandas (>=2.0)", "scipy (>=1.11.2)"] -developer = ["mypy (>=1.15)", "pre-commit (>=4.1)"] -doc = ["intersphinx-registry", "myst-nb (>=1.1)", "numpydoc (>=1.8.0)", "pillow (>=10)", "pydata-sphinx-theme (>=0.16)", "sphinx (>=8.0)", "sphinx-gallery (>=0.18)", "texext (>=0.6.7)"] -example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "momepy (>=0.7.2)", "osmnx (>=2.0.0)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"] -extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=1.14)", "sympy (>=1.10)"] -test = ["pytest (>=7.2)", "pytest-cov (>=4.0)", "pytest-xdist (>=3.0)"] -test-extras = ["pytest-mpl", "pytest-randomly"] - -[[package]] -name = "nltk" -version = "3.9.2" -description = "Natural Language Toolkit" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "nltk-3.9.2-py3-none-any.whl", hash = "sha256:1e209d2b3009110635ed9709a67a1a3e33a10f799490fa71cf4bec218c11c88a"}, - {file = "nltk-3.9.2.tar.gz", hash = "sha256:0f409e9b069ca4177c1903c3e843eef90c7e92992fa4931ae607da6de49e1419"}, -] - -[package.dependencies] -click = "*" -joblib = "*" -regex = ">=2021.8.3" -tqdm = "*" - -[package.extras] -all = ["matplotlib", "numpy", "pyparsing", "python-crfsuite", "requests", "scikit-learn", "scipy", "twython"] -corenlp = ["requests"] -machine-learning = ["numpy", "python-crfsuite", "scikit-learn", "scipy"] -plot = ["matplotlib"] -tgrep = ["pyparsing"] -twitter = ["twython"] - -[[package]] -name = "notebook" -version = "7.4.7" -description = "Jupyter Notebook - A web-based notebook environment for interactive computing" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "notebook-7.4.7-py3-none-any.whl", hash = "sha256:362b7c95527f7dd3c4c84d410b782872fd9c734fb2524c11dd92758527b6eda6"}, - {file = "notebook-7.4.7.tar.gz", hash = "sha256:3f0a04027dfcee8a876de48fba13ab77ec8c12f72f848a222ed7f5081b9e342a"}, -] - -[package.dependencies] -jupyter-server = ">=2.4.0,<3" -jupyterlab = ">=4.4.9,<4.5" -jupyterlab-server = ">=2.27.1,<3" -notebook-shim = ">=0.2,<0.3" -tornado = ">=6.2.0" - -[package.extras] -dev = ["hatch", "pre-commit"] -docs = ["myst-parser", "nbsphinx", "pydata-sphinx-theme", "sphinx (>=1.3.6)", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["importlib-resources (>=5.0) ; python_version < \"3.10\"", "ipykernel", "jupyter-server[test] (>=2.4.0,<3)", "jupyterlab-server[test] (>=2.27.1,<3)", "nbval", "pytest (>=7.0)", "pytest-console-scripts", "pytest-timeout", "pytest-tornasync", "requests"] - -[[package]] -name = "notebook-shim" -version = "0.2.4" -description = "A shim layer for notebook traits and config" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef"}, - {file = "notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb"}, -] - -[package.dependencies] -jupyter-server = ">=1.8,<3" - -[package.extras] -test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync"] - -[[package]] -name = "numpy" -version = "2.3.4" -description = "Fundamental package for array computing in Python" -optional = false -python-versions = ">=3.11" -groups = ["main"] -files = [ - {file = "numpy-2.3.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e78aecd2800b32e8347ce49316d3eaf04aed849cd5b38e0af39f829a4e59f5eb"}, - {file = "numpy-2.3.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7fd09cc5d65bda1e79432859c40978010622112e9194e581e3415a3eccc7f43f"}, - {file = "numpy-2.3.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:1b219560ae2c1de48ead517d085bc2d05b9433f8e49d0955c82e8cd37bd7bf36"}, - {file = "numpy-2.3.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:bafa7d87d4c99752d07815ed7a2c0964f8ab311eb8168f41b910bd01d15b6032"}, - {file = "numpy-2.3.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36dc13af226aeab72b7abad501d370d606326a0029b9f435eacb3b8c94b8a8b7"}, - {file = "numpy-2.3.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7b2f9a18b5ff9824a6af80de4f37f4ec3c2aab05ef08f51c77a093f5b89adda"}, - {file = "numpy-2.3.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9984bd645a8db6ca15d850ff996856d8762c51a2239225288f08f9050ca240a0"}, - {file = "numpy-2.3.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:64c5825affc76942973a70acf438a8ab618dbd692b84cd5ec40a0a0509edc09a"}, - {file = "numpy-2.3.4-cp311-cp311-win32.whl", hash = "sha256:ed759bf7a70342f7817d88376eb7142fab9fef8320d6019ef87fae05a99874e1"}, - {file = "numpy-2.3.4-cp311-cp311-win_amd64.whl", hash = "sha256:faba246fb30ea2a526c2e9645f61612341de1a83fb1e0c5edf4ddda5a9c10996"}, - {file = "numpy-2.3.4-cp311-cp311-win_arm64.whl", hash = "sha256:4c01835e718bcebe80394fd0ac66c07cbb90147ebbdad3dcecd3f25de2ae7e2c"}, - {file = "numpy-2.3.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ef1b5a3e808bc40827b5fa2c8196151a4c5abe110e1726949d7abddfe5c7ae11"}, - {file = "numpy-2.3.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c2f91f496a87235c6aaf6d3f3d89b17dba64996abadccb289f48456cff931ca9"}, - {file = "numpy-2.3.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f77e5b3d3da652b474cc80a14084927a5e86a5eccf54ca8ca5cbd697bf7f2667"}, - {file = "numpy-2.3.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:8ab1c5f5ee40d6e01cbe96de5863e39b215a4d24e7d007cad56c7184fdf4aeef"}, - {file = "numpy-2.3.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77b84453f3adcb994ddbd0d1c5d11db2d6bda1a2b7fd5ac5bd4649d6f5dc682e"}, - {file = "numpy-2.3.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4121c5beb58a7f9e6dfdee612cb24f4df5cd4db6e8261d7f4d7450a997a65d6a"}, - {file = "numpy-2.3.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:65611ecbb00ac9846efe04db15cbe6186f562f6bb7e5e05f077e53a599225d16"}, - {file = "numpy-2.3.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dabc42f9c6577bcc13001b8810d300fe814b4cfbe8a92c873f269484594f9786"}, - {file = "numpy-2.3.4-cp312-cp312-win32.whl", hash = "sha256:a49d797192a8d950ca59ee2d0337a4d804f713bb5c3c50e8db26d49666e351dc"}, - {file = "numpy-2.3.4-cp312-cp312-win_amd64.whl", hash = "sha256:985f1e46358f06c2a09921e8921e2c98168ed4ae12ccd6e5e87a4f1857923f32"}, - {file = "numpy-2.3.4-cp312-cp312-win_arm64.whl", hash = "sha256:4635239814149e06e2cb9db3dd584b2fa64316c96f10656983b8026a82e6e4db"}, - {file = "numpy-2.3.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c090d4860032b857d94144d1a9976b8e36709e40386db289aaf6672de2a81966"}, - {file = "numpy-2.3.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a13fc473b6db0be619e45f11f9e81260f7302f8d180c49a22b6e6120022596b3"}, - {file = "numpy-2.3.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:3634093d0b428e6c32c3a69b78e554f0cd20ee420dcad5a9f3b2a63762ce4197"}, - {file = "numpy-2.3.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:043885b4f7e6e232d7df4f51ffdef8c36320ee9d5f227b380ea636722c7ed12e"}, - {file = "numpy-2.3.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ee6a571d1e4f0ea6d5f22d6e5fbd6ed1dc2b18542848e1e7301bd190500c9d7"}, - {file = "numpy-2.3.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc8a63918b04b8571789688b2780ab2b4a33ab44bfe8ccea36d3eba51228c953"}, - {file = "numpy-2.3.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:40cc556d5abbc54aabe2b1ae287042d7bdb80c08edede19f0c0afb36ae586f37"}, - {file = "numpy-2.3.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ecb63014bb7f4ce653f8be7f1df8cbc6093a5a2811211770f6606cc92b5a78fd"}, - {file = "numpy-2.3.4-cp313-cp313-win32.whl", hash = "sha256:e8370eb6925bb8c1c4264fec52b0384b44f675f191df91cbe0140ec9f0955646"}, - {file = "numpy-2.3.4-cp313-cp313-win_amd64.whl", hash = "sha256:56209416e81a7893036eea03abcb91c130643eb14233b2515c90dcac963fe99d"}, - {file = "numpy-2.3.4-cp313-cp313-win_arm64.whl", hash = "sha256:a700a4031bc0fd6936e78a752eefb79092cecad2599ea9c8039c548bc097f9bc"}, - {file = "numpy-2.3.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:86966db35c4040fdca64f0816a1c1dd8dbd027d90fca5a57e00e1ca4cd41b879"}, - {file = "numpy-2.3.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:838f045478638b26c375ee96ea89464d38428c69170360b23a1a50fa4baa3562"}, - {file = "numpy-2.3.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d7315ed1dab0286adca467377c8381cd748f3dc92235f22a7dfc42745644a96a"}, - {file = "numpy-2.3.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:84f01a4d18b2cc4ade1814a08e5f3c907b079c847051d720fad15ce37aa930b6"}, - {file = "numpy-2.3.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:817e719a868f0dacde4abdfc5c1910b301877970195db9ab6a5e2c4bd5b121f7"}, - {file = "numpy-2.3.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85e071da78d92a214212cacea81c6da557cab307f2c34b5f85b628e94803f9c0"}, - {file = "numpy-2.3.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2ec646892819370cf3558f518797f16597b4e4669894a2ba712caccc9da53f1f"}, - {file = "numpy-2.3.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:035796aaaddfe2f9664b9a9372f089cfc88bd795a67bd1bfe15e6e770934cf64"}, - {file = "numpy-2.3.4-cp313-cp313t-win32.whl", hash = "sha256:fea80f4f4cf83b54c3a051f2f727870ee51e22f0248d3114b8e755d160b38cfb"}, - {file = "numpy-2.3.4-cp313-cp313t-win_amd64.whl", hash = "sha256:15eea9f306b98e0be91eb344a94c0e630689ef302e10c2ce5f7e11905c704f9c"}, - {file = "numpy-2.3.4-cp313-cp313t-win_arm64.whl", hash = "sha256:b6c231c9c2fadbae4011ca5e7e83e12dc4a5072f1a1d85a0a7b3ed754d145a40"}, - {file = "numpy-2.3.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:81c3e6d8c97295a7360d367f9f8553973651b76907988bb6066376bc2252f24e"}, - {file = "numpy-2.3.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7c26b0b2bf58009ed1f38a641f3db4be8d960a417ca96d14e5b06df1506d41ff"}, - {file = "numpy-2.3.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:62b2198c438058a20b6704351b35a1d7db881812d8512d67a69c9de1f18ca05f"}, - {file = "numpy-2.3.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:9d729d60f8d53a7361707f4b68a9663c968882dd4f09e0d58c044c8bf5faee7b"}, - {file = "numpy-2.3.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd0c630cf256b0a7fd9d0a11c9413b42fef5101219ce6ed5a09624f5a65392c7"}, - {file = "numpy-2.3.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5e081bc082825f8b139f9e9fe42942cb4054524598aaeb177ff476cc76d09d2"}, - {file = "numpy-2.3.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:15fb27364ed84114438fff8aaf998c9e19adbeba08c0b75409f8c452a8692c52"}, - {file = "numpy-2.3.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:85d9fb2d8cd998c84d13a79a09cc0c1091648e848e4e6249b0ccd7f6b487fa26"}, - {file = "numpy-2.3.4-cp314-cp314-win32.whl", hash = "sha256:e73d63fd04e3a9d6bc187f5455d81abfad05660b212c8804bf3b407e984cd2bc"}, - {file = "numpy-2.3.4-cp314-cp314-win_amd64.whl", hash = "sha256:3da3491cee49cf16157e70f607c03a217ea6647b1cea4819c4f48e53d49139b9"}, - {file = "numpy-2.3.4-cp314-cp314-win_arm64.whl", hash = "sha256:6d9cd732068e8288dbe2717177320723ccec4fb064123f0caf9bbd90ab5be868"}, - {file = "numpy-2.3.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:22758999b256b595cf0b1d102b133bb61866ba5ceecf15f759623b64c020c9ec"}, - {file = "numpy-2.3.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9cb177bc55b010b19798dc5497d540dea67fd13a8d9e882b2dae71de0cf09eb3"}, - {file = "numpy-2.3.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:0f2bcc76f1e05e5ab58893407c63d90b2029908fa41f9f1cc51eecce936c3365"}, - {file = "numpy-2.3.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:8dc20bde86802df2ed8397a08d793da0ad7a5fd4ea3ac85d757bf5dd4ad7c252"}, - {file = "numpy-2.3.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e199c087e2aa71c8f9ce1cb7a8e10677dc12457e7cc1be4798632da37c3e86e"}, - {file = "numpy-2.3.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85597b2d25ddf655495e2363fe044b0ae999b75bc4d630dc0d886484b03a5eb0"}, - {file = "numpy-2.3.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04a69abe45b49c5955923cf2c407843d1c85013b424ae8a560bba16c92fe44a0"}, - {file = "numpy-2.3.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e1708fac43ef8b419c975926ce1eaf793b0c13b7356cfab6ab0dc34c0a02ac0f"}, - {file = "numpy-2.3.4-cp314-cp314t-win32.whl", hash = "sha256:863e3b5f4d9915aaf1b8ec79ae560ad21f0b8d5e3adc31e73126491bb86dee1d"}, - {file = "numpy-2.3.4-cp314-cp314t-win_amd64.whl", hash = "sha256:962064de37b9aef801d33bc579690f8bfe6c5e70e29b61783f60bcba838a14d6"}, - {file = "numpy-2.3.4-cp314-cp314t-win_arm64.whl", hash = "sha256:8b5a9a39c45d852b62693d9b3f3e0fe052541f804296ff401a72a1b60edafb29"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6e274603039f924c0fe5cb73438fa9246699c78a6df1bd3decef9ae592ae1c05"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d149aee5c72176d9ddbc6803aef9c0f6d2ceeea7626574fc68518da5476fa346"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:6d34ed9db9e6395bb6cd33286035f73a59b058169733a9db9f85e650b88df37e"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:fdebe771ca06bb8d6abce84e51dca9f7921fe6ad34a0c914541b063e9a68928b"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e92defe6c08211eb77902253b14fe5b480ebc5112bc741fd5e9cd0608f847"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13b9062e4f5c7ee5c7e5be96f29ba71bc5a37fed3d1d77c37390ae00724d296d"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:81b3a59793523e552c4a96109dde028aa4448ae06ccac5a76ff6532a85558a7f"}, - {file = "numpy-2.3.4.tar.gz", hash = "sha256:a7d018bfedb375a8d979ac758b120ba846a7fe764911a64465fd87b8729f4a6a"}, -] - -[[package]] -name = "nvidia-cublas-cu12" -version = "12.6.4.1" -description = "CUBLAS native runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_cublas_cu12-12.6.4.1-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:08ed2686e9875d01b58e3cb379c6896df8e76c75e0d4a7f7dace3d7b6d9ef8eb"}, - {file = "nvidia_cublas_cu12-12.6.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:235f728d6e2a409eddf1df58d5b0921cf80cfa9e72b9f2775ccb7b4a87984668"}, - {file = "nvidia_cublas_cu12-12.6.4.1-py3-none-win_amd64.whl", hash = "sha256:9e4fa264f4d8a4eb0cdbd34beadc029f453b3bafae02401e999cf3d5a5af75f8"}, -] - -[[package]] -name = "nvidia-cublas-cu12" -version = "12.8.4.1" -description = "CUBLAS native runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0"}, - {file = "nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142"}, - {file = "nvidia_cublas_cu12-12.8.4.1-py3-none-win_amd64.whl", hash = "sha256:47e9b82132fa8d2b4944e708049229601448aaad7e6f296f630f2d1a32de35af"}, -] - -[[package]] -name = "nvidia-cuda-cupti-cu12" -version = "12.6.80" -description = "CUDA profiling tools runtime libs." -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:166ee35a3ff1587f2490364f90eeeb8da06cd867bd5b701bf7f9a02b78bc63fc"}, - {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_aarch64.whl", hash = "sha256:358b4a1d35370353d52e12f0a7d1769fc01ff74a191689d3870b2123156184c4"}, - {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6768bad6cab4f19e8292125e5f1ac8aa7d1718704012a0e3272a6f61c4bce132"}, - {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a3eff6cdfcc6a4c35db968a06fcadb061cbc7d6dde548609a941ff8701b98b73"}, - {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-win_amd64.whl", hash = "sha256:bbe6ae76e83ce5251b56e8c8e61a964f757175682bbad058b170b136266ab00a"}, -] - -[[package]] -name = "nvidia-cuda-cupti-cu12" -version = "12.8.90" -description = "CUDA profiling tools runtime libs." -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed"}, - {file = "nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182"}, - {file = "nvidia_cuda_cupti_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:bb479dcdf7e6d4f8b0b01b115260399bf34154a1a2e9fe11c85c517d87efd98e"}, -] - -[[package]] -name = "nvidia-cuda-nvrtc-cu12" -version = "12.6.77" -description = "NVRTC native runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_cuda_nvrtc_cu12-12.6.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5847f1d6e5b757f1d2b3991a01082a44aad6f10ab3c5c0213fa3e25bddc25a13"}, - {file = "nvidia_cuda_nvrtc_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:35b0cc6ee3a9636d5409133e79273ce1f3fd087abb0532d2d2e8fff1fe9efc53"}, - {file = "nvidia_cuda_nvrtc_cu12-12.6.77-py3-none-win_amd64.whl", hash = "sha256:f7007dbd914c56bd80ea31bc43e8e149da38f68158f423ba845fc3292684e45a"}, -] - -[[package]] -name = "nvidia-cuda-nvrtc-cu12" -version = "12.8.93" -description = "NVRTC native runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994"}, - {file = "nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8"}, - {file = "nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:7a4b6b2904850fe78e0bd179c4b655c404d4bb799ef03ddc60804247099ae909"}, -] - -[[package]] -name = "nvidia-cuda-runtime-cu12" -version = "12.6.77" -description = "CUDA Runtime native Libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6116fad3e049e04791c0256a9778c16237837c08b27ed8c8401e2e45de8d60cd"}, - {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d461264ecb429c84c8879a7153499ddc7b19b5f8d84c204307491989a365588e"}, - {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ba3b56a4f896141e25e19ab287cd71e52a6a0f4b29d0d31609f60e3b4d5219b7"}, - {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a84d15d5e1da416dd4774cb42edf5e954a3e60cc945698dc1d5be02321c44dc8"}, - {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-win_amd64.whl", hash = "sha256:86c58044c824bf3c173c49a2dbc7a6c8b53cb4e4dca50068be0bf64e9dab3f7f"}, -] - -[[package]] -name = "nvidia-cuda-runtime-cu12" -version = "12.8.90" -description = "CUDA Runtime native Libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d"}, - {file = "nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90"}, - {file = "nvidia_cuda_runtime_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:c0c6027f01505bfed6c3b21ec546f69c687689aad5f1a377554bc6ca4aa993a8"}, -] - -[[package]] -name = "nvidia-cudnn-cu12" -version = "9.5.1.17" -description = "cuDNN runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_cudnn_cu12-9.5.1.17-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:9fd4584468533c61873e5fda8ca41bac3a38bcb2d12350830c69b0a96a7e4def"}, - {file = "nvidia_cudnn_cu12-9.5.1.17-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:30ac3869f6db17d170e0e556dd6cc5eee02647abc31ca856634d5a40f82c15b2"}, - {file = "nvidia_cudnn_cu12-9.5.1.17-py3-none-win_amd64.whl", hash = "sha256:d7af0f8a4f3b4b9dbb3122f2ef553b45694ed9c384d5a75bab197b8eefb79ab8"}, -] - -[package.dependencies] -nvidia-cublas-cu12 = "*" - -[[package]] -name = "nvidia-cudnn-cu12" -version = "9.10.2.21" -description = "cuDNN runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8"}, - {file = "nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8"}, - {file = "nvidia_cudnn_cu12-9.10.2.21-py3-none-win_amd64.whl", hash = "sha256:c6288de7d63e6cf62988f0923f96dc339cea362decb1bf5b3141883392a7d65e"}, -] - -[package.dependencies] -nvidia-cublas-cu12 = "*" - -[[package]] -name = "nvidia-cufft-cu12" -version = "11.3.0.4" -description = "CUFFT native runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d16079550df460376455cba121db6564089176d9bac9e4f360493ca4741b22a6"}, - {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8510990de9f96c803a051822618d42bf6cb8f069ff3f48d93a8486efdacb48fb"}, - {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ccba62eb9cef5559abd5e0d54ceed2d9934030f51163df018532142a8ec533e5"}, - {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_x86_64.whl", hash = "sha256:768160ac89f6f7b459bee747e8d175dbf53619cfe74b2a5636264163138013ca"}, - {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-win_amd64.whl", hash = "sha256:6048ebddfb90d09d2707efb1fd78d4e3a77cb3ae4dc60e19aab6be0ece2ae464"}, -] - -[package.dependencies] -nvidia-nvjitlink-cu12 = "*" - -[[package]] -name = "nvidia-cufft-cu12" -version = "11.3.3.83" -description = "CUFFT native runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a"}, - {file = "nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74"}, - {file = "nvidia_cufft_cu12-11.3.3.83-py3-none-win_amd64.whl", hash = "sha256:7a64a98ef2a7c47f905aaf8931b69a3a43f27c55530c698bb2ed7c75c0b42cb7"}, -] - -[package.dependencies] -nvidia-nvjitlink-cu12 = "*" - -[[package]] -name = "nvidia-cufile-cu12" -version = "1.11.1.6" -description = "cuFile GPUDirect libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_cufile_cu12-1.11.1.6-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc23469d1c7e52ce6c1d55253273d32c565dd22068647f3aa59b3c6b005bf159"}, - {file = "nvidia_cufile_cu12-1.11.1.6-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:8f57a0051dcf2543f6dc2b98a98cb2719c37d3cee1baba8965d57f3bbc90d4db"}, -] - -[[package]] -name = "nvidia-cufile-cu12" -version = "1.13.1.3" -description = "cuFile GPUDirect libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc"}, - {file = "nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a"}, -] - -[[package]] -name = "nvidia-curand-cu12" -version = "10.3.7.77" -description = "CURAND native runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_curand_cu12-10.3.7.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:6e82df077060ea28e37f48a3ec442a8f47690c7499bff392a5938614b56c98d8"}, - {file = "nvidia_curand_cu12-10.3.7.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a42cd1344297f70b9e39a1e4f467a4e1c10f1da54ff7a85c12197f6c652c8bdf"}, - {file = "nvidia_curand_cu12-10.3.7.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:99f1a32f1ac2bd134897fc7a203f779303261268a65762a623bf30cc9fe79117"}, - {file = "nvidia_curand_cu12-10.3.7.77-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:7b2ed8e95595c3591d984ea3603dd66fe6ce6812b886d59049988a712ed06b6e"}, - {file = "nvidia_curand_cu12-10.3.7.77-py3-none-win_amd64.whl", hash = "sha256:6d6d935ffba0f3d439b7cd968192ff068fafd9018dbf1b85b37261b13cfc9905"}, -] - -[[package]] -name = "nvidia-curand-cu12" -version = "10.3.9.90" -description = "CURAND native runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd"}, - {file = "nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9"}, - {file = "nvidia_curand_cu12-10.3.9.90-py3-none-win_amd64.whl", hash = "sha256:f149a8ca457277da854f89cf282d6ef43176861926c7ac85b2a0fbd237c587ec"}, -] - -[[package]] -name = "nvidia-cusolver-cu12" -version = "11.7.1.2" -description = "CUDA solver native runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0ce237ef60acde1efc457335a2ddadfd7610b892d94efee7b776c64bb1cac9e0"}, - {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e9e49843a7707e42022babb9bcfa33c29857a93b88020c4e4434656a655b698c"}, - {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6cf28f17f64107a0c4d7802be5ff5537b2130bfc112f25d5a30df227058ca0e6"}, - {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dbbe4fc38ec1289c7e5230e16248365e375c3673c9c8bac5796e2e20db07f56e"}, - {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-win_amd64.whl", hash = "sha256:6813f9d8073f555444a8705f3ab0296d3e1cb37a16d694c5fc8b862a0d8706d7"}, -] - -[package.dependencies] -nvidia-cublas-cu12 = "*" -nvidia-cusparse-cu12 = "*" -nvidia-nvjitlink-cu12 = "*" - -[[package]] -name = "nvidia-cusolver-cu12" -version = "11.7.3.90" -description = "CUDA solver native runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0"}, - {file = "nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450"}, - {file = "nvidia_cusolver_cu12-11.7.3.90-py3-none-win_amd64.whl", hash = "sha256:4a550db115fcabc4d495eb7d39ac8b58d4ab5d8e63274d3754df1c0ad6a22d34"}, -] - -[package.dependencies] -nvidia-cublas-cu12 = "*" -nvidia-cusparse-cu12 = "*" -nvidia-nvjitlink-cu12 = "*" - -[[package]] -name = "nvidia-cusparse-cu12" -version = "12.5.4.2" -description = "CUSPARSE native runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d25b62fb18751758fe3c93a4a08eff08effedfe4edf1c6bb5afd0890fe88f887"}, - {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7aa32fa5470cf754f72d1116c7cbc300b4e638d3ae5304cfa4a638a5b87161b1"}, - {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7556d9eca156e18184b94947ade0fba5bb47d69cec46bf8660fd2c71a4b48b73"}, - {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:23749a6571191a215cb74d1cdbff4a86e7b19f1200c071b3fcf844a5bea23a2f"}, - {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-win_amd64.whl", hash = "sha256:4acb8c08855a26d737398cba8fb6f8f5045d93f82612b4cfd84645a2332ccf20"}, -] - -[package.dependencies] -nvidia-nvjitlink-cu12 = "*" - -[[package]] -name = "nvidia-cusparse-cu12" -version = "12.5.8.93" -description = "CUSPARSE native runtime libraries" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc"}, - {file = "nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b"}, - {file = "nvidia_cusparse_cu12-12.5.8.93-py3-none-win_amd64.whl", hash = "sha256:9a33604331cb2cac199f2e7f5104dfbb8a5a898c367a53dfda9ff2acb6b6b4dd"}, -] - -[package.dependencies] -nvidia-nvjitlink-cu12 = "*" - -[[package]] -name = "nvidia-cusparselt-cu12" -version = "0.6.3" -description = "NVIDIA cuSPARSELt" -optional = false -python-versions = "*" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_cusparselt_cu12-0.6.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8371549623ba601a06322af2133c4a44350575f5a3108fb75f3ef20b822ad5f1"}, - {file = "nvidia_cusparselt_cu12-0.6.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e5c8a26c36445dd2e6812f1177978a24e2d37cacce7e090f297a688d1ec44f46"}, - {file = "nvidia_cusparselt_cu12-0.6.3-py3-none-win_amd64.whl", hash = "sha256:3b325bcbd9b754ba43df5a311488fca11a6b5dc3d11df4d190c000cf1a0765c7"}, -] - -[[package]] -name = "nvidia-cusparselt-cu12" -version = "0.7.1" -description = "NVIDIA cuSPARSELt" -optional = false -python-versions = "*" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5"}, - {file = "nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623"}, - {file = "nvidia_cusparselt_cu12-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f67fbb5831940ec829c9117b7f33807db9f9678dc2a617fbe781cac17b4e1075"}, -] - -[[package]] -name = "nvidia-nccl-cu12" -version = "2.26.2" -description = "NVIDIA Collective Communication Library (NCCL) Runtime" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_nccl_cu12-2.26.2-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c196e95e832ad30fbbb50381eb3cbd1fadd5675e587a548563993609af19522"}, - {file = "nvidia_nccl_cu12-2.26.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:694cf3879a206553cc9d7dbda76b13efaf610fdb70a50cba303de1b0d1530ac6"}, -] - -[[package]] -name = "nvidia-nccl-cu12" -version = "2.27.5" -description = "NVIDIA Collective Communication Library (NCCL) Runtime" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31432ad4d1fb1004eb0c56203dc9bc2178a1ba69d1d9e02d64a6938ab5e40e7a"}, - {file = "nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457"}, -] - -[[package]] -name = "nvidia-nvjitlink-cu12" -version = "12.6.85" -description = "Nvidia JIT LTO Library" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:eedc36df9e88b682efe4309aa16b5b4e78c2407eac59e8c10a6a47535164369a"}, - {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cf4eaa7d4b6b543ffd69d6abfb11efdeb2db48270d94dfd3a452c24150829e41"}, - {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-win_amd64.whl", hash = "sha256:e61120e52ed675747825cdd16febc6a0730537451d867ee58bee3853b1b13d1c"}, -] - -[[package]] -name = "nvidia-nvjitlink-cu12" -version = "12.8.93" -description = "Nvidia JIT LTO Library" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88"}, - {file = "nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7"}, - {file = "nvidia_nvjitlink_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:bd93fbeeee850917903583587f4fc3a4eafa022e34572251368238ab5e6bd67f"}, -] - -[[package]] -name = "nvidia-nvshmem-cu12" -version = "3.3.20" -description = "NVSHMEM creates a global address space that provides efficient and scalable communication for NVIDIA GPU clusters." -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b0b960da3842212758e4fa4696b94f129090b30e5122fea3c5345916545cff0"}, - {file = "nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5"}, -] - -[[package]] -name = "nvidia-nvtx-cu12" -version = "12.6.77" -description = "NVIDIA Tools Extension" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f44f8d86bb7d5629988d61c8d3ae61dddb2015dee142740536bc7481b022fe4b"}, - {file = "nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:adcaabb9d436c9761fca2b13959a2d237c5f9fd406c8e4b723c695409ff88059"}, - {file = "nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b90bed3df379fa79afbd21be8e04a0314336b8ae16768b58f2d34cb1d04cd7d2"}, - {file = "nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6574241a3ec5fdc9334353ab8c479fe75841dbe8f4532a8fc97ce63503330ba1"}, - {file = "nvidia_nvtx_cu12-12.6.77-py3-none-win_amd64.whl", hash = "sha256:2fb11a4af04a5e6c84073e6404d26588a34afd35379f0855a99797897efa75c0"}, -] - -[[package]] -name = "nvidia-nvtx-cu12" -version = "12.8.90" -description = "NVIDIA Tools Extension" -optional = false -python-versions = ">=3" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615"}, - {file = "nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f"}, - {file = "nvidia_nvtx_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:619c8304aedc69f02ea82dd244541a83c3d9d40993381b3b590f1adaed3db41e"}, -] - -[[package]] -name = "openpyxl" -version = "3.1.5" -description = "A Python library to read/write Excel 2010 xlsx/xlsm files" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2"}, - {file = "openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050"}, -] - -[package.dependencies] -et-xmlfile = "*" - -[[package]] -name = "orjson" -version = "3.11.4" -description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a69ab657a4e6733133a3dca82768f2f8b884043714e8d2b9ba9f52b6efef5c44"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3740bffd9816fc0326ddc406098a3a8f387e42223f5f455f2a02a9f834ead80c"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65fd2f5730b1bf7f350c6dc896173d3460d235c4be007af73986d7cd9a2acd23"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fdc3ae730541086158d549c97852e2eea6820665d4faf0f41bf99df41bc11ea"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e10b4d65901da88845516ce9f7f9736f9638d19a1d483b3883dc0182e6e5edba"}, - {file = "orjson-3.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6a03a678085f64b97f9d4a9ae69376ce91a3a9e9b56a82b1580d8e1d501aff"}, - {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c82e4f0b1c712477317434761fbc28b044c838b6b1240d895607441412371ac"}, - {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d58c166a18f44cc9e2bad03a327dc2d1a3d2e85b847133cfbafd6bfc6719bd79"}, - {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94f206766bf1ea30e1382e4890f763bd1eefddc580e08fec1ccdc20ddd95c827"}, - {file = "orjson-3.11.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:41bf25fb39a34cf8edb4398818523277ee7096689db352036a9e8437f2f3ee6b"}, - {file = "orjson-3.11.4-cp310-cp310-win32.whl", hash = "sha256:fa9627eba4e82f99ca6d29bc967f09aba446ee2b5a1ea728949ede73d313f5d3"}, - {file = "orjson-3.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:23ef7abc7fca96632d8174ac115e668c1e931b8fe4dde586e92a500bf1914dcc"}, - {file = "orjson-3.11.4-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e59d23cd93ada23ec59a96f215139753fbfe3a4d989549bcb390f8c00370b39"}, - {file = "orjson-3.11.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5c3aedecfc1beb988c27c79d52ebefab93b6c3921dbec361167e6559aba2d36d"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9e5301f1c2caa2a9a4a303480d79c9ad73560b2e7761de742ab39fe59d9175"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8873812c164a90a79f65368f8f96817e59e35d0cc02786a5356f0e2abed78040"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d7feb0741ebb15204e748f26c9638e6665a5fa93c37a2c73d64f1669b0ddc63"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ee5487fefee21e6910da4c2ee9eef005bee568a0879834df86f888d2ffbdd9"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d40d46f348c0321df01507f92b95a377240c4ec31985225a6668f10e2676f9a"}, - {file = "orjson-3.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95713e5fc8af84d8edc75b785d2386f653b63d62b16d681687746734b4dfc0be"}, - {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad73ede24f9083614d6c4ca9a85fe70e33be7bf047ec586ee2363bc7418fe4d7"}, - {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:842289889de515421f3f224ef9c1f1efb199a32d76d8d2ca2706fa8afe749549"}, - {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3b2427ed5791619851c52a1261b45c233930977e7de8cf36de05636c708fa905"}, - {file = "orjson-3.11.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c36e524af1d29982e9b190573677ea02781456b2e537d5840e4538a5ec41907"}, - {file = "orjson-3.11.4-cp311-cp311-win32.whl", hash = "sha256:87255b88756eab4a68ec61837ca754e5d10fa8bc47dc57f75cedfeaec358d54c"}, - {file = "orjson-3.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:e2d5d5d798aba9a0e1fede8d853fa899ce2cb930ec0857365f700dffc2c7af6a"}, - {file = "orjson-3.11.4-cp311-cp311-win_arm64.whl", hash = "sha256:6bb6bb41b14c95d4f2702bce9975fda4516f1db48e500102fc4d8119032ff045"}, - {file = "orjson-3.11.4-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d4371de39319d05d3f482f372720b841c841b52f5385bd99c61ed69d55d9ab50"}, - {file = "orjson-3.11.4-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:e41fd3b3cac850eaae78232f37325ed7d7436e11c471246b87b2cd294ec94853"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:600e0e9ca042878c7fdf189cf1b028fe2c1418cc9195f6cb9824eb6ed99cb938"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7bbf9b333f1568ef5da42bc96e18bf30fd7f8d54e9ae066d711056add508e415"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4806363144bb6e7297b8e95870e78d30a649fdc4e23fc84daa80c8ebd366ce44"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad355e8308493f527d41154e9053b86a5be892b3b359a5c6d5d95cda23601cb2"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a7517482667fb9f0ff1b2f16fe5829296ed7a655d04d68cd9711a4d8a4e708"}, - {file = "orjson-3.11.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97eb5942c7395a171cbfecc4ef6701fc3c403e762194683772df4c54cfbb2210"}, - {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:149d95d5e018bdd822e3f38c103b1a7c91f88d38a88aada5c4e9b3a73a244241"}, - {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:624f3951181eb46fc47dea3d221554e98784c823e7069edb5dbd0dc826ac909b"}, - {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:03bfa548cf35e3f8b3a96c4e8e41f753c686ff3d8e182ce275b1751deddab58c"}, - {file = "orjson-3.11.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:525021896afef44a68148f6ed8a8bf8375553d6066c7f48537657f64823565b9"}, - {file = "orjson-3.11.4-cp312-cp312-win32.whl", hash = "sha256:b58430396687ce0f7d9eeb3dd47761ca7d8fda8e9eb92b3077a7a353a75efefa"}, - {file = "orjson-3.11.4-cp312-cp312-win_amd64.whl", hash = "sha256:c6dbf422894e1e3c80a177133c0dda260f81428f9de16d61041949f6a2e5c140"}, - {file = "orjson-3.11.4-cp312-cp312-win_arm64.whl", hash = "sha256:d38d2bc06d6415852224fcc9c0bfa834c25431e466dc319f0edd56cca81aa96e"}, - {file = "orjson-3.11.4-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2d6737d0e616a6e053c8b4acc9eccea6b6cce078533666f32d140e4f85002534"}, - {file = "orjson-3.11.4-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:afb14052690aa328cc118a8e09f07c651d301a72e44920b887c519b313d892ff"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38aa9e65c591febb1b0aed8da4d469eba239d434c218562df179885c94e1a3ad"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f2cf4dfaf9163b0728d061bebc1e08631875c51cd30bf47cb9e3293bfbd7dcd5"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89216ff3dfdde0e4070932e126320a1752c9d9a758d6a32ec54b3b9334991a6a"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9daa26ca8e97fae0ce8aa5d80606ef8f7914e9b129b6b5df9104266f764ce436"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c8b2769dc31883c44a9cd126560327767f848eb95f99c36c9932f51090bfce9"}, - {file = "orjson-3.11.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1469d254b9884f984026bd9b0fa5bbab477a4bfe558bba6848086f6d43eb5e73"}, - {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:68e44722541983614e37117209a194e8c3ad07838ccb3127d96863c95ec7f1e0"}, - {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8e7805fda9672c12be2f22ae124dcd7b03928d6c197544fe12174b86553f3196"}, - {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:04b69c14615fb4434ab867bf6f38b2d649f6f300af30a6705397e895f7aec67a"}, - {file = "orjson-3.11.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:639c3735b8ae7f970066930e58cf0ed39a852d417c24acd4a25fc0b3da3c39a6"}, - {file = "orjson-3.11.4-cp313-cp313-win32.whl", hash = "sha256:6c13879c0d2964335491463302a6ca5ad98105fc5db3565499dcb80b1b4bd839"}, - {file = "orjson-3.11.4-cp313-cp313-win_amd64.whl", hash = "sha256:09bf242a4af98732db9f9a1ec57ca2604848e16f132e3f72edfd3c5c96de009a"}, - {file = "orjson-3.11.4-cp313-cp313-win_arm64.whl", hash = "sha256:a85f0adf63319d6c1ba06fb0dbf997fced64a01179cf17939a6caca662bf92de"}, - {file = "orjson-3.11.4-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:42d43a1f552be1a112af0b21c10a5f553983c2a0938d2bbb8ecd8bc9fb572803"}, - {file = "orjson-3.11.4-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:26a20f3fbc6c7ff2cb8e89c4c5897762c9d88cf37330c6a117312365d6781d54"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e3f20be9048941c7ffa8fc523ccbd17f82e24df1549d1d1fe9317712d19938e"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aac364c758dc87a52e68e349924d7e4ded348dedff553889e4d9f22f74785316"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5c54a6d76e3d741dcc3f2707f8eeb9ba2a791d3adbf18f900219b62942803b1"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f28485bdca8617b79d44627f5fb04336897041dfd9fa66d383a49d09d86798bc"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bfc2a484cad3585e4ba61985a6062a4c2ed5c7925db6d39f1fa267c9d166487f"}, - {file = "orjson-3.11.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e34dbd508cb91c54f9c9788923daca129fe5b55c5b4eebe713bf5ed3791280cf"}, - {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b13c478fa413d4b4ee606ec8e11c3b2e52683a640b006bb586b3041c2ca5f606"}, - {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:724ca721ecc8a831b319dcd72cfa370cc380db0bf94537f08f7edd0a7d4e1780"}, - {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:977c393f2e44845ce1b540e19a786e9643221b3323dae190668a98672d43fb23"}, - {file = "orjson-3.11.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e539e382cf46edec157ad66b0b0872a90d829a6b71f17cb633d6c160a223155"}, - {file = "orjson-3.11.4-cp314-cp314-win32.whl", hash = "sha256:d63076d625babab9db5e7836118bdfa086e60f37d8a174194ae720161eb12394"}, - {file = "orjson-3.11.4-cp314-cp314-win_amd64.whl", hash = "sha256:0a54d6635fa3aaa438ae32e8570b9f0de36f3f6562c308d2a2a452e8b0592db1"}, - {file = "orjson-3.11.4-cp314-cp314-win_arm64.whl", hash = "sha256:78b999999039db3cf58f6d230f524f04f75f129ba3d1ca2ed121f8657e575d3d"}, - {file = "orjson-3.11.4-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:405261b0a8c62bcbd8e2931c26fdc08714faf7025f45531541e2b29e544b545b"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af02ff34059ee9199a3546f123a6ab4c86caf1708c79042caf0820dc290a6d4f"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b2eba969ea4203c177c7b38b36c69519e6067ee68c34dc37081fac74c796e10"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0baa0ea43cfa5b008a28d3c07705cf3ada40e5d347f0f44994a64b1b7b4b5350"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80fd082f5dcc0e94657c144f1b2a3a6479c44ad50be216cf0c244e567f5eae19"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e3704d35e47d5bee811fb1cbd8599f0b4009b14d451c4c57be5a7e25eb89a13"}, - {file = "orjson-3.11.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:caa447f2b5356779d914658519c874cf3b7629e99e63391ed519c28c8aea4919"}, - {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bba5118143373a86f91dadb8df41d9457498226698ebdf8e11cbb54d5b0e802d"}, - {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:622463ab81d19ef3e06868b576551587de8e4d518892d1afab71e0fbc1f9cffc"}, - {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3e0a700c4b82144b72946b6629968df9762552ee1344bfdb767fecdd634fbd5a"}, - {file = "orjson-3.11.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6e18a5c15e764e5f3fc569b47872450b4bcea24f2a6354c0a0e95ad21045d5a9"}, - {file = "orjson-3.11.4-cp39-cp39-win32.whl", hash = "sha256:fb1c37c71cad991ef4d89c7a634b5ffb4447dbd7ae3ae13e8f5ee7f1775e7ab1"}, - {file = "orjson-3.11.4-cp39-cp39-win_amd64.whl", hash = "sha256:e2985ce8b8c42d00492d0ed79f2bd2b6460d00f2fa671dfde4bf2e02f49bf5c6"}, - {file = "orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d"}, -] - -[[package]] -name = "packaging" -version = "24.2" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev", "test"] -files = [ - {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, - {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, -] - -[[package]] -name = "pandas" -version = "2.3.3" -description = "Powerful data structures for data analysis, time series, and statistics" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c"}, - {file = "pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a"}, - {file = "pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1"}, - {file = "pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838"}, - {file = "pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250"}, - {file = "pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4"}, - {file = "pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826"}, - {file = "pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523"}, - {file = "pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45"}, - {file = "pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66"}, - {file = "pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b"}, - {file = "pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791"}, - {file = "pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151"}, - {file = "pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c"}, - {file = "pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53"}, - {file = "pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35"}, - {file = "pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908"}, - {file = "pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89"}, - {file = "pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98"}, - {file = "pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084"}, - {file = "pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b"}, - {file = "pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713"}, - {file = "pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8"}, - {file = "pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d"}, - {file = "pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac"}, - {file = "pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c"}, - {file = "pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493"}, - {file = "pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee"}, - {file = "pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5"}, - {file = "pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21"}, - {file = "pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78"}, - {file = "pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110"}, - {file = "pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86"}, - {file = "pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc"}, - {file = "pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0"}, - {file = "pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593"}, - {file = "pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c"}, - {file = "pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b"}, - {file = "pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6"}, - {file = "pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3"}, - {file = "pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5"}, - {file = "pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec"}, - {file = "pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7"}, - {file = "pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450"}, - {file = "pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5"}, - {file = "pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788"}, - {file = "pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87"}, - {file = "pandas-2.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c503ba5216814e295f40711470446bc3fd00f0faea8a086cbc688808e26f92a2"}, - {file = "pandas-2.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a637c5cdfa04b6d6e2ecedcb81fc52ffb0fd78ce2ebccc9ea964df9f658de8c8"}, - {file = "pandas-2.3.3-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:854d00d556406bffe66a4c0802f334c9ad5a96b4f1f868adf036a21b11ef13ff"}, - {file = "pandas-2.3.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf1f8a81d04ca90e32a0aceb819d34dbd378a98bf923b6398b9a3ec0bf44de29"}, - {file = "pandas-2.3.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:23ebd657a4d38268c7dfbdf089fbc31ea709d82e4923c5ffd4fbd5747133ce73"}, - {file = "pandas-2.3.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5554c929ccc317d41a5e3d1234f3be588248e61f08a74dd17c9eabb535777dc9"}, - {file = "pandas-2.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:d3e28b3e83862ccf4d85ff19cf8c20b2ae7e503881711ff2d534dc8f761131aa"}, - {file = "pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b"}, -] - -[package.dependencies] -numpy = {version = ">=1.26.0", markers = "python_version >= \"3.12\""} -python-dateutil = ">=2.8.2" -pytz = ">=2020.1" -tzdata = ">=2022.7" - -[package.extras] -all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] -aws = ["s3fs (>=2022.11.0)"] -clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] -compression = ["zstandard (>=0.19.0)"] -computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] -consortium-standard = ["dataframe-api-compat (>=0.1.7)"] -excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] -feather = ["pyarrow (>=10.0.1)"] -fss = ["fsspec (>=2022.11.0)"] -gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] -hdf5 = ["tables (>=3.8.0)"] -html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] -mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] -output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] -parquet = ["pyarrow (>=10.0.1)"] -performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] -plot = ["matplotlib (>=3.6.3)"] -postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] -pyarrow = ["pyarrow (>=10.0.1)"] -spss = ["pyreadstat (>=1.2.0)"] -sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] -test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] -xml = ["lxml (>=4.9.2)"] - -[[package]] -name = "pandocfilters" -version = "1.5.1" -description = "Utilities for writing pandoc filters in python" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -groups = ["dev"] -files = [ - {file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"}, - {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"}, -] - -[[package]] -name = "parso" -version = "0.8.5" -description = "A Python Parser" -optional = false -python-versions = ">=3.6" -groups = ["dev"] -files = [ - {file = "parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887"}, - {file = "parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a"}, -] - -[package.extras] -qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["docopt", "pytest"] - -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - -[[package]] -name = "pexpect" -version = "4.9.0" -description = "Pexpect allows easy control of interactive console applications." -optional = false -python-versions = "*" -groups = ["dev"] -markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" -files = [ - {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, - {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, -] - -[package.dependencies] -ptyprocess = ">=0.5" - -[[package]] -name = "pillow" -version = "11.3.0" -description = "Python Imaging Library (Fork)" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"}, - {file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"}, - {file = "pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0"}, - {file = "pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b"}, - {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50"}, - {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae"}, - {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9"}, - {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e"}, - {file = "pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6"}, - {file = "pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f"}, - {file = "pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f"}, - {file = "pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722"}, - {file = "pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288"}, - {file = "pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d"}, - {file = "pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494"}, - {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58"}, - {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f"}, - {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e"}, - {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94"}, - {file = "pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0"}, - {file = "pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac"}, - {file = "pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd"}, - {file = "pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4"}, - {file = "pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69"}, - {file = "pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d"}, - {file = "pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6"}, - {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7"}, - {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024"}, - {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809"}, - {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d"}, - {file = "pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149"}, - {file = "pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d"}, - {file = "pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542"}, - {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd"}, - {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8"}, - {file = "pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f"}, - {file = "pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c"}, - {file = "pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd"}, - {file = "pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e"}, - {file = "pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1"}, - {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805"}, - {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8"}, - {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2"}, - {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b"}, - {file = "pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3"}, - {file = "pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"}, - {file = "pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580"}, - {file = "pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e"}, - {file = "pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d"}, - {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced"}, - {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c"}, - {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8"}, - {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59"}, - {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe"}, - {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c"}, - {file = "pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788"}, - {file = "pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31"}, - {file = "pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e"}, - {file = "pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12"}, - {file = "pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a"}, - {file = "pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632"}, - {file = "pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673"}, - {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027"}, - {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77"}, - {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874"}, - {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a"}, - {file = "pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214"}, - {file = "pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635"}, - {file = "pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6"}, - {file = "pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae"}, - {file = "pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653"}, - {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6"}, - {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36"}, - {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b"}, - {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477"}, - {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50"}, - {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b"}, - {file = "pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12"}, - {file = "pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db"}, - {file = "pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa"}, - {file = "pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f"}, - {file = "pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081"}, - {file = "pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4"}, - {file = "pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc"}, - {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06"}, - {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a"}, - {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978"}, - {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d"}, - {file = "pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71"}, - {file = "pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada"}, - {file = "pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb"}, - {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967"}, - {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe"}, - {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c"}, - {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25"}, - {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27"}, - {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a"}, - {file = "pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f"}, - {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6"}, - {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438"}, - {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3"}, - {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c"}, - {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361"}, - {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7"}, - {file = "pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8"}, - {file = "pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523"}, -] - -[package.extras] -docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] -fpx = ["olefile"] -mic = ["olefile"] -test-arrow = ["pyarrow"] -tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"] -typing = ["typing-extensions ; python_version < \"3.10\""] -xmp = ["defusedxml"] - -[[package]] -name = "platformdirs" -version = "4.5.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3"}, - {file = "platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312"}, -] - -[package.extras] -docs = ["furo (>=2025.9.25)", "proselint (>=0.14)", "sphinx (>=8.2.3)", "sphinx-autodoc-typehints (>=3.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.4.2)", "pytest-cov (>=7)", "pytest-mock (>=3.15.1)"] -type = ["mypy (>=1.18.2)"] - -[[package]] -name = "pluggy" -version = "1.6.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.9" -groups = ["main", "test"] -files = [ - {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, - {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["coverage", "pytest", "pytest-benchmark"] - -[[package]] -name = "prometheus-client" -version = "0.23.1" -description = "Python client for the Prometheus monitoring system." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99"}, - {file = "prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce"}, -] - -[package.extras] -twisted = ["twisted"] - -[[package]] -name = "prompt-toolkit" -version = "3.0.52" -description = "Library for building powerful interactive command lines in Python" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955"}, - {file = "prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855"}, -] - -[package.dependencies] -wcwidth = "*" - -[[package]] -name = "propcache" -version = "0.4.1" -description = "Accelerated property cache" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db"}, - {file = "propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8"}, - {file = "propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925"}, - {file = "propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21"}, - {file = "propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5"}, - {file = "propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db"}, - {file = "propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7"}, - {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4"}, - {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60"}, - {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f"}, - {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900"}, - {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c"}, - {file = "propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb"}, - {file = "propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37"}, - {file = "propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581"}, - {file = "propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf"}, - {file = "propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5"}, - {file = "propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e"}, - {file = "propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566"}, - {file = "propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165"}, - {file = "propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc"}, - {file = "propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48"}, - {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570"}, - {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85"}, - {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e"}, - {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757"}, - {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f"}, - {file = "propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1"}, - {file = "propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6"}, - {file = "propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239"}, - {file = "propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2"}, - {file = "propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403"}, - {file = "propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207"}, - {file = "propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72"}, - {file = "propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367"}, - {file = "propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4"}, - {file = "propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf"}, - {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3"}, - {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778"}, - {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6"}, - {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9"}, - {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75"}, - {file = "propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8"}, - {file = "propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db"}, - {file = "propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1"}, - {file = "propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf"}, - {file = "propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311"}, - {file = "propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74"}, - {file = "propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe"}, - {file = "propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af"}, - {file = "propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c"}, - {file = "propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f"}, - {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1"}, - {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24"}, - {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa"}, - {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61"}, - {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66"}, - {file = "propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81"}, - {file = "propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e"}, - {file = "propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1"}, - {file = "propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b"}, - {file = "propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566"}, - {file = "propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835"}, - {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e"}, - {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859"}, - {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b"}, - {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0"}, - {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af"}, - {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393"}, - {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874"}, - {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7"}, - {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1"}, - {file = "propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717"}, - {file = "propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37"}, - {file = "propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a"}, - {file = "propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12"}, - {file = "propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c"}, - {file = "propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded"}, - {file = "propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641"}, - {file = "propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4"}, - {file = "propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44"}, - {file = "propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d"}, - {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b"}, - {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e"}, - {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f"}, - {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49"}, - {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144"}, - {file = "propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f"}, - {file = "propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153"}, - {file = "propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992"}, - {file = "propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f"}, - {file = "propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393"}, - {file = "propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0"}, - {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a"}, - {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be"}, - {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc"}, - {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a"}, - {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89"}, - {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726"}, - {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367"}, - {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36"}, - {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455"}, - {file = "propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85"}, - {file = "propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1"}, - {file = "propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9"}, - {file = "propcache-0.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d233076ccf9e450c8b3bc6720af226b898ef5d051a2d145f7d765e6e9f9bcff"}, - {file = "propcache-0.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:357f5bb5c377a82e105e44bd3d52ba22b616f7b9773714bff93573988ef0a5fb"}, - {file = "propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cbc3b6dfc728105b2a57c06791eb07a94229202ea75c59db644d7d496b698cac"}, - {file = "propcache-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:182b51b421f0501952d938dc0b0eb45246a5b5153c50d42b495ad5fb7517c888"}, - {file = "propcache-0.4.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b536b39c5199b96fc6245eb5fb796c497381d3942f169e44e8e392b29c9ebcc"}, - {file = "propcache-0.4.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db65d2af507bbfbdcedb254a11149f894169d90488dd3e7190f7cdcb2d6cd57a"}, - {file = "propcache-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd2dbc472da1f772a4dae4fa24be938a6c544671a912e30529984dd80400cd88"}, - {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:daede9cd44e0f8bdd9e6cc9a607fc81feb80fae7a5fc6cecaff0e0bb32e42d00"}, - {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:71b749281b816793678ae7f3d0d84bd36e694953822eaad408d682efc5ca18e0"}, - {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:0002004213ee1f36cfb3f9a42b5066100c44276b9b72b4e1504cddd3d692e86e"}, - {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fe49d0a85038f36ba9e3ffafa1103e61170b28e95b16622e11be0a0ea07c6781"}, - {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99d43339c83aaf4d32bda60928231848eee470c6bda8d02599cc4cebe872d183"}, - {file = "propcache-0.4.1-cp39-cp39-win32.whl", hash = "sha256:a129e76735bc792794d5177069691c3217898b9f5cee2b2661471e52ffe13f19"}, - {file = "propcache-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:948dab269721ae9a87fd16c514a0a2c2a1bdb23a9a61b969b0f9d9ee2968546f"}, - {file = "propcache-0.4.1-cp39-cp39-win_arm64.whl", hash = "sha256:5fd37c406dd6dc85aa743e214cef35dc54bbdd1419baac4f6ae5e5b1a2976938"}, - {file = "propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237"}, - {file = "propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d"}, -] - -[[package]] -name = "psutil" -version = "6.1.1" -description = "Cross-platform lib for process and system monitoring in Python." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -groups = ["main", "dev"] -files = [ - {file = "psutil-6.1.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9ccc4316f24409159897799b83004cb1e24f9819b0dcf9c0b68bdcb6cefee6a8"}, - {file = "psutil-6.1.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ca9609c77ea3b8481ab005da74ed894035936223422dc591d6772b147421f777"}, - {file = "psutil-6.1.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8df0178ba8a9e5bc84fed9cfa61d54601b371fbec5c8eebad27575f1e105c0d4"}, - {file = "psutil-6.1.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:1924e659d6c19c647e763e78670a05dbb7feaf44a0e9c94bf9e14dfc6ba50468"}, - {file = "psutil-6.1.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:018aeae2af92d943fdf1da6b58665124897cfc94faa2ca92098838f83e1b1bca"}, - {file = "psutil-6.1.1-cp27-none-win32.whl", hash = "sha256:6d4281f5bbca041e2292be3380ec56a9413b790579b8e593b1784499d0005dac"}, - {file = "psutil-6.1.1-cp27-none-win_amd64.whl", hash = "sha256:c777eb75bb33c47377c9af68f30e9f11bc78e0f07fbf907be4a5d70b2fe5f030"}, - {file = "psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8"}, - {file = "psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377"}, - {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003"}, - {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160"}, - {file = "psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3"}, - {file = "psutil-6.1.1-cp36-cp36m-win32.whl", hash = "sha256:384636b1a64b47814437d1173be1427a7c83681b17a450bfc309a1953e329603"}, - {file = "psutil-6.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8be07491f6ebe1a693f17d4f11e69d0dc1811fa082736500f649f79df7735303"}, - {file = "psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53"}, - {file = "psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649"}, - {file = "psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5"}, -] - -[package.extras] -dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"] -test = ["pytest", "pytest-xdist", "setuptools"] - -[[package]] -name = "ptyprocess" -version = "0.7.0" -description = "Run a subprocess in a pseudo terminal" -optional = false -python-versions = "*" -groups = ["dev"] -markers = "os_name != \"nt\" or sys_platform != \"win32\" and sys_platform != \"emscripten\"" -files = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, -] - -[[package]] -name = "pure-eval" -version = "0.2.3" -description = "Safely evaluate AST nodes without side effects" -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, - {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, -] - -[package.extras] -tests = ["pytest"] - -[[package]] -name = "pycparser" -version = "2.23" -description = "C parser in Python" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -markers = "implementation_name != \"PyPy\"" -files = [ - {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, - {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, -] - -[[package]] -name = "pydantic" -version = "2.12.3" -description = "Data validation using Python type hints" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "pydantic-2.12.3-py3-none-any.whl", hash = "sha256:6986454a854bc3bc6e5443e1369e06a3a456af9d339eda45510f517d9ea5c6bf"}, - {file = "pydantic-2.12.3.tar.gz", hash = "sha256:1da1c82b0fc140bb0103bc1441ffe062154c8d38491189751ee00fd8ca65ce74"}, -] - -[package.dependencies] -annotated-types = ">=0.6.0" -pydantic-core = "2.41.4" -typing-extensions = ">=4.14.1" -typing-inspection = ">=0.4.2" - -[package.extras] -email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] - -[[package]] -name = "pydantic-core" -version = "2.41.4" -description = "Core functionality for Pydantic validation and serialization" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "pydantic_core-2.41.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2442d9a4d38f3411f22eb9dd0912b7cbf4b7d5b6c92c4173b75d3e1ccd84e36e"}, - {file = "pydantic_core-2.41.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:30a9876226dda131a741afeab2702e2d127209bde3c65a2b8133f428bc5d006b"}, - {file = "pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d55bbac04711e2980645af68b97d445cdbcce70e5216de444a6c4b6943ebcccd"}, - {file = "pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e1d778fb7849a42d0ee5927ab0f7453bf9f85eef8887a546ec87db5ddb178945"}, - {file = "pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b65077a4693a98b90ec5ad8f203ad65802a1b9b6d4a7e48066925a7e1606706"}, - {file = "pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62637c769dee16eddb7686bf421be48dfc2fae93832c25e25bc7242e698361ba"}, - {file = "pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfe3aa529c8f501babf6e502936b9e8d4698502b2cfab41e17a028d91b1ac7b"}, - {file = "pydantic_core-2.41.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca2322da745bf2eeb581fc9ea3bbb31147702163ccbcbf12a3bb630e4bf05e1d"}, - {file = "pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e8cd3577c796be7231dcf80badcf2e0835a46665eaafd8ace124d886bab4d700"}, - {file = "pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:1cae8851e174c83633f0833e90636832857297900133705ee158cf79d40f03e6"}, - {file = "pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a26d950449aae348afe1ac8be5525a00ae4235309b729ad4d3399623125b43c9"}, - {file = "pydantic_core-2.41.4-cp310-cp310-win32.whl", hash = "sha256:0cf2a1f599efe57fa0051312774280ee0f650e11152325e41dfd3018ef2c1b57"}, - {file = "pydantic_core-2.41.4-cp310-cp310-win_amd64.whl", hash = "sha256:a8c2e340d7e454dc3340d3d2e8f23558ebe78c98aa8f68851b04dcb7bc37abdc"}, - {file = "pydantic_core-2.41.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:28ff11666443a1a8cf2a044d6a545ebffa8382b5f7973f22c36109205e65dc80"}, - {file = "pydantic_core-2.41.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:61760c3925d4633290292bad462e0f737b840508b4f722247d8729684f6539ae"}, - {file = "pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eae547b7315d055b0de2ec3965643b0ab82ad0106a7ffd29615ee9f266a02827"}, - {file = "pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef9ee5471edd58d1fcce1c80ffc8783a650e3e3a193fe90d52e43bb4d87bff1f"}, - {file = "pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15dd504af121caaf2c95cb90c0ebf71603c53de98305621b94da0f967e572def"}, - {file = "pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a926768ea49a8af4d36abd6a8968b8790f7f76dd7cbd5a4c180db2b4ac9a3a2"}, - {file = "pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916b9b7d134bff5440098a4deb80e4cb623e68974a87883299de9124126c2a8"}, - {file = "pydantic_core-2.41.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5cf90535979089df02e6f17ffd076f07237efa55b7343d98760bde8743c4b265"}, - {file = "pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7533c76fa647fade2d7ec75ac5cc079ab3f34879626dae5689b27790a6cf5a5c"}, - {file = "pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:37e516bca9264cbf29612539801ca3cd5d1be465f940417b002905e6ed79d38a"}, - {file = "pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0c19cb355224037c83642429b8ce261ae108e1c5fbf5c028bac63c77b0f8646e"}, - {file = "pydantic_core-2.41.4-cp311-cp311-win32.whl", hash = "sha256:09c2a60e55b357284b5f31f5ab275ba9f7f70b7525e18a132ec1f9160b4f1f03"}, - {file = "pydantic_core-2.41.4-cp311-cp311-win_amd64.whl", hash = "sha256:711156b6afb5cb1cb7c14a2cc2c4a8b4c717b69046f13c6b332d8a0a8f41ca3e"}, - {file = "pydantic_core-2.41.4-cp311-cp311-win_arm64.whl", hash = "sha256:6cb9cf7e761f4f8a8589a45e49ed3c0d92d1d696a45a6feaee8c904b26efc2db"}, - {file = "pydantic_core-2.41.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ab06d77e053d660a6faaf04894446df7b0a7e7aba70c2797465a0a1af00fc887"}, - {file = "pydantic_core-2.41.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c53ff33e603a9c1179a9364b0a24694f183717b2e0da2b5ad43c316c956901b2"}, - {file = "pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:304c54176af2c143bd181d82e77c15c41cbacea8872a2225dd37e6544dce9999"}, - {file = "pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:025ba34a4cf4fb32f917d5d188ab5e702223d3ba603be4d8aca2f82bede432a4"}, - {file = "pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9f5f30c402ed58f90c70e12eff65547d3ab74685ffe8283c719e6bead8ef53f"}, - {file = "pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd96e5d15385d301733113bcaa324c8bcf111275b7675a9c6e88bfb19fc05e3b"}, - {file = "pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98f348cbb44fae6e9653c1055db7e29de67ea6a9ca03a5fa2c2e11a47cff0e47"}, - {file = "pydantic_core-2.41.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec22626a2d14620a83ca583c6f5a4080fa3155282718b6055c2ea48d3ef35970"}, - {file = "pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3a95d4590b1f1a43bf33ca6d647b990a88f4a3824a8c4572c708f0b45a5290ed"}, - {file = "pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:f9672ab4d398e1b602feadcffcdd3af44d5f5e6ddc15bc7d15d376d47e8e19f8"}, - {file = "pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:84d8854db5f55fead3b579f04bda9a36461dab0730c5d570e1526483e7bb8431"}, - {file = "pydantic_core-2.41.4-cp312-cp312-win32.whl", hash = "sha256:9be1c01adb2ecc4e464392c36d17f97e9110fbbc906bcbe1c943b5b87a74aabd"}, - {file = "pydantic_core-2.41.4-cp312-cp312-win_amd64.whl", hash = "sha256:d682cf1d22bab22a5be08539dca3d1593488a99998f9f412137bc323179067ff"}, - {file = "pydantic_core-2.41.4-cp312-cp312-win_arm64.whl", hash = "sha256:833eebfd75a26d17470b58768c1834dfc90141b7afc6eb0429c21fc5a21dcfb8"}, - {file = "pydantic_core-2.41.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:85e050ad9e5f6fe1004eec65c914332e52f429bc0ae12d6fa2092407a462c746"}, - {file = "pydantic_core-2.41.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7393f1d64792763a48924ba31d1e44c2cfbc05e3b1c2c9abb4ceeadd912cced"}, - {file = "pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94dab0940b0d1fb28bcab847adf887c66a27a40291eedf0b473be58761c9799a"}, - {file = "pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:de7c42f897e689ee6f9e93c4bec72b99ae3b32a2ade1c7e4798e690ff5246e02"}, - {file = "pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:664b3199193262277b8b3cd1e754fb07f2c6023289c815a1e1e8fb415cb247b1"}, - {file = "pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d95b253b88f7d308b1c0b417c4624f44553ba4762816f94e6986819b9c273fb2"}, - {file = "pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1351f5bbdbbabc689727cb91649a00cb9ee7203e0a6e54e9f5ba9e22e384b84"}, - {file = "pydantic_core-2.41.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1affa4798520b148d7182da0615d648e752de4ab1a9566b7471bc803d88a062d"}, - {file = "pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7b74e18052fea4aa8dea2fb7dbc23d15439695da6cbe6cfc1b694af1115df09d"}, - {file = "pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:285b643d75c0e30abda9dc1077395624f314a37e3c09ca402d4015ef5979f1a2"}, - {file = "pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:f52679ff4218d713b3b33f88c89ccbf3a5c2c12ba665fb80ccc4192b4608dbab"}, - {file = "pydantic_core-2.41.4-cp313-cp313-win32.whl", hash = "sha256:ecde6dedd6fff127c273c76821bb754d793be1024bc33314a120f83a3c69460c"}, - {file = "pydantic_core-2.41.4-cp313-cp313-win_amd64.whl", hash = "sha256:d081a1f3800f05409ed868ebb2d74ac39dd0c1ff6c035b5162356d76030736d4"}, - {file = "pydantic_core-2.41.4-cp313-cp313-win_arm64.whl", hash = "sha256:f8e49c9c364a7edcbe2a310f12733aad95b022495ef2a8d653f645e5d20c1564"}, - {file = "pydantic_core-2.41.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ed97fd56a561f5eb5706cebe94f1ad7c13b84d98312a05546f2ad036bafe87f4"}, - {file = "pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a870c307bf1ee91fc58a9a61338ff780d01bfae45922624816878dce784095d2"}, - {file = "pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d25e97bc1f5f8f7985bdc2335ef9e73843bb561eb1fa6831fdfc295c1c2061cf"}, - {file = "pydantic_core-2.41.4-cp313-cp313t-win_amd64.whl", hash = "sha256:d405d14bea042f166512add3091c1af40437c2e7f86988f3915fabd27b1e9cd2"}, - {file = "pydantic_core-2.41.4-cp313-cp313t-win_arm64.whl", hash = "sha256:19f3684868309db5263a11bace3c45d93f6f24afa2ffe75a647583df22a2ff89"}, - {file = "pydantic_core-2.41.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:e9205d97ed08a82ebb9a307e92914bb30e18cdf6f6b12ca4bedadb1588a0bfe1"}, - {file = "pydantic_core-2.41.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:82df1f432b37d832709fbcc0e24394bba04a01b6ecf1ee87578145c19cde12ac"}, - {file = "pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3b4cc4539e055cfa39a3763c939f9d409eb40e85813257dcd761985a108554"}, - {file = "pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1eb1754fce47c63d2ff57fdb88c351a6c0150995890088b33767a10218eaa4e"}, - {file = "pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6ab5ab30ef325b443f379ddb575a34969c333004fca5a1daa0133a6ffaad616"}, - {file = "pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:31a41030b1d9ca497634092b46481b937ff9397a86f9f51bd41c4767b6fc04af"}, - {file = "pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a44ac1738591472c3d020f61c6df1e4015180d6262ebd39bf2aeb52571b60f12"}, - {file = "pydantic_core-2.41.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d72f2b5e6e82ab8f94ea7d0d42f83c487dc159c5240d8f83beae684472864e2d"}, - {file = "pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c4d1e854aaf044487d31143f541f7aafe7b482ae72a022c664b2de2e466ed0ad"}, - {file = "pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b568af94267729d76e6ee5ececda4e283d07bbb28e8148bb17adad93d025d25a"}, - {file = "pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6d55fb8b1e8929b341cc313a81a26e0d48aa3b519c1dbaadec3a6a2b4fcad025"}, - {file = "pydantic_core-2.41.4-cp314-cp314-win32.whl", hash = "sha256:5b66584e549e2e32a1398df11da2e0a7eff45d5c2d9db9d5667c5e6ac764d77e"}, - {file = "pydantic_core-2.41.4-cp314-cp314-win_amd64.whl", hash = "sha256:557a0aab88664cc552285316809cab897716a372afaf8efdbef756f8b890e894"}, - {file = "pydantic_core-2.41.4-cp314-cp314-win_arm64.whl", hash = "sha256:3f1ea6f48a045745d0d9f325989d8abd3f1eaf47dd00485912d1a3a63c623a8d"}, - {file = "pydantic_core-2.41.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6c1fe4c5404c448b13188dd8bd2ebc2bdd7e6727fa61ff481bcc2cca894018da"}, - {file = "pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:523e7da4d43b113bf8e7b49fa4ec0c35bf4fe66b2230bfc5c13cc498f12c6c3e"}, - {file = "pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5729225de81fb65b70fdb1907fcf08c75d498f4a6f15af005aabb1fdadc19dfa"}, - {file = "pydantic_core-2.41.4-cp314-cp314t-win_amd64.whl", hash = "sha256:de2cfbb09e88f0f795fd90cf955858fc2c691df65b1f21f0aa00b99f3fbc661d"}, - {file = "pydantic_core-2.41.4-cp314-cp314t-win_arm64.whl", hash = "sha256:d34f950ae05a83e0ede899c595f312ca976023ea1db100cd5aa188f7005e3ab0"}, - {file = "pydantic_core-2.41.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:646e76293345954acea6966149683047b7b2ace793011922208c8e9da12b0062"}, - {file = "pydantic_core-2.41.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cc8e85a63085a137d286e2791037f5fdfff0aabb8b899483ca9c496dd5797338"}, - {file = "pydantic_core-2.41.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:692c622c8f859a17c156492783902d8370ac7e121a611bd6fe92cc71acf9ee8d"}, - {file = "pydantic_core-2.41.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1e2906efb1031a532600679b424ef1d95d9f9fb507f813951f23320903adbd7"}, - {file = "pydantic_core-2.41.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04e2f7f8916ad3ddd417a7abdd295276a0bf216993d9318a5d61cc058209166"}, - {file = "pydantic_core-2.41.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df649916b81822543d1c8e0e1d079235f68acdc7d270c911e8425045a8cfc57e"}, - {file = "pydantic_core-2.41.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66c529f862fdba70558061bb936fe00ddbaaa0c647fd26e4a4356ef1d6561891"}, - {file = "pydantic_core-2.41.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3b4c5a1fd3a311563ed866c2c9b62da06cb6398bee186484ce95c820db71cb"}, - {file = "pydantic_core-2.41.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6e0fc40d84448f941df9b3334c4b78fe42f36e3bf631ad54c3047a0cdddc2514"}, - {file = "pydantic_core-2.41.4-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:44e7625332683b6c1c8b980461475cde9595eff94447500e80716db89b0da005"}, - {file = "pydantic_core-2.41.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:170ee6835f6c71081d031ef1c3b4dc4a12b9efa6a9540f93f95b82f3c7571ae8"}, - {file = "pydantic_core-2.41.4-cp39-cp39-win32.whl", hash = "sha256:3adf61415efa6ce977041ba9745183c0e1f637ca849773afa93833e04b163feb"}, - {file = "pydantic_core-2.41.4-cp39-cp39-win_amd64.whl", hash = "sha256:a238dd3feee263eeaeb7dc44aea4ba1364682c4f9f9467e6af5596ba322c2332"}, - {file = "pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:a1b2cfec3879afb742a7b0bcfa53e4f22ba96571c9e54d6a3afe1052d17d843b"}, - {file = "pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:d175600d975b7c244af6eb9c9041f10059f20b8bbffec9e33fdd5ee3f67cdc42"}, - {file = "pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f184d657fa4947ae5ec9c47bd7e917730fa1cbb78195037e32dcbab50aca5ee"}, - {file = "pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed810568aeffed3edc78910af32af911c835cc39ebbfacd1f0ab5dd53028e5c"}, - {file = "pydantic_core-2.41.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:4f5d640aeebb438517150fdeec097739614421900e4a08db4a3ef38898798537"}, - {file = "pydantic_core-2.41.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:4a9ab037b71927babc6d9e7fc01aea9e66dc2a4a34dff06ef0724a4049629f94"}, - {file = "pydantic_core-2.41.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4dab9484ec605c3016df9ad4fd4f9a390bc5d816a3b10c6550f8424bb80b18c"}, - {file = "pydantic_core-2.41.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8a5028425820731d8c6c098ab642d7b8b999758e24acae03ed38a66eca8335"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1e5ab4fc177dd41536b3c32b2ea11380dd3d4619a385860621478ac2d25ceb00"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:3d88d0054d3fa11ce936184896bed3c1c5441d6fa483b498fac6a5d0dd6f64a9"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b2a054a8725f05b4b6503357e0ac1c4e8234ad3b0c2ac130d6ffc66f0e170e2"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0d9db5a161c99375a0c68c058e227bee1d89303300802601d76a3d01f74e258"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:6273ea2c8ffdac7b7fda2653c49682db815aebf4a89243a6feccf5e36c18c347"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:4c973add636efc61de22530b2ef83a65f39b6d6f656df97f678720e20de26caa"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b69d1973354758007f46cf2d44a4f3d0933f10b6dc9bf15cf1356e037f6f731a"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3619320641fd212aaf5997b6ca505e97540b7e16418f4a241f44cdf108ffb50d"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:491535d45cd7ad7e4a2af4a5169b0d07bebf1adfd164b0368da8aa41e19907a5"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:54d86c0cada6aba4ec4c047d0e348cbad7063b87ae0f005d9f8c9ad04d4a92a2"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca1124aced216b2500dc2609eade086d718e8249cb9696660ab447d50a758bd"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c9024169becccf0cb470ada03ee578d7348c119a0d42af3dcf9eda96e3a247c"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:26895a4268ae5a2849269f4991cdc97236e4b9c010e51137becf25182daac405"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:ca4df25762cf71308c446e33c9b1fdca2923a3f13de616e2a949f38bf21ff5a8"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5a28fcedd762349519276c36634e71853b4541079cab4acaaac60c4421827308"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c173ddcd86afd2535e2b695217e82191580663a1d1928239f877f5a1649ef39f"}, - {file = "pydantic_core-2.41.4.tar.gz", hash = "sha256:70e47929a9d4a1905a67e4b687d5946026390568a8e952b92824118063cee4d5"}, -] - -[package.dependencies] -typing-extensions = ">=4.14.1" - -[[package]] -name = "pydantic-settings" -version = "2.11.0" -description = "Settings management using Pydantic" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "pydantic_settings-2.11.0-py3-none-any.whl", hash = "sha256:fe2cea3413b9530d10f3a5875adffb17ada5c1e1bab0b2885546d7310415207c"}, - {file = "pydantic_settings-2.11.0.tar.gz", hash = "sha256:d0e87a1c7d33593beb7194adb8470fc426e95ba02af83a0f23474a04c9a08180"}, -] - -[package.dependencies] -pydantic = ">=2.7.0" -python-dotenv = ">=0.21.0" -typing-inspection = ">=0.4.0" - -[package.extras] -aws-secrets-manager = ["boto3 (>=1.35.0)", "boto3-stubs[secretsmanager]"] -azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"] -gcp-secret-manager = ["google-cloud-secret-manager (>=2.23.1)"] -toml = ["tomli (>=2.0.1)"] -yaml = ["pyyaml (>=6.0.1)"] - -[[package]] -name = "pygments" -version = "2.19.2" -description = "Pygments is a syntax highlighting package written in Python." -optional = false -python-versions = ">=3.8" -groups = ["main", "dev", "test"] -files = [ - {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, - {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, -] - -[package.extras] -windows-terminal = ["colorama (>=0.4.6)"] - -[[package]] -name = "pymupdf" -version = "1.26.5" -description = "A high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents." -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "pymupdf-1.26.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2bfb58f07ad631e5f71ad0bd6f1ff52700f7ba7ebb4973130e81e75b721beae1"}, - {file = "pymupdf-1.26.5-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:d58599479bc471d3ae56c3d68d9160d0b7de8a3bd40221ddc3a4eaae2d281b86"}, - {file = "pymupdf-1.26.5-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7dfea81fdd73437a6a6ce83e1fcf556faee9327a6540571e58bf04fa362bb0cd"}, - {file = "pymupdf-1.26.5-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:caad0ffeb63dcc4a29ca40f3c68d7b78d32a932e834b0056b529cc0bdbaaffc9"}, - {file = "pymupdf-1.26.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e24e7a7d696bd398543cc5c147869edb2026d5d5a21b7f8e35db2f20170b389e"}, - {file = "pymupdf-1.26.5-cp39-abi3-win32.whl", hash = "sha256:a2a42f5911d153a47bf5c3e162a0bfe8745eb9bec3e59fbaf87617b4003d8270"}, - {file = "pymupdf-1.26.5-cp39-abi3-win_amd64.whl", hash = "sha256:39a6fb58182b27b51ea8150a0cd2e4ee7e0cf71e9d6723978f28699b42ee61ae"}, - {file = "pymupdf-1.26.5.tar.gz", hash = "sha256:8ef335e07f648492df240f2247854d0e7c0467afb9c4dc2376ec30978ec158c3"}, -] - -[[package]] -name = "pytest" -version = "8.4.2" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.9" -groups = ["main", "test"] -files = [ - {file = "pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79"}, - {file = "pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01"}, -] - -[package.dependencies] -colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} -iniconfig = ">=1" -packaging = ">=20" -pluggy = ">=1.5,<2" -pygments = ">=2.7.2" - -[package.extras] -dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "pytest-cov" -version = "6.3.0" -description = "Pytest plugin for measuring coverage." -optional = false -python-versions = ">=3.9" -groups = ["test"] -files = [ - {file = "pytest_cov-6.3.0-py3-none-any.whl", hash = "sha256:440db28156d2468cafc0415b4f8e50856a0d11faefa38f30906048fe490f1749"}, - {file = "pytest_cov-6.3.0.tar.gz", hash = "sha256:35c580e7800f87ce892e687461166e1ac2bcb8fb9e13aea79032518d6e503ff2"}, -] - -[package.dependencies] -coverage = {version = ">=7.5", extras = ["toml"]} -pluggy = ">=1.2" -pytest = ">=6.2.5" - -[package.extras] -testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] - -[[package]] -name = "pytest-mock" -version = "3.15.1" -description = "Thin-wrapper around the mock package for easier use with pytest" -optional = false -python-versions = ">=3.9" -groups = ["main", "test"] -files = [ - {file = "pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d"}, - {file = "pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f"}, -] - -[package.dependencies] -pytest = ">=6.2.5" - -[package.extras] -dev = ["pre-commit", "pytest-asyncio", "tox"] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main", "dev"] -files = [ - {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "python-dotenv" -version = "1.2.1" -description = "Read key-value pairs from a .env file and set them as environment variables" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61"}, - {file = "python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6"}, -] - -[package.extras] -cli = ["click (>=5.0)"] - -[[package]] -name = "python-json-logger" -version = "4.0.0" -description = "JSON Log Formatter for the Python Logging Package" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2"}, - {file = "python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f"}, -] - -[package.extras] -dev = ["backports.zoneinfo ; python_version < \"3.9\"", "black", "build", "freezegun", "mdx_truly_sane_lists", "mike", "mkdocs", "mkdocs-awesome-pages-plugin", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-material (>=8.5)", "mkdocstrings[python]", "msgspec ; implementation_name != \"pypy\"", "mypy", "orjson ; implementation_name != \"pypy\"", "pylint", "pytest", "tzdata", "validate-pyproject[all]"] - -[[package]] -name = "pytz" -version = "2025.2" -description = "World timezone definitions, modern and historical" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"}, - {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, -] - -[[package]] -name = "pywinpty" -version = "3.0.2" -description = "Pseudo terminal support for Windows from Python." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -markers = "os_name == \"nt\"" -files = [ - {file = "pywinpty-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:65db57fd3387d71e8372b6a54269cbcd0f6dfa6d4616a29e0af749ec19f5c558"}, - {file = "pywinpty-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:327790d70e4c841ebd9d0f295a780177149aeb405bca44c7115a3de5c2054b23"}, - {file = "pywinpty-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:99fdd9b455f0ad6419aba6731a7a0d2f88ced83c3c94a80ff9533d95fa8d8a9e"}, - {file = "pywinpty-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:18f78b81e4cfee6aabe7ea8688441d30247b73e52cd9657138015c5f4ee13a51"}, - {file = "pywinpty-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:663383ecfab7fc382cc97ea5c4f7f0bb32c2f889259855df6ea34e5df42d305b"}, - {file = "pywinpty-3.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:28297cecc37bee9f24d8889e47231972d6e9e84f7b668909de54f36ca785029a"}, - {file = "pywinpty-3.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:34b55ae9a1b671fe3eae071d86618110538e8eaad18fcb1531c0830b91a82767"}, - {file = "pywinpty-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:3962daf801bc38dd4de872108c424b5338c9a46c6efca5761854cd66370a9022"}, - {file = "pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004"}, -] - -[[package]] -name = "pyxlsb" -version = "1.0.10" -description = "Excel 2007-2010 Binary Workbook (xlsb) parser" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "pyxlsb-1.0.10-py2.py3-none-any.whl", hash = "sha256:87c122a9a622e35ca5e741d2e541201d28af00fb46bec492cfa9586890b120b4"}, - {file = "pyxlsb-1.0.10.tar.gz", hash = "sha256:8062d1ea8626d3f1980e8b1cfe91a4483747449242ecb61013bc2df85435f685"}, -] - -[[package]] -name = "pyyaml" -version = "6.0.3" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, - {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, - {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, - {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, - {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, - {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, - {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, - {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, - {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, - {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, - {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, - {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, - {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, - {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, - {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, - {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, - {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, - {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, - {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, - {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, - {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, - {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, - {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, - {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, - {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, - {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, - {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, - {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, - {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, - {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, - {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, - {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, - {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, - {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, - {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, - {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, - {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, - {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, - {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, - {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, - {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, - {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, - {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, - {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, - {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, - {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, - {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, - {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, - {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, - {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, - {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, - {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, - {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, - {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, - {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, - {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, - {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, - {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, - {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, - {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, - {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, - {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, - {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, - {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, - {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, - {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, - {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, - {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, - {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, - {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, - {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, - {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, - {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, -] - -[[package]] -name = "pyzmq" -version = "27.1.0" -description = "Python bindings for 0MQ" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4"}, - {file = "pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556"}, - {file = "pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b"}, - {file = "pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e"}, - {file = "pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526"}, - {file = "pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1"}, - {file = "pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386"}, - {file = "pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda"}, - {file = "pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f"}, - {file = "pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32"}, - {file = "pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86"}, - {file = "pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581"}, - {file = "pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f"}, - {file = "pyzmq-27.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e"}, - {file = "pyzmq-27.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e"}, - {file = "pyzmq-27.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2"}, - {file = "pyzmq-27.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394"}, - {file = "pyzmq-27.1.0-cp311-cp311-win32.whl", hash = "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f"}, - {file = "pyzmq-27.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97"}, - {file = "pyzmq-27.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07"}, - {file = "pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc"}, - {file = "pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113"}, - {file = "pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233"}, - {file = "pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31"}, - {file = "pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28"}, - {file = "pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856"}, - {file = "pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496"}, - {file = "pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd"}, - {file = "pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf"}, - {file = "pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f"}, - {file = "pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5"}, - {file = "pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6"}, - {file = "pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7"}, - {file = "pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05"}, - {file = "pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9"}, - {file = "pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128"}, - {file = "pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39"}, - {file = "pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97"}, - {file = "pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db"}, - {file = "pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c"}, - {file = "pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2"}, - {file = "pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e"}, - {file = "pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a"}, - {file = "pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea"}, - {file = "pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96"}, - {file = "pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d"}, - {file = "pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146"}, - {file = "pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd"}, - {file = "pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a"}, - {file = "pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92"}, - {file = "pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0"}, - {file = "pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7"}, - {file = "pyzmq-27.1.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:18339186c0ed0ce5835f2656cdfb32203125917711af64da64dbaa3d949e5a1b"}, - {file = "pyzmq-27.1.0-cp38-cp38-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:753d56fba8f70962cd8295fb3edb40b9b16deaa882dd2b5a3a2039f9ff7625aa"}, - {file = "pyzmq-27.1.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b721c05d932e5ad9ff9344f708c96b9e1a485418c6618d765fca95d4daacfbef"}, - {file = "pyzmq-27.1.0-cp38-cp38-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be883ff3d722e6085ee3f4afc057a50f7f2e0c72d289fd54df5706b4e3d3a50"}, - {file = "pyzmq-27.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:b2e592db3a93128daf567de9650a2f3859017b3f7a66bc4ed6e4779d6034976f"}, - {file = "pyzmq-27.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad68808a61cbfbbae7ba26d6233f2a4aa3b221de379ce9ee468aa7a83b9c36b0"}, - {file = "pyzmq-27.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:e2687c2d230e8d8584fbea433c24382edfeda0c60627aca3446aa5e58d5d1831"}, - {file = "pyzmq-27.1.0-cp38-cp38-win32.whl", hash = "sha256:a1aa0ee920fb3825d6c825ae3f6c508403b905b698b6460408ebd5bb04bbb312"}, - {file = "pyzmq-27.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:df7cd397ece96cf20a76fae705d40efbab217d217897a5053267cd88a700c266"}, - {file = "pyzmq-27.1.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:96c71c32fff75957db6ae33cd961439f386505c6e6b377370af9b24a1ef9eafb"}, - {file = "pyzmq-27.1.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:49d3980544447f6bd2968b6ac913ab963a49dcaa2d4a2990041f16057b04c429"}, - {file = "pyzmq-27.1.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:849ca054d81aa1c175c49484afaaa5db0622092b5eccb2055f9f3bb8f703782d"}, - {file = "pyzmq-27.1.0-cp39-cp39-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3970778e74cb7f85934d2b926b9900e92bfe597e62267d7499acc39c9c28e345"}, - {file = "pyzmq-27.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:da96ecdcf7d3919c3be2de91a8c513c186f6762aa6cf7c01087ed74fad7f0968"}, - {file = "pyzmq-27.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9541c444cfe1b1c0156c5c86ece2bb926c7079a18e7b47b0b1b3b1b875e5d098"}, - {file = "pyzmq-27.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e30a74a39b93e2e1591b58eb1acef4902be27c957a8720b0e368f579b82dc22f"}, - {file = "pyzmq-27.1.0-cp39-cp39-win32.whl", hash = "sha256:b1267823d72d1e40701dcba7edc45fd17f71be1285557b7fe668887150a14b78"}, - {file = "pyzmq-27.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0c996ded912812a2fcd7ab6574f4ad3edc27cb6510349431e4930d4196ade7db"}, - {file = "pyzmq-27.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:346e9ba4198177a07e7706050f35d733e08c1c1f8ceacd5eb6389d653579ffbc"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74"}, - {file = "pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271"}, - {file = "pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:50081a4e98472ba9f5a02850014b4c9b629da6710f8f14f3b15897c666a28f1b"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:510869f9df36ab97f89f4cff9d002a89ac554c7ac9cadd87d444aa4cf66abd27"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1f8426a01b1c4098a750973c37131cf585f61c7911d735f729935a0c701b68d3"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:726b6a502f2e34c6d2ada5e702929586d3ac948a4dbbb7fed9854ec8c0466027"}, - {file = "pyzmq-27.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:bd67e7c8f4654bef471c0b1ca6614af0b5202a790723a58b79d9584dc8022a78"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:722ea791aa233ac0a819fc2c475e1292c76930b31f1d828cb61073e2fe5e208f"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:01f9437501886d3a1dd4b02ef59fb8cc384fa718ce066d52f175ee49dd5b7ed8"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4a19387a3dddcc762bfd2f570d14e2395b2c9701329b266f83dd87a2b3cbd381"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c618fbcd069e3a29dcd221739cacde52edcc681f041907867e0f5cc7e85f172"}, - {file = "pyzmq-27.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ff8d114d14ac671d88c89b9224c63d6c4e5a613fe8acd5594ce53d752a3aafe9"}, - {file = "pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540"}, -] - -[package.dependencies] -cffi = {version = "*", markers = "implementation_name == \"pypy\""} - -[[package]] -name = "rank-bm25" -version = "0.2.2" -description = "Various BM25 algorithms for document ranking" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "rank_bm25-0.2.2-py3-none-any.whl", hash = "sha256:7bd4a95571adadfc271746fa146a4bcfd89c0cf731e49c3d1ad863290adbe8ae"}, - {file = "rank_bm25-0.2.2.tar.gz", hash = "sha256:096ccef76f8188563419aaf384a02f0ea459503fdf77901378d4fd9d87e5e51d"}, -] - -[package.dependencies] -numpy = "*" - -[package.extras] -dev = ["pytest"] - -[[package]] -name = "rapidfuzz" -version = "3.14.2" -description = "rapid fuzzy string matching" -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "rapidfuzz-3.14.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:37ddc4cc3eafe29ec8ba451fcec5244af441eeb53b4e7b4d1d886cd3ff3624f4"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:654be63b17f3da8414968dfdf15c46c8205960ec8508cbb9d837347bf036dc0b"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75866e9fa474ccfe6b77367fb7c10e6f9754fb910d9b110490a6fad25501a039"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd915693a8d441e5f277bef23065275a2bb492724b5ccf64e38e60edd702b0fb"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e702e76a6166bff466a33888902404209fffd83740d24918ef74514542f66367"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78f84592f3a2f2773d6f411b755d683b1ce7f05adff4c12c0de923d5f2786e51"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:36d43c9f1b88322ad05b22fa80b6b4a95d2b193d392d3aa7bee652c144cfb1d9"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:69d6f93916717314209f4e8701d203876baeadf8c9dcaee961b8afeba7435643"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e262958d3ca723c1ce32030384a1626e3d43ba7465e01a3e2b633f4300956150"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:26b5e6e0d39337431ab1b36faf604873cb1f0de9280e0703f61c6753c8fa1f7f"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2aad09712e1ffbc00ac25f12646c7065b84496af7cd0a70b1d5aff6318405732"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f10dbbafa3decee704b7a02ffe7914d7dfbbd3d1fce7f37ed2c3d6c3a7c9a8e6"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-win32.whl", hash = "sha256:6c3dab8f9d4271e32c8746461a58412871ebb07654f77aa6121961e796482d30"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-win_amd64.whl", hash = "sha256:5386ce287e5b71db4fd71747a23ae0ca5053012dc959049e160857c5fdadf6cd"}, - {file = "rapidfuzz-3.14.2-cp310-cp310-win_arm64.whl", hash = "sha256:c78d6f205b871f2d41173f82ded66bcef2f692e1b90c0f627cc8035b72898f35"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3969670d4b85e589564d6a75638ec2372a4375b7e68e747f3bd37b507cf843e4"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:061884b23a8c5eea9443e52acf02cbd533aff93a5439b0e90b5586a0638b8720"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6fc2bc48a219c171deb8529bfcc90ca6663fbcaa42b54ef202858976078f858a"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cfa62729ac2d77a50a240b6331e9fffb5e070625e97e8f7e50fa882b3ea396ad"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2d001aaf47a500083b189140df16eaefd675bf06c818a71ae9f687b0d6f804f8"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c95eeaa7f2a990757826aa34e7375b50d49172da5ca7536dc461b1d197e0de9b"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:30af5e015462f89408d7b3bbdd614c739adc386e3d47bd565b53ffb670266021"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:35f12b07d58b932ef95b5f66b40c9efc60c5201bccd3c5ddde4a87df19d0aba8"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:0aa67110e016d2cdce3e5a3330d09fb1dba3cf83350f6eb46a6b9276cbafd094"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b13dc4743a5d222600d98fb4a0345e910829ef4f286e81b34349627355884c87"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:b16c40709f22c8fc16ca49a5484a468fe0a95f08f29c68043f46f8771e2c37e2"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac2bd7c74523f952a66536f72b3f68260427e2a6954f1f03d758f01bbbf60564"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-win32.whl", hash = "sha256:37d7045dc0ab4cab49d7cca66b651b44939e18e098a2f55466082e173b1aa452"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-win_amd64.whl", hash = "sha256:9a55ff35536662028563f22e0eadab47c7e94c8798239fe25d3ceca5ab156fd8"}, - {file = "rapidfuzz-3.14.2-cp311-cp311-win_arm64.whl", hash = "sha256:b2f0e1310f7cb1c0c0033987d0a0e85b4fd51a1c4882f556f082687d519f045d"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0418f6ac1da7adf7e6e469876508f63168e80d3265a9e7ab9a2e999020577bfa"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f6028090b49015fc9ff0df3c06751078fe300a291e933a378a7c37b78c4d6a3e"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21aa299985d1bbdb3ccf8a8214e7daee72bb7e8c8fb25a520f015dc200a57816"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e247612909876f36e6132265deef34efcaaf490e1857022204b206ff76578076"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9cf077475cd4118a5b846a72749d54b520243be6baddba1dd1446f3b1dbab29c"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5e7e02fb51f9a78e32f4fb8b5546d543e1fb637409cb682a6b8cb12e0c3015c"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:b1febabf4a4a664a2b6025830d93d7703f1cd9dcbe656ed7159053091b4d9389"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:766d133f11888c48497f26a1722afc697a5fbad05bbfec3a41a4bc04fd21af9d"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:2a851a7c6660b6e47723378ca7692cd42700660a8783e4e7d07254a984d63ec8"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:686594bd7f7132cb85900a4cc910e9acb9d39466412b8a275f3d4bc37faba23c"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e1d412122de3c5c492acfcde020f543b9b529e2eb115f875e2fd7470e44ab441"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2611b1f6464dddf900bffeee2aa29a9aa1039317cbb226e18d3a5f029d4cf303"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-win32.whl", hash = "sha256:e6968b6db188fbb4c7a18aac25e075940a8204434a2a0d6bddb0a695d7f0c898"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-win_amd64.whl", hash = "sha256:1a6d43683c04ffb4270bb1498951a39e9c200eb326f933fd5d608c19485049b8"}, - {file = "rapidfuzz-3.14.2-cp312-cp312-win_arm64.whl", hash = "sha256:4ecd3ab9aebb17becb462eac19151bd143abc614e3d2a0351a72171371ac3f4b"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f1f5a2566af7409d11f11b0b4e9f76a0ac64577737b821c64a2a6afc971c1c25"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:810863f3a98d09392e5fb481aef9d82597df6ee06f7f11ceafe6077585c4e018"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e8c0d16c0724dab7c7dc4099c1ec410679b2d11c1650b069d15d4ab4370f1cc"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:004f04356d84660feffbf8c26975cb0db0e010b2225d6e21b3d84dd8df764652"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3c2aea6b1db03a8abd62bb157161d7a65b896c9f85d5efc2f1bb444a107c47a"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8bef63704b7851ad1adf5d7ceb7f1b3136b78ee0b34240c14ab85ea775f6caa7"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:52e8e37566313ac60bfa80754c4c0367eec65b3ef52bb8cc409b88e878b03182"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b3fad0fb5ac44944ad8f81e729ec45f65a85efb7d7ea4cf67343799c0ea9874b"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d027842a956b86aa9706b836c48186da405413d03957afaccda2fbe414bc3912"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:27dcb45427b1966fb43c904d19c841c3e6da147931959cf05388ecef9c5a1e8d"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1aab0676884e91282817b5710933efc4ea9466d2ba5703b5a7541468695d807a"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ef36c21ecb7f4bad7e4e119fe746a787ad684eaf1c383c17a2aff5d75b20fa58"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-win32.whl", hash = "sha256:ed3af4fa0dbd6d1964f171ac6fff82ed9e76c737eb34ae3daf926c4aefc2ce9b"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-win_amd64.whl", hash = "sha256:3fc2e7c3ab006299366b1c8256e452f00eb1659d0e4790b140633627c7d947b7"}, - {file = "rapidfuzz-3.14.2-cp313-cp313-win_arm64.whl", hash = "sha256:def48d5010ddcd2a80b44f14bf0172c29bfc27906d13c0ea69a6e3c00e6f225c"}, - {file = "rapidfuzz-3.14.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a39952b8e033758ee15b2de48a5b0689c83ea6bd93c8df3635f2fbf21e52fd25"}, - {file = "rapidfuzz-3.14.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f786811555869b5961b3718b007179e87d73c47414afee5fb882ae1b9b174c0c"}, - {file = "rapidfuzz-3.14.2-cp313-cp313t-win32.whl", hash = "sha256:6c0a25490a99c4b73f1deca3efae004df5f2b254760d98cac8d93becf41260d4"}, - {file = "rapidfuzz-3.14.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e5af2dab8ec5a180d9ff24fbb5b25e589848b93cccb755eceb0bf0e3cfed7e5c"}, - {file = "rapidfuzz-3.14.2-cp313-cp313t-win_arm64.whl", hash = "sha256:8cf2aefb0d246d540ea83b4648db690bd7e25d34a7c23c5f250dcba2e4989192"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ace3a6b108679888833cdceea9a6231e406db202b8336eaf68279fe71a1d2ac4"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32c7cc978447202ba592e197228767b230d85e52e5ef229e2b22e51c8e3d06ad"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a479a824cbf6a646bcec1c34fbbfb85393d03eb2811657e3a6536298d435f76"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a3bc0c8b65dcd1e55a1cc42a7c7b34e93ad5d4bd1501dc998f4625042e1b110"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:217b46bf096818df16c0e2c43202aa8352e67c4379b1d5f25e98c5d1c7f5414d"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:07d3e8afeeb81044873644e505e56ba06d8bdcc291ef7e26ac0f54c58309267d"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:b7832c8707bfa4f9b081def64aa49954d4813cff7fc9ff4a0b184a4e8697147f"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:35581ba6981e016333063c52719c0b0b1bef0f944e641ad0f4ea34e0b39161f3"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:fbd5152169dc3f6c894c24fc04813f50bf9b929d137f2b965ac926e03329ceba"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:98a119c3f9b152e9b62ec43520392669bd8deae9df269f30569f1c87bf6055a4"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9e84164e7a68f9c3523c5d104dda6601202b39bae0aac1b73a4f119d387275c4"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:64c67402b86a073666f92c2807811e3817a17fedfe505fe89a9f93eea264481c"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-win32.whl", hash = "sha256:58d79f4df3e4332b31e671f9487f0c215856cf1f2d9ac3848ac10c27262fd723"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-win_amd64.whl", hash = "sha256:dc6fe7a27ad9e233c155e89b7e1d9b6d13963e3261ea5b30f3e79c3556c49bc9"}, - {file = "rapidfuzz-3.14.2-cp314-cp314-win_arm64.whl", hash = "sha256:bb4e96d80de7e6364850a2e168e899b8e85ab80ce19827cc4fbe0aa3c57f8124"}, - {file = "rapidfuzz-3.14.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c7d4d0927a6b1ef2529a8cc57adf2ce965f7aaef324a4d1ae826d0de43ab4f82"}, - {file = "rapidfuzz-3.14.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c0fae06e7fb4be18e86eb51e77f0d441975a3ba9ef963f957d750a2a41536ba1"}, - {file = "rapidfuzz-3.14.2-cp314-cp314t-win32.whl", hash = "sha256:d1d3ef72665d460b7b3e61d3dff4341a195dcb3250b4471eef71db23fca2d91a"}, - {file = "rapidfuzz-3.14.2-cp314-cp314t-win_amd64.whl", hash = "sha256:3a0960c5c11a34e8129a3062f1b1cbb371fad364e2195ebe46a88a9d5eeec0f1"}, - {file = "rapidfuzz-3.14.2-cp314-cp314t-win_arm64.whl", hash = "sha256:ed29600e55d7df104d5778d499678c305e32e3ccfa873489a7c8304489c5f8f3"}, - {file = "rapidfuzz-3.14.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:172630396d8bdbb5ea1a58e82afc489c8e18076e1f2b2edea20cb30f8926325a"}, - {file = "rapidfuzz-3.14.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:6cff0d6749fac8dd7fdf26d0604d8a47c5ee786061972077d71ec7ac0fb7ced2"}, - {file = "rapidfuzz-3.14.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f558bc2ee3a0bb5d7238ed10a0b76455f2d28c97e93564a1f7855cea4096ef1c"}, - {file = "rapidfuzz-3.14.2.tar.gz", hash = "sha256:69bf91e66aeb84a104aea35e1b3f6b3aa606faaee6db1cfc76950f2a6a828a12"}, -] - -[package.extras] -all = ["numpy"] - -[[package]] -name = "referencing" -version = "0.37.0" -description = "JSON Referencing + Python" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231"}, - {file = "referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8"}, -] - -[package.dependencies] -attrs = ">=22.2.0" -rpds-py = ">=0.7.0" -typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""} - -[[package]] -name = "regex" -version = "2025.10.23" -description = "Alternative regular expression module, to replace re." -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "regex-2025.10.23-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:17bbcde374bef1c5fad9b131f0e28a6a24856dd90368d8c0201e2b5a69533daa"}, - {file = "regex-2025.10.23-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b4e10434279cc8567f99ca6e018e9025d14f2fded2a603380b6be2090f476426"}, - {file = "regex-2025.10.23-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c9bb421cbe7012c744a5a56cf4d6c80829c72edb1a2991677299c988d6339c8"}, - {file = "regex-2025.10.23-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:275cd1c2ed8c4a78ebfa489618d7aee762e8b4732da73573c3e38236ec5f65de"}, - {file = "regex-2025.10.23-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7b426ae7952f3dc1e73a86056d520bd4e5f021397484a6835902fc5648bcacce"}, - {file = "regex-2025.10.23-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c5cdaf5b6d37c7da1967dbe729d819461aab6a98a072feef65bbcff0a6e60649"}, - {file = "regex-2025.10.23-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bfeff0b08f296ab28b4332a7e03ca31c437ee78b541ebc874bbf540e5932f8d"}, - {file = "regex-2025.10.23-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f97236a67307b775f30a74ef722b64b38b7ab7ba3bb4a2508518a5de545459c"}, - {file = "regex-2025.10.23-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:be19e7de499940cd72475fb8e46ab2ecb1cf5906bebdd18a89f9329afb1df82f"}, - {file = "regex-2025.10.23-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:883df76ee42d9ecb82b37ff8d01caea5895b3f49630a64d21111078bbf8ef64c"}, - {file = "regex-2025.10.23-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2e9117d1d35fc2addae6281019ecc70dc21c30014b0004f657558b91c6a8f1a7"}, - {file = "regex-2025.10.23-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0ff1307f531a5d8cf5c20ea517254551ff0a8dc722193aab66c656c5a900ea68"}, - {file = "regex-2025.10.23-cp310-cp310-win32.whl", hash = "sha256:7888475787cbfee4a7cd32998eeffe9a28129fa44ae0f691b96cb3939183ef41"}, - {file = "regex-2025.10.23-cp310-cp310-win_amd64.whl", hash = "sha256:ec41a905908496ce4906dab20fb103c814558db1d69afc12c2f384549c17936a"}, - {file = "regex-2025.10.23-cp310-cp310-win_arm64.whl", hash = "sha256:b2b7f19a764d5e966d5a62bf2c28a8b4093cc864c6734510bdb4aeb840aec5e6"}, - {file = "regex-2025.10.23-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6c531155bf9179345e85032052a1e5fe1a696a6abf9cea54b97e8baefff970fd"}, - {file = "regex-2025.10.23-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:912e9df4e89d383681268d38ad8f5780d7cccd94ba0e9aa09ca7ab7ab4f8e7eb"}, - {file = "regex-2025.10.23-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f375c61bfc3138b13e762fe0ae76e3bdca92497816936534a0177201666f44f"}, - {file = "regex-2025.10.23-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e248cc9446081119128ed002a3801f8031e0c219b5d3c64d3cc627da29ac0a33"}, - {file = "regex-2025.10.23-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b52bf9282fdf401e4f4e721f0f61fc4b159b1307244517789702407dd74e38ca"}, - {file = "regex-2025.10.23-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c084889ab2c59765a0d5ac602fd1c3c244f9b3fcc9a65fdc7ba6b74c5287490"}, - {file = "regex-2025.10.23-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d80e8eb79009bdb0936658c44ca06e2fbbca67792013e3818eea3f5f228971c2"}, - {file = "regex-2025.10.23-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6f259118ba87b814a8ec475380aee5f5ae97a75852a3507cf31d055b01b5b40"}, - {file = "regex-2025.10.23-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9b8c72a242683dcc72d37595c4f1278dfd7642b769e46700a8df11eab19dfd82"}, - {file = "regex-2025.10.23-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a8d7b7a0a3df9952f9965342159e0c1f05384c0f056a47ce8b61034f8cecbe83"}, - {file = "regex-2025.10.23-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:413bfea20a484c524858125e92b9ce6ffdd0a4b97d4ff96b5859aa119b0f1bdd"}, - {file = "regex-2025.10.23-cp311-cp311-win32.whl", hash = "sha256:f76deef1f1019a17dad98f408b8f7afc4bd007cbe835ae77b737e8c7f19ae575"}, - {file = "regex-2025.10.23-cp311-cp311-win_amd64.whl", hash = "sha256:59bba9f7125536f23fdab5deeea08da0c287a64c1d3acc1c7e99515809824de8"}, - {file = "regex-2025.10.23-cp311-cp311-win_arm64.whl", hash = "sha256:b103a752b6f1632ca420225718d6ed83f6a6ced3016dd0a4ab9a6825312de566"}, - {file = "regex-2025.10.23-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7a44d9c00f7a0a02d3b777429281376370f3d13d2c75ae74eb94e11ebcf4a7fc"}, - {file = "regex-2025.10.23-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b83601f84fde939ae3478bb32a3aef36f61b58c3208d825c7e8ce1a735f143f2"}, - {file = "regex-2025.10.23-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ec13647907bb9d15fd192bbfe89ff06612e098a5709e7d6ecabbdd8f7908fc45"}, - {file = "regex-2025.10.23-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78d76dd2957d62501084e7012ddafc5fcd406dd982b7a9ca1ea76e8eaaf73e7e"}, - {file = "regex-2025.10.23-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8668e5f067e31a47699ebb354f43aeb9c0ef136f915bd864243098524482ac43"}, - {file = "regex-2025.10.23-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a32433fe3deb4b2d8eda88790d2808fed0dc097e84f5e683b4cd4f42edef6cca"}, - {file = "regex-2025.10.23-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d97d73818c642c938db14c0668167f8d39520ca9d983604575ade3fda193afcc"}, - {file = "regex-2025.10.23-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bca7feecc72ee33579e9f6ddf8babbe473045717a0e7dbc347099530f96e8b9a"}, - {file = "regex-2025.10.23-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7e24af51e907d7457cc4a72691ec458320b9ae67dc492f63209f01eecb09de32"}, - {file = "regex-2025.10.23-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d10bcde58bbdf18146f3a69ec46dd03233b94a4a5632af97aa5378da3a47d288"}, - {file = "regex-2025.10.23-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:44383bc0c933388516c2692c9a7503e1f4a67e982f20b9a29d2fb70c6494f147"}, - {file = "regex-2025.10.23-cp312-cp312-win32.whl", hash = "sha256:6040a86f95438a0114bba16e51dfe27f1bc004fd29fe725f54a586f6d522b079"}, - {file = "regex-2025.10.23-cp312-cp312-win_amd64.whl", hash = "sha256:436b4c4352fe0762e3bfa34a5567079baa2ef22aa9c37cf4d128979ccfcad842"}, - {file = "regex-2025.10.23-cp312-cp312-win_arm64.whl", hash = "sha256:f4b1b1991617055b46aff6f6db24888c1f05f4db9801349d23f09ed0714a9335"}, - {file = "regex-2025.10.23-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:b7690f95404a1293923a296981fd943cca12c31a41af9c21ba3edd06398fc193"}, - {file = "regex-2025.10.23-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1a32d77aeaea58a13230100dd8797ac1a84c457f3af2fdf0d81ea689d5a9105b"}, - {file = "regex-2025.10.23-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b24b29402f264f70a3c81f45974323b41764ff7159655360543b7cabb73e7d2f"}, - {file = "regex-2025.10.23-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:563824a08c7c03d96856d84b46fdb3bbb7cfbdf79da7ef68725cda2ce169c72a"}, - {file = "regex-2025.10.23-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0ec8bdd88d2e2659c3518087ee34b37e20bd169419ffead4240a7004e8ed03b"}, - {file = "regex-2025.10.23-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b577601bfe1d33913fcd9276d7607bbac827c4798d9e14d04bf37d417a6c41cb"}, - {file = "regex-2025.10.23-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c9f2c68ac6cb3de94eea08a437a75eaa2bd33f9e97c84836ca0b610a5804368"}, - {file = "regex-2025.10.23-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:89f8b9ea3830c79468e26b0e21c3585f69f105157c2154a36f6b7839f8afb351"}, - {file = "regex-2025.10.23-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:98fd84c4e4ea185b3bb5bf065261ab45867d8875032f358a435647285c722673"}, - {file = "regex-2025.10.23-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1e11d3e5887b8b096f96b4154dfb902f29c723a9556639586cd140e77e28b313"}, - {file = "regex-2025.10.23-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f13450328a6634348d47a88367e06b64c9d84980ef6a748f717b13f8ce64e87"}, - {file = "regex-2025.10.23-cp313-cp313-win32.whl", hash = "sha256:37be9296598a30c6a20236248cb8b2c07ffd54d095b75d3a2a2ee5babdc51df1"}, - {file = "regex-2025.10.23-cp313-cp313-win_amd64.whl", hash = "sha256:ea7a3c283ce0f06fe789365841e9174ba05f8db16e2fd6ae00a02df9572c04c0"}, - {file = "regex-2025.10.23-cp313-cp313-win_arm64.whl", hash = "sha256:d9a4953575f300a7bab71afa4cd4ac061c7697c89590a2902b536783eeb49a4f"}, - {file = "regex-2025.10.23-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7d6606524fa77b3912c9ef52a42ef63c6cfbfc1077e9dc6296cd5da0da286044"}, - {file = "regex-2025.10.23-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c037aadf4d64bdc38af7db3dbd34877a057ce6524eefcb2914d6d41c56f968cc"}, - {file = "regex-2025.10.23-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:99018c331fb2529084a0c9b4c713dfa49fafb47c7712422e49467c13a636c656"}, - {file = "regex-2025.10.23-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd8aba965604d70306eb90a35528f776e59112a7114a5162824d43b76fa27f58"}, - {file = "regex-2025.10.23-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:238e67264b4013e74136c49f883734f68656adf8257bfa13b515626b31b20f8e"}, - {file = "regex-2025.10.23-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b2eb48bd9848d66fd04826382f5e8491ae633de3233a3d64d58ceb4ecfa2113a"}, - {file = "regex-2025.10.23-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d36591ce06d047d0c0fe2fc5f14bfbd5b4525d08a7b6a279379085e13f0e3d0e"}, - {file = "regex-2025.10.23-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b5d4ece8628d6e364302006366cea3ee887db397faebacc5dacf8ef19e064cf8"}, - {file = "regex-2025.10.23-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:39a7e8083959cb1c4ff74e483eecb5a65d3b3e1d821b256e54baf61782c906c6"}, - {file = "regex-2025.10.23-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:842d449a8fefe546f311656cf8c0d6729b08c09a185f1cad94c756210286d6a8"}, - {file = "regex-2025.10.23-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d614986dc68506be8f00474f4f6960e03e4ca9883f7df47744800e7d7c08a494"}, - {file = "regex-2025.10.23-cp313-cp313t-win32.whl", hash = "sha256:a5b7a26b51a9df473ec16a1934d117443a775ceb7b39b78670b2e21893c330c9"}, - {file = "regex-2025.10.23-cp313-cp313t-win_amd64.whl", hash = "sha256:ce81c5544a5453f61cb6f548ed358cfb111e3b23f3cd42d250a4077a6be2a7b6"}, - {file = "regex-2025.10.23-cp313-cp313t-win_arm64.whl", hash = "sha256:e9bf7f6699f490e4e43c44757aa179dab24d1960999c84ab5c3d5377714ed473"}, - {file = "regex-2025.10.23-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:5b5cb5b6344c4c4c24b2dc87b0bfee78202b07ef7633385df70da7fcf6f7cec6"}, - {file = "regex-2025.10.23-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a6ce7973384c37bdf0f371a843f95a6e6f4e1489e10e0cf57330198df72959c5"}, - {file = "regex-2025.10.23-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2ee3663f2c334959016b56e3bd0dd187cbc73f948e3a3af14c3caaa0c3035d10"}, - {file = "regex-2025.10.23-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2003cc82a579107e70d013482acce8ba773293f2db534fb532738395c557ff34"}, - {file = "regex-2025.10.23-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:182c452279365a93a9f45874f7f191ec1c51e1f1eb41bf2b16563f1a40c1da3a"}, - {file = "regex-2025.10.23-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b1249e9ff581c5b658c8f0437f883b01f1edcf424a16388591e7c05e5e9e8b0c"}, - {file = "regex-2025.10.23-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b841698f93db3ccc36caa1900d2a3be281d9539b822dc012f08fc80b46a3224"}, - {file = "regex-2025.10.23-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:956d89e0c92d471e8f7eee73f73fdff5ed345886378c45a43175a77538a1ffe4"}, - {file = "regex-2025.10.23-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5c259cb363299a0d90d63b5c0d7568ee98419861618a95ee9d91a41cb9954462"}, - {file = "regex-2025.10.23-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:185d2b18c062820b3a40d8fefa223a83f10b20a674bf6e8c4a432e8dfd844627"}, - {file = "regex-2025.10.23-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:281d87fa790049c2b7c1b4253121edd80b392b19b5a3d28dc2a77579cb2a58ec"}, - {file = "regex-2025.10.23-cp314-cp314-win32.whl", hash = "sha256:63b81eef3656072e4ca87c58084c7a9c2b81d41a300b157be635a8a675aacfb8"}, - {file = "regex-2025.10.23-cp314-cp314-win_amd64.whl", hash = "sha256:0967c5b86f274800a34a4ed862dfab56928144d03cb18821c5153f8777947796"}, - {file = "regex-2025.10.23-cp314-cp314-win_arm64.whl", hash = "sha256:c70dfe58b0a00b36aa04cdb0f798bf3e0adc31747641f69e191109fd8572c9a9"}, - {file = "regex-2025.10.23-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1f5799ea1787aa6de6c150377d11afad39a38afd033f0c5247aecb997978c422"}, - {file = "regex-2025.10.23-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:a9639ab7540cfea45ef57d16dcbea2e22de351998d614c3ad2f9778fa3bdd788"}, - {file = "regex-2025.10.23-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:08f52122c352eb44c3421dab78b9b73a8a77a282cc8314ae576fcaa92b780d10"}, - {file = "regex-2025.10.23-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ebf1baebef1c4088ad5a5623decec6b52950f0e4d7a0ae4d48f0a99f8c9cb7d7"}, - {file = "regex-2025.10.23-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:16b0f1c2e2d566c562d5c384c2b492646be0a19798532fdc1fdedacc66e3223f"}, - {file = "regex-2025.10.23-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7ada5d9dceafaab92646aa00c10a9efd9b09942dd9b0d7c5a4b73db92cc7e61"}, - {file = "regex-2025.10.23-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a36b4005770044bf08edecc798f0e41a75795b9e7c9c12fe29da8d792ef870c"}, - {file = "regex-2025.10.23-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:af7b2661dcc032da1fae82069b5ebf2ac1dfcd5359ef8b35e1367bfc92181432"}, - {file = "regex-2025.10.23-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:1cb976810ac1416a67562c2e5ba0accf6f928932320fef302e08100ed681b38e"}, - {file = "regex-2025.10.23-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:1a56a54be3897d62f54290190fbcd754bff6932934529fbf5b29933da28fcd43"}, - {file = "regex-2025.10.23-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8f3e6d202fb52c2153f532043bbcf618fd177df47b0b306741eb9b60ba96edc3"}, - {file = "regex-2025.10.23-cp314-cp314t-win32.whl", hash = "sha256:1fa1186966b2621b1769fd467c7b22e317e6ba2d2cdcecc42ea3089ef04a8521"}, - {file = "regex-2025.10.23-cp314-cp314t-win_amd64.whl", hash = "sha256:08a15d40ce28362eac3e78e83d75475147869c1ff86bc93285f43b4f4431a741"}, - {file = "regex-2025.10.23-cp314-cp314t-win_arm64.whl", hash = "sha256:a93e97338e1c8ea2649e130dcfbe8cd69bba5e1e163834752ab64dcb4de6d5ed"}, - {file = "regex-2025.10.23-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8d286760ee5b77fd21cf6b33cc45e0bffd1deeda59ca65b9be996f590a9828a"}, - {file = "regex-2025.10.23-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e72e3b84b170fec02193d32620a0a7060a22e52c46e45957dcd14742e0d28fb"}, - {file = "regex-2025.10.23-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ec506e8114fa12d21616deb44800f536d6bf2e1a69253dbf611f69af92395c99"}, - {file = "regex-2025.10.23-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d7e481f9710e8e24228ce2c77b41db7662a3f68853395da86a292b49dadca2aa"}, - {file = "regex-2025.10.23-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4663ff2fc367735ae7b90b4f0e05b25554446df4addafc76fdaacaaa0ba852b5"}, - {file = "regex-2025.10.23-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0879dd3251a42d2e9b938e1e03b1e9f60de90b4d153015193f5077a376a18439"}, - {file = "regex-2025.10.23-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:651c58aecbab7e97bdf8ec76298a28d2bf2b6238c099ec6bf32e6d41e2f9a9cb"}, - {file = "regex-2025.10.23-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ceabc62a0e879169cd1bf066063bd6991c3e41e437628936a2ce66e0e2071c32"}, - {file = "regex-2025.10.23-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bfdf4e9aa3e7b7d02fda97509b4ceeed34542361694ecc0a81db1688373ecfbd"}, - {file = "regex-2025.10.23-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:92f565ff9beb9f51bc7cc8c578a7e92eb5c4576b69043a4c58cd05d73fda83c5"}, - {file = "regex-2025.10.23-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:abbea548b1076eaf8635caf1071c9d86efdf0fa74abe71fca26c05a2d64cda80"}, - {file = "regex-2025.10.23-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:33535dcf34f47821381e341f7b715cbd027deda4223af4d3932adcd371d3192a"}, - {file = "regex-2025.10.23-cp39-cp39-win32.whl", hash = "sha256:345c9df49a15bf6460534b104b336581bc5f35c286cac526416e7a63d389b09b"}, - {file = "regex-2025.10.23-cp39-cp39-win_amd64.whl", hash = "sha256:f668fe1fd3358c5423355a289a4a003e58005ce829d217b828f80bd605a90145"}, - {file = "regex-2025.10.23-cp39-cp39-win_arm64.whl", hash = "sha256:07a3fd25d9074923e4d7258b551ae35ab6bdfe01904b8f0d5341c7d8b20eb18d"}, - {file = "regex-2025.10.23.tar.gz", hash = "sha256:8cbaf8ceb88f96ae2356d01b9adf5e6306fa42fa6f7eab6b97794e37c959ac26"}, -] - -[[package]] -name = "requests" -version = "2.32.5" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, - {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, -] - -[package.dependencies] -certifi = ">=2017.4.17" -charset_normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "requests-toolbelt" -version = "1.0.0" -description = "A utility belt for advanced users of python-requests" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -groups = ["main"] -files = [ - {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, - {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, -] - -[package.dependencies] -requests = ">=2.0.1,<3.0.0" - -[[package]] -name = "rfc3339-validator" -version = "0.1.4" -description = "A pure python RFC3339 validator" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -groups = ["dev"] -files = [ - {file = "rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"}, - {file = "rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b"}, -] - -[package.dependencies] -six = "*" - -[[package]] -name = "rfc3986-validator" -version = "0.1.1" -description = "Pure python rfc3986 validator" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -groups = ["dev"] -files = [ - {file = "rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9"}, - {file = "rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055"}, -] - -[[package]] -name = "rfc3987-syntax" -version = "1.1.0" -description = "Helper functions to syntactically validate strings according to RFC 3987." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f"}, - {file = "rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d"}, -] - -[package.dependencies] -lark = ">=1.2.2" - -[package.extras] -testing = ["pytest (>=8.3.5)"] - -[[package]] -name = "rpds-py" -version = "0.28.0" -description = "Python bindings to Rust's persistent data structures (rpds)" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "rpds_py-0.28.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7b6013db815417eeb56b2d9d7324e64fcd4fa289caeee6e7a78b2e11fc9b438a"}, - {file = "rpds_py-0.28.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a4c6b05c685c0c03f80dabaeb73e74218c49deea965ca63f76a752807397207"}, - {file = "rpds_py-0.28.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4794c6c3fbe8f9ac87699b131a1f26e7b4abcf6d828da46a3a52648c7930eba"}, - {file = "rpds_py-0.28.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2e8456b6ee5527112ff2354dd9087b030e3429e43a74f480d4a5ca79d269fd85"}, - {file = "rpds_py-0.28.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:beb880a9ca0a117415f241f66d56025c02037f7c4efc6fe59b5b8454f1eaa50d"}, - {file = "rpds_py-0.28.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6897bebb118c44b38c9cb62a178e09f1593c949391b9a1a6fe777ccab5934ee7"}, - {file = "rpds_py-0.28.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1b553dd06e875249fd43efd727785efb57a53180e0fde321468222eabbeaafa"}, - {file = "rpds_py-0.28.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:f0b2044fdddeea5b05df832e50d2a06fe61023acb44d76978e1b060206a8a476"}, - {file = "rpds_py-0.28.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05cf1e74900e8da73fa08cc76c74a03345e5a3e37691d07cfe2092d7d8e27b04"}, - {file = "rpds_py-0.28.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:efd489fec7c311dae25e94fe7eeda4b3d06be71c68f2cf2e8ef990ffcd2cd7e8"}, - {file = "rpds_py-0.28.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada7754a10faacd4f26067e62de52d6af93b6d9542f0df73c57b9771eb3ba9c4"}, - {file = "rpds_py-0.28.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c2a34fd26588949e1e7977cfcbb17a9a42c948c100cab890c6d8d823f0586457"}, - {file = "rpds_py-0.28.0-cp310-cp310-win32.whl", hash = "sha256:f9174471d6920cbc5e82a7822de8dfd4dcea86eb828b04fc8c6519a77b0ee51e"}, - {file = "rpds_py-0.28.0-cp310-cp310-win_amd64.whl", hash = "sha256:6e32dd207e2c4f8475257a3540ab8a93eff997abfa0a3fdb287cae0d6cd874b8"}, - {file = "rpds_py-0.28.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:03065002fd2e287725d95fbc69688e0c6daf6c6314ba38bdbaa3895418e09296"}, - {file = "rpds_py-0.28.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28ea02215f262b6d078daec0b45344c89e161eab9526b0d898221d96fdda5f27"}, - {file = "rpds_py-0.28.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25dbade8fbf30bcc551cb352376c0ad64b067e4fc56f90e22ba70c3ce205988c"}, - {file = "rpds_py-0.28.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c03002f54cc855860bfdc3442928ffdca9081e73b5b382ed0b9e8efe6e5e205"}, - {file = "rpds_py-0.28.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9699fa7990368b22032baf2b2dce1f634388e4ffc03dfefaaac79f4695edc95"}, - {file = "rpds_py-0.28.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9b06fe1a75e05e0713f06ea0c89ecb6452210fd60e2f1b6ddc1067b990e08d9"}, - {file = "rpds_py-0.28.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9f83e7b326a3f9ec3ef84cda98fb0a74c7159f33e692032233046e7fd15da2"}, - {file = "rpds_py-0.28.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:0d3259ea9ad8743a75a43eb7819324cdab393263c91be86e2d1901ee65c314e0"}, - {file = "rpds_py-0.28.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a7548b345f66f6695943b4ef6afe33ccd3f1b638bd9afd0f730dd255c249c9e"}, - {file = "rpds_py-0.28.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9a40040aa388b037eb39416710fbcce9443498d2eaab0b9b45ae988b53f5c67"}, - {file = "rpds_py-0.28.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8f60c7ea34e78c199acd0d3cda37a99be2c861dd2b8cf67399784f70c9f8e57d"}, - {file = "rpds_py-0.28.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1571ae4292649100d743b26d5f9c63503bb1fedf538a8f29a98dce2d5ba6b4e6"}, - {file = "rpds_py-0.28.0-cp311-cp311-win32.whl", hash = "sha256:5cfa9af45e7c1140af7321fa0bef25b386ee9faa8928c80dc3a5360971a29e8c"}, - {file = "rpds_py-0.28.0-cp311-cp311-win_amd64.whl", hash = "sha256:dd8d86b5d29d1b74100982424ba53e56033dc47720a6de9ba0259cf81d7cecaa"}, - {file = "rpds_py-0.28.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e27d3a5709cc2b3e013bf93679a849213c79ae0573f9b894b284b55e729e120"}, - {file = "rpds_py-0.28.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6b4f28583a4f247ff60cd7bdda83db8c3f5b05a7a82ff20dd4b078571747708f"}, - {file = "rpds_py-0.28.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d678e91b610c29c4b3d52a2c148b641df2b4676ffe47c59f6388d58b99cdc424"}, - {file = "rpds_py-0.28.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e819e0e37a44a78e1383bf1970076e2ccc4dc8c2bbaa2f9bd1dc987e9afff628"}, - {file = "rpds_py-0.28.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5ee514e0f0523db5d3fb171f397c54875dbbd69760a414dccf9d4d7ad628b5bd"}, - {file = "rpds_py-0.28.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f3fa06d27fdcee47f07a39e02862da0100cb4982508f5ead53ec533cd5fe55e"}, - {file = "rpds_py-0.28.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46959ef2e64f9e4a41fc89aa20dbca2b85531f9a72c21099a3360f35d10b0d5a"}, - {file = "rpds_py-0.28.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8455933b4bcd6e83fde3fefc987a023389c4b13f9a58c8d23e4b3f6d13f78c84"}, - {file = "rpds_py-0.28.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:ad50614a02c8c2962feebe6012b52f9802deec4263946cddea37aaf28dd25a66"}, - {file = "rpds_py-0.28.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e5deca01b271492553fdb6c7fd974659dce736a15bae5dad7ab8b93555bceb28"}, - {file = "rpds_py-0.28.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:735f8495a13159ce6a0d533f01e8674cec0c57038c920495f87dcb20b3ddb48a"}, - {file = "rpds_py-0.28.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:961ca621ff10d198bbe6ba4957decca61aa2a0c56695384c1d6b79bf61436df5"}, - {file = "rpds_py-0.28.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2374e16cc9131022e7d9a8f8d65d261d9ba55048c78f3b6e017971a4f5e6353c"}, - {file = "rpds_py-0.28.0-cp312-cp312-win32.whl", hash = "sha256:d15431e334fba488b081d47f30f091e5d03c18527c325386091f31718952fe08"}, - {file = "rpds_py-0.28.0-cp312-cp312-win_amd64.whl", hash = "sha256:a410542d61fc54710f750d3764380b53bf09e8c4edbf2f9141a82aa774a04f7c"}, - {file = "rpds_py-0.28.0-cp312-cp312-win_arm64.whl", hash = "sha256:1f0cfd1c69e2d14f8c892b893997fa9a60d890a0c8a603e88dca4955f26d1edd"}, - {file = "rpds_py-0.28.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e9e184408a0297086f880556b6168fa927d677716f83d3472ea333b42171ee3b"}, - {file = "rpds_py-0.28.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:edd267266a9b0448f33dc465a97cfc5d467594b600fe28e7fa2f36450e03053a"}, - {file = "rpds_py-0.28.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85beb8b3f45e4e32f6802fb6cd6b17f615ef6c6a52f265371fb916fae02814aa"}, - {file = "rpds_py-0.28.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d2412be8d00a1b895f8ad827cc2116455196e20ed994bb704bf138fe91a42724"}, - {file = "rpds_py-0.28.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf128350d384b777da0e68796afdcebc2e9f63f0e9f242217754e647f6d32491"}, - {file = "rpds_py-0.28.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2036d09b363aa36695d1cc1a97b36865597f4478470b0697b5ee9403f4fe399"}, - {file = "rpds_py-0.28.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8e1e9be4fa6305a16be628959188e4fd5cd6f1b0e724d63c6d8b2a8adf74ea6"}, - {file = "rpds_py-0.28.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0a403460c9dd91a7f23fc3188de6d8977f1d9603a351d5db6cf20aaea95b538d"}, - {file = "rpds_py-0.28.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d7366b6553cdc805abcc512b849a519167db8f5e5c3472010cd1228b224265cb"}, - {file = "rpds_py-0.28.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5b43c6a3726efd50f18d8120ec0551241c38785b68952d240c45ea553912ac41"}, - {file = "rpds_py-0.28.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0cb7203c7bc69d7c1585ebb33a2e6074492d2fc21ad28a7b9d40457ac2a51ab7"}, - {file = "rpds_py-0.28.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a52a5169c664dfb495882adc75c304ae1d50df552fbd68e100fdc719dee4ff9"}, - {file = "rpds_py-0.28.0-cp313-cp313-win32.whl", hash = "sha256:2e42456917b6687215b3e606ab46aa6bca040c77af7df9a08a6dcfe8a4d10ca5"}, - {file = "rpds_py-0.28.0-cp313-cp313-win_amd64.whl", hash = "sha256:e0a0311caedc8069d68fc2bf4c9019b58a2d5ce3cd7cb656c845f1615b577e1e"}, - {file = "rpds_py-0.28.0-cp313-cp313-win_arm64.whl", hash = "sha256:04c1b207ab8b581108801528d59ad80aa83bb170b35b0ddffb29c20e411acdc1"}, - {file = "rpds_py-0.28.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f296ea3054e11fc58ad42e850e8b75c62d9a93a9f981ad04b2e5ae7d2186ff9c"}, - {file = "rpds_py-0.28.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5a7306c19b19005ad98468fcefeb7100b19c79fc23a5f24a12e06d91181193fa"}, - {file = "rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5d9b86aa501fed9862a443c5c3116f6ead8bc9296185f369277c42542bd646b"}, - {file = "rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e5bbc701eff140ba0e872691d573b3d5d30059ea26e5785acba9132d10c8c31d"}, - {file = "rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a5690671cd672a45aa8616d7374fdf334a1b9c04a0cac3c854b1136e92374fe"}, - {file = "rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9f1d92ecea4fa12f978a367c32a5375a1982834649cdb96539dcdc12e609ab1a"}, - {file = "rpds_py-0.28.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d252db6b1a78d0a3928b6190156042d54c93660ce4d98290d7b16b5296fb7cc"}, - {file = "rpds_py-0.28.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d61b355c3275acb825f8777d6c4505f42b5007e357af500939d4a35b19177259"}, - {file = "rpds_py-0.28.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:acbe5e8b1026c0c580d0321c8aae4b0a1e1676861d48d6e8c6586625055b606a"}, - {file = "rpds_py-0.28.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8aa23b6f0fc59b85b4c7d89ba2965af274346f738e8d9fc2455763602e62fd5f"}, - {file = "rpds_py-0.28.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7b14b0c680286958817c22d76fcbca4800ddacef6f678f3a7c79a1fe7067fe37"}, - {file = "rpds_py-0.28.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:bcf1d210dfee61a6c86551d67ee1031899c0fdbae88b2d44a569995d43797712"}, - {file = "rpds_py-0.28.0-cp313-cp313t-win32.whl", hash = "sha256:3aa4dc0fdab4a7029ac63959a3ccf4ed605fee048ba67ce89ca3168da34a1342"}, - {file = "rpds_py-0.28.0-cp313-cp313t-win_amd64.whl", hash = "sha256:7b7d9d83c942855e4fdcfa75d4f96f6b9e272d42fffcb72cd4bb2577db2e2907"}, - {file = "rpds_py-0.28.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:dcdcb890b3ada98a03f9f2bb108489cdc7580176cb73b4f2d789e9a1dac1d472"}, - {file = "rpds_py-0.28.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f274f56a926ba2dc02976ca5b11c32855cbd5925534e57cfe1fda64e04d1add2"}, - {file = "rpds_py-0.28.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fe0438ac4a29a520ea94c8c7f1754cdd8feb1bc490dfda1bfd990072363d527"}, - {file = "rpds_py-0.28.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8a358a32dd3ae50e933347889b6af9a1bdf207ba5d1a3f34e1a38cd3540e6733"}, - {file = "rpds_py-0.28.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e80848a71c78aa328fefaba9c244d588a342c8e03bda518447b624ea64d1ff56"}, - {file = "rpds_py-0.28.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f586db2e209d54fe177e58e0bc4946bea5fb0102f150b1b2f13de03e1f0976f8"}, - {file = "rpds_py-0.28.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ae8ee156d6b586e4292491e885d41483136ab994e719a13458055bec14cf370"}, - {file = "rpds_py-0.28.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:a805e9b3973f7e27f7cab63a6b4f61d90f2e5557cff73b6e97cd5b8540276d3d"}, - {file = "rpds_py-0.28.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5d3fd16b6dc89c73a4da0b4ac8b12a7ecc75b2864b95c9e5afed8003cb50a728"}, - {file = "rpds_py-0.28.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6796079e5d24fdaba6d49bda28e2c47347e89834678f2bc2c1b4fc1489c0fb01"}, - {file = "rpds_py-0.28.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:76500820c2af232435cbe215e3324c75b950a027134e044423f59f5b9a1ba515"}, - {file = "rpds_py-0.28.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bbdc5640900a7dbf9dd707fe6388972f5bbd883633eb68b76591044cfe346f7e"}, - {file = "rpds_py-0.28.0-cp314-cp314-win32.whl", hash = "sha256:adc8aa88486857d2b35d75f0640b949759f79dc105f50aa2c27816b2e0dd749f"}, - {file = "rpds_py-0.28.0-cp314-cp314-win_amd64.whl", hash = "sha256:66e6fa8e075b58946e76a78e69e1a124a21d9a48a5b4766d15ba5b06869d1fa1"}, - {file = "rpds_py-0.28.0-cp314-cp314-win_arm64.whl", hash = "sha256:a6fe887c2c5c59413353b7c0caff25d0e566623501ccfff88957fa438a69377d"}, - {file = "rpds_py-0.28.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7a69df082db13c7070f7b8b1f155fa9e687f1d6aefb7b0e3f7231653b79a067b"}, - {file = "rpds_py-0.28.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b1cde22f2c30ebb049a9e74c5374994157b9b70a16147d332f89c99c5960737a"}, - {file = "rpds_py-0.28.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5338742f6ba7a51012ea470bd4dc600a8c713c0c72adaa0977a1b1f4327d6592"}, - {file = "rpds_py-0.28.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e1460ebde1bcf6d496d80b191d854adedcc619f84ff17dc1c6d550f58c9efbba"}, - {file = "rpds_py-0.28.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e3eb248f2feba84c692579257a043a7699e28a77d86c77b032c1d9fbb3f0219c"}, - {file = "rpds_py-0.28.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3bbba5def70b16cd1c1d7255666aad3b290fbf8d0fe7f9f91abafb73611a91"}, - {file = "rpds_py-0.28.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3114f4db69ac5a1f32e7e4d1cbbe7c8f9cf8217f78e6e002cedf2d54c2a548ed"}, - {file = "rpds_py-0.28.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:4b0cb8a906b1a0196b863d460c0222fb8ad0f34041568da5620f9799b83ccf0b"}, - {file = "rpds_py-0.28.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf681ac76a60b667106141e11a92a3330890257e6f559ca995fbb5265160b56e"}, - {file = "rpds_py-0.28.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1e8ee6413cfc677ce8898d9cde18cc3a60fc2ba756b0dec5b71eb6eb21c49fa1"}, - {file = "rpds_py-0.28.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b3072b16904d0b5572a15eb9d31c1954e0d3227a585fc1351aa9878729099d6c"}, - {file = "rpds_py-0.28.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b670c30fd87a6aec281c3c9896d3bae4b205fd75d79d06dc87c2503717e46092"}, - {file = "rpds_py-0.28.0-cp314-cp314t-win32.whl", hash = "sha256:8014045a15b4d2b3476f0a287fcc93d4f823472d7d1308d47884ecac9e612be3"}, - {file = "rpds_py-0.28.0-cp314-cp314t-win_amd64.whl", hash = "sha256:7a4e59c90d9c27c561eb3160323634a9ff50b04e4f7820600a2beb0ac90db578"}, - {file = "rpds_py-0.28.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f5e7101145427087e493b9c9b959da68d357c28c562792300dd21a095118ed16"}, - {file = "rpds_py-0.28.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:31eb671150b9c62409a888850aaa8e6533635704fe2b78335f9aaf7ff81eec4d"}, - {file = "rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48b55c1f64482f7d8bd39942f376bfdf2f6aec637ee8c805b5041e14eeb771db"}, - {file = "rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24743a7b372e9a76171f6b69c01aedf927e8ac3e16c474d9fe20d552a8cb45c7"}, - {file = "rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:389c29045ee8bbb1627ea190b4976a310a295559eaf9f1464a1a6f2bf84dde78"}, - {file = "rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23690b5827e643150cf7b49569679ec13fe9a610a15949ed48b85eb7f98f34ec"}, - {file = "rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f0c9266c26580e7243ad0d72fc3e01d6b33866cfab5084a6da7576bcf1c4f72"}, - {file = "rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:4c6c4db5d73d179746951486df97fd25e92396be07fc29ee8ff9a8f5afbdfb27"}, - {file = "rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3b695a8fa799dd2cfdb4804b37096c5f6dba1ac7f48a7fbf6d0485bcd060316"}, - {file = "rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:6aa1bfce3f83baf00d9c5fcdbba93a3ab79958b4c7d7d1f55e7fe68c20e63912"}, - {file = "rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:7b0f9dceb221792b3ee6acb5438eb1f02b0cb2c247796a72b016dcc92c6de829"}, - {file = "rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5d0145edba8abd3db0ab22b5300c99dc152f5c9021fab861be0f0544dc3cbc5f"}, - {file = "rpds_py-0.28.0.tar.gz", hash = "sha256:abd4df20485a0983e2ca334a216249b6186d6e3c1627e106651943dbdb791aea"}, -] - -[[package]] -name = "s3transfer" -version = "0.14.0" -description = "An Amazon S3 Transfer Manager" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "s3transfer-0.14.0-py3-none-any.whl", hash = "sha256:ea3b790c7077558ed1f02a3072fb3cb992bbbd253392f4b6e9e8976941c7d456"}, - {file = "s3transfer-0.14.0.tar.gz", hash = "sha256:eff12264e7c8b4985074ccce27a3b38a485bb7f7422cc8046fee9be4983e4125"}, -] - -[package.dependencies] -botocore = ">=1.37.4,<2.0a.0" - -[package.extras] -crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"] - -[[package]] -name = "safetensors" -version = "0.6.2" -description = "" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "safetensors-0.6.2-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:9c85ede8ec58f120bad982ec47746981e210492a6db876882aa021446af8ffba"}, - {file = "safetensors-0.6.2-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d6675cf4b39c98dbd7d940598028f3742e0375a6b4d4277e76beb0c35f4b843b"}, - {file = "safetensors-0.6.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d2d2b3ce1e2509c68932ca03ab8f20570920cd9754b05063d4368ee52833ecd"}, - {file = "safetensors-0.6.2-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:93de35a18f46b0f5a6a1f9e26d91b442094f2df02e9fd7acf224cfec4238821a"}, - {file = "safetensors-0.6.2-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89a89b505f335640f9120fac65ddeb83e40f1fd081cb8ed88b505bdccec8d0a1"}, - {file = "safetensors-0.6.2-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fc4d0d0b937e04bdf2ae6f70cd3ad51328635fe0e6214aa1fc811f3b576b3bda"}, - {file = "safetensors-0.6.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8045db2c872db8f4cbe3faa0495932d89c38c899c603f21e9b6486951a5ecb8f"}, - {file = "safetensors-0.6.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:81e67e8bab9878bb568cffbc5f5e655adb38d2418351dc0859ccac158f753e19"}, - {file = "safetensors-0.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0e4d029ab0a0e0e4fdf142b194514695b1d7d3735503ba700cf36d0fc7136ce"}, - {file = "safetensors-0.6.2-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:fa48268185c52bfe8771e46325a1e21d317207bcabcb72e65c6e28e9ffeb29c7"}, - {file = "safetensors-0.6.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:d83c20c12c2d2f465997c51b7ecb00e407e5f94d7dec3ea0cc11d86f60d3fde5"}, - {file = "safetensors-0.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d944cea65fad0ead848b6ec2c37cc0b197194bec228f8020054742190e9312ac"}, - {file = "safetensors-0.6.2-cp38-abi3-win32.whl", hash = "sha256:cab75ca7c064d3911411461151cb69380c9225798a20e712b102edda2542ddb1"}, - {file = "safetensors-0.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:c7b214870df923cbc1593c3faee16bec59ea462758699bd3fee399d00aac072c"}, - {file = "safetensors-0.6.2.tar.gz", hash = "sha256:43ff2aa0e6fa2dc3ea5524ac7ad93a9839256b8703761e76e2d0b2a3fa4f15d9"}, -] - -[package.extras] -all = ["safetensors[jax]", "safetensors[numpy]", "safetensors[paddlepaddle]", "safetensors[pinned-tf]", "safetensors[quality]", "safetensors[testing]", "safetensors[torch]"] -dev = ["safetensors[all]"] -jax = ["flax (>=0.6.3)", "jax (>=0.3.25)", "jaxlib (>=0.3.25)", "safetensors[numpy]"] -mlx = ["mlx (>=0.0.9)"] -numpy = ["numpy (>=1.21.6)"] -paddlepaddle = ["paddlepaddle (>=2.4.1)", "safetensors[numpy]"] -pinned-tf = ["safetensors[numpy]", "tensorflow (==2.18.0)"] -quality = ["ruff"] -tensorflow = ["safetensors[numpy]", "tensorflow (>=2.11.0)"] -testing = ["h5py (>=3.7.0)", "huggingface-hub (>=0.12.1)", "hypothesis (>=6.70.2)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "safetensors[numpy]", "setuptools-rust (>=1.5.2)"] -testingfree = ["huggingface-hub (>=0.12.1)", "hypothesis (>=6.70.2)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "safetensors[numpy]", "setuptools-rust (>=1.5.2)"] -torch = ["safetensors[numpy]", "torch (>=1.10)"] - -[[package]] -name = "scikit-learn" -version = "1.7.2" -description = "A set of python modules for machine learning and data mining" -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f"}, - {file = "scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c"}, - {file = "scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8"}, - {file = "scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18"}, - {file = "scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5"}, - {file = "scikit_learn-1.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7509693451651cd7361d30ce4e86a1347493554f172b1c72a39300fa2aea79e"}, - {file = "scikit_learn-1.7.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0486c8f827c2e7b64837c731c8feff72c0bd2b998067a8a9cbc10643c31f0fe1"}, - {file = "scikit_learn-1.7.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89877e19a80c7b11a2891a27c21c4894fb18e2c2e077815bcade10d34287b20d"}, - {file = "scikit_learn-1.7.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8da8bf89d4d79aaec192d2bda62f9b56ae4e5b4ef93b6a56b5de4977e375c1f1"}, - {file = "scikit_learn-1.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:9b7ed8d58725030568523e937c43e56bc01cadb478fc43c042a9aca1dacb3ba1"}, - {file = "scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96"}, - {file = "scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476"}, - {file = "scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b"}, - {file = "scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44"}, - {file = "scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290"}, - {file = "scikit_learn-1.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b7dacaa05e5d76759fb071558a8b5130f4845166d88654a0f9bdf3eb57851b7"}, - {file = "scikit_learn-1.7.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:abebbd61ad9e1deed54cca45caea8ad5f79e1b93173dece40bb8e0c658dbe6fe"}, - {file = "scikit_learn-1.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502c18e39849c0ea1a5d681af1dbcf15f6cce601aebb657aabbfe84133c1907f"}, - {file = "scikit_learn-1.7.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a4c328a71785382fe3fe676a9ecf2c86189249beff90bf85e22bdb7efaf9ae0"}, - {file = "scikit_learn-1.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:63a9afd6f7b229aad94618c01c252ce9e6fa97918c5ca19c9a17a087d819440c"}, - {file = "scikit_learn-1.7.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9acb6c5e867447b4e1390930e3944a005e2cb115922e693c08a323421a6966e8"}, - {file = "scikit_learn-1.7.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:2a41e2a0ef45063e654152ec9d8bcfc39f7afce35b08902bfe290c2498a67a6a"}, - {file = "scikit_learn-1.7.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98335fb98509b73385b3ab2bd0639b1f610541d3988ee675c670371d6a87aa7c"}, - {file = "scikit_learn-1.7.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191e5550980d45449126e23ed1d5e9e24b2c68329ee1f691a3987476e115e09c"}, - {file = "scikit_learn-1.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:57dc4deb1d3762c75d685507fbd0bc17160144b2f2ba4ccea5dc285ab0d0e973"}, - {file = "scikit_learn-1.7.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fa8f63940e29c82d1e67a45d5297bdebbcb585f5a5a50c4914cc2e852ab77f33"}, - {file = "scikit_learn-1.7.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:f95dc55b7902b91331fa4e5845dd5bde0580c9cd9612b1b2791b7e80c3d32615"}, - {file = "scikit_learn-1.7.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9656e4a53e54578ad10a434dc1f993330568cfee176dff07112b8785fb413106"}, - {file = "scikit_learn-1.7.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96dc05a854add0e50d3f47a1ef21a10a595016da5b007c7d9cd9d0bffd1fcc61"}, - {file = "scikit_learn-1.7.2-cp314-cp314-win_amd64.whl", hash = "sha256:bb24510ed3f9f61476181e4db51ce801e2ba37541def12dc9333b946fc7a9cf8"}, - {file = "scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda"}, -] - -[package.dependencies] -joblib = ">=1.2.0" -numpy = ">=1.22.0" -scipy = ">=1.8.0" -threadpoolctl = ">=3.1.0" - -[package.extras] -benchmark = ["matplotlib (>=3.5.0)", "memory_profiler (>=0.57.0)", "pandas (>=1.4.0)"] -build = ["cython (>=3.0.10)", "meson-python (>=0.17.1)", "numpy (>=1.22.0)", "scipy (>=1.8.0)"] -docs = ["Pillow (>=8.4.0)", "matplotlib (>=3.5.0)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.4.0)", "plotly (>=5.14.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.19.0)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-design (>=0.6.0)", "sphinx-gallery (>=0.17.1)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)", "towncrier (>=24.8.0)"] -examples = ["matplotlib (>=3.5.0)", "pandas (>=1.4.0)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.19.0)", "seaborn (>=0.9.0)"] -install = ["joblib (>=1.2.0)", "numpy (>=1.22.0)", "scipy (>=1.8.0)", "threadpoolctl (>=3.1.0)"] -maintenance = ["conda-lock (==3.0.1)"] -tests = ["matplotlib (>=3.5.0)", "mypy (>=1.15)", "numpydoc (>=1.2.0)", "pandas (>=1.4.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.2.1)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.11.7)", "scikit-image (>=0.19.0)"] - -[[package]] -name = "scipy" -version = "1.16.3" -description = "Fundamental algorithms for scientific computing in Python" -optional = false -python-versions = ">=3.11" -groups = ["main"] -files = [ - {file = "scipy-1.16.3-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:40be6cf99e68b6c4321e9f8782e7d5ff8265af28ef2cd56e9c9b2638fa08ad97"}, - {file = "scipy-1.16.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8be1ca9170fcb6223cc7c27f4305d680ded114a1567c0bd2bfcbf947d1b17511"}, - {file = "scipy-1.16.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bea0a62734d20d67608660f69dcda23e7f90fb4ca20974ab80b6ed40df87a005"}, - {file = "scipy-1.16.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:2a207a6ce9c24f1951241f4693ede2d393f59c07abc159b2cb2be980820e01fb"}, - {file = "scipy-1.16.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:532fb5ad6a87e9e9cd9c959b106b73145a03f04c7d57ea3e6f6bb60b86ab0876"}, - {file = "scipy-1.16.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0151a0749efeaaab78711c78422d413c583b8cdd2011a3c1d6c794938ee9fdb2"}, - {file = "scipy-1.16.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7180967113560cca57418a7bc719e30366b47959dd845a93206fbed693c867e"}, - {file = "scipy-1.16.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:deb3841c925eeddb6afc1e4e4a45e418d19ec7b87c5df177695224078e8ec733"}, - {file = "scipy-1.16.3-cp311-cp311-win_amd64.whl", hash = "sha256:53c3844d527213631e886621df5695d35e4f6a75f620dca412bcd292f6b87d78"}, - {file = "scipy-1.16.3-cp311-cp311-win_arm64.whl", hash = "sha256:9452781bd879b14b6f055b26643703551320aa8d79ae064a71df55c00286a184"}, - {file = "scipy-1.16.3-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:81fc5827606858cf71446a5e98715ba0e11f0dbc83d71c7409d05486592a45d6"}, - {file = "scipy-1.16.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:c97176013d404c7346bf57874eaac5187d969293bf40497140b0a2b2b7482e07"}, - {file = "scipy-1.16.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2b71d93c8a9936046866acebc915e2af2e292b883ed6e2cbe5c34beb094b82d9"}, - {file = "scipy-1.16.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3d4a07a8e785d80289dfe66b7c27d8634a773020742ec7187b85ccc4b0e7b686"}, - {file = "scipy-1.16.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0553371015692a898e1aa858fed67a3576c34edefa6b7ebdb4e9dde49ce5c203"}, - {file = "scipy-1.16.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:72d1717fd3b5e6ec747327ce9bda32d5463f472c9dce9f54499e81fbd50245a1"}, - {file = "scipy-1.16.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fb2472e72e24d1530debe6ae078db70fb1605350c88a3d14bc401d6306dbffe"}, - {file = "scipy-1.16.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c5192722cffe15f9329a3948c4b1db789fbb1f05c97899187dcf009b283aea70"}, - {file = "scipy-1.16.3-cp312-cp312-win_amd64.whl", hash = "sha256:56edc65510d1331dae01ef9b658d428e33ed48b4f77b1d51caf479a0253f96dc"}, - {file = "scipy-1.16.3-cp312-cp312-win_arm64.whl", hash = "sha256:a8a26c78ef223d3e30920ef759e25625a0ecdd0d60e5a8818b7513c3e5384cf2"}, - {file = "scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c"}, - {file = "scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d"}, - {file = "scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9"}, - {file = "scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4"}, - {file = "scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959"}, - {file = "scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88"}, - {file = "scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234"}, - {file = "scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d"}, - {file = "scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304"}, - {file = "scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2"}, - {file = "scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b"}, - {file = "scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079"}, - {file = "scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a"}, - {file = "scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119"}, - {file = "scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c"}, - {file = "scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e"}, - {file = "scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135"}, - {file = "scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6"}, - {file = "scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc"}, - {file = "scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a"}, - {file = "scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6"}, - {file = "scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657"}, - {file = "scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26"}, - {file = "scipy-1.16.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7f68154688c515cdb541a31ef8eb66d8cd1050605be9dcd74199cbd22ac739bc"}, - {file = "scipy-1.16.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3c820ddb80029fe9f43d61b81d8b488d3ef8ca010d15122b152db77dc94c22"}, - {file = "scipy-1.16.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3837938ae715fc0fe3c39c0202de3a8853aff22ca66781ddc2ade7554b7e2cc"}, - {file = "scipy-1.16.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aadd23f98f9cb069b3bd64ddc900c4d277778242e961751f77a8cb5c4b946fb0"}, - {file = "scipy-1.16.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b7c5f1bda1354d6a19bc6af73a649f8285ca63ac6b52e64e658a5a11d4d69800"}, - {file = "scipy-1.16.3-cp314-cp314-win_amd64.whl", hash = "sha256:e5d42a9472e7579e473879a1990327830493a7047506d58d73fc429b84c1d49d"}, - {file = "scipy-1.16.3-cp314-cp314-win_arm64.whl", hash = "sha256:6020470b9d00245926f2d5bb93b119ca0340f0d564eb6fbaad843eaebf9d690f"}, - {file = "scipy-1.16.3-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:e1d27cbcb4602680a49d787d90664fa4974063ac9d4134813332a8c53dbe667c"}, - {file = "scipy-1.16.3-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9b9c9c07b6d56a35777a1b4cc8966118fb16cfd8daf6743867d17d36cfad2d40"}, - {file = "scipy-1.16.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:3a4c460301fb2cffb7f88528f30b3127742cff583603aa7dc964a52c463b385d"}, - {file = "scipy-1.16.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f667a4542cc8917af1db06366d3f78a5c8e83badd56409f94d1eac8d8d9133fa"}, - {file = "scipy-1.16.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f379b54b77a597aa7ee5e697df0d66903e41b9c85a6dd7946159e356319158e8"}, - {file = "scipy-1.16.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4aff59800a3b7f786b70bfd6ab551001cb553244988d7d6b8299cb1ea653b353"}, - {file = "scipy-1.16.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:da7763f55885045036fabcebd80144b757d3db06ab0861415d1c3b7c69042146"}, - {file = "scipy-1.16.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa6eea95283b2b8079b821dc11f50a17d0571c92b43e2b5b12764dc5f9b285d"}, - {file = "scipy-1.16.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d9f48cafc7ce94cf9b15c6bffdc443a81a27bf7075cf2dcd5c8b40f85d10c4e7"}, - {file = "scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562"}, - {file = "scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb"}, -] - -[package.dependencies] -numpy = ">=1.25.2,<2.6" - -[package.extras] -dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] -doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "linkify-it-py", "matplotlib (>=3.5)", "myst-nb (>=1.2.0)", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.2.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] -test = ["Cython", "array-api-strict (>=2.3.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest (>=8.0.0)", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] - -[[package]] -name = "send2trash" -version = "1.8.3" -description = "Send file to trash natively under Mac OS X, Windows and Linux" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -groups = ["dev"] -files = [ - {file = "Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9"}, - {file = "Send2Trash-1.8.3.tar.gz", hash = "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf"}, -] - -[package.extras] -nativelib = ["pyobjc-framework-Cocoa ; sys_platform == \"darwin\"", "pywin32 ; sys_platform == \"win32\""] -objc = ["pyobjc-framework-Cocoa ; sys_platform == \"darwin\""] -win32 = ["pywin32 ; sys_platform == \"win32\""] - -[[package]] -name = "sentence-transformers" -version = "3.4.1" -description = "State-of-the-Art Text Embeddings" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "sentence_transformers-3.4.1-py3-none-any.whl", hash = "sha256:e026dc6d56801fd83f74ad29a30263f401b4b522165c19386d8bc10dcca805da"}, - {file = "sentence_transformers-3.4.1.tar.gz", hash = "sha256:68daa57504ff548340e54ff117bd86c1d2f784b21e0fb2689cf3272b8937b24b"}, -] - -[package.dependencies] -huggingface-hub = ">=0.20.0" -Pillow = "*" -scikit-learn = "*" -scipy = "*" -torch = ">=1.11.0" -tqdm = "*" -transformers = ">=4.41.0,<5.0.0" - -[package.extras] -dev = ["accelerate (>=0.20.3)", "datasets", "peft", "pre-commit", "pytest", "pytest-cov"] -onnx = ["optimum[onnxruntime] (>=1.23.1)"] -onnx-gpu = ["optimum[onnxruntime-gpu] (>=1.23.1)"] -openvino = ["optimum-intel[openvino] (>=1.20.0)"] -train = ["accelerate (>=0.20.3)", "datasets"] - -[[package]] -name = "setuptools" -version = "80.9.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"}, - {file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"}, -] - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""] -core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"] - -[[package]] -name = "six" -version = "1.17.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main", "dev"] -files = [ - {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, - {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" -groups = ["main", "dev"] -files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, -] - -[[package]] -name = "soupsieve" -version = "2.8" -description = "A modern CSS selector implementation for Beautiful Soup." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c"}, - {file = "soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f"}, -] - -[[package]] -name = "sqlalchemy" -version = "2.0.44" -description = "Database Abstraction Library" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "SQLAlchemy-2.0.44-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:471733aabb2e4848d609141a9e9d56a427c0a038f4abf65dd19d7a21fd563632"}, - {file = "SQLAlchemy-2.0.44-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48bf7d383a35e668b984c805470518b635d48b95a3c57cb03f37eaa3551b5f9f"}, - {file = "SQLAlchemy-2.0.44-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bf4bb6b3d6228fcf3a71b50231199fb94d2dd2611b66d33be0578ea3e6c2726"}, - {file = "SQLAlchemy-2.0.44-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:e998cf7c29473bd077704cea3577d23123094311f59bdc4af551923b168332b1"}, - {file = "SQLAlchemy-2.0.44-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ebac3f0b5732014a126b43c2b7567f2f0e0afea7d9119a3378bde46d3dcad88e"}, - {file = "SQLAlchemy-2.0.44-cp37-cp37m-win32.whl", hash = "sha256:3255d821ee91bdf824795e936642bbf43a4c7cedf5d1aed8d24524e66843aa74"}, - {file = "SQLAlchemy-2.0.44-cp37-cp37m-win_amd64.whl", hash = "sha256:78e6c137ba35476adb5432103ae1534f2f5295605201d946a4198a0dea4b38e7"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c77f3080674fc529b1bd99489378c7f63fcb4ba7f8322b79732e0258f0ea3ce"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4c26ef74ba842d61635b0152763d057c8d48215d5be9bb8b7604116a059e9985"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4a172b31785e2f00780eccab00bc240ccdbfdb8345f1e6063175b3ff12ad1b0"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9480c0740aabd8cb29c329b422fb65358049840b34aba0adf63162371d2a96e"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17835885016b9e4d0135720160db3095dc78c583e7b902b6be799fb21035e749"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cbe4f85f50c656d753890f39468fcd8190c5f08282caf19219f684225bfd5fd2"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-win32.whl", hash = "sha256:2fcc4901a86ed81dc76703f3b93ff881e08761c63263c46991081fd7f034b165"}, - {file = "sqlalchemy-2.0.44-cp310-cp310-win_amd64.whl", hash = "sha256:9919e77403a483ab81e3423151e8ffc9dd992c20d2603bf17e4a8161111e55f5"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fe3917059c7ab2ee3f35e77757062b1bea10a0b6ca633c58391e3f3c6c488dd"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:de4387a354ff230bc979b46b2207af841dc8bf29847b6c7dbe60af186d97aefa"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3678a0fb72c8a6a29422b2732fe423db3ce119c34421b5f9955873eb9b62c1e"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cf6872a23601672d61a68f390e44703442639a12ee9dd5a88bbce52a695e46e"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:329aa42d1be9929603f406186630135be1e7a42569540577ba2c69952b7cf399"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:70e03833faca7166e6a9927fbee7c27e6ecde436774cd0b24bbcc96353bce06b"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-win32.whl", hash = "sha256:253e2f29843fb303eca6b2fc645aca91fa7aa0aa70b38b6950da92d44ff267f3"}, - {file = "sqlalchemy-2.0.44-cp311-cp311-win_amd64.whl", hash = "sha256:7a8694107eb4308a13b425ca8c0e67112f8134c846b6e1f722698708741215d5"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72fea91746b5890f9e5e0997f16cbf3d53550580d76355ba2d998311b17b2250"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:585c0c852a891450edbb1eaca8648408a3cc125f18cf433941fa6babcc359e29"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b94843a102efa9ac68a7a30cd46df3ff1ed9c658100d30a725d10d9c60a2f44"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:119dc41e7a7defcefc57189cfa0e61b1bf9c228211aba432b53fb71ef367fda1"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0765e318ee9179b3718c4fd7ba35c434f4dd20332fbc6857a5e8df17719c24d7"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2e7b5b079055e02d06a4308d0481658e4f06bc7ef211567edc8f7d5dce52018d"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-win32.whl", hash = "sha256:846541e58b9a81cce7dee8329f352c318de25aa2f2bbe1e31587eb1f057448b4"}, - {file = "sqlalchemy-2.0.44-cp312-cp312-win_amd64.whl", hash = "sha256:7cbcb47fd66ab294703e1644f78971f6f2f1126424d2b300678f419aa73c7b6e"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ff486e183d151e51b1d694c7aa1695747599bb00b9f5f604092b54b74c64a8e1"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b1af8392eb27b372ddb783b317dea0f650241cea5bd29199b22235299ca2e45"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b61188657e3a2b9ac4e8f04d6cf8e51046e28175f79464c67f2fd35bceb0976"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b87e7b91a5d5973dda5f00cd61ef72ad75a1db73a386b62877d4875a8840959c"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:15f3326f7f0b2bfe406ee562e17f43f36e16167af99c4c0df61db668de20002d"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e77faf6ff919aa8cd63f1c4e561cac1d9a454a191bb864d5dd5e545935e5a40"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-win32.whl", hash = "sha256:ee51625c2d51f8baadf2829fae817ad0b66b140573939dd69284d2ba3553ae73"}, - {file = "sqlalchemy-2.0.44-cp313-cp313-win_amd64.whl", hash = "sha256:c1c80faaee1a6c3428cecf40d16a2365bcf56c424c92c2b6f0f9ad204b899e9e"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2fc44e5965ea46909a416fff0af48a219faefd5773ab79e5f8a5fcd5d62b2667"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dc8b3850d2a601ca2320d081874033684e246d28e1c5e89db0864077cfc8f5a9"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d733dec0614bb8f4bcb7c8af88172b974f685a31dc3a65cca0527e3120de5606"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22be14009339b8bc16d6b9dc8780bacaba3402aa7581658e246114abbd2236e3"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:357bade0e46064f88f2c3a99808233e67b0051cdddf82992379559322dfeb183"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4848395d932e93c1595e59a8672aa7400e8922c39bb9b0668ed99ac6fa867822"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-win32.whl", hash = "sha256:2f19644f27c76f07e10603580a47278abb2a70311136a7f8fd27dc2e096b9013"}, - {file = "sqlalchemy-2.0.44-cp38-cp38-win_amd64.whl", hash = "sha256:1df4763760d1de0dfc8192cc96d8aa293eb1a44f8f7a5fbe74caf1b551905c5e"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7027414f2b88992877573ab780c19ecb54d3a536bef3397933573d6b5068be4"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fe166c7d00912e8c10d3a9a0ce105569a31a3d0db1a6e82c4e0f4bf16d5eca9"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3caef1ff89b1caefc28f0368b3bde21a7e3e630c2eddac16abd9e47bd27cc36a"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc2856d24afa44295735e72f3c75d6ee7fdd4336d8d3a8f3d44de7aa6b766df2"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:11bac86b0deada30b6b5f93382712ff0e911fe8d31cb9bf46e6b149ae175eff0"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4d18cd0e9a0f37c9f4088e50e3839fcb69a380a0ec957408e0b57cff08ee0a26"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-win32.whl", hash = "sha256:9e9018544ab07614d591a26c1bd4293ddf40752cc435caf69196740516af7100"}, - {file = "sqlalchemy-2.0.44-cp39-cp39-win_amd64.whl", hash = "sha256:8e0e4e66fd80f277a8c3de016a81a554e76ccf6b8d881ee0b53200305a8433f6"}, - {file = "sqlalchemy-2.0.44-py3-none-any.whl", hash = "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05"}, - {file = "sqlalchemy-2.0.44.tar.gz", hash = "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22"}, -] - -[package.dependencies] -greenlet = {version = ">=1", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} -typing-extensions = ">=4.6.0" - -[package.extras] -aiomysql = ["aiomysql (>=0.2.0)", "greenlet (>=1)"] -aioodbc = ["aioodbc", "greenlet (>=1)"] -aiosqlite = ["aiosqlite", "greenlet (>=1)", "typing_extensions (!=3.10.0.1)"] -asyncio = ["greenlet (>=1)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (>=1)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"] -mssql = ["pyodbc"] -mssql-pymssql = ["pymssql"] -mssql-pyodbc = ["pyodbc"] -mypy = ["mypy (>=0.910)"] -mysql = ["mysqlclient (>=1.4.0)"] -mysql-connector = ["mysql-connector-python"] -oracle = ["cx_oracle (>=8)"] -oracle-oracledb = ["oracledb (>=1.0.1)"] -postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (>=1)"] -postgresql-pg8000 = ["pg8000 (>=1.29.1)"] -postgresql-psycopg = ["psycopg (>=3.0.7)"] -postgresql-psycopg2binary = ["psycopg2-binary"] -postgresql-psycopg2cffi = ["psycopg2cffi"] -postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] -pymysql = ["pymysql"] -sqlcipher = ["sqlcipher3_binary"] - -[[package]] -name = "stack-data" -version = "0.6.3" -description = "Extract data from python stack frames and tracebacks for informative displays" -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, - {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, -] - -[package.dependencies] -asttokens = ">=2.1.0" -executing = ">=1.2.0" -pure-eval = "*" - -[package.extras] -tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] - -[[package]] -name = "sympy" -version = "1.14.0" -description = "Computer algebra system (CAS) in Python" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5"}, - {file = "sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517"}, -] - -[package.dependencies] -mpmath = ">=1.1.0,<1.4" - -[package.extras] -dev = ["hypothesis (>=6.70.0)", "pytest (>=7.1.0)"] - -[[package]] -name = "tenacity" -version = "9.1.2" -description = "Retry code until it succeeds" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"}, - {file = "tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb"}, -] - -[package.extras] -doc = ["reno", "sphinx"] -test = ["pytest", "tornado (>=4.5)", "typeguard"] - -[[package]] -name = "terminado" -version = "0.18.1" -description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0"}, - {file = "terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e"}, -] - -[package.dependencies] -ptyprocess = {version = "*", markers = "os_name != \"nt\""} -pywinpty = {version = ">=1.1.0", markers = "os_name == \"nt\""} -tornado = ">=6.1.0" - -[package.extras] -docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["pre-commit", "pytest (>=7.0)", "pytest-timeout"] -typing = ["mypy (>=1.6,<2.0)", "traitlets (>=5.11.1)"] - -[[package]] -name = "threadpoolctl" -version = "3.6.0" -description = "threadpoolctl" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb"}, - {file = "threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e"}, -] - -[[package]] -name = "tinycss2" -version = "1.4.0" -description = "A tiny CSS parser" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289"}, - {file = "tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7"}, -] - -[package.dependencies] -webencodings = ">=0.4" - -[package.extras] -doc = ["sphinx", "sphinx_rtd_theme"] -test = ["pytest", "ruff"] - -[[package]] -name = "tokenizers" -version = "0.22.1" -description = "" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "tokenizers-0.22.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:59fdb013df17455e5f950b4b834a7b3ee2e0271e6378ccb33aa74d178b513c73"}, - {file = "tokenizers-0.22.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:8d4e484f7b0827021ac5f9f71d4794aaef62b979ab7608593da22b1d2e3c4edc"}, - {file = "tokenizers-0.22.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19d2962dd28bc67c1f205ab180578a78eef89ac60ca7ef7cbe9635a46a56422a"}, - {file = "tokenizers-0.22.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38201f15cdb1f8a6843e6563e6e79f4abd053394992b9bbdf5213ea3469b4ae7"}, - {file = "tokenizers-0.22.1-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1cbe5454c9a15df1b3443c726063d930c16f047a3cc724b9e6e1a91140e5a21"}, - {file = "tokenizers-0.22.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7d094ae6312d69cc2a872b54b91b309f4f6fbce871ef28eb27b52a98e4d0214"}, - {file = "tokenizers-0.22.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afd7594a56656ace95cdd6df4cca2e4059d294c5cfb1679c57824b605556cb2f"}, - {file = "tokenizers-0.22.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ef6063d7a84994129732b47e7915e8710f27f99f3a3260b8a38fc7ccd083f4"}, - {file = "tokenizers-0.22.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ba0a64f450b9ef412c98f6bcd2a50c6df6e2443b560024a09fa6a03189726879"}, - {file = "tokenizers-0.22.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:331d6d149fa9c7d632cde4490fb8bbb12337fa3a0232e77892be656464f4b446"}, - {file = "tokenizers-0.22.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:607989f2ea68a46cb1dfbaf3e3aabdf3f21d8748312dbeb6263d1b3b66c5010a"}, - {file = "tokenizers-0.22.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a0f307d490295717726598ef6fa4f24af9d484809223bbc253b201c740a06390"}, - {file = "tokenizers-0.22.1-cp39-abi3-win32.whl", hash = "sha256:b5120eed1442765cd90b903bb6cfef781fd8fe64e34ccaecbae4c619b7b12a82"}, - {file = "tokenizers-0.22.1-cp39-abi3-win_amd64.whl", hash = "sha256:65fd6e3fb11ca1e78a6a93602490f134d1fdeb13bcef99389d5102ea318ed138"}, - {file = "tokenizers-0.22.1.tar.gz", hash = "sha256:61de6522785310a309b3407bac22d99c4db5dba349935e99e4d15ea2226af2d9"}, -] - -[package.dependencies] -huggingface-hub = ">=0.16.4,<2.0" - -[package.extras] -dev = ["tokenizers[testing]"] -docs = ["setuptools-rust", "sphinx", "sphinx-rtd-theme"] -testing = ["black (==22.3)", "datasets", "numpy", "pytest", "pytest-asyncio", "requests", "ruff"] - -[[package]] -name = "torch" -version = "2.7.1" -description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" -optional = false -python-versions = ">=3.9.0" -groups = ["main"] -markers = "python_version >= \"3.14\"" -files = [ - {file = "torch-2.7.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a103b5d782af5bd119b81dbcc7ffc6fa09904c423ff8db397a1e6ea8fd71508f"}, - {file = "torch-2.7.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:fe955951bdf32d182ee8ead6c3186ad54781492bf03d547d31771a01b3d6fb7d"}, - {file = "torch-2.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:885453d6fba67d9991132143bf7fa06b79b24352f4506fd4d10b309f53454162"}, - {file = "torch-2.7.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:d72acfdb86cee2a32c0ce0101606f3758f0d8bb5f8f31e7920dc2809e963aa7c"}, - {file = "torch-2.7.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:236f501f2e383f1cb861337bdf057712182f910f10aeaf509065d54d339e49b2"}, - {file = "torch-2.7.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:06eea61f859436622e78dd0cdd51dbc8f8c6d76917a9cf0555a333f9eac31ec1"}, - {file = "torch-2.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:8273145a2e0a3c6f9fd2ac36762d6ee89c26d430e612b95a99885df083b04e52"}, - {file = "torch-2.7.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:aea4fc1bf433d12843eb2c6b2204861f43d8364597697074c8d38ae2507f8730"}, - {file = "torch-2.7.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:27ea1e518df4c9de73af7e8a720770f3628e7f667280bce2be7a16292697e3fa"}, - {file = "torch-2.7.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c33360cfc2edd976c2633b3b66c769bdcbbf0e0b6550606d188431c81e7dd1fc"}, - {file = "torch-2.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:d8bf6e1856ddd1807e79dc57e54d3335f2b62e6f316ed13ed3ecfe1fc1df3d8b"}, - {file = "torch-2.7.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:787687087412c4bd68d315e39bc1223f08aae1d16a9e9771d95eabbb04ae98fb"}, - {file = "torch-2.7.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:03563603d931e70722dce0e11999d53aa80a375a3d78e6b39b9f6805ea0a8d28"}, - {file = "torch-2.7.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:d632f5417b6980f61404a125b999ca6ebd0b8b4bbdbb5fbbba44374ab619a412"}, - {file = "torch-2.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:23660443e13995ee93e3d844786701ea4ca69f337027b05182f5ba053ce43b38"}, - {file = "torch-2.7.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:0da4f4dba9f65d0d203794e619fe7ca3247a55ffdcbd17ae8fb83c8b2dc9b585"}, - {file = "torch-2.7.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:e08d7e6f21a617fe38eeb46dd2213ded43f27c072e9165dc27300c9ef9570934"}, - {file = "torch-2.7.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:30207f672328a42df4f2174b8f426f354b2baa0b7cca3a0adb3d6ab5daf00dc8"}, - {file = "torch-2.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:79042feca1c634aaf6603fe6feea8c6b30dfa140a6bbc0b973e2260c7e79a22e"}, - {file = "torch-2.7.1-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:988b0cbc4333618a1056d2ebad9eb10089637b659eb645434d0809d8d937b946"}, - {file = "torch-2.7.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:e0d81e9a12764b6f3879a866607c8ae93113cbcad57ce01ebde63eb48a576369"}, - {file = "torch-2.7.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:8394833c44484547ed4a47162318337b88c97acdb3273d85ea06e03ffff44998"}, - {file = "torch-2.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:df41989d9300e6e3c19ec9f56f856187a6ef060c3662fe54f4b6baf1fc90bd19"}, - {file = "torch-2.7.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:a737b5edd1c44a5c1ece2e9f3d00df9d1b3fb9541138bee56d83d38293fb6c9d"}, -] - -[package.dependencies] -filelock = "*" -fsspec = "*" -jinja2 = "*" -networkx = "*" -nvidia-cublas-cu12 = {version = "12.6.4.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-cupti-cu12 = {version = "12.6.80", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-nvrtc-cu12 = {version = "12.6.77", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-runtime-cu12 = {version = "12.6.77", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cudnn-cu12 = {version = "9.5.1.17", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cufft-cu12 = {version = "11.3.0.4", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cufile-cu12 = {version = "1.11.1.6", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-curand-cu12 = {version = "10.3.7.77", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusolver-cu12 = {version = "11.7.1.2", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusparse-cu12 = {version = "12.5.4.2", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusparselt-cu12 = {version = "0.6.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nccl-cu12 = {version = "2.26.2", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nvjitlink-cu12 = {version = "12.6.85", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nvtx-cu12 = {version = "12.6.77", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -setuptools = {version = "*", markers = "python_version >= \"3.12\""} -sympy = ">=1.13.3" -triton = {version = "3.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -typing-extensions = ">=4.10.0" - -[package.extras] -opt-einsum = ["opt-einsum (>=3.3)"] -optree = ["optree (>=0.13.0)"] - -[[package]] -name = "torch" -version = "2.9.0" -description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" -optional = false -python-versions = ">=3.10" -groups = ["main"] -markers = "python_version <= \"3.13\"" -files = [ - {file = "torch-2.9.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:030bbfe367379ae6a4ae4042b6c44da25383343b8b3c68abaa9c7231efbaf2dd"}, - {file = "torch-2.9.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:51cb63902182a78e90886e8068befd8ea102af4b00e420263591a3d70c7d3c6c"}, - {file = "torch-2.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:3f6aad4d2f0ee2248bac25339d74858ff846c3969b27d14ac235821f055af83d"}, - {file = "torch-2.9.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:413e1654c9203733138858780e184d9fc59442f0b3b209e16f39354eb893db9b"}, - {file = "torch-2.9.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c596708b5105d0b199215acf0c9be7c1db5f1680d88eddadf4b75a299259a677"}, - {file = "torch-2.9.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:51de31219c97c51cf4bf2be94d622e3deb5dcc526c6dc00e97c17eaec0fc1d67"}, - {file = "torch-2.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:dd515c70059afd95f48b8192733764c08ca37a1d19803af6401b5ecad7c8676e"}, - {file = "torch-2.9.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:614a185e4986326d526a91210c8fc1397e76e8cfafa78baf6296a790e53a9eec"}, - {file = "torch-2.9.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e5f7af1dc4c0a7c4a260c2534f41ddaf209714f7c89145e644c44712fbd6b642"}, - {file = "torch-2.9.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:01cff95ecd9a212ea2f141db28acccdceb6a4c54f64e6c51091146f5e2a772c6"}, - {file = "torch-2.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:4582b162f541651f0cb184d3e291c05c2f556c7117c64a9873e2ee158d40062b"}, - {file = "torch-2.9.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:33f58e9a102a91259af289d50525c30323b5c9ae1d31322b6447c0814da68695"}, - {file = "torch-2.9.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c30a17fc83eeab346913e237c64b15b5ba6407fff812f6c541e322e19bc9ea0e"}, - {file = "torch-2.9.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:8f25033b8667b57857dfd01458fbf2a9e6a6df1f8def23aef0dc46292f6aa642"}, - {file = "torch-2.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:d037f1b4ffd25013be4a7bf3651a0a910c68554956c7b2c92ebe87c76475dece"}, - {file = "torch-2.9.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e4e5b5cba837a2a8d1a497ba9a58dae46fa392593eaa13b871c42f71847503a5"}, - {file = "torch-2.9.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:64693568f5dc4dbd5f880a478b1cea0201cc6b510d91d1bc54fea86ac5d1a637"}, - {file = "torch-2.9.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:f8ed31ddd7d10bfb3fbe0b9fe01b1243577f13d75e6f4a0839a283915ce3791e"}, - {file = "torch-2.9.0-cp313-cp313t-win_amd64.whl", hash = "sha256:eff527d4e4846e6f70d2afd8058b73825761203d66576a7e04ea2ecfebcb4ab8"}, - {file = "torch-2.9.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:f8877779cf56d1ce431a7636703bdb13307f5960bb1af49716d8b179225e0e6a"}, - {file = "torch-2.9.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7e614fae699838038d888729f82b687c03413c5989ce2a9481f9a7e7a396e0bb"}, - {file = "torch-2.9.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:dfb5b8cd310ba3436c7e14e8b7833ef658cf3045e50d2bdaed23c8fc517065eb"}, - {file = "torch-2.9.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:b3d29524993a478e46f5d598b249cd824b7ed98d7fba538bd9c4cde6c803948f"}, - {file = "torch-2.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:71c7578984f5ec0eb645eb4816ac8435fcf3e3e2ae1901bcd2f519a9cafb5125"}, - {file = "torch-2.9.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:71d9309aee457bbe0b164bce2111cd911c4ed4e847e65d5077dbbcd3aba6befc"}, - {file = "torch-2.9.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c08fb654d783899e204a32cca758a7ce8a45b2d78eeb89517cc937088316f78e"}, - {file = "torch-2.9.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ec8feb0099b2daa5728fbc7abb0b05730fd97e0f359ff8bda09865aaa7bd7d4b"}, - {file = "torch-2.9.0-cp314-cp314t-win_amd64.whl", hash = "sha256:695ba920f234ad4170c9c50e28d56c848432f8f530e6bc7f88fcb15ddf338e75"}, -] - -[package.dependencies] -filelock = "*" -fsspec = ">=0.8.5" -jinja2 = "*" -networkx = ">=2.5.1" -nvidia-cublas-cu12 = {version = "12.8.4.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-cupti-cu12 = {version = "12.8.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-nvrtc-cu12 = {version = "12.8.93", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-runtime-cu12 = {version = "12.8.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cudnn-cu12 = {version = "9.10.2.21", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cufft-cu12 = {version = "11.3.3.83", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cufile-cu12 = {version = "1.13.1.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-curand-cu12 = {version = "10.3.9.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusolver-cu12 = {version = "11.7.3.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusparse-cu12 = {version = "12.5.8.93", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusparselt-cu12 = {version = "0.7.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nccl-cu12 = {version = "2.27.5", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nvjitlink-cu12 = {version = "12.8.93", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nvshmem-cu12 = {version = "3.3.20", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nvtx-cu12 = {version = "12.8.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -setuptools = {version = "*", markers = "python_version >= \"3.12\""} -sympy = ">=1.13.3" -triton = {version = "3.5.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -typing-extensions = ">=4.10.0" - -[package.extras] -opt-einsum = ["opt-einsum (>=3.3)"] -optree = ["optree (>=0.13.0)"] -pyyaml = ["pyyaml"] - -[[package]] -name = "tornado" -version = "6.5.2" -description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6"}, - {file = "tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef"}, - {file = "tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e"}, - {file = "tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882"}, - {file = "tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108"}, - {file = "tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c"}, - {file = "tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4"}, - {file = "tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04"}, - {file = "tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0"}, - {file = "tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f"}, - {file = "tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af"}, - {file = "tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0"}, -] - -[[package]] -name = "tqdm" -version = "4.67.1" -description = "Fast, Extensible Progress Meter" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, - {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[package.extras] -dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] -discord = ["requests"] -notebook = ["ipywidgets (>=6)"] -slack = ["slack-sdk"] -telegram = ["requests"] - -[[package]] -name = "traitlets" -version = "5.14.3" -description = "Traitlets Python configuration system" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, - {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, -] - -[package.extras] -docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] - -[[package]] -name = "transformers" -version = "4.57.1" -description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" -optional = false -python-versions = ">=3.9.0" -groups = ["main"] -files = [ - {file = "transformers-4.57.1-py3-none-any.whl", hash = "sha256:b10d05da8fa67dc41644dbbf9bc45a44cb86ae33da6f9295f5fbf5b7890bd267"}, - {file = "transformers-4.57.1.tar.gz", hash = "sha256:f06c837959196c75039809636cd964b959f6604b75b8eeec6fdfc0440b89cc55"}, -] - -[package.dependencies] -filelock = "*" -huggingface-hub = ">=0.34.0,<1.0" -numpy = ">=1.17" -packaging = ">=20.0" -pyyaml = ">=5.1" -regex = "!=2019.12.17" -requests = "*" -safetensors = ">=0.4.3" -tokenizers = ">=0.22.0,<=0.23.0" -tqdm = ">=4.27" - -[package.extras] -accelerate = ["accelerate (>=0.26.0)"] -all = ["Pillow (>=10.0.1,<=15.0)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "accelerate (>=0.26.0)", "av", "codecarbon (>=2.8.1)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "jinja2 (>=3.1.0)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "kernels (>=0.6.1,<=0.9)", "librosa", "mistral-common[opencv] (>=1.6.3)", "num2words", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm (!=1.0.18,<=1.0.19)", "tokenizers (>=0.22.0,<=0.23.0)", "torch (>=2.2)", "torchaudio", "torchvision"] -audio = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] -benchmark = ["optimum-benchmark (>=0.3.0)"] -chat-template = ["jinja2 (>=3.1.0)"] -codecarbon = ["codecarbon (>=2.8.1)"] -deepspeed = ["accelerate (>=0.26.0)", "deepspeed (>=0.9.3)"] -deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.26.0)", "accelerate (>=0.26.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fastapi", "libcst", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "openai (>=1.98.0)", "optuna", "parameterized (>=0.9)", "protobuf", "psutil", "pydantic (>=2)", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures (<16.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.13.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "sentencepiece (>=0.1.91,!=0.1.92)", "starlette", "tensorboard", "timeout-decorator", "torch (>=2.2)", "uvicorn"] -dev = ["GitPython (<3.1.19)", "GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "accelerate (>=0.26.0)", "accelerate (>=0.26.0)", "av", "beautifulsoup4", "codecarbon (>=2.8.1)", "cookiecutter (==1.7.3)", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fastapi", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "jinja2 (>=3.1.0)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "kernels (>=0.6.1,<=0.9)", "libcst", "libcst", "librosa", "mistral-common[opencv] (>=1.6.3)", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "num2words", "onnxconverter-common", "openai (>=1.98.0)", "optax (>=0.0.8,<=0.1.4)", "optuna", "pandas (<2.3.0)", "parameterized (>=0.9)", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic (>=2)", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures (<16.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.13.1)", "ruff (==0.13.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sentencepiece (>=0.1.91,!=0.1.92)", "starlette", "sudachidict_core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "timm (!=1.0.18,<=1.0.19)", "tokenizers (>=0.22.0,<=0.23.0)", "torch (>=2.2)", "torch (>=2.2)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic_lite (>=1.0.7)", "urllib3 (<2.0.0)", "uvicorn"] -dev-tensorflow = ["GitPython (<3.1.19)", "GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fastapi", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "libcst", "libcst", "librosa", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "onnxconverter-common", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "openai (>=1.98.0)", "pandas (<2.3.0)", "parameterized (>=0.9)", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic (>=2)", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures (<16.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.13.1)", "ruff (==0.13.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sentencepiece (>=0.1.91,!=0.1.92)", "starlette", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "tf2onnx", "timeout-decorator", "tokenizers (>=0.22.0,<=0.23.0)", "torch (>=2.2)", "urllib3 (<2.0.0)", "uvicorn"] -dev-torch = ["GitPython (<3.1.19)", "GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "accelerate (>=0.26.0)", "beautifulsoup4", "codecarbon (>=2.8.1)", "cookiecutter (==1.7.3)", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fastapi", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "kenlm", "kernels (>=0.6.1,<=0.9)", "libcst", "libcst", "librosa", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "num2words", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "openai (>=1.98.0)", "optuna", "pandas (<2.3.0)", "parameterized (>=0.9)", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic (>=2)", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures (<16.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.13.1)", "ruff (==0.13.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sentencepiece (>=0.1.91,!=0.1.92)", "starlette", "sudachidict_core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "timeout-decorator", "timm (!=1.0.18,<=1.0.19)", "tokenizers (>=0.22.0,<=0.23.0)", "torch (>=2.2)", "torch (>=2.2)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic_lite (>=1.0.7)", "urllib3 (<2.0.0)", "uvicorn"] -flax = ["flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "optax (>=0.0.8,<=0.1.4)", "scipy (<1.13.0)"] -flax-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] -ftfy = ["ftfy"] -hf-xet = ["hf_xet"] -hub-kernels = ["kernels (>=0.6.1,<=0.9)"] -integrations = ["kernels (>=0.6.1,<=0.9)", "optuna", "ray[tune] (>=2.7.0)"] -ja = ["fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "rhoknp (>=1.1.0,<1.3.1)", "sudachidict_core (>=20220729)", "sudachipy (>=0.6.6)", "unidic (>=1.0.2)", "unidic_lite (>=1.0.7)"] -mistral-common = ["mistral-common[opencv] (>=1.6.3)"] -modelcreation = ["cookiecutter (==1.7.3)"] -natten = ["natten (>=0.14.6,<0.15.0)"] -num2words = ["num2words"] -onnx = ["onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "tf2onnx"] -onnxruntime = ["onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)"] -open-telemetry = ["opentelemetry-api", "opentelemetry-exporter-otlp", "opentelemetry-sdk"] -optuna = ["optuna"] -quality = ["GitPython (<3.1.19)", "datasets (>=2.15.0)", "libcst", "pandas (<2.3.0)", "rich", "ruff (==0.13.1)", "urllib3 (<2.0.0)"] -ray = ["ray[tune] (>=2.7.0)"] -retrieval = ["datasets (>=2.15.0)", "faiss-cpu"] -ruff = ["ruff (==0.13.1)"] -sagemaker = ["sagemaker (>=2.31.0)"] -sentencepiece = ["protobuf", "sentencepiece (>=0.1.91,!=0.1.92)"] -serving = ["accelerate (>=0.26.0)", "fastapi", "openai (>=1.98.0)", "pydantic (>=2)", "starlette", "torch (>=2.2)", "uvicorn"] -sigopt = ["sigopt"] -sklearn = ["scikit-learn"] -speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] -testing = ["GitPython (<3.1.19)", "accelerate (>=0.26.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "datasets (>=2.15.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fastapi", "libcst", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "openai (>=1.98.0)", "parameterized (>=0.9)", "psutil", "pydantic (>=2)", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures (<16.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.13.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "starlette", "tensorboard", "timeout-decorator", "torch (>=2.2)", "uvicorn"] -tf = ["keras-nlp (>=0.3.1,<0.14.0)", "onnxconverter-common", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx"] -tf-cpu = ["keras (>2.9,<2.16)", "keras-nlp (>=0.3.1,<0.14.0)", "onnxconverter-common", "tensorflow-cpu (>2.9,<2.16)", "tensorflow-probability (<0.24)", "tensorflow-text (<2.16)", "tf2onnx"] -tf-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] -tiktoken = ["blobfile", "tiktoken"] -timm = ["timm (!=1.0.18,<=1.0.19)"] -tokenizers = ["tokenizers (>=0.22.0,<=0.23.0)"] -torch = ["accelerate (>=0.26.0)", "torch (>=2.2)"] -torch-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] -torch-vision = ["Pillow (>=10.0.1,<=15.0)", "torchvision"] -torchhub = ["filelock", "huggingface-hub (>=0.34.0,<1.0)", "importlib_metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.22.0,<=0.23.0)", "torch (>=2.2)", "tqdm (>=4.27)"] -video = ["av"] -vision = ["Pillow (>=10.0.1,<=15.0)"] - -[[package]] -name = "triton" -version = "3.3.1" -description = "A language and compiler for custom Deep Learning operations" -optional = false -python-versions = "*" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.14\"" -files = [ - {file = "triton-3.3.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b74db445b1c562844d3cfad6e9679c72e93fdfb1a90a24052b03bb5c49d1242e"}, - {file = "triton-3.3.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b31e3aa26f8cb3cc5bf4e187bf737cbacf17311e1112b781d4a059353dfd731b"}, - {file = "triton-3.3.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9999e83aba21e1a78c1f36f21bce621b77bcaa530277a50484a7cb4a822f6e43"}, - {file = "triton-3.3.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b89d846b5a4198317fec27a5d3a609ea96b6d557ff44b56c23176546023c4240"}, - {file = "triton-3.3.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3198adb9d78b77818a5388bff89fa72ff36f9da0bc689db2f0a651a67ce6a42"}, - {file = "triton-3.3.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f6139aeb04a146b0b8e0fbbd89ad1e65861c57cfed881f21d62d3cb94a36bab7"}, -] - -[package.dependencies] -setuptools = ">=40.8.0" - -[package.extras] -build = ["cmake (>=3.20)", "lit"] -tests = ["autopep8", "isort", "llnl-hatchet", "numpy", "pytest", "pytest-forked", "pytest-xdist", "scipy (>=1.7.1)"] -tutorials = ["matplotlib", "pandas", "tabulate"] - -[[package]] -name = "triton" -version = "3.5.0" -description = "A language and compiler for custom Deep Learning operations" -optional = false -python-versions = "<3.15,>=3.10" -groups = ["main"] -markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version <= \"3.13\"" -files = [ - {file = "triton-3.5.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f90de6a6566bb619b4c0adc9855729e1b1b5e26533fca1bf6206e96b6d277a3"}, - {file = "triton-3.5.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5d3b3d480debf24eaa739623c9a42446b0b77f95593d30eb1f64cd2278cc1f0"}, - {file = "triton-3.5.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8457b22148defefdcb7fa8144b05ce211b9faefad650a1ce85b23df488d5549c"}, - {file = "triton-3.5.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f34bfa21c5b3a203c0f0eab28dcc1e49bd1f67d22724e77fb6665a659200a4ec"}, - {file = "triton-3.5.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7da21fccceafc163e3a5e857abe34351ef76345af06cabf9637a914742671f0b"}, - {file = "triton-3.5.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9e71db82261c4ffa3921cd050cd5faa18322d2d405c30eb56084afaff3b0833"}, - {file = "triton-3.5.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:188da5b81fa2f8322c27fec1627703eac24cb9bb7ab0dfbe9925973bc1b070d3"}, - {file = "triton-3.5.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e6bb9aa5519c084a333acdba443789e50012a4b851cd486c54f0b8dc2a8d3a12"}, - {file = "triton-3.5.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03127d9b33aaf979c856676b394bc059ec1d68cb6da68ae03f62dd8ad77a04ae"}, - {file = "triton-3.5.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c83f2343e1a220a716c7b3ab9fccfcbe3ad4020d189549200e2d2e8d5868bed9"}, - {file = "triton-3.5.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:468936651d383f4a6d10068d34a627505e13af55be5d002b9f27b987e7a5f0ac"}, - {file = "triton-3.5.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da0fa67ccd76c3dcfb0bffe1b1c57c685136a6bd33d141c24d9655d4185b1289"}, - {file = "triton-3.5.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7ceef21410229ac23173a28eee5cfc0e37c1dfdb8b4bc11ecda2e3ecec7c686"}, - {file = "triton-3.5.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:317fe477ea8fd4524a6a8c499fb0a36984a56d0b75bf9c9cb6133a1c56d5a6e7"}, -] - -[package.extras] -build = ["cmake (>=3.20,<4.0)", "lit"] -tests = ["autopep8", "isort", "llnl-hatchet", "numpy", "pytest", "pytest-forked", "pytest-xdist", "scipy (>=1.7.1)"] -tutorials = ["matplotlib", "pandas", "tabulate"] - -[[package]] -name = "types-requests" -version = "2.32.4.20250913" -description = "Typing stubs for requests" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "types_requests-2.32.4.20250913-py3-none-any.whl", hash = "sha256:78c9c1fffebbe0fa487a418e0fa5252017e9c60d1a2da394077f1780f655d7e1"}, - {file = "types_requests-2.32.4.20250913.tar.gz", hash = "sha256:abd6d4f9ce3a9383f269775a9835a4c24e5cd6b9f647d64f88aa4613c33def5d"}, -] - -[package.dependencies] -urllib3 = ">=2" - -[[package]] -name = "typing-extensions" -version = "4.15.0" -description = "Backported and Experimental Type Hints for Python 3.9+" -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, - {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, -] - -[[package]] -name = "typing-inspect" -version = "0.9.0" -description = "Runtime inspection utilities for typing module." -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, - {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, -] - -[package.dependencies] -mypy-extensions = ">=0.3.0" -typing-extensions = ">=3.7.4" - -[[package]] -name = "typing-inspection" -version = "0.4.2" -description = "Runtime typing introspection tools" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, - {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, -] - -[package.dependencies] -typing-extensions = ">=4.12.0" - -[[package]] -name = "tzdata" -version = "2025.2" -description = "Provider of IANA time zone data" -optional = false -python-versions = ">=2" -groups = ["main", "dev"] -files = [ - {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, - {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, -] - -[[package]] -name = "uri-template" -version = "1.3.0" -description = "RFC 6570 URI Template Processor" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7"}, - {file = "uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363"}, -] - -[package.extras] -dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake8-commas", "flake8-comprehensions", "flake8-continuation", "flake8-datetimez", "flake8-docstrings", "flake8-import-order", "flake8-literal", "flake8-modern-annotations", "flake8-noqa", "flake8-pyproject", "flake8-requirements", "flake8-typechecking-import", "flake8-use-fstring", "mypy", "pep8-naming", "types-PyYAML"] - -[[package]] -name = "urllib3" -version = "2.5.0" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, - {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, -] - -[package.extras] -brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "wcwidth" -version = "0.2.14" -description = "Measures the displayed width of unicode strings in a terminal" -optional = false -python-versions = ">=3.6" -groups = ["dev"] -files = [ - {file = "wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1"}, - {file = "wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605"}, -] - -[[package]] -name = "webcolors" -version = "25.10.0" -description = "A library for working with the color formats defined by HTML and CSS." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d"}, - {file = "webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf"}, -] - -[[package]] -name = "webencodings" -version = "0.5.1" -description = "Character encoding aliases for legacy web content" -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, - {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, -] - -[[package]] -name = "websocket-client" -version = "1.9.0" -description = "WebSocket client for Python with low level API options" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef"}, - {file = "websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98"}, -] - -[package.extras] -docs = ["Sphinx (>=6.0)", "myst-parser (>=2.0.0)", "sphinx_rtd_theme (>=1.1.0)"] -optional = ["python-socks", "wsaccel"] -test = ["pytest", "websockets"] - -[[package]] -name = "widgetsnbextension" -version = "4.0.14" -description = "Jupyter interactive widgets for Jupyter Notebook" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "widgetsnbextension-4.0.14-py3-none-any.whl", hash = "sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575"}, - {file = "widgetsnbextension-4.0.14.tar.gz", hash = "sha256:a3629b04e3edb893212df862038c7232f62973373869db5084aed739b437b5af"}, -] - -[[package]] -name = "word2number" -version = "1.1" -description = "Convert number words eg. three hundred and forty two to numbers (342)." -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "word2number-1.1.zip", hash = "sha256:70e27a5d387f67b04c71fbb7621c05930b19bfd26efd6851e6e0f9969dcde7d0"}, -] - -[[package]] -name = "xlsxwriter" -version = "3.2.9" -description = "A Python module for creating Excel XLSX files." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "xlsxwriter-3.2.9-py3-none-any.whl", hash = "sha256:9a5db42bc5dff014806c58a20b9eae7322a134abb6fce3c92c181bfb275ec5b3"}, - {file = "xlsxwriter-3.2.9.tar.gz", hash = "sha256:254b1c37a368c444eac6e2f867405cc9e461b0ed97a3233b2ac1e574efb4140c"}, -] - -[[package]] -name = "yarl" -version = "1.22.0" -description = "Yet another URL library" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e"}, - {file = "yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f"}, - {file = "yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf"}, - {file = "yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a"}, - {file = "yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c"}, - {file = "yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147"}, - {file = "yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb"}, - {file = "yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6"}, - {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0"}, - {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda"}, - {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc"}, - {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737"}, - {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467"}, - {file = "yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea"}, - {file = "yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca"}, - {file = "yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b"}, - {file = "yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511"}, - {file = "yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6"}, - {file = "yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028"}, - {file = "yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d"}, - {file = "yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503"}, - {file = "yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65"}, - {file = "yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e"}, - {file = "yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d"}, - {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7"}, - {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967"}, - {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed"}, - {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6"}, - {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e"}, - {file = "yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca"}, - {file = "yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b"}, - {file = "yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376"}, - {file = "yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f"}, - {file = "yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2"}, - {file = "yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74"}, - {file = "yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df"}, - {file = "yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb"}, - {file = "yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2"}, - {file = "yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82"}, - {file = "yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a"}, - {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124"}, - {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa"}, - {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7"}, - {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d"}, - {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520"}, - {file = "yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8"}, - {file = "yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c"}, - {file = "yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74"}, - {file = "yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53"}, - {file = "yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a"}, - {file = "yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c"}, - {file = "yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601"}, - {file = "yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a"}, - {file = "yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df"}, - {file = "yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2"}, - {file = "yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b"}, - {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273"}, - {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a"}, - {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d"}, - {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02"}, - {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67"}, - {file = "yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95"}, - {file = "yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d"}, - {file = "yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b"}, - {file = "yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10"}, - {file = "yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3"}, - {file = "yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9"}, - {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f"}, - {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0"}, - {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e"}, - {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708"}, - {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f"}, - {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d"}, - {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8"}, - {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5"}, - {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f"}, - {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62"}, - {file = "yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03"}, - {file = "yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249"}, - {file = "yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b"}, - {file = "yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4"}, - {file = "yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683"}, - {file = "yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b"}, - {file = "yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e"}, - {file = "yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590"}, - {file = "yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2"}, - {file = "yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da"}, - {file = "yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784"}, - {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b"}, - {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694"}, - {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d"}, - {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd"}, - {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da"}, - {file = "yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2"}, - {file = "yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79"}, - {file = "yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33"}, - {file = "yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1"}, - {file = "yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca"}, - {file = "yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53"}, - {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c"}, - {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf"}, - {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face"}, - {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b"}, - {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486"}, - {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138"}, - {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a"}, - {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529"}, - {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093"}, - {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c"}, - {file = "yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e"}, - {file = "yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27"}, - {file = "yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1"}, - {file = "yarl-1.22.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3aa27acb6de7a23785d81557577491f6c38a5209a254d1191519d07d8fe51748"}, - {file = "yarl-1.22.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:af74f05666a5e531289cb1cc9c883d1de2088b8e5b4de48004e5ca8a830ac859"}, - {file = "yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:62441e55958977b8167b2709c164c91a6363e25da322d87ae6dd9c6019ceecf9"}, - {file = "yarl-1.22.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b580e71cac3f8113d3135888770903eaf2f507e9421e5697d6ee6d8cd1c7f054"}, - {file = "yarl-1.22.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e81fda2fb4a07eda1a2252b216aa0df23ebcd4d584894e9612e80999a78fd95b"}, - {file = "yarl-1.22.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:99b6fc1d55782461b78221e95fc357b47ad98b041e8e20f47c1411d0aacddc60"}, - {file = "yarl-1.22.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:088e4e08f033db4be2ccd1f34cf29fe994772fb54cfe004bbf54db320af56890"}, - {file = "yarl-1.22.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e4e1f6f0b4da23e61188676e3ed027ef0baa833a2e633c29ff8530800edccba"}, - {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:84fc3ec96fce86ce5aa305eb4aa9358279d1aa644b71fab7b8ed33fe3ba1a7ca"}, - {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5dbeefd6ca588b33576a01b0ad58aa934bc1b41ef89dee505bf2932b22ddffba"}, - {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14291620375b1060613f4aab9ebf21850058b6b1b438f386cc814813d901c60b"}, - {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:a4fcfc8eb2c34148c118dfa02e6427ca278bfd0f3df7c5f99e33d2c0e81eae3e"}, - {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:029866bde8d7b0878b9c160e72305bbf0a7342bcd20b9999381704ae03308dc8"}, - {file = "yarl-1.22.0-cp39-cp39-win32.whl", hash = "sha256:4dcc74149ccc8bba31ce1944acee24813e93cfdee2acda3c172df844948ddf7b"}, - {file = "yarl-1.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:10619d9fdee46d20edc49d3479e2f8269d0779f1b031e6f7c2aa1c76be04b7ed"}, - {file = "yarl-1.22.0-cp39-cp39-win_arm64.whl", hash = "sha256:dd7afd3f8b0bfb4e0d9fc3c31bfe8a4ec7debe124cfd90619305def3c8ca8cd2"}, - {file = "yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff"}, - {file = "yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71"}, -] - -[package.dependencies] -idna = ">=2.0" -multidict = ">=4.0" -propcache = ">=0.2.1" - -[[package]] -name = "zstandard" -version = "0.25.0" -description = "Zstandard bindings for Python" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "zstandard-0.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e59fdc271772f6686e01e1b3b74537259800f57e24280be3f29c8a0deb1904dd"}, - {file = "zstandard-0.25.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4d441506e9b372386a5271c64125f72d5df6d2a8e8a2a45a0ae09b03cb781ef7"}, - {file = "zstandard-0.25.0-cp310-cp310-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:ab85470ab54c2cb96e176f40342d9ed41e58ca5733be6a893b730e7af9c40550"}, - {file = "zstandard-0.25.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e05ab82ea7753354bb054b92e2f288afb750e6b439ff6ca78af52939ebbc476d"}, - {file = "zstandard-0.25.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:78228d8a6a1c177a96b94f7e2e8d012c55f9c760761980da16ae7546a15a8e9b"}, - {file = "zstandard-0.25.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2b6bd67528ee8b5c5f10255735abc21aa106931f0dbaf297c7be0c886353c3d0"}, - {file = "zstandard-0.25.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4b6d83057e713ff235a12e73916b6d356e3084fd3d14ced499d84240f3eecee0"}, - {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9174f4ed06f790a6869b41cba05b43eeb9a35f8993c4422ab853b705e8112bbd"}, - {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:25f8f3cd45087d089aef5ba3848cd9efe3ad41163d3400862fb42f81a3a46701"}, - {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3756b3e9da9b83da1796f8809dd57cb024f838b9eeafde28f3cb472012797ac1"}, - {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:81dad8d145d8fd981b2962b686b2241d3a1ea07733e76a2f15435dfb7fb60150"}, - {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a5a419712cf88862a45a23def0ae063686db3d324cec7edbe40509d1a79a0aab"}, - {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e7360eae90809efd19b886e59a09dad07da4ca9ba096752e61a2e03c8aca188e"}, - {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:75ffc32a569fb049499e63ce68c743155477610532da1eb38e7f24bf7cd29e74"}, - {file = "zstandard-0.25.0-cp310-cp310-win32.whl", hash = "sha256:106281ae350e494f4ac8a80470e66d1fe27e497052c8d9c3b95dc4cf1ade81aa"}, - {file = "zstandard-0.25.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea9d54cc3d8064260114a0bbf3479fc4a98b21dffc89b3459edd506b69262f6e"}, - {file = "zstandard-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:933b65d7680ea337180733cf9e87293cc5500cc0eb3fc8769f4d3c88d724ec5c"}, - {file = "zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3f79487c687b1fc69f19e487cd949bf3aae653d181dfb5fde3bf6d18894706f"}, - {file = "zstandard-0.25.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:0bbc9a0c65ce0eea3c34a691e3c4b6889f5f3909ba4822ab385fab9057099431"}, - {file = "zstandard-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01582723b3ccd6939ab7b3a78622c573799d5d8737b534b86d0e06ac18dbde4a"}, - {file = "zstandard-0.25.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5f1ad7bf88535edcf30038f6919abe087f606f62c00a87d7e33e7fc57cb69fcc"}, - {file = "zstandard-0.25.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:06acb75eebeedb77b69048031282737717a63e71e4ae3f77cc0c3b9508320df6"}, - {file = "zstandard-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9300d02ea7c6506f00e627e287e0492a5eb0371ec1670ae852fefffa6164b072"}, - {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfd06b1c5584b657a2892a6014c2f4c20e0db0208c159148fa78c65f7e0b0277"}, - {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f373da2c1757bb7f1acaf09369cdc1d51d84131e50d5fa9863982fd626466313"}, - {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c0e5a65158a7946e7a7affa6418878ef97ab66636f13353b8502d7ea03c8097"}, - {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c8e167d5adf59476fa3e37bee730890e389410c354771a62e3c076c86f9f7778"}, - {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:98750a309eb2f020da61e727de7d7ba3c57c97cf6213f6f6277bb7fb42a8e065"}, - {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22a086cff1b6ceca18a8dd6096ec631e430e93a8e70a9ca5efa7561a00f826fa"}, - {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72d35d7aa0bba323965da807a462b0966c91608ef3a48ba761678cb20ce5d8b7"}, - {file = "zstandard-0.25.0-cp311-cp311-win32.whl", hash = "sha256:f5aeea11ded7320a84dcdd62a3d95b5186834224a9e55b92ccae35d21a8b63d4"}, - {file = "zstandard-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:daab68faadb847063d0c56f361a289c4f268706b598afbf9ad113cbe5c38b6b2"}, - {file = "zstandard-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:22a06c5df3751bb7dc67406f5374734ccee8ed37fc5981bf1ad7041831fa1137"}, - {file = "zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b"}, - {file = "zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00"}, - {file = "zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64"}, - {file = "zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea"}, - {file = "zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb"}, - {file = "zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a"}, - {file = "zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902"}, - {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f"}, - {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b"}, - {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6"}, - {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91"}, - {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708"}, - {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512"}, - {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa"}, - {file = "zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd"}, - {file = "zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01"}, - {file = "zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9"}, - {file = "zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94"}, - {file = "zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1"}, - {file = "zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f"}, - {file = "zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea"}, - {file = "zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e"}, - {file = "zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551"}, - {file = "zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a"}, - {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611"}, - {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3"}, - {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b"}, - {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851"}, - {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250"}, - {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98"}, - {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf"}, - {file = "zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09"}, - {file = "zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5"}, - {file = "zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049"}, - {file = "zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3"}, - {file = "zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f"}, - {file = "zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c"}, - {file = "zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439"}, - {file = "zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043"}, - {file = "zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859"}, - {file = "zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0"}, - {file = "zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7"}, - {file = "zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2"}, - {file = "zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344"}, - {file = "zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c"}, - {file = "zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088"}, - {file = "zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12"}, - {file = "zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2"}, - {file = "zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d"}, - {file = "zstandard-0.25.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b9af1fe743828123e12b41dd8091eca1074d0c1569cc42e6e1eee98027f2bbd0"}, - {file = "zstandard-0.25.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b14abacf83dfb5c25eb4e4a79520de9e7e205f72c9ee7702f91233ae57d33a2"}, - {file = "zstandard-0.25.0-cp39-cp39-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:a51ff14f8017338e2f2e5dab738ce1ec3b5a851f23b18c1ae1359b1eecbee6df"}, - {file = "zstandard-0.25.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3b870ce5a02d4b22286cf4944c628e0f0881b11b3f14667c1d62185a99e04f53"}, - {file = "zstandard-0.25.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:05353cef599a7b0b98baca9b068dd36810c3ef0f42bf282583f438caf6ddcee3"}, - {file = "zstandard-0.25.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:19796b39075201d51d5f5f790bf849221e58b48a39a5fc74837675d8bafc7362"}, - {file = "zstandard-0.25.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:53e08b2445a6bc241261fea89d065536f00a581f02535f8122eba42db9375530"}, - {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1f3689581a72eaba9131b1d9bdbfe520ccd169999219b41000ede2fca5c1bfdb"}, - {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d8c56bb4e6c795fc77d74d8e8b80846e1fb8292fc0b5060cd8131d522974b751"}, - {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:53f94448fe5b10ee75d246497168e5825135d54325458c4bfffbaafabcc0a577"}, - {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c2ba942c94e0691467ab901fc51b6f2085ff48f2eea77b1a48240f011e8247c7"}, - {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:07b527a69c1e1c8b5ab1ab14e2afe0675614a09182213f21a0717b62027b5936"}, - {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:51526324f1b23229001eb3735bc8c94f9c578b1bd9e867a0a646a3b17109f388"}, - {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89c4b48479a43f820b749df49cd7ba2dbc2b1b78560ecb5ab52985574fd40b27"}, - {file = "zstandard-0.25.0-cp39-cp39-win32.whl", hash = "sha256:1cd5da4d8e8ee0e88be976c294db744773459d51bb32f707a0f166e5ad5c8649"}, - {file = "zstandard-0.25.0-cp39-cp39-win_amd64.whl", hash = "sha256:37daddd452c0ffb65da00620afb8e17abd4adaae6ce6310702841760c2c26860"}, - {file = "zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b"}, -] - -[package.extras] -cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and python_version < \"3.14\"", "cffi (>=2.0.0b) ; platform_python_implementation != \"PyPy\" and python_version >= \"3.14\""] - -[metadata] -lock-version = "2.1" -python-versions = "^3.12" -content-hash = "3f82f89f27294f328c93d31edd8d64df332af6ac7f390b379d1a8f4a00cc9258" diff --git a/fieldExtraction/pyproject.toml b/fieldExtraction/pyproject.toml deleted file mode 100644 index bceaf7f..0000000 --- a/fieldExtraction/pyproject.toml +++ /dev/null @@ -1,62 +0,0 @@ -[tool.poetry] -name = "doczy-field-extraction" -version = "0.1.0" -description = "" -authors = ["Alex Galarce "] -readme = "README.md" -package-mode = false - -[tool.poetry.dependencies] -python = "^3.12" -pandas = "^2.2.3" -boto3 = "^1.35.40" -anthropic = "^0.36.0" -python-dotenv = "^1.0.1" -psutil = "^6.1.0" -rapidfuzz = "^3.10.1" -pyxlsb = "^1.0.10" -openpyxl = "^3.1.5" -pytest-mock = "^3.14.0" -langchain = "^0.3.14" -langchainhub = "^0.1.21" -langchain-aws = "^0.2.11" -langchain-text-splitters = "^0.3.5" -langchain-community = "^0.3.15" -nltk = "^3.9.1" -rank-bm25 = "^0.2.2" -sentence-transformers = "^3.4.1" -faiss-cpu = "^1.10.0" -word2number = "^1.1" -orjson = "^3.10.16" -pymupdf = "^1.25.5" -pillow = "^11.2.1" -xlsxwriter = "^3.2.9" - -[tool.poetry.group.dev.dependencies] -black = "^24.10.0" -mypy = "^1.12.0" -jupyter = "^1.1.1" -isort = "^5.13.2" - -[tool.poetry.group.test.dependencies] -pytest = "^8.3.3" -pytest-mock = "^3.14.0" -pytest-cov = "^6.0.0" - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" - -[tool.black] -line-length = 88 -target-version = ['py312'] - -[tool.mypy] -disable_error_code = ["import-untyped","assignment","name-defined","call-arg","var-annotated","attr-defined","arg-type"] -exclude = ["scripts/"] - -[tool.pytest.ini_options] -pythonpath=["."] -testpaths = [ - "tests" -] diff --git a/fieldExtraction/release/Dockerfile b/fieldExtraction/release/Dockerfile deleted file mode 100644 index 7eba78f..0000000 --- a/fieldExtraction/release/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -# syntax=docker/dockerfile:1 - -ARG PYTHON_VERSION=3.12.7 -FROM python:${PYTHON_VERSION} - -# Prevents Python from writing pyc files. -ENV PYTHONDONTWRITEBYTECODE=1 - -# Keeps Python from buffering stdout and stderr to avoid situations where -# the application crashes without emitting any logs due to buffering. -ENV PYTHONUNBUFFERED=1 - -RUN --mount=type=cache,target=/root/.cache/pip \ - python -m pip install poetry - -WORKDIR /app - -COPY pyproject.toml . -COPY poetry.lock . - -RUN --mount=type=cache,target=/root/.cache/pip \ - poetry install --only main --compile - -COPY src/ src/ - -COPY constants/ constants/ - -COPY embeddings/ embeddings/ - -CMD [ "poetry", "run", "python", "src/main.py" ] diff --git a/fieldExtraction/src/investment/exhibit_funcs.py b/fieldExtraction/src/investment/exhibit_funcs.py deleted file mode 100644 index 4e31519..0000000 --- a/fieldExtraction/src/investment/exhibit_funcs.py +++ /dev/null @@ -1,143 +0,0 @@ -""" -Exhibit class for tracking exhibit state during one-to-n processing. - -This module provides the Exhibit class which maintains all state and field values -for a single exhibit during field extraction, including a linked list structure -for propagating dynamic fields from exhibit n-1 to exhibit n. -""" - -from typing import Optional - -from src.prompts.fieldset import FieldSet - - -class Exhibit: - """ - Tracks all state and field values for a single exhibit during processing. - - Maintains a linked list structure via prev_exhibit to enable field propagation - from exhibit n-1 to exhibit n during dynamic assignment. - - Attributes: - exhibit_page (str): The page number where this exhibit starts - exhibit_page_nums (list[str]): All page numbers that belong to this exhibit - exhibit_header (str): The header text of the exhibit - exhibit_text (str): The full text content of the exhibit - num_pages (int): Number of pages in this exhibit - prev_exhibit (Optional[Exhibit]): Pointer to the previous exhibit (n-1) - dynamic_primary_fields (FieldSet): Dynamic primary fields from exhibit_level - dynamic_reimbursement_fields (FieldSet): Dynamic reimbursement fields from exhibit_level - exhibit_level_answers (dict): Exhibit-level field answers - reimbursement_rows (list[dict]): Reimbursement rows from page processing - special_case_rows (list[dict]): Special case rows from page processing - has_reimbursements (bool): Whether this exhibit has any reimbursements - final_rows (list[dict]): Final combined and cleaned rows - """ - - def __init__(self, exhibit_page: str, exhibit_page_nums: list[str], - exhibit_header: str, exhibit_text: str, prev_exhibit: Optional['Exhibit'] = None): - """ - Initialize a new Exhibit instance. - - Args: - exhibit_page: The starting page number for this exhibit - exhibit_page_nums: List of all page numbers in this exhibit - exhibit_header: The header text of the exhibit - exhibit_text: The full text content of the exhibit - prev_exhibit: Optional pointer to the previous exhibit for field propagation - """ - # Basic exhibit metadata - self.exhibit_page = exhibit_page - self.exhibit_page_nums = exhibit_page_nums - self.exhibit_header = exhibit_header - self.exhibit_text = exhibit_text - self.num_pages = len(exhibit_page_nums) - - # Linked list for exhibit chain - self.prev_exhibit = prev_exhibit - - # Field tracking (populated in Step 2) - self.dynamic_primary_fields = FieldSet() - self.dynamic_reimbursement_fields = FieldSet() - self.exhibit_level_answers = {} - - # Reimbursement data (populated in Step 1) - self.reimbursement_rows = [] - self.special_case_rows = [] - self.has_reimbursements = False - - # Final combined rows (populated in Step 3) - self.final_rows = [] - - def add_reimbursement_rows(self, reimbursement_rows: list[dict], special_case_rows: list[dict]): - """ - Add reimbursement rows from page processing. - - This is called during Step 1 (parallel page processing) to accumulate - reimbursement and special case rows from all pages in this exhibit. - - Args: - reimbursement_rows: List of reimbursement dictionaries from a page - special_case_rows: List of special case dictionaries from a page - """ - self.reimbursement_rows.extend(reimbursement_rows) - self.special_case_rows.extend(special_case_rows) - self.has_reimbursements = len(reimbursement_rows) > 0 or len(special_case_rows) > 0 - - def set_exhibit_level_data(self, exhibit_level_answers: dict, dynamic_reimbursement_fields: FieldSet): - """ - Set exhibit-level field data from exhibit_level processing. - - This is called during Step 2 (exhibit-level processing) to store the - exhibit-level answers and dynamic fields that will be used in Step 3. - - Args: - exhibit_level_answers: Dictionary of exhibit-level field answers - dynamic_reimbursement_fields: FieldSet of dynamic reimbursement fields - """ - self.exhibit_level_answers = exhibit_level_answers - self.dynamic_reimbursement_fields = dynamic_reimbursement_fields - - # Extract dynamic primary fields from exhibit level answers - # These are the fields that can be propagated to next exhibit - self.dynamic_primary_fields = dynamic_reimbursement_fields - - def get_previous_exhibit_dynamic_fields(self) -> FieldSet: - """ - Get dynamic primary fields from previous exhibit (n-1) if available. - - This enables field propagation across exhibits, allowing exhibit n to - inherit dynamic fields from exhibit n-1 when appropriate. - - Returns: - FieldSet: The previous exhibit's dynamic primary fields, or an empty - FieldSet if there is no previous exhibit - """ - if self.prev_exhibit is not None: - return self.prev_exhibit.dynamic_primary_fields - return FieldSet() - - def __repr__(self): - """String representation for debugging.""" - return (f"Exhibit(page={self.exhibit_page}, pages={len(self.exhibit_page_nums)}, " - f"has_reimb={self.has_reimbursements}, reimb_count={len(self.reimbursement_rows)})") - - - -def get_exhibit_list(text_dict: dict[str, str], exhibit_chunk_mapping: dict[str, str], all_exhibit_headers: dict[str, str]) -> list[Exhibit]: - exhibits = [] - prev_exhibit = None - for exhibit_page, exhibit_page_nums in exhibit_chunk_mapping.items(): - exhibit_text = "\n".join([text_dict[page_num] for page_num in exhibit_page_nums]) - exhibit_header = all_exhibit_headers.get(exhibit_page, "") - exhibit = Exhibit( - exhibit_page=exhibit_page, - exhibit_page_nums=exhibit_page_nums, - exhibit_header=exhibit_header, - exhibit_text=exhibit_text, - prev_exhibit=prev_exhibit - ) - exhibits.append(exhibit) - prev_exhibit = exhibit - return exhibits - diff --git a/fieldExtraction/src/investment/preprocessing_funcs.py b/fieldExtraction/src/investment/preprocessing_funcs.py deleted file mode 100644 index 167d9fe..0000000 --- a/fieldExtraction/src/investment/preprocessing_funcs.py +++ /dev/null @@ -1,319 +0,0 @@ -import logging -import re - -import src.utils.string_utils as string_utils -from src.investment import prompt_calls - -def remove_page_indicators(contract_text: str) -> str: - """Clean textract output by removing page number indicators in the form of "Page X of Y" - - This function processes input text to remove lines that indicate page numbers (e.g. 'Page 1 of 10') - - Args: - contract_text (str): Raw text output from Textract to be cleaned - - Returns: - str: cleaned text with newlines and page number indicators removed - """ - - if contract_text: - cleaned_text = re.sub(r"Page [0-9]+ of [0-9]+\n\n", " ", contract_text) - else: - cleaned_text = contract_text - return cleaned_text - - -def split_text(text: str) -> dict[str, str]: - """Split text on pages by the string `Start of Page No. = ' - - Args: - text (str): Raw text output from Textract to be split - - Returns: - dict[str, str]: A dictionary, keyed by the string page number and valued by the page text. - """ - temp_list = text.split("Start of Page No. = ") - text_list = re.split(r"Start of Page No. = [0-9]+\n", text) - - text_dict = {} - for i in range(len(text_list)): - if temp_list[i]: - text_dict[temp_list[i].split()[0]] = text_list[ - i - ] # splits on whitespace characters, which includes spaces, tabs, and newline characters - - return {k: v for k, v in text_dict.items() if k != "Document"} - - -def clean_law_symbols(contract_text): - if not contract_text: - return contract_text - # First correction: Replace '$$' with '$' - contract_text = contract_text.replace("$$", "$") - - contract_text = re.sub( - r"(U\.?S\.?C\.?) \$", r"\1§", contract_text - ) # replaces $ with § when it follows abbreviations like "U.S.C." (United States Code). - contract_text = re.sub( - r"(C\.?F\.?R\.?) \$", r"\1§", contract_text - ) # replaces $ with § when it follows abbreviations like "C.F.R." (Code of Federal Regulations). - - # Second correction: Replace '$' with '§' when followed by a number with three decimal places - contract_text = re.sub(r"\$(?=\d+\.\d{3})", "§", contract_text) - - return contract_text - -def clean_newlines(contract_text: str) -> str: - """Clean textract output by removing newlines and page number indicators. - - This function processes input text to: - 1. Remove all newline characters. - 2. Remove lines that indicate page numbers (e.g. 'Page 1 of 10') - - Args: - contract_text (str): Raw text output from Textract to be cleaned - - Returns: - str: cleaned text with newlines and page number indicators removed - """ - cleaned_text = re.sub(r"(? tuple[list[str], dict[str, str]]: - """ - Identify exhibit pages from the text dictionary. - This function processes the text dictionary to identify pages that are considered exhibits. - It uses the first page as an exhibit and checks subsequent pages for exhibit headers. - If a page is identified as an exhibit, it is added to the exhibit pages list and its header is stored in the exhibit header dictionary. - If a page does not have a header or is not an exhibit, it is skipped. - Args: - text_dict (dict[str, str]): A dictionary where keys are page numbers (as strings) and values are the text of those pages. - filename (str): The name of the file being processed, used for logging and LLM invocation. - Returns: - tuple[list[str], dict[str, str]]: A tuple containing: - - A list of page numbers (as strings) that are identified as exhibit pages. - - A dictionary where keys are page numbers and values are the headers of those exhibits. - """ - sorted_pages = sorted(text_dict.keys(), key=string_utils.page_key_sort) - exhibit_pages = [] - exhibit_header_dict = {} - - for page_num in sorted_pages: - page_content = text_dict[page_num] - if "." not in page_num or ".0" in page_num: - exhibit_header = prompt_calls.prompt_exhibit_header(page_content, EXHIBIT_HEADER_MARKERS, filename) - if "N/A" in exhibit_header: - is_exhibit = False - else: - exhibit_pages.append(page_num) - exhibit_header_dict[page_num] = exhibit_header - is_exhibit = True - elif is_exhibit == True: - exhibit_pages.append(page_num) - return exhibit_pages, exhibit_header_dict - - -def link_exhibit_pages( - all_exhibit_headers: dict[str, str], text_dict: dict[str, str], filename: str -): - """ - Filters exhibit pages to include only those with meaningfully different headers. - This function processes exhibit headers sequentially and uses literal comparison and - LLM-based semantic comparison to determine when exhibits represent continuation pages - vs. distinct exhibits. Continuation pages are filtered out of the headers list and - mapping, and when used downstream are included in their parent exhibit's text chunk. - Links exhibit pages based on their headers. If the header of a page is identical (either literally or semantically) to the previous page's header, it is not added to the final list of exhibit pages. - This function will link contiguous header pages together, so that the final list of exhibit pages will only contain pages that are meaningfully different from the previous page. E.g. "1" with header {"Exhibit 1"} and "2" with header {"Continued exhibit 1"} will be linked together, but "3" with header {"Exhibit 2"} will not be linked to either of them. - Args: - all_exhibit_headers (dict[str, str]): A dictionary mapping page numbers (as strings) to their exhibit headers. Expected to be in chronological order - text_dict (dict[str, str]): A dictionary mapping page numbers to their text content. - filename (str): The name of the file being processed, used for logging and LLM invocation. - Returns: - tuple[list[str], dict[str, str]]: A tuple containing: - - A list of page numbers (as strings) that are identified as exhibit pages. - - A dictionary where keys are page numbers and values are the headers of those exhibits. - Example: - Input: {"1": "Exhibit A", "2": "Exhibit A (continued)", "3": "Exhibit B"} - Output (["1", "3"], {"1": "Exhibit A", "3": "Exhibit B"}) - Notes: - - First exhibit page is always included. - - Literal header comparison is performed first to optimize LLM usage and latency. - - Uses `EXHIBIT_LINKAGE` prompt for semantic similarity assessment - - Expects LLM to return "Y" or "N" enclosed in pipe delimiters - - Pages with non-distinct headers are excluded from the final results. - """ - first_exhibit = True - final_exhibit_pages = [] - final_exhibit_headers = {} - for page_num, page_header in all_exhibit_headers.items(): - if first_exhibit: - exhibit_is_different = "N" - previous_header = page_header - final_exhibit_pages.append(page_num) - final_exhibit_headers[page_num] = page_header - first_exhibit = False - else: - # If literally identical, skip prompt (unless it has a table) - if page_header.upper().strip() == previous_header.upper().strip(): - exhibit_is_different = "N" - elif string_utils.is_empty(previous_header): - exhibit_is_different = "Y" - previous_header = page_header - else: - exhibit_is_different = prompt_calls.prompt_exhibit_linkage(page_header, previous_header, filename) - previous_header = page_header - - # If the prompt has identified that the current exhibit is meaningfully different than the previous - if "Y" in exhibit_is_different: - final_exhibit_pages.append(page_num) - final_exhibit_headers[page_num] = page_header - - return final_exhibit_pages, final_exhibit_headers - - -def chunk_by_exhibit(text_dict: dict, exhibit_pages: list) -> dict: - """ - Organizes pages into groups based on their association with specific exhibits. - - This function assigns each page number from the `text_dict` dictionary to an exhibit - based on the `exhibit_pages` list. Pages are grouped under the nearest preceding - page number in `exhibit_pages`. If a page number in `text_dict` is itself in - `exhibit_pages`, it starts a new exhibit group. - - Parameters: - text_dict (dict): A dictionary where keys are page numbers and values are page text - exhibit_pages (list): A list of page numbers that mark the beginning of a new - exhibit. - - Returns: - dict: A dictionary where keys are exhibit identifiers (page numbers from exhibit_pages) - and values are lists of page numbers that belong to that exhibit. - Example: {'1': ['1', '2'], '3': ['3', '4', '5']} - """ - if len(exhibit_pages) == 0: - return {key: [key] for key in text_dict.keys()} - - exhibit_chunk_mapping = {} - current_exhibit = list(text_dict.keys())[0] - - for page_num in text_dict.keys(): - if page_num in exhibit_pages: - current_exhibit = page_num - # Initialize the list for this exhibit if not already present - if current_exhibit not in exhibit_chunk_mapping: - exhibit_chunk_mapping[current_exhibit] = [] - - # Add the page to the current exhibit's list - if current_exhibit not in exhibit_chunk_mapping: - exhibit_chunk_mapping[current_exhibit] = [] - exhibit_chunk_mapping[current_exhibit].append(page_num) - - return exhibit_chunk_mapping - -def simplify_exhibit(text_dict: dict[str, str], exhibit_page_nums: list[str], current_page_num: str) -> str: - """ - Simplify exhibit text by replacing table content with 'Table X' placeholders on all pages - except the current page being processed. - - Args: - text_dict: Dictionary mapping page numbers to page text - exhibit_page_nums: List of page numbers that belong to this exhibit - current_page_num: The current page being processed (will NOT be simplified) - - Returns: - str: The exhibit text with tables simplified on all pages except current_page_num - """ - def replace_tables_with_placeholder(page_text: str, starting_table_num: int) -> tuple[str, int]: - """Replace table blocks with 'Table X' labels and return next table number.""" - if not page_text: - return page_text, starting_table_num - - start_marker = "-------Table Start--------" - end_marker = "-------Table End--------" - result = [] - pos = 0 - table_num = starting_table_num - - while True: - start_idx = page_text.find(start_marker, pos) - if start_idx == -1: - # No more tables, append remaining text - result.append(page_text[pos:]) - break - - # Append text before table - result.append(page_text[pos:start_idx]) - - # Find end of table - end_idx = page_text.find(end_marker, start_idx + len(start_marker)) - - # Replace table with placeholder - result.append(f"Table {table_num}") - table_num += 1 - - # Move position past the table end marker - if end_idx != -1: - pos = end_idx + len(end_marker) - else: - # No end marker found, stop processing - break - - return "".join(result), table_num - - # Process each page in the exhibit - simplified_exhibit_pages = [] - table_counter = 1 - - for page_num in exhibit_page_nums: - page_text = text_dict.get(page_num, "") - - if page_num == current_page_num: - # Don't simplify the current page - keep it as-is - simplified_exhibit_pages.append(page_text) - # But still need to count tables to keep numbering consistent - if "-------Table Start--------" in page_text: - _, table_counter = replace_tables_with_placeholder(page_text, table_counter) - else: - # Simplify other pages by replacing tables with placeholders - if "-------Table Start--------" in page_text: - simplified_page, table_counter = replace_tables_with_placeholder(page_text, table_counter) - simplified_exhibit_pages.append(simplified_page) - else: - simplified_exhibit_pages.append(page_text) - - return "\n".join(simplified_exhibit_pages) \ No newline at end of file diff --git a/fieldExtraction/tests/test_exhibit_funcs.py b/fieldExtraction/tests/test_exhibit_funcs.py deleted file mode 100644 index b079cca..0000000 --- a/fieldExtraction/tests/test_exhibit_funcs.py +++ /dev/null @@ -1,29 +0,0 @@ -from src.investment.exhibit_funcs import Exhibit, get_exhibit_list -from src.prompts.fieldset import FieldSet - - -def test_add_reimbursement_rows_sets_flag(): - exhibit = Exhibit(exhibit_page="1", exhibit_page_nums=["1"], exhibit_header="H", exhibit_text="text") - exhibit.add_reimbursement_rows([{"a": 1}], []) - assert exhibit.has_reimbursements is True - assert len(exhibit.reimbursement_rows) == 1 - - -def test_set_exhibit_level_and_previous_dynamic_fields(): - prev = Exhibit(exhibit_page="1", exhibit_page_nums=["1"], exhibit_header="H1", exhibit_text="text1") - dyn_fields = FieldSet() - prev.dynamic_primary_fields = dyn_fields - current = Exhibit(exhibit_page="2", exhibit_page_nums=["2"], exhibit_header="H2", exhibit_text="text2", prev_exhibit=prev) - - current.set_exhibit_level_data({"X": "Y"}, FieldSet()) - assert current.exhibit_level_answers["X"] == "Y" - assert current.get_previous_exhibit_dynamic_fields() is dyn_fields - - -def test_get_exhibit_list_links_previous(): - text_dict = {"1": "A", "2": "B"} - mapping = {"1": ["1"], "2": ["2"]} - headers = {"1": "H1", "2": "H2"} - exhibits = get_exhibit_list(text_dict, mapping, headers) - assert len(exhibits) == 2 - assert exhibits[1].prev_exhibit is exhibits[0] diff --git a/fieldExtraction/tests/test_one_to_n.py b/fieldExtraction/tests/test_one_to_n.py deleted file mode 100644 index 724a317..0000000 --- a/fieldExtraction/tests/test_one_to_n.py +++ /dev/null @@ -1,698 +0,0 @@ -import unittest -from unittest.mock import Mock, patch, MagicMock -from src.investment import one_to_n_funcs -from src.prompts.fieldset import FieldSet -from constants.constants import Constants - - -class TestOneToNFuncs(unittest.TestCase): - """Test suite for one_to_n_funcs.py functions.""" - - def setUp(self): - """Set up test fixtures.""" - self.constants = Constants() - self.filename = "test_contract.pdf" - self.exhibit_text = "This is a sample exhibit text with reimbursement terms." - self.exhibit_header = "Exhibit A - Fee Schedule" - self.exhibit_page = "1" - - # ==================== exhibit_level Tests ==================== - - @patch('src.utils.llm_utils.invoke_claude') # Mock at the invoke_claude level - @patch('src.investment.one_to_n_funcs.dynamic_funcs.dynamic_primary') - def test_exhibit_level_basic(self, mock_dynamic_primary, mock_invoke_claude): - """Test basic exhibit level processing.""" - # Mock LLM response for dynamic_primary call - mock_invoke_claude.return_value = '{"AARETE_DERIVED_LOB": "Medicaid", "AARETE_DERIVED_NETWORK": "In-Network"}' - - # Mock dynamic primary returning updated answers and fields - mock_dynamic_fields = Mock(spec=FieldSet) - mock_dynamic_primary.return_value = ( - {"SERVICE_CATEGORY_CD": "INPATIENT", "PROV_TYPE_CD": "HOSPITAL", "AARETE_DERIVED_LOB": "Medicaid"}, - mock_dynamic_fields - ) - - exhibit_level_answers, dynamic_fields = one_to_n_funcs.exhibit_level( - self.exhibit_text, self.exhibit_header, self.exhibit_page, self.constants, self.filename - ) - - # Assertions - assert exhibit_level_answers is not None - mock_invoke_claude.assert_called() - - # ==================== reimbursement_level Tests ==================== - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_reimbursement_primary') - @patch('src.investment.one_to_n_funcs.clean_reimbursement_primary') - def test_reimbursement_level_with_results(self, mock_clean, mock_prompt_reimb): - """Test reimbursement level extraction with valid results.""" - mock_prompt_reimb.return_value = [ - {"SERVICE_TERM": "Lab Services", "REIMB_TERM": "100% of Medicare"}, - {"SERVICE_TERM": "Radiology", "REIMB_TERM": "90% of billed charges"} - ] - mock_clean.return_value = mock_prompt_reimb.return_value - - page_text = "Lab Services will be reimbursed at 100% of Medicare." - result = one_to_n_funcs.reimbursement_level(page_text, self.constants, self.filename) - - self.assertEqual(len(result), 2) - mock_prompt_reimb.assert_called_once_with(page_text, self.filename) - mock_clean.assert_called_once() - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_reimbursement_primary') - def test_reimbursement_level_no_results(self, mock_prompt_reimb): - """Test reimbursement level when no reimbursements found.""" - mock_prompt_reimb.return_value = None - - page_text = "This page has no reimbursement information." - result = one_to_n_funcs.reimbursement_level(page_text, self.constants, self.filename) - - self.assertIsNone(result) - - # ==================== clean_reimbursement_primary Tests ==================== - - @patch('src.investment.one_to_n_funcs.filter_services_without_reimbursements') - def test_clean_reimbursement_primary_basic(self, mock_filter): - """Test basic cleaning of reimbursement primary answers.""" - input_answers = [ - {"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"}, - {"SERVICE_TERM": "X-Ray", "REIMB_TERM": "Fee schedule"} - ] - mock_filter.return_value = input_answers - - result = one_to_n_funcs.clean_reimbursement_primary( - input_answers, self.constants, self.filename - ) - - self.assertEqual(len(result), 2) - mock_filter.assert_called_once_with(input_answers, self.filename) - - def test_clean_reimbursement_primary_empty_input(self): - """Test cleaning with empty input.""" - result = one_to_n_funcs.clean_reimbursement_primary( - [], self.constants, self.filename - ) - self.assertEqual(result, []) - - def test_clean_reimbursement_primary_none_input(self): - """Test cleaning with None input.""" - result = one_to_n_funcs.clean_reimbursement_primary( - None, self.constants, self.filename - ) - self.assertEqual(result, []) - - # ==================== methodology_breakout Tests ==================== - - @patch('src.investment.one_to_n_funcs.methodology_breakout_single_row') - def test_methodology_breakout_multiple_rows(self, mock_single_row): - """Test methodology breakout with multiple rows.""" - mock_single_row.side_effect = [ - [{"SERVICE_TERM": "Labs", "AARETE_DERIVED_REIMB_METHOD": "Fee Schedule"}], - [{"SERVICE_TERM": "Surgery", "AARETE_DERIVED_REIMB_METHOD": "Grouper"}] - ] - - input_answers = [ - {"SERVICE_TERM": "Labs", "REIMB_TERM": "Medicare fee schedule"}, - {"SERVICE_TERM": "Surgery", "REIMB_TERM": "MS-DRG"} - ] - - result = one_to_n_funcs.methodology_breakout( - input_answers, self.constants, self.filename - ) - - self.assertEqual(len(result), 2) - self.assertEqual(mock_single_row.call_count, 2) - - # ==================== methodology_breakout_single_row Tests ==================== - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_methodology_breakout') - @patch('src.investment.one_to_n_funcs.methodology_breakout_secondary') - def test_methodology_breakout_single_row_basic(self, mock_secondary, mock_prompt): - """Test single row methodology breakout.""" - mock_prompt.return_value = { - "AARETE_DERIVED_REIMB_METHOD": "Fee Schedule", - "REIMB_FEE_RATE": "N/A", - "REIMB_PCT_RATE": "100" - } - mock_secondary.return_value = {"FEE_SCHEDULE": "Medicare"} - - answer_dict = {"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"} - - result = one_to_n_funcs.methodology_breakout_single_row( - answer_dict, self.constants, self.filename - ) - - self.assertEqual(len(result), 1) - self.assertIn("AARETE_DERIVED_REIMB_METHOD", result[0]) - self.assertIn("FEE_SCHEDULE", result[0]) - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_methodology_breakout') - def test_methodology_breakout_single_row_no_reimb_term(self, mock_prompt): - """Test single row breakout when REIMB_TERM is missing.""" - answer_dict = {"SERVICE_TERM": "Labs"} - - result = one_to_n_funcs.methodology_breakout_single_row( - answer_dict, self.constants, self.filename - ) - - self.assertEqual(result, [answer_dict]) - mock_prompt.assert_not_called() - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_methodology_breakout') - @patch('src.investment.one_to_n_funcs.methodology_breakout_secondary') - def test_methodology_breakout_single_row_list_output(self, mock_secondary, mock_prompt): - """Test single row breakout when LLM returns list of methodologies.""" - mock_prompt.return_value = [ - {"AARETE_DERIVED_REIMB_METHOD": "Fee Schedule"}, - {"AARETE_DERIVED_REIMB_METHOD": "Per Diem"} - ] - mock_secondary.side_effect = [ - {"FEE_SCHEDULE": "Medicare"}, - {"FEE_SCHEDULE": "N/A"} - ] - - answer_dict = {"SERVICE_TERM": "Labs", "REIMB_TERM": "Medicare or $500 per day"} - - result = one_to_n_funcs.methodology_breakout_single_row( - answer_dict, self.constants, self.filename - ) - - self.assertEqual(len(result), 2) - self.assertEqual(mock_secondary.call_count, 2) - - # ==================== methodology_breakout_secondary Tests ==================== - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_fee_schedule_breakout') - def test_methodology_breakout_secondary_fee_schedule(self, mock_fs_breakout): - """Test secondary breakout for Fee Schedule methodology.""" - mock_fs_breakout.return_value = { - "FEE_SCHEDULE": "Medicare", - "FEE_SCHEDULE_VERSION": "2024" - } - - methodology_dict = {"AARETE_DERIVED_REIMB_METHOD": "Fee Schedule"} - - with patch('src.investment.one_to_n_funcs.FieldSet') as mock_fieldset: - mock_grouper_fields = Mock() - mock_grouper_fields.list_fields.return_value = ["GROUPER_TYPE", "DRG_WEIGHT_TYPE"] - mock_fieldset.return_value = mock_grouper_fields - - result = one_to_n_funcs.methodology_breakout_secondary( - methodology_dict, "Labs", "Medicare fee schedule", - Mock(), mock_grouper_fields, self.constants, self.filename - ) - - self.assertIn("FEE_SCHEDULE", result) - self.assertEqual(result["GROUPER_TYPE"], "N/A") - self.assertEqual(result["DRG_WEIGHT_TYPE"], "N/A") - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_grouper_breakout') - def test_methodology_breakout_secondary_grouper(self, mock_grouper_breakout): - """Test secondary breakout for Grouper methodology.""" - mock_grouper_breakout.return_value = { - "GROUPER_TYPE": "MS-DRG", - "DRG_WEIGHT_TYPE": "CMS" - } - - methodology_dict = {"AARETE_DERIVED_REIMB_METHOD": "Grouper"} - - with patch('src.investment.one_to_n_funcs.FieldSet') as mock_fieldset: - mock_fs_fields = Mock() - mock_fs_fields.list_fields.return_value = ["FEE_SCHEDULE", "FEE_SCHEDULE_VERSION"] - mock_fieldset.return_value = mock_fs_fields - - result = one_to_n_funcs.methodology_breakout_secondary( - methodology_dict, "Surgery", "MS-DRG", - mock_fs_fields, Mock(), self.constants, self.filename - ) - - self.assertIn("GROUPER_TYPE", result) - self.assertEqual(result["FEE_SCHEDULE"], "N/A") - self.assertEqual(result["FEE_SCHEDULE_VERSION"], "N/A") - - def test_methodology_breakout_secondary_other_methodology(self): - """Test secondary breakout for non-FS, non-Grouper methodology.""" - methodology_dict = {"AARETE_DERIVED_REIMB_METHOD": "Per Diem"} - - with patch('src.investment.one_to_n_funcs.FieldSet') as mock_fieldset: - mock_fields = Mock() - mock_fields.list_fields.return_value = ["FEE_SCHEDULE", "GROUPER_TYPE"] - mock_fieldset.return_value = mock_fields - - result = one_to_n_funcs.methodology_breakout_secondary( - methodology_dict, "Inpatient", "$500 per day", - mock_fields, mock_fields, self.constants, self.filename - ) - - self.assertEqual(result["FEE_SCHEDULE"], "N/A") - self.assertEqual(result["GROUPER_TYPE"], "N/A") - - # ==================== carveout_and_special_case Tests ==================== - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_carveout_check') - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_special_case_breakout') - def test_carveout_and_special_case_base_covered(self, mock_special_breakout, mock_carveout_check): - """Test carveout check for BASE_COVERED_SERVICES.""" - mock_carveout_check.return_value = "BASE_COVERED_SERVICES" - - input_answers = [{"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"}] - - reimb_answers, special_answers = one_to_n_funcs.carveout_and_special_case( - input_answers, self.constants, self.filename - ) - - self.assertEqual(len(reimb_answers), 1) - self.assertEqual(len(special_answers), 0) - self.assertEqual(reimb_answers[0]["CARVEOUT_CD"], "BASE_COVERED_SERVICES") - self.assertEqual(reimb_answers[0]["CARVEOUT_IND"], "N") - self.assertEqual(reimb_answers[0]["DEFAULT_IND"], "N") - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_carveout_check') - def test_carveout_and_special_case_default_term(self, mock_carveout_check): - """Test carveout check for DEFAULT_TERM.""" - mock_carveout_check.return_value = "DEFAULT_TERM" - - input_answers = [{"SERVICE_TERM": "All other services", "REIMB_TERM": "As negotiated"}] - - reimb_answers, special_answers = one_to_n_funcs.carveout_and_special_case( - input_answers, self.constants, self.filename - ) - - self.assertEqual(reimb_answers[0]["CARVEOUT_CD"], "DEFAULT_TERM") - self.assertEqual(reimb_answers[0]["CARVEOUT_IND"], "N") - self.assertEqual(reimb_answers[0]["DEFAULT_IND"], "Y") - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_carveout_check') - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_special_case_breakout') - def test_carveout_and_special_case_trigger_cap(self, mock_special_breakout, mock_carveout_check): - """Test carveout check for TRIGGER_CAP with breakout.""" - mock_carveout_check.return_value = "TRIGGER_CAP" - mock_special_breakout.return_value = {"TRIGGER_AMOUNT": "$10000", "CAP_AMOUNT": "$50000"} - - input_answers = [{"SERVICE_TERM": "Surgery", "REIMB_TERM": "Trigger at $10k, cap at $50k"}] - - reimb_answers, special_answers = one_to_n_funcs.carveout_and_special_case( - input_answers, self.constants, self.filename - ) - - self.assertEqual(reimb_answers[0]["CARVEOUT_CD"], "TRIGGER_CAP") - self.assertEqual(reimb_answers[0]["CARVEOUT_IND"], "Y") - self.assertEqual(reimb_answers[0]["DEFAULT_IND"], "N") - self.assertIn("TRIGGER_AMOUNT", reimb_answers[0]) - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_carveout_check') - def test_carveout_and_special_case_special_case_field(self, mock_carveout_check): - """Test when result is a special case field, not a carveout.""" - mock_carveout_check.return_value = "OUTLIER_TERM" - - input_answers = [{"SERVICE_TERM": "High-cost cases", "REIMB_TERM": "Outlier payment above $25,000"}] - - reimb_answers, special_answers = one_to_n_funcs.carveout_and_special_case( - input_answers, self.constants, self.filename - ) - - self.assertEqual(len(reimb_answers), 0) - self.assertEqual(len(special_answers), 1) - self.assertIn("OUTLIER_TERM", special_answers[0]) - self.assertNotIn("SERVICE_TERM", special_answers[0]) - self.assertNotIn("REIMB_TERM", special_answers[0]) - - # ==================== special_case_breakout Tests ==================== - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_special_case_breakout') - def test_special_case_breakout_outlier(self, mock_breakout): - """Test special case breakout for outlier terms.""" - mock_breakout.return_value = { - "OUTLIER_THRESHOLD": "$25000", - "OUTLIER_PAYMENT_METHOD": "Cost-based" - } - - input_answers = [{"OUTLIER_TERM": "Outlier payment for cases exceeding $25,000"}] - - with patch('src.investment.one_to_n_funcs.FieldSet') as mock_fieldset: - mock_field = Mock() - mock_field.get_breakout_template.return_value = "OUTLIER_BREAKOUT template" - - mock_fields = Mock() - mock_fields.get_field.return_value = mock_field - mock_fieldset.return_value = mock_fields - - result = one_to_n_funcs.special_case_breakout(input_answers, self.filename) - - self.assertEqual(len(result), 1) - self.assertIn("OUTLIER_THRESHOLD", result[0]) - self.assertIn("OUTLIER_PAYMENT_METHOD", result[0]) - - # ==================== filter_services_without_reimbursements Tests ==================== - - @patch('src.investment.one_to_n_funcs.prompt_calls.validate_reimbursements_for_llm') - def test_filter_services_all_valid(self, mock_validate): - """Test filtering when all services have valid reimbursements.""" - mock_validate.return_value = True - - input_answers = [ - {"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"}, - {"SERVICE_TERM": "X-Ray", "REIMB_TERM": "Fee schedule"} - ] - - result = one_to_n_funcs.filter_services_without_reimbursements( - input_answers, self.filename - ) - - self.assertEqual(len(result), 2) - self.assertEqual(mock_validate.call_count, 2) - - @patch('src.investment.one_to_n_funcs.prompt_calls.validate_reimbursements_for_llm') - def test_filter_services_some_invalid(self, mock_validate): - """Test filtering when some services lack reimbursements.""" - mock_validate.side_effect = [True, False, True] - - input_answers = [ - {"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"}, - {"SERVICE_TERM": "Definitions", "REIMB_TERM": "Standard eyeglass lenses as defined by DMAP"}, - {"SERVICE_TERM": "Surgery", "REIMB_TERM": "MS-DRG"} - ] - - result = one_to_n_funcs.filter_services_without_reimbursements( - input_answers, self.filename - ) - - self.assertEqual(len(result), 2) - self.assertEqual(result[0]["SERVICE_TERM"], "Labs") - self.assertEqual(result[1]["SERVICE_TERM"], "Surgery") - - @patch('src.investment.one_to_n_funcs.prompt_calls.validate_reimbursements_for_llm') - def test_filter_services_all_invalid(self, mock_validate): - """Test filtering when all services are invalid.""" - mock_validate.return_value = False - - input_answers = [ - {"SERVICE_TERM": "Admin", "REIMB_TERM": "Administrative terms apply"}, - {"SERVICE_TERM": "Definitions", "REIMB_TERM": "See glossary"} - ] - - result = one_to_n_funcs.filter_services_without_reimbursements( - input_answers, self.filename - ) - - self.assertEqual(len(result), 0) - - # ==================== split_reimb_dates Tests ==================== - - @patch('src.investment.one_to_n_funcs.llm_utils.invoke_claude') - @patch('src.investment.one_to_n_funcs.string_utils.universal_json_load') - def test_split_reimb_dates_valid_range(self, mock_json_load, mock_invoke): - """Test splitting valid date range.""" - mock_invoke.return_value = '{"start_date": "2024-01-01", "end_date": "2024-12-31"}' - mock_json_load.return_value = {"start_date": "2024-01-01", "end_date": "2024-12-31"} - - input_data = [ - {"SERVICE_TERM": "Labs", "REIMB_DATES": "January 1, 2024 through December 31, 2024"} - ] - - result = one_to_n_funcs.split_reimb_dates(input_data, self.filename) - - self.assertEqual(result[0]["REIMB_EFFECTIVE_DT"], "2024-01-01") - self.assertEqual(result[0]["REIMB_TERMINATION_DT"], "2024-12-31") - self.assertNotIn("REIMB_DATES", result[0]) - - def test_split_reimb_dates_no_dates(self): - """Test splitting when no REIMB_DATES field exists.""" - input_data = [ - {"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"} - ] - - result = one_to_n_funcs.split_reimb_dates(input_data, self.filename) - - self.assertIsNone(result[0]["REIMB_EFFECTIVE_DT"]) - self.assertIsNone(result[0]["REIMB_TERMINATION_DT"]) - - def test_split_reimb_dates_empty_dates(self): - """Test splitting when REIMB_DATES is empty string.""" - input_data = [ - {"SERVICE_TERM": "Labs", "REIMB_DATES": ""} - ] - - result = one_to_n_funcs.split_reimb_dates(input_data, self.filename) - - self.assertIsNone(result[0]["REIMB_EFFECTIVE_DT"]) - self.assertIsNone(result[0]["REIMB_TERMINATION_DT"]) - self.assertNotIn("REIMB_DATES", result[0]) - - def test_split_reimb_dates_empty_input(self): - """Test splitting with empty input list.""" - result = one_to_n_funcs.split_reimb_dates([], self.filename) - self.assertEqual(result, []) - - def test_split_reimb_dates_none_input(self): - """Test splitting with None input.""" - result = one_to_n_funcs.split_reimb_dates(None, self.filename) - self.assertIsNone(result) - - @patch('src.investment.one_to_n_funcs.llm_utils.invoke_claude') - def test_split_reimb_dates_llm_error(self, mock_invoke): - """Test splitting when LLM call fails.""" - mock_invoke.side_effect = Exception("LLM API error") - - input_data = [ - {"SERVICE_TERM": "Labs", "REIMB_DATES": "January 1, 2024 through December 31, 2024"} - ] - - result = one_to_n_funcs.split_reimb_dates(input_data, self.filename) - - # Should still remove REIMB_DATES and initialize new fields - self.assertIsNone(result[0]["REIMB_EFFECTIVE_DT"]) - self.assertIsNone(result[0]["REIMB_TERMINATION_DT"]) - self.assertNotIn("REIMB_DATES", result[0]) - - # ==================== get_lob_relationship Tests ==================== - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lob_relationship') - @patch('src.investment.one_to_n_funcs.string_utils.is_empty') - def test_get_lob_relationship_with_program(self, mock_is_empty, mock_prompt_lob): - """Test LOB-Program relationship extraction.""" - mock_is_empty.side_effect = [False, False, True] # LOB not empty, PROGRAM not empty, PRODUCT empty - mock_prompt_lob.return_value = "PROGRAM_SPECIFIC" - - input_data = [ - {"AARETE_DERIVED_LOB": "Medicaid", "AARETE_DERIVED_PROGRAM": "CHIP"} - ] - - result = one_to_n_funcs.get_lob_relationship( - input_data, self.exhibit_text, self.filename - ) - - self.assertEqual(result[0]["LOB_PROGRAM_RELATIONSHIP"], "PROGRAM_SPECIFIC") - mock_prompt_lob.assert_called_once() - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lob_relationship') - @patch('src.investment.one_to_n_funcs.string_utils.is_empty') - def test_get_lob_relationship_with_product(self, mock_is_empty, mock_prompt_lob): - """Test LOB-Product relationship extraction.""" - mock_is_empty.side_effect = [False, True, False] # LOB not empty, PROGRAM empty, PRODUCT not empty - mock_prompt_lob.return_value = "PRODUCT_SPECIFIC" - - input_data = [ - {"AARETE_DERIVED_LOB": "Commercial", "AARETE_DERIVED_PRODUCT": "HMO"} - ] - - result = one_to_n_funcs.get_lob_relationship( - input_data, self.exhibit_text, self.filename - ) - - self.assertEqual(result[0]["LOB_PRODUCT_RELATIONSHIP"], "PRODUCT_SPECIFIC") - mock_prompt_lob.assert_called_once() - - @patch('src.investment.one_to_n_funcs.string_utils.is_empty') - def test_get_lob_relationship_no_lob(self, mock_is_empty): - """Test relationship extraction when LOB is empty.""" - mock_is_empty.return_value = True - - input_data = [ - {"AARETE_DERIVED_PROGRAM": "CHIP"} - ] - - result = one_to_n_funcs.get_lob_relationship( - input_data, self.exhibit_text, self.filename - ) - - # Should skip processing and return unchanged - self.assertEqual(result, input_data) - - # ==================== one_to_n_cleaning Tests ==================== - - @patch('src.investment.one_to_n_funcs.aarete_derived.get_crosswalk_fields') - @patch('src.investment.one_to_n_funcs.get_lob_relationship') - @patch('src.investment.one_to_n_funcs.aarete_derived.fill_na_mapping') - @patch('src.investment.one_to_n_funcs.postprocessing_funcs.update_lob_for_duals') - @patch('src.investment.one_to_n_funcs.split_reimb_dates') - def test_one_to_n_cleaning_full_pipeline(self, mock_split_dates, mock_update_duals, - mock_fill_na, mock_get_lob, mock_crosswalk): - """Test full one-to-n cleaning pipeline.""" - input_data = [{"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"}] - - mock_crosswalk.return_value = input_data - mock_get_lob.return_value = input_data - mock_fill_na.return_value = input_data - mock_update_duals.return_value = input_data - mock_split_dates.return_value = input_data - - result = one_to_n_funcs.one_to_n_cleaning( - input_data, self.exhibit_text, self.constants, self.filename - ) - - # Verify all cleaning steps were called - mock_crosswalk.assert_called_once() - mock_get_lob.assert_called_once() - mock_fill_na.assert_called_once() - mock_update_duals.assert_called_once() - mock_split_dates.assert_called_once() - - self.assertEqual(result, input_data) - - # ==================== lesser_of_distribution Tests ==================== - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_check') - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_distribution') - def test_lesser_of_distribution_with_lesser_term_not_overarching(self, mock_lesser_dist, mock_lesser_check): - """Test lesser_of_distribution when 'less' is in term but not overarching.""" - mock_lesser_check.return_value = False # Not overarching - - input_answers = [ - {"SERVICE_TERM": "Labs", "REIMB_TERM": "lesser of Medicare or billed charges"} - ] - - result = one_to_n_funcs.lesser_of_distribution( - input_answers, "exhibit text", "1", self.constants, self.filename - ) - - self.assertEqual(len(result), 1) - self.assertEqual(result[0]["REIMB_TERM"], "lesser of Medicare or billed charges") - mock_lesser_check.assert_called_once() - mock_lesser_dist.assert_not_called() - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_check') - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_distribution') - def test_lesser_of_distribution_with_lesser_term_overarching(self, mock_lesser_dist, mock_lesser_check): - """Test lesser_of_distribution when 'less' is in term and is overarching.""" - mock_lesser_check.return_value = True # Is overarching - - input_answers = [ - {"SERVICE_TERM": "Labs", "REIMB_TERM": "lesser of Medicare or billed charges"} - ] - - result = one_to_n_funcs.lesser_of_distribution( - input_answers, "exhibit text", "1", self.constants, self.filename - ) - - # When overarching, the answer should not be included (filtered out) - self.assertEqual(len(result), 0) - mock_lesser_check.assert_called_once() - mock_lesser_dist.assert_not_called() - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_check') - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_distribution') - def test_lesser_of_distribution_without_lesser_term(self, mock_lesser_dist, mock_lesser_check): - """Test lesser_of_distribution when 'less' is not in term.""" - mock_lesser_dist.return_value = "100% of Medicare fee schedule" - - input_answers = [ - {"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"} - ] - - result = one_to_n_funcs.lesser_of_distribution( - input_answers, "exhibit text", "1", self.constants, self.filename - ) - - self.assertEqual(len(result), 1) - self.assertEqual(result[0]["REIMB_TERM"], "100% of Medicare fee schedule") - mock_lesser_check.assert_not_called() - mock_lesser_dist.assert_called_once_with( - "Labs", "100% of Medicare", "exhibit text", "1", self.filename - ) - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_check') - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_distribution') - def test_lesser_of_distribution_multiple_answers(self, mock_lesser_dist, mock_lesser_check): - """Test lesser_of_distribution with multiple reimbursement answers.""" - mock_lesser_check.return_value = False - mock_lesser_dist.side_effect = [ - "Updated term 1", - "Updated term 2" - ] - - input_answers = [ - {"SERVICE_TERM": "Labs", "REIMB_TERM": "lesser of A or B"}, - {"SERVICE_TERM": "X-Ray", "REIMB_TERM": "Fee schedule"}, - {"SERVICE_TERM": "Surgery", "REIMB_TERM": "Per diem"} - ] - - result = one_to_n_funcs.lesser_of_distribution( - input_answers, "exhibit text", "1", self.constants, self.filename - ) - - self.assertEqual(len(result), 3) - # First answer has "less" but not overarching, so kept as-is - self.assertEqual(result[0]["REIMB_TERM"], "lesser of A or B") - # Second and third answers get updated via prompt_lesser_of_distribution - self.assertEqual(result[1]["REIMB_TERM"], "Updated term 1") - self.assertEqual(result[2]["REIMB_TERM"], "Updated term 2") - self.assertEqual(mock_lesser_check.call_count, 1) - self.assertEqual(mock_lesser_dist.call_count, 2) - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_check') - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_distribution') - def test_lesser_of_distribution_case_insensitive_less(self, mock_lesser_dist, mock_lesser_check): - """Test that 'less' detection is case-insensitive.""" - mock_lesser_check.return_value = False - - input_answers = [ - {"SERVICE_TERM": "Labs", "REIMB_TERM": "LESSER of Medicare or billed"}, - {"SERVICE_TERM": "X-Ray", "REIMB_TERM": "Less of A or B"}, - {"SERVICE_TERM": "Surgery", "REIMB_TERM": "LESS of X or Y"} - ] - - result = one_to_n_funcs.lesser_of_distribution( - input_answers, "exhibit text", "1", self.constants, self.filename - ) - - # All three should trigger lesser_of_check (case-insensitive) - self.assertEqual(mock_lesser_check.call_count, 3) - self.assertEqual(len(result), 3) - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_check') - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_distribution') - def test_lesser_of_distribution_empty_input(self, mock_lesser_dist, mock_lesser_check): - """Test lesser_of_distribution with empty input list.""" - result = one_to_n_funcs.lesser_of_distribution( - [], "exhibit text", "1", self.constants, self.filename - ) - - self.assertEqual(result, []) - mock_lesser_check.assert_not_called() - mock_lesser_dist.assert_not_called() - - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_check') - @patch('src.investment.one_to_n_funcs.prompt_calls.prompt_lesser_of_distribution') - def test_lesser_of_distribution_return_type(self, mock_lesser_dist, mock_lesser_check): - """Test that lesser_of_distribution returns correct type structure.""" - mock_lesser_dist.return_value = "Updated term" - - input_answers = [ - {"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"} - ] - - result = one_to_n_funcs.lesser_of_distribution( - input_answers, "exhibit text", "1", self.constants, self.filename - ) - - # Verify return type is list[dict[str, str]] - self.assertIsInstance(result, list) - self.assertGreater(len(result), 0) - self.assertIsInstance(result[0], dict) - self.assertIn("SERVICE_TERM", result[0]) - self.assertIn("REIMB_TERM", result[0]) - - -if __name__ == "__main__": - unittest.main() \ No newline at end of file diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index fdccb2d..0000000 --- a/poetry.lock +++ /dev/null @@ -1,1421 +0,0 @@ -# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. - -[[package]] -name = "annotated-types" -version = "0.7.0" -description = "Reusable constraint types to use with typing.Annotated" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, - {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, -] - -[[package]] -name = "anthropic" -version = "0.36.0" -description = "The official Python library for the anthropic API" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "anthropic-0.36.0-py3-none-any.whl", hash = "sha256:9183b9eaa0f409f2047244d7ef02c9c3eb916959c0b2960f7605dcb6cabbf548"}, - {file = "anthropic-0.36.0.tar.gz", hash = "sha256:7b0b1457096605572a29559d9a8ce224b9389d379b410e7d1bf5e0c1379f9ee2"}, -] - -[package.dependencies] -anyio = ">=3.5.0,<5" -distro = ">=1.7.0,<2" -httpx = ">=0.23.0,<1" -jiter = ">=0.4.0,<1" -pydantic = ">=1.9.0,<3" -sniffio = "*" -tokenizers = ">=0.13.0" -typing-extensions = ">=4.7,<5" - -[package.extras] -bedrock = ["boto3 (>=1.28.57)", "botocore (>=1.31.57)"] -vertex = ["google-auth (>=2,<3)"] - -[[package]] -name = "anyio" -version = "4.6.2.post1" -description = "High level compatibility layer for multiple asynchronous event loop implementations" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, - {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, -] - -[package.dependencies] -idna = ">=2.8" -sniffio = ">=1.1" - -[package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21.0b1) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\""] -trio = ["trio (>=0.26.1)"] - -[[package]] -name = "black" -version = "24.10.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, - {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, - {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, - {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, - {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, - {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, - {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, - {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, - {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, - {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, - {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, - {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, - {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, - {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, - {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, - {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, - {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, - {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, - {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, - {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, - {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, - {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.10)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "boto3" -version = "1.35.40" -description = "The AWS SDK for Python" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "boto3-1.35.40-py3-none-any.whl", hash = "sha256:9352f6d61f15c789231a5d608613f03425059072ed862c32e1ed102b17206abf"}, - {file = "boto3-1.35.40.tar.gz", hash = "sha256:33c6a7aeab316f7e0b3ad8552afe95a4a10bfd58519d00741c4d4f3047da8382"}, -] - -[package.dependencies] -botocore = ">=1.35.40,<1.36.0" -jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.10.0,<0.11.0" - -[package.extras] -crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] - -[[package]] -name = "botocore" -version = "1.35.40" -description = "Low-level, data-driven core of boto 3." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "botocore-1.35.40-py3-none-any.whl", hash = "sha256:072cc47f29cb1de4fa77ce6632e4f0480af29b70816973ff415fbaa3f50bd1db"}, - {file = "botocore-1.35.40.tar.gz", hash = "sha256:547e0a983856c7d7aeaa30fca2a283873c57c07366cd806d2d639856341b3c31"}, -] - -[package.dependencies] -jmespath = ">=0.7.1,<2.0.0" -python-dateutil = ">=2.1,<3.0.0" -urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} - -[package.extras] -crt = ["awscrt (==0.22.0)"] - -[[package]] -name = "certifi" -version = "2024.8.30" -description = "Python package for providing Mozilla's CA Bundle." -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, - {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.0" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.7.0" -groups = ["main"] -files = [ - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, - {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, - {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, -] - -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev"] -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] -markers = {main = "platform_system == \"Windows\"", dev = "sys_platform == \"win32\" or platform_system == \"Windows\""} - -[[package]] -name = "distro" -version = "1.9.0" -description = "Distro - an OS platform information API" -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, - {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, -] - -[[package]] -name = "filelock" -version = "3.16.1" -description = "A platform independent file lock." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, - {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, -] - -[package.extras] -docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] -typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""] - -[[package]] -name = "fsspec" -version = "2024.9.0" -description = "File-system specification" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "fsspec-2024.9.0-py3-none-any.whl", hash = "sha256:a0947d552d8a6efa72cc2c730b12c41d043509156966cca4fb157b0f2a0c574b"}, - {file = "fsspec-2024.9.0.tar.gz", hash = "sha256:4b0afb90c2f21832df142f292649035d80b421f60a9e1c027802e5a0da2b04e8"}, -] - -[package.extras] -abfs = ["adlfs"] -adl = ["adlfs"] -arrow = ["pyarrow (>=1)"] -dask = ["dask", "distributed"] -dev = ["pre-commit", "ruff"] -doc = ["numpydoc", "sphinx", "sphinx-design", "sphinx-rtd-theme", "yarl"] -dropbox = ["dropbox", "dropboxdrivefs", "requests"] -full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"] -fuse = ["fusepy"] -gcs = ["gcsfs"] -git = ["pygit2"] -github = ["requests"] -gs = ["gcsfs"] -gui = ["panel"] -hdfs = ["pyarrow (>=1)"] -http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"] -libarchive = ["libarchive-c"] -oci = ["ocifs"] -s3 = ["s3fs"] -sftp = ["paramiko"] -smb = ["smbprotocol"] -ssh = ["paramiko"] -test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"] -test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask-expr", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"] -test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard"] -tqdm = ["tqdm"] - -[[package]] -name = "h11" -version = "0.14.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, -] - -[[package]] -name = "httpcore" -version = "1.0.6" -description = "A minimal low-level HTTP client." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"}, - {file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"}, -] - -[package.dependencies] -certifi = "*" -h11 = ">=0.13,<0.15" - -[package.extras] -asyncio = ["anyio (>=4.0,<5.0)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<1.0)"] - -[[package]] -name = "httpx" -version = "0.27.2" -description = "The next generation HTTP client." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, - {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, -] - -[package.dependencies] -anyio = "*" -certifi = "*" -httpcore = "==1.*" -idna = "*" -sniffio = "*" - -[package.extras] -brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "huggingface-hub" -version = "0.25.2" -description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" -optional = false -python-versions = ">=3.8.0" -groups = ["main"] -files = [ - {file = "huggingface_hub-0.25.2-py3-none-any.whl", hash = "sha256:1897caf88ce7f97fe0110603d8f66ac264e3ba6accdf30cd66cc0fed5282ad25"}, - {file = "huggingface_hub-0.25.2.tar.gz", hash = "sha256:a1014ea111a5f40ccd23f7f7ba8ac46e20fa3b658ced1f86a00c75c06ec6423c"}, -] - -[package.dependencies] -filelock = "*" -fsspec = ">=2023.5.0" -packaging = ">=20.9" -pyyaml = ">=5.1" -requests = "*" -tqdm = ">=4.42.1" -typing-extensions = ">=3.7.4.3" - -[package.extras] -all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.5.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] -cli = ["InquirerPy (==0.3.4)"] -dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.5.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] -fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] -hf-transfer = ["hf-transfer (>=0.1.4)"] -inference = ["aiohttp", "minijinja (>=1.0)"] -quality = ["mypy (==1.5.1)", "ruff (>=0.5.0)"] -tensorflow = ["graphviz", "pydot", "tensorflow"] -tensorflow-testing = ["keras (<3.0)", "tensorflow"] -testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] -torch = ["safetensors[torch]", "torch"] -typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] - -[[package]] -name = "idna" -version = "3.10" -description = "Internationalized Domain Names in Applications (IDNA)" -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, - {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, -] - -[package.extras] -all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, -] - -[[package]] -name = "jiter" -version = "0.6.1" -description = "Fast iterable JSON parser." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "jiter-0.6.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d08510593cb57296851080018006dfc394070178d238b767b1879dc1013b106c"}, - {file = "jiter-0.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adef59d5e2394ebbad13b7ed5e0306cceb1df92e2de688824232a91588e77aa7"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3e02f7a27f2bcc15b7d455c9df05df8ffffcc596a2a541eeda9a3110326e7a3"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed69a7971d67b08f152c17c638f0e8c2aa207e9dd3a5fcd3cba294d39b5a8d2d"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2019d966e98f7c6df24b3b8363998575f47d26471bfb14aade37630fae836a1"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36c0b51a285b68311e207a76c385650322734c8717d16c2eb8af75c9d69506e7"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:220e0963b4fb507c525c8f58cde3da6b1be0bfddb7ffd6798fb8f2531226cdb1"}, - {file = "jiter-0.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aa25c7a9bf7875a141182b9c95aed487add635da01942ef7ca726e42a0c09058"}, - {file = "jiter-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e90552109ca8ccd07f47ca99c8a1509ced93920d271bb81780a973279974c5ab"}, - {file = "jiter-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:67723a011964971864e0b484b0ecfee6a14de1533cff7ffd71189e92103b38a8"}, - {file = "jiter-0.6.1-cp310-none-win32.whl", hash = "sha256:33af2b7d2bf310fdfec2da0177eab2fedab8679d1538d5b86a633ebfbbac4edd"}, - {file = "jiter-0.6.1-cp310-none-win_amd64.whl", hash = "sha256:7cea41c4c673353799906d940eee8f2d8fd1d9561d734aa921ae0f75cb9732f4"}, - {file = "jiter-0.6.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b03c24e7da7e75b170c7b2b172d9c5e463aa4b5c95696a368d52c295b3f6847f"}, - {file = "jiter-0.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:47fee1be677b25d0ef79d687e238dc6ac91a8e553e1a68d0839f38c69e0ee491"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25f0d2f6e01a8a0fb0eab6d0e469058dab2be46ff3139ed2d1543475b5a1d8e7"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b809e39e342c346df454b29bfcc7bca3d957f5d7b60e33dae42b0e5ec13e027"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e9ac7c2f092f231f5620bef23ce2e530bd218fc046098747cc390b21b8738a7a"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e51a2d80d5fe0ffb10ed2c82b6004458be4a3f2b9c7d09ed85baa2fbf033f54b"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3343d4706a2b7140e8bd49b6c8b0a82abf9194b3f0f5925a78fc69359f8fc33c"}, - {file = "jiter-0.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82521000d18c71e41c96960cb36e915a357bc83d63a8bed63154b89d95d05ad1"}, - {file = "jiter-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c843e7c1633470708a3987e8ce617ee2979ee18542d6eb25ae92861af3f1d62"}, - {file = "jiter-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a2e861658c3fe849efc39b06ebb98d042e4a4c51a8d7d1c3ddc3b1ea091d0784"}, - {file = "jiter-0.6.1-cp311-none-win32.whl", hash = "sha256:7d72fc86474862c9c6d1f87b921b70c362f2b7e8b2e3c798bb7d58e419a6bc0f"}, - {file = "jiter-0.6.1-cp311-none-win_amd64.whl", hash = "sha256:3e36a320634f33a07794bb15b8da995dccb94f944d298c8cfe2bd99b1b8a574a"}, - {file = "jiter-0.6.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1fad93654d5a7dcce0809aff66e883c98e2618b86656aeb2129db2cd6f26f867"}, - {file = "jiter-0.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4e6e340e8cd92edab7f6a3a904dbbc8137e7f4b347c49a27da9814015cc0420c"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:691352e5653af84ed71763c3c427cff05e4d658c508172e01e9c956dfe004aba"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:defee3949313c1f5b55e18be45089970cdb936eb2a0063f5020c4185db1b63c9"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26d2bdd5da097e624081c6b5d416d3ee73e5b13f1703bcdadbb1881f0caa1933"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18aa9d1626b61c0734b973ed7088f8a3d690d0b7f5384a5270cd04f4d9f26c86"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a3567c8228afa5ddcce950631c6b17397ed178003dc9ee7e567c4c4dcae9fa0"}, - {file = "jiter-0.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e5c0507131c922defe3f04c527d6838932fcdfd69facebafd7d3574fa3395314"}, - {file = "jiter-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:540fcb224d7dc1bcf82f90f2ffb652df96f2851c031adca3c8741cb91877143b"}, - {file = "jiter-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e7b75436d4fa2032b2530ad989e4cb0ca74c655975e3ff49f91a1a3d7f4e1df2"}, - {file = "jiter-0.6.1-cp312-none-win32.whl", hash = "sha256:883d2ced7c21bf06874fdeecab15014c1c6d82216765ca6deef08e335fa719e0"}, - {file = "jiter-0.6.1-cp312-none-win_amd64.whl", hash = "sha256:91e63273563401aadc6c52cca64a7921c50b29372441adc104127b910e98a5b6"}, - {file = "jiter-0.6.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:852508a54fe3228432e56019da8b69208ea622a3069458252f725d634e955b31"}, - {file = "jiter-0.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f491cc69ff44e5a1e8bc6bf2b94c1f98d179e1aaf4a554493c171a5b2316b701"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc56c8f0b2a28ad4d8047f3ae62d25d0e9ae01b99940ec0283263a04724de1f3"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51b58f7a0d9e084a43b28b23da2b09fc5e8df6aa2b6a27de43f991293cab85fd"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f79ce15099154c90ef900d69c6b4c686b64dfe23b0114e0971f2fecd306ec6c"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:03a025b52009f47e53ea619175d17e4ded7c035c6fbd44935cb3ada11e1fd592"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74a8d93718137c021d9295248a87c2f9fdc0dcafead12d2930bc459ad40f885"}, - {file = "jiter-0.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40b03b75f903975f68199fc4ec73d546150919cb7e534f3b51e727c4d6ccca5a"}, - {file = "jiter-0.6.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:825651a3f04cf92a661d22cad61fc913400e33aa89b3e3ad9a6aa9dc8a1f5a71"}, - {file = "jiter-0.6.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:928bf25eb69ddb292ab8177fe69d3fbf76c7feab5fce1c09265a7dccf25d3991"}, - {file = "jiter-0.6.1-cp313-none-win32.whl", hash = "sha256:352cd24121e80d3d053fab1cc9806258cad27c53cad99b7a3cac57cf934b12e4"}, - {file = "jiter-0.6.1-cp313-none-win_amd64.whl", hash = "sha256:be7503dd6f4bf02c2a9bacb5cc9335bc59132e7eee9d3e931b13d76fd80d7fda"}, - {file = "jiter-0.6.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:31d8e00e1fb4c277df8ab6f31a671f509ebc791a80e5c61fdc6bc8696aaa297c"}, - {file = "jiter-0.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77c296d65003cd7ee5d7b0965f6acbe6cffaf9d1fa420ea751f60ef24e85fed5"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aeeb0c0325ef96c12a48ea7e23e2e86fe4838e6e0a995f464cf4c79fa791ceeb"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a31c6fcbe7d6c25d6f1cc6bb1cba576251d32795d09c09961174fe461a1fb5bd"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59e2b37f3b9401fc9e619f4d4badcab2e8643a721838bcf695c2318a0475ae42"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bae5ae4853cb9644144e9d0755854ce5108d470d31541d83f70ca7ecdc2d1637"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9df588e9c830b72d8db1dd7d0175af6706b0904f682ea9b1ca8b46028e54d6e9"}, - {file = "jiter-0.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15f8395e835cf561c85c1adee72d899abf2733d9df72e9798e6d667c9b5c1f30"}, - {file = "jiter-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a99d4e0b5fc3b05ea732d67eb2092fe894e95a90e6e413f2ea91387e228a307"}, - {file = "jiter-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a311df1fa6be0ccd64c12abcd85458383d96e542531bafbfc0a16ff6feda588f"}, - {file = "jiter-0.6.1-cp38-none-win32.whl", hash = "sha256:81116a6c272a11347b199f0e16b6bd63f4c9d9b52bc108991397dd80d3c78aba"}, - {file = "jiter-0.6.1-cp38-none-win_amd64.whl", hash = "sha256:13f9084e3e871a7c0b6e710db54444088b1dd9fbefa54d449b630d5e73bb95d0"}, - {file = "jiter-0.6.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:f1c53615fcfec3b11527c08d19cff6bc870da567ce4e57676c059a3102d3a082"}, - {file = "jiter-0.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f791b6a4da23238c17a81f44f5b55d08a420c5692c1fda84e301a4b036744eb1"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c97e90fec2da1d5f68ef121444c2c4fa72eabf3240829ad95cf6bbeca42a301"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cbc1a66b4e41511209e97a2866898733c0110b7245791ac604117b7fb3fedb7"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4e85f9e12cd8418ab10e1fcf0e335ae5bb3da26c4d13a0fd9e6a17a674783b6"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08be33db6dcc374c9cc19d3633af5e47961a7b10d4c61710bd39e48d52a35824"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:677be9550004f5e010d673d3b2a2b815a8ea07a71484a57d3f85dde7f14cf132"}, - {file = "jiter-0.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e8bd065be46c2eecc328e419d6557bbc37844c88bb07b7a8d2d6c91c7c4dedc9"}, - {file = "jiter-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bd95375ce3609ec079a97c5d165afdd25693302c071ca60c7ae1cf826eb32022"}, - {file = "jiter-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db459ed22d0208940d87f614e1f0ea5a946d29a3cfef71f7e1aab59b6c6b2afb"}, - {file = "jiter-0.6.1-cp39-none-win32.whl", hash = "sha256:d71c962f0971347bd552940ab96aa42ceefcd51b88c4ced8a27398182efa8d80"}, - {file = "jiter-0.6.1-cp39-none-win_amd64.whl", hash = "sha256:d465db62d2d10b489b7e7a33027c4ae3a64374425d757e963f86df5b5f2e7fc5"}, - {file = "jiter-0.6.1.tar.gz", hash = "sha256:e19cd21221fc139fb032e4112986656cb2739e9fe6d84c13956ab30ccc7d4449"}, -] - -[[package]] -name = "jmespath" -version = "1.0.1" -description = "JSON Matching Expressions" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, - {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, -] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -groups = ["dev"] -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "numpy" -version = "2.1.2" -description = "Fundamental package for array computing in Python" -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "numpy-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30d53720b726ec36a7f88dc873f0eec8447fbc93d93a8f079dfac2629598d6ee"}, - {file = "numpy-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d3ca0a72dd8846eb6f7dfe8f19088060fcb76931ed592d29128e0219652884"}, - {file = "numpy-2.1.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:fc44e3c68ff00fd991b59092a54350e6e4911152682b4782f68070985aa9e648"}, - {file = "numpy-2.1.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:7c1c60328bd964b53f8b835df69ae8198659e2b9302ff9ebb7de4e5a5994db3d"}, - {file = "numpy-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cdb606a7478f9ad91c6283e238544451e3a95f30fb5467fbf715964341a8a86"}, - {file = "numpy-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d666cb72687559689e9906197e3bec7b736764df6a2e58ee265e360663e9baf7"}, - {file = "numpy-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6eef7a2dbd0abfb0d9eaf78b73017dbfd0b54051102ff4e6a7b2980d5ac1a03"}, - {file = "numpy-2.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:12edb90831ff481f7ef5f6bc6431a9d74dc0e5ff401559a71e5e4611d4f2d466"}, - {file = "numpy-2.1.2-cp310-cp310-win32.whl", hash = "sha256:a65acfdb9c6ebb8368490dbafe83c03c7e277b37e6857f0caeadbbc56e12f4fb"}, - {file = "numpy-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:860ec6e63e2c5c2ee5e9121808145c7bf86c96cca9ad396c0bd3e0f2798ccbe2"}, - {file = "numpy-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b42a1a511c81cc78cbc4539675713bbcf9d9c3913386243ceff0e9429ca892fe"}, - {file = "numpy-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:faa88bc527d0f097abdc2c663cddf37c05a1c2f113716601555249805cf573f1"}, - {file = "numpy-2.1.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:c82af4b2ddd2ee72d1fc0c6695048d457e00b3582ccde72d8a1c991b808bb20f"}, - {file = "numpy-2.1.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:13602b3174432a35b16c4cfb5de9a12d229727c3dd47a6ce35111f2ebdf66ff4"}, - {file = "numpy-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ebec5fd716c5a5b3d8dfcc439be82a8407b7b24b230d0ad28a81b61c2f4659a"}, - {file = "numpy-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2b49c3c0804e8ecb05d59af8386ec2f74877f7ca8fd9c1e00be2672e4d399b1"}, - {file = "numpy-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cbba4b30bf31ddbe97f1c7205ef976909a93a66bb1583e983adbd155ba72ac2"}, - {file = "numpy-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8e00ea6fc82e8a804433d3e9cedaa1051a1422cb6e443011590c14d2dea59146"}, - {file = "numpy-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5006b13a06e0b38d561fab5ccc37581f23c9511879be7693bd33c7cd15ca227c"}, - {file = "numpy-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:f1eb068ead09f4994dec71c24b2844f1e4e4e013b9629f812f292f04bd1510d9"}, - {file = "numpy-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7bf0a4f9f15b32b5ba53147369e94296f5fffb783db5aacc1be15b4bf72f43b"}, - {file = "numpy-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b1d0fcae4f0949f215d4632be684a539859b295e2d0cb14f78ec231915d644db"}, - {file = "numpy-2.1.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f751ed0a2f250541e19dfca9f1eafa31a392c71c832b6bb9e113b10d050cb0f1"}, - {file = "numpy-2.1.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:bd33f82e95ba7ad632bc57837ee99dba3d7e006536200c4e9124089e1bf42426"}, - {file = "numpy-2.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b8cde4f11f0a975d1fd59373b32e2f5a562ade7cde4f85b7137f3de8fbb29a0"}, - {file = "numpy-2.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d95f286b8244b3649b477ac066c6906fbb2905f8ac19b170e2175d3d799f4df"}, - {file = "numpy-2.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ab4754d432e3ac42d33a269c8567413bdb541689b02d93788af4131018cbf366"}, - {file = "numpy-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e585c8ae871fd38ac50598f4763d73ec5497b0de9a0ab4ef5b69f01c6a046142"}, - {file = "numpy-2.1.2-cp312-cp312-win32.whl", hash = "sha256:9c6c754df29ce6a89ed23afb25550d1c2d5fdb9901d9c67a16e0b16eaf7e2550"}, - {file = "numpy-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:456e3b11cb79ac9946c822a56346ec80275eaf2950314b249b512896c0d2505e"}, - {file = "numpy-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a84498e0d0a1174f2b3ed769b67b656aa5460c92c9554039e11f20a05650f00d"}, - {file = "numpy-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4d6ec0d4222e8ffdab1744da2560f07856421b367928026fb540e1945f2eeeaf"}, - {file = "numpy-2.1.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:259ec80d54999cc34cd1eb8ded513cb053c3bf4829152a2e00de2371bd406f5e"}, - {file = "numpy-2.1.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:675c741d4739af2dc20cd6c6a5c4b7355c728167845e3c6b0e824e4e5d36a6c3"}, - {file = "numpy-2.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b2d4e667895cc55e3ff2b56077e4c8a5604361fc21a042845ea3ad67465aa8"}, - {file = "numpy-2.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43cca367bf94a14aca50b89e9bc2061683116cfe864e56740e083392f533ce7a"}, - {file = "numpy-2.1.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:76322dcdb16fccf2ac56f99048af32259dcc488d9b7e25b51e5eca5147a3fb98"}, - {file = "numpy-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:32e16a03138cabe0cb28e1007ee82264296ac0983714094380b408097a418cfe"}, - {file = "numpy-2.1.2-cp313-cp313-win32.whl", hash = "sha256:242b39d00e4944431a3cd2db2f5377e15b5785920421993770cddb89992c3f3a"}, - {file = "numpy-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f2ded8d9b6f68cc26f8425eda5d3877b47343e68ca23d0d0846f4d312ecaa445"}, - {file = "numpy-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ffef621c14ebb0188a8633348504a35c13680d6da93ab5cb86f4e54b7e922b5"}, - {file = "numpy-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ad369ed238b1959dfbade9018a740fb9392c5ac4f9b5173f420bd4f37ba1f7a0"}, - {file = "numpy-2.1.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d82075752f40c0ddf57e6e02673a17f6cb0f8eb3f587f63ca1eaab5594da5b17"}, - {file = "numpy-2.1.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:1600068c262af1ca9580a527d43dc9d959b0b1d8e56f8a05d830eea39b7c8af6"}, - {file = "numpy-2.1.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a26ae94658d3ba3781d5e103ac07a876b3e9b29db53f68ed7df432fd033358a8"}, - {file = "numpy-2.1.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13311c2db4c5f7609b462bc0f43d3c465424d25c626d95040f073e30f7570e35"}, - {file = "numpy-2.1.2-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:2abbf905a0b568706391ec6fa15161fad0fb5d8b68d73c461b3c1bab6064dd62"}, - {file = "numpy-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ef444c57d664d35cac4e18c298c47d7b504c66b17c2ea91312e979fcfbdfb08a"}, - {file = "numpy-2.1.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bdd407c40483463898b84490770199d5714dcc9dd9b792f6c6caccc523c00952"}, - {file = "numpy-2.1.2-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:da65fb46d4cbb75cb417cddf6ba5e7582eb7bb0b47db4b99c9fe5787ce5d91f5"}, - {file = "numpy-2.1.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c193d0b0238638e6fc5f10f1b074a6993cb13b0b431f64079a509d63d3aa8b7"}, - {file = "numpy-2.1.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a7d80b2e904faa63068ead63107189164ca443b42dd1930299e0d1cb041cec2e"}, - {file = "numpy-2.1.2.tar.gz", hash = "sha256:13532a088217fa624c99b843eeb54640de23b3414b14aa66d023805eb731066c"}, -] - -[[package]] -name = "packaging" -version = "24.1" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] -files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, -] - -[[package]] -name = "pandas" -version = "2.2.3" -description = "Powerful data structures for data analysis, time series, and statistics" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5"}, - {file = "pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348"}, - {file = "pandas-2.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed"}, - {file = "pandas-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57"}, - {file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42"}, - {file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f"}, - {file = "pandas-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645"}, - {file = "pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039"}, - {file = "pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd"}, - {file = "pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698"}, - {file = "pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc"}, - {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3"}, - {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32"}, - {file = "pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5"}, - {file = "pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9"}, - {file = "pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4"}, - {file = "pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3"}, - {file = "pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319"}, - {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8"}, - {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a"}, - {file = "pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13"}, - {file = "pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015"}, - {file = "pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28"}, - {file = "pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0"}, - {file = "pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24"}, - {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659"}, - {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb"}, - {file = "pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d"}, - {file = "pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468"}, - {file = "pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18"}, - {file = "pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2"}, - {file = "pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4"}, - {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d"}, - {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a"}, - {file = "pandas-2.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39"}, - {file = "pandas-2.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30"}, - {file = "pandas-2.2.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c"}, - {file = "pandas-2.2.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c"}, - {file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea"}, - {file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761"}, - {file = "pandas-2.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e"}, - {file = "pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667"}, -] - -[package.dependencies] -numpy = {version = ">=1.26.0", markers = "python_version >= \"3.12\""} -python-dateutil = ">=2.8.2" -pytz = ">=2020.1" -tzdata = ">=2022.7" - -[package.extras] -all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] -aws = ["s3fs (>=2022.11.0)"] -clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] -compression = ["zstandard (>=0.19.0)"] -computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] -consortium-standard = ["dataframe-api-compat (>=0.1.7)"] -excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] -feather = ["pyarrow (>=10.0.1)"] -fss = ["fsspec (>=2022.11.0)"] -gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] -hdf5 = ["tables (>=3.8.0)"] -html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] -mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] -output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] -parquet = ["pyarrow (>=10.0.1)"] -performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] -plot = ["matplotlib (>=3.6.3)"] -postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] -pyarrow = ["pyarrow (>=10.0.1)"] -spss = ["pyreadstat (>=1.2.0)"] -sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] -test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] -xml = ["lxml (>=4.9.2)"] - -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - -[[package]] -name = "pillow" -version = "11.2.1" -description = "Python Imaging Library (Fork)" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "pillow-11.2.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:d57a75d53922fc20c165016a20d9c44f73305e67c351bbc60d1adaf662e74047"}, - {file = "pillow-11.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:127bf6ac4a5b58b3d32fc8289656f77f80567d65660bc46f72c0d77e6600cc95"}, - {file = "pillow-11.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ba4be812c7a40280629e55ae0b14a0aafa150dd6451297562e1764808bbe61"}, - {file = "pillow-11.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8bd62331e5032bc396a93609982a9ab6b411c05078a52f5fe3cc59234a3abd1"}, - {file = "pillow-11.2.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:562d11134c97a62fe3af29581f083033179f7ff435f78392565a1ad2d1c2c45c"}, - {file = "pillow-11.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c97209e85b5be259994eb5b69ff50c5d20cca0f458ef9abd835e262d9d88b39d"}, - {file = "pillow-11.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0c3e6d0f59171dfa2e25d7116217543310908dfa2770aa64b8f87605f8cacc97"}, - {file = "pillow-11.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc1c3bc53befb6096b84165956e886b1729634a799e9d6329a0c512ab651e579"}, - {file = "pillow-11.2.1-cp310-cp310-win32.whl", hash = "sha256:312c77b7f07ab2139924d2639860e084ec2a13e72af54d4f08ac843a5fc9c79d"}, - {file = "pillow-11.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9bc7ae48b8057a611e5fe9f853baa88093b9a76303937449397899385da06fad"}, - {file = "pillow-11.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:2728567e249cdd939f6cc3d1f049595c66e4187f3c34078cbc0a7d21c47482d2"}, - {file = "pillow-11.2.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35ca289f712ccfc699508c4658a1d14652e8033e9b69839edf83cbdd0ba39e70"}, - {file = "pillow-11.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0409af9f829f87a2dfb7e259f78f317a5351f2045158be321fd135973fff7bf"}, - {file = "pillow-11.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e5c5edee874dce4f653dbe59db7c73a600119fbea8d31f53423586ee2aafd7"}, - {file = "pillow-11.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93a07e76d13bff9444f1a029e0af2964e654bfc2e2c2d46bfd080df5ad5f3d8"}, - {file = "pillow-11.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e6def7eed9e7fa90fde255afaf08060dc4b343bbe524a8f69bdd2a2f0018f600"}, - {file = "pillow-11.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8f4f3724c068be008c08257207210c138d5f3731af6c155a81c2b09a9eb3a788"}, - {file = "pillow-11.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0a6709b47019dff32e678bc12c63008311b82b9327613f534e496dacaefb71e"}, - {file = "pillow-11.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6b0c664ccb879109ee3ca702a9272d877f4fcd21e5eb63c26422fd6e415365e"}, - {file = "pillow-11.2.1-cp311-cp311-win32.whl", hash = "sha256:cc5d875d56e49f112b6def6813c4e3d3036d269c008bf8aef72cd08d20ca6df6"}, - {file = "pillow-11.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f5c7eda47bf8e3c8a283762cab94e496ba977a420868cb819159980b6709193"}, - {file = "pillow-11.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:4d375eb838755f2528ac8cbc926c3e31cc49ca4ad0cf79cff48b20e30634a4a7"}, - {file = "pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f"}, - {file = "pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b"}, - {file = "pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d"}, - {file = "pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4"}, - {file = "pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d"}, - {file = "pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4"}, - {file = "pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443"}, - {file = "pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c"}, - {file = "pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3"}, - {file = "pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941"}, - {file = "pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb"}, - {file = "pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28"}, - {file = "pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830"}, - {file = "pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0"}, - {file = "pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1"}, - {file = "pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f"}, - {file = "pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155"}, - {file = "pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14"}, - {file = "pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b"}, - {file = "pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2"}, - {file = "pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691"}, - {file = "pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c"}, - {file = "pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22"}, - {file = "pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7"}, - {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16"}, - {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b"}, - {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406"}, - {file = "pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91"}, - {file = "pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751"}, - {file = "pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9"}, - {file = "pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd"}, - {file = "pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e"}, - {file = "pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681"}, - {file = "pillow-11.2.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:7491cf8a79b8eb867d419648fff2f83cb0b3891c8b36da92cc7f1931d46108c8"}, - {file = "pillow-11.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b02d8f9cb83c52578a0b4beadba92e37d83a4ef11570a8688bbf43f4ca50909"}, - {file = "pillow-11.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:014ca0050c85003620526b0ac1ac53f56fc93af128f7546623cc8e31875ab928"}, - {file = "pillow-11.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3692b68c87096ac6308296d96354eddd25f98740c9d2ab54e1549d6c8aea9d79"}, - {file = "pillow-11.2.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:f781dcb0bc9929adc77bad571b8621ecb1e4cdef86e940fe2e5b5ee24fd33b35"}, - {file = "pillow-11.2.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:2b490402c96f907a166615e9a5afacf2519e28295f157ec3a2bb9bd57de638cb"}, - {file = "pillow-11.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd6b20b93b3ccc9c1b597999209e4bc5cf2853f9ee66e3fc9a400a78733ffc9a"}, - {file = "pillow-11.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4b835d89c08a6c2ee7781b8dd0a30209a8012b5f09c0a665b65b0eb3560b6f36"}, - {file = "pillow-11.2.1-cp39-cp39-win32.whl", hash = "sha256:b10428b3416d4f9c61f94b494681280be7686bda15898a3a9e08eb66a6d92d67"}, - {file = "pillow-11.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:6ebce70c3f486acf7591a3d73431fa504a4e18a9b97ff27f5f47b7368e4b9dd1"}, - {file = "pillow-11.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:c27476257b2fdcd7872d54cfd119b3a9ce4610fb85c8e32b70b42e3680a29a1e"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9b7b0d4fd2635f54ad82785d56bc0d94f147096493a79985d0ab57aedd563156"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:aa442755e31c64037aa7c1cb186e0b369f8416c567381852c63444dd666fb772"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d3348c95b766f54b76116d53d4cb171b52992a1027e7ca50c81b43b9d9e363"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85d27ea4c889342f7e35f6d56e7e1cb345632ad592e8c51b693d7b7556043ce0"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bf2c33d6791c598142f00c9c4c7d47f6476731c31081331664eb26d6ab583e01"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e616e7154c37669fc1dfc14584f11e284e05d1c650e1c0f972f281c4ccc53193"}, - {file = "pillow-11.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:39ad2e0f424394e3aebc40168845fee52df1394a4673a6ee512d840d14ab3013"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80f1df8dbe9572b4b7abdfa17eb5d78dd620b1d55d9e25f834efdbee872d3aed"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea926cfbc3957090becbcbbb65ad177161a2ff2ad578b5a6ec9bb1e1cd78753c"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:738db0e0941ca0376804d4de6a782c005245264edaa253ffce24e5a15cbdc7bd"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db98ab6565c69082ec9b0d4e40dd9f6181dab0dd236d26f7a50b8b9bfbd5076"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:036e53f4170e270ddb8797d4c590e6dd14d28e15c7da375c18978045f7e6c37b"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14f73f7c291279bd65fda51ee87affd7c1e097709f7fdd0188957a16c264601f"}, - {file = "pillow-11.2.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:208653868d5c9ecc2b327f9b9ef34e0e42a4cdd172c2988fd81d62d2bc9bc044"}, - {file = "pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6"}, -] - -[package.extras] -docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] -fpx = ["olefile"] -mic = ["olefile"] -test-arrow = ["pyarrow"] -tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "trove-classifiers (>=2024.10.12)"] -typing = ["typing-extensions ; python_version < \"3.10\""] -xmp = ["defusedxml"] - -[[package]] -name = "platformdirs" -version = "4.3.6" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, - {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, -] - -[package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.11.2)"] - -[[package]] -name = "pluggy" -version = "1.5.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "pydantic" -version = "2.9.2" -description = "Data validation using Python type hints" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, - {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, -] - -[package.dependencies] -annotated-types = ">=0.6.0" -pydantic-core = "2.23.4" -typing-extensions = [ - {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, - {version = ">=4.6.1", markers = "python_version < \"3.13\""}, -] - -[package.extras] -email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata ; python_version >= \"3.9\" and sys_platform == \"win32\""] - -[[package]] -name = "pydantic-core" -version = "2.23.4" -description = "Core functionality for Pydantic validation and serialization" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, - {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, - {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, - {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, - {file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, - {file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, - {file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, - {file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, - {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, - {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, - {file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, - {file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, - {file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, - {file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, - {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, - {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, - {file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, - {file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, - {file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, - {file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, - {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, - {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, - {file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, - {file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, - {file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, - {file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, - {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, - {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, - {file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, - {file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, - {file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, - {file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, - {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, - {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, - {file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, - {file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, - {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, -] - -[package.dependencies] -typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" - -[[package]] -name = "pymupdf" -version = "1.25.5" -description = "A high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents." -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "pymupdf-1.25.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cde4e1c9cfb09c0e1e9c2b7f4b787dd6bb34a32cfe141a4675e24af7c0c25dd3"}, - {file = "pymupdf-1.25.5-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:5a35e2725fae0ab57f058dff77615c15eb5961eac50ba04f41ebc792cd8facad"}, - {file = "pymupdf-1.25.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d94b800e9501929c42283d39bc241001dd87fdeea297b5cb40d5b5714534452f"}, - {file = "pymupdf-1.25.5-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee22155d3a634642d76553204867d862ae1bdd9f7cf70c0797d8127ebee6bed5"}, - {file = "pymupdf-1.25.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6ed7fc25271004d6d3279c20a80cb2bb4cda3efa9f9088dcc07cd790eca0bc63"}, - {file = "pymupdf-1.25.5-cp39-abi3-win32.whl", hash = "sha256:65e18ddb37fe8ec4edcdbebe9be3a8486b6a2f42609d0a142677e42f3a0614f8"}, - {file = "pymupdf-1.25.5-cp39-abi3-win_amd64.whl", hash = "sha256:7f44bc3d03ea45b2f68c96464f96105e8c7908896f2fb5e8c04f1fb8dae7981e"}, - {file = "pymupdf-1.25.5.tar.gz", hash = "sha256:5f96311cacd13254c905f6654a004a0a2025b71cabc04fda667f5472f72c15a0"}, -] - -[[package]] -name = "pytest" -version = "8.3.3" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, - {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=1.5,<2" - -[package.extras] -dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main"] -files = [ - {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "python-dotenv" -version = "1.2.1" -description = "Read key-value pairs from a .env file and set them as environment variables" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61"}, - {file = "python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6"}, -] - -[package.extras] -cli = ["click (>=5.0)"] - -[[package]] -name = "pytz" -version = "2024.2" -description = "World timezone definitions, modern and historical" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, - {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, - {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, - {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, - {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, - {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, - {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, - {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, - {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, - {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, - {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, - {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, - {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, - {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, - {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, - {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, - {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, - {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, -] - -[[package]] -name = "requests" -version = "2.32.3" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, - {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, -] - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "s3transfer" -version = "0.10.3" -description = "An Amazon S3 Transfer Manager" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "s3transfer-0.10.3-py3-none-any.whl", hash = "sha256:263ed587a5803c6c708d3ce44dc4dfedaab4c1a32e8329bab818933d79ddcf5d"}, - {file = "s3transfer-0.10.3.tar.gz", hash = "sha256:4f50ed74ab84d474ce614475e0b8d5047ff080810aac5d01ea25231cfc944b0c"}, -] - -[package.dependencies] -botocore = ">=1.33.2,<2.0a.0" - -[package.extras] -crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -groups = ["main"] -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, -] - -[[package]] -name = "tokenizers" -version = "0.20.1" -description = "" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "tokenizers-0.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:439261da7c0a5c88bda97acb284d49fbdaf67e9d3b623c0bfd107512d22787a9"}, - {file = "tokenizers-0.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03dae629d99068b1ea5416d50de0fea13008f04129cc79af77a2a6392792d93c"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b61f561f329ffe4b28367798b89d60c4abf3f815d37413b6352bc6412a359867"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec870fce1ee5248a10be69f7a8408a234d6f2109f8ea827b4f7ecdbf08c9fd15"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d388d1ea8b7447da784e32e3b86a75cce55887e3b22b31c19d0b186b1c677800"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:299c85c1d21135bc01542237979bf25c32efa0d66595dd0069ae259b97fb2dbe"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e96f6c14c9752bb82145636b614d5a78e9cde95edfbe0a85dad0dd5ddd6ec95c"}, - {file = "tokenizers-0.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc9e95ad49c932b80abfbfeaf63b155761e695ad9f8a58c52a47d962d76e310f"}, - {file = "tokenizers-0.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f22dee205329a636148c325921c73cf3e412e87d31f4d9c3153b302a0200057b"}, - {file = "tokenizers-0.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2ffd9a8895575ac636d44500c66dffaef133823b6b25067604fa73bbc5ec09d"}, - {file = "tokenizers-0.20.1-cp310-none-win32.whl", hash = "sha256:2847843c53f445e0f19ea842a4e48b89dd0db4e62ba6e1e47a2749d6ec11f50d"}, - {file = "tokenizers-0.20.1-cp310-none-win_amd64.whl", hash = "sha256:f9aa93eacd865f2798b9e62f7ce4533cfff4f5fbd50c02926a78e81c74e432cd"}, - {file = "tokenizers-0.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4a717dcb08f2dabbf27ae4b6b20cbbb2ad7ed78ce05a829fae100ff4b3c7ff15"}, - {file = "tokenizers-0.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f84dad1ff1863c648d80628b1b55353d16303431283e4efbb6ab1af56a75832"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:929c8f3afa16a5130a81ab5079c589226273ec618949cce79b46d96e59a84f61"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d10766473954397e2d370f215ebed1cc46dcf6fd3906a2a116aa1d6219bfedc3"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9300fac73ddc7e4b0330acbdda4efaabf74929a4a61e119a32a181f534a11b47"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ecaf7b0e39caeb1aa6dd6e0975c405716c82c1312b55ac4f716ef563a906969"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5170be9ec942f3d1d317817ced8d749b3e1202670865e4fd465e35d8c259de83"}, - {file = "tokenizers-0.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f1ae08fa9aea5891cbd69df29913e11d3841798e0bfb1ff78b78e4e7ea0a4"}, - {file = "tokenizers-0.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ee86d4095d3542d73579e953c2e5e07d9321af2ffea6ecc097d16d538a2dea16"}, - {file = "tokenizers-0.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:86dcd08da163912e17b27bbaba5efdc71b4fbffb841530fdb74c5707f3c49216"}, - {file = "tokenizers-0.20.1-cp311-none-win32.whl", hash = "sha256:9af2dc4ee97d037bc6b05fa4429ddc87532c706316c5e11ce2f0596dfcfa77af"}, - {file = "tokenizers-0.20.1-cp311-none-win_amd64.whl", hash = "sha256:899152a78b095559c287b4c6d0099469573bb2055347bb8154db106651296f39"}, - {file = "tokenizers-0.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:407ab666b38e02228fa785e81f7cf79ef929f104bcccf68a64525a54a93ceac9"}, - {file = "tokenizers-0.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f13a2d16032ebc8bd812eb8099b035ac65887d8f0c207261472803b9633cf3e"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e98eee4dca22849fbb56a80acaa899eec5b72055d79637dd6aa15d5e4b8628c9"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47c1bcdd61e61136087459cb9e0b069ff23b5568b008265e5cbc927eae3387ce"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:128c1110e950534426e2274837fc06b118ab5f2fa61c3436e60e0aada0ccfd67"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2e2d47a819d2954f2c1cd0ad51bb58ffac6f53a872d5d82d65d79bf76b9896d"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bdd67a0e3503a9a7cf8bc5a4a49cdde5fa5bada09a51e4c7e1c73900297539bd"}, - {file = "tokenizers-0.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:689b93d2e26d04da337ac407acec8b5d081d8d135e3e5066a88edd5bdb5aff89"}, - {file = "tokenizers-0.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0c6a796ddcd9a19ad13cf146997cd5895a421fe6aec8fd970d69f9117bddb45c"}, - {file = "tokenizers-0.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3ea919687aa7001a8ff1ba36ac64f165c4e89035f57998fa6cedcfd877be619d"}, - {file = "tokenizers-0.20.1-cp312-none-win32.whl", hash = "sha256:6d3ac5c1f48358ffe20086bf065e843c0d0a9fce0d7f0f45d5f2f9fba3609ca5"}, - {file = "tokenizers-0.20.1-cp312-none-win_amd64.whl", hash = "sha256:b0874481aea54a178f2bccc45aa2d0c99cd3f79143a0948af6a9a21dcc49173b"}, - {file = "tokenizers-0.20.1-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:96af92e833bd44760fb17f23f402e07a66339c1dcbe17d79a9b55bb0cc4f038e"}, - {file = "tokenizers-0.20.1-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:65f34e5b731a262dfa562820818533c38ce32a45864437f3d9c82f26c139ca7f"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17f98fccb5c12ab1ce1f471731a9cd86df5d4bd2cf2880c5a66b229802d96145"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8c0fc3542cf9370bf92c932eb71bdeb33d2d4aeeb4126d9fd567b60bd04cb30"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b39356df4575d37f9b187bb623aab5abb7b62c8cb702867a1768002f814800c"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfdad27b0e50544f6b838895a373db6114b85112ba5c0cefadffa78d6daae563"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:094663dd0e85ee2e573126918747bdb40044a848fde388efb5b09d57bc74c680"}, - {file = "tokenizers-0.20.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e4cf033a2aa207d7ac790e91adca598b679999710a632c4a494aab0fc3a1b2"}, - {file = "tokenizers-0.20.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9310951c92c9fb91660de0c19a923c432f110dbfad1a2d429fbc44fa956bf64f"}, - {file = "tokenizers-0.20.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:05e41e302c315bd2ed86c02e917bf03a6cf7d2f652c9cee1a0eb0d0f1ca0d32c"}, - {file = "tokenizers-0.20.1-cp37-none-win32.whl", hash = "sha256:212231ab7dfcdc879baf4892ca87c726259fa7c887e1688e3f3cead384d8c305"}, - {file = "tokenizers-0.20.1-cp37-none-win_amd64.whl", hash = "sha256:896195eb9dfdc85c8c052e29947169c1fcbe75a254c4b5792cdbd451587bce85"}, - {file = "tokenizers-0.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:741fb22788482d09d68e73ece1495cfc6d9b29a06c37b3df90564a9cfa688e6d"}, - {file = "tokenizers-0.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:10be14ebd8082086a342d969e17fc2d6edc856c59dbdbddd25f158fa40eaf043"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:514cf279b22fa1ae0bc08e143458c74ad3b56cd078b319464959685a35c53d5e"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a647c5b7cb896d6430cf3e01b4e9a2d77f719c84cefcef825d404830c2071da2"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cdf379219e1e1dd432091058dab325a2e6235ebb23e0aec8d0508567c90cd01"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ba72260449e16c4c2f6f3252823b059fbf2d31b32617e582003f2b18b415c39"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:910b96ed87316e4277b23c7bcaf667ce849c7cc379a453fa179e7e09290eeb25"}, - {file = "tokenizers-0.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e53975a6694428a0586534cc1354b2408d4e010a3103117f617cbb550299797c"}, - {file = "tokenizers-0.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:07c4b7be58da142b0730cc4e5fd66bb7bf6f57f4986ddda73833cd39efef8a01"}, - {file = "tokenizers-0.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b605c540753e62199bf15cf69c333e934077ef2350262af2ccada46026f83d1c"}, - {file = "tokenizers-0.20.1-cp38-none-win32.whl", hash = "sha256:88b3bc76ab4db1ab95ead623d49c95205411e26302cf9f74203e762ac7e85685"}, - {file = "tokenizers-0.20.1-cp38-none-win_amd64.whl", hash = "sha256:d412a74cf5b3f68a90c615611a5aa4478bb303d1c65961d22db45001df68afcb"}, - {file = "tokenizers-0.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a25dcb2f41a0a6aac31999e6c96a75e9152fa0127af8ece46c2f784f23b8197a"}, - {file = "tokenizers-0.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a12c3cebb8c92e9c35a23ab10d3852aee522f385c28d0b4fe48c0b7527d59762"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02e18da58cf115b7c40de973609c35bde95856012ba42a41ee919c77935af251"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f326a1ac51ae909b9760e34671c26cd0dfe15662f447302a9d5bb2d872bab8ab"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b4872647ea6f25224e2833b044b0b19084e39400e8ead3cfe751238b0802140"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce6238a3311bb8e4c15b12600927d35c267b92a52c881ef5717a900ca14793f7"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57b7a8880b208866508b06ce365dc631e7a2472a3faa24daa430d046fb56c885"}, - {file = "tokenizers-0.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a908c69c2897a68f412aa05ba38bfa87a02980df70f5a72fa8490479308b1f2d"}, - {file = "tokenizers-0.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:da1001aa46f4490099c82e2facc4fbc06a6a32bf7de3918ba798010954b775e0"}, - {file = "tokenizers-0.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:42c097390e2f0ed0a5c5d569e6669dd4e9fff7b31c6a5ce6e9c66a61687197de"}, - {file = "tokenizers-0.20.1-cp39-none-win32.whl", hash = "sha256:3d4d218573a3d8b121a1f8c801029d70444ffb6d8f129d4cca1c7b672ee4a24c"}, - {file = "tokenizers-0.20.1-cp39-none-win_amd64.whl", hash = "sha256:37d1e6f616c84fceefa7c6484a01df05caf1e207669121c66213cb5b2911d653"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48689da7a395df41114f516208d6550e3e905e1239cc5ad386686d9358e9cef0"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:712f90ea33f9bd2586b4a90d697c26d56d0a22fd3c91104c5858c4b5b6489a79"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:359eceb6a620c965988fc559cebc0a98db26713758ec4df43fb76d41486a8ed5"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d3caf244ce89d24c87545aafc3448be15870096e796c703a0d68547187192e1"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03b03cf8b9a32254b1bf8a305fb95c6daf1baae0c1f93b27f2b08c9759f41dee"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:218e5a3561561ea0f0ef1559c6d95b825308dbec23fb55b70b92589e7ff2e1e8"}, - {file = "tokenizers-0.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f40df5e0294a95131cc5f0e0eb91fe86d88837abfbee46b9b3610b09860195a7"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:08aaa0d72bb65058e8c4b0455f61b840b156c557e2aca57627056624c3a93976"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:998700177b45f70afeb206ad22c08d9e5f3a80639dae1032bf41e8cbc4dada4b"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62f7fbd3c2c38b179556d879edae442b45f68312019c3a6013e56c3947a4e648"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31e87fca4f6bbf5cc67481b562147fe932f73d5602734de7dd18a8f2eee9c6dd"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:956f21d359ae29dd51ca5726d2c9a44ffafa041c623f5aa33749da87cfa809b9"}, - {file = "tokenizers-0.20.1-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1fbbaf17a393c78d8aedb6a334097c91cb4119a9ced4764ab8cfdc8d254dc9f9"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ebe63e31f9c1a970c53866d814e35ec2ec26fda03097c486f82f3891cee60830"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:81970b80b8ac126910295f8aab2d7ef962009ea39e0d86d304769493f69aaa1e"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:130e35e76f9337ed6c31be386e75d4925ea807055acf18ca1a9b0eec03d8fe23"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd28a8614f5c82a54ab2463554e84ad79526c5184cf4573bbac2efbbbcead457"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9041ee665d0fa7f5c4ccf0f81f5e6b7087f797f85b143c094126fc2611fec9d0"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:62eb9daea2a2c06bcd8113a5824af8ef8ee7405d3a71123ba4d52c79bb3d9f1a"}, - {file = "tokenizers-0.20.1-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f861889707b54a9ab1204030b65fd6c22bdd4a95205deec7994dc22a8baa2ea4"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:89d5c337d74ea6e5e7dc8af124cf177be843bbb9ca6e58c01f75ea103c12c8a9"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:0b7f515c83397e73292accdbbbedc62264e070bae9682f06061e2ddce67cacaf"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0305fc1ec6b1e5052d30d9c1d5c807081a7bd0cae46a33d03117082e91908c"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dc611e6ac0fa00a41de19c3bf6391a05ea201d2d22b757d63f5491ec0e67faa"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5ffe0d7f7bfcfa3b2585776ecf11da2e01c317027c8573c78ebcb8985279e23"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e7edb8ec12c100d5458d15b1e47c0eb30ad606a05641f19af7563bc3d1608c14"}, - {file = "tokenizers-0.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:de291633fb9303555793cc544d4a86e858da529b7d0b752bcaf721ae1d74b2c9"}, - {file = "tokenizers-0.20.1.tar.gz", hash = "sha256:84edcc7cdeeee45ceedb65d518fffb77aec69311c9c8e30f77ad84da3025f002"}, -] - -[package.dependencies] -huggingface-hub = ">=0.16.4,<1.0" - -[package.extras] -dev = ["tokenizers[testing]"] -docs = ["setuptools-rust", "sphinx", "sphinx-rtd-theme"] -testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests", "ruff"] - -[[package]] -name = "tqdm" -version = "4.66.5" -description = "Fast, Extensible Progress Meter" -optional = false -python-versions = ">=3.7" -groups = ["main"] -files = [ - {file = "tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd"}, - {file = "tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[package.extras] -dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] -notebook = ["ipywidgets (>=6)"] -slack = ["slack-sdk"] -telegram = ["requests"] - -[[package]] -name = "typing-extensions" -version = "4.12.2" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, -] - -[[package]] -name = "tzdata" -version = "2024.2" -description = "Provider of IANA time zone data" -optional = false -python-versions = ">=2" -groups = ["main"] -files = [ - {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, - {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, -] - -[[package]] -name = "urllib3" -version = "2.2.3" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, - {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, -] - -[package.extras] -brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] - -[metadata] -lock-version = "2.1" -python-versions = "^3.12" -content-hash = "c7560454f4aab51b844fa489cfa6844f7800703a9ac87a55c02d05226fb1cefc" diff --git a/pyproject.toml b/pyproject.toml index 0b887ae..42186bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,33 +1,59 @@ -[tool.poetry] -name = "doczy-smart-chunking" +[project] +name = "doczy-field-extraction" version = "0.1.0" -description = "" -authors = ["Alex Galarce "] +description = "Contract field extraction using LLMs" readme = "README.md" -package-mode = false +requires-python = ">=3.12" +dependencies = [ + "pandas>=2.2.3", + "boto3>=1.35.40", + "anthropic>=0.36.0", + "python-dotenv>=1.0.1", + "psutil>=6.1.0", + "rapidfuzz>=3.10.1", + "pyxlsb>=1.0.10", + "openpyxl>=3.1.5", + "langchain>=0.3.14", + "langchainhub>=0.1.21", + "langchain-aws>=0.2.11", + "langchain-text-splitters>=0.3.5", + "langchain-community>=0.3.15", + "nltk>=3.9.1", + "rank-bm25>=0.2.2", + "sentence-transformers>=3.4.1", + "faiss-cpu>=1.10.0", + "word2number>=1.1", + "orjson>=3.10.16", + "pymupdf>=1.25.5", + "pillow>=11.2.1", + "xlsxwriter>=3.2.9", + "langchain-classic>=1.0.1", +] -[tool.poetry.dependencies] -python = "^3.12" -pandas = "^2.2.3" -boto3 = "^1.35.40" -anthropic = "^0.36.0" -pymupdf = "^1.25.5" -pillow = "^11.2.1" -python-dotenv = "^1.0.0" - -[tool.poetry.group.dev.dependencies] -pytest = "^8.3.3" -black = "^24.10.0" - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" +[dependency-groups] +dev = [ + "black>=24.10.0", + "mypy>=1.12.0", + "jupyter>=1.1.1", + "isort>=5.13.2", + "pytest>=8.3.3", + "pytest-mock>=3.14.0", +] +test = [ + "pytest>=8.3.3", + "pytest-mock>=3.14.0", + "pytest-cov>=6.0.0", +] [tool.black] line-length = 88 target-version = ['py312'] [tool.mypy] -#disable_error_code = [] -#install_types = true -#non_interactive = true +disable_error_code = ["import-untyped","assignment","name-defined","call-arg","var-annotated","attr-defined","arg-type","return-value"] +exclude = ["scripts/"] +explicit_package_bases = true + +[tool.pytest.ini_options] +pythonpath = ["."] +testpaths = ["src/tests"] diff --git a/readme.md b/readme.md index 2e24cce..49519d1 100644 --- a/readme.md +++ b/readme.md @@ -1,33 +1,123 @@ -# Branching and Release Management Guide +# Field Extraction Pipeline -## Overview +Contract field extraction using LLMs. -This guide outlines the naming conventions, branching strategy, and merging process for our Git repository. +## Setup -## Branch Naming Conventions +### Install uv (if not already installed) -- **Feature Branch**: `feature/` - - Example: `feature/add_build_stage` -- **Bugfix Branch**: `bugfix/` - - Example: `bugfix/pages_duplication` -- **Hotfix Branch**: `hotfix/` - - Example: `hotfix/deployment_failure` +```bash +# Ubuntu/WSL (recommended) +curl -LsSf https://astral.sh/uv/install.sh | sh +source ~/.bashrc # or restart terminal -## .... +# macOS +curl -LsSf https://astral.sh/uv/install.sh | sh -## Branching Strategy +# Windows (PowerShell - native, not WSL) +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" +``` -### Creating Branches +Verify installation: `uv --version` -1. Create a feature branch from `main` using the appropriate naming convention. -2. Create a small and complete change. `main` must always have deployable code. -3. Create a Pull Request back to `main`. -4. Ensure all checks have passed. -5. Merge new code. -6. Ensure the functionality is verified in the dev environment. +### Install dependencies -## Refer to the branching guide in Confluence for more info on this +```bash +uv sync +``` ---- +## Running the Code -This guide ensures that all team members follow the best practices for branch management and releases. \ No newline at end of file +Use `uv run` with Python's module flag from the project root: + +```bash +# Run the default SaaS pipeline +uv run python -m src.pipelines.saas.main + +# Run with unified runner (supports client selection) +uv run python -m src.pipelines.runner --client saas --input-dir /path/to/input + +# Run with specific client +uv run python -m src.pipelines.runner --client clover --input-dir /path/to/input +``` + +**Note:** Always use `uv run` to ensure correct virtual environment. Always use `-m` flag for proper imports. + +## Development + +**Before pushing, always run these checks to avoid breaking the CI pipeline:** + +```bash +# Format code +uv run black src/ + +# Type checking +uv run mypy src/ + +# Run tests +uv run pytest +``` + +All checks must pass before merging to main. + +## Project Structure + +``` +├── src/ +│ ├── pipelines/ # Pipeline implementations +│ │ ├── runner.py # Unified CLI entry point with client routing +│ │ ├── saas/ # Default SaaS pipeline +│ │ │ └── main.py # Main entry point for SaaS +│ │ ├── shared/ # Shared pipeline components +│ │ │ ├── preprocessing/ # Document preprocessing +│ │ │ ├── extraction/ # Field extraction logic +│ │ │ └── postprocessing/ # Result postprocessing +│ │ └── clients/ # Client-specific overrides +│ │ └── clover/ # Clover client customizations +│ ├── core/ # Core utilities (registry, fieldset) +│ ├── constants/ # Constants, mappings, and field definitions +│ │ ├── mappings/ # Crosswalk JSON files +│ │ └── lists/ # Lookup lists +│ ├── prompts/ # LLM prompt templates +│ ├── utils/ # Shared utilities (IO, string, logging, etc.) +│ ├── codes/ # Medical code extraction utilities +│ ├── crosswalk/ # Crosswalk mapping logic +│ ├── embeddings/ # Pre-computed embeddings for code matching +│ ├── qc_qa/ # QC/QA validation pipeline +│ ├── parent_child/ # Parent-child relationship mapping +│ ├── document_classification/ # Document type classification (DTC) +│ └── tests/ # Unit tests +├── documentation/ # Project documentation +├── outputs/ # Pipeline output files (gitignored) +├── logs/ # Log files (gitignored) +└── pyproject.toml # Project dependencies (uv/pip) +``` + +## Branching + +### Naming Conventions + +| Type | Pattern | Use Case | Example | +|------|---------|----------|---------| +| Feature | `feature/-` | New functionality | `feature/PROJ-123-add-export-csv` | +| Bugfix | `bugfix/-` | Bug fixes | `bugfix/PROJ-456-fix-null-handling` | +| Hotfix | `hotfix/-` | Urgent production fixes | `hotfix/PROJ-789-critical-parse-error` | +| Test | `test/` | Testing/experimentation | `test/lesser-table-caching-refactor` | +| Release | `release/` | Release preparation | `release/v1.2.0` | + +### Branch Guidelines + +- Use lowercase with hyphens (kebab-case) for descriptions +- Include ticket number when applicable (e.g., JIRA, GitHub issue) +- Keep branch names concise but descriptive +- Delete branches after merging + +### Workflow + +1. Create branch from `main` +2. Make changes and commit with clear messages +3. Run checks before pushing: `uv run black src/ && uv run mypy src/ && uv run pytest` +4. Create PR to `main` +5. Ensure all CI checks pass +6. Get code review approval +7. Squash and merge diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..5923c8a --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,2 @@ +# Re-export subpackages +from src import pipelines diff --git a/fieldExtraction/src/codes/code_funcs.py b/src/codes/code_funcs.py similarity index 94% rename from fieldExtraction/src/codes/code_funcs.py rename to src/codes/code_funcs.py index d232649..b2929fa 100644 --- a/fieldExtraction/src/codes/code_funcs.py +++ b/src/codes/code_funcs.py @@ -10,8 +10,8 @@ import src.config as config import src.prompts.prompt_templates as prompt_templates import src.utils.llm_utils as llm_utils import src.utils.string_utils as string_utils -from constants.constants import Constants -from constants.delimiters import Delimiter +from src.constants.constants import Constants +from src.constants.delimiters import Delimiter from src.prompts.fieldset import FieldSet @@ -159,7 +159,7 @@ def code_category(service, proc_category, hcpcs_level2_mapping, filename): ] code_answer_dict["PROCEDURE_CD"].append(str(code)) code_answer_dict["PROCEDURE_CD_DESC"].append(str(answer)) - + return code_answer_dict @@ -184,9 +184,38 @@ def code_implicit_special(service, filename): special_case_mapping = { "Drugs": ["J0000-J9999"], - "Vaccines": ["J0000-J9999", "90471‑90474", "90620‑90621", "90633", "90647‑90648", "90651", "90670", "90672", "90680‑90681", "90686", "90696", "90698", "90700", "90707", "90710", "90713", "90714"], + "Vaccines": [ + "J0000-J9999", + "90471-90474", + "90620-90621", + "90633", + "90647-90648", + "90651", + "90670", + "90672", + "90680-90681", + "90686", + "90696", + "90698", + "90700", + "90707", + "90710", + "90713", + "90714", + ], "Surgery": ["10004-69990"], - "PT/OT/ST": ["92507-92508", "92526", "97014", "97110", "97112", "97116", "97150", "97161-97168", "97530", "97535"], + "PT/OT/ST": [ + "92507-92508", + "92526", + "97014", + "97110", + "97112", + "97116", + "97150", + "97161-97168", + "97530", + "97535", + ], "PT": ["PT Codes TBD"], "OT": ["OT Codes TBD"], "ST": ["ST Codes TBD"], @@ -409,7 +438,14 @@ def code_last_check(service, filename): return claude_answer_final -def fill_bill_type(service, answer_dict, BILL_TYPE_MAPPING, BILL_TYPE_REVERSE_MAPPING, reimb_term=None, exhibit_text=None): +def fill_bill_type( + service, + answer_dict, + BILL_TYPE_MAPPING, + BILL_TYPE_REVERSE_MAPPING, + reimb_term=None, + exhibit_text=None, +): """ Fills the BILL_TYPE_CD and BILL_TYPE_CD_DESC fields in the answer dictionary. @@ -426,21 +462,28 @@ def fill_bill_type(service, answer_dict, BILL_TYPE_MAPPING, BILL_TYPE_REVERSE_MA """ valid_bill_type = sorted(list(set(BILL_TYPE_MAPPING.values()))) - + # First attempt: Service term + reimbursement term claude_answer_raw = llm_utils.invoke_claude( - prompt_templates.FILL_BILL_TYPE(service, valid_bill_type, reimb_term=reimb_term, exhibit_text=None), - "sonnet_latest", - "" + prompt_templates.FILL_BILL_TYPE( + service, valid_bill_type, reimb_term=reimb_term, exhibit_text=None + ), + "sonnet_latest", + "", ) claude_answer_final = string_utils.universal_json_load(claude_answer_raw) - + # Second attempt: Service term + reimbursement term + exhibit context (if first attempt failed and context available) if not claude_answer_final and exhibit_text: claude_answer_raw = llm_utils.invoke_claude( - prompt_templates.FILL_BILL_TYPE(service, valid_bill_type, reimb_term=reimb_term, exhibit_text=exhibit_text), - "sonnet_latest", - "" + prompt_templates.FILL_BILL_TYPE( + service, + valid_bill_type, + reimb_term=reimb_term, + exhibit_text=exhibit_text, + ), + "sonnet_latest", + "", ) claude_answer_final = string_utils.universal_json_load(claude_answer_raw) @@ -550,18 +593,18 @@ def get_implicit_runs(answer_dict): def normalize_answer_dict_codes(answer_dict): """ Normalizes code fields in an answer dictionary to JSON list format. - + Args: answer_dict (dict): Dictionary containing code fields to normalize. Returns: dict: Dictionary with normalized code fields. """ fields_to_normalize = ["REVENUE_CD", "PROCEDURE_CD", "CPT4_PROC_CD"] - + for field in fields_to_normalize: if field in answer_dict: answer_dict[field] = string_utils.normalize_to_json_list(answer_dict[field]) - + return answer_dict @@ -745,12 +788,22 @@ def code_breakout(merged_results: pd.DataFrame, constants: Constants): df = pd.DataFrame(answer_dicts_with_code) # Normalize code columns to JSON list format - for col in ["PROCEDURE_CD", "CPT4_PROC_MOD", "REVENUE_CD", "DIAG_CD", "GROUPER_CD", "NDC_CD", "CLAIM_ADMIT_TYPE_CD", "CLAIM_STATUS_CD"]: + for col in [ + "PROCEDURE_CD", + "CPT4_PROC_MOD", + "REVENUE_CD", + "DIAG_CD", + "GROUPER_CD", + "NDC_CD", + "CLAIM_ADMIT_TYPE_CD", + "CLAIM_STATUS_CD", + ]: if col in df.columns: df[col] = df[col].apply(string_utils.normalize_to_json_list) return df + def grouper_breakout(results_with_code: pd.DataFrame): """ Processes a DataFrame to extract and fill in grouper-related information in cases where we got a grouper_cd from code_breakout @@ -778,7 +831,9 @@ def grouper_breakout(results_with_code: pd.DataFrame): else: no_breakout_needed.append(answer_dict) - logging.debug(f"Grouper breakout: {len(needs_breakout)} rows need LLM processing, {len(no_breakout_needed)} rows skip") + logging.debug( + f"Grouper breakout: {len(needs_breakout)} rows need LLM processing, {len(no_breakout_needed)} rows skip" + ) # Parallelize LLM calls for rows that need breakout def process_grouper_breakout(answer_dict): @@ -801,7 +856,9 @@ def grouper_breakout(results_with_code: pd.DataFrame): if needs_breakout: max_workers = min(len(needs_breakout), 10) with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: - processed_breakout = list(executor.map(process_grouper_breakout, needs_breakout)) + processed_breakout = list( + executor.map(process_grouper_breakout, needs_breakout) + ) else: processed_breakout = [] diff --git a/fieldExtraction/src/codes/main.py b/src/codes/main.py similarity index 92% rename from fieldExtraction/src/codes/main.py rename to src/codes/main.py index 19cdcf7..96ebdf5 100644 --- a/fieldExtraction/src/codes/main.py +++ b/src/codes/main.py @@ -6,7 +6,7 @@ import src.codes.code_funcs as code_funcs import src.config as config import src.utils.string_utils as string_utils import src.utils.io_utils as io_utils -from constants.constants import Constants +from src.constants.constants import Constants from sentence_transformers import SentenceTransformer @@ -74,7 +74,16 @@ def main(): print(f"Error updating DataFrame at row {idx}, key '{key}': {e}") # NORMALIZE ALL CODE COLUMNS - for col in ["CPT4_PROC_CD", "CPT4_PROC_MOD", "REVENUE_CD", "DIAG_CD", "GROUPER_CD", "NDC_CD", "CLAIM_ADMIT_TYPE_CD", "CLAIM_STATUS_CD"]: + for col in [ + "CPT4_PROC_CD", + "CPT4_PROC_MOD", + "REVENUE_CD", + "DIAG_CD", + "GROUPER_CD", + "NDC_CD", + "CLAIM_ADMIT_TYPE_CD", + "CLAIM_STATUS_CD", + ]: if col in df.columns: df[col] = df[col].apply(string_utils.normalize_to_json_list) @@ -98,4 +107,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/fieldExtraction/src/config.py b/src/config.py similarity index 84% rename from fieldExtraction/src/config.py rename to src/config.py index 36f78c4..9429d1d 100644 --- a/fieldExtraction/src/config.py +++ b/src/config.py @@ -108,6 +108,10 @@ ENABLE_RUNTIME_ROTATION = False # Set to True to enable multi-runtime failover FIELDS = get_arg_value("fields", "all") # Valid: one_to_one, one_to_n, all FIELD_JSON_PATH = "src/prompts/investment_prompts.json" +# Client-specific prompts +CLOVER_PROMPTS_PATH = "src/prompts/clover_prompts.json" +BCBS_PROMISE_PROMPTS_PATH = "src/prompts/bcbs_promise_prompts.json" + RAG_RETRIEVAL_QUESTIONS_PATH = "src/prompts/rag_retrieval_questions.json" # Client-specific args @@ -173,8 +177,22 @@ PROV_TYPE = None ######################################## I/O SETTINGS ######################################## -CONSOLIDATED_OUTPUT_DIRECTORY = "output_consolidated" -REPORTING_OUTPUT_DIRECTORY = "output_reports" +OUTPUT_BASE = "outputs" + +# Determine client-specific output directory +# saas → outputs/saas, clover → outputs/clients/clover, etc. +_client_name = CLIENT[0].lower() if CLIENT and CLIENT[0] != "None" else "saas" +if _client_name == "saas": + CONSOLIDATED_OUTPUT_DIRECTORY = f"{OUTPUT_BASE}/saas" +else: + CONSOLIDATED_OUTPUT_DIRECTORY = f"{OUTPUT_BASE}/clients/{_client_name}" + +# Pipeline-specific output directories +SAAS_OUTPUT_DIRECTORY = f"{OUTPUT_BASE}/saas" +QC_QA_OUTPUT_DIRECTORY = f"{OUTPUT_BASE}/qc_qa" +PARENT_CHILD_OUTPUT_DIRECTORY = f"{OUTPUT_BASE}/parent_child" +INDIVIDUAL_OUTPUT_DIRECTORY = f"{OUTPUT_BASE}/individual" +REPORTING_OUTPUT_DIRECTORY = f"{OUTPUT_BASE}/reports" UNPROCESSED_RESULTS_NAME = f"{BATCH_ID}-B-Unprocessed.csv" AC_RESULTS_NAME = f"{BATCH_ID}-AC.csv" @@ -272,12 +290,21 @@ COMPLEX_OUTPUT_FILENAME = f"{TODAY}_complex_flag_test.csv" TABLE_ROW_LIMIT = 10 +######################################## TABLE SPLITTING SETTINGS ######################################## +# Enable table splitting feature +TABLE_SPLITTING_ENABLED = get_arg_value("table_splitting_enabled", "True") == "True" +# Maximum cells (rows × columns) per table sub-page +MAX_TABLE_CELLS_PER_SUBPAGE = int(get_arg_value("max_table_cells_per_subpage", "40")) +# Minimum rows to trigger splitting +MIN_TABLE_ROWS_TO_SPLIT = int(get_arg_value("min_table_rows_to_split", "20")) +# Table splitting method (currently only "cells" is supported) +TABLE_SPLITTING_METHOD = get_arg_value("table_splitting_method", "cells") + ######################################## EC2 ######################################## # DEPRECATED: MODEL_STATS and GLOBAL_STATS are no longer updated. - def assume_role_and_get_runtime(account_id, role_name): sts_client = boto3.client("sts") role_arn = f"arn:aws:iam::{account_id}:role/{role_name}" @@ -311,16 +338,24 @@ ENABLE_VISION = get_arg_value("enable_vision", "False") == "True" # False by de ############## PARENT CHILD CONFIG ############## PERFORM_PARENT_CHILD_MAPPING = get_arg_value("perform_pc", "False") == "True" -DOCZY_OUTPUT_FOR_PC = get_arg_value("doczy_output_for_pc", "") # Pass either S3 URI path, or local path +DOCZY_OUTPUT_FOR_PC = get_arg_value( + "doczy_output_for_pc", "" +) # Pass either S3 URI path, or local path WRITE_PC_TO_S3 = get_arg_value("write_pc_to_s3", "False") == "True" ############## DOCUMENT TYPE CLASSIFICATION SETTINGS ############## -PERFORM_DTC = get_arg_value("perform_dtc", "False") == "True" # Enable document type classification pre-filter +PERFORM_DTC = ( + get_arg_value("perform_dtc", "False") == "True" +) # Enable document type classification pre-filter DTC_PROMPTS_JSON_PATH = "src/prompts/document_classification_prompts.json" -DTC_MAX_PAGES_TO_CHECK = 5 # Number of pages to check per document for contract detection -DTC_OUTPUT_FILE = f"{BATCH_ID}_Document_Classification_Report.csv" # Output CSV file path +DTC_MAX_PAGES_TO_CHECK = ( + 5 # Number of pages to check per document for contract detection +) +DTC_OUTPUT_FILE = ( + f"{BATCH_ID}_Document_Classification_Report.csv" # Output CSV file path +) DTC_JSON_OUTPUT_FOLDER = "dtc_json_results" # Folder for individual JSON results ############## QC/QA VALIDATION SETTINGS ############## # Enable QC/QA validation in pipeline -ENABLE_QC_QA = get_arg_value("enable_qc_qa", "True") == "True" \ No newline at end of file +ENABLE_QC_QA = get_arg_value("enable_qc_qa", "True") == "True" diff --git a/fieldExtraction/src/__init__.py b/src/constants/__init__.py similarity index 100% rename from fieldExtraction/src/__init__.py rename to src/constants/__init__.py diff --git a/fieldExtraction/constants/constants.py b/src/constants/constants.py similarity index 71% rename from fieldExtraction/constants/constants.py rename to src/constants/constants.py index ab66359..fad51e3 100644 --- a/fieldExtraction/constants/constants.py +++ b/src/constants/constants.py @@ -1,8 +1,17 @@ +from pathlib import Path from sentence_transformers import SentenceTransformer from src.crosswalk.crosswalk_builder import CrosswalkBuilder from src.crosswalk.list_builder import ListBuilder -from constants.embedding import CodeEmbedding +from src.constants.embedding import CodeEmbedding + +# Absolute path to src/ directory +_SRC_DIR = Path(__file__).parent.parent.resolve() + + +def _path(relative_path: str) -> str: + """Resolve a path relative to the src/ directory.""" + return str(_SRC_DIR / relative_path) class Constants: @@ -14,66 +23,66 @@ class Constants: # Dynamic Primary self.CROSSWALK_LOB = CrosswalkBuilder().from_json( - path="constants/mappings/crosswalk_lob.json" + path=_path("constants/mappings/crosswalk_lob.json") ) self.VALID_LOBS = list(self.CROSSWALK_LOB.mapping.keys()) self.CROSSWALK_PROGRAM = CrosswalkBuilder().from_json( - path="constants/mappings/crosswalk_program.json" + path=_path("constants/mappings/crosswalk_program.json") ) self.VALID_PROGRAMS = list(self.CROSSWALK_PROGRAM.mapping.keys()) self.CROSSWALK_NETWORK = CrosswalkBuilder().from_json( - path="constants/mappings/crosswalk_network.json" + path=_path("constants/mappings/crosswalk_network.json") ) self.VALID_NETWORKS = list(self.CROSSWALK_NETWORK.mapping.keys()) self.CROSSWALK_PRODUCT = CrosswalkBuilder().from_json( - path="constants/mappings/crosswalk_product_lob.json" + path=_path("constants/mappings/crosswalk_product_lob.json") ) self.VALID_PRODUCTS = list(self.CROSSWALK_PRODUCT.mapping.keys()) # Dynamic Codes self.CROSSWALK_PROV_SPECIALTY_CD = CrosswalkBuilder().from_json( - path="constants/mappings/crosswalk_provider_specialty.json" + path=_path("constants/mappings/crosswalk_provider_specialty.json") ) self.VALID_PROV_SPECIALTY = list( self.CROSSWALK_PROV_SPECIALTY_CD.mapping.keys() ) self.CROSSWALK_BILL_TYPE_CD = CrosswalkBuilder().from_json( - path="constants/mappings/crosswalk_bill_type.json" + path=_path("constants/mappings/crosswalk_bill_type.json") ) self.VALID_BILL_TYPE = list(set(self.CROSSWALK_BILL_TYPE_CD.mapping.values())) self.CROSSWALK_PLACE_OF_SERVICE_CD = CrosswalkBuilder().from_json( - path="constants/mappings/crosswalk_place_of_service.json" + path=_path("constants/mappings/crosswalk_place_of_service.json") ) self.VALID_PLACE_OF_SERVICE = list( self.CROSSWALK_PLACE_OF_SERVICE_CD.mapping.keys() ) self.CROSSWALK_CLAIM_TYPE_CD = CrosswalkBuilder().from_json( - path="constants/mappings/crosswalk_claim_type.json" + path=_path("constants/mappings/crosswalk_claim_type.json") ) self.VALID_CLAIM_TYPE = list(set(self.CROSSWALK_CLAIM_TYPE_CD.mapping.keys())) # Provider Type self.LIST_VALID_PROV_TYPE = ( - ListBuilder().from_json("constants/lists/valid_prov_type.json").list + ListBuilder().from_json(_path("constants/lists/valid_prov_type.json")).list ) #################################### Code Breakout #################################### self.SYNONYM_MAP = ( CrosswalkBuilder() - .from_json(path="constants/mappings/synonym_map.json") + .from_json(path=_path("constants/mappings/synonym_map.json")) .mapping ) self.STOP_WORD_LIST = ( - ListBuilder().from_json("constants/lists/stop_words.json").list + ListBuilder().from_json(_path("constants/lists/stop_words.json")).list ) self.DO_NOT_RUN = ( - ListBuilder().from_json("constants/lists/do_not_run.json").list + ListBuilder().from_json(_path("constants/lists/do_not_run.json")).list ) self.REMOVAL_LIST = self._load_removal_list() @@ -81,51 +90,63 @@ class Constants: self.CPT_LEVEL1_MAPPING = ( CrosswalkBuilder() .from_excel( - "constants/mapping_csvs/proc_cd/cpt_level1.csv", "Code", "Description" + "src/constants/mapping_csvs/proc_cd/cpt_level1.csv", + "Code", + "Description", ) .mapping ) self.CPT_LEVEL2_MAPPING = ( CrosswalkBuilder() .from_excel( - "constants/mapping_csvs/proc_cd/cpt_level2.csv", "Code", "Description" + "src/constants/mapping_csvs/proc_cd/cpt_level2.csv", + "Code", + "Description", ) .mapping ) - # self.CPT_LEVEL3_MAPPING = CrosswalkBuilder().from_excel("constants/mapping_csvs/proc_cd/cpt_level3.csv", "Code", "Description").mapping + # self.CPT_LEVEL3_MAPPING = CrosswalkBuilder().from_excel(_path("constants/mapping_csvs/proc_cd/cpt_level3.csv", "Code", "Description").mapping self.HCPCS_LEVEL1_MAPPING = ( CrosswalkBuilder() .from_excel( - "constants/mapping_csvs/proc_cd/hcpcs_level1.csv", "Code", "Description" + "src/constants/mapping_csvs/proc_cd/hcpcs_level1.csv", + "Code", + "Description", ) .mapping ) self.HCPCS_LEVEL2_MAPPING = ( CrosswalkBuilder() .from_excel( - "constants/mapping_csvs/proc_cd/hcpcs_level2.csv", "Code", "Description" + "src/constants/mapping_csvs/proc_cd/hcpcs_level2.csv", + "Code", + "Description", ) .mapping ) - # self.HCPCS_MAPPING = CrosswalkBuilder().from_excel("constants/mapping_csvs/proc_cd/hcpcs.csv", "Code", "Description").mapping + # self.HCPCS_MAPPING = CrosswalkBuilder().from_excel(_path("constants/mapping_csvs/proc_cd/hcpcs.csv", "Code", "Description").mapping self.REV_LEVEL1_MAPPING = ( CrosswalkBuilder() .from_excel( - "constants/mapping_csvs/rev_cd/rev_level1.csv", "Code", "Description" + "src/constants/mapping_csvs/rev_cd/rev_level1.csv", + "Code", + "Description", ) .mapping ) self.REV_MAPPING = ( CrosswalkBuilder() - .from_excel("constants/mapping_csvs/rev_cd/rev.csv", "Code", "Description") + .from_excel( + _path("constants/mapping_csvs/rev_cd/rev.csv"), "Code", "Description" + ) .mapping ) self.GROUPER_APR_DRG_MAPPING = ( CrosswalkBuilder() .from_excel( - "constants/mapping_csvs/grouper_cd/drg_mapping_apr-drg.csv", + "src/constants/mapping_csvs/grouper_cd/drg_mapping_apr-drg.csv", "Code", "Description", ) @@ -134,7 +155,7 @@ class Constants: self.GROUPER_MS_DRG_MAPPING = ( CrosswalkBuilder() .from_excel( - "constants/mapping_csvs/grouper_cd/drg_mapping_ms-drg.csv", + "src/constants/mapping_csvs/grouper_cd/drg_mapping_ms-drg.csv", "Code", "Description", ) @@ -143,12 +164,12 @@ class Constants: self.BILL_TYPE_MAPPING = ( CrosswalkBuilder() - .from_json("constants/mappings/crosswalk_bill_type.json") + .from_json(_path("constants/mappings/crosswalk_bill_type.json")) .mapping ) self.BILL_TYPE_REVERSE_MAPPING = ( CrosswalkBuilder() - .from_json("constants/mappings/crosswalk_bill_type.json") + .from_json(_path("constants/mappings/crosswalk_bill_type.json")) .create_reverse_mapping() ) @@ -168,40 +189,42 @@ class Constants: #################################### Methodology Breakout #################################### self.VALID_AARETE_DERIVED_FEE_SCHEDULE = ( - ListBuilder().from_json(path="constants/lists/valid_fee_schedule.json").list + ListBuilder() + .from_json(path=_path("constants/lists/valid_fee_schedule.json")) + .list ) self.VALID_AARETE_DERIVED_FEE_SCHEDULE_VERSION = ( ListBuilder() - .from_json(path="constants/lists/valid_fee_schedule_version.json") + .from_json(path=_path("constants/lists/valid_fee_schedule_version.json")) .list ) self.VALID_REIMB_METHODOLOGY = ( ListBuilder() - .from_json(path="constants/lists/valid_reimb_methodology.json") + .from_json(path=_path("constants/lists/valid_reimb_methodology.json")) .list ) self.VALID_UNIT_OF_MEASURE = ( ListBuilder() - .from_json(path="constants/lists/valid_unit_of_measure.json") + .from_json(path=_path("constants/lists/valid_unit_of_measure.json")) .list ) #################################### Carveout and Special Case #################################### self.VALID_CARVEOUTS = ( CrosswalkBuilder() - .from_json(path="constants/mappings/valid_carveouts.json") + .from_json(path=_path("constants/mappings/valid_carveouts.json")) .mapping ) #################################### Other #################################### self.COMPOUND_INDICATORS = ( ListBuilder() - .from_json(path="constants/lists/compound_indicators.json") + .from_json(path=_path("constants/lists/compound_indicators.json")) .list ) self.EXHIBIT_HEADER_MARKERS = ( ListBuilder() - .from_json(path="constants/lists/exhibit_header_markers.json") + .from_json(path=_path("constants/lists/exhibit_header_markers.json")) .list ) @@ -213,7 +236,7 @@ class Constants: + list( set( CrosswalkBuilder() - .from_json(path="constants/mappings/crosswalk_network.json") + .from_json(path=_path("constants/mappings/crosswalk_network.json")) .mapping.values() ) ) @@ -221,7 +244,7 @@ class Constants: + list( set( CrosswalkBuilder() - .from_json(path="constants/mappings/crosswalk_program.json") + .from_json(path=_path("constants/mappings/crosswalk_program.json")) .mapping.values() ) ) diff --git a/fieldExtraction/constants/delimiters.py b/src/constants/delimiters.py similarity index 100% rename from fieldExtraction/constants/delimiters.py rename to src/constants/delimiters.py diff --git a/src/constants/embedding.py b/src/constants/embedding.py new file mode 100644 index 0000000..31fb32f --- /dev/null +++ b/src/constants/embedding.py @@ -0,0 +1,26 @@ +import pickle +from pathlib import Path + +import faiss +import numpy as np + +# Absolute path to src/ directory (where embeddings/ folder is) +_SRC_DIR = Path(__file__).parent.parent.resolve() + + +class CodeEmbedding: + """Class to manage Embeddings for a Doczy.ai execution""" + + def __init__( + self, + level, + index_name="faiss_index.bin", + embedding_name="embeddings.npy", + choices_name="choices.pkl", + ): + self.level = level + embeddings_dir = _SRC_DIR / "embeddings" / level + self.index = faiss.read_index(str(embeddings_dir / index_name)) + self.embeddings = np.load(str(embeddings_dir / embedding_name)) + with open(str(embeddings_dir / choices_name), "rb") as f: + self.choices = pickle.load(f) diff --git a/fieldExtraction/constants/investment_columns.py b/src/constants/investment_columns.py similarity index 100% rename from fieldExtraction/constants/investment_columns.py rename to src/constants/investment_columns.py diff --git a/fieldExtraction/constants/lists/compound_indicators.json b/src/constants/lists/compound_indicators.json similarity index 100% rename from fieldExtraction/constants/lists/compound_indicators.json rename to src/constants/lists/compound_indicators.json diff --git a/fieldExtraction/constants/lists/do_not_run.json b/src/constants/lists/do_not_run.json similarity index 100% rename from fieldExtraction/constants/lists/do_not_run.json rename to src/constants/lists/do_not_run.json diff --git a/fieldExtraction/constants/lists/exhibit_header_markers.json b/src/constants/lists/exhibit_header_markers.json similarity index 100% rename from fieldExtraction/constants/lists/exhibit_header_markers.json rename to src/constants/lists/exhibit_header_markers.json diff --git a/fieldExtraction/constants/lists/stop_words.json b/src/constants/lists/stop_words.json similarity index 100% rename from fieldExtraction/constants/lists/stop_words.json rename to src/constants/lists/stop_words.json diff --git a/fieldExtraction/constants/lists/valid_fee_schedule.json b/src/constants/lists/valid_fee_schedule.json similarity index 100% rename from fieldExtraction/constants/lists/valid_fee_schedule.json rename to src/constants/lists/valid_fee_schedule.json diff --git a/fieldExtraction/constants/lists/valid_fee_schedule_version.json b/src/constants/lists/valid_fee_schedule_version.json similarity index 100% rename from fieldExtraction/constants/lists/valid_fee_schedule_version.json rename to src/constants/lists/valid_fee_schedule_version.json diff --git a/fieldExtraction/constants/lists/valid_prov_type.json b/src/constants/lists/valid_prov_type.json similarity index 100% rename from fieldExtraction/constants/lists/valid_prov_type.json rename to src/constants/lists/valid_prov_type.json diff --git a/fieldExtraction/constants/lists/valid_reimb_methodology.json b/src/constants/lists/valid_reimb_methodology.json similarity index 100% rename from fieldExtraction/constants/lists/valid_reimb_methodology.json rename to src/constants/lists/valid_reimb_methodology.json diff --git a/fieldExtraction/constants/lists/valid_unit_of_measure.json b/src/constants/lists/valid_unit_of_measure.json similarity index 100% rename from fieldExtraction/constants/lists/valid_unit_of_measure.json rename to src/constants/lists/valid_unit_of_measure.json diff --git a/fieldExtraction/constants/mapping_csvs/admit_type_cd/admit_mapping.csv b/src/constants/mapping_csvs/admit_type_cd/admit_mapping.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/admit_type_cd/admit_mapping.csv rename to src/constants/mapping_csvs/admit_type_cd/admit_mapping.csv diff --git a/fieldExtraction/constants/mapping_csvs/diag_cd/diag.csv b/src/constants/mapping_csvs/diag_cd/diag.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/diag_cd/diag.csv rename to src/constants/mapping_csvs/diag_cd/diag.csv diff --git a/fieldExtraction/constants/mapping_csvs/grouper_cd/drg_mapping_apr-drg.csv b/src/constants/mapping_csvs/grouper_cd/drg_mapping_apr-drg.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/grouper_cd/drg_mapping_apr-drg.csv rename to src/constants/mapping_csvs/grouper_cd/drg_mapping_apr-drg.csv diff --git a/fieldExtraction/constants/mapping_csvs/grouper_cd/drg_mapping_ms-drg.csv b/src/constants/mapping_csvs/grouper_cd/drg_mapping_ms-drg.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/grouper_cd/drg_mapping_ms-drg.csv rename to src/constants/mapping_csvs/grouper_cd/drg_mapping_ms-drg.csv diff --git a/fieldExtraction/constants/mapping_csvs/proc_cd/cpt.csv b/src/constants/mapping_csvs/proc_cd/cpt.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/proc_cd/cpt.csv rename to src/constants/mapping_csvs/proc_cd/cpt.csv diff --git a/fieldExtraction/constants/mapping_csvs/proc_cd/cpt_level1.csv b/src/constants/mapping_csvs/proc_cd/cpt_level1.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/proc_cd/cpt_level1.csv rename to src/constants/mapping_csvs/proc_cd/cpt_level1.csv diff --git a/fieldExtraction/constants/mapping_csvs/proc_cd/cpt_level2.csv b/src/constants/mapping_csvs/proc_cd/cpt_level2.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/proc_cd/cpt_level2.csv rename to src/constants/mapping_csvs/proc_cd/cpt_level2.csv diff --git a/fieldExtraction/constants/mapping_csvs/proc_cd/cpt_level3.csv b/src/constants/mapping_csvs/proc_cd/cpt_level3.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/proc_cd/cpt_level3.csv rename to src/constants/mapping_csvs/proc_cd/cpt_level3.csv diff --git a/fieldExtraction/constants/mapping_csvs/proc_cd/hcpcs.csv b/src/constants/mapping_csvs/proc_cd/hcpcs.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/proc_cd/hcpcs.csv rename to src/constants/mapping_csvs/proc_cd/hcpcs.csv diff --git a/fieldExtraction/constants/mapping_csvs/proc_cd/hcpcs_level1.csv b/src/constants/mapping_csvs/proc_cd/hcpcs_level1.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/proc_cd/hcpcs_level1.csv rename to src/constants/mapping_csvs/proc_cd/hcpcs_level1.csv diff --git a/fieldExtraction/constants/mapping_csvs/proc_cd/hcpcs_level2.csv b/src/constants/mapping_csvs/proc_cd/hcpcs_level2.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/proc_cd/hcpcs_level2.csv rename to src/constants/mapping_csvs/proc_cd/hcpcs_level2.csv diff --git a/fieldExtraction/constants/mapping_csvs/rev_cd/rev.csv b/src/constants/mapping_csvs/rev_cd/rev.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/rev_cd/rev.csv rename to src/constants/mapping_csvs/rev_cd/rev.csv diff --git a/fieldExtraction/constants/mapping_csvs/rev_cd/rev_level1.csv b/src/constants/mapping_csvs/rev_cd/rev_level1.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/rev_cd/rev_level1.csv rename to src/constants/mapping_csvs/rev_cd/rev_level1.csv diff --git a/fieldExtraction/constants/mapping_csvs/taxonomy_cd/taxonomy_mapping.csv b/src/constants/mapping_csvs/taxonomy_cd/taxonomy_mapping.csv similarity index 100% rename from fieldExtraction/constants/mapping_csvs/taxonomy_cd/taxonomy_mapping.csv rename to src/constants/mapping_csvs/taxonomy_cd/taxonomy_mapping.csv diff --git a/fieldExtraction/constants/mappings/crosswalk_bill_type.json b/src/constants/mappings/crosswalk_bill_type.json similarity index 100% rename from fieldExtraction/constants/mappings/crosswalk_bill_type.json rename to src/constants/mappings/crosswalk_bill_type.json diff --git a/fieldExtraction/constants/mappings/crosswalk_claim_type.json b/src/constants/mappings/crosswalk_claim_type.json similarity index 100% rename from fieldExtraction/constants/mappings/crosswalk_claim_type.json rename to src/constants/mappings/crosswalk_claim_type.json diff --git a/fieldExtraction/constants/mappings/crosswalk_lob.json b/src/constants/mappings/crosswalk_lob.json similarity index 100% rename from fieldExtraction/constants/mappings/crosswalk_lob.json rename to src/constants/mappings/crosswalk_lob.json diff --git a/fieldExtraction/constants/mappings/crosswalk_network.json b/src/constants/mappings/crosswalk_network.json similarity index 100% rename from fieldExtraction/constants/mappings/crosswalk_network.json rename to src/constants/mappings/crosswalk_network.json diff --git a/fieldExtraction/constants/mappings/crosswalk_place_of_service.json b/src/constants/mappings/crosswalk_place_of_service.json similarity index 100% rename from fieldExtraction/constants/mappings/crosswalk_place_of_service.json rename to src/constants/mappings/crosswalk_place_of_service.json diff --git a/fieldExtraction/constants/mappings/crosswalk_product_lob.json b/src/constants/mappings/crosswalk_product_lob.json similarity index 100% rename from fieldExtraction/constants/mappings/crosswalk_product_lob.json rename to src/constants/mappings/crosswalk_product_lob.json diff --git a/fieldExtraction/constants/mappings/crosswalk_program.json b/src/constants/mappings/crosswalk_program.json similarity index 100% rename from fieldExtraction/constants/mappings/crosswalk_program.json rename to src/constants/mappings/crosswalk_program.json diff --git a/fieldExtraction/constants/mappings/crosswalk_program_lob.json b/src/constants/mappings/crosswalk_program_lob.json similarity index 100% rename from fieldExtraction/constants/mappings/crosswalk_program_lob.json rename to src/constants/mappings/crosswalk_program_lob.json diff --git a/fieldExtraction/constants/mappings/crosswalk_provider_specialty.json b/src/constants/mappings/crosswalk_provider_specialty.json similarity index 100% rename from fieldExtraction/constants/mappings/crosswalk_provider_specialty.json rename to src/constants/mappings/crosswalk_provider_specialty.json diff --git a/fieldExtraction/constants/mappings/exclude_keywords_for_pc.json b/src/constants/mappings/exclude_keywords_for_pc.json similarity index 100% rename from fieldExtraction/constants/mappings/exclude_keywords_for_pc.json rename to src/constants/mappings/exclude_keywords_for_pc.json diff --git a/fieldExtraction/constants/mappings/numeric_mappigs.json b/src/constants/mappings/numeric_mappigs.json similarity index 100% rename from fieldExtraction/constants/mappings/numeric_mappigs.json rename to src/constants/mappings/numeric_mappigs.json diff --git a/fieldExtraction/constants/mappings/stop_words_for_pc_cleanup.json b/src/constants/mappings/stop_words_for_pc_cleanup.json similarity index 100% rename from fieldExtraction/constants/mappings/stop_words_for_pc_cleanup.json rename to src/constants/mappings/stop_words_for_pc_cleanup.json diff --git a/fieldExtraction/constants/mappings/synonym_map.json b/src/constants/mappings/synonym_map.json similarity index 100% rename from fieldExtraction/constants/mappings/synonym_map.json rename to src/constants/mappings/synonym_map.json diff --git a/fieldExtraction/constants/mappings/valid_carveouts.json b/src/constants/mappings/valid_carveouts.json similarity index 100% rename from fieldExtraction/constants/mappings/valid_carveouts.json rename to src/constants/mappings/valid_carveouts.json diff --git a/fieldExtraction/constants/regex_patterns.py b/src/constants/regex_patterns.py similarity index 100% rename from fieldExtraction/constants/regex_patterns.py rename to src/constants/regex_patterns.py diff --git a/src/core/__init__.py b/src/core/__init__.py new file mode 100644 index 0000000..74871a6 --- /dev/null +++ b/src/core/__init__.py @@ -0,0 +1,21 @@ +""" +Core framework abstractions for the extraction pipeline. + +This module provides: +- Field/FieldSet: Field definitions and management +- PipelineRegistry: Client pipeline discovery and access +- BasePipeline: Base class for pipeline implementations +""" + +from src.core.fieldset import Field, FieldSet +from src.core.registry import PipelineRegistry, get_registry +from src.core.base_pipeline import BasePipeline, SaaSPipeline + +__all__ = [ + "Field", + "FieldSet", + "PipelineRegistry", + "get_registry", + "BasePipeline", + "SaaSPipeline", +] diff --git a/src/core/base_pipeline.py b/src/core/base_pipeline.py new file mode 100644 index 0000000..4f92a53 --- /dev/null +++ b/src/core/base_pipeline.py @@ -0,0 +1,271 @@ +""" +Base Pipeline Class + +Abstract base class defining the interface for all extraction pipelines. +SaaS pipeline and client-specific pipelines inherit from this class. + +Usage: + from src.core.base_pipeline import BasePipeline + + class MolinaPipeline(BasePipeline): + def preprocess(self, text, config): + # Custom preprocessing for Molina + ... +""" + +from abc import ABC, abstractmethod +from typing import Any, Dict, List, Optional, Tuple +import pandas as pd + + +class BasePipeline(ABC): + """ + Abstract base class for extraction pipelines. + + Defines the contract that all pipeline implementations must follow. + Provides hooks for customization at each stage of processing. + """ + + def __init__(self, client_name: str = "saas", config: Optional[dict] = None): + """ + Initialize the pipeline. + + Args: + client_name: Name of the client this pipeline serves + config: Optional configuration dictionary + """ + self.client_name = client_name + self.config = config or {} + + # ========================================================================= + # PREPROCESSING STAGE + # ========================================================================= + + def preprocess(self, text: str, **kwargs) -> Dict[str, Any]: + """ + Preprocess raw text before extraction. + + Override this method to customize text preprocessing. + Default implementation calls the standard preprocessing. + + Args: + text: Raw document text + **kwargs: Additional preprocessing options + + Returns: + Dict containing preprocessed data (chunks, metadata, etc.) + """ + return self._default_preprocess(text, **kwargs) + + def _default_preprocess(self, text: str, **kwargs) -> Dict[str, Any]: + """Default preprocessing implementation using saas module.""" + from src.pipelines.shared.preprocessing import preprocess + + return preprocess.preprocess(text, **kwargs) + + # ========================================================================= + # EXTRACTION STAGE + # ========================================================================= + + def extract_one_to_one( + self, text: str, fields: List[Any], **kwargs + ) -> Dict[str, Any]: + """ + Extract one-to-one fields (single value per document). + + Override this method to customize one-to-one extraction. + + Args: + text: Preprocessed document text + fields: List of Field objects to extract + **kwargs: Additional extraction options + + Returns: + Dict mapping field names to extracted values + """ + return self._default_extract_one_to_one(text, fields, **kwargs) + + def _default_extract_one_to_one( + self, text: str, fields: List[Any], **kwargs + ) -> Dict[str, Any]: + """Default one-to-one extraction using saas module.""" + from src.pipelines.shared.extraction import one_to_one_funcs + + return one_to_one_funcs.extract_one_to_one_fields(text, fields, **kwargs) + + def extract_one_to_n( + self, text: str, fields: List[Any], **kwargs + ) -> List[Dict[str, Any]]: + """ + Extract one-to-n fields (multiple values per document). + + Override this method to customize one-to-n extraction. + + Args: + text: Preprocessed document text + fields: List of Field objects to extract + **kwargs: Additional extraction options + + Returns: + List of dicts, each containing extracted values for one row + """ + return self._default_extract_one_to_n(text, fields, **kwargs) + + def _default_extract_one_to_n( + self, text: str, fields: List[Any], **kwargs + ) -> List[Dict[str, Any]]: + """Default one-to-n extraction using saas module.""" + from src.pipelines.shared.extraction import one_to_n_funcs + + return one_to_n_funcs.extract_one_to_n_fields(text, fields, **kwargs) + + # ========================================================================= + # POSTPROCESSING STAGE + # ========================================================================= + + def postprocess( + self, results: Dict[str, Any], **kwargs + ) -> Tuple[pd.DataFrame, Dict[str, Any]]: + """ + Postprocess extraction results. + + Override this method to customize postprocessing logic. + + Args: + results: Raw extraction results + **kwargs: Additional postprocessing options + + Returns: + Tuple of (processed DataFrame, metadata dict) + """ + return self._default_postprocess(results, **kwargs) + + def _default_postprocess( + self, results: Dict[str, Any], **kwargs + ) -> Tuple[pd.DataFrame, Dict[str, Any]]: + """Default postprocessing using saas module.""" + from src.pipelines.shared.postprocessing import postprocess + + return postprocess.postprocess(results, **kwargs) + + # ========================================================================= + # FULL PIPELINE + # ========================================================================= + + def process_file(self, file_path: str, **kwargs) -> Tuple[pd.DataFrame, Dict]: + """ + Process a single file through the complete pipeline. + + Override this for full control over the pipeline flow. + + Args: + file_path: Path to the file to process + **kwargs: Additional processing options + + Returns: + Tuple of (results DataFrame, metadata dict) + """ + return self._default_process_file(file_path, **kwargs) + + def _default_process_file( + self, file_path: str, **kwargs + ) -> Tuple[pd.DataFrame, Dict]: + """Default file processing using saas module.""" + from src.pipelines.saas import file_processing + + return file_processing.process_file(file_path, **kwargs) + + # ========================================================================= + # HOOKS FOR CLIENT CUSTOMIZATION + # ========================================================================= + + def on_before_preprocess(self, text: str, **kwargs) -> str: + """ + Hook called before preprocessing. + + Override to modify text before preprocessing. + """ + return text + + def on_after_preprocess(self, result: Dict[str, Any], **kwargs) -> Dict[str, Any]: + """ + Hook called after preprocessing. + + Override to modify preprocessing results. + """ + return result + + def on_before_extraction(self, data: Dict[str, Any], **kwargs) -> Dict[str, Any]: + """ + Hook called before extraction. + + Override to modify data before extraction. + """ + return data + + def on_after_extraction(self, results: Dict[str, Any], **kwargs) -> Dict[str, Any]: + """ + Hook called after extraction. + + Override to modify extraction results. + """ + return results + + def on_before_postprocess( + self, results: Dict[str, Any], **kwargs + ) -> Dict[str, Any]: + """ + Hook called before postprocessing. + + Override to modify results before postprocessing. + """ + return results + + def on_after_postprocess( + self, df: pd.DataFrame, metadata: Dict, **kwargs + ) -> Tuple[pd.DataFrame, Dict]: + """ + Hook called after postprocessing. + + Override to modify final results. + """ + return df, metadata + + # ========================================================================= + # UTILITY METHODS + # ========================================================================= + + def get_fields(self, field_type: str = None) -> List[Any]: + """ + Get field definitions for this pipeline. + + Override to provide client-specific field definitions. + + Args: + field_type: Optional filter for field type + + Returns: + List of Field objects + """ + from src.core.fieldset import FieldSet + import src.config as config + + filters = {} + if field_type: + filters["field_type"] = field_type + + return FieldSet(file_path=config.FIELD_JSON_PATH, **filters) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(client={self.client_name})" + + +class SaaSPipeline(BasePipeline): + """ + Default SaaS pipeline implementation. + + Uses all default methods from BasePipeline. + """ + + def __init__(self, config: Optional[dict] = None): + super().__init__(client_name="saas", config=config) diff --git a/fieldExtraction/constants/embedding.py b/src/core/embedding.py similarity index 50% rename from fieldExtraction/constants/embedding.py rename to src/core/embedding.py index d93e48e..3cd4022 100644 --- a/fieldExtraction/constants/embedding.py +++ b/src/core/embedding.py @@ -1,9 +1,13 @@ import os import pickle +from pathlib import Path import faiss import numpy as np +# Absolute path to src/ directory +_SRC_DIR = Path(__file__).parent.parent.resolve() + class CodeEmbedding: """Class to manage Embeddings for a Doczy.ai execution""" @@ -16,7 +20,8 @@ class CodeEmbedding: choices_name="choices.pkl", ): self.level = level - self.index = faiss.read_index(os.path.join("embeddings", level, index_name)) - self.embeddings = np.load(os.path.join("embeddings", level, embedding_name)) - with open(os.path.join("embeddings", level, choices_name), "rb") as f: + embeddings_dir = _SRC_DIR / "embeddings" / level + self.index = faiss.read_index(str(embeddings_dir / index_name)) + self.embeddings = np.load(str(embeddings_dir / embedding_name)) + with open(str(embeddings_dir / choices_name), "rb") as f: self.choices = pickle.load(f) diff --git a/fieldExtraction/src/prompts/fieldset.py b/src/core/fieldset.py similarity index 99% rename from fieldExtraction/src/prompts/fieldset.py rename to src/core/fieldset.py index 10a0330..5f9d21c 100644 --- a/fieldExtraction/src/prompts/fieldset.py +++ b/src/core/fieldset.py @@ -2,7 +2,7 @@ import json from threading import Lock import src.utils.string_utils as string_utils -from constants.constants import Constants +from src.constants.constants import Constants # =================================================================== # FILE CACHING IMPLEMENTATION @@ -198,7 +198,7 @@ class Field: raise AttributeError( f"Breakout template '{self.breakout_template}' not found in prompt_templates module" ) - + def get_valid_values(self, constants: Constants): return constants.get_constant(self.valid_values) @@ -213,7 +213,7 @@ class FieldSet: FieldSet(file_path="investment_prompts.json", relationship="one_to_one") FieldSet(file_path="investment_prompts.json", relationship="one_to_n", field_type="exhibit_level") FieldSet(file_path="investment_prompts.json", field_type="reimbursement_level") - + # Now supports lists for any attribute: FieldSet(file_path="investment_prompts.json", field_name=["LOB", "PROGRAM"]) FieldSet(file_path="investment_prompts.json", field_type=["exhibit_level", "reimbursement_level"]) @@ -261,10 +261,10 @@ class FieldSet: for field_dict in data: # Check if this field_dict matches all filters matches_all_filters = True - + for attr, filter_value in filters.items(): field_value = field_dict.get(attr) - + # Handle special case for True filter (check if attribute exists) if filter_value is True: if field_value is None: @@ -279,7 +279,7 @@ class FieldSet: elif field_value != filter_value: matches_all_filters = False break - + # If all filters matched, add this field if matches_all_filters: self.fields.append(Field(field_dict)) diff --git a/src/core/registry.py b/src/core/registry.py new file mode 100644 index 0000000..6c8a0cd --- /dev/null +++ b/src/core/registry.py @@ -0,0 +1,170 @@ +""" +Client Pipeline Registry + +Auto-discovers and manages client pipeline implementations. +Provides a unified interface for getting the correct pipeline based on client name. + +Usage: + from src.core.registry import PipelineRegistry + + registry = PipelineRegistry() + pipeline = registry.get_pipeline("molina") # Returns Molina pipeline + pipeline = registry.get_pipeline("saas") # Returns default SaaS pipeline +""" + +import importlib +import os +from pathlib import Path +from typing import Dict, Optional, Type, Any + + +class PipelineRegistry: + """ + Registry for client pipeline implementations. + + Automatically discovers client implementations in pipelines/clients/ + and provides a unified interface for accessing them. + """ + + _instance = None + _initialized = False + + def __new__(cls): + """Singleton pattern - only one registry instance.""" + if cls._instance is None: + cls._instance = super().__new__(cls) + return cls._instance + + def __init__(self): + """Initialize the registry with discovered clients.""" + if PipelineRegistry._initialized: + return + + self._clients: Dict[str, dict] = {} + self._base_path = Path(__file__).parent.parent / "pipelines" + self._discover_clients() + PipelineRegistry._initialized = True + + def _discover_clients(self) -> None: + """ + Discover all client implementations in pipelines/clients/. + + Each client directory should have: + - __init__.py + - config.yaml (optional) + - Various override modules (preprocessing/, extraction/, etc.) + """ + clients_path = self._base_path / "clients" + + if not clients_path.exists(): + return + + for client_dir in clients_path.iterdir(): + if client_dir.is_dir() and not client_dir.name.startswith("_"): + client_name = client_dir.name.lower() + self._clients[client_name] = { + "name": client_name, + "path": client_dir, + "has_config": (client_dir / "config.yaml").exists(), + "has_preprocessing": (client_dir / "preprocessing").is_dir(), + "has_extraction": (client_dir / "extraction").is_dir(), + "has_postprocessing": (client_dir / "postprocessing").is_dir(), + "has_prompts": (client_dir / "prompts").is_dir(), + } + + def list_clients(self) -> list: + """Return list of all registered client names.""" + return list(self._clients.keys()) + + def get_client_info(self, client_name: str) -> Optional[dict]: + """ + Get information about a specific client. + + Args: + client_name: Name of the client (case-insensitive) + + Returns: + Dict with client info or None if not found + """ + return self._clients.get(client_name.lower()) + + def has_client(self, client_name: str) -> bool: + """Check if a client is registered.""" + return client_name.lower() in self._clients + + def get_module(self, client_name: str, module_type: str) -> Any: + """ + Get a specific module for a client, falling back to saas if not overridden. + + Args: + client_name: Name of the client (or "saas" for default) + module_type: One of "preprocessing", "extraction", "postprocessing", "prompts" + + Returns: + The imported module + + Example: + preprocessing = registry.get_module("molina", "preprocessing") + # Returns molina's preprocessing if it exists, else saas preprocessing + """ + client_name = client_name.lower() + + # Check if client has this module overridden + if client_name != "saas" and self.has_client(client_name): + client_info = self._clients[client_name] + has_override = client_info.get(f"has_{module_type}", False) + + if has_override: + module_path = f"src.pipelines.clients.{client_name}.{module_type}" + try: + return importlib.import_module(module_path) + except ImportError: + pass # Fall through to saas + + # Default to saas module + saas_module_path = f"src.pipelines.saas.{module_type}" + return importlib.import_module(saas_module_path) + + def get_config(self, client_name: str) -> Optional[dict]: + """ + Load client configuration from config.yaml. + + Args: + client_name: Name of the client + + Returns: + Dict with config or None if no config exists + """ + import yaml + + client_name = client_name.lower() + + if client_name == "saas": + config_path = self._base_path / "saas" / "config.yaml" + elif self.has_client(client_name): + config_path = self._clients[client_name]["path"] / "config.yaml" + else: + return None + + if config_path.exists(): + with open(config_path, "r") as f: + return yaml.safe_load(f) + + return None + + def refresh(self) -> None: + """Re-discover clients (useful after adding new client directories).""" + self._clients.clear() + self._discover_clients() + + +# Module-level singleton instance +_registry = None + + +def get_registry() -> PipelineRegistry: + """Get the global pipeline registry instance.""" + global _registry + if _registry is None: + _registry = PipelineRegistry() + return _registry diff --git a/fieldExtraction/src/crosswalk/README.md b/src/crosswalk/README.md similarity index 100% rename from fieldExtraction/src/crosswalk/README.md rename to src/crosswalk/README.md diff --git a/fieldExtraction/src/crosswalk/crosswalk_builder.py b/src/crosswalk/crosswalk_builder.py similarity index 100% rename from fieldExtraction/src/crosswalk/crosswalk_builder.py rename to src/crosswalk/crosswalk_builder.py diff --git a/fieldExtraction/src/crosswalk/list_builder.py b/src/crosswalk/list_builder.py similarity index 100% rename from fieldExtraction/src/crosswalk/list_builder.py rename to src/crosswalk/list_builder.py diff --git a/fieldExtraction/src/document_classification/main.py b/src/document_classification/main.py similarity index 98% rename from fieldExtraction/src/document_classification/main.py rename to src/document_classification/main.py index ec3bbc8..9c9f481 100644 --- a/fieldExtraction/src/document_classification/main.py +++ b/src/document_classification/main.py @@ -6,7 +6,7 @@ from threading import Lock import pandas as pd -from src.investment.preprocessing_funcs import ( +from src.pipelines.shared.preprocessing.preprocessing_funcs import ( clean_newlines, split_text, clean_law_symbols, @@ -312,7 +312,7 @@ def main(input_dict, run_timestamp): if __name__ == "__main__": logging.basicConfig( level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", ) # Generate timestamp for this run diff --git a/fieldExtraction/embeddings/cpt_level1/choices.pkl b/src/embeddings/cpt_level1/choices.pkl similarity index 100% rename from fieldExtraction/embeddings/cpt_level1/choices.pkl rename to src/embeddings/cpt_level1/choices.pkl diff --git a/fieldExtraction/embeddings/cpt_level1/embeddings.npy b/src/embeddings/cpt_level1/embeddings.npy similarity index 100% rename from fieldExtraction/embeddings/cpt_level1/embeddings.npy rename to src/embeddings/cpt_level1/embeddings.npy diff --git a/fieldExtraction/embeddings/cpt_level1/faiss_index.bin b/src/embeddings/cpt_level1/faiss_index.bin similarity index 100% rename from fieldExtraction/embeddings/cpt_level1/faiss_index.bin rename to src/embeddings/cpt_level1/faiss_index.bin diff --git a/fieldExtraction/embeddings/cpt_level2/choices.pkl b/src/embeddings/cpt_level2/choices.pkl similarity index 100% rename from fieldExtraction/embeddings/cpt_level2/choices.pkl rename to src/embeddings/cpt_level2/choices.pkl diff --git a/fieldExtraction/embeddings/cpt_level2/embeddings.npy b/src/embeddings/cpt_level2/embeddings.npy similarity index 100% rename from fieldExtraction/embeddings/cpt_level2/embeddings.npy rename to src/embeddings/cpt_level2/embeddings.npy diff --git a/fieldExtraction/embeddings/cpt_level2/faiss_index.bin b/src/embeddings/cpt_level2/faiss_index.bin similarity index 100% rename from fieldExtraction/embeddings/cpt_level2/faiss_index.bin rename to src/embeddings/cpt_level2/faiss_index.bin diff --git a/fieldExtraction/embeddings/cpt_level3/choices.pkl b/src/embeddings/cpt_level3/choices.pkl similarity index 100% rename from fieldExtraction/embeddings/cpt_level3/choices.pkl rename to src/embeddings/cpt_level3/choices.pkl diff --git a/fieldExtraction/embeddings/cpt_level3/embeddings.npy b/src/embeddings/cpt_level3/embeddings.npy similarity index 100% rename from fieldExtraction/embeddings/cpt_level3/embeddings.npy rename to src/embeddings/cpt_level3/embeddings.npy diff --git a/fieldExtraction/embeddings/cpt_level3/faiss_index.bin b/src/embeddings/cpt_level3/faiss_index.bin similarity index 100% rename from fieldExtraction/embeddings/cpt_level3/faiss_index.bin rename to src/embeddings/cpt_level3/faiss_index.bin diff --git a/fieldExtraction/embeddings/hcpcs_level1/choices.pkl b/src/embeddings/hcpcs_level1/choices.pkl similarity index 100% rename from fieldExtraction/embeddings/hcpcs_level1/choices.pkl rename to src/embeddings/hcpcs_level1/choices.pkl diff --git a/fieldExtraction/embeddings/hcpcs_level1/embeddings.npy b/src/embeddings/hcpcs_level1/embeddings.npy similarity index 100% rename from fieldExtraction/embeddings/hcpcs_level1/embeddings.npy rename to src/embeddings/hcpcs_level1/embeddings.npy diff --git a/fieldExtraction/embeddings/hcpcs_level1/faiss_index.bin b/src/embeddings/hcpcs_level1/faiss_index.bin similarity index 100% rename from fieldExtraction/embeddings/hcpcs_level1/faiss_index.bin rename to src/embeddings/hcpcs_level1/faiss_index.bin diff --git a/fieldExtraction/embeddings/hcpcs_level2/choices.pkl b/src/embeddings/hcpcs_level2/choices.pkl similarity index 100% rename from fieldExtraction/embeddings/hcpcs_level2/choices.pkl rename to src/embeddings/hcpcs_level2/choices.pkl diff --git a/fieldExtraction/embeddings/hcpcs_level2/embeddings.npy b/src/embeddings/hcpcs_level2/embeddings.npy similarity index 100% rename from fieldExtraction/embeddings/hcpcs_level2/embeddings.npy rename to src/embeddings/hcpcs_level2/embeddings.npy diff --git a/fieldExtraction/embeddings/hcpcs_level2/faiss_index.bin b/src/embeddings/hcpcs_level2/faiss_index.bin similarity index 100% rename from fieldExtraction/embeddings/hcpcs_level2/faiss_index.bin rename to src/embeddings/hcpcs_level2/faiss_index.bin diff --git a/fieldExtraction/embeddings/rev/choices.pkl b/src/embeddings/rev/choices.pkl similarity index 100% rename from fieldExtraction/embeddings/rev/choices.pkl rename to src/embeddings/rev/choices.pkl diff --git a/fieldExtraction/embeddings/rev/embeddings.npy b/src/embeddings/rev/embeddings.npy similarity index 100% rename from fieldExtraction/embeddings/rev/embeddings.npy rename to src/embeddings/rev/embeddings.npy diff --git a/fieldExtraction/embeddings/rev/faiss_index.bin b/src/embeddings/rev/faiss_index.bin similarity index 100% rename from fieldExtraction/embeddings/rev/faiss_index.bin rename to src/embeddings/rev/faiss_index.bin diff --git a/fieldExtraction/embeddings/rev_level1/choices.pkl b/src/embeddings/rev_level1/choices.pkl similarity index 100% rename from fieldExtraction/embeddings/rev_level1/choices.pkl rename to src/embeddings/rev_level1/choices.pkl diff --git a/fieldExtraction/embeddings/rev_level1/embeddings.npy b/src/embeddings/rev_level1/embeddings.npy similarity index 100% rename from fieldExtraction/embeddings/rev_level1/embeddings.npy rename to src/embeddings/rev_level1/embeddings.npy diff --git a/fieldExtraction/embeddings/rev_level1/faiss_index.bin b/src/embeddings/rev_level1/faiss_index.bin similarity index 100% rename from fieldExtraction/embeddings/rev_level1/faiss_index.bin rename to src/embeddings/rev_level1/faiss_index.bin diff --git a/fieldExtraction/src/investment/__init__.py b/src/parent_child/__init__.py similarity index 100% rename from fieldExtraction/src/investment/__init__.py rename to src/parent_child/__init__.py diff --git a/fieldExtraction/src/parent_child/main.py b/src/parent_child/main.py similarity index 100% rename from fieldExtraction/src/parent_child/main.py rename to src/parent_child/main.py diff --git a/fieldExtraction/src/parent_child/parent_child_mapping.py b/src/parent_child/parent_child_mapping.py similarity index 100% rename from fieldExtraction/src/parent_child/parent_child_mapping.py rename to src/parent_child/parent_child_mapping.py diff --git a/fieldExtraction/src/parent_child/parent_child_preprocessing.py b/src/parent_child/parent_child_preprocessing.py similarity index 99% rename from fieldExtraction/src/parent_child/parent_child_preprocessing.py rename to src/parent_child/parent_child_preprocessing.py index d061044..ff40bfa 100644 --- a/fieldExtraction/src/parent_child/parent_child_preprocessing.py +++ b/src/parent_child/parent_child_preprocessing.py @@ -12,7 +12,7 @@ import logging from src.utils import io_utils stop_words_dict = io_utils.convert_json_to_dict( - "constants/mappings/stop_words_for_pc_cleanup.json" + "src/constants/mappings/stop_words_for_pc_cleanup.json" ) stop_words = stop_words_dict["stop_words"] @@ -28,6 +28,7 @@ def clean_filename(all_fields_df, contact_name_col="FILE_NAME"): # Fixing FILE_ ) return all_fields_df + # ... rest of the file remains the same diff --git a/fieldExtraction/src/.gitignore b/src/pipelines/.gitignore similarity index 100% rename from fieldExtraction/src/.gitignore rename to src/pipelines/.gitignore diff --git a/src/pipelines/__init__.py b/src/pipelines/__init__.py new file mode 100644 index 0000000..6123044 --- /dev/null +++ b/src/pipelines/__init__.py @@ -0,0 +1,2 @@ +# Re-export subpackages +from src.pipelines import shared diff --git a/src/pipelines/clients/__init__.py b/src/pipelines/clients/__init__.py new file mode 100644 index 0000000..a6ee39c --- /dev/null +++ b/src/pipelines/clients/__init__.py @@ -0,0 +1 @@ +"""Client pipeline implementations.""" diff --git a/fieldExtraction/src/parent_child/__init__.py b/src/pipelines/clients/bcbs_promise/__init__.py similarity index 100% rename from fieldExtraction/src/parent_child/__init__.py rename to src/pipelines/clients/bcbs_promise/__init__.py diff --git a/src/pipelines/clients/bcbs_promise/file_processing.py b/src/pipelines/clients/bcbs_promise/file_processing.py new file mode 100644 index 0000000..a962ae5 --- /dev/null +++ b/src/pipelines/clients/bcbs_promise/file_processing.py @@ -0,0 +1,537 @@ +import concurrent.futures +import logging +from typing import TYPE_CHECKING, Optional + +import pandas as pd +import src.codes.code_funcs as code_funcs +from src.pipelines.shared.preprocessing import ( + preprocessing_funcs, + preprocess, + hybrid_smart_chunking_funcs, +) +from src.pipelines.shared.postprocessing import ( + aarete_derived, + postprocess, + postprocessing_funcs, +) +from src.pipelines.shared.extraction import ( + dynamic_funcs, + one_to_n_funcs, + one_to_one_funcs, + row_funcs, + tin_npi_funcs, + exhibit_funcs, +) +from src.pipelines.shared.extraction.exhibit_funcs import Exhibit +from src.utils import io_utils, logging_utils, string_utils, timing_utils +from src.constants.constants import Constants +from src import config +from src.prompts.fieldset import FieldSet +from src.utils.string_utils import datetime_str + +if TYPE_CHECKING: + from src.pipelines.shared.extraction.page_funcs import Page + + +def process_file(file_object, constants: Constants, run_timestamp): + filename, contract_text = file_object + + # Set per-file logging context: + # With this, all logging calls in this thread will now route to logs/{filename}.log + # This includes logging from all called functions (preprocess, one_to_n_funcs, etc.) + logging_utils.set_current_file(filename) + logging.info(f"{datetime_str()} Processing {filename}...") + + # Set default values + dynamic_one_to_one_fields = FieldSet() + process_one_to_n = config.FIELDS in ["all", "one_to_n"] + process_one_to_one = config.FIELDS in ["all", "one_to_one"] + # Initialize default fallback for final results + final_results = pd.DataFrame([{"FILE_NAME": filename}]) + + ################## PREPROCESS ################## + with timing_utils.timed_block("preprocess", context=filename): + contract_text = preprocess.clean_text(contract_text) + text_dict, top_sheet_dict = preprocess.split_text(contract_text) + text_dict, header, footer = preprocess.find_headers_and_footers(text_dict) + + # ONE TO N PROCESSING + one_to_n_results = pd.DataFrame() # Initialize empty DataFrame for one_to_n_results + if process_one_to_n: + # Use split_text_with_pages() to get Page objects with table splitting + # Note: split_text_with_pages() internally calls split_text() which applies headers/footers + # But we need to apply headers/footers first, so we'll create pages_dict from the cleaned text_dict + from src.pipelines.shared.extraction.page_funcs import Page + from src.pipelines.shared.preprocessing import preprocessing_funcs as prep_funcs + + # Create pages_dict from text_dict (headers/footers already applied) + pages_dict = prep_funcs.split_large_tables(text_dict) + + with timing_utils.timed_block("one_to_n_exhibit_chunking", context=filename): + # Use pages_dict for exhibit chunking (preferred) or fall back to text_dict + exhibit_chunk_mapping, all_exhibit_headers = ( + preprocess.one_to_n_exhibit_chunking( + pages_dict=pages_dict, + text_dict=text_dict, + EXHIBIT_HEADER_MARKERS=constants.EXHIBIT_HEADER_MARKERS, + filename=filename, + ) + ) + logging.info(f"{datetime_str()} Preprocessing Complete - {filename}") + + one_to_n_results = pd.DataFrame([{"FILE_NAME": filename}]) # Initialize here + + if string_utils.contains_reimbursement(contract_text): + logging.info( + f"{datetime_str()} Starting One-to-N extraction for {len(exhibit_chunk_mapping)} exhibits - {filename}" + ) + with timing_utils.timed_block("one_to_n_extraction", context=filename): + ( + one_to_n_results, + dynamic_one_to_one_fields, + first_reimbursement_page, + ) = run_one_to_n_prompts( + pages_dict=pages_dict, + text_dict=text_dict, + exhibit_chunk_mapping=exhibit_chunk_mapping, + all_exhibit_headers=all_exhibit_headers, + constants=constants, + filename=filename, + ) + if not one_to_n_results.empty: + one_to_n_results["FILE_NAME"] = filename + with timing_utils.timed_block( + "one_to_n_generate_reimb_ids", context=filename + ): + one_to_n_results = postprocessing_funcs.generate_reimb_ids( + one_to_n_results + ) + logging.info(f"{datetime_str()} One to N Complete - {filename}") + else: + first_reimbursement_page = "1" + logging.info( + f"{datetime_str()} No Reimbursement Found, Skipping - {filename}" + ) + + final_results = one_to_n_results # Set as final results + else: + first_reimbursement_page = "1" + logging.info( + f"{datetime_str()} Fields not configured for One to N, Skipping - {filename}" + ) + + # ONE TO ONE PROCESSING + if process_one_to_one: + with timing_utils.timed_block("one_to_one_extraction", context=filename): + one_to_one_results = run_one_to_one_prompts( + filename, + contract_text, + text_dict, + top_sheet_dict, + dynamic_one_to_one_fields, + first_reimbursement_page, + constants, + ) + one_to_one_results["FILE_NAME"] = filename + logging.info(f"{datetime_str()} One to One Complete - {filename}") + + # Decide how to handle one_to_one results + with timing_utils.timed_block( + "merge_one_to_one_into_one_to_n", context=filename + ): + if not one_to_n_results.empty: + # BOTH processed - merge into one_to_n + final_results = row_funcs.merge_one_to_one_into_one_to_n( + one_to_n_results, one_to_one_results, constants + ) + else: + # ONLY one_to_one processed - convert dict to DataFrame + final_results = pd.DataFrame([one_to_one_results]) + else: + logging.info( + f"{datetime_str()} Fields not configured for One to One, Skipping - {filename}" + ) + + # APPLY CODES IF ONE_TO_N WAS PROCESSED + if not one_to_n_results.empty: + with timing_utils.timed_block("code_processing", context=filename): + results_with_code = code_funcs.code_breakout(final_results, constants) + final_results = code_funcs.grouper_breakout(results_with_code) + logging.info(f"{datetime_str()} Codes Complete - {filename}") + + # POSTPROCESS + with timing_utils.timed_block("postprocess", context=filename): + final_df = postprocess.postprocess(final_results, constants) + logging.info(f"{datetime_str()} Postprocessing Complete - {filename}") + + ################## WRITE INDIVIDUAL ################## + with timing_utils.timed_block("write_individual", context=filename): + if config.WRITE_TO_S3: + io_utils.write_s3(final_df, filename, run_timestamp, "individual") + else: + io_utils.write_local(final_df, filename, "", "individual") + + logging.info(f"{datetime_str()} Writing Complete - {filename}") + + return final_df + + +def run_one_to_one_prompts( + filename: str, + contract_text: str, + text_dict: dict[str, str], + top_sheet_dict, + dynamic_one_to_one_fields: FieldSet, + first_reimbursement_page: str, + constants: Constants, +): + + ################## INITIALIZE FIELDS ################## + one_to_one_fields = FieldSet( + relationship="one_to_one", file_path=config.FIELD_JSON_PATH + ).combine(dynamic_one_to_one_fields) + + ################## INITIALIZE BCBS PROMISE FIELDS ################## + bcbs_promise_fields = FieldSet( + relationship="one_to_one", file_path=config.BCBS_PROMISE_PROMPTS_PATH + ) + # Combine bcbs_promise fields with one_to_one_fields for HSC processing + hsc_fields = one_to_one_fields.combine(bcbs_promise_fields) + + ################## RUN PROVIDER INFO ################## + with timing_utils.timed_block("one_to_one.provider_info", context=filename): + one_to_one_results = tin_npi_funcs.run_provider_info_fields( + contract_text, text_dict, filename, payer_name="" + ) + + ################## RUN HYBRID SMART CHUNKED PROMPTS ################## + # RAG function loads retrieval questions internally + # hsc_fields includes both investment_prompts.json AND bcbs_promise_prompts.json fields + with timing_utils.timed_block("one_to_one.hybrid_smart_chunking", context=filename): + hybrid_smart_chunked_answers_dict = ( + hybrid_smart_chunking_funcs.run_hybrid_smart_chunked_fields( + hsc_fields, constants, contract_text, filename, text_dict + ) + ) + + ################## RUN FULL CONTEXT PROMPTS ################## + # Use hsc_fields (not one_to_one_fields) to include bcbs_promise fields + # This ensures fallback to full_context works if HSC fails for any field + with timing_utils.timed_block("one_to_one.full_context", context=filename): + full_context_answers_dict = one_to_one_funcs.run_full_context_fields( + hsc_fields, + contract_text, + text_dict, + first_reimbursement_page, + constants, + filename, + ) + ################## COMBINE ANSWERS ################ + # Prefer HSC answers over full_context when HSC value is not N/A + for key, value in full_context_answers_dict.items(): + one_to_one_results[key] = value + + for key, value in hybrid_smart_chunked_answers_dict.items(): + if not string_utils.is_empty(value): + one_to_one_results[key] = value + elif key not in one_to_one_results: + # Add HSC's N/A if field doesn't exist yet + one_to_one_results[key] = value + + one_to_one_results = tin_npi_funcs.merge_provider_info_with_hybrid_smart_chunking( + one_to_one_results, filename + ) + + ################## DERIVE BCBS PROMISE FIELDS ################## + # Derive OFFSET_INDICATOR from OFFSET_TERM + offset_term = one_to_one_results.get("OFFSET_TERM", "N/A") + if not string_utils.is_empty(offset_term): + one_to_one_results["OFFSET_INDICATOR"] = "Y" + else: + one_to_one_results["OFFSET_INDICATOR"] = "N" + + ################## ADD AD FIELDS ################ + one_to_one_results = one_to_one_funcs.get_aarete_derived_dates( + one_to_one_results, text_dict, filename + ) + + ################## ADD SIGNATURE COUNT ################## + one_to_one_results = one_to_one_funcs.add_signature_count( + one_to_one_results, contract_text + ) + + ################## Crosswalk Fields ################## + one_to_one_results = aarete_derived.get_crosswalk_fields( + [one_to_one_results], constants + ) + + ################## Fill NA Mapping ################## + one_to_one_results = aarete_derived.fill_na_mapping(one_to_one_results) + + return one_to_one_results[0] + + +def process_page_reimbursements( + exhibit: Exhibit, + page_num: str, + pages_dict: Optional[dict[str, "Page"]] = None, + text_dict: Optional[dict[str, str]] = None, + exhibit_page_nums: Optional[list[str]] = None, + constants: Optional[Constants] = None, + filename: Optional[str] = None, +): + """ + STEP 1 HELPER: Extract reimbursements from a single page (without exhibit-level fields). + Runs: reimbursement_level → carveout_and_special_case → lesser_of_distribution → breakout + + Args: + exhibit: Exhibit object containing the page + page_num: Page identifier (can be "27" or "27.1" for sub-pages) + pages_dict: Dictionary mapping page numbers to Page objects (preferred) + text_dict: Dictionary mapping page numbers to text strings (for backward compatibility) + exhibit_page_nums: List of page numbers in the exhibit (for backward compatibility) + constants: Constants object + filename: Name of the file being processed + """ + # Get page text - prefer using exhibit.get_page_text() if available + if exhibit.pages is not None: + page_text = exhibit.get_page_text(page_num) + exhibit_page_nums = exhibit.exhibit_page_nums + elif pages_dict is not None: + # Handle sub-pages: "27.1" means get sub-page "1" from page "27" + if "." in page_num and not page_num.startswith("."): + base_page, sub_page = page_num.rsplit(".", 1) + if base_page in pages_dict: + page_text = pages_dict[base_page].get_text(sub_page) + else: + page_text = "" + elif page_num in pages_dict: + page_text = pages_dict[page_num].get_text() + else: + page_text = "" + exhibit_page_nums = ( + exhibit.exhibit_page_nums + if exhibit_page_nums is None + else exhibit_page_nums + ) + elif text_dict is not None: + page_text = text_dict.get(page_num, "") + exhibit_page_nums = ( + exhibit_page_nums + if exhibit_page_nums is not None + else exhibit.exhibit_page_nums + ) + else: + raise ValueError( + "Either pages_dict, text_dict, or exhibit.pages must be provided" + ) + + # Simplify exhibit text - prefer using exhibit object + exhibit_text_simplified = preprocessing_funcs.simplify_exhibit( + exhibit=exhibit, + current_page_num=page_num, + ) + + ############################### Reimbursement Primary ############################### + reimbursement_level_answers = one_to_n_funcs.reimbursement_level( + page_text, constants, filename + ) + + if not reimbursement_level_answers: + return [], [] + + ################################ Carveouts and Special Case ################################ + reimbursement_level_answers, special_case_answers = ( + one_to_n_funcs.carveout_and_special_case( + reimbursement_level_answers, constants, filename + ) + ) + + ############################### Lesser of Distribution ############################### + # Note: We run lesser_of without dynamic fields in Step 1 + reimbursement_level_answers = one_to_n_funcs.lesser_of_distribution( + reimbursement_level_answers, + exhibit_text_simplified, + page_num, + constants, + filename, + exhibit, # ← Added this parameter + ) + + ################################ Get Breakouts ############################### + reimbursement_level_answers, special_case_answers = one_to_n_funcs.breakout( + reimbursement_level_answers, + special_case_answers, + filename, + constants, + ) + + ################################ Assign REIMB_PAGE ############################### + for answer_dict in reimbursement_level_answers: + answer_dict["REIMB_PAGE"] = page_num + + return reimbursement_level_answers, special_case_answers + + +def run_one_to_n_prompts( + pages_dict: Optional[dict[str, "Page"]] = None, + text_dict: Optional[dict[str, str]] = None, + exhibit_chunk_mapping: Optional[dict[str, list[str]]] = None, + all_exhibit_headers: Optional[dict[str, str]] = None, + constants: Optional[Constants] = None, + filename: Optional[str] = None, +): + """ + 3-STEP APPROACH (per exhibit): + Step 1: Extract reimbursements for exhibit pages (parallel within exhibit) + Step 2: Run exhibit_level when exhibit has reimbursements + Step 3: Run dynamic_assignment and combine results + + Args: + pages_dict: Dictionary mapping page numbers to Page objects (preferred) + text_dict: Dictionary mapping page numbers to text strings (for backward compatibility) + exhibit_chunk_mapping: Dictionary mapping exhibit pages to lists of page numbers + all_exhibit_headers: Dictionary mapping exhibit pages to their headers + constants: Constants object + filename: Name of the file being processed + """ + if exhibit_chunk_mapping is None: + exhibit_chunk_mapping = {} + if all_exhibit_headers is None: + all_exhibit_headers = {} + + total_exhibits = len(exhibit_chunk_mapping) + logging.debug( + f"{datetime_str()} Processing {total_exhibits} exhibits with NEW 3-step approach - {filename}" + ) + + # Create Exhibit objects in order (maintains exhibit chain via prev_exhibit) + exhibits = exhibit_funcs.get_exhibit_list( + pages_dict=pages_dict, + text_dict=text_dict, + exhibit_chunk_mapping=exhibit_chunk_mapping, + all_exhibit_headers=all_exhibit_headers, + ) # <- Returns list[Exhibit] + + # Process exhibits serially; within each exhibit, process pages in parallel + total_pages = sum(len(exhibit.exhibit_page_nums) for exhibit in exhibits) + completed_pages = 0 + one_to_n_results = [] + first_reimbursement_page = "1" + + for exhibit in exhibits: + exhibit_pages = exhibit.exhibit_page_nums + if exhibit_pages: + with concurrent.futures.ThreadPoolExecutor( + max_workers=min(len(exhibit_pages), 20) + ) as executor: + page_futures = { + executor.submit( + process_page_reimbursements, + exhibit, + page_num, + pages_dict, + text_dict, + exhibit_pages, + constants, + filename, + ): page_num + for page_num in exhibit_pages + } + + for future in concurrent.futures.as_completed(page_futures): + try: + page_num = page_futures[future] + reimbursement_rows, special_case_rows = future.result() + exhibit.add_reimbursement_rows( + reimbursement_rows, special_case_rows + ) + completed_pages += 1 + if completed_pages % 20 == 0 or completed_pages == total_pages: + logging.debug( + f"{datetime_str()} Page progress: {completed_pages}/{total_pages} - {filename}" + ) + except Exception as e: + logging.error(f"Error processing page: {str(e)}") + + if not exhibit.has_reimbursements: + continue + + # STEP 2: exhibit_level for this exhibit + exhibit_level_answers, dynamic_reimbursement_fields = ( + one_to_n_funcs.exhibit_level( + exhibit.exhibit_text, + exhibit.exhibit_header, + exhibit.exhibit_page, + constants, + filename, + ) + ) + exhibit.set_exhibit_level_data( + exhibit_level_answers, dynamic_reimbursement_fields + ) + logging.debug( + f"Exhibit Level Answers for {filename}, Page {exhibit.exhibit_page}: {exhibit_level_answers}" + ) + + # STEP 3: dynamic assignment & combine for this exhibit + # Get dynamic fields from previous exhibit if needed (for future use) + if exhibit.dynamic_reimbursement_fields: + dynamic_fields = exhibit.dynamic_reimbursement_fields + elif ( + exhibit.prev_exhibit + and not exhibit.prev_exhibit.has_reimbursements + and exhibit.get_previous_exhibit_dynamic_fields().fields + ): + dynamic_fields = exhibit.get_previous_exhibit_dynamic_fields() + else: + dynamic_fields = None + + # Run dynamic assignment for ALL reimbursement rows in this exhibit + # Note: dynamic_assignment expects a list of rows and returns a list of rows + reimbursement_rows_with_dynamic = exhibit.reimbursement_rows + if exhibit.reimbursement_rows and dynamic_fields is not None: + reimbursement_rows_with_dynamic = dynamic_funcs.dynamic_assignment( + exhibit.reimbursement_rows, + dynamic_fields, + pages_dict, + text_dict, + exhibit, + constants, + filename, + ) + + # Combine reimbursement rows with exhibit-level answers + combined_rows = row_funcs.combine_one_to_n( + exhibit.exhibit_text, + reimbursement_rows_with_dynamic, + exhibit.special_case_rows, + exhibit.exhibit_level_answers, + filename, + ) + + # Run cleaning + combined_rows = one_to_n_funcs.one_to_n_cleaning( + combined_rows, exhibit.exhibit_text, constants, filename + ) + + exhibit.final_rows = combined_rows + one_to_n_results.extend(combined_rows) + + # Track first reimbursement page + if first_reimbursement_page == "1" and exhibit.has_reimbursements: + first_reimbursement_page = exhibit.exhibit_page + + logging.debug( + f"{datetime_str()} STEP 3 COMPLETE: Combined {len(one_to_n_results)} total rows - {filename}" + ) + + ################## Add N/A Dynamic or Exhibit to One-to-One ################## + dynamic_one_to_one_fields = dynamic_funcs.get_dynamic_one_to_one_fields( + one_to_n_results, constants + ) + + ################## CONVERT TO DF ################## + one_to_n_df = pd.DataFrame(one_to_n_results) + + return one_to_n_df, dynamic_one_to_one_fields, first_reimbursement_page diff --git a/fieldExtraction/src/investment/main.py b/src/pipelines/clients/bcbs_promise/main.py similarity index 83% rename from fieldExtraction/src/investment/main.py rename to src/pipelines/clients/bcbs_promise/main.py index 549048f..0344109 100644 --- a/fieldExtraction/src/investment/main.py +++ b/src/pipelines/clients/bcbs_promise/main.py @@ -1,6 +1,5 @@ import concurrent.futures import logging -import os import random import time import traceback @@ -10,18 +9,23 @@ import pandas as pd random.seed(42) -import src.investment.file_processing as file_processing +import src.pipelines.saas.file_processing as file_processing import src.prompts.prompt_templates as prompt_templates import src.utils.io_utils as io_utils import src.utils.llm_utils as llm_utils import src.utils.logging_utils as logging_utils import src.utils.usage_tracking as usage_tracking import src.utils.timing_utils as timing_utils -from constants.constants import Constants +from src.constants.constants import Constants from src import config from src.parent_child import main as parent_child_main from src.document_classification import main as dtc_main -from src.qc_qa.pipeline import generate_statistics, run_qc_qa_pipeline, save_qc_qa_outputs +from src.qc_qa.pipeline import ( + generate_statistics, + run_qc_qa_pipeline, + save_qc_qa_outputs, +) + def safe_process_file(item, constants, run_timestamp): """Process a single file with comprehensive error handling. @@ -103,7 +107,9 @@ def main(testing=False, test_params={}): max_workers = test_params["max_workers"] if "input_files" in test_params: input_dict = { - k: v for k, v in input_dict.items() if k in test_params["input_files"] + k: v + for k, v in input_dict.items() + if k in test_params["input_files"] } logging.info(f"Total Input Files : {len(input_dict)}") @@ -117,7 +123,9 @@ def main(testing=False, test_params={}): # run DTC classification dtc_main.main(input_dict, run_timestamp) - logging.info("DTC classification complete. Exiting (investment pipeline not run).") + logging.info( + "DTC classification complete. Exiting (investment pipeline not run)." + ) logging.info("=" * 80) return @@ -126,14 +134,16 @@ def main(testing=False, test_params={}): logging.info("Warming prompt caches before parallel processing...") with timing_utils.timed_block("warm_prompt_caches", log_level="INFO"): try: - cacheable_instructions = prompt_templates.get_cacheable_instructions(constants) + cacheable_instructions = prompt_templates.get_cacheable_instructions() for cache_key, instruction in cacheable_instructions.items(): llm_utils.warm_prompt_cache( instruction=instruction, cache_key=cache_key, - model_id="sonnet_latest" + model_id="sonnet_latest", ) - logging.info(f"Successfully warmed {len(cacheable_instructions)} prompt caches") + logging.info( + f"Successfully warmed {len(cacheable_instructions)} prompt caches" + ) except Exception as e: logging.warning(f"Error warming caches (will proceed anyway): {str(e)}") @@ -164,7 +174,9 @@ def main(testing=False, test_params={}): completed_count += 1 if completed_count % 5 == 0: # Log progress every 5 files - logging.info(f"Processed {completed_count}/{len(futures)} files...") + logging.info( + f"Processed {completed_count}/{len(futures)} files..." + ) except ( Exception ) as e: # When there's an issue with the future itself (not the processing inside the future) @@ -193,7 +205,9 @@ def main(testing=False, test_params={}): try: # Ensure unique index before QC/QA (safety check) if FINAL_RESULT_DF.index.has_duplicates: - logging.warning("Detected duplicate indices in FINAL_RESULT_DF, resetting index...") + logging.warning( + "Detected duplicate indices in FINAL_RESULT_DF, resetting index..." + ) FINAL_RESULT_DF = FINAL_RESULT_DF.reset_index(drop=True) # Create a copy for validation - preserve original FINAL_RESULT_DF @@ -210,7 +224,7 @@ def main(testing=False, test_params={}): validated_df=validated_df, stats_df=qc_qa_stats_df, run_timestamp=run_timestamp, - write_to_s3=config.WRITE_TO_S3 + write_to_s3=config.WRITE_TO_S3, ) except Exception as e: logging.error(f"QC/QA validation failed: {str(e)}") @@ -226,27 +240,41 @@ def main(testing=False, test_params={}): with timing_utils.timed_block("write_outputs", log_level="INFO"): if config.WRITE_TO_S3: - doczy_output_for_pc = io_utils.write_s3(FINAL_RESULT_DF, "", run_timestamp, "final") + doczy_output_for_pc = io_utils.write_s3( + FINAL_RESULT_DF, "", run_timestamp, "final" + ) if not ERROR_RESULT_DF.empty: io_utils.write_s3(ERROR_RESULT_DF, "", run_timestamp, "error") - logging.warning(f"{len(ERROR_RESULT_DF)} files failed processing - error results written to S3") + logging.warning( + f"{len(ERROR_RESULT_DF)} files failed processing - error results written to S3" + ) # Export usage and cost tracking data to S3 only if both dataframes have data if not per_file_usage_df.empty and not batch_summary_df.empty: logging.info("Exporting usage and cost tracking data to S3...") io_utils.write_s3(per_file_usage_df, "", run_timestamp, "usage") - io_utils.write_s3(batch_summary_df, "", run_timestamp, "usage_summary") + io_utils.write_s3( + batch_summary_df, "", run_timestamp, "usage_summary" + ) else: - doczy_output_for_pc = io_utils.write_local(FINAL_RESULT_DF, "", run_timestamp, "final") + doczy_output_for_pc = io_utils.write_local( + FINAL_RESULT_DF, "", run_timestamp, "final" + ) if not ERROR_RESULT_DF.empty: io_utils.write_local(ERROR_RESULT_DF, "", run_timestamp, "error") - logging.warning(f"{len(ERROR_RESULT_DF)} files failed processing - error results written locally") + logging.warning( + f"{len(ERROR_RESULT_DF)} files failed processing - error results written locally" + ) if config.PERFORM_PARENT_CHILD_MAPPING: if FINAL_RESULT_DF.empty: - logging.warning("Skipping Parent-Child mapping: No successful results to process (FINAL_RESULT_DF is empty)") + logging.warning( + "Skipping Parent-Child mapping: No successful results to process (FINAL_RESULT_DF is empty)" + ) else: - logging.info(f"Starting Parent-Child mapping with {len(FINAL_RESULT_DF)} records from: {doczy_output_for_pc}") + logging.info( + f"Starting Parent-Child mapping with {len(FINAL_RESULT_DF)} records from: {doczy_output_for_pc}" + ) with timing_utils.timed_block("parent_child_mapping", log_level="INFO"): parent_child_main.main(doczy_output_for_pc) @@ -268,4 +296,3 @@ def main(testing=False, test_params={}): if __name__ == "__main__": main() - diff --git a/src/pipelines/clients/bcbs_promise/prompts/__init__.py b/src/pipelines/clients/bcbs_promise/prompts/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/pipelines/clients/bcbs_promise/prompts/__init__.py @@ -0,0 +1 @@ + diff --git a/fieldExtraction/src/investment/prompt_calls.py b/src/pipelines/clients/bcbs_promise/prompts/prompt_calls.py similarity index 72% rename from fieldExtraction/src/investment/prompt_calls.py rename to src/pipelines/clients/bcbs_promise/prompts/prompt_calls.py index 6be03cf..ae36572 100644 --- a/fieldExtraction/src/investment/prompt_calls.py +++ b/src/pipelines/clients/bcbs_promise/prompts/prompt_calls.py @@ -2,10 +2,11 @@ import logging import src.config as config import src.prompts.prompt_templates as prompt_templates -from constants.constants import Constants -from constants.delimiters import Delimiter +from src.constants.constants import Constants +from src.constants.delimiters import Delimiter from src.prompts.fieldset import Field, FieldSet from src.utils import llm_utils, string_utils +import json def prompt_exhibit_level( @@ -25,24 +26,25 @@ def prompt_exhibit_level( prompt, "sonnet_latest", filename, max_tokens=8192 ) logging.debug(f"LLM raw output for {filename}: {llm_answer_raw}") - + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) - - - + return llm_answer_final -def prompt_exhibit_level_breakout(exhibit_level_answers: dict[str, str], filename: str) -> dict[str, str]: + +def prompt_exhibit_level_breakout( + exhibit_level_answers: dict[str, str], filename: str +) -> dict[str, str]: """ Process exhibit-level answers by breaking out facility adjustment terms using an LLM. This function checks if a FACILITY_ADJUSTMENT_TERM exists in the exhibit-level answers, and if present, invokes Claude LLM to break it down into structured components. The resulting parsed data is then merged back into the exhibit-level answers dictionary. Args: - exhibit_level_answers (dict[str, str]): A dictionary containing exhibit-level + exhibit_level_answers (dict[str, str]): A dictionary containing exhibit-level field names as keys and their corresponding values as strings. Must contain a "FACILITY_ADJUSTMENT_TERM" key to trigger processing. - filename (str): The name of the file being processed, used for logging and + filename (str): The name of the file being processed, used for logging and tracking purposes in the LLM invocation. Returns: dict[str, str]: The updated exhibit_level_answers dictionary with additional @@ -52,24 +54,24 @@ def prompt_exhibit_level_breakout(exhibit_level_answers: dict[str, str], filenam Any exceptions raised by llm_utils.invoke_claude() or string_utils.universal_json_load() will propagate to the caller. """ - + # FACILITY_ADJUSTMENT_BREAKOUT - if not string_utils.is_empty(exhibit_level_answers.get("FACILITY_ADJUSTMENT_TERM", "")): + if not string_utils.is_empty( + exhibit_level_answers.get("FACILITY_ADJUSTMENT_TERM", "") + ): prompt = prompt_templates.FACILITY_ADJUSTMENT_BREAKOUT( exhibit_level_answers["FACILITY_ADJUSTMENT_TERM"] ) llm_answer_raw = llm_utils.invoke_claude( - prompt=prompt, - model_id="sonnet_latest", - filename=filename + prompt=prompt, model_id="sonnet_latest", filename=filename ) print("Facility Adjustment: ", llm_answer_raw) llm_answer_final = string_utils.universal_json_load(llm_answer_raw) exhibit_level_answers.update(llm_answer_final) - + return exhibit_level_answers - - + + def prompt_exhibit_lesser( exhibit_text: str, exhibit_level_answers: dict, @@ -120,7 +122,7 @@ def prompt_reimbursement_primary( filename: str, ) -> list[dict[str, str]]: - instruction, prompt = prompt_templates.REIMBURSEMENT_PRIMARY(page_text) + prompt = prompt_templates.REIMBURSEMENT_PRIMARY(page_text) logging.debug( f"""Running reimbursement primary prompt for {filename} with prompt: {prompt}""" @@ -131,7 +133,7 @@ def prompt_reimbursement_primary( filename, max_tokens=25000, cache=True, - instruction=instruction, + instruction=prompt_templates.REIMBURSEMENT_PRIMARY_INSTRUCTION(), usage_label="REIMBURSEMENT_PRIMARY", ) logging.debug(f"""LLM raw output for {filename}: {llm_answer_raw}""") @@ -156,8 +158,9 @@ def prompt_methodology_breakout( constants: Constants, filename: str, ): - instruction, prompt = prompt_templates.METHODOLOGY_BREAKOUT( - service_term, reimb_term, + prompt = prompt_templates.METHODOLOGY_BREAKOUT( + service_term, + reimb_term, methodology_breakout_questions.print_prompt_dict(constants), ) logging.debug(f"Methodology Breakout Prompt for {filename}: {prompt}") @@ -166,7 +169,7 @@ def prompt_methodology_breakout( "sonnet_latest", filename, cache=True, - instruction=instruction, + instruction=prompt_templates.METHODOLOGY_BREAKOUT_INSTRUCTION(), ) logging.debug(f"LLM Response for {filename}: {llm_response}") try: @@ -231,13 +234,14 @@ def prompt_grouper_breakout( def prompt_carveout_check( - service_term: str, reimb_term: str, carveout_definitions, special_case_definitions, filename: str + service_term: str, + reimb_term: str, + carveout_definitions, + special_case_definitions, + filename: str, ): carveout_prompt = prompt_templates.CARVEOUT_CHECK( - service_term, - reimb_term, - carveout_definitions, - special_case_definitions + service_term, reimb_term, carveout_definitions, special_case_definitions ) logging.debug( f"Running carveout check for {filename} with prompt:\n{carveout_prompt}" @@ -258,14 +262,8 @@ def prompt_carveout_check( def prompt_special_case_breakout(breakout_template, term_answer, filename): - # Some breakout templates (e.g., OUTLIER_BREAKOUT) return (instruction, prompt) - # while others return just a prompt string. Handle both cases safely. - prompt_obj = breakout_template(term_answer) - instruction = None - if isinstance(prompt_obj, tuple) and len(prompt_obj) == 2: - instruction, prompt = prompt_obj - else: - prompt = prompt_obj + # Get the prompt from the template + prompt = breakout_template(term_answer) # Ensure prompt is a string for Bedrock messages API if not isinstance(prompt, str): @@ -274,15 +272,19 @@ def prompt_special_case_breakout(breakout_template, term_answer, filename): ) prompt = str(prompt) - # If we have an instruction, enable prompt caching for efficiency - if instruction: + # Look for a corresponding _INSTRUCTION() function for caching + template_name = getattr(breakout_template, "__name__", "SPECIAL_CASE_BREAKOUT") + instruction_func_name = f"{template_name}_INSTRUCTION" + instruction_func = getattr(prompt_templates, instruction_func_name, None) + + if instruction_func and callable(instruction_func): llm_answer_raw = llm_utils.invoke_claude( prompt, "sonnet_latest", filename, cache=True, - instruction=instruction, - usage_label=(getattr(breakout_template, "__name__", "SPECIAL_CASE_BREAKOUT")), + instruction=instruction_func(), + usage_label=template_name, ) else: llm_answer_raw = llm_utils.invoke_claude( @@ -323,7 +325,7 @@ def prompt_special_case_assignment( special_case_dicts: list, special_case_term: str, filename: str, -)->dict[str, str]: +) -> dict[str, str]: # If all non-term values are identical across dictionaries, return first dict non_term_keys = [k for k in special_case_dicts[0].keys() if "_TERM" not in k] @@ -447,12 +449,14 @@ def validate_reimbursements_for_llm(answer_dict: dict[str, str], filename: str) if isinstance(answer_dict, str): answer_dict = {"SERVICE_TERM": "", "REIMB_TERM": answer_dict} - if string_utils.is_empty(answer_dict.get("SERVICE_TERM", None)) or string_utils.is_empty(answer_dict.get("REIMB_TERM", None)): + if string_utils.is_empty( + answer_dict.get("SERVICE_TERM", None) + ) or string_utils.is_empty(answer_dict.get("REIMB_TERM", None)): logging.warning( f"Missing SERVICE_TERM or REIMB_TERM in {filename}: {answer_dict}" ) return False - + service_term, reimb_term = answer_dict["SERVICE_TERM"], answer_dict["REIMB_TERM"] prompt = prompt_templates.VALIDATE_REIMBURSEMENTS_PROMPT(service_term, reimb_term) logging.debug(f"Prompt for reimbursement validation in {filename}:\n{prompt}") @@ -500,10 +504,11 @@ def prompt_dynamic(text: str, field_prompts, filename): llm_answer_final = string_utils.universal_json_load(llm_answer_raw) return llm_answer_final + def prompt_exhibit_linkage(page_header, previous_header, filename): """Determine if current page header represents a different exhibit from the previous page. - Uses LLM to compare page headers and determine if they indicate a transition to a + Uses LLM to compare page headers and determine if they indicate a transition to a new exhibit section in the contract. Args: @@ -515,14 +520,13 @@ def prompt_exhibit_linkage(page_header, previous_header, filename): str: LLM response indicating if the exhibit has changed. """ prompt = prompt_templates.EXHIBIT_LINKAGE(page_header, previous_header) - claude_answer_raw = llm_utils.invoke_claude( - prompt, "legacy_sonnet", filename - ) + claude_answer_raw = llm_utils.invoke_claude(prompt, "legacy_sonnet", filename) exhibit_is_different = string_utils.extract_text_from_delimiters( claude_answer_raw, Delimiter.PIPE ) return exhibit_is_different + def prompt_exhibit_header(page_content, EXHIBIT_HEADER_MARKERS, filename): """Extract exhibit header identifier from page content using pattern matching. @@ -549,10 +553,12 @@ def prompt_exhibit_header(page_content, EXHIBIT_HEADER_MARKERS, filename): return llm_answer_extracted -def prompt_smart_chunked(answers_dict, new_field_groups, field_group, one_to_one_chunks, filename): +def prompt_smart_chunked( + answers_dict, new_field_groups, field_group, one_to_one_chunks, filename +): """Extract field values from chunked contract text using appropriate prompt templates. - Selects single-field or multi-field prompt templates based on the number of fields + Selects single-field or multi-field prompt templates based on the number of fields in the group and processes the corresponding text chunk to extract structured answers. Args: @@ -578,13 +584,9 @@ def prompt_smart_chunked(answers_dict, new_field_groups, field_group, one_to_one question = questions[ fields[0].field_name ] # Take the one question for the single field included - prompt = prompt_templates.ONE_TO_ONE_SINGLE_FIELD_TEMPLATE( - context, question - ) + prompt = prompt_templates.ONE_TO_ONE_SINGLE_FIELD_TEMPLATE(context, question) elif len(fields) > 1: - prompt = prompt_templates.ONE_TO_ONE_MULTI_FIELD_TEMPLATE( - context, questions - ) + prompt = prompt_templates.ONE_TO_ONE_MULTI_FIELD_TEMPLATE(context, questions) else: raise ValueError("Field group has no defined fields") @@ -596,9 +598,7 @@ def prompt_smart_chunked(answers_dict, new_field_groups, field_group, one_to_one field_group_answer_parsed = string_utils.extract_text_from_delimiters( field_group_answer_raw, Delimiter.PIPE ) - field_group_answer_dict = { - fields[0].field_name: field_group_answer_parsed - } + field_group_answer_dict = {fields[0].field_name: field_group_answer_parsed} elif len(fields) > 1: field_group_answer_dict = string_utils.json_parsing_search( field_group_answer_raw, [field.field_name for field in fields] @@ -609,9 +609,7 @@ def prompt_smart_chunked(answers_dict, new_field_groups, field_group, one_to_one if expected_fields != received_fields: missing = expected_fields - received_fields extra = received_fields - expected_fields - raise ValueError( - f"Field mismatch - Missing: {missing}, Extra: {extra}" - ) + raise ValueError(f"Field mismatch - Missing: {missing}, Extra: {extra}") # Load up answers dict for field in fields: @@ -622,9 +620,10 @@ def prompt_smart_chunked(answers_dict, new_field_groups, field_group, one_to_one logging.error(f"Error processing field {field}: {type(e)}, {str(e)}") for field in fields: answers_dict[field.field_name] = f"Error: {str(e)}" - + return answers_dict + def prompt_date_fix(date: str) -> str: """Processes dates using `prompt_templates.date_fix_prompt`. @@ -656,12 +655,13 @@ def prompt_derived_term_date( Returns: str: ISO-formatted termination date (YYYY-MM-DD) or "N/A" if calculation fails. """ - prompt = prompt_templates.DERIVED_TERM_DATE_PROMPT(effective_date, termination_information) + prompt = prompt_templates.DERIVED_TERM_DATE_PROMPT( + effective_date, termination_information + ) response = llm_utils.invoke_claude(prompt, "haiku_latest", "derive_term_date") return string_utils.extract_text_from_delimiters(response, Delimiter.PIPE) - def prompt_global_lesser_of_breakout( global_lesser_of_stmt: str, constants: Constants, filename: str ) -> dict[str, str]: @@ -729,7 +729,7 @@ def prompt_global_lesser_of_breakout( # Create a mock service term for the breakout mock_service = "Global Lesser Of (all services)" - instruction, prompt = prompt_templates.METHODOLOGY_BREAKOUT( + prompt = prompt_templates.METHODOLOGY_BREAKOUT( [mock_service, global_lesser_of_stmt], FieldSet( file_path=config.FIELD_JSON_PATH, field_type="methodology_breakout" @@ -740,8 +740,13 @@ def prompt_global_lesser_of_breakout( ) llm_response = llm_utils.invoke_claude( - prompt, "sonnet_latest", filename, cache=True, instruction=instruction - , usage_label="GLOBAL_LESSER_OF_BREAKOUT") + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.METHODOLOGY_BREAKOUT_INSTRUCTION(), + usage_label="GLOBAL_LESSER_OF_BREAKOUT", + ) try: breakout_results = string_utils.universal_json_load(llm_response) @@ -757,11 +762,20 @@ def prompt_global_lesser_of_breakout( ) return {"REIMB_TERM": f"[GLOBAL LESSER OF] {global_lesser_of_stmt}"} -def prompt_dynamic_assignment(service_term: str, reimb_term: str, dynamic_field: Field, exhibit_text_simplified: str, page_num: str, constants: Constants, filename: str): + +def prompt_dynamic_assignment( + service_term: str, + reimb_term: str, + dynamic_field: Field, + exhibit_text_simplified: str, + page_num: str, + constants: Constants, + filename: str, +): field_name = dynamic_field.field_name field_prompt = dynamic_field.get_prompt(constants) - + # Use specialized prompt for REIMB_DATES assignment if field_name == "REIMB_DATES": prompt = prompt_templates.REIMB_DATES_ASSIGNMENT( @@ -770,88 +784,279 @@ def prompt_dynamic_assignment(service_term: str, reimb_term: str, dynamic_field: else: # Use generic DYNAMIC_ASSIGNMENT for other fields prompt = prompt_templates.DYNAMIC_ASSIGNMENT( - service_term, reimb_term, field_name, field_prompt, exhibit_text_simplified, page_num + service_term, + reimb_term, + field_name, + field_prompt, + exhibit_text_simplified, + page_num, ) llm_answer_raw = llm_utils.invoke_claude( prompt, model_id="sonnet_latest", - filename=filename + filename=filename, + cache=True, + instruction=prompt_templates.DYNAMIC_ASSIGNMENT_INSTRUCTION(), + usage_label="DYNAMIC_ASSIGNMENT", ) try: llm_answer_final = string_utils.universal_json_load(llm_answer_raw) return llm_answer_final except: - logging.error(f"Failed to parse Dynamic Field: {field_name}. Response: {llm_answer_raw}") + logging.error( + f"Failed to parse Dynamic Field: {field_name}. Response: {llm_answer_raw}" + ) return {field_name: "Extraction Error"} -def prompt_lesser_of_distribution(service_term: str, reimb_term: str, exhibit_text_simplified: str, page_num: str, filename: str): +def prompt_lesser_of_distribution( + service_term: str, + reimb_term: str, + exhibit_text_simplified: str, + page_num: str, + cross_exhibit_lesser_of: list[dict], + filename: str, +) -> str: + """ + Apply lesser-of logic to a service and rate using hybrid approach. + + Combines: + 1. Cross-exhibit templates (GLOBAL and OTHER) from other exhibits (pre-provided) + 2. Intra-exhibit statements by searching the current exhibit text + + This approach avoids race conditions by: + - Storing only GLOBAL and cross-exhibit (OTHER) templates between exhibits + - Searching exhibit text for intra-exhibit statements (CURRENT) + - Exhibits process serially, so cross-exhibit templates are safe + + Args: + service_term: Service description + reimb_term: Original reimbursement term (rate without lesser-of) + exhibit_text_simplified: Simplified exhibit text to search for intra-exhibit statements + page_num: Current page number + cross_exhibit_lesser_of: List of GLOBAL and cross-exhibit lesser-of answer dicts. + Each dict contains: service_term, reimb_term, scope, + target_exhibit, exhibit_reference, page_num + filename: Filename for logging + + Returns: + str: Combined reimbursement term with lesser-of applied, or original term if no lesser-of applies + + Example: + >>> cross_exhibit = [{ + ... 'reimb_term': 'All services: lesser of rates or charges', + ... 'scope': 'GLOBAL', + ... 'page_num': '5' + ... }] + >>> result = prompt_lesser_of_distribution( + ... "Office Visit", "$150", exhibit_text, "10", cross_exhibit, "contract.pdf" + ... ) + >>> # Returns: "Office Visit paid at the lesser of $150 or charges" + """ prompt = prompt_templates.LESSER_OF_DISTRIBUTION( service_term, reimb_term, + page_num, exhibit_text_simplified, - page_num + cross_exhibit_lesser_of, # Pass list of cross-exhibit answer dicts ) + llm_answer_raw = llm_utils.invoke_claude( prompt, "sonnet_latest", - filename + filename, + cache=True, + instruction=prompt_templates.LESSER_OF_DISTRIBUTION_INSTRUCTION(), + usage_label="LESSER_OF_DISTRIBUTION", ) + # Check if LLM determined no lesser-of applies if "N/A" in llm_answer_raw: - return reimb_term + logging.debug( + f"No lesser-of constraints apply to '{service_term}' on page {page_num}" + ) + return reimb_term # Return original term unchanged else: - llm_answer_final = string_utils.extract_text_from_delimiters(llm_answer_raw, Delimiter.PIPE) + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + + logging.debug( + f"Applied lesser-of to '{service_term}' on page {page_num}: " + f"{reimb_term} → {llm_answer_final[:60]}..." + ) + return llm_answer_final -def prompt_lesser_of_check(service_term: str, reimb_term: str, filename: str): - prompt = prompt_templates.LESSER_OF_CHECK(service_term, reimb_term) + +def prompt_lesser_of_check( + service_term: str, reimb_term: str, exhibit_title: str, filename: str +) -> dict: + """ + Classify a lesser-of statement into GLOBAL, EXHIBIT_SPECIFIC, or STANDALONE. + + Args: + service_term: Service description + reimb_term: Reimbursement term containing lesser-of language + exhibit_title: Current exhibit's title/header + filename: Filename for logging + + Returns: + dict: Classification result with keys: + - service_term: str + - reimb_term: str + - scope: "GLOBAL" | "EXHIBIT_SPECIFIC" | "STANDALONE" + - target_exhibit: "ALL" | "CURRENT" | "OTHER" | None + - exhibit_reference: str | None (exhibit name if target is OTHER) + """ + # DEBUG: Log what we're sending + logging.info( + f"LESSER_OF_CHECK input: service='{service_term[:50]}...', reimb_term='{reimb_term[:100]}...'" + ) + + prompt = prompt_templates.LESSER_OF_CHECK(service_term, reimb_term, exhibit_title) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.LESSER_OF_CHECK_INSTRUCTION(), + usage_label="LESSER_OF_CHECK", + ) + + try: + # Extract JSON from pipes + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + + logging.debug(f"LESSER_OF_CHECK extracted from pipes: {llm_answer_final}") + + # Parse JSON + lesser_of_answer_dict = json.loads(llm_answer_final) + + # Validate required fields + required_fields = [ + "service_term", + "reimb_term", + "scope", + "target_exhibit", + "exhibit_reference", + ] + for field in required_fields: + if field not in lesser_of_answer_dict: + logging.warning( + f"LESSER_OF_CHECK missing field '{field}' for service '{service_term}', " + f"exhibit '{exhibit_title}', defaulting to STANDALONE" + ) + return { + "service_term": service_term, + "reimb_term": reimb_term, + "scope": "STANDALONE", + "target_exhibit": None, + "exhibit_reference": None, + } + + logging.info( + f"LESSER_OF_CHECK classification: scope={lesser_of_answer_dict['scope']}, " + f"target={lesser_of_answer_dict['target_exhibit']}, " + f"exhibit_ref={lesser_of_answer_dict.get('exhibit_reference')}, " + f"service='{service_term}...', exhibit='{exhibit_title}'" + ) + + return lesser_of_answer_dict + + except json.JSONDecodeError as e: + logging.error( + f"Failed to parse LESSER_OF_CHECK JSON for service '{service_term}', " + f"exhibit '{exhibit_title}': {e}. Raw response: {llm_answer_final[:200]}... " + f"Defaulting to STANDALONE" + ) + return { + "service_term": service_term, + "reimb_term": reimb_term, + "scope": "STANDALONE", + "target_exhibit": None, + "exhibit_reference": None, + } + except Exception as e: + logging.error( + f"Error in prompt_lesser_of_check for service '{service_term}', " + f"exhibit '{exhibit_title}': {e}. Defaulting to STANDALONE" + ) + return { + "service_term": service_term, + "reimb_term": reimb_term, + "scope": "STANDALONE", + "target_exhibit": None, + "exhibit_reference": None, + } + + +def prompt_exhibit_title_match( + current_exhibit_title: str, target_exhibit_reference: str, filename: str = "" +) -> str: + prompt = prompt_templates.EXHIBIT_TITLE_MATCH( + current_exhibit_title, target_exhibit_reference + ) llm_answer_raw = llm_utils.invoke_claude(prompt, "sonnet_latest", filename) try: - llm_answer_final = string_utils.extract_text_from_delimiters(llm_answer_raw, Delimiter.PIPE) - return llm_answer_final == "Y" + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + return llm_answer_final.strip().upper() # Return "YES" or "NO" as string except: - return True # Default to True - prefer extra rows to missing + return "NO" # Default to "NO" string def provider_name_match_check( - provider_name: str, - hybrid_smart_chunking_provider_group_name: str, - filename: str + provider_name: str, hybrid_smart_chunking_provider_group_name: str, filename: str ) -> bool: """Check if the provider name from npi/tin page match provider group name""" - if string_utils.is_empty(provider_name) or string_utils.is_empty(hybrid_smart_chunking_provider_group_name): + if string_utils.is_empty(provider_name) or string_utils.is_empty( + hybrid_smart_chunking_provider_group_name + ): return False - + if hybrid_smart_chunking_provider_group_name == "N/A": return False - + # Create prompt for LLM CHECK_PROVIDER_NAME_MATCH_PROMPT = prompt_templates.CHECK_PROVIDER_NAME_MATCH_PROMPT( provider_name=provider_name, - hybrid_smart_chunking_provider_group_name=hybrid_smart_chunking_provider_group_name + hybrid_smart_chunking_provider_group_name=hybrid_smart_chunking_provider_group_name, ) - + try: # Adjust this based on your LLM client - response = llm_utils.invoke_claude(CHECK_PROVIDER_NAME_MATCH_PROMPT, "sonnet_latest", filename) - + response = llm_utils.invoke_claude( + CHECK_PROVIDER_NAME_MATCH_PROMPT, "sonnet_latest", filename + ) + # Extract last character (should be Y or N) response = string_utils.extract_text_from_delimiters(response, Delimiter.PIPE) - - if response=='Y': - logging.debug(f"[is_provider_name_match_llm] ✓ LLM matched: '{provider_name}' ≈ '{hybrid_smart_chunking_provider_group_name}'") + + if response == "Y": + logging.debug( + f"[is_provider_name_match_llm] ✓ LLM matched: '{provider_name}' ≈ '{hybrid_smart_chunking_provider_group_name}'" + ) return True - elif response=='N': - logging.debug(f"[is_provider_name_match_llm] ✗ LLM no match: '{provider_name}' ≠ '{hybrid_smart_chunking_provider_group_name}'") + elif response == "N": + logging.debug( + f"[is_provider_name_match_llm] ✗ LLM no match: '{provider_name}' ≠ '{hybrid_smart_chunking_provider_group_name}'" + ) return False else: - logging.warning(f"[is_provider_name_match_llm] Unexpected response: {response}, defaulting to False") + logging.warning( + f"[is_provider_name_match_llm] Unexpected response: {response}, defaulting to False" + ) return False - + except Exception as e: - logging.error(f"[is_provider_name_match_llm] Error calling LLM: {e}, defaulting to False") - return False \ No newline at end of file + logging.error( + f"[is_provider_name_match_llm] Error calling LLM: {e}, defaulting to False" + ) + return False diff --git a/fieldExtraction/src/tracking/__init__.py b/src/pipelines/clients/clover/__init__.py similarity index 100% rename from fieldExtraction/src/tracking/__init__.py rename to src/pipelines/clients/clover/__init__.py diff --git a/src/pipelines/clients/clover/file_processing.py b/src/pipelines/clients/clover/file_processing.py new file mode 100644 index 0000000..f441d10 --- /dev/null +++ b/src/pipelines/clients/clover/file_processing.py @@ -0,0 +1,539 @@ +import concurrent.futures +import logging +from typing import TYPE_CHECKING, Optional + +import pandas as pd +import src.codes.code_funcs as code_funcs +from src.pipelines.shared.preprocessing import ( + preprocessing_funcs, + preprocess, + hybrid_smart_chunking_funcs, +) +from src.pipelines.shared.postprocessing import ( + aarete_derived, + postprocess, + postprocessing_funcs, +) +from src.pipelines.shared.extraction import ( + dynamic_funcs, + one_to_n_funcs, + one_to_one_funcs, + row_funcs, + tin_npi_funcs, + exhibit_funcs, +) +from src.pipelines.shared.extraction.exhibit_funcs import Exhibit +from src.utils import io_utils, logging_utils, string_utils, timing_utils +from src.constants.constants import Constants +from src import config +from src.prompts.fieldset import FieldSet +from src.utils.string_utils import datetime_str + +if TYPE_CHECKING: + from src.pipelines.shared.extraction.page_funcs import Page + + +def process_file(file_object, constants: Constants, run_timestamp): + filename, contract_text = file_object + + # Set per-file logging context: + # With this, all logging calls in this thread will now route to logs/{filename}.log + # This includes logging from all called functions (preprocess, one_to_n_funcs, etc.) + logging_utils.set_current_file(filename) + logging.info(f"{datetime_str()} Processing {filename}...") + + # Set default values + dynamic_one_to_one_fields = FieldSet() + process_one_to_n = config.FIELDS in ["all", "one_to_n"] + process_one_to_one = config.FIELDS in ["all", "one_to_one"] + # Initialize default fallback for final results + final_results = pd.DataFrame([{"FILE_NAME": filename}]) + + ################## PREPROCESS ################## + with timing_utils.timed_block("preprocess", context=filename): + contract_text = preprocess.clean_text(contract_text) + text_dict, top_sheet_dict = preprocess.split_text(contract_text) + text_dict, header, footer = preprocess.find_headers_and_footers(text_dict) + + # ONE TO N PROCESSING + one_to_n_results = pd.DataFrame() # Initialize empty DataFrame for one_to_n_results + if process_one_to_n: + # Use split_text_with_pages() to get Page objects with table splitting + # Note: split_text_with_pages() internally calls split_text() which applies headers/footers + # But we need to apply headers/footers first, so we'll create pages_dict from the cleaned text_dict + from src.pipelines.shared.extraction.page_funcs import Page + from src.pipelines.shared.preprocessing import preprocessing_funcs as prep_funcs + + # Create pages_dict from text_dict (headers/footers already applied) + pages_dict = prep_funcs.split_large_tables(text_dict) + + with timing_utils.timed_block("one_to_n_exhibit_chunking", context=filename): + # Use pages_dict for exhibit chunking (preferred) or fall back to text_dict + exhibit_chunk_mapping, all_exhibit_headers = ( + preprocess.one_to_n_exhibit_chunking( + pages_dict=pages_dict, + text_dict=text_dict, + EXHIBIT_HEADER_MARKERS=constants.EXHIBIT_HEADER_MARKERS, + filename=filename, + ) + ) + logging.info(f"{datetime_str()} Preprocessing Complete - {filename}") + + one_to_n_results = pd.DataFrame([{"FILE_NAME": filename}]) # Initialize here + + if string_utils.contains_reimbursement(contract_text): + logging.info( + f"{datetime_str()} Starting One-to-N extraction for {len(exhibit_chunk_mapping)} exhibits - {filename}" + ) + with timing_utils.timed_block("one_to_n_extraction", context=filename): + ( + one_to_n_results, + dynamic_one_to_one_fields, + first_reimbursement_page, + ) = run_one_to_n_prompts( + pages_dict=pages_dict, + text_dict=text_dict, + exhibit_chunk_mapping=exhibit_chunk_mapping, + all_exhibit_headers=all_exhibit_headers, + constants=constants, + filename=filename, + ) + if not one_to_n_results.empty: + one_to_n_results["FILE_NAME"] = filename + with timing_utils.timed_block( + "one_to_n_generate_reimb_ids", context=filename + ): + one_to_n_results = postprocessing_funcs.generate_reimb_ids( + one_to_n_results + ) + logging.info(f"{datetime_str()} One to N Complete - {filename}") + else: + first_reimbursement_page = "1" + logging.info( + f"{datetime_str()} No Reimbursement Found, Skipping - {filename}" + ) + + final_results = one_to_n_results # Set as final results + else: + first_reimbursement_page = "1" + logging.info( + f"{datetime_str()} Fields not configured for One to N, Skipping - {filename}" + ) + + # ONE TO ONE PROCESSING + if process_one_to_one: + with timing_utils.timed_block("one_to_one_extraction", context=filename): + one_to_one_results = run_one_to_one_prompts( + filename, + contract_text, + text_dict, + top_sheet_dict, + dynamic_one_to_one_fields, + first_reimbursement_page, + constants, + ) + one_to_one_results["FILE_NAME"] = filename + logging.info(f"{datetime_str()} One to One Complete - {filename}") + + # Decide how to handle one_to_one results + with timing_utils.timed_block( + "merge_one_to_one_into_one_to_n", context=filename + ): + if not one_to_n_results.empty: + # BOTH processed - merge into one_to_n + final_results = row_funcs.merge_one_to_one_into_one_to_n( + one_to_n_results, one_to_one_results, constants + ) + else: + # ONLY one_to_one processed - convert dict to DataFrame + final_results = pd.DataFrame([one_to_one_results]) + else: + logging.info( + f"{datetime_str()} Fields not configured for One to One, Skipping - {filename}" + ) + + # APPLY CODES IF ONE_TO_N WAS PROCESSED + if not one_to_n_results.empty: + with timing_utils.timed_block("code_processing", context=filename): + results_with_code = code_funcs.code_breakout(final_results, constants) + final_results = code_funcs.grouper_breakout(results_with_code) + logging.info(f"{datetime_str()} Codes Complete - {filename}") + + # POSTPROCESS + with timing_utils.timed_block("postprocess", context=filename): + final_df = postprocess.postprocess(final_results, constants) + logging.info(f"{datetime_str()} Postprocessing Complete - {filename}") + + ################## WRITE INDIVIDUAL ################## + with timing_utils.timed_block("write_individual", context=filename): + if config.WRITE_TO_S3: + io_utils.write_s3(final_df, filename, run_timestamp, "individual") + else: + io_utils.write_local(final_df, filename, "", "individual") + + logging.info(f"{datetime_str()} Writing Complete - {filename}") + + return final_df + + +def run_one_to_one_prompts( + filename: str, + contract_text: str, + text_dict: dict[str, str], + top_sheet_dict, + dynamic_one_to_one_fields: FieldSet, + first_reimbursement_page: str, + constants: Constants, +): + + ################## INITIALIZE FIELDS ################## + one_to_one_fields = FieldSet( + relationship="one_to_one", file_path=config.FIELD_JSON_PATH + ).combine(dynamic_one_to_one_fields) + + ################## INITIALIZE CLOVER FIELDS ################## + clover_fields = FieldSet( + relationship="one_to_one", file_path=config.CLOVER_PROMPTS_PATH + ) + + ################## RUN PROVIDER INFO ################## + with timing_utils.timed_block("one_to_one.provider_info", context=filename): + one_to_one_results = tin_npi_funcs.run_provider_info_fields( + contract_text, text_dict, filename, payer_name="" + ) + + ################## RUN HYBRID SMART CHUNKED PROMPTS ################## + # RAG function loads retrieval questions internally and matches with investment_prompts.json + with timing_utils.timed_block("one_to_one.hybrid_smart_chunking", context=filename): + hybrid_smart_chunked_answers_dict = ( + hybrid_smart_chunking_funcs.run_hybrid_smart_chunked_fields( + one_to_one_fields, constants, contract_text, filename, text_dict + ) + ) + + ################## RUN FULL CONTEXT PROMPTS ################## + with timing_utils.timed_block("one_to_one.full_context", context=filename): + full_context_answers_dict = one_to_one_funcs.run_full_context_fields( + one_to_one_fields, + contract_text, + text_dict, + first_reimbursement_page, + constants, + filename, + ) + + ################## RUN CLOVER PROMPTS ################## + with timing_utils.timed_block("one_to_one.clover_fields", context=filename): + clover_answers_dict = one_to_one_funcs.run_full_context_fields( + clover_fields, + contract_text, + text_dict, + first_reimbursement_page, + constants, + filename, + ) + ################## COMBINE ANSWERS ################ + # Prefer HSC answers over full_context when HSC value is not N/A + for key, value in full_context_answers_dict.items(): + one_to_one_results[key] = value + + for key, value in hybrid_smart_chunked_answers_dict.items(): + if not string_utils.is_empty(value): + one_to_one_results[key] = value + elif key not in one_to_one_results: + # Add HSC's N/A if field doesn't exist yet + one_to_one_results[key] = value + + one_to_one_results = tin_npi_funcs.merge_provider_info_with_hybrid_smart_chunking( + one_to_one_results, filename + ) + + # Add clover fields (Claims Timely Filing Days, Appeals Timely Filing Days, etc.) + for key, value in clover_answers_dict.items(): + one_to_one_results[key] = value + + ################## ADD AD FIELDS ################ + one_to_one_results = one_to_one_funcs.get_aarete_derived_dates( + one_to_one_results, text_dict, filename + ) + + ################## ADD SIGNATURE COUNT ################## + one_to_one_results = one_to_one_funcs.add_signature_count( + one_to_one_results, contract_text + ) + + ################## Crosswalk Fields ################## + one_to_one_results = aarete_derived.get_crosswalk_fields( + [one_to_one_results], constants + ) + + ################## Fill NA Mapping ################## + one_to_one_results = aarete_derived.fill_na_mapping(one_to_one_results) + + return one_to_one_results[0] + + +def process_page_reimbursements( + exhibit: Exhibit, + page_num: str, + pages_dict: Optional[dict[str, "Page"]] = None, + text_dict: Optional[dict[str, str]] = None, + exhibit_page_nums: Optional[list[str]] = None, + constants: Optional[Constants] = None, + filename: Optional[str] = None, +): + """ + STEP 1 HELPER: Extract reimbursements from a single page (without exhibit-level fields). + Runs: reimbursement_level → carveout_and_special_case → lesser_of_distribution → breakout + + Args: + exhibit: Exhibit object containing the page + page_num: Page identifier (can be "27" or "27.1" for sub-pages) + pages_dict: Dictionary mapping page numbers to Page objects (preferred) + text_dict: Dictionary mapping page numbers to text strings (for backward compatibility) + exhibit_page_nums: List of page numbers in the exhibit (for backward compatibility) + constants: Constants object + filename: Name of the file being processed + """ + # Get page text - prefer using exhibit.get_page_text() if available + if exhibit.pages is not None: + page_text = exhibit.get_page_text(page_num) + exhibit_page_nums = exhibit.exhibit_page_nums + elif pages_dict is not None: + # Handle sub-pages: "27.1" means get sub-page "1" from page "27" + if "." in page_num and not page_num.startswith("."): + base_page, sub_page = page_num.rsplit(".", 1) + if base_page in pages_dict: + page_text = pages_dict[base_page].get_text(sub_page) + else: + page_text = "" + elif page_num in pages_dict: + page_text = pages_dict[page_num].get_text() + else: + page_text = "" + exhibit_page_nums = ( + exhibit.exhibit_page_nums + if exhibit_page_nums is None + else exhibit_page_nums + ) + elif text_dict is not None: + page_text = text_dict.get(page_num, "") + exhibit_page_nums = ( + exhibit_page_nums + if exhibit_page_nums is not None + else exhibit.exhibit_page_nums + ) + else: + raise ValueError( + "Either pages_dict, text_dict, or exhibit.pages must be provided" + ) + + # Simplify exhibit text - prefer using exhibit object + exhibit_text_simplified = preprocessing_funcs.simplify_exhibit( + exhibit=exhibit, + current_page_num=page_num, + ) + + ############################### Reimbursement Primary ############################### + reimbursement_level_answers = one_to_n_funcs.reimbursement_level( + page_text, constants, filename + ) + + if not reimbursement_level_answers: + return [], [] + + ################################ Carveouts and Special Case ################################ + reimbursement_level_answers, special_case_answers = ( + one_to_n_funcs.carveout_and_special_case( + reimbursement_level_answers, constants, filename + ) + ) + + ############################### Lesser of Distribution ############################### + # Note: We run lesser_of without dynamic fields in Step 1 + reimbursement_level_answers = one_to_n_funcs.lesser_of_distribution( + reimbursement_level_answers, + exhibit_text_simplified, + page_num, + constants, + filename, + exhibit, # ← Added this parameter + ) + + ################################ Get Breakouts ############################### + reimbursement_level_answers, special_case_answers = one_to_n_funcs.breakout( + reimbursement_level_answers, + special_case_answers, + filename, + constants, + ) + + ################################ Assign REIMB_PAGE ############################### + for answer_dict in reimbursement_level_answers: + answer_dict["REIMB_PAGE"] = page_num + + return reimbursement_level_answers, special_case_answers + + +def run_one_to_n_prompts( + pages_dict: Optional[dict[str, "Page"]] = None, + text_dict: Optional[dict[str, str]] = None, + exhibit_chunk_mapping: Optional[dict[str, list[str]]] = None, + all_exhibit_headers: Optional[dict[str, str]] = None, + constants: Optional[Constants] = None, + filename: Optional[str] = None, +): + """ + 3-STEP APPROACH (per exhibit): + Step 1: Extract reimbursements for exhibit pages (parallel within exhibit) + Step 2: Run exhibit_level when exhibit has reimbursements + Step 3: Run dynamic_assignment and combine results + + Args: + pages_dict: Dictionary mapping page numbers to Page objects (preferred) + text_dict: Dictionary mapping page numbers to text strings (for backward compatibility) + exhibit_chunk_mapping: Dictionary mapping exhibit pages to lists of page numbers + all_exhibit_headers: Dictionary mapping exhibit pages to their headers + constants: Constants object + filename: Name of the file being processed + """ + if exhibit_chunk_mapping is None: + exhibit_chunk_mapping = {} + if all_exhibit_headers is None: + all_exhibit_headers = {} + + total_exhibits = len(exhibit_chunk_mapping) + logging.debug( + f"{datetime_str()} Processing {total_exhibits} exhibits with NEW 3-step approach - {filename}" + ) + + # Create Exhibit objects in order (maintains exhibit chain via prev_exhibit) + exhibits = exhibit_funcs.get_exhibit_list( + pages_dict=pages_dict, + text_dict=text_dict, + exhibit_chunk_mapping=exhibit_chunk_mapping, + all_exhibit_headers=all_exhibit_headers, + ) # <- Returns list[Exhibit] + + # Process exhibits serially; within each exhibit, process pages in parallel + total_pages = sum(len(exhibit.exhibit_page_nums) for exhibit in exhibits) + completed_pages = 0 + one_to_n_results = [] + first_reimbursement_page = "1" + + for exhibit in exhibits: + exhibit_pages = exhibit.exhibit_page_nums + if exhibit_pages: + with concurrent.futures.ThreadPoolExecutor( + max_workers=min(len(exhibit_pages), 20) + ) as executor: + page_futures = { + executor.submit( + process_page_reimbursements, + exhibit, + page_num, + pages_dict, + text_dict, + exhibit_pages, + constants, + filename, + ): page_num + for page_num in exhibit_pages + } + + for future in concurrent.futures.as_completed(page_futures): + try: + page_num = page_futures[future] + reimbursement_rows, special_case_rows = future.result() + exhibit.add_reimbursement_rows( + reimbursement_rows, special_case_rows + ) + completed_pages += 1 + if completed_pages % 20 == 0 or completed_pages == total_pages: + logging.debug( + f"{datetime_str()} Page progress: {completed_pages}/{total_pages} - {filename}" + ) + except Exception as e: + logging.error(f"Error processing page: {str(e)}") + + if not exhibit.has_reimbursements: + continue + + # STEP 2: exhibit_level for this exhibit + exhibit_level_answers, dynamic_reimbursement_fields = ( + one_to_n_funcs.exhibit_level( + exhibit.exhibit_text, + exhibit.exhibit_header, + exhibit.exhibit_page, + constants, + filename, + ) + ) + exhibit.set_exhibit_level_data( + exhibit_level_answers, dynamic_reimbursement_fields + ) + logging.debug( + f"Exhibit Level Answers for {filename}, Page {exhibit.exhibit_page}: {exhibit_level_answers}" + ) + + # STEP 3: dynamic assignment & combine for this exhibit + # Get dynamic fields from previous exhibit if needed (for future use) + if exhibit.dynamic_reimbursement_fields: + dynamic_fields = exhibit.dynamic_reimbursement_fields + elif ( + exhibit.prev_exhibit + and not exhibit.prev_exhibit.has_reimbursements + and exhibit.get_previous_exhibit_dynamic_fields().fields + ): + dynamic_fields = exhibit.get_previous_exhibit_dynamic_fields() + else: + dynamic_fields = None + + # Run dynamic assignment for ALL reimbursement rows in this exhibit + # Note: dynamic_assignment expects a list of rows and returns a list of rows + reimbursement_rows_with_dynamic = exhibit.reimbursement_rows + if exhibit.reimbursement_rows and dynamic_fields is not None: + reimbursement_rows_with_dynamic = dynamic_funcs.dynamic_assignment( + exhibit.reimbursement_rows, + dynamic_fields, + pages_dict, + text_dict, + exhibit, + constants, + filename, + ) + + # Combine reimbursement rows with exhibit-level answers + combined_rows = row_funcs.combine_one_to_n( + exhibit.exhibit_text, + reimbursement_rows_with_dynamic, + exhibit.special_case_rows, + exhibit.exhibit_level_answers, + filename, + ) + + # Run cleaning + combined_rows = one_to_n_funcs.one_to_n_cleaning( + combined_rows, exhibit.exhibit_text, constants, filename + ) + + exhibit.final_rows = combined_rows + one_to_n_results.extend(combined_rows) + + # Track first reimbursement page + if first_reimbursement_page == "1" and exhibit.has_reimbursements: + first_reimbursement_page = exhibit.exhibit_page + + logging.debug( + f"{datetime_str()} STEP 3 COMPLETE: Combined {len(one_to_n_results)} total rows - {filename}" + ) + + ################## Add N/A Dynamic or Exhibit to One-to-One ################## + dynamic_one_to_one_fields = dynamic_funcs.get_dynamic_one_to_one_fields( + one_to_n_results, constants + ) + + ################## CONVERT TO DF ################## + one_to_n_df = pd.DataFrame(one_to_n_results) + + return one_to_n_df, dynamic_one_to_one_fields, first_reimbursement_page diff --git a/src/pipelines/clients/clover/prompts/__init__.py b/src/pipelines/clients/clover/prompts/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/pipelines/clients/clover/prompts/__init__.py @@ -0,0 +1 @@ + diff --git a/src/pipelines/clients/clover/prompts/prompt_calls.py b/src/pipelines/clients/clover/prompts/prompt_calls.py new file mode 100644 index 0000000..167a637 --- /dev/null +++ b/src/pipelines/clients/clover/prompts/prompt_calls.py @@ -0,0 +1,1153 @@ +import logging + +import src.config as config +import src.prompts.prompt_templates as prompt_templates +from src.constants.constants import Constants +from src.constants.delimiters import Delimiter +from src.prompts.fieldset import Field, FieldSet +from src.utils import llm_utils, string_utils +import json + + +def prompt_exhibit_level( + exhibit_text: str, + exhibit_level_fields: FieldSet, + constants: Constants, + filename: str, +): + logging.debug(f"Running exhibit Level Fields for {filename}:") + logging.debug(exhibit_level_fields.print_prompt_dict(constants)) + if not exhibit_level_fields.contains_fields(): + return {} + prompt = prompt_templates.EXHIBIT_LEVEL( + exhibit_text, exhibit_level_fields.print_prompt_dict(constants) + ) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + max_tokens=8192, + cache=True, + instruction=prompt_templates.EXHIBIT_LEVEL_INSTRUCTION(), + usage_label="EXHIBIT_LEVEL", + ) + logging.debug(f"LLM raw output for {filename}: {llm_answer_raw}") + + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + + return llm_answer_final + + +def prompt_exhibit_level_breakout( + exhibit_level_answers: dict[str, str], filename: str +) -> dict[str, str]: + """ + Process exhibit-level answers by breaking out facility adjustment terms using an LLM. + This function checks if a FACILITY_ADJUSTMENT_TERM exists in the exhibit-level answers, + and if present, invokes Claude LLM to break it down into structured components. The + resulting parsed data is then merged back into the exhibit-level answers dictionary. + Args: + exhibit_level_answers (dict[str, str]): A dictionary containing exhibit-level + field names as keys and their corresponding values as strings. Must contain + a "FACILITY_ADJUSTMENT_TERM" key to trigger processing. + filename (str): The name of the file being processed, used for logging and + tracking purposes in the LLM invocation. + Returns: + dict[str, str]: The updated exhibit_level_answers dictionary with additional + fields extracted from the FACILITY_ADJUSTMENT_TERM breakout, or the original + dictionary if no FACILITY_ADJUSTMENT_TERM was present. + Raises: + Any exceptions raised by llm_utils.invoke_claude() or string_utils.universal_json_load() + will propagate to the caller. + """ + + # FACILITY_ADJUSTMENT_BREAKOUT + if not string_utils.is_empty( + exhibit_level_answers.get("FACILITY_ADJUSTMENT_TERM", "") + ): + prompt = prompt_templates.FACILITY_ADJUSTMENT_BREAKOUT( + exhibit_level_answers["FACILITY_ADJUSTMENT_TERM"] + ) + llm_answer_raw = llm_utils.invoke_claude( + prompt=prompt, model_id="sonnet_latest", filename=filename + ) + print("Facility Adjustment: ", llm_answer_raw) + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + exhibit_level_answers.update(llm_answer_final) + + return exhibit_level_answers + + +def prompt_exhibit_lesser( + exhibit_text: str, + exhibit_level_answers: dict, + filename: str, +): + logging.debug(f"Running Exhibit-Level Lesser for {filename}:") + + prompt = prompt_templates.EXHIBIT_LEVEL_LESSER_OF(exhibit_text) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "legacy_sonnet", + filename, + max_tokens=8192, + cache=True, + instruction=prompt_templates.EXHIBIT_LEVEL_LESSER_OF_INSTRUCTION(), + usage_label="EXHIBIT_LEVEL_LESSER_OF", + ) + logging.debug(f"LLM raw output for {filename}: {llm_answer_raw}") + try: + exhibit_lesser_of_answer = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + except: + exhibit_lesser_of_answer = "N/A" + exhibit_level_answers["EXHIBIT_LESSER_OF_STATEMENT"] = exhibit_lesser_of_answer + return exhibit_level_answers + + +def prompt_dynamic_primary( + exhibit_text: str, field: Field, constants: Constants, filename: str, TEMPLATE +): + prompt = TEMPLATE(exhibit_text, field.field_name, field.get_prompt(constants)) + logging.debug(f"Dynamic primary prompt for {filename}; {field}: {prompt}") + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.DYNAMIC_PRIMARY_INSTRUCTION(), + ) + logging.debug(f"Claude answer for {filename}; {field}: {llm_answer_raw}") + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, string_utils.Delimiter.PIPE + ) + if "," in llm_answer_final: + llm_answer_final = "|".join( + [item.strip() for item in llm_answer_final.split(",")] + ) + return llm_answer_final + + +def prompt_reimbursement_primary( + page_text: str, + filename: str, +) -> list[dict[str, str]]: + + prompt = prompt_templates.REIMBURSEMENT_PRIMARY(page_text) + + logging.debug( + f"""Running reimbursement primary prompt for {filename} with prompt: {prompt}""" + ) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + max_tokens=25000, + cache=True, + instruction=prompt_templates.REIMBURSEMENT_PRIMARY_INSTRUCTION(), + usage_label="REIMBURSEMENT_PRIMARY", + ) + logging.debug(f"""LLM raw output for {filename}: {llm_answer_raw}""") + + # Check for the special "no results" case + if "NO_REIMBURSEMENT_TERMS_FOUND" in llm_answer_raw: + return [] # Return empty list if no reimbursement terms found + + try: + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + except ValueError as e: + logging.error(f"Error parsing LLM response: {e}") + logging.error(f"Raw LLM output: {llm_answer_raw}") + raise + return llm_answer_final + + +def prompt_methodology_breakout( + service_term: str, + reimb_term: str, + methodology_breakout_questions: FieldSet, + constants: Constants, + filename: str, +): + prompt = prompt_templates.METHODOLOGY_BREAKOUT( + service_term, + reimb_term, + methodology_breakout_questions.print_prompt_dict(constants), + ) + logging.debug(f"Methodology Breakout Prompt for {filename}: {prompt}") + llm_response = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.METHODOLOGY_BREAKOUT_INSTRUCTION(), + ) + logging.debug(f"LLM Response for {filename}: {llm_response}") + try: + methodology_breakout_answers = string_utils.universal_json_load(llm_response) + except ValueError as e: + logging.error(f"Error parsing LLM response: {e}") + methodology_breakout_answers = [] + return methodology_breakout_answers + + +def prompt_fee_schedule_breakout( + methodology_breakout_dict: dict, + reimbursement_method: str, + fs_breakout_questions: FieldSet, + constants: Constants, + filename: str, +): + prompt = prompt_templates.FEE_SCHEDULE_BREAKOUT( + reimbursement_method, + methodology_breakout_dict.get("FEE_SCHEDULE"), + fs_breakout_questions.print_prompt_dict(constants), + ) + logging.debug(f"Fee Schedule Breakout Prompt for {filename}: {prompt}") + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.FEE_SCHEDULE_BREAKOUT_INSTRUCTION(), + usage_label="FEE_SCHEDULE_BREAKOUT", + ) + logging.debug(f"LLM Response for {filename}: {llm_answer_raw}") + try: + fs_breakout_dict = string_utils.universal_json_load(llm_answer_raw) + except ValueError as e: + fs_breakout_dict = {} + return fs_breakout_dict + + +def prompt_grouper_breakout( + service: str, + reimbursement_method: str, + grouper_breakout_questions: FieldSet, + constants: Constants, + filename: str, +): + prompt = prompt_templates.GROUPER_BREAKOUT( + service, + reimbursement_method, + grouper_breakout_questions.print_prompt_dict(constants), + ) + logging.debug(f"Grouper Breakout Prompt for {filename}: {prompt}") + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.GROUPER_BREAKOUT_INSTRUCTION(), + usage_label="GROUPER_BREAKOUT", + ) + logging.debug(f"LLM Response for {filename}: {llm_answer_raw}") + try: + grouper_breakout_dict = string_utils.universal_json_load(llm_answer_raw) + except: + grouper_breakout_dict = {} + + return grouper_breakout_dict + + +def prompt_carveout_check( + service_term: str, + reimb_term: str, + carveout_definitions, + special_case_definitions, + filename: str, +): + carveout_prompt = prompt_templates.CARVEOUT_CHECK( + service_term, reimb_term, carveout_definitions, special_case_definitions + ) + logging.debug( + f"Running carveout check for {filename} with prompt:\n{carveout_prompt}" + ) + llm_answer_raw = llm_utils.invoke_claude( + carveout_prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.CARVEOUT_CHECK_INSTRUCTION(), + usage_label="CARVEOUT_CHECK", + ) + + carveout_answer = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + return carveout_answer + + +def prompt_special_case_breakout(breakout_template, term_answer, filename): + # Get the prompt from the template + prompt = breakout_template(term_answer) + + # Ensure prompt is a string for Bedrock messages API + if not isinstance(prompt, str): + logging.warning( + f"Expected prompt string, got {type(prompt)} in prompt_special_case_breakout; coercing to str." + ) + prompt = str(prompt) + + # Look for a corresponding _INSTRUCTION() function for caching + template_name = getattr(breakout_template, "__name__", "SPECIAL_CASE_BREAKOUT") + instruction_func_name = f"{template_name}_INSTRUCTION" + instruction_func = getattr(prompt_templates, instruction_func_name, None) + + if instruction_func and callable(instruction_func): + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=instruction_func(), + usage_label=template_name, + ) + else: + llm_answer_raw = llm_utils.invoke_claude( + prompt, "sonnet_latest", filename, usage_label="SPECIAL_CASE_BREAKOUT" + ) + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + return llm_answer_final + + +def prompt_lob_relationship( + answer_dict: dict, field: str, exhibit_text: str, filename: str +): + """ + Helper function to prompt LLM for LOB relationship based on the field and exhibit text. + """ + programs = answer_dict.get(field) + dynamic_primary_values = ( + f"LOB: {answer_dict.get("AARETE_DERIVED_LOB")}\nPROGRAM: {programs}" + ) + + prompt = prompt_templates.LOB_RELATIONSHIP(exhibit_text, dynamic_primary_values) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + model_id="sonnet_latest", + filename=filename, + cache=True, + instruction=prompt_templates.LOB_RELATIONSHIP_INSTRUCTION(), + ) + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + return llm_answer_final + + +def prompt_special_case_assignment( + exhibit_text: str, + reimbursement_dict: dict, + special_case_dicts: list, + special_case_term: str, + filename: str, +) -> dict[str, str]: + + # If all non-term values are identical across dictionaries, return first dict + non_term_keys = [k for k in special_case_dicts[0].keys() if "_TERM" not in k] + if all( + all(d[key] == special_case_dicts[0][key] for d in special_case_dicts[1:]) + for key in non_term_keys + ): + answer_dict = special_case_dicts[0].copy() + answer_dict[special_case_term] = "|".join( + [ + special_case_dict[special_case_term] + for special_case_dict in special_case_dicts + ] + ) + return answer_dict + + # Otherwise use LLM + llm_answer_raw = llm_utils.invoke_claude( + prompt_templates.SPECIAL_CASE_ASSIGNMENT( + exhibit_text, reimbursement_dict, special_case_dicts, special_case_term + ), + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.SPECIAL_CASE_ASSIGNMENT_INSTRUCTION(), + usage_label="SPECIAL_CASE_ASSIGNMENT", + ) + index_answer = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + try: + if not string_utils.is_empty(index_answer): + return special_case_dicts[int(index_answer)] + else: + return {} + except: + return special_case_dicts[0] + + +def extract_and_parse(text): + import re + import json + + pattern = r"\{[^{}]+\}" + match = re.search(pattern, text, re.DOTALL) + + if not match: + return {} + + try: + return json.loads(match.group(0)) + except json.JSONDecodeError as e: + raise ValueError(f"Invalid JSON: {e}") + + +def prompt_full_context( + contract_text: str, + full_context_fields: FieldSet, + constants: Constants, + filename: str, +): + + prompt_questions = full_context_fields.print_prompt_dict(constants) + + full_context_prompt = prompt_templates.ONE_TO_ONE_MULTI_FIELD_TEMPLATE( + context=contract_text[ + 0 : min( + config.MAX_CONTEXT_LENGTH - len(prompt_questions), + len(contract_text) - 1, + ) + ], + questions=prompt_questions, + ) + try: + claude_answer_raw = llm_utils.invoke_claude( + full_context_prompt, + "sonnet_latest", + filename, + 8192, + cache=True, + instruction=prompt_templates.ONE_TO_ONE_MULTI_FIELD_INSTRUCTION(), + ) + full_context_answers_dict = string_utils.universal_json_load(claude_answer_raw) + if not isinstance(full_context_answers_dict, dict): + full_context_answers_dict = extract_and_parse(claude_answer_raw) + + except Exception as e: + logging.error(f"Error processing high accuracy fields: {str(e)}") + full_context_answers_dict = {} + for field in full_context_fields.list_fields(): + full_context_answers_dict[field] = f"Error: {str(e)}" + + return full_context_answers_dict + + +def is_exhibit_lesser_of_redundant( + reimb_term: str, exhibit_lesser_of: str, filename: str +) -> bool: + """Use LLM to determine if exhibit-level lesser-of statement is redundant with the reimbursement term. + + This is a second step of filtering, after checking for exact substring matches. + Small variations in punctuation may make it past the first filter, so in those cases + where it's determined NOT to contain the substring, we use LLM to check if the + semantic meaning is the same. + + Args: + reimb_term (str): The original reimbursement term. + exhibit_lesser_of (str): The exhibit-level lesser-of statement. + filename (str): The name of the file being processed, for logging. + + Returns: + bool: True if the exhibit-level lesser-of statement is redundant, False otherwise. + """ + + prompt = prompt_templates.CHECK_REDUNDANT_LESSER(reimb_term, exhibit_lesser_of) + + response = llm_utils.invoke_claude( + prompt, + "haiku_latest", + filename=filename, + cache=True, + instruction=prompt_templates.CHECK_REDUNDANT_LESSER_INSTRUCTION(), + ) + logging.debug(f"LLM response for redundancy check in {filename}: {response}") + return ( + string_utils.extract_text_from_delimiters(response, Delimiter.PIPE) + .strip() + .upper() + == "YES" + ) + + +def validate_reimbursements_for_llm(answer_dict: dict[str, str], filename: str) -> bool: + """Use LLM to determine if a service has actual reimbursement methodology. + + Args: + answer_dict (dict): The service-reimbursement answer dictionary. + filename (str): The name of the file being processed. + + Returns: + bool: True if the service has a clear reimbursement methodology, False otherwise. + """ + if isinstance(answer_dict, str): + answer_dict = {"SERVICE_TERM": "", "REIMB_TERM": answer_dict} + + if string_utils.is_empty( + answer_dict.get("SERVICE_TERM", None) + ) or string_utils.is_empty(answer_dict.get("REIMB_TERM", None)): + logging.warning( + f"Missing SERVICE_TERM or REIMB_TERM in {filename}: {answer_dict}" + ) + return False + + service_term, reimb_term = answer_dict["SERVICE_TERM"], answer_dict["REIMB_TERM"] + prompt = prompt_templates.VALIDATE_REIMBURSEMENTS_PROMPT(service_term, reimb_term) + logging.debug(f"Prompt for reimbursement validation in {filename}:\n{prompt}") + + llm_response = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.VALIDATE_REIMBURSEMENTS_INSTRUCTION(), + ) + logging.debug( + f"LLM response for reimbursement validation in {filename}:\n{llm_response}" + ) + final_answer = ( + string_utils.extract_text_from_delimiters(llm_response, Delimiter.PIPE) + .strip() + .upper() + ) + return final_answer == "YES" + + +def prompt_dynamic(text: str, field_prompts, filename): + """ + Prompts an LLM to process dynamic fields in a given text and extracts structured responses. + + Args: + text (str): The text to analyze and extract dynamic fields from. + field_prompts (dict): A dictionary mapping field names to prompts. + filename (str): The name of the file being processed. + + Returns: + dict: A dictionary containing field names as keys and extracted answers as values. + """ + prompt = prompt_templates.EXHIBIT_LEVEL(text, field_prompts) + logging.debug(f"Dynamic prompt for {filename}: {prompt}") + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.EXHIBIT_LEVEL_INSTRUCTION(), + ) # Returns dictionary of lists + logging.debug(f"Dynamic answer for {filename}: {llm_answer_raw}") + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + return llm_answer_final + + +def prompt_exhibit_linkage(page_header, previous_header, filename): + """Determine if current page header represents a different exhibit from the previous page. + + Uses LLM to compare page headers and determine if they indicate a transition to a + new exhibit section in the contract. + + Args: + page_header (str): Header text from the current page. + previous_header (str): Header text from the previous page. + filename (str): Source filename for logging and LLM attribution. + + Returns: + str: LLM response indicating if the exhibit has changed. + """ + prompt = prompt_templates.EXHIBIT_LINKAGE(page_header, previous_header) + claude_answer_raw = llm_utils.invoke_claude( + prompt, + "legacy_sonnet", + filename, + cache=True, + instruction=prompt_templates.EXHIBIT_LINKAGE_INSTRUCTION(), + usage_label="EXHIBIT_LINKAGE", + ) + exhibit_is_different = string_utils.extract_text_from_delimiters( + claude_answer_raw, Delimiter.PIPE + ) + return exhibit_is_different + + +def prompt_exhibit_header(page_content, EXHIBIT_HEADER_MARKERS, filename): + """Extract exhibit header identifier from page content using pattern matching. + + Uses LLM to identify exhibit headers in page content based on predefined markers + and extract the exhibit identifier. + + Args: + page_content (str): First 400 characters of page content to analyze. + EXHIBIT_HEADER_MARKERS (list): List of exhibit header pattern markers. + filename (str): Source filename for logging and LLM attribution. + + Returns: + str: Extracted exhibit header identifier or marker indicating no header found. + """ + prompt = prompt_templates.EXHIBIT_HEADER( + page_content[0:400], EXHIBIT_HEADER_MARKERS + ) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + max_tokens=300, + cache=True, + instruction=prompt_templates.EXHIBIT_HEADER_INSTRUCTION(), + usage_label="EXHIBIT_HEADER", + ) + llm_answer_extracted = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + return llm_answer_extracted + + +def prompt_smart_chunked( + answers_dict, new_field_groups, field_group, one_to_one_chunks, filename +): + """Extract field values from chunked contract text using appropriate prompt templates. + + Selects single-field or multi-field prompt templates based on the number of fields + in the group and processes the corresponding text chunk to extract structured answers. + + Args: + answers_dict (dict): Existing answers dictionary, mutated in place with new field values. + new_field_groups (dict): Field group definitions containing fields and their prompts. + field_group (str): Name of the field group to process. + one_to_one_chunks (dict): Text chunks mapped to field groups. + filename (str): Source filename for logging and LLM attribution. + + Returns: + dict: The mutated answers_dict with extracted field values or error messages. + """ + fields = new_field_groups[field_group].get("fields", []) + questions = {} + for field in fields: + questions[field.field_name] = field.prompt + + context = one_to_one_chunks[field_group] + context = context[0 : min(config.MAX_CONTEXT_LENGTH, len(context)) - 1] + + # prepare prompt + if len(fields) == 1: + question = questions[ + fields[0].field_name + ] # Take the one question for the single field included + prompt = prompt_templates.ONE_TO_ONE_SINGLE_FIELD_TEMPLATE(context, question) + elif len(fields) > 1: + prompt = prompt_templates.ONE_TO_ONE_MULTI_FIELD_TEMPLATE(context, questions) + else: + raise ValueError("Field group has no defined fields") + + try: + # Use appropriate instruction based on single vs multi-field + instruction = ( + prompt_templates.ONE_TO_ONE_SINGLE_FIELD_INSTRUCTION() + if len(fields) == 1 + else prompt_templates.ONE_TO_ONE_MULTI_FIELD_INSTRUCTION() + ) + field_group_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + 8192, + cache=True, + instruction=instruction, + usage_label="ONE_TO_ONE_CHUNKED", + ) + if len(fields) == 1: + field_group_answer_parsed = string_utils.extract_text_from_delimiters( + field_group_answer_raw, Delimiter.PIPE + ) + field_group_answer_dict = {fields[0].field_name: field_group_answer_parsed} + elif len(fields) > 1: + field_group_answer_dict = string_utils.json_parsing_search( + field_group_answer_raw, [field.field_name for field in fields] + ) + # Validate field names coming out of Claude: + expected_fields = {field.field_name for field in fields} + received_fields = set(field_group_answer_dict.keys()) + if expected_fields != received_fields: + missing = expected_fields - received_fields + extra = received_fields - expected_fields + raise ValueError(f"Field mismatch - Missing: {missing}, Extra: {extra}") + + # Load up answers dict + for field in fields: + field_answer = field_group_answer_dict[field.field_name] + answers_dict[field.field_name] = field_answer + + except Exception as e: + logging.error(f"Error processing field {field}: {type(e)}, {str(e)}") + for field in fields: + answers_dict[field.field_name] = f"Error: {str(e)}" + + return answers_dict + + +def prompt_date_fix(date: str) -> str: + """Processes dates using `prompt_templates.date_fix_prompt`. + + Args: + date (str): Input date string to be processed. + + Returns: + str: Processed date; either a date in YYYY/MM/DD format, a duration (e.g. "3 years"), or "N/A". + """ + if string_utils.is_empty(date): + return "N/A" + prompt = prompt_templates.DATE_FIX_PROMPT(date) + response = llm_utils.invoke_claude( + prompt, + "haiku_latest", + "date_fix", + cache=True, + instruction=prompt_templates.DATE_FIX_INSTRUCTION(), + usage_label="DATE_FIX", + ) + return string_utils.extract_text_from_delimiters(response, Delimiter.PIPE) + + +def prompt_derived_term_date( + effective_date: str = None, termination_information: str = None +) -> str: + """Calculate contract termination date from effective date and term duration using LLM. + + Uses LLM to parse term duration text and calculate the corresponding termination date + based on the provided effective date. + + Args: + effective_date (str): ISO-formatted effective date (YYYY-MM-DD) or date string. + termination_information (str): Term duration text (e.g., "3 years from effective date"). + + Returns: + str: ISO-formatted termination date (YYYY-MM-DD) or "N/A" if calculation fails. + """ + prompt = prompt_templates.DERIVED_TERM_DATE_PROMPT( + effective_date, termination_information + ) + response = llm_utils.invoke_claude( + prompt, + "haiku_latest", + "derive_term_date", + cache=True, + instruction=prompt_templates.DERIVED_TERM_DATE_INSTRUCTION(), + usage_label="DERIVED_TERM_DATE", + ) + return string_utils.extract_text_from_delimiters(response, Delimiter.PIPE) + + +def prompt_global_lesser_of_breakout( + global_lesser_of_stmt: str, constants: Constants, filename: str +) -> dict[str, str]: + """Parse global lesser-of statement into structured methodology fields using LLM breakout. + + This function reuses the same METHODOLOGY_BREAKOUT prompt template used for individual + service-level reimbursement terms to extract structured fields from contract-wide lesser-of + constraints. The extracted fields follow the same structure as methodology_breakout fields + defined in the field JSON. + + The function works by: + 1. Creating a mock service term "Global Lesser Of (all services)" to fit the breakout template + 2. Loading methodology_breakout fields from the field JSON configuration + 3. Invoking Claude with the METHODOLOGY_BREAKOUT prompt to parse the statement + 4. Adding "[GLOBAL LESSER OF]" prefix to REIMB_TERM for tracking/identification + 5. Returning the parsed fields or a minimal dict with just REIMB_TERM if parsing fails + + Args: + global_lesser_of_stmt (str): Global lesser-of statement extracted from contract. + Example: "At no time will reimbursement exceed 100% of billed charges" + constants (Constants): Configuration object containing valid codes and business rules + used during methodology breakout parsing + filename (str): Source filename (e.g., "contract_001.txt"). Used for: + - Logging context + - LLM request attribution + - Error tracking + + Returns: + dict[str, str]: Dictionary of methodology breakout fields extracted from the statement. + Always includes REIMB_TERM with "[GLOBAL LESSER OF]" prefix. Other fields depend on + what's defined as field_type="methodology_breakout" in the field JSON (e.g., + REIMB_PCT_RATE, REIMB_FEE_RATE, UNIT_OF_MEASURE, etc.) + + If parsing fails, returns: {"REIMB_TERM": "[GLOBAL LESSER OF] {original_statement}"} + + Side Effects: + - Makes LLM API call via llm_utils.invoke_claude() + - Logs debug information about prompt and response (via logging_utils context) + - Logs error if parsing fails but continues execution + + Notes: + - Uses the same METHODOLOGY_BREAKOUT template as one-to-n service-level terms + - The mock service term "Global Lesser Of (all services)" allows the global statement + to fit the [service, term] tuple expected by METHODOLOGY_BREAKOUT + - Parsing failures are non-fatal - returns minimal dict to allow processing to continue + - The "[GLOBAL LESSER OF]" prefix in REIMB_TERM distinguishes these from service-level terms + - This function is typically called from row_funcs.apply_global_lesser_of() which uses + the results to create duplicate rows via create_global_lesser_of_row() + - The specific methodology fields returned depend on the field_type="methodology_breakout" + definitions in the field JSON configuration + + Example: + >>> stmt = "At no time will reimbursement exceed 100% of billed charges" + >>> constants = Constants(...) + >>> result = run_global_lesser_of_breakout(stmt, constants, "contract.txt") + >>> result["REIMB_TERM"] + '[GLOBAL LESSER OF] At no time will reimbursement exceed 100% of billed charges' + >>> result["AARETE_DERIVED_REIMB_METHOD"] + 'billed charges' + >>> result["REIMB_PCT_RATE"] + '100' + >>> # Other fields depend on methodology_breakout field definitions in JSON + """ + + # Create a mock service term for the breakout + mock_service = "Global Lesser Of (all services)" + + prompt = prompt_templates.METHODOLOGY_BREAKOUT( + [mock_service, global_lesser_of_stmt], + FieldSet( + file_path=config.FIELD_JSON_PATH, field_type="methodology_breakout" + ).print_prompt_dict(constants), + ) + logging.debug( + f"Running global lesser of breakout for {filename} with prompt: {prompt}" + ) + + llm_response = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.METHODOLOGY_BREAKOUT_INSTRUCTION(), + usage_label="GLOBAL_LESSER_OF_BREAKOUT", + ) + + try: + breakout_results = string_utils.universal_json_load(llm_response) + result = breakout_results[0] if breakout_results else {} + + # Add the global lesser of statement as the REIMB_TERM + result["REIMB_TERM"] = f"[GLOBAL LESSER OF] {global_lesser_of_stmt}" + + return result + except: + logging.error( + f"Failed to parse global lesser of breakout response for {filename}. Response: {llm_response}" + ) + return {"REIMB_TERM": f"[GLOBAL LESSER OF] {global_lesser_of_stmt}"} + + +def prompt_dynamic_assignment( + service_term: str, + reimb_term: str, + dynamic_field: Field, + exhibit_text_simplified: str, + page_num: str, + constants: Constants, + filename: str, +): + + field_name = dynamic_field.field_name + field_prompt = dynamic_field.get_prompt(constants) + + # Use specialized prompt for REIMB_DATES assignment + if field_name == "REIMB_DATES": + prompt = prompt_templates.REIMB_DATES_ASSIGNMENT( + service_term, reimb_term, field_prompt, exhibit_text_simplified, page_num + ) + else: + # Use generic DYNAMIC_ASSIGNMENT for other fields + prompt = prompt_templates.DYNAMIC_ASSIGNMENT( + service_term, + reimb_term, + field_name, + field_prompt, + exhibit_text_simplified, + page_num, + ) + + llm_answer_raw = llm_utils.invoke_claude( + prompt, + model_id="sonnet_latest", + filename=filename, + cache=True, + instruction=prompt_templates.DYNAMIC_ASSIGNMENT_INSTRUCTION(), + usage_label="DYNAMIC_ASSIGNMENT", + ) + + try: + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + return llm_answer_final + except: + logging.error( + f"Failed to parse Dynamic Field: {field_name}. Response: {llm_answer_raw}" + ) + return {field_name: "Extraction Error"} + + +def prompt_lesser_of_distribution( + service_term: str, + reimb_term: str, + exhibit_text_simplified: str, + page_num: str, + cross_exhibit_lesser_of: list[dict], + filename: str, +) -> str: + """ + Apply lesser-of logic to a service and rate using hybrid approach. + + Combines: + 1. Cross-exhibit templates (GLOBAL and OTHER) from other exhibits (pre-provided) + 2. Intra-exhibit statements by searching the current exhibit text + + This approach avoids race conditions by: + - Storing only GLOBAL and cross-exhibit (OTHER) templates between exhibits + - Searching exhibit text for intra-exhibit statements (CURRENT) + - Exhibits process serially, so cross-exhibit templates are safe + + Args: + service_term: Service description + reimb_term: Original reimbursement term (rate without lesser-of) + exhibit_text_simplified: Simplified exhibit text to search for intra-exhibit statements + page_num: Current page number + cross_exhibit_lesser_of: List of GLOBAL and cross-exhibit lesser-of answer dicts. + Each dict contains: service_term, reimb_term, scope, + target_exhibit, exhibit_reference, page_num + filename: Filename for logging + + Returns: + str: Combined reimbursement term with lesser-of applied, or original term if no lesser-of applies + + Example: + >>> cross_exhibit = [{ + ... 'reimb_term': 'All services: lesser of rates or charges', + ... 'scope': 'GLOBAL', + ... 'page_num': '5' + ... }] + >>> result = prompt_lesser_of_distribution( + ... "Office Visit", "$150", exhibit_text, "10", cross_exhibit, "contract.pdf" + ... ) + >>> # Returns: "Office Visit paid at the lesser of $150 or charges" + """ + prompt = prompt_templates.LESSER_OF_DISTRIBUTION( + service_term, + reimb_term, + page_num, + exhibit_text_simplified, + cross_exhibit_lesser_of, # Pass list of cross-exhibit answer dicts + ) + + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.LESSER_OF_DISTRIBUTION_INSTRUCTION(), + usage_label="LESSER_OF_DISTRIBUTION", + ) + + # Check if LLM determined no lesser-of applies + if "N/A" in llm_answer_raw: + logging.debug( + f"No lesser-of constraints apply to '{service_term}' on page {page_num}" + ) + return reimb_term # Return original term unchanged + else: + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + + logging.debug( + f"Applied lesser-of to '{service_term}' on page {page_num}: " + f"{reimb_term} → {llm_answer_final[:60]}..." + ) + + return llm_answer_final + + +def prompt_lesser_of_check( + service_term: str, reimb_term: str, exhibit_title: str, filename: str +) -> dict: + """ + Classify a lesser-of statement into GLOBAL, EXHIBIT_SPECIFIC, or STANDALONE. + + Args: + service_term: Service description + reimb_term: Reimbursement term containing lesser-of language + exhibit_title: Current exhibit's title/header + filename: Filename for logging + + Returns: + dict: Classification result with keys: + - service_term: str + - reimb_term: str + - scope: "GLOBAL" | "EXHIBIT_SPECIFIC" | "STANDALONE" + - target_exhibit: "ALL" | "CURRENT" | "OTHER" | None + - exhibit_reference: str | None (exhibit name if target is OTHER) + """ + # DEBUG: Log what we're sending + logging.info( + f"LESSER_OF_CHECK input: service='{service_term[:50]}...', reimb_term='{reimb_term[:100]}...'" + ) + + prompt = prompt_templates.LESSER_OF_CHECK(service_term, reimb_term, exhibit_title) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.LESSER_OF_CHECK_INSTRUCTION(), + usage_label="LESSER_OF_CHECK", + ) + + try: + # Extract JSON from pipes + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + + logging.debug(f"LESSER_OF_CHECK extracted from pipes: {llm_answer_final}") + + # Parse JSON + lesser_of_answer_dict = json.loads(llm_answer_final) + + # Validate required fields + required_fields = [ + "service_term", + "reimb_term", + "scope", + "target_exhibit", + "exhibit_reference", + ] + for field in required_fields: + if field not in lesser_of_answer_dict: + logging.warning( + f"LESSER_OF_CHECK missing field '{field}' for service '{service_term}', " + f"exhibit '{exhibit_title}', defaulting to STANDALONE" + ) + return { + "service_term": service_term, + "reimb_term": reimb_term, + "scope": "STANDALONE", + "target_exhibit": None, + "exhibit_reference": None, + } + + logging.info( + f"LESSER_OF_CHECK classification: scope={lesser_of_answer_dict['scope']}, " + f"target={lesser_of_answer_dict['target_exhibit']}, " + f"exhibit_ref={lesser_of_answer_dict.get('exhibit_reference')}, " + f"service='{service_term}...', exhibit='{exhibit_title}'" + ) + + return lesser_of_answer_dict + + except json.JSONDecodeError as e: + logging.error( + f"Failed to parse LESSER_OF_CHECK JSON for service '{service_term}', " + f"exhibit '{exhibit_title}': {e}. Raw response: {llm_answer_final[:200]}... " + f"Defaulting to STANDALONE" + ) + return { + "service_term": service_term, + "reimb_term": reimb_term, + "scope": "STANDALONE", + "target_exhibit": None, + "exhibit_reference": None, + } + except Exception as e: + logging.error( + f"Error in prompt_lesser_of_check for service '{service_term}', " + f"exhibit '{exhibit_title}': {e}. Defaulting to STANDALONE" + ) + return { + "service_term": service_term, + "reimb_term": reimb_term, + "scope": "STANDALONE", + "target_exhibit": None, + "exhibit_reference": None, + } + + +def prompt_exhibit_title_match( + current_exhibit_title: str, target_exhibit_reference: str, filename: str = "" +) -> str: + prompt = prompt_templates.EXHIBIT_TITLE_MATCH( + current_exhibit_title, target_exhibit_reference + ) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.EXHIBIT_TITLE_MATCH_INSTRUCTION(), + usage_label="EXHIBIT_TITLE_MATCH", + ) + + try: + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + return llm_answer_final.strip().upper() # Return "YES" or "NO" as string + except: + return "NO" # Default to "NO" string + + +def provider_name_match_check( + provider_name: str, hybrid_smart_chunking_provider_group_name: str, filename: str +) -> bool: + """Check if the provider name from npi/tin page match provider group name""" + if string_utils.is_empty(provider_name) or string_utils.is_empty( + hybrid_smart_chunking_provider_group_name + ): + return False + + if hybrid_smart_chunking_provider_group_name == "N/A": + return False + + # Create prompt for LLM + CHECK_PROVIDER_NAME_MATCH_PROMPT = prompt_templates.CHECK_PROVIDER_NAME_MATCH_PROMPT( + provider_name=provider_name, + hybrid_smart_chunking_provider_group_name=hybrid_smart_chunking_provider_group_name, + ) + + try: + # Adjust this based on your LLM client + response = llm_utils.invoke_claude( + CHECK_PROVIDER_NAME_MATCH_PROMPT, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.CHECK_PROVIDER_NAME_MATCH_INSTRUCTION(), + usage_label="CHECK_PROVIDER_NAME_MATCH", + ) + + # Extract last character (should be Y or N) + response = string_utils.extract_text_from_delimiters(response, Delimiter.PIPE) + + if response == "Y": + logging.debug( + f"[is_provider_name_match_llm] ✓ LLM matched: '{provider_name}' ≈ '{hybrid_smart_chunking_provider_group_name}'" + ) + return True + elif response == "N": + logging.debug( + f"[is_provider_name_match_llm] ✗ LLM no match: '{provider_name}' ≠ '{hybrid_smart_chunking_provider_group_name}'" + ) + return False + else: + logging.warning( + f"[is_provider_name_match_llm] Unexpected response: {response}, defaulting to False" + ) + return False + + except Exception as e: + logging.error( + f"[is_provider_name_match_llm] Error calling LLM: {e}, defaulting to False" + ) + return False diff --git a/src/pipelines/runner.py b/src/pipelines/runner.py new file mode 100644 index 0000000..4594f51 --- /dev/null +++ b/src/pipelines/runner.py @@ -0,0 +1,269 @@ +""" +Common Pipeline Runner + +Handles shared orchestration (DTC, QC/QA, cache warming) and routes +to client-specific file_processing implementations. + +Usage: + from src.pipelines.runner import main + main(client="saas") # Run default SaaS pipeline + main(client="clover") # Run Clover client pipeline +""" + +import concurrent.futures +import importlib +import logging +import traceback +import warnings +from datetime import datetime + +import pandas as pd + +# Suppress Pydantic protected namespace warning from langchain-aws +warnings.filterwarnings("ignore", message=".*protected namespace.*") + +import src.prompts.prompt_templates as prompt_templates +import src.utils.io_utils as io_utils +import src.utils.llm_utils as llm_utils +import src.utils.logging_utils as logging_utils +import src.utils.usage_tracking as usage_tracking +from src.constants.constants import Constants +from src import config +from src.core.registry import get_registry +from src.parent_child import main as parent_child_main +from src.document_classification import main as dtc_main +from src.qc_qa.pipeline import ( + generate_statistics, + run_qc_qa_pipeline, + save_qc_qa_outputs, +) + + +def get_file_processing_module(client: str): + """Get the file_processing module for a client. + + Args: + client: Client name ("saas", "clover", etc.) + + Returns: + The file_processing module for the specified client + """ + if client == "saas": + from src.pipelines.saas import file_processing + + return file_processing + else: + # Dynamic import for client + module_path = f"src.pipelines.clients.{client}.file_processing" + return importlib.import_module(module_path) + + +def safe_process_file(item, constants, run_timestamp, file_processing): + """Process a single file with comprehensive error handling. + + Args: + item: Tuple of (filename, contract_text) representing the file to process + constants: Constants object containing configuration and processing rules + run_timestamp: Timestamp string for output file naming and tracking + file_processing: The file_processing module to use + + Returns: + pd.DataFrame: Either: + - DataFrame with extracted field results (success case) + - Single-row DataFrame with error details (failure case) + """ + file_id = item[0] if isinstance(item, (list, tuple)) and len(item) > 0 else item + try: + result = file_processing.process_file(item, constants, run_timestamp) + return result + except Exception as e: + error_type = type(e).__name__ + error_message = str(e) + full_traceback = traceback.format_exc() + + logging.error(f"Error processing file {file_id}") + logging.error(f"Error type: {error_type}") + logging.error(f"Error Message: {error_message}") + logging.error(f"Full traceback:\n{full_traceback}") + + return pd.DataFrame( + [ + { + "FILE_NAME": file_id, + "error": error_message.replace(",", ";").replace("\n", " "), + "error_type": error_type, + "traceback": full_traceback.replace(",", ";").replace("\n", " | "), + } + ] + ) + + +def main(client: str = "saas", testing=False, test_params={}): + """Main entry point for all clients. + + Args: + client: Client name ("saas", "clover", etc.) + testing: Whether running in test mode + test_params: Test parameters if testing=True + """ + # Validate client + registry = get_registry() + if client != "saas" and not registry.has_client(client): + raise ValueError( + f"Unknown client: {client}. Available clients: {registry.list_clients()}" + ) + + # Get client-specific file processing module + file_processing = get_file_processing_module(client) + logging.info(f"Using {client} pipeline") + + # Set up per-file logging + logging_utils.setup_per_file_logging() + + # Windows paths cannot contain ':'; use '-' in time component + run_timestamp = datetime.now().strftime(f"run_%Y%m%d_%H-%M_{config.BATCH_ID}") + + # Read Constants + constants = Constants() + + # Read and process input + if not testing: + input_dict = io_utils.read_input() + max_workers = config.MAX_WORKERS + else: + input_dict = io_utils.read_input(test_params["local_input_dir"]) + max_workers = test_params["max_workers"] + if "input_files" in test_params: + input_dict = { + k: v for k, v in input_dict.items() if k in test_params["input_files"] + } + + logging.info(f"Total Input Files : {len(input_dict)}") + + # ========== COMMON: Document Type Classification ========== + if config.PERFORM_DTC: + logging.info("=" * 80) + logging.info("DOCUMENT TYPE CLASSIFICATION MODE - Running DTC and exiting") + logging.info("=" * 80) + dtc_main.main(input_dict, run_timestamp) + logging.info( + "DTC classification complete. Exiting (investment pipeline not run)." + ) + logging.info("=" * 80) + return + + # ========== COMMON: Warm prompt caches ========== + logging.info("Warming prompt caches before parallel processing...") + try: + cacheable_instructions = prompt_templates.get_cacheable_instructions() + for cache_key, instruction in cacheable_instructions.items(): + llm_utils.warm_prompt_cache( + instruction=instruction, cache_key=cache_key, model_id="sonnet_latest" + ) + logging.info(f"Successfully warmed {len(cacheable_instructions)} prompt caches") + except Exception as e: + logging.warning(f"Error warming caches (will proceed anyway): {str(e)}") + + # ========== CLIENT-SPECIFIC: File Processing ========== + successful_results = [] + error_results = [] + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + futures = [ + executor.submit( + safe_process_file, item, constants, run_timestamp, file_processing + ) + for item in input_dict.items() + ] + + for future in concurrent.futures.as_completed(futures): + try: + results = future.result() + if "error" in results.columns: + error_results.append(results) + else: + successful_results.append(results) + except Exception as e: + logging.error(f"Error processing future: {str(e)}") + error_results.append(pd.DataFrame([{"error": str(e)}])) + + # Combine results + if len(successful_results) > 0: + FINAL_RESULT_DF = pd.concat(successful_results) + else: + FINAL_RESULT_DF = pd.DataFrame() + + if len(error_results) > 0: + ERROR_RESULT_DF = pd.concat(error_results) + else: + ERROR_RESULT_DF = pd.DataFrame() + + # ========== COMMON: QC/QA Validation ========== + if config.ENABLE_QC_QA and not FINAL_RESULT_DF.empty: + logging.info("=" * 80) + logging.info("Running QC/QA Validation Pipeline...") + logging.info("=" * 80) + try: + validated_df = run_qc_qa_pipeline(FINAL_RESULT_DF.copy(), stats_df=None) + logging.info("QC/QA validation completed successfully") + + logging.info("Generating QC/QA statistics...") + qc_qa_stats_df = generate_statistics(validated_df) + logging.info("QC/QA statistics generated successfully") + + save_qc_qa_outputs( + validated_df=validated_df, + stats_df=qc_qa_stats_df, + run_timestamp=run_timestamp, + write_to_s3=config.WRITE_TO_S3, + ) + except Exception as e: + logging.error(f"QC/QA validation failed: {str(e)}") + logging.error(f"Full traceback:\n{traceback.format_exc()}") + logging.warning("Continuing with original unvalidated results...") + logging.info("=" * 80) + + # ========== COMMON: Output & Parent-Child ========== + if not testing: + per_file_usage_df, batch_summary_df = usage_tracking.get_usage_dataframes( + config.BATCH_ID, run_timestamp + ) + + if config.WRITE_TO_S3: + doczy_output_for_pc = io_utils.write_s3( + FINAL_RESULT_DF, "", run_timestamp, "final" + ) + if not ERROR_RESULT_DF.empty: + io_utils.write_s3(ERROR_RESULT_DF, "", run_timestamp, "error") + + if not per_file_usage_df.empty and not batch_summary_df.empty: + logging.info("Exporting usage and cost tracking data to S3...") + io_utils.write_s3(per_file_usage_df, "", run_timestamp, "usage") + io_utils.write_s3(batch_summary_df, "", run_timestamp, "usage_summary") + else: + doczy_output_for_pc = io_utils.write_local( + FINAL_RESULT_DF, "", run_timestamp, "final" + ) + if not ERROR_RESULT_DF.empty: + io_utils.write_local(ERROR_RESULT_DF, "", run_timestamp, "error") + + if config.PERFORM_PARENT_CHILD_MAPPING: + parent_child_main.main(doczy_output_for_pc) + + if not per_file_usage_df.empty and not batch_summary_df.empty: + logging.info("Exporting usage and cost tracking data locally...") + io_utils.write_local(per_file_usage_df, "", run_timestamp, "usage") + io_utils.write_local(batch_summary_df, "", run_timestamp, "usage_summary") + else: + return FINAL_RESULT_DF, ERROR_RESULT_DF + + +if __name__ == "__main__": + # Default to saas, can be overridden via config or CLI arg + client_arg = getattr(config, "CLIENT", ["saas"]) + # CLIENT is a list from config, get first element or default to "saas" + client = ( + client_arg[0] + if client_arg and isinstance(client_arg, list) + else client_arg or "saas" + ) + main(client=client) diff --git a/fieldExtraction/src/utils/__init__.py b/src/pipelines/saas/__init__.py similarity index 100% rename from fieldExtraction/src/utils/__init__.py rename to src/pipelines/saas/__init__.py diff --git a/fieldExtraction/src/investment/file_processing.py b/src/pipelines/saas/file_processing.py similarity index 55% rename from fieldExtraction/src/investment/file_processing.py rename to src/pipelines/saas/file_processing.py index ca43463..9cab5ef 100644 --- a/fieldExtraction/src/investment/file_processing.py +++ b/src/pipelines/saas/file_processing.py @@ -1,16 +1,37 @@ import concurrent.futures import logging +from typing import TYPE_CHECKING, Optional import pandas as pd import src.codes.code_funcs as code_funcs -from src.investment import preprocessing_funcs, aarete_derived, dynamic_funcs, one_to_n_funcs, one_to_one_funcs, postprocess, postprocessing_funcs, preprocess, hybrid_smart_chunking_funcs, row_funcs, tin_npi_funcs, exhibit_funcs -from src.investment.exhibit_funcs import Exhibit +from src.pipelines.shared.preprocessing import ( + preprocessing_funcs, + preprocess, + hybrid_smart_chunking_funcs, +) +from src.pipelines.shared.postprocessing import ( + aarete_derived, + postprocess, + postprocessing_funcs, +) +from src.pipelines.shared.extraction import ( + dynamic_funcs, + one_to_n_funcs, + one_to_one_funcs, + row_funcs, + tin_npi_funcs, + exhibit_funcs, +) +from src.pipelines.shared.extraction.exhibit_funcs import Exhibit from src.utils import io_utils, logging_utils, string_utils, timing_utils -from constants.constants import Constants +from src.constants.constants import Constants from src import config from src.prompts.fieldset import FieldSet from src.utils.string_utils import datetime_str +if TYPE_CHECKING: + from src.pipelines.shared.extraction.page_funcs import Page + def process_file(file_object, constants: Constants, run_timestamp): filename, contract_text = file_object @@ -23,8 +44,8 @@ def process_file(file_object, constants: Constants, run_timestamp): # Set default values dynamic_one_to_one_fields = FieldSet() - process_one_to_n = config.FIELDS in ['all', 'one_to_n'] - process_one_to_one = config.FIELDS in ['all', 'one_to_one'] + process_one_to_n = config.FIELDS in ["all", "one_to_n"] + process_one_to_one = config.FIELDS in ["all", "one_to_one"] # Initialize default fallback for final results final_results = pd.DataFrame([{"FILE_NAME": filename}]) @@ -37,33 +58,67 @@ def process_file(file_object, constants: Constants, run_timestamp): # ONE TO N PROCESSING one_to_n_results = pd.DataFrame() # Initialize empty DataFrame for one_to_n_results if process_one_to_n: + # Use split_text_with_pages() to get Page objects with table splitting + # Note: split_text_with_pages() internally calls split_text() which applies headers/footers + # But we need to apply headers/footers first, so we'll create pages_dict from the cleaned text_dict + from src.pipelines.shared.extraction.page_funcs import Page + from src.pipelines.shared.preprocessing import preprocessing_funcs as prep_funcs + + # Create pages_dict from text_dict (headers/footers already applied) + pages_dict = prep_funcs.split_large_tables(text_dict) + with timing_utils.timed_block("one_to_n_exhibit_chunking", context=filename): - exhibit_chunk_mapping, all_exhibit_headers = preprocess.one_to_n_exhibit_chunking( - text_dict, constants.EXHIBIT_HEADER_MARKERS, filename + # Use pages_dict for exhibit chunking (preferred) or fall back to text_dict + exhibit_chunk_mapping, all_exhibit_headers = ( + preprocess.one_to_n_exhibit_chunking( + pages_dict=pages_dict, + text_dict=text_dict, + EXHIBIT_HEADER_MARKERS=constants.EXHIBIT_HEADER_MARKERS, + filename=filename, + ) ) logging.info(f"{datetime_str()} Preprocessing Complete - {filename}") one_to_n_results = pd.DataFrame([{"FILE_NAME": filename}]) # Initialize here if string_utils.contains_reimbursement(contract_text): - logging.info(f"{datetime_str()} Starting One-to-N extraction for {len(exhibit_chunk_mapping)} exhibits - {filename}") + logging.info( + f"{datetime_str()} Starting One-to-N extraction for {len(exhibit_chunk_mapping)} exhibits - {filename}" + ) with timing_utils.timed_block("one_to_n_extraction", context=filename): - one_to_n_results, dynamic_one_to_one_fields, first_reimbursement_page = run_one_to_n_prompts( - text_dict, exhibit_chunk_mapping, all_exhibit_headers, constants, filename + ( + one_to_n_results, + dynamic_one_to_one_fields, + first_reimbursement_page, + ) = run_one_to_n_prompts( + pages_dict=pages_dict, + text_dict=text_dict, + exhibit_chunk_mapping=exhibit_chunk_mapping, + all_exhibit_headers=all_exhibit_headers, + constants=constants, + filename=filename, ) if not one_to_n_results.empty: one_to_n_results["FILE_NAME"] = filename - with timing_utils.timed_block("one_to_n_generate_reimb_ids", context=filename): - one_to_n_results = postprocessing_funcs.generate_reimb_ids(one_to_n_results) + with timing_utils.timed_block( + "one_to_n_generate_reimb_ids", context=filename + ): + one_to_n_results = postprocessing_funcs.generate_reimb_ids( + one_to_n_results + ) logging.info(f"{datetime_str()} One to N Complete - {filename}") else: - first_reimbursement_page = '1' - logging.info(f"{datetime_str()} No Reimbursement Found, Skipping - {filename}") + first_reimbursement_page = "1" + logging.info( + f"{datetime_str()} No Reimbursement Found, Skipping - {filename}" + ) final_results = one_to_n_results # Set as final results else: - first_reimbursement_page = '1' - logging.info(f"{datetime_str()} Fields not configured for One to N, Skipping - {filename}") + first_reimbursement_page = "1" + logging.info( + f"{datetime_str()} Fields not configured for One to N, Skipping - {filename}" + ) # ONE TO ONE PROCESSING if process_one_to_one: @@ -81,7 +136,9 @@ def process_file(file_object, constants: Constants, run_timestamp): logging.info(f"{datetime_str()} One to One Complete - {filename}") # Decide how to handle one_to_one results - with timing_utils.timed_block("merge_one_to_one_into_one_to_n", context=filename): + with timing_utils.timed_block( + "merge_one_to_one_into_one_to_n", context=filename + ): if not one_to_n_results.empty: # BOTH processed - merge into one_to_n final_results = row_funcs.merge_one_to_one_into_one_to_n( @@ -91,7 +148,9 @@ def process_file(file_object, constants: Constants, run_timestamp): # ONLY one_to_one processed - convert dict to DataFrame final_results = pd.DataFrame([one_to_one_results]) else: - logging.info(f"{datetime_str()} Fields not configured for One to One, Skipping - {filename}") + logging.info( + f"{datetime_str()} Fields not configured for One to One, Skipping - {filename}" + ) # APPLY CODES IF ONE_TO_N WAS PROCESSED if not one_to_n_results.empty: @@ -100,7 +159,6 @@ def process_file(file_object, constants: Constants, run_timestamp): final_results = code_funcs.grouper_breakout(results_with_code) logging.info(f"{datetime_str()} Codes Complete - {filename}") - # POSTPROCESS with timing_utils.timed_block("postprocess", context=filename): final_df = postprocess.postprocess(final_results, constants) @@ -142,15 +200,21 @@ def run_one_to_one_prompts( ################## RUN HYBRID SMART CHUNKED PROMPTS ################## # RAG function loads retrieval questions internally and matches with investment_prompts.json with timing_utils.timed_block("one_to_one.hybrid_smart_chunking", context=filename): - hybrid_smart_chunked_answers_dict = hybrid_smart_chunking_funcs.run_hybrid_smart_chunked_fields( - one_to_one_fields, constants, contract_text, filename, text_dict + hybrid_smart_chunked_answers_dict = ( + hybrid_smart_chunking_funcs.run_hybrid_smart_chunked_fields( + one_to_one_fields, constants, contract_text, filename, text_dict + ) ) - ################## RUN FULL CONTEXT PROMPTS ################## with timing_utils.timed_block("one_to_one.full_context", context=filename): full_context_answers_dict = one_to_one_funcs.run_full_context_fields( - one_to_one_fields, contract_text, text_dict, first_reimbursement_page, constants, filename + one_to_one_fields, + contract_text, + text_dict, + first_reimbursement_page, + constants, + filename, ) ################## COMBINE ANSWERS ################ # Prefer HSC answers over full_context when HSC value is not N/A @@ -163,14 +227,20 @@ def run_one_to_one_prompts( elif key not in one_to_one_results: # Add HSC's N/A if field doesn't exist yet one_to_one_results[key] = value - - one_to_one_results = tin_npi_funcs.merge_provider_info_with_hybrid_smart_chunking(one_to_one_results, filename) + + one_to_one_results = tin_npi_funcs.merge_provider_info_with_hybrid_smart_chunking( + one_to_one_results, filename + ) ################## ADD AD FIELDS ################ - one_to_one_results = one_to_one_funcs.get_aarete_derived_dates(one_to_one_results, text_dict, filename) - + one_to_one_results = one_to_one_funcs.get_aarete_derived_dates( + one_to_one_results, text_dict, filename + ) + ################## ADD SIGNATURE COUNT ################## - one_to_one_results = one_to_one_funcs.add_signature_count(one_to_one_results, contract_text) + one_to_one_results = one_to_one_funcs.add_signature_count( + one_to_one_results, contract_text + ) ################## Crosswalk Fields ################## one_to_one_results = aarete_derived.get_crosswalk_fields( @@ -183,34 +253,91 @@ def run_one_to_one_prompts( return one_to_one_results[0] -def process_page_reimbursements(exhibit: Exhibit, page_num: str, text_dict: dict[str, str], - exhibit_page_nums: list[str], constants: Constants, filename: str): +def process_page_reimbursements( + exhibit: Exhibit, + page_num: str, + pages_dict: Optional[dict[str, "Page"]] = None, + text_dict: Optional[dict[str, str]] = None, + exhibit_page_nums: Optional[list[str]] = None, + constants: Optional[Constants] = None, + filename: Optional[str] = None, +): """ STEP 1 HELPER: Extract reimbursements from a single page (without exhibit-level fields). Runs: reimbursement_level → carveout_and_special_case → lesser_of_distribution → breakout + + Args: + exhibit: Exhibit object containing the page + page_num: Page identifier (can be "27" or "27.1" for sub-pages) + pages_dict: Dictionary mapping page numbers to Page objects (preferred) + text_dict: Dictionary mapping page numbers to text strings (for backward compatibility) + exhibit_page_nums: List of page numbers in the exhibit (for backward compatibility) + constants: Constants object + filename: Name of the file being processed """ - page_text = text_dict[page_num] - exhibit_text_simplified = preprocessing_funcs.simplify_exhibit(text_dict, exhibit_page_nums, page_num) + # Get page text - prefer using exhibit.get_page_text() if available + if exhibit.pages is not None: + page_text = exhibit.get_page_text(page_num) + exhibit_page_nums = exhibit.exhibit_page_nums + elif pages_dict is not None: + # Handle sub-pages: "27.1" means get sub-page "1" from page "27" + if "." in page_num and not page_num.startswith("."): + base_page, sub_page = page_num.rsplit(".", 1) + if base_page in pages_dict: + page_text = pages_dict[base_page].get_text(sub_page) + else: + page_text = "" + elif page_num in pages_dict: + page_text = pages_dict[page_num].get_text() + else: + page_text = "" + exhibit_page_nums = ( + exhibit.exhibit_page_nums + if exhibit_page_nums is None + else exhibit_page_nums + ) + elif text_dict is not None: + page_text = text_dict.get(page_num, "") + exhibit_page_nums = ( + exhibit_page_nums + if exhibit_page_nums is not None + else exhibit.exhibit_page_nums + ) + else: + raise ValueError( + "Either pages_dict, text_dict, or exhibit.pages must be provided" + ) + + # Simplify exhibit text - prefer using exhibit object + exhibit_text_simplified = preprocessing_funcs.simplify_exhibit( + exhibit=exhibit, + current_page_num=page_num, + ) ############################### Reimbursement Primary ############################### reimbursement_level_answers = one_to_n_funcs.reimbursement_level( - page_text, - constants, - filename + page_text, constants, filename ) if not reimbursement_level_answers: return [], [] ################################ Carveouts and Special Case ################################ - reimbursement_level_answers, special_case_answers = one_to_n_funcs.carveout_and_special_case( - reimbursement_level_answers, constants, filename + reimbursement_level_answers, special_case_answers = ( + one_to_n_funcs.carveout_and_special_case( + reimbursement_level_answers, constants, filename + ) ) ############################### Lesser of Distribution ############################### # Note: We run lesser_of without dynamic fields in Step 1 reimbursement_level_answers = one_to_n_funcs.lesser_of_distribution( - reimbursement_level_answers, exhibit_text_simplified, page_num, constants, filename + reimbursement_level_answers, + exhibit_text_simplified, + page_num, + constants, + filename, + exhibit, # ← Added this parameter ) ################################ Get Breakouts ############################### @@ -228,42 +355,68 @@ def process_page_reimbursements(exhibit: Exhibit, page_num: str, text_dict: dict return reimbursement_level_answers, special_case_answers -def run_one_to_n_prompts(text_dict: dict[str, str], - exhibit_chunk_mapping: dict[str, list[str]], - all_exhibit_headers: dict[str, str], - constants: Constants, - filename: str): +def run_one_to_n_prompts( + pages_dict: Optional[dict[str, "Page"]] = None, + text_dict: Optional[dict[str, str]] = None, + exhibit_chunk_mapping: Optional[dict[str, list[str]]] = None, + all_exhibit_headers: Optional[dict[str, str]] = None, + constants: Optional[Constants] = None, + filename: Optional[str] = None, +): """ 3-STEP APPROACH (per exhibit): Step 1: Extract reimbursements for exhibit pages (parallel within exhibit) Step 2: Run exhibit_level when exhibit has reimbursements Step 3: Run dynamic_assignment and combine results + + Args: + pages_dict: Dictionary mapping page numbers to Page objects (preferred) + text_dict: Dictionary mapping page numbers to text strings (for backward compatibility) + exhibit_chunk_mapping: Dictionary mapping exhibit pages to lists of page numbers + all_exhibit_headers: Dictionary mapping exhibit pages to their headers + constants: Constants object + filename: Name of the file being processed """ + if exhibit_chunk_mapping is None: + exhibit_chunk_mapping = {} + if all_exhibit_headers is None: + all_exhibit_headers = {} total_exhibits = len(exhibit_chunk_mapping) - logging.debug(f"{datetime_str()} Processing {total_exhibits} exhibits with NEW 3-step approach - {filename}") + logging.debug( + f"{datetime_str()} Processing {total_exhibits} exhibits with NEW 3-step approach - {filename}" + ) # Create Exhibit objects in order (maintains exhibit chain via prev_exhibit) exhibits = exhibit_funcs.get_exhibit_list( - text_dict, - exhibit_chunk_mapping, - all_exhibit_headers - ) # <- Returns list[Exhibit] - + pages_dict=pages_dict, + text_dict=text_dict, + exhibit_chunk_mapping=exhibit_chunk_mapping, + all_exhibit_headers=all_exhibit_headers, + ) # <- Returns list[Exhibit] + # Process exhibits serially; within each exhibit, process pages in parallel total_pages = sum(len(exhibit.exhibit_page_nums) for exhibit in exhibits) completed_pages = 0 one_to_n_results = [] - first_reimbursement_page = '1' + first_reimbursement_page = "1" for exhibit in exhibits: exhibit_pages = exhibit.exhibit_page_nums if exhibit_pages: - with concurrent.futures.ThreadPoolExecutor(max_workers=min(len(exhibit_pages), 20)) as executor: + with concurrent.futures.ThreadPoolExecutor( + max_workers=min(len(exhibit_pages), 20) + ) as executor: page_futures = { executor.submit( process_page_reimbursements, - exhibit, page_num, text_dict, exhibit_pages, constants, filename + exhibit, + page_num, + pages_dict, + text_dict, + exhibit_pages, + constants, + filename, ): page_num for page_num in exhibit_pages } @@ -272,10 +425,14 @@ def run_one_to_n_prompts(text_dict: dict[str, str], try: page_num = page_futures[future] reimbursement_rows, special_case_rows = future.result() - exhibit.add_reimbursement_rows(reimbursement_rows, special_case_rows) + exhibit.add_reimbursement_rows( + reimbursement_rows, special_case_rows + ) completed_pages += 1 if completed_pages % 20 == 0 or completed_pages == total_pages: - logging.debug(f"{datetime_str()} Page progress: {completed_pages}/{total_pages} - {filename}") + logging.debug( + f"{datetime_str()} Page progress: {completed_pages}/{total_pages} - {filename}" + ) except Exception as e: logging.error(f"Error processing page: {str(e)}") @@ -283,21 +440,31 @@ def run_one_to_n_prompts(text_dict: dict[str, str], continue # STEP 2: exhibit_level for this exhibit - exhibit_level_answers, dynamic_reimbursement_fields = one_to_n_funcs.exhibit_level( - exhibit.exhibit_text, - exhibit.exhibit_header, - exhibit.exhibit_page, - constants, - filename, + exhibit_level_answers, dynamic_reimbursement_fields = ( + one_to_n_funcs.exhibit_level( + exhibit.exhibit_text, + exhibit.exhibit_header, + exhibit.exhibit_page, + constants, + filename, + ) + ) + exhibit.set_exhibit_level_data( + exhibit_level_answers, dynamic_reimbursement_fields + ) + logging.debug( + f"Exhibit Level Answers for {filename}, Page {exhibit.exhibit_page}: {exhibit_level_answers}" ) - exhibit.set_exhibit_level_data(exhibit_level_answers, dynamic_reimbursement_fields) - logging.debug(f"Exhibit Level Answers for {filename}, Page {exhibit.exhibit_page}: {exhibit_level_answers}") # STEP 3: dynamic assignment & combine for this exhibit # Get dynamic fields from previous exhibit if needed (for future use) if exhibit.dynamic_reimbursement_fields: dynamic_fields = exhibit.dynamic_reimbursement_fields - elif exhibit.prev_exhibit and not exhibit.prev_exhibit.has_reimbursements and exhibit.get_previous_exhibit_dynamic_fields().fields: + elif ( + exhibit.prev_exhibit + and not exhibit.prev_exhibit.has_reimbursements + and exhibit.get_previous_exhibit_dynamic_fields().fields + ): dynamic_fields = exhibit.get_previous_exhibit_dynamic_fields() else: dynamic_fields = None @@ -309,10 +476,11 @@ def run_one_to_n_prompts(text_dict: dict[str, str], reimbursement_rows_with_dynamic = dynamic_funcs.dynamic_assignment( exhibit.reimbursement_rows, dynamic_fields, + pages_dict, text_dict, exhibit, constants, - filename + filename, ) # Combine reimbursement rows with exhibit-level answers @@ -321,7 +489,7 @@ def run_one_to_n_prompts(text_dict: dict[str, str], reimbursement_rows_with_dynamic, exhibit.special_case_rows, exhibit.exhibit_level_answers, - filename + filename, ) # Run cleaning @@ -333,17 +501,18 @@ def run_one_to_n_prompts(text_dict: dict[str, str], one_to_n_results.extend(combined_rows) # Track first reimbursement page - if first_reimbursement_page == '1' and exhibit.has_reimbursements: + if first_reimbursement_page == "1" and exhibit.has_reimbursements: first_reimbursement_page = exhibit.exhibit_page - logging.debug(f"{datetime_str()} STEP 3 COMPLETE: Combined {len(one_to_n_results)} total rows - {filename}") + logging.debug( + f"{datetime_str()} STEP 3 COMPLETE: Combined {len(one_to_n_results)} total rows - {filename}" + ) ################## Add N/A Dynamic or Exhibit to One-to-One ################## dynamic_one_to_one_fields = dynamic_funcs.get_dynamic_one_to_one_fields( one_to_n_results, constants ) - ################## CONVERT TO DF ################## one_to_n_df = pd.DataFrame(one_to_n_results) diff --git a/src/pipelines/saas/main.py b/src/pipelines/saas/main.py new file mode 100644 index 0000000..0344109 --- /dev/null +++ b/src/pipelines/saas/main.py @@ -0,0 +1,298 @@ +import concurrent.futures +import logging +import random +import time +import traceback +from datetime import datetime + +import pandas as pd + +random.seed(42) + +import src.pipelines.saas.file_processing as file_processing +import src.prompts.prompt_templates as prompt_templates +import src.utils.io_utils as io_utils +import src.utils.llm_utils as llm_utils +import src.utils.logging_utils as logging_utils +import src.utils.usage_tracking as usage_tracking +import src.utils.timing_utils as timing_utils +from src.constants.constants import Constants +from src import config +from src.parent_child import main as parent_child_main +from src.document_classification import main as dtc_main +from src.qc_qa.pipeline import ( + generate_statistics, + run_qc_qa_pipeline, + save_qc_qa_outputs, +) + + +def safe_process_file(item, constants, run_timestamp): + """Process a single file with comprehensive error handling. + + This function wraps the main file processing logic to ensure that: + - Individual file failures don't crash the entire batch + - Detailed error information is captured for debugging + + Args: + item: Tuple of (filename, contract_text) representing the file to process + constants: Constants object containing configuration and processing rules + run_timestamp: Timestamp string for output file naming and tracking + + Returns: + pd.DataFrame: Either: + - DataFrame with extracted field results (success case) + - Single-row DataFrame with error details (failure case) + + Note: + Always returns a DataFrame to maintain consistent output format for pd.concat. + With FAISS migration, no special resource cleanup is needed. + """ + file_id = ( + item[0] if isinstance(item, (list, tuple)) and len(item) > 0 else item + ) # unpack file_id from item (passed in as a tuple below) + try: + result = file_processing.process_file(item, constants, run_timestamp) + return result + except ( + Exception + ) as e: # When there's an issue with the processing inside the future + error_type = type(e).__name__ + error_message = str(e) + full_traceback = traceback.format_exc() + + logging.error(f"Error processing file {file_id}") + logging.error(f"Error type: {error_type}") + logging.error(f"Error Message: {error_message}") + + logging.error(f"Full traceback:\n{full_traceback}") + + return pd.DataFrame( + [ + { + "FILE_NAME": file_id, + "error": error_message.replace(",", ";").replace( + "\n", " " + ), # Replace problematic characters for CSV compatibility + "error_type": error_type, + "traceback": full_traceback.replace(",", ";").replace( + "\n", " | " + ), # keep line breaks as separators + } + ] + ) # Return a single-row dataframe so we can still concat it later + + +def main(testing=False, test_params={}): + # Set up per-file logging (creates separate log files for each document) + logging_utils.setup_per_file_logging() + + # Windows paths cannot contain ':'; use '-' in time component + run_timestamp = datetime.now().strftime(f"run_%Y%m%d_%H-%M_{config.BATCH_ID}") + + # Track overall pipeline time + pipeline_start = time.time() + + # Read Constants + with timing_utils.timed_block("read_constants", log_level="INFO"): + constants = Constants() + + # Read and process input + with timing_utils.timed_block("read_input", log_level="INFO"): + if not testing: + input_dict = io_utils.read_input() + max_workers = config.MAX_WORKERS + else: + input_dict = io_utils.read_input(test_params["local_input_dir"]) + max_workers = test_params["max_workers"] + if "input_files" in test_params: + input_dict = { + k: v + for k, v in input_dict.items() + if k in test_params["input_files"] + } + + logging.info(f"Total Input Files : {len(input_dict)}") + + # Run document type classification if enabled - DTC mode only, then exit + if config.PERFORM_DTC: + logging.info("=" * 80) + logging.info("DOCUMENT TYPE CLASSIFICATION MODE - Running DTC and exiting") + logging.info("=" * 80) + + # run DTC classification + dtc_main.main(input_dict, run_timestamp) + + logging.info( + "DTC classification complete. Exiting (investment pipeline not run)." + ) + logging.info("=" * 80) + return + + # Warm prompt caches before parallel processing + # This ensures the cache is registered before multiple threads try to use it + logging.info("Warming prompt caches before parallel processing...") + with timing_utils.timed_block("warm_prompt_caches", log_level="INFO"): + try: + cacheable_instructions = prompt_templates.get_cacheable_instructions() + for cache_key, instruction in cacheable_instructions.items(): + llm_utils.warm_prompt_cache( + instruction=instruction, + cache_key=cache_key, + model_id="sonnet_latest", + ) + logging.info( + f"Successfully warmed {len(cacheable_instructions)} prompt caches" + ) + except Exception as e: + logging.warning(f"Error warming caches (will proceed anyway): {str(e)}") + + # Process files concurrently - each thread gets its own per-file logging context + successful_results = [] + error_results = [] + + logging.info(f"Starting parallel file processing with {max_workers} workers...") + with timing_utils.timed_block("parallel_file_processing", log_level="INFO"): + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + # Each submitted task will set its own logging context in file_processing.process_file() + # We use an executor to process files concurrently; use submit() instead of map() + # so that we can catch exceptions and continue processing other files + futures = [ + executor.submit(safe_process_file, item, constants, run_timestamp) + for item in input_dict.items() + ] + + # collect results as they complete + completed_count = 0 + for future in concurrent.futures.as_completed(futures): + try: + results = future.result() + if "error" in results.columns: + error_results.append(results) + else: + successful_results.append(results) + + completed_count += 1 + if completed_count % 5 == 0: # Log progress every 5 files + logging.info( + f"Processed {completed_count}/{len(futures)} files..." + ) + except ( + Exception + ) as e: # When there's an issue with the future itself (not the processing inside the future) + logging.error(f"Error processing future: {str(e)}") + # Coerce this to the format expected by pd.concat (so a single-row dataframe) + error_results.append(pd.DataFrame([{"error": str(e)}])) + + # only concat if we have results + with timing_utils.timed_block("concat_results", log_level="INFO"): + if len(successful_results) > 0: + FINAL_RESULT_DF = pd.concat(successful_results, ignore_index=True) + else: + FINAL_RESULT_DF = pd.DataFrame() + + if len(error_results) > 0: + ERROR_RESULT_DF = pd.concat(error_results, ignore_index=True) + else: + ERROR_RESULT_DF = pd.DataFrame() + + # Run QC/QA validation if enabled (creates separate validated copy) + if config.ENABLE_QC_QA and not FINAL_RESULT_DF.empty: + logging.info("=" * 80) + logging.info("Running QC/QA Validation Pipeline...") + logging.info("=" * 80) + with timing_utils.timed_block("qc_qa_validation", log_level="INFO"): + try: + # Ensure unique index before QC/QA (safety check) + if FINAL_RESULT_DF.index.has_duplicates: + logging.warning( + "Detected duplicate indices in FINAL_RESULT_DF, resetting index..." + ) + FINAL_RESULT_DF = FINAL_RESULT_DF.reset_index(drop=True) + + # Create a copy for validation - preserve original FINAL_RESULT_DF + validated_df = run_qc_qa_pipeline(FINAL_RESULT_DF.copy(), stats_df=None) + logging.info("QC/QA validation completed successfully") + + # Generate validation statistics + logging.info("Generating QC/QA statistics...") + qc_qa_stats_df = generate_statistics(validated_df) + logging.info("QC/QA statistics generated successfully") + + # Save QC/QA outputs (local + S3) - separate from main results + save_qc_qa_outputs( + validated_df=validated_df, + stats_df=qc_qa_stats_df, + run_timestamp=run_timestamp, + write_to_s3=config.WRITE_TO_S3, + ) + except Exception as e: + logging.error(f"QC/QA validation failed: {str(e)}") + logging.error(f"Full traceback:\n{traceback.format_exc()}") + logging.warning("Continuing with original unvalidated results...") + logging.info("=" * 80) + + if not testing: + # Get usage tracking dataframes + per_file_usage_df, batch_summary_df = usage_tracking.get_usage_dataframes( + config.BATCH_ID, run_timestamp + ) + + with timing_utils.timed_block("write_outputs", log_level="INFO"): + if config.WRITE_TO_S3: + doczy_output_for_pc = io_utils.write_s3( + FINAL_RESULT_DF, "", run_timestamp, "final" + ) + if not ERROR_RESULT_DF.empty: + io_utils.write_s3(ERROR_RESULT_DF, "", run_timestamp, "error") + logging.warning( + f"{len(ERROR_RESULT_DF)} files failed processing - error results written to S3" + ) + + # Export usage and cost tracking data to S3 only if both dataframes have data + if not per_file_usage_df.empty and not batch_summary_df.empty: + logging.info("Exporting usage and cost tracking data to S3...") + io_utils.write_s3(per_file_usage_df, "", run_timestamp, "usage") + io_utils.write_s3( + batch_summary_df, "", run_timestamp, "usage_summary" + ) + else: + doczy_output_for_pc = io_utils.write_local( + FINAL_RESULT_DF, "", run_timestamp, "final" + ) + if not ERROR_RESULT_DF.empty: + io_utils.write_local(ERROR_RESULT_DF, "", run_timestamp, "error") + logging.warning( + f"{len(ERROR_RESULT_DF)} files failed processing - error results written locally" + ) + + if config.PERFORM_PARENT_CHILD_MAPPING: + if FINAL_RESULT_DF.empty: + logging.warning( + "Skipping Parent-Child mapping: No successful results to process (FINAL_RESULT_DF is empty)" + ) + else: + logging.info( + f"Starting Parent-Child mapping with {len(FINAL_RESULT_DF)} records from: {doczy_output_for_pc}" + ) + with timing_utils.timed_block("parent_child_mapping", log_level="INFO"): + parent_child_main.main(doczy_output_for_pc) + + # Export usage and cost tracking data locally only if both dataframes have data + if not per_file_usage_df.empty and not batch_summary_df.empty: + logging.info("Exporting usage and cost tracking data locally...") + io_utils.write_local(per_file_usage_df, "", run_timestamp, "usage") + io_utils.write_local(batch_summary_df, "", run_timestamp, "usage_summary") + + # Print timing summary + pipeline_duration = time.time() - pipeline_start + logging.info("=" * 80) + logging.info(f"PIPELINE COMPLETE - Total time: {pipeline_duration:.2f}s") + logging.info("=" * 80) + timing_utils.print_hierarchical_timing_summary() + else: + return FINAL_RESULT_DF, ERROR_RESULT_DF + + +if __name__ == "__main__": + main() diff --git a/src/pipelines/saas/prompts/__init__.py b/src/pipelines/saas/prompts/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/pipelines/saas/prompts/__init__.py @@ -0,0 +1 @@ + diff --git a/src/pipelines/saas/prompts/prompt_calls.py b/src/pipelines/saas/prompts/prompt_calls.py new file mode 100644 index 0000000..b4d80d4 --- /dev/null +++ b/src/pipelines/saas/prompts/prompt_calls.py @@ -0,0 +1,1134 @@ +import logging + +import src.config as config +import src.prompts.prompt_templates as prompt_templates +from src.constants.constants import Constants +from src.constants.delimiters import Delimiter +from src.prompts.fieldset import Field, FieldSet +from src.utils import llm_utils, string_utils +import json + + +def prompt_exhibit_level( + exhibit_text: str, + exhibit_level_fields: FieldSet, + constants: Constants, + filename: str, +): + logging.debug(f"Running exhibit Level Fields for {filename}:") + logging.debug(exhibit_level_fields.print_prompt_dict(constants)) + if not exhibit_level_fields.contains_fields(): + return {} + prompt = prompt_templates.EXHIBIT_LEVEL( + exhibit_text, exhibit_level_fields.print_prompt_dict(constants) + ) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + max_tokens=8192, + cache=True, + instruction=prompt_templates.EXHIBIT_LEVEL_INSTRUCTION(), + usage_label="EXHIBIT_LEVEL", + ) + logging.debug(f"LLM raw output for {filename}: {llm_answer_raw}") + + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + + return llm_answer_final + + +def prompt_exhibit_level_breakout( + exhibit_level_answers: dict[str, str], filename: str +) -> dict[str, str]: + """ + Process exhibit-level answers by breaking out facility adjustment terms using an LLM. + This function checks if a FACILITY_ADJUSTMENT_TERM exists in the exhibit-level answers, + and if present, invokes Claude LLM to break it down into structured components. The + resulting parsed data is then merged back into the exhibit-level answers dictionary. + Args: + exhibit_level_answers (dict[str, str]): A dictionary containing exhibit-level + field names as keys and their corresponding values as strings. Must contain + a "FACILITY_ADJUSTMENT_TERM" key to trigger processing. + filename (str): The name of the file being processed, used for logging and + tracking purposes in the LLM invocation. + Returns: + dict[str, str]: The updated exhibit_level_answers dictionary with additional + fields extracted from the FACILITY_ADJUSTMENT_TERM breakout, or the original + dictionary if no FACILITY_ADJUSTMENT_TERM was present. + Raises: + Any exceptions raised by llm_utils.invoke_claude() or string_utils.universal_json_load() + will propagate to the caller. + """ + + # FACILITY_ADJUSTMENT_BREAKOUT + if not string_utils.is_empty( + exhibit_level_answers.get("FACILITY_ADJUSTMENT_TERM", "") + ): + prompt = prompt_templates.FACILITY_ADJUSTMENT_BREAKOUT( + exhibit_level_answers["FACILITY_ADJUSTMENT_TERM"] + ) + llm_answer_raw = llm_utils.invoke_claude( + prompt=prompt, model_id="sonnet_latest", filename=filename + ) + print("Facility Adjustment: ", llm_answer_raw) + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + exhibit_level_answers.update(llm_answer_final) + + return exhibit_level_answers + + +def prompt_exhibit_lesser( + exhibit_text: str, + exhibit_level_answers: dict, + filename: str, +): + logging.debug(f"Running Exhibit-Level Lesser for {filename}:") + + prompt = prompt_templates.EXHIBIT_LEVEL_LESSER_OF(exhibit_text) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "legacy_sonnet", + filename, + max_tokens=8192, + cache=True, + instruction=prompt_templates.EXHIBIT_LEVEL_LESSER_OF_INSTRUCTION(), + usage_label="EXHIBIT_LEVEL_LESSER_OF", + ) + logging.debug(f"LLM raw output for {filename}: {llm_answer_raw}") + try: + exhibit_lesser_of_answer = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + except: + exhibit_lesser_of_answer = "N/A" + exhibit_level_answers["EXHIBIT_LESSER_OF_STATEMENT"] = exhibit_lesser_of_answer + return exhibit_level_answers + + +def prompt_dynamic_primary( + exhibit_text: str, field: Field, constants: Constants, filename: str, TEMPLATE +): + prompt = TEMPLATE(exhibit_text, field.field_name, field.get_prompt(constants)) + logging.debug(f"Dynamic primary prompt for {filename}; {field}: {prompt}") + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.DYNAMIC_PRIMARY_INSTRUCTION(), + ) + logging.debug(f"Claude answer for {filename}; {field}: {llm_answer_raw}") + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, string_utils.Delimiter.PIPE + ) + if "," in llm_answer_final: + llm_answer_final = "|".join( + [item.strip() for item in llm_answer_final.split(",")] + ) + return llm_answer_final + + +def prompt_reimbursement_primary( + page_text: str, + filename: str, +) -> list[dict[str, str]]: + + prompt = prompt_templates.REIMBURSEMENT_PRIMARY(page_text) + + logging.debug( + f"""Running reimbursement primary prompt for {filename} with prompt: {prompt}""" + ) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + max_tokens=25000, + cache=True, + instruction=prompt_templates.REIMBURSEMENT_PRIMARY_INSTRUCTION(), + usage_label="REIMBURSEMENT_PRIMARY", + ) + logging.debug(f"""LLM raw output for {filename}: {llm_answer_raw}""") + + # Check for the special "no results" case + if "NO_REIMBURSEMENT_TERMS_FOUND" in llm_answer_raw: + return [] # Return empty list if no reimbursement terms found + + try: + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + except ValueError as e: + logging.error(f"Error parsing LLM response: {e}") + logging.error(f"Raw LLM output: {llm_answer_raw}") + raise + return llm_answer_final + + +def prompt_methodology_breakout( + service_term: str, + reimb_term: str, + methodology_breakout_questions: FieldSet, + constants: Constants, + filename: str, +): + prompt = prompt_templates.METHODOLOGY_BREAKOUT( + service_term, + reimb_term, + methodology_breakout_questions.print_prompt_dict(constants), + ) + logging.debug(f"Methodology Breakout Prompt for {filename}: {prompt}") + llm_response = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.METHODOLOGY_BREAKOUT_INSTRUCTION(), + ) + logging.debug(f"LLM Response for {filename}: {llm_response}") + try: + methodology_breakout_answers = string_utils.universal_json_load(llm_response) + except ValueError as e: + logging.error(f"Error parsing LLM response: {e}") + methodology_breakout_answers = [] + return methodology_breakout_answers + + +def prompt_fee_schedule_breakout( + methodology_breakout_dict: dict, + reimbursement_method: str, + fs_breakout_questions: FieldSet, + constants: Constants, + filename: str, +): + prompt = prompt_templates.FEE_SCHEDULE_BREAKOUT( + reimbursement_method, + methodology_breakout_dict.get("FEE_SCHEDULE"), + fs_breakout_questions.print_prompt_dict(constants), + ) + logging.debug(f"Fee Schedule Breakout Prompt for {filename}: {prompt}") + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.FEE_SCHEDULE_BREAKOUT_INSTRUCTION(), + usage_label="FEE_SCHEDULE_BREAKOUT", + ) + logging.debug(f"LLM Response for {filename}: {llm_answer_raw}") + try: + fs_breakout_dict = string_utils.universal_json_load(llm_answer_raw) + except ValueError as e: + fs_breakout_dict = {} + return fs_breakout_dict + + +def prompt_grouper_breakout( + service: str, + reimbursement_method: str, + grouper_breakout_questions: FieldSet, + constants: Constants, + filename: str, +): + prompt = prompt_templates.GROUPER_BREAKOUT( + service, + reimbursement_method, + grouper_breakout_questions.print_prompt_dict(constants), + ) + logging.debug(f"Grouper Breakout Prompt for {filename}: {prompt}") + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.GROUPER_BREAKOUT_INSTRUCTION(), + usage_label="GROUPER_BREAKOUT", + ) + logging.debug(f"LLM Response for {filename}: {llm_answer_raw}") + try: + grouper_breakout_dict = string_utils.universal_json_load(llm_answer_raw) + except: + grouper_breakout_dict = {} + + return grouper_breakout_dict + + +def prompt_carveout_check( + service_term: str, + reimb_term: str, + carveout_definitions, + special_case_definitions, + filename: str, +): + carveout_prompt = prompt_templates.CARVEOUT_CHECK( + service_term, reimb_term, carveout_definitions, special_case_definitions + ) + logging.debug( + f"Running carveout check for {filename} with prompt:\n{carveout_prompt}" + ) + llm_answer_raw = llm_utils.invoke_claude( + carveout_prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.CARVEOUT_CHECK_INSTRUCTION(), + usage_label="CARVEOUT_CHECK", + ) + + carveout_answer = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + return carveout_answer + + +def prompt_special_case_breakout(breakout_template, term_answer, filename): + # Get the prompt from the template + prompt = breakout_template(term_answer) + + # Ensure prompt is a string for Bedrock messages API + if not isinstance(prompt, str): + logging.warning( + f"Expected prompt string, got {type(prompt)} in prompt_special_case_breakout; coercing to str." + ) + prompt = str(prompt) + + # Look for a corresponding _INSTRUCTION() function for caching + template_name = getattr(breakout_template, "__name__", "SPECIAL_CASE_BREAKOUT") + instruction_func_name = f"{template_name}_INSTRUCTION" + instruction_func = getattr(prompt_templates, instruction_func_name, None) + + if instruction_func and callable(instruction_func): + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=instruction_func(), + usage_label=template_name, + ) + else: + llm_answer_raw = llm_utils.invoke_claude( + prompt, "sonnet_latest", filename, usage_label="SPECIAL_CASE_BREAKOUT" + ) + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + return llm_answer_final + + +def prompt_lob_relationship( + answer_dict: dict, field: str, exhibit_text: str, filename: str +): + """ + Helper function to prompt LLM for LOB relationship based on the field and exhibit text. + """ + programs = answer_dict.get(field) + dynamic_primary_values = ( + f"LOB: {answer_dict.get("AARETE_DERIVED_LOB")}\nPROGRAM: {programs}" + ) + + prompt = prompt_templates.LOB_RELATIONSHIP(exhibit_text, dynamic_primary_values) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + model_id="sonnet_latest", + filename=filename, + cache=True, + instruction=prompt_templates.LOB_RELATIONSHIP_INSTRUCTION(), + ) + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + return llm_answer_final + + +def prompt_special_case_assignment( + exhibit_text: str, + reimbursement_dict: dict, + special_case_dicts: list, + special_case_term: str, + filename: str, +) -> dict[str, str]: + + # If all non-term values are identical across dictionaries, return first dict + non_term_keys = [k for k in special_case_dicts[0].keys() if "_TERM" not in k] + if all( + all(d[key] == special_case_dicts[0][key] for d in special_case_dicts[1:]) + for key in non_term_keys + ): + answer_dict = special_case_dicts[0].copy() + answer_dict[special_case_term] = "|".join( + [ + special_case_dict[special_case_term] + for special_case_dict in special_case_dicts + ] + ) + return answer_dict + + # Otherwise use LLM + llm_answer_raw = llm_utils.invoke_claude( + prompt_templates.SPECIAL_CASE_ASSIGNMENT( + exhibit_text, reimbursement_dict, special_case_dicts, special_case_term + ), + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.SPECIAL_CASE_ASSIGNMENT_INSTRUCTION(), + usage_label="SPECIAL_CASE_ASSIGNMENT", + ) + index_answer = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + try: + if not string_utils.is_empty(index_answer): + return special_case_dicts[int(index_answer)] + else: + return {} + except: + return special_case_dicts[0] + + +def prompt_full_context( + contract_text: str, + full_context_fields: FieldSet, + constants: Constants, + filename: str, +): + + prompt_questions = full_context_fields.print_prompt_dict(constants) + + full_context_prompt = prompt_templates.ONE_TO_ONE_MULTI_FIELD_TEMPLATE( + context=contract_text[ + 0 : min( + config.MAX_CONTEXT_LENGTH - len(prompt_questions), + len(contract_text) - 1, + ) + ], + questions=prompt_questions, + ) + try: + claude_answer_raw = llm_utils.invoke_claude( + full_context_prompt, + "sonnet_latest", + filename, + 8192, + cache=True, + instruction=prompt_templates.ONE_TO_ONE_MULTI_FIELD_INSTRUCTION(), + ) + full_context_answers_dict = string_utils.universal_json_load(claude_answer_raw) + except Exception as e: + logging.error(f"Error processing high accuracy fields: {str(e)}") + full_context_answers_dict = {} + for field in full_context_fields.list_fields(): + full_context_answers_dict[field] = f"Error: {str(e)}" + + return full_context_answers_dict + + +def is_exhibit_lesser_of_redundant( + reimb_term: str, exhibit_lesser_of: str, filename: str +) -> bool: + """Use LLM to determine if exhibit-level lesser-of statement is redundant with the reimbursement term. + + This is a second step of filtering, after checking for exact substring matches. + Small variations in punctuation may make it past the first filter, so in those cases + where it's determined NOT to contain the substring, we use LLM to check if the + semantic meaning is the same. + + Args: + reimb_term (str): The original reimbursement term. + exhibit_lesser_of (str): The exhibit-level lesser-of statement. + filename (str): The name of the file being processed, for logging. + + Returns: + bool: True if the exhibit-level lesser-of statement is redundant, False otherwise. + """ + + prompt = prompt_templates.CHECK_REDUNDANT_LESSER(reimb_term, exhibit_lesser_of) + + response = llm_utils.invoke_claude( + prompt, + "haiku_latest", + filename=filename, + cache=True, + instruction=prompt_templates.CHECK_REDUNDANT_LESSER_INSTRUCTION(), + ) + logging.debug(f"LLM response for redundancy check in {filename}: {response}") + return ( + string_utils.extract_text_from_delimiters(response, Delimiter.PIPE) + .strip() + .upper() + == "YES" + ) + + +def validate_reimbursements_for_llm(answer_dict: dict[str, str], filename: str) -> bool: + """Use LLM to determine if a service has actual reimbursement methodology. + + Args: + answer_dict (dict): The service-reimbursement answer dictionary. + filename (str): The name of the file being processed. + + Returns: + bool: True if the service has a clear reimbursement methodology, False otherwise. + """ + if isinstance(answer_dict, str): + answer_dict = {"SERVICE_TERM": "", "REIMB_TERM": answer_dict} + + if string_utils.is_empty( + answer_dict.get("SERVICE_TERM", None) + ) or string_utils.is_empty(answer_dict.get("REIMB_TERM", None)): + logging.warning( + f"Missing SERVICE_TERM or REIMB_TERM in {filename}: {answer_dict}" + ) + return False + + service_term, reimb_term = answer_dict["SERVICE_TERM"], answer_dict["REIMB_TERM"] + prompt = prompt_templates.VALIDATE_REIMBURSEMENTS_PROMPT(service_term, reimb_term) + logging.debug(f"Prompt for reimbursement validation in {filename}:\n{prompt}") + + llm_response = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.VALIDATE_REIMBURSEMENTS_INSTRUCTION(), + ) + logging.debug( + f"LLM response for reimbursement validation in {filename}:\n{llm_response}" + ) + final_answer = ( + string_utils.extract_text_from_delimiters(llm_response, Delimiter.PIPE) + .strip() + .upper() + ) + return final_answer == "YES" + + +def prompt_dynamic(text: str, field_prompts, filename): + """ + Prompts an LLM to process dynamic fields in a given text and extracts structured responses. + + Args: + text (str): The text to analyze and extract dynamic fields from. + field_prompts (dict): A dictionary mapping field names to prompts. + filename (str): The name of the file being processed. + + Returns: + dict: A dictionary containing field names as keys and extracted answers as values. + """ + prompt = prompt_templates.EXHIBIT_LEVEL(text, field_prompts) + logging.debug(f"Dynamic prompt for {filename}: {prompt}") + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.EXHIBIT_LEVEL_INSTRUCTION(), + ) # Returns dictionary of lists + logging.debug(f"Dynamic answer for {filename}: {llm_answer_raw}") + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + return llm_answer_final + + +def prompt_exhibit_linkage(page_header, previous_header, filename): + """Determine if current page header represents a different exhibit from the previous page. + + Uses LLM to compare page headers and determine if they indicate a transition to a + new exhibit section in the contract. + + Args: + page_header (str): Header text from the current page. + previous_header (str): Header text from the previous page. + filename (str): Source filename for logging and LLM attribution. + + Returns: + str: LLM response indicating if the exhibit has changed. + """ + prompt = prompt_templates.EXHIBIT_LINKAGE(page_header, previous_header) + claude_answer_raw = llm_utils.invoke_claude( + prompt, + "legacy_sonnet", + filename, + cache=True, + instruction=prompt_templates.EXHIBIT_LINKAGE_INSTRUCTION(), + usage_label="EXHIBIT_LINKAGE", + ) + exhibit_is_different = string_utils.extract_text_from_delimiters( + claude_answer_raw, Delimiter.PIPE + ) + return exhibit_is_different + + +def prompt_exhibit_header(page_content, EXHIBIT_HEADER_MARKERS, filename): + """Extract exhibit header identifier from page content using pattern matching. + + Uses LLM to identify exhibit headers in page content based on predefined markers + and extract the exhibit identifier. + + Args: + page_content (str): First 400 characters of page content to analyze. + EXHIBIT_HEADER_MARKERS (list): List of exhibit header pattern markers. + filename (str): Source filename for logging and LLM attribution. + + Returns: + str: Extracted exhibit header identifier or marker indicating no header found. + """ + prompt = prompt_templates.EXHIBIT_HEADER( + page_content[0:400], EXHIBIT_HEADER_MARKERS + ) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + max_tokens=300, + cache=True, + instruction=prompt_templates.EXHIBIT_HEADER_INSTRUCTION(), + usage_label="EXHIBIT_HEADER", + ) + llm_answer_extracted = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + return llm_answer_extracted + + +def prompt_smart_chunked( + answers_dict, new_field_groups, field_group, one_to_one_chunks, filename +): + """Extract field values from chunked contract text using appropriate prompt templates. + + Selects single-field or multi-field prompt templates based on the number of fields + in the group and processes the corresponding text chunk to extract structured answers. + + Args: + answers_dict (dict): Existing answers dictionary, mutated in place with new field values. + new_field_groups (dict): Field group definitions containing fields and their prompts. + field_group (str): Name of the field group to process. + one_to_one_chunks (dict): Text chunks mapped to field groups. + filename (str): Source filename for logging and LLM attribution. + + Returns: + dict: The mutated answers_dict with extracted field values or error messages. + """ + fields = new_field_groups[field_group].get("fields", []) + questions = {} + for field in fields: + questions[field.field_name] = field.prompt + + context = one_to_one_chunks[field_group] + context = context[0 : min(config.MAX_CONTEXT_LENGTH, len(context)) - 1] + + # prepare prompt + if len(fields) == 1: + question = questions[ + fields[0].field_name + ] # Take the one question for the single field included + prompt = prompt_templates.ONE_TO_ONE_SINGLE_FIELD_TEMPLATE(context, question) + elif len(fields) > 1: + prompt = prompt_templates.ONE_TO_ONE_MULTI_FIELD_TEMPLATE(context, questions) + else: + raise ValueError("Field group has no defined fields") + + try: + # Use appropriate instruction based on single vs multi-field + instruction = ( + prompt_templates.ONE_TO_ONE_SINGLE_FIELD_INSTRUCTION() + if len(fields) == 1 + else prompt_templates.ONE_TO_ONE_MULTI_FIELD_INSTRUCTION() + ) + field_group_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + 8192, + cache=True, + instruction=instruction, + usage_label="ONE_TO_ONE_CHUNKED", + ) + if len(fields) == 1: + field_group_answer_parsed = string_utils.extract_text_from_delimiters( + field_group_answer_raw, Delimiter.PIPE + ) + field_group_answer_dict = {fields[0].field_name: field_group_answer_parsed} + elif len(fields) > 1: + field_group_answer_dict = string_utils.json_parsing_search( + field_group_answer_raw, [field.field_name for field in fields] + ) + # Validate field names coming out of Claude: + expected_fields = {field.field_name for field in fields} + received_fields = set(field_group_answer_dict.keys()) + if expected_fields != received_fields: + missing = expected_fields - received_fields + extra = received_fields - expected_fields + raise ValueError(f"Field mismatch - Missing: {missing}, Extra: {extra}") + + # Load up answers dict + for field in fields: + field_answer = field_group_answer_dict[field.field_name] + answers_dict[field.field_name] = field_answer + + except Exception as e: + logging.error(f"Error processing field {field}: {type(e)}, {str(e)}") + for field in fields: + answers_dict[field.field_name] = f"Error: {str(e)}" + + return answers_dict + + +def prompt_date_fix(date: str) -> str: + """Processes dates using `prompt_templates.date_fix_prompt`. + + Args: + date (str): Input date string to be processed. + + Returns: + str: Processed date; either a date in YYYY/MM/DD format, a duration (e.g. "3 years"), or "N/A". + """ + if string_utils.is_empty(date): + return "N/A" + prompt = prompt_templates.DATE_FIX_PROMPT(date) + response = llm_utils.invoke_claude( + prompt, + "haiku_latest", + "date_fix", + cache=True, + instruction=prompt_templates.DATE_FIX_INSTRUCTION(), + usage_label="DATE_FIX", + ) + return string_utils.extract_text_from_delimiters(response, Delimiter.PIPE) + + +def prompt_derived_term_date( + effective_date: str = None, termination_information: str = None +) -> str: + """Calculate contract termination date from effective date and term duration using LLM. + + Uses LLM to parse term duration text and calculate the corresponding termination date + based on the provided effective date. + + Args: + effective_date (str): ISO-formatted effective date (YYYY-MM-DD) or date string. + termination_information (str): Term duration text (e.g., "3 years from effective date"). + + Returns: + str: ISO-formatted termination date (YYYY-MM-DD) or "N/A" if calculation fails. + """ + prompt = prompt_templates.DERIVED_TERM_DATE_PROMPT( + effective_date, termination_information + ) + response = llm_utils.invoke_claude( + prompt, + "haiku_latest", + "derive_term_date", + cache=True, + instruction=prompt_templates.DERIVED_TERM_DATE_INSTRUCTION(), + usage_label="DERIVED_TERM_DATE", + ) + return string_utils.extract_text_from_delimiters(response, Delimiter.PIPE) + + +def prompt_global_lesser_of_breakout( + global_lesser_of_stmt: str, constants: Constants, filename: str +) -> dict[str, str]: + """Parse global lesser-of statement into structured methodology fields using LLM breakout. + + This function reuses the same METHODOLOGY_BREAKOUT prompt template used for individual + service-level reimbursement terms to extract structured fields from contract-wide lesser-of + constraints. The extracted fields follow the same structure as methodology_breakout fields + defined in the field JSON. + + The function works by: + 1. Creating a mock service term "Global Lesser Of (all services)" to fit the breakout template + 2. Loading methodology_breakout fields from the field JSON configuration + 3. Invoking Claude with the METHODOLOGY_BREAKOUT prompt to parse the statement + 4. Adding "[GLOBAL LESSER OF]" prefix to REIMB_TERM for tracking/identification + 5. Returning the parsed fields or a minimal dict with just REIMB_TERM if parsing fails + + Args: + global_lesser_of_stmt (str): Global lesser-of statement extracted from contract. + Example: "At no time will reimbursement exceed 100% of billed charges" + constants (Constants): Configuration object containing valid codes and business rules + used during methodology breakout parsing + filename (str): Source filename (e.g., "contract_001.txt"). Used for: + - Logging context + - LLM request attribution + - Error tracking + + Returns: + dict[str, str]: Dictionary of methodology breakout fields extracted from the statement. + Always includes REIMB_TERM with "[GLOBAL LESSER OF]" prefix. Other fields depend on + what's defined as field_type="methodology_breakout" in the field JSON (e.g., + REIMB_PCT_RATE, REIMB_FEE_RATE, UNIT_OF_MEASURE, etc.) + + If parsing fails, returns: {"REIMB_TERM": "[GLOBAL LESSER OF] {original_statement}"} + + Side Effects: + - Makes LLM API call via llm_utils.invoke_claude() + - Logs debug information about prompt and response (via logging_utils context) + - Logs error if parsing fails but continues execution + + Notes: + - Uses the same METHODOLOGY_BREAKOUT template as one-to-n service-level terms + - The mock service term "Global Lesser Of (all services)" allows the global statement + to fit the [service, term] tuple expected by METHODOLOGY_BREAKOUT + - Parsing failures are non-fatal - returns minimal dict to allow processing to continue + - The "[GLOBAL LESSER OF]" prefix in REIMB_TERM distinguishes these from service-level terms + - This function is typically called from row_funcs.apply_global_lesser_of() which uses + the results to create duplicate rows via create_global_lesser_of_row() + - The specific methodology fields returned depend on the field_type="methodology_breakout" + definitions in the field JSON configuration + + Example: + >>> stmt = "At no time will reimbursement exceed 100% of billed charges" + >>> constants = Constants(...) + >>> result = run_global_lesser_of_breakout(stmt, constants, "contract.txt") + >>> result["REIMB_TERM"] + '[GLOBAL LESSER OF] At no time will reimbursement exceed 100% of billed charges' + >>> result["AARETE_DERIVED_REIMB_METHOD"] + 'billed charges' + >>> result["REIMB_PCT_RATE"] + '100' + >>> # Other fields depend on methodology_breakout field definitions in JSON + """ + + # Create a mock service term for the breakout + mock_service = "Global Lesser Of (all services)" + + prompt = prompt_templates.METHODOLOGY_BREAKOUT( + [mock_service, global_lesser_of_stmt], + FieldSet( + file_path=config.FIELD_JSON_PATH, field_type="methodology_breakout" + ).print_prompt_dict(constants), + ) + logging.debug( + f"Running global lesser of breakout for {filename} with prompt: {prompt}" + ) + + llm_response = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.METHODOLOGY_BREAKOUT_INSTRUCTION(), + usage_label="GLOBAL_LESSER_OF_BREAKOUT", + ) + + try: + breakout_results = string_utils.universal_json_load(llm_response) + result = breakout_results[0] if breakout_results else {} + + # Add the global lesser of statement as the REIMB_TERM + result["REIMB_TERM"] = f"[GLOBAL LESSER OF] {global_lesser_of_stmt}" + + return result + except: + logging.error( + f"Failed to parse global lesser of breakout response for {filename}. Response: {llm_response}" + ) + return {"REIMB_TERM": f"[GLOBAL LESSER OF] {global_lesser_of_stmt}"} + + +def prompt_dynamic_assignment( + service_term: str, + reimb_term: str, + dynamic_field: Field, + exhibit_text_simplified: str, + page_num: str, + constants: Constants, + filename: str, +): + + field_name = dynamic_field.field_name + field_prompt = dynamic_field.get_prompt(constants) + + # Use specialized prompt for REIMB_DATES assignment + if field_name == "REIMB_DATES": + prompt = prompt_templates.REIMB_DATES_ASSIGNMENT( + service_term, reimb_term, field_prompt, exhibit_text_simplified, page_num + ) + else: + # Use generic DYNAMIC_ASSIGNMENT for other fields + prompt = prompt_templates.DYNAMIC_ASSIGNMENT( + service_term, + reimb_term, + field_name, + field_prompt, + exhibit_text_simplified, + page_num, + ) + + llm_answer_raw = llm_utils.invoke_claude( + prompt, + model_id="sonnet_latest", + filename=filename, + cache=True, + instruction=prompt_templates.DYNAMIC_ASSIGNMENT_INSTRUCTION(), + usage_label="DYNAMIC_ASSIGNMENT", + ) + + try: + llm_answer_final = string_utils.universal_json_load(llm_answer_raw) + return llm_answer_final + except: + logging.error( + f"Failed to parse Dynamic Field: {field_name}. Response: {llm_answer_raw}" + ) + return {field_name: "Extraction Error"} + + +def prompt_lesser_of_distribution( + service_term: str, + reimb_term: str, + exhibit_text_simplified: str, + page_num: str, + cross_exhibit_lesser_of: list[dict], + filename: str, +) -> str: + """ + Apply lesser-of logic to a service and rate using hybrid approach. + + Combines: + 1. Cross-exhibit templates (GLOBAL and OTHER) from other exhibits (pre-provided) + 2. Intra-exhibit statements by searching the current exhibit text + + This approach avoids race conditions by: + - Storing only GLOBAL and cross-exhibit (OTHER) templates between exhibits + - Searching exhibit text for intra-exhibit statements (CURRENT) + - Exhibits process serially, so cross-exhibit templates are safe + + Args: + service_term: Service description + reimb_term: Original reimbursement term (rate without lesser-of) + exhibit_text_simplified: Simplified exhibit text to search for intra-exhibit statements + page_num: Current page number + cross_exhibit_lesser_of: List of GLOBAL and cross-exhibit lesser-of answer dicts. + Each dict contains: service_term, reimb_term, scope, + target_exhibit, exhibit_reference, page_num + filename: Filename for logging + + Returns: + str: Combined reimbursement term with lesser-of applied, or original term if no lesser-of applies + + Example: + >>> cross_exhibit = [{ + ... 'reimb_term': 'All services: lesser of rates or charges', + ... 'scope': 'GLOBAL', + ... 'page_num': '5' + ... }] + >>> result = prompt_lesser_of_distribution( + ... "Office Visit", "$150", exhibit_text, "10", cross_exhibit, "contract.pdf" + ... ) + >>> # Returns: "Office Visit paid at the lesser of $150 or charges" + """ + prompt = prompt_templates.LESSER_OF_DISTRIBUTION( + service_term, + reimb_term, + page_num, + exhibit_text_simplified, + cross_exhibit_lesser_of, # Pass list of cross-exhibit answer dicts + ) + + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.LESSER_OF_DISTRIBUTION_INSTRUCTION(), + usage_label="LESSER_OF_DISTRIBUTION", + ) + + # Check if LLM determined no lesser-of applies + if "N/A" in llm_answer_raw: + logging.debug( + f"No lesser-of constraints apply to '{service_term}' on page {page_num}" + ) + return reimb_term # Return original term unchanged + else: + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + + logging.debug( + f"Applied lesser-of to '{service_term}' on page {page_num}: " + f"{reimb_term} → {llm_answer_final[:60]}..." + ) + + return llm_answer_final + + +def prompt_lesser_of_check( + service_term: str, reimb_term: str, exhibit_title: str, filename: str +) -> dict: + """ + Classify a lesser-of statement into GLOBAL, EXHIBIT_SPECIFIC, or STANDALONE. + + Args: + service_term: Service description + reimb_term: Reimbursement term containing lesser-of language + exhibit_title: Current exhibit's title/header + filename: Filename for logging + + Returns: + dict: Classification result with keys: + - service_term: str + - reimb_term: str + - scope: "GLOBAL" | "EXHIBIT_SPECIFIC" | "STANDALONE" + - target_exhibit: "ALL" | "CURRENT" | "OTHER" | None + - exhibit_reference: str | None (exhibit name if target is OTHER) + """ + # DEBUG: Log what we're sending + logging.info( + f"LESSER_OF_CHECK input: service='{service_term[:50]}...', reimb_term='{reimb_term[:100]}...'" + ) + + prompt = prompt_templates.LESSER_OF_CHECK(service_term, reimb_term, exhibit_title) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.LESSER_OF_CHECK_INSTRUCTION(), + usage_label="LESSER_OF_CHECK", + ) + + try: + # Extract JSON from pipes + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + + logging.debug(f"LESSER_OF_CHECK extracted from pipes: {llm_answer_final}") + + # Parse JSON + lesser_of_answer_dict = json.loads(llm_answer_final) + + # Validate required fields + required_fields = [ + "service_term", + "reimb_term", + "scope", + "target_exhibit", + "exhibit_reference", + ] + for field in required_fields: + if field not in lesser_of_answer_dict: + logging.warning( + f"LESSER_OF_CHECK missing field '{field}' for service '{service_term}', " + f"exhibit '{exhibit_title}', defaulting to STANDALONE" + ) + return { + "service_term": service_term, + "reimb_term": reimb_term, + "scope": "STANDALONE", + "target_exhibit": None, + "exhibit_reference": None, + } + + logging.info( + f"LESSER_OF_CHECK classification: scope={lesser_of_answer_dict['scope']}, " + f"target={lesser_of_answer_dict['target_exhibit']}, " + f"exhibit_ref={lesser_of_answer_dict.get('exhibit_reference')}, " + f"service='{service_term}...', exhibit='{exhibit_title}'" + ) + + return lesser_of_answer_dict + + except json.JSONDecodeError as e: + logging.error( + f"Failed to parse LESSER_OF_CHECK JSON for service '{service_term}', " + f"exhibit '{exhibit_title}': {e}. Raw response: {llm_answer_final[:200]}... " + f"Defaulting to STANDALONE" + ) + return { + "service_term": service_term, + "reimb_term": reimb_term, + "scope": "STANDALONE", + "target_exhibit": None, + "exhibit_reference": None, + } + except Exception as e: + logging.error( + f"Error in prompt_lesser_of_check for service '{service_term}', " + f"exhibit '{exhibit_title}': {e}. Defaulting to STANDALONE" + ) + return { + "service_term": service_term, + "reimb_term": reimb_term, + "scope": "STANDALONE", + "target_exhibit": None, + "exhibit_reference": None, + } + + +def prompt_exhibit_title_match( + current_exhibit_title: str, target_exhibit_reference: str, filename: str = "" +) -> str: + prompt = prompt_templates.EXHIBIT_TITLE_MATCH( + current_exhibit_title, target_exhibit_reference + ) + llm_answer_raw = llm_utils.invoke_claude( + prompt, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.EXHIBIT_TITLE_MATCH_INSTRUCTION(), + usage_label="EXHIBIT_TITLE_MATCH", + ) + + try: + llm_answer_final = string_utils.extract_text_from_delimiters( + llm_answer_raw, Delimiter.PIPE + ) + return llm_answer_final.strip().upper() # Return "YES" or "NO" as string + except: + return "NO" # Default to "NO" string + + +def provider_name_match_check( + provider_name: str, hybrid_smart_chunking_provider_group_name: str, filename: str +) -> bool: + """Check if the provider name from npi/tin page match provider group name""" + if string_utils.is_empty(provider_name) or string_utils.is_empty( + hybrid_smart_chunking_provider_group_name + ): + return False + + if hybrid_smart_chunking_provider_group_name == "N/A": + return False + + # Create prompt for LLM + CHECK_PROVIDER_NAME_MATCH_PROMPT = prompt_templates.CHECK_PROVIDER_NAME_MATCH_PROMPT( + provider_name=provider_name, + hybrid_smart_chunking_provider_group_name=hybrid_smart_chunking_provider_group_name, + ) + + try: + # Adjust this based on your LLM client + response = llm_utils.invoke_claude( + CHECK_PROVIDER_NAME_MATCH_PROMPT, + "sonnet_latest", + filename, + cache=True, + instruction=prompt_templates.CHECK_PROVIDER_NAME_MATCH_INSTRUCTION(), + usage_label="CHECK_PROVIDER_NAME_MATCH", + ) + + # Extract last character (should be Y or N) + response = string_utils.extract_text_from_delimiters(response, Delimiter.PIPE) + + if response == "Y": + logging.debug( + f"[is_provider_name_match_llm] ✓ LLM matched: '{provider_name}' ≈ '{hybrid_smart_chunking_provider_group_name}'" + ) + return True + elif response == "N": + logging.debug( + f"[is_provider_name_match_llm] ✗ LLM no match: '{provider_name}' ≠ '{hybrid_smart_chunking_provider_group_name}'" + ) + return False + else: + logging.warning( + f"[is_provider_name_match_llm] Unexpected response: {response}, defaulting to False" + ) + return False + + except Exception as e: + logging.error( + f"[is_provider_name_match_llm] Error calling LLM: {e}, defaulting to False" + ) + return False diff --git a/src/pipelines/shared/__init__.py b/src/pipelines/shared/__init__.py new file mode 100644 index 0000000..921751f --- /dev/null +++ b/src/pipelines/shared/__init__.py @@ -0,0 +1,20 @@ +# Re-export extraction modules +from src.pipelines.shared.extraction import dynamic_funcs +from src.pipelines.shared.extraction import exhibit_funcs +from src.pipelines.shared.extraction import one_to_n_funcs +from src.pipelines.shared.extraction import one_to_one_funcs +from src.pipelines.shared.extraction import page_funcs +from src.pipelines.shared.extraction import row_funcs +from src.pipelines.shared.extraction import tin_npi_funcs +from src.pipelines.shared.extraction import vision_funcs + +# Re-export preprocessing modules +from src.pipelines.shared.preprocessing import hybrid_smart_chunking_funcs +from src.pipelines.shared.preprocessing import hybrid_smart_chunking_preprocessing +from src.pipelines.shared.preprocessing import preprocess +from src.pipelines.shared.preprocessing import preprocessing_funcs + +# Re-export postprocessing modules +from src.pipelines.shared.postprocessing import aarete_derived +from src.pipelines.shared.postprocessing import postprocess +from src.pipelines.shared.postprocessing import postprocessing_funcs diff --git a/src/pipelines/shared/extraction/__init__.py b/src/pipelines/shared/extraction/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/pipelines/shared/extraction/__init__.py @@ -0,0 +1 @@ + diff --git a/fieldExtraction/src/investment/dynamic_funcs.py b/src/pipelines/shared/extraction/dynamic_funcs.py similarity index 80% rename from fieldExtraction/src/investment/dynamic_funcs.py rename to src/pipelines/shared/extraction/dynamic_funcs.py index 9d6fb51..e204c7e 100644 --- a/fieldExtraction/src/investment/dynamic_funcs.py +++ b/src/pipelines/shared/extraction/dynamic_funcs.py @@ -1,13 +1,18 @@ import logging import concurrent.futures +from typing import TYPE_CHECKING, Optional -from src.investment import prompt_calls, preprocessing_funcs +from src.pipelines.saas.prompts import prompt_calls +from src.pipelines.shared.preprocessing import preprocessing_funcs from src.utils import string_utils -from constants.constants import Constants +from src.constants.constants import Constants from src import config from src.prompts import prompt_templates from src.prompts.fieldset import Field, FieldSet -from src.investment.exhibit_funcs import Exhibit +from src.pipelines.shared.extraction.exhibit_funcs import Exhibit + +if TYPE_CHECKING: + from src.pipelines.shared.extraction.page_funcs import Page def dynamic_primary( @@ -36,7 +41,7 @@ def dynamic_primary( dynamic_reimbursement_fields = FieldSet() exhibit_level_answer_dict = {} - + for field in dynamic_primary_fields.fields: exhibit_text_answer = prompt_calls.prompt_dynamic_primary( exhibit_text, @@ -141,16 +146,31 @@ def dynamic( return exhibit_level_answers, dynamic_reimbursement_fields -def dynamic_assignment(reimbursement_primary_answers: list[dict[str, str]], - dynamic_reimbursement_fields: FieldSet, - text_dict: dict[str, str], - exhibit: Exhibit, - constants: Constants, - filename: str - ) -> list[dict[str, str]]: +def dynamic_assignment( + reimbursement_primary_answers: list[dict[str, str]], + dynamic_reimbursement_fields: FieldSet, + pages_dict: Optional[dict[str, "Page"]] = None, + text_dict: Optional[dict[str, str]] = None, + exhibit: Optional[Exhibit] = None, + constants: Optional[Constants] = None, + filename: Optional[str] = None, +) -> list[dict[str, str]]: """ Enrich reimbursement rows with dynamic fields in parallel. + + Args: + reimbursement_primary_answers: List of reimbursement answer dictionaries + dynamic_reimbursement_fields: FieldSet of dynamic fields to assign + pages_dict: Dictionary mapping page numbers to Page objects (preferred) + text_dict: Dictionary mapping page numbers to text strings (for backward compatibility) + exhibit: Exhibit object (preferred - uses exhibit.pages) + constants: Constants object + filename: Name of the file being processed """ + # Check for exhibit first (required parameter) + if exhibit is None: + raise ValueError("exhibit must be provided") + if not reimbursement_primary_answers or not dynamic_reimbursement_fields.fields: return reimbursement_primary_answers @@ -159,13 +179,22 @@ def dynamic_assignment(reimbursement_primary_answers: list[dict[str, str]], updated = answer_dict.copy() page_num = updated["REIMB_PAGE"] exhibit_text_simplified = preprocessing_funcs.simplify_exhibit( - text_dict, exhibit.exhibit_page_nums, page_num + pages_dict=pages_dict, + text_dict=text_dict, + exhibit=exhibit, + current_page_num=page_num, ) - service_term = updated['SERVICE_TERM'] - reimb_term = updated['REIMB_TERM'] + service_term = updated["SERVICE_TERM"] + reimb_term = updated["REIMB_TERM"] for dynamic_field in dynamic_reimbursement_fields.fields: dynamic_field_answer = prompt_calls.prompt_dynamic_assignment( - service_term, reimb_term, dynamic_field, exhibit_text_simplified, page_num, constants, filename + service_term, + reimb_term, + dynamic_field, + exhibit_text_simplified, + page_num, + constants, + filename, ) updated.update(dynamic_field_answer) return updated @@ -175,7 +204,9 @@ def dynamic_assignment(reimbursement_primary_answers: list[dict[str, str]], return list(executor.map(_assign_single, reimbursement_primary_answers)) -def add_one_to_one_field(one_to_one_fields, field_to_add, answer_dicts, constants: Constants): +def add_one_to_one_field( + one_to_one_fields, field_to_add, answer_dicts, constants: Constants +): field_to_add.field_type = "smart_chunked" field_to_add.relationship = "one_to_one" @@ -185,9 +216,7 @@ def add_one_to_one_field(one_to_one_fields, field_to_add, answer_dicts, constant # NOTE: Check raw LOB field, not AARETE_DERIVED_LOB, because AARETE_DERIVED_LOB # is populated later via crosswalk and may be derived from PROGRAM/PRODUCT if field_to_add.field_name in ["PROGRAM", "PRODUCT", "NETWORK"]: - lob_values = [ - answer_dict.get("LOB", "") for answer_dict in answer_dicts - ] + lob_values = [answer_dict.get("LOB", "") for answer_dict in answer_dicts] unique_lobs = set([lob for lob in lob_values if not string_utils.is_empty(lob)]) if len(unique_lobs) > 0: return one_to_one_fields @@ -210,7 +239,9 @@ def add_one_to_one_field(one_to_one_fields, field_to_add, answer_dicts, constant return one_to_one_fields -def get_dynamic_one_to_one_fields(answer_dicts: list[dict[str, str]], constants: Constants): +def get_dynamic_one_to_one_fields( + answer_dicts: list[dict[str, str]], constants: Constants +): """ Returns a FieldSet object of dynamic fields that have are empty for at least one dict in answer_dicts """ @@ -225,9 +256,7 @@ def get_dynamic_one_to_one_fields(answer_dicts: list[dict[str, str]], constants: # Only search for PROGRAM, PRODUCT, NETWORK when NO LOB has been found # NOTE: Check raw LOB field, not AARETE_DERIVED_LOB, because AARETE_DERIVED_LOB # is populated later via crosswalk and may be derived from PROGRAM/PRODUCT - lob_values = [ - answer_dict.get("LOB", "") for answer_dict in answer_dicts - ] + lob_values = [answer_dict.get("LOB", "") for answer_dict in answer_dicts] unique_lobs = set([lob for lob in lob_values if not string_utils.is_empty(lob)]) has_lob = len(unique_lobs) > 0 @@ -236,28 +265,26 @@ def get_dynamic_one_to_one_fields(answer_dicts: list[dict[str, str]], constants: field_name = field.field_name if "REIMB" in field_name: # Don't do this for the REIMB_ fields continue - + empty_count = sum( - 1 for answer_dict in answer_dicts + 1 + for answer_dict in answer_dicts if string_utils.is_empty(answer_dict.get(field_name)) ) total_count = len(answer_dicts) - + if empty_count == total_count: # Skip PROGRAM, PRODUCT, NETWORK if any LOB has been found # Only search for these fields when NO LOB has been found if has_lob and field_name in ["PROGRAM", "PRODUCT", "NETWORK"]: continue - + field_to_add = Field.load_from_file( file_path=config.FIELD_JSON_PATH, - field_name=field.base_field if field.base_field else field.field_name - ) # Try base_field first, fall back to field_name if base_field is None/empty + field_name=field.base_field if field.base_field else field.field_name, + ) # Try base_field first, fall back to field_name if base_field is None/empty one_to_one_fields = add_one_to_one_field( one_to_one_fields, field_to_add, answer_dicts, constants ) - + return one_to_one_fields - - - diff --git a/src/pipelines/shared/extraction/exhibit_funcs.py b/src/pipelines/shared/extraction/exhibit_funcs.py new file mode 100644 index 0000000..24a95c0 --- /dev/null +++ b/src/pipelines/shared/extraction/exhibit_funcs.py @@ -0,0 +1,455 @@ +""" +Exhibit class for tracking exhibit state during one-to-n processing. + +This module provides the Exhibit class which maintains all state and field values +for a single exhibit during field extraction, including a linked list structure +for propagating dynamic fields from exhibit n-1 to exhibit n. +""" + +from typing import TYPE_CHECKING, Optional + +from src.prompts.fieldset import FieldSet + +if TYPE_CHECKING: + from src.pipelines.shared.extraction.page_funcs import Page + +from src.pipelines.saas.prompts import prompt_calls +import logging + + +class Exhibit: + """ + Tracks all state and field values for a single exhibit during processing. + + Maintains a linked list structure via prev_exhibit to enable field propagation + from exhibit n-1 to exhibit n during dynamic assignment. + + Attributes: + exhibit_page (str): The page number where this exhibit starts + exhibit_page_nums (list[str]): All page numbers that belong to this exhibit + (includes sub-pages like "27.1", "27.2" for split tables) + exhibit_header (str): The header text of the exhibit + exhibit_text (str): The full text content of the exhibit (computed from pages) + pages (dict[str, Page]): Dictionary mapping page identifiers to Page objects + num_pages (int): Number of pages in this exhibit + prev_exhibit (Optional[Exhibit]): Pointer to the previous exhibit (n-1) + dynamic_primary_fields (FieldSet): Dynamic primary fields from exhibit_level + dynamic_reimbursement_fields (FieldSet): Dynamic reimbursement fields from exhibit_level + exhibit_level_answers (dict): Exhibit-level field answers + reimbursement_rows (list[dict]): Reimbursement rows from page processing + special_case_rows (list[dict]): Special case rows from page processing + has_reimbursements (bool): Whether this exhibit has any reimbursements + final_rows (list[dict]): Final combined and cleaned rows + lesser_of_answers (list[dict]): Lesser-of results from LESSER_OF_CHECK + """ + + def __init__( + self, + exhibit_page: str, + exhibit_page_nums: list[str], + exhibit_header: str, + pages: Optional[dict[str, "Page"]] = None, + exhibit_text: Optional[str] = None, + prev_exhibit: Optional["Exhibit"] = None, + ): + """ + Initialize a new Exhibit instance. + + Args: + exhibit_page: The starting page number for this exhibit + exhibit_page_nums: List of all page/sub-page identifiers in this exhibit + exhibit_header: The header text of the exhibit + pages: Dictionary mapping page identifiers to Page objects (preferred) + exhibit_text: The full text content of the exhibit (for backward compatibility) + prev_exhibit: Optional pointer to the previous exhibit for field propagation + + Note: + If `pages` is provided, `exhibit_text` will be computed from pages. + If only `exhibit_text` is provided (backward compatibility), pages will be None. + """ + # Basic exhibit metadata + self.exhibit_page = exhibit_page + self.exhibit_page_nums = exhibit_page_nums + self.exhibit_header = exhibit_header + self._pages = pages + self._exhibit_text = exhibit_text + self.num_pages = len(exhibit_page_nums) + + # Linked list for exhibit chain + self.prev_exhibit = prev_exhibit + + # Field tracking (populated in Step 2) + self.dynamic_primary_fields = FieldSet() + self.dynamic_reimbursement_fields = FieldSet() + self.exhibit_level_answers = {} + + # Reimbursement data (populated in Step 1) + self.reimbursement_rows = [] + self.special_case_rows = [] + self.has_reimbursements = False + + # Final combined rows (populated in Step 3) + self.final_rows = [] + + # NEW: Lesser-of answer tracking + self.lesser_of_answers = [] # List[dict] - answer dicts from LESSER_OF_CHECK + + @property + def pages(self) -> Optional[dict[str, "Page"]]: + """ + Get the pages dictionary. + + Returns: + Dictionary mapping page identifiers to Page objects, or None if not set + """ + return self._pages + + @property + def exhibit_text(self) -> str: + """ + Get the full exhibit text. + + Computed from pages if available, otherwise returns stored exhibit_text. + This property provides backward compatibility. + + Returns: + Full text content of the exhibit + """ + if self._pages is not None: + # Compute from pages + text_parts = [] + for page_id in self.exhibit_page_nums: + # Handle sub-pages: "27.1" means get sub-page "1" from page "27" + if "." in page_id and not page_id.startswith("."): + base_page, sub_page = page_id.rsplit(".", 1) + if base_page in self._pages: + page_text = self._pages[base_page].get_text(sub_page) + text_parts.append(page_text) + elif page_id in self._pages: + page_text = self._pages[page_id].get_text() + text_parts.append(page_text) + return "\n".join(text_parts) + elif self._exhibit_text is not None: + return self._exhibit_text + else: + return "" + + def get_page_text(self, page_id: str) -> str: + """ + Get text for a specific page or sub-page. + + Args: + page_id: Page identifier (e.g., "27" or "27.1" for sub-page) + + Returns: + Text content for the specified page/sub-page + """ + if self._pages is not None: + # Handle sub-pages: "27.1" means get sub-page "1" from page "27" + if "." in page_id and not page_id.startswith("."): + base_page, sub_page = page_id.rsplit(".", 1) + if base_page in self._pages: + return self._pages[base_page].get_text(sub_page) + elif page_id in self._pages: + return self._pages[page_id].get_text() + return "" + else: + # Backward compatibility: return empty string if pages not available + return "" + + def get_all_page_nums(self) -> list[str]: + """ + Get all page/sub-page identifiers for this exhibit. + + Returns: + List of all page identifiers (includes sub-pages for split tables) + """ + if self._pages is not None: + # Collect all identifiers from pages (including sub-pages) + all_identifiers = [] + for page_id in self.exhibit_page_nums: + if page_id in self._pages: + page = self._pages[page_id] + if page.is_split: + # Add all sub-page identifiers + all_identifiers.extend(page.get_all_page_identifiers()) + else: + # Add the base page identifier + all_identifiers.append(page_id) + return all_identifiers if all_identifiers else self.exhibit_page_nums + else: + return self.exhibit_page_nums + + def add_reimbursement_rows( + self, reimbursement_rows: list[dict], special_case_rows: list[dict] + ): + """ + Add reimbursement rows from page processing. + + This is called during Step 1 (parallel page processing) to accumulate + reimbursement and special case rows from all pages in this exhibit. + + Args: + reimbursement_rows: List of reimbursement dictionaries from a page + special_case_rows: List of special case dictionaries from a page + """ + self.reimbursement_rows.extend(reimbursement_rows) + self.special_case_rows.extend(special_case_rows) + self.has_reimbursements = ( + len(reimbursement_rows) > 0 or len(special_case_rows) > 0 + ) + + def set_exhibit_level_data( + self, exhibit_level_answers: dict, dynamic_reimbursement_fields: FieldSet + ): + """ + Set exhibit-level field data from exhibit_level processing. + + This is called during Step 2 (exhibit-level processing) to store the + exhibit-level answers and dynamic fields that will be used in Step 3. + + Args: + exhibit_level_answers: Dictionary of exhibit-level field answers + dynamic_reimbursement_fields: FieldSet of dynamic reimbursement fields + """ + self.exhibit_level_answers = exhibit_level_answers + self.dynamic_reimbursement_fields = dynamic_reimbursement_fields + + # Extract dynamic primary fields from exhibit level answers + # These are the fields that can be propagated to next exhibit + self.dynamic_primary_fields = dynamic_reimbursement_fields + + def get_previous_exhibit_dynamic_fields(self) -> FieldSet: + """ + Get dynamic primary fields from previous exhibit (n-1) if available. + + This enables field propagation across exhibits, allowing exhibit n to + inherit dynamic fields from exhibit n-1 when appropriate. + + Returns: + FieldSet: The previous exhibit's dynamic primary fields, or an empty + FieldSet if there is no previous exhibit + """ + if self.prev_exhibit is not None: + return self.prev_exhibit.dynamic_primary_fields + return FieldSet() + + def add_lesser_of_statement(self, lesser_of_answer_dict: dict): + """Store a lesser-of classification result.""" + self.lesser_of_answers.append(lesser_of_answer_dict) + + def get_cross_exhibit_lesser_of(self) -> list[dict]: + """ + Get GLOBAL and cross-exhibit lesser-of templates that apply to THIS exhibit. + + This method retrieves lesser-of statements from other exhibits that should be + applied to the current exhibit. It does NOT include intra-exhibit statements + (EXHIBIT_SPECIFIC with target=CURRENT) as those are found via text search to + avoid race conditions during parallel page processing. + + Walks backward through the exhibit chain to find: + - GLOBAL statements: Apply to all exhibits in the contract + - EXHIBIT_SPECIFIC (OTHER): Cross-exhibit references that target this exhibit + + Does NOT return: + - EXHIBIT_SPECIFIC (CURRENT): Handled via exhibit_text_simplified search + - STANDALONE: Complete rates, not templates + + Returns: + list[dict]: List of lesser-of answer dicts that apply to this exhibit. + Each dict contains keys: service_term, reimb_term, scope, + target_exhibit, exhibit_reference, page_num + + Example: + # Exhibit A (page 10): "All services: lesser of rates or charges" [GLOBAL] + # Exhibit A (page 15): "For Exhibit B: not to exceed Medicare" [OTHER] + # Exhibit B calls get_cross_exhibit_lesser_of(): + # Returns: [GLOBAL from A, OTHER from A targeting B] + """ + global_statements = [] + cross_exhibit_statements = [] + + # Walk backward through exhibit chain (don't include self, start from previous) + current = self.prev_exhibit + + while current is not None: + if not current.lesser_of_answers: + current = current.prev_exhibit + continue + + logging.debug( + f"get_cross_exhibit_lesser_of: Checking {len(current.lesser_of_answers)} " + f"statement(s) from exhibit '{current.exhibit_header}' (page {current.exhibit_page})" + ) + + for lesser_of_answer_dict in current.lesser_of_answers: + scope = lesser_of_answer_dict["scope"] + target = lesser_of_answer_dict.get("target_exhibit") + exhibit_ref = lesser_of_answer_dict.get("exhibit_reference") + page_num = lesser_of_answer_dict.get("page_num") + + # GLOBAL: applies to entire contract (all exhibits) + if scope == "GLOBAL": + global_statements.append(lesser_of_answer_dict) + logging.debug( + f" ✓ GLOBAL statement from page {page_num} applies to " + f"exhibit '{self.exhibit_header}': " + f"{lesser_of_answer_dict['reimb_term'][:60]}..." + ) + + # EXHIBIT_SPECIFIC (OTHER): cross-exhibit reference + elif scope == "EXHIBIT_SPECIFIC" and target == "OTHER": + # Check if this cross-exhibit reference targets THIS exhibit + if self._title_matches(exhibit_ref): + cross_exhibit_statements.append(lesser_of_answer_dict) + logging.debug( + f" ✓ CROSS-EXHIBIT statement from page {page_num} applies " + f"(target '{exhibit_ref}' matches '{self.exhibit_header}'): " + f"{lesser_of_answer_dict['reimb_term'][:60]}..." + ) + else: + logging.debug( + f" ✗ CROSS-EXHIBIT statement from page {page_num} skipped " + f"(target '{exhibit_ref}' does NOT match '{self.exhibit_header}')" + ) + + current = current.prev_exhibit + + # Combine: GLOBAL statements first (higher priority), then cross-exhibit + all_applicable = global_statements + cross_exhibit_statements + + if all_applicable: + logging.info( + f"Exhibit '{self.exhibit_header}': Found {len(global_statements)} GLOBAL " + f"and {len(cross_exhibit_statements)} cross-exhibit lesser-of statement(s)" + ) + else: + logging.debug( + f"Exhibit '{self.exhibit_header}': No cross-exhibit lesser-of statements found" + ) + + return all_applicable + + def _title_matches(self, target_ref: str) -> bool: + """Check if this exhibit's title matches the target reference using LLM.""" + if not target_ref: + return False + + try: + match_result = prompt_calls.prompt_exhibit_title_match( + self.exhibit_header, target_ref, "" # filename + ) + + logging.debug( + f"_title_matches: Got result type={type(match_result)}, value={match_result}" + ) + + if isinstance(match_result, bool): + return match_result + elif isinstance(match_result, str): + return match_result.strip().upper() == "YES" + else: + logging.warning( + f"_title_matches: Unexpected type {type(match_result)}, defaulting to False" + ) + return False + except Exception as e: + logging.error( + f"Error in _title_matches: {e}, exhibit_header={self.exhibit_header}, target_ref={target_ref}" + ) + return ( + False # ✅ Default to False on error (don't match if can't determine) + ) + + def __repr__(self): + """String representation for debugging.""" + return ( + f"Exhibit(page={self.exhibit_page}, pages={len(self.exhibit_page_nums)}, " + f"has_reimb={self.has_reimbursements}, reimb_count={len(self.reimbursement_rows)})" + ) + + +def get_exhibit_list( + pages_dict: Optional[dict[str, "Page"]] = None, + text_dict: Optional[dict[str, str]] = None, + exhibit_chunk_mapping: Optional[dict[str, list[str]]] = None, + all_exhibit_headers: Optional[dict[str, str]] = None, +) -> list[Exhibit]: + """ + Create a list of Exhibit objects from pages or text dictionary. + + This function supports both the new Page-based approach and the legacy + text_dict approach for backward compatibility. + + Args: + pages_dict: Dictionary mapping page numbers to Page objects (preferred) + text_dict: Dictionary mapping page numbers to text strings (backward compatibility) + exhibit_chunk_mapping: Dictionary mapping exhibit pages to lists of page numbers + all_exhibit_headers: Dictionary mapping exhibit pages to their headers + + Returns: + List of Exhibit objects + + Note: + Either pages_dict or text_dict must be provided. If both are provided, + pages_dict takes precedence. + """ + if exhibit_chunk_mapping is None: + exhibit_chunk_mapping = {} + if all_exhibit_headers is None: + all_exhibit_headers = {} + + exhibits = [] + prev_exhibit = None + + for exhibit_page, exhibit_page_nums in exhibit_chunk_mapping.items(): + exhibit_header = all_exhibit_headers.get(exhibit_page, "") + + if pages_dict is not None: + # New approach: use Page objects + # Collect all page identifiers including sub-pages + all_page_identifiers = [] + exhibit_pages_dict = {} + + for page_num in exhibit_page_nums: + if page_num in pages_dict: + page = pages_dict[page_num] + exhibit_pages_dict[page_num] = page + + # If page is split, add sub-page identifiers + if page.is_split: + sub_page_ids = page.get_all_page_identifiers() + all_page_identifiers.extend(sub_page_ids) + else: + all_page_identifiers.append(page_num) + + # If no sub-pages were found, use original page_nums + if not all_page_identifiers: + all_page_identifiers = exhibit_page_nums + + exhibit = Exhibit( + exhibit_page=exhibit_page, + exhibit_page_nums=all_page_identifiers, + exhibit_header=exhibit_header, + pages=exhibit_pages_dict, + prev_exhibit=prev_exhibit, + ) + elif text_dict is not None: + # Backward compatibility: use text_dict + exhibit_text = "\n".join( + [text_dict[page_num] for page_num in exhibit_page_nums] + ) + exhibit = Exhibit( + exhibit_page=exhibit_page, + exhibit_page_nums=exhibit_page_nums, + exhibit_header=exhibit_header, + exhibit_text=exhibit_text, + prev_exhibit=prev_exhibit, + ) + else: + raise ValueError("Either pages_dict or text_dict must be provided") + + exhibits.append(exhibit) + prev_exhibit = exhibit + + return exhibits diff --git a/fieldExtraction/src/investment/one_to_n_funcs.py b/src/pipelines/shared/extraction/one_to_n_funcs.py similarity index 78% rename from fieldExtraction/src/investment/one_to_n_funcs.py rename to src/pipelines/shared/extraction/one_to_n_funcs.py index 1704bbd..c5db04a 100644 --- a/fieldExtraction/src/investment/one_to_n_funcs.py +++ b/src/pipelines/shared/extraction/one_to_n_funcs.py @@ -1,12 +1,15 @@ import concurrent.futures import logging -from src.investment import dynamic_funcs, prompt_calls, aarete_derived, postprocessing_funcs +from src.pipelines.shared.extraction import dynamic_funcs +from src.pipelines.saas.prompts import prompt_calls +from src.pipelines.shared.postprocessing import aarete_derived, postprocessing_funcs from src.utils import llm_utils, string_utils import src.prompts.prompt_templates as prompt_templates -from constants.constants import Constants +from src.constants.constants import Constants from src import config from src.prompts.fieldset import FieldSet +from src.pipelines.shared.extraction.exhibit_funcs import Exhibit def exhibit_level( @@ -29,18 +32,14 @@ def exhibit_level( dict: All Exhibit-Level answers FieldSet: Updated reimbursement_level_fields with any dynamically added fields """ - exhibit_level_fields = FieldSet( - config.FIELD_JSON_PATH, field_type="exhibit_level" - ) + exhibit_level_fields = FieldSet(config.FIELD_JSON_PATH, field_type="exhibit_level") dynamic_primary_fields = FieldSet( config.FIELD_JSON_PATH, field_type="dynamic_primary" ) dynamic_reimb_info_fields = FieldSet( config.FIELD_JSON_PATH, field_type="dynamic_reimb_info" ) - dynamic_code_fields = FieldSet( - config.FIELD_JSON_PATH, field_type="dynamic_code" - ) + dynamic_code_fields = FieldSet(config.FIELD_JSON_PATH, field_type="dynamic_code") # True Exhibit Level - these apply to the entire Exhibit exhibit_level_answers = prompt_calls.prompt_exhibit_level( @@ -51,14 +50,9 @@ def exhibit_level( exhibit_level_answers, filename ) - # Dynamic Primary exhibit_level_answers, dynamic_reimbursement_fields = dynamic_funcs.dynamic_primary( - exhibit_text, - exhibit_level_answers, - constants, - filename, - dynamic_primary_fields + exhibit_text, exhibit_level_answers, constants, filename, dynamic_primary_fields ) # Dynamic Codes @@ -69,7 +63,7 @@ def exhibit_level( constants, filename, dynamic_code_fields, - dynamic_reimbursement_fields + dynamic_reimbursement_fields, ) # Dynamic Reimb Info @@ -80,7 +74,7 @@ def exhibit_level( constants, filename, dynamic_reimb_info_fields, - dynamic_reimbursement_fields + dynamic_reimbursement_fields, ) # add exhibit identifiers @@ -91,11 +85,9 @@ def exhibit_level( def reimbursement_level( - page_text: str, - constants: Constants, - filename: str + page_text: str, constants: Constants, filename: str ) -> list[dict[str, str]]: - + # Reimbursement Primary reimbursement_primary_answers = prompt_calls.prompt_reimbursement_primary( page_text, filename @@ -105,7 +97,7 @@ def reimbursement_level( reimbursement_primary_answers = clean_reimbursement_primary( reimbursement_primary_answers, constants, filename ) - + return reimbursement_primary_answers @@ -148,7 +140,7 @@ def breakout( reimbursement_level_answers: list[dict[str, str]], special_case_answers: list[dict[str, str]], filename: str, - constants: Constants + constants: Constants, ) -> tuple[list[dict[str, str]], list[dict[str, str]]]: """ Performs breakout processing on reimbursement primary answers and special case primary answers. @@ -166,31 +158,43 @@ def breakout( ) # Including base methodology breakout, grouper, and fee schedule # Special Case Breakout - special_case_answers = special_case_breakout( - special_case_answers, filename - ) + special_case_answers = special_case_breakout(special_case_answers, filename) return reimbursement_level_answers, special_case_answers -def process_single_carveout(answer_dict, carveout_definitions, special_case_definitions, filename): +def process_single_carveout( + answer_dict, carveout_definitions, special_case_definitions, filename +): """Process a single carveout/special case in parallel""" - service_term, reimb_term = answer_dict.get("SERVICE_TERM"), answer_dict.get("REIMB_TERM") + service_term, reimb_term = answer_dict.get("SERVICE_TERM"), answer_dict.get( + "REIMB_TERM" + ) reimbursement_categorization = prompt_calls.prompt_carveout_check( - service_term, reimb_term, carveout_definitions, special_case_definitions, filename + service_term, + reimb_term, + carveout_definitions, + special_case_definitions, + filename, ) if reimbursement_categorization in carveout_definitions.keys(): answer_dict["CARVEOUT_CD"] = reimbursement_categorization # Standard N/A OR Base response gets CARVEOUT_IND=N - if reimbursement_categorization in ["N/A", "BASE_COVERED_SERVICES", "DEFAULT_TERM"]: + if reimbursement_categorization in [ + "N/A", + "BASE_COVERED_SERVICES", + "DEFAULT_TERM", + ]: answer_dict["CARVEOUT_IND"] = "N" else: answer_dict["CARVEOUT_IND"] = "Y" # Determine DEFAULT_IND based on specific carveout_answer values answer_dict["DEFAULT_IND"] = ( - "Y" if reimbursement_categorization in ["DEFAULT_TERM", "UNLISTED_CODE"] else "N" + "Y" + if reimbursement_categorization in ["DEFAULT_TERM", "UNLISTED_CODE"] + else "N" ) # Carveout breakouts @@ -229,15 +233,25 @@ def carveout_and_special_case( list[dict]: The updated reimbursement breakout answers with carveout details. """ carveout_definitions = constants.VALID_CARVEOUTS - special_case_definitions = FieldSet(config.FIELD_JSON_PATH, field_type="special_case_check").get_prompt_dict(constants) + special_case_definitions = FieldSet( + config.FIELD_JSON_PATH, field_type="special_case_check" + ).get_prompt_dict(constants) reimbursement_level_answers, special_case_answers = [], [] # Parallelize carveout processing if reimbursement_breakout_answers: - with concurrent.futures.ThreadPoolExecutor(max_workers=min(len(reimbursement_breakout_answers), 5)) as executor: + with concurrent.futures.ThreadPoolExecutor( + max_workers=min(len(reimbursement_breakout_answers), 5) + ) as executor: futures = [ - executor.submit(process_single_carveout, answer_dict.copy(), carveout_definitions, special_case_definitions, filename) + executor.submit( + process_single_carveout, + answer_dict.copy(), + carveout_definitions, + special_case_definitions, + filename, + ) for answer_dict in reimbursement_breakout_answers ] @@ -276,9 +290,13 @@ def methodology_breakout( # Parallelize methodology breakout processing if reimbursement_primary_answers: - with concurrent.futures.ThreadPoolExecutor(max_workers=min(len(reimbursement_primary_answers), 5)) as executor: + with concurrent.futures.ThreadPoolExecutor( + max_workers=min(len(reimbursement_primary_answers), 5) + ) as executor: futures = [ - executor.submit(methodology_breakout_single_row, answer_dict, constants, filename) + executor.submit( + methodology_breakout_single_row, answer_dict, constants, filename + ) for answer_dict in reimbursement_primary_answers ] @@ -309,7 +327,9 @@ def methodology_breakout_single_row( list[dict]: Updated list with methodology breakout details and fee schedule information. """ - reimb_term, service_term = answer_dict.get("REIMB_TERM"), answer_dict.get("SERVICE_TERM") + reimb_term, service_term = answer_dict.get("REIMB_TERM"), answer_dict.get( + "SERVICE_TERM" + ) methodology_breakout_questions = FieldSet( config.FIELD_JSON_PATH, field_type="methodology_breakout" ) @@ -323,7 +343,8 @@ def methodology_breakout_single_row( # Methodology Breakout: AARETE_DERIVED_REIMB_METHOD, REIMB_FEE_RATE, REIMB_PCT_RATE, LESSER_OF_IND, GREATER_OF_IND, AARETE_DERIVED_PROV_TYPE if reimb_term: methodology_breakout_answers = prompt_calls.prompt_methodology_breakout( - service_term, reimb_term, + service_term, + reimb_term, methodology_breakout_questions, constants, filename, @@ -439,7 +460,16 @@ def methodology_breakout_secondary( def process_single_special_case_breakout(answer_dict, special_case_fields, filename): """Process a single special case breakout in parallel""" - term_field_name = [field_name for field_name in answer_dict.keys() if "_TERM" in field_name and field_name not in ["SERVICE_TERM","REIMB_TERM",]][0] + term_field_name = [ + field_name + for field_name in answer_dict.keys() + if "_TERM" in field_name + and field_name + not in [ + "SERVICE_TERM", + "REIMB_TERM", + ] + ][0] term_answer = answer_dict[term_field_name] term_field = special_case_fields.get_field(term_field_name) breakout_template = term_field.get_breakout_template() @@ -478,14 +508,23 @@ def special_case_breakout( if not special_case_answers: return special_case_answers - special_case_fields = FieldSet(config.FIELD_JSON_PATH, field_type="special_case_check") + special_case_fields = FieldSet( + config.FIELD_JSON_PATH, field_type="special_case_check" + ) # Parallelize special case breakout processing updated_answers = [] if special_case_answers: - with concurrent.futures.ThreadPoolExecutor(max_workers=min(len(special_case_answers), 5)) as executor: + with concurrent.futures.ThreadPoolExecutor( + max_workers=min(len(special_case_answers), 5) + ) as executor: futures = [ - executor.submit(process_single_special_case_breakout, answer_dict.copy(), special_case_fields, filename) + executor.submit( + process_single_special_case_breakout, + answer_dict.copy(), + special_case_fields, + filename, + ) for answer_dict in special_case_answers ] @@ -539,7 +578,9 @@ def filter_services_without_reimbursements( # Parallelize validation if reimbursement_primary_answers: - with concurrent.futures.ThreadPoolExecutor(max_workers=min(len(reimbursement_primary_answers), 5)) as executor: + with concurrent.futures.ThreadPoolExecutor( + max_workers=min(len(reimbursement_primary_answers), 5) + ) as executor: # Create futures with index tracking future_to_index = { executor.submit(validate_single_reimbursement, answer_dict, filename): i @@ -570,7 +611,6 @@ def filter_services_without_reimbursements( return valid_reimbursements - def split_reimb_dates(one_to_n_results: list, filename: str) -> list: """Splits REIMB_DATES field into separate effective and termination date fields. @@ -711,9 +751,16 @@ def get_lob_relationship(answer_dicts, exhibit_text, filename): # Parallelize LOB relationship processing updated_dicts = [] if answer_dicts: - with concurrent.futures.ThreadPoolExecutor(max_workers=min(len(answer_dicts), 5)) as executor: + with concurrent.futures.ThreadPoolExecutor( + max_workers=min(len(answer_dicts), 5) + ) as executor: futures = [ - executor.submit(process_single_lob_relationship, answer_dict.copy(), exhibit_text, filename) + executor.submit( + process_single_lob_relationship, + answer_dict.copy(), + exhibit_text, + filename, + ) for answer_dict in answer_dicts ] @@ -725,17 +772,16 @@ def get_lob_relationship(answer_dicts, exhibit_text, filename): return updated_dicts -def one_to_n_cleaning(all_exhibit_rows: list[dict], exhibit_text: str, constants: Constants, filename: str): + +def one_to_n_cleaning( + all_exhibit_rows: list[dict], exhibit_text: str, constants: Constants, filename: str +): ################################ Crosswalk Fields ################################ - all_exhibit_rows = aarete_derived.get_crosswalk_fields( - all_exhibit_rows, constants - ) + all_exhibit_rows = aarete_derived.get_crosswalk_fields(all_exhibit_rows, constants) ################################ Determine LOB Relationship ################################ - all_exhibit_rows = get_lob_relationship( - all_exhibit_rows, exhibit_text, filename - ) + all_exhibit_rows = get_lob_relationship(all_exhibit_rows, exhibit_text, filename) ################################ Fill NA Mapping ################################ all_exhibit_rows = aarete_derived.fill_na_mapping(all_exhibit_rows) @@ -749,18 +795,117 @@ def one_to_n_cleaning(all_exhibit_rows: list[dict], exhibit_text: str, constants return all_exhibit_rows -def lesser_of_distribution(reimbursement_level_answers: list[dict[str, str]], exhibit_text_simplified: str, page_num: str, constants: Constants, filename: str) -> list[dict[str, str]]: +def lesser_of_distribution( + reimbursement_level_answers: list[dict[str, str]], + exhibit_text_simplified: str, + page_num: str, + constants: Constants, + filename: str, + exhibit: Exhibit, +) -> list[dict[str, str]]: + """ + Process lesser-of statements withcross-exhibit support. + + Hybrid approach: + - Intra-exhibit (GLOBAL, CURRENT): Search exhibit_text_simplified to avoid race conditions + - Cross-exhibit (OTHER): Store templates in exhibit.lesser_of_answers for cross-exhibit use + + For statements containing "less" or "not to exceed": + - Classify them using LESSER_OF_CHECK + - Store GLOBAL and EXHIBIT_SPECIFIC (OTHER) templates for cross-exhibit use + - Keep STANDALONE statements in final results + - Keep EXHIBIT_SPECIFIC (CURRENT) in final results (handled via text search) + + For statements without "less": + - Retrieve GLOBAL and cross-exhibit templates from other exhibits + - Search current exhibit text for intra-exhibit statements + - Apply all applicable lesser-of constraints + + Args: + reimbursement_level_answers: List of reimbursement dicts from page + exhibit_text_simplified: Simplified exhibit text for searching intra-exhibit statements + page_num: Current page number + constants: Constants object + filename: Filename for logging + exhibit: Exhibit object for storing/retrieving cross-exhibit lesser-of statements + + Returns: + List of reimbursement dicts with lesser-of statements applied + """ final_reimbursement_level_answers = [] + for answer_dict in reimbursement_level_answers: - service_term, original_reimb_term = answer_dict['SERVICE_TERM'], answer_dict["REIMB_TERM"] - if "less" in original_reimb_term.lower(): - is_overarching_lesser = prompt_calls.prompt_lesser_of_check(service_term, original_reimb_term, filename) - if not is_overarching_lesser: + service_term = answer_dict["SERVICE_TERM"] + original_reimb_term = answer_dict["REIMB_TERM"] + + # Branch A: Statement contains "less" or "not to exceed" - classify and handle + if ( + "less" in original_reimb_term.lower() + or "not to exceed" in original_reimb_term.lower() + ): + + # Get full JSON classification + lesser_of_answer_dict = prompt_calls.prompt_lesser_of_check( + service_term, original_reimb_term, exhibit.exhibit_header, filename + ) + + # Add page number to the classification + lesser_of_answer_dict["page_num"] = page_num + + scope = lesser_of_answer_dict["scope"] + target = lesser_of_answer_dict.get("target_exhibit") + exhibit_ref = lesser_of_answer_dict.get("exhibit_reference") + + # Store GLOBAL and cross-exhibit templates for use by other exhibits + if scope == "GLOBAL": + exhibit.add_lesser_of_statement(lesser_of_answer_dict) + logging.info(f"Stored GLOBAL lesser-of template from page {page_num}") final_reimbursement_level_answers.append(answer_dict) + + # EXHIBIT_SPECIFIC (OTHER): Store but exclude from results + elif scope == "EXHIBIT_SPECIFIC" and target == "OTHER": + exhibit.add_lesser_of_statement(lesser_of_answer_dict) + logging.info( + f"Stored cross-exhibit template from page {page_num}" + ) # Still excluded (not a rate) + + # STANDALONE: Complete rate with both options present + # EXHIBIT_SPECIFIC (CURRENT): Applies to current exhibit (found via text search) + # Both should be kept in final results + else: + logging.debug( + f"Keeping {scope} lesser-of statement on page {page_num}: " + f"{original_reimb_term[:60]}..." + ) + final_reimbursement_level_answers.append(answer_dict) + + # Branch B: Statement doesn't contain "less" - apply lesser-of if applicable else: - new_reimb_term = prompt_calls.prompt_lesser_of_distribution(answer_dict['SERVICE_TERM'], original_reimb_term, exhibit_text_simplified, page_num, filename) - answer_dict["REIMB_TERM"] = new_reimb_term + + # Step 1: Get GLOBAL and cross-exhibit templates from other exhibits + cross_exhibit_lesser_of = exhibit.get_cross_exhibit_lesser_of() + + # Step 2: Apply lesser-of (searches current exhibit text + uses cross-exhibit templates) + new_reimb_term = prompt_calls.prompt_lesser_of_distribution( + service_term, + original_reimb_term, + exhibit_text_simplified, # Search for intra-exhibit statements + page_num, + cross_exhibit_lesser_of, # Pass GLOBAL and cross-exhibit templates + filename, + ) + + # Update the term if changed + if new_reimb_term != original_reimb_term: + answer_dict["REIMB_TERM"] = new_reimb_term + logging.debug( + f"Applied lesser-of to '{service_term}': " + f"{original_reimb_term} → {new_reimb_term[:50]}..." + ) + + # Add to final results (with or without lesser-of applied) final_reimbursement_level_answers.append(answer_dict) + return final_reimbursement_level_answers @@ -772,23 +917,23 @@ def check_and_combine_exhibit_inheritance( ) -> tuple[bool, list[str], FieldSet]: """ Check if inheritance should happen and combine exhibits if needed. - + Conditions for inheritance: 1. Previous exhibit exists 2. Current exhibit's dynamic_reimbursement_fields is empty FieldSet 3. Previous exhibit's dynamic_reimbursement_fields is NOT empty 4. Previous exhibit had NO reimbursement rows - + When inheritance happens: - Replace current dynamic_reimbursement_fields with previous exhibit's dynamic_reimbursement_fields - Combine exhibit_page_nums (previous + current) to provide context through simplify_exhibit - + Args: previous_exhibit: Dict with keys: 'exhibit_page_nums', 'dynamic_reimbursement_fields', 'had_reimbursements' current_exhibit_page_nums: List of page numbers for current exhibit current_exhibit_text: Full text of current exhibit (not used in return, but kept for consistency) current_dynamic_fields: FieldSet of dynamic fields found in current exhibit - + Returns: Tuple of: - should_inherit: bool indicating if inheritance happened @@ -798,40 +943,44 @@ def check_and_combine_exhibit_inheritance( # Check if previous exhibit exists if previous_exhibit is None: return False, current_exhibit_page_nums, current_dynamic_fields - + # Check if current exhibit's dynamic_reimbursement_fields is empty current_field_names = current_dynamic_fields.list_fields() current_is_empty = len(current_field_names) == 0 - + if not current_is_empty: return False, current_exhibit_page_nums, current_dynamic_fields - + # Check if previous exhibit's dynamic_reimbursement_fields is NOT empty - prev_dynamic_fields = previous_exhibit['dynamic_reimbursement_fields'] + prev_dynamic_fields = previous_exhibit["dynamic_reimbursement_fields"] prev_field_names = prev_dynamic_fields.list_fields() prev_is_not_empty = len(prev_field_names) > 0 - + if not prev_is_not_empty: return False, current_exhibit_page_nums, current_dynamic_fields - + # Check if previous exhibit had NO reimbursement rows - prev_no_reimbursements = not previous_exhibit.get('had_reimbursements', True) - + prev_no_reimbursements = not previous_exhibit.get("had_reimbursements", True) + if not prev_no_reimbursements: return False, current_exhibit_page_nums, current_dynamic_fields - + # All conditions met - inheritance should happen # Combine exhibit_page_nums (previous + current) # This ensures simplify_exhibit will include context from both exhibits - combined_page_nums = previous_exhibit['exhibit_page_nums'] + current_exhibit_page_nums - + combined_page_nums = ( + previous_exhibit["exhibit_page_nums"] + current_exhibit_page_nums + ) + # Replace current dynamic_reimbursement_fields with previous exhibit's updated_dynamic_fields = prev_dynamic_fields - + # Minimal logging: inheritance activated, pages being merged, and fields inherited - prev_pages = ', '.join(previous_exhibit.get('exhibit_page_nums', [])) - current_pages = ', '.join(current_exhibit_page_nums) - fields_str = ', '.join(prev_field_names) - logging.debug(f"Exhibit inheritance activated: merging pages {prev_pages} → {current_pages}, inheriting fields: {fields_str}") - + prev_pages = ", ".join(previous_exhibit.get("exhibit_page_nums", [])) + current_pages = ", ".join(current_exhibit_page_nums) + fields_str = ", ".join(prev_field_names) + logging.debug( + f"Exhibit inheritance activated: merging pages {prev_pages} → {current_pages}, inheriting fields: {fields_str}" + ) + return True, combined_page_nums, updated_dynamic_fields diff --git a/fieldExtraction/src/investment/one_to_one_funcs.py b/src/pipelines/shared/extraction/one_to_one_funcs.py similarity index 91% rename from fieldExtraction/src/investment/one_to_one_funcs.py rename to src/pipelines/shared/extraction/one_to_one_funcs.py index 6d08004..a0d3555 100644 --- a/fieldExtraction/src/investment/one_to_one_funcs.py +++ b/src/pipelines/shared/extraction/one_to_one_funcs.py @@ -4,19 +4,22 @@ import re import json import pandas as pd -import src.investment.postprocessing_funcs as postprocessing_funcs -import src.investment.prompt_calls as prompt_calls +import src.pipelines.shared.postprocessing.postprocessing_funcs as postprocessing_funcs +import src.pipelines.saas.prompts.prompt_calls as prompt_calls import src.prompts.prompt_templates as prompt_templates import src.utils.llm_utils as llm_utils import src.utils.string_utils as string_utils -from constants.constants import Constants -from constants.delimiters import Delimiter +from src.constants.constants import Constants +from src.constants.delimiters import Delimiter from src import config -from src.investment import postprocessing_funcs -from src.investment.vision_funcs import get_image_array_based_answer +from src.pipelines.shared.postprocessing import postprocessing_funcs +from src.pipelines.shared.extraction.vision_funcs import get_image_array_based_answer from src.prompts.fieldset import Field, FieldSet -def extract_global_lesser_of(text_dict: str, first_reimbursement_page: str, filename: str) -> dict: + +def extract_global_lesser_of( + text_dict: str, first_reimbursement_page: str, filename: str +) -> dict: """Extract global "lesser of" statements that apply contract-wide. Args: @@ -31,7 +34,13 @@ def extract_global_lesser_of(text_dict: str, first_reimbursement_page: str, file file_path=config.FIELD_JSON_PATH, field_name="GLOBAL_LESSER_OF_STATEMENT" ) - context = "\n".join([page_text for page_num, page_text in text_dict.items() if int(page_num) < int(first_reimbursement_page)]) + context = "\n".join( + [ + page_text + for page_num, page_text in text_dict.items() + if int(page_num) < int(first_reimbursement_page) + ] + ) # Process using existing full context logic prompt = prompt_templates.ONE_TO_ONE_SINGLE_FIELD_TEMPLATE( @@ -60,6 +69,7 @@ def extract_global_lesser_of(text_dict: str, first_reimbursement_page: str, file or "N/A" } + def pass_smart_chunked_to_full_context(answers_dict, one_to_one_fields): # even after running the vision api, if the effective date is still N/A, we need to run the prompt again with full context if "EFFECTIVE_DT" in answers_dict and string_utils.is_empty( @@ -83,6 +93,7 @@ def pass_smart_chunked_to_full_context(answers_dict, one_to_one_fields): ) return one_to_one_fields + def check_and_update_effective_date(answers_dict, text_dict, filename): """Apply two-stage postprocessing to effective date with optional vision-based fallback. @@ -139,10 +150,8 @@ def check_and_update_effective_date(answers_dict, text_dict, filename): """ # Postprocess the effective date - answers_dict["AARETE_DERIVED_EFFECTIVE_DT"] = ( - prompt_calls.prompt_date_fix( - answers_dict.get("EFFECTIVE_DT", "N/A") - ) + answers_dict["AARETE_DERIVED_EFFECTIVE_DT"] = prompt_calls.prompt_date_fix( + answers_dict.get("EFFECTIVE_DT", "N/A") ) answers_dict["AARETE_DERIVED_EFFECTIVE_DT"] = ( postprocessing_funcs.validate_and_reformat_date( @@ -250,16 +259,35 @@ def run_full_context_fields( ) if "PROV_GROUP_NAME_FULL" in full_context_answers_dict: - full_context_answers_dict["PROV_INFO_JSON"] = json.dumps([{"TIN": "UNKNOWN", "NPI": "UNKNOWN", "NAME": full_context_answers_dict["PROV_GROUP_NAME_FULL"]}]) - full_context_answers_dict["PROV_INFO_JSON_FORMATTED"] = json.dumps([{"TIN": "UNKNOWN", "NPI": "UNKNOWN", "NAME": full_context_answers_dict["PROV_GROUP_NAME_FULL"]}]) + full_context_answers_dict["PROV_INFO_JSON"] = json.dumps( + [ + { + "TIN": "UNKNOWN", + "NPI": "UNKNOWN", + "NAME": full_context_answers_dict["PROV_GROUP_NAME_FULL"], + } + ] + ) + full_context_answers_dict["PROV_INFO_JSON_FORMATTED"] = json.dumps( + [ + { + "TIN": "UNKNOWN", + "NPI": "UNKNOWN", + "NAME": full_context_answers_dict["PROV_GROUP_NAME_FULL"], + } + ] + ) # Normalize PAYER_STATE to two-letter abbreviation if "PAYER_STATE" in full_context_answers_dict: - full_context_answers_dict["PAYER_STATE"] = string_utils.normalize_state_to_abbreviation( - full_context_answers_dict["PAYER_STATE"] + full_context_answers_dict["PAYER_STATE"] = ( + string_utils.normalize_state_to_abbreviation( + full_context_answers_dict["PAYER_STATE"] + ) ) full_context_answers_dict = string_utils.normalize_state_field( - full_context_answers_dict, field_name="PAYER_STATE") + full_context_answers_dict, field_name="PAYER_STATE" + ) # normalize PROVIDER_STATE to two-letter abbreviation if "PROVIDER_STATE" in full_context_answers_dict: @@ -275,7 +303,9 @@ def run_full_context_fields( for field in separate_fields.fields: if field.field_name == "GLOBAL_LESSER_OF_STATEMENT": # Add global lesser of extraction - global_lesser_of_results = extract_global_lesser_of(text_dict, first_reimbursement_page, filename) + global_lesser_of_results = extract_global_lesser_of( + text_dict, first_reimbursement_page, filename + ) full_context_answers_dict.update(global_lesser_of_results) return full_context_answers_dict @@ -424,14 +454,15 @@ def create_global_lesser_of_row( new_row["GLOBAL_LESSER_OF_APPLIED"] = "Y" return new_row + def get_aarete_derived_termination_dt(one_to_one_results: dict): """Derive standardized termination date from effective date and term duration. - Uses LLM to calculate contract termination date by combining the validated effective + Uses LLM to calculate contract termination date by combining the validated effective date with the extracted term duration text (e.g., "3 years from effective date"). Args: - one_to_one_results (dict): Field values including "AARETE_DERIVED_EFFECTIVE_DT" + one_to_one_results (dict): Field values including "AARETE_DERIVED_EFFECTIVE_DT" and "TERMINATION_DT". Mutated in place with derived termination date. Returns: @@ -440,27 +471,32 @@ def get_aarete_derived_termination_dt(one_to_one_results: dict): """ required_keys = ["AARETE_DERIVED_EFFECTIVE_DT", "TERMINATION_DT"] if all(k in one_to_one_results.keys() for k in required_keys): - one_to_one_results["AARETE_DERIVED_TERMINATION_DT"] = prompt_calls.prompt_derived_term_date( + one_to_one_results["AARETE_DERIVED_TERMINATION_DT"] = ( + prompt_calls.prompt_derived_term_date( one_to_one_results["AARETE_DERIVED_EFFECTIVE_DT"], - one_to_one_results["TERMINATION_DT"] + one_to_one_results["TERMINATION_DT"], + ) ) return one_to_one_results -def get_aarete_derived_dates(one_to_one_results: dict, text_dict: dict, filename: str) -> dict: + +def get_aarete_derived_dates( + one_to_one_results: dict, text_dict: dict, filename: str +) -> dict: """Process and derive standardized contract dates from extracted one-to-one field results. - Orchestrates the complete date extraction and derivation pipeline combining text-based - extraction, vision-based fallback, and logical date derivation to produce reliable + Orchestrates the complete date extraction and derivation pipeline combining text-based + extraction, vision-based fallback, and logical date derivation to produce reliable contract date information. Processing workflow: 1. Effective date processing via check_and_update_effective_date() - text normalization, vision fallback if enabled, and ISO format standardization - 2. Termination date derivation via get_aarete_derived_termination_dt() - logical + 2. Termination date derivation via get_aarete_derived_termination_dt() - logical derivation from effective date and term duration Args: - one_to_one_results (dict): Extracted one-to-one field values including "EFFECTIVE_DT" + one_to_one_results (dict): Extracted one-to-one field values including "EFFECTIVE_DT" and "TERMINATION_DT". Mutated in place with derived date fields. text_dict (dict): Page-segmented contract text for vision extraction context. filename (str): Source filename for logging and PDF path derivation. @@ -470,8 +506,10 @@ def get_aarete_derived_dates(one_to_one_results: dict, text_dict: dict, filename - "AARETE_DERIVED_EFFECTIVE_DT": ISO-formatted date (YYYY-MM-DD) or "N/A" - "AARETE_DERIVED_TERMINATION_DT": ISO-formatted date (YYYY-MM-DD) or "N/A" """ - - one_to_one_results = check_and_update_effective_date(one_to_one_results, text_dict, filename) + + one_to_one_results = check_and_update_effective_date( + one_to_one_results, text_dict, filename + ) one_to_one_results = get_aarete_derived_termination_dt(one_to_one_results) diff --git a/src/pipelines/shared/extraction/page_funcs.py b/src/pipelines/shared/extraction/page_funcs.py new file mode 100644 index 0000000..6ca26fc --- /dev/null +++ b/src/pipelines/shared/extraction/page_funcs.py @@ -0,0 +1,365 @@ +""" +Page class for managing page text and table splitting functionality. + +This module provides the Page class which can represent either a regular page +or a collection of sub-pages (for split tables). It handles table detection, +parsing, and splitting into manageable chunks. +""" + +import ast +import logging +import re +from typing import Optional + +from src import config + + +TABLE_START_MARKER = "-------Table Start--------" +TABLE_END_MARKER = "-------Table End--------" + + +class Page: + """ + Represents a single page or a collection of sub-pages (for split tables). + + A Page can be in one of two states: + 1. Regular page: Contains a single text string + 2. Split table page: Contains multiple sub-pages (chunks of a table) + + Attributes: + page_num (str): Original page number from the document + is_split (bool): Whether this page has been split into sub-pages + text (str): Full text of the page (if not split) or combined text of all sub-pages + sub_pages (dict[str, str]): Mapping of sub-page identifiers to sub-page text + Format: {"page_num.1": "text", "page_num.2": "text", ...} + original_text (str): Original unsplit text (preserved for reference) + """ + + def __init__(self, page_num: str, text: str): + """ + Initialize a Page object. + + Args: + page_num: The page number identifier + text: The text content of the page + """ + self.page_num = page_num + self.original_text = text + self.text = text + self.is_split = False + self.sub_pages: dict[str, str] = {} + + def has_table(self) -> bool: + """ + Check if page contains a table. + + Returns: + bool: True if page contains table markers, False otherwise + """ + return TABLE_START_MARKER in self.text and TABLE_END_MARKER in self.text + + def split_table( + self, + max_cells: Optional[int] = None, + min_rows_to_split: Optional[int] = None, + ) -> None: + """ + Split table into sub-pages based on cell count (rows × columns). + + This method will: + 1. Extract the table content + 2. Parse table rows and detect column count + 3. Split into chunks where rows × columns <= max_cells + 4. Create sub-pages with appropriate identifiers + 5. Preserve text before/after the table + + Args: + max_cells: Maximum number of cells (rows × columns) per sub-page. + If None, uses config.MAX_TABLE_CELLS_PER_SUBPAGE + min_rows_to_split: Minimum rows to trigger splitting. + If None, uses config.MIN_TABLE_ROWS_TO_SPLIT + """ + if max_cells is None: + max_cells = config.MAX_TABLE_CELLS_PER_SUBPAGE + if min_rows_to_split is None: + min_rows_to_split = config.MIN_TABLE_ROWS_TO_SPLIT + if not self.has_table(): + return + + table_content = detect_table_in_text(self.text) + if not table_content: + return + + table_text, text_before, text_after = table_content + + # Parse table rows and detect column count + table_rows, num_columns = parse_table_rows(table_text, self.page_num) + + if len(table_rows) < min_rows_to_split: + # Table is too small to split + return + + # Calculate if table needs splitting based on total cell count + total_cells = len(table_rows) * num_columns + if total_cells <= max_cells: + # Table is small enough, don't split + return + + # Split table into chunks based on cell count + table_chunks = split_table_by_cell_count(table_rows, num_columns, max_cells) + + # Create sub-pages + self.sub_pages = {} + for i, chunk in enumerate(table_chunks, start=1): + sub_page_id = f"{self.page_num}.{i}" + sub_page_text = "" + + # Add text before table only to first sub-page + if i == 1: + sub_page_text += text_before + + # Add table chunk with markers + sub_page_text += f"{TABLE_START_MARKER}\n{chunk}\n{TABLE_END_MARKER}" + + # Add text after table only to last sub-page + if i == len(table_chunks): + sub_page_text += text_after + + self.sub_pages[sub_page_id] = sub_page_text + + # Mark as split + self.is_split = True + + # Update combined text + self.text = "\n".join(self.sub_pages.values()) + + def get_text(self, sub_page: Optional[str] = None) -> str: + """ + Get text for a specific sub-page or full page. + + Args: + sub_page: Optional sub-page identifier. Can be: + - None: Returns full page text (combined sub-pages if split) + - Full identifier (e.g., "1.1"): Returns that specific sub-page + - Partial identifier (e.g., "1"): Returns sub-page "page_num.1" + + Returns: + str: The requested text content + """ + if not self.is_split: + return self.text + + if sub_page is None: + # Return combined text of all sub-pages + return self.text + + # Handle full sub-page identifier (e.g., "1.1") + if sub_page in self.sub_pages: + return self.sub_pages[sub_page] + + # Handle partial identifier (e.g., "1" -> "page_num.1") + sub_page_id = f"{self.page_num}.{sub_page}" + if sub_page_id in self.sub_pages: + return self.sub_pages[sub_page_id] + + # Not found, return empty string + return "" + + def get_all_sub_pages(self) -> dict[str, str]: + """ + Get all sub-pages if split, else return single page. + + Returns: + dict: Mapping of page/sub-page identifiers to text content + """ + if not self.is_split: + return {self.page_num: self.text} + + return self.sub_pages.copy() + + def get_all_page_identifiers(self) -> list[str]: + """ + Get list of all page/sub-page identifiers. + + Returns: + list[str]: List of page identifiers (e.g., ["27"] or ["27.1", "27.2", ...]) + """ + if not self.is_split: + return [self.page_num] + + return sorted(self.sub_pages.keys(), key=lambda x: float(x.split(".")[-1])) + + def __repr__(self) -> str: + """String representation for debugging.""" + if self.is_split: + return ( + f"Page(page_num={self.page_num}, is_split=True, " + f"sub_pages={len(self.sub_pages)})" + ) + return f"Page(page_num={self.page_num}, is_split=False)" + + +def detect_table_in_text(text: str) -> Optional[tuple[str, str, str]]: + """ + Detect if text contains a table and return table content with context. + + Args: + text: The text to analyze + + Returns: + Optional[tuple[str, str, str]]: If table found, returns (table_text, text_before, text_after). + Otherwise returns None. + """ + if TABLE_START_MARKER not in text or TABLE_END_MARKER not in text: + return None + + start_idx = text.find(TABLE_START_MARKER) + end_idx = text.find(TABLE_END_MARKER, start_idx + len(TABLE_START_MARKER)) + + if end_idx == -1: + # Table start found but no end marker - return None + return None + + # Extract components + text_before = text[:start_idx].strip() + table_text = text[start_idx + len(TABLE_START_MARKER) : end_idx].strip() + text_after = text[end_idx + len(TABLE_END_MARKER) :].strip() + + return (table_text, text_before, text_after) + + +def parse_table_rows(table_text: str, page_num: str = "") -> tuple[list[str], int]: + """ + Parse table text into individual rows and detect column count. + + Expects Textract output format: [['Service', 'Payment'], ['Item 1', '$100'], ...] + + The table text may contain descriptive text before/after the list structure. + This function will find and extract the list structure from within the table text. + + Args: + table_text: The table content between markers (may include text before/after list) + page_num: Page number for logging purposes (optional) + + Returns: + tuple[list[str], int]: List of table rows as strings and column count. + Returns empty list and 0 columns if format is unexpected. + """ + if not table_text: + return [], 0 + + rows = [] + num_columns = 0 + + # First, try to find the list structure within the table text + # Look for the first '[' that starts a list structure + list_start = table_text.find("[") + + if list_start == -1: + # No list structure found + logging.warning( + f"Table on page {page_num} does not contain a list structure. " + "Table will not be split." + ) + return [], 0 + + # Extract from the first '[' onwards + # Use bracket matching to find the closing ']' for the entire list + bracket_count = 0 + list_end = -1 + + for i in range(list_start, len(table_text)): + if table_text[i] == "[": + bracket_count += 1 + elif table_text[i] == "]": + bracket_count -= 1 + if bracket_count == 0: + list_end = i + 1 + break + + if list_end == -1: + # Couldn't find matching closing bracket + logging.warning( + f"Table on page {page_num} contains incomplete list structure. " + "Table will not be split." + ) + return [], 0 + + # Extract the list text + list_text = table_text[list_start:list_end] + + # Parse the list structure + try: + parsed = ast.literal_eval(list_text) + if isinstance(parsed, list) and len(parsed) > 0: + # Convert each row to a string representation + for row in parsed: + if isinstance(row, list): + # Update column count based on first row + if num_columns == 0: + num_columns = len(row) + # Join list items with a separator + row_str = " | ".join(str(item) for item in row) + rows.append(row_str) + else: + # Non-list row - log warning but include it + logging.warning( + f"Table on page {page_num} contains non-list row: {row}. " + "Expected all rows to be lists." + ) + rows.append(str(row)) + else: + logging.warning( + f"Table on page {page_num} is not in expected format. " + f"Expected list of lists, got: {type(parsed).__name__}. " + "Table will not be split." + ) + return [], 0 + except (ValueError, SyntaxError) as e: + logging.warning( + f"Table on page {page_num} could not be parsed as expected list format. " + f"Error: {str(e)}. Table will not be split." + ) + return [], 0 + + if num_columns == 0: + logging.warning( + f"Table on page {page_num} has no columns detected. " + "Table will not be split." + ) + return [], 0 + + return rows, num_columns + + +def split_table_by_cell_count( + table_rows: list[str], num_columns: int, max_cells: int = 40 +) -> list[str]: + """ + Split table rows into chunks based on cell count (rows × columns). + + The product of rows × columns in each chunk will be <= max_cells. + This means tables with more columns will have fewer rows per chunk. + + Args: + table_rows: List of table row strings + num_columns: Number of columns in the table + max_cells: Maximum number of cells (rows × columns) per chunk (default: 40) + + Returns: + list[str]: List of table chunks, each as a string + """ + if not table_rows or num_columns == 0: + return [] + + # Calculate maximum rows per chunk based on column count + # max_rows = floor(max_cells / num_columns) + # Minimum of 1 row per chunk + max_rows = max(1, max_cells // num_columns) + + chunks = [] + for i in range(0, len(table_rows), max_rows): + chunk = table_rows[i : i + max_rows] + chunks.append("\n".join(chunk)) + + return chunks diff --git a/fieldExtraction/src/investment/row_funcs.py b/src/pipelines/shared/extraction/row_funcs.py similarity index 88% rename from fieldExtraction/src/investment/row_funcs.py rename to src/pipelines/shared/extraction/row_funcs.py index 275a9ac..c9891d9 100644 --- a/fieldExtraction/src/investment/row_funcs.py +++ b/src/pipelines/shared/extraction/row_funcs.py @@ -1,9 +1,9 @@ import logging from copy import deepcopy import pandas as pd -import src.investment.prompt_calls as prompt_calls -from constants.constants import Constants -from src.investment import one_to_one_funcs +import src.pipelines.saas.prompts.prompt_calls as prompt_calls +from src.constants.constants import Constants +from src.pipelines.shared.extraction import one_to_one_funcs from src.utils import string_utils from src.prompts.fieldset import FieldSet from src import config @@ -15,16 +15,20 @@ def combine_one_to_n( all_exhibit_special_case: list[dict[str, str]], exhibit_level_answers: dict[str, str], filename, -): - +): + # Combine reimbursement_level with exhibit_level # Reimbursement-level values take precedence - only add exhibit-level values that are missing in reimbursement combined_answers = [] for reimbursement_dict in all_exhibit_reimbursements: - combined_dict = {**reimbursement_dict} # Start with reimbursement-level (preserves reimbursement values) + combined_dict = { + **reimbursement_dict + } # Start with reimbursement-level (preserves reimbursement values) # Only add exhibit-level values that don't exist in reimbursement (or are empty/N/A in reimbursement) for key, value in exhibit_level_answers.items(): - if key not in combined_dict or string_utils.is_empty(combined_dict.get(key)): + if key not in combined_dict or string_utils.is_empty( + combined_dict.get(key) + ): combined_dict[key] = value # Add exhibit text for contextual analysis (e.g., for bill type code determination) combined_dict["EXHIBIT_TEXT"] = exhibit_text @@ -33,9 +37,15 @@ def combine_one_to_n( # Initialize final_combined_answers with the current combined list so that it has value even if no special cases are present final_combined_answers = combined_answers - special_case_fields = FieldSet(config.FIELD_JSON_PATH, field_type="special_case_check").list_fields() + special_case_fields = FieldSet( + config.FIELD_JSON_PATH, field_type="special_case_check" + ).list_fields() for field_name in special_case_fields: - special_case_answer_dicts = [answer_dict for answer_dict in all_exhibit_special_case if field_name in answer_dict.keys()] + special_case_answer_dicts = [ + answer_dict + for answer_dict in all_exhibit_special_case + if field_name in answer_dict.keys() + ] if not special_case_answer_dicts: continue elif len(special_case_answer_dicts) == 1: @@ -44,12 +54,21 @@ def combine_one_to_n( reimbursement_dict.update(special_case_answer_dict) else: for reimbursement_dict in final_combined_answers: - special_case_answer_dict = prompt_calls.prompt_special_case_assignment(exhibit_text, reimbursement_dict, special_case_answer_dicts, field_name, filename) + special_case_answer_dict = prompt_calls.prompt_special_case_assignment( + exhibit_text, + reimbursement_dict, + special_case_answer_dicts, + field_name, + filename, + ) reimbursement_dict.update(special_case_answer_dict) return final_combined_answers + def merge_one_to_one_into_one_to_n( - one_to_n_results: pd.DataFrame, one_to_one_results: dict[str, str], constants: Constants + one_to_n_results: pd.DataFrame, + one_to_one_results: dict[str, str], + constants: Constants, ) -> pd.DataFrame: """ Merges one_to_one_results into one_to_n_results. diff --git a/fieldExtraction/src/investment/tin_npi_funcs.py b/src/pipelines/shared/extraction/tin_npi_funcs.py similarity index 92% rename from fieldExtraction/src/investment/tin_npi_funcs.py rename to src/pipelines/shared/extraction/tin_npi_funcs.py index 3fdd01a..03073dd 100644 --- a/fieldExtraction/src/investment/tin_npi_funcs.py +++ b/src/pipelines/shared/extraction/tin_npi_funcs.py @@ -4,15 +4,16 @@ import logging import re from typing import Optional -import constants.regex_patterns as regex_patterns +import src.constants.regex_patterns as regex_patterns import src.config as config import src.prompts.prompt_templates as prompt_templates from src.utils import llm_utils, string_utils -from src.investment import prompt_calls -from constants.delimiters import Delimiter +from src.pipelines.saas.prompts import prompt_calls +from src.constants.delimiters import Delimiter from src.prompts.fieldset import Field, FieldSet from difflib import SequenceMatcher + def get_all_matches(text: str, pattern: str) -> list[str]: """ Extracts all unique matches of a given pattern from the provided text. @@ -178,7 +179,9 @@ def clean_provider_info(provider_info: list[dict]) -> list[dict]: # Clean Name - remove extra spaces and ensure it's not empty if "NAME" in provider and provider["NAME"]: - cleaned_provider["NAME"] = " ".join(provider["NAME"].split()).strip().rstrip('.') + cleaned_provider["NAME"] = ( + " ".join(provider["NAME"].split()).strip().rstrip(".") + ) # If name is empty after cleaning, set to "UNKNOWN" if not cleaned_provider["NAME"]: cleaned_provider["NAME"] = "UNKNOWN" @@ -209,20 +212,24 @@ def merge_provider_info_with_hybrid_smart_chunking(one_to_one_results, filename) other_tins = [] other_npis = [] other_names = [] - - provider_name = one_to_one_results.get('PROVIDER_NAME') - provider_info = one_to_one_results['PROV_INFO_JSON'] - provider_list = json.loads(provider_info) if isinstance(provider_info, str) else provider_info - + + provider_name = one_to_one_results.get("PROVIDER_NAME") + provider_info = one_to_one_results["PROV_INFO_JSON"] + provider_list = ( + json.loads(provider_info) if isinstance(provider_info, str) else provider_info + ) + # Track if we found any name matches found_match = False - + for provider in provider_list: - name_matches = prompt_calls.provider_name_match_check(provider_name, provider.get('NAME', 'UNKNOWN'), filename) + name_matches = prompt_calls.provider_name_match_check( + provider_name, provider.get("NAME", "UNKNOWN"), filename + ) if name_matches: found_match = True - provider['IS_GROUP'] = 'Y' + provider["IS_GROUP"] = "Y" if provider.get("TIN"): group_tins.add(provider["TIN"]) if provider.get("NPI"): @@ -230,7 +237,7 @@ def merge_provider_info_with_hybrid_smart_chunking(one_to_one_results, filename) if provider.get("NAME"): group_names.add(provider["NAME"]) else: - provider['IS_GROUP'] = 'N' + provider["IS_GROUP"] = "N" if provider.get("TIN"): other_tins.append(provider["TIN"]) if provider.get("NPI"): @@ -241,10 +248,10 @@ def merge_provider_info_with_hybrid_smart_chunking(one_to_one_results, filename) # If provider_name is not null and no match was found, add a new record if provider_name and not found_match: new_provider = { - 'NAME': provider_name, - 'TIN': 'UNKNOWN', - 'NPI': 'UNKNOWN', - 'IS_GROUP': 'Y' + "NAME": provider_name, + "TIN": "UNKNOWN", + "NPI": "UNKNOWN", + "IS_GROUP": "Y", } provider_list.append(new_provider) group_names.add(provider_name) @@ -274,8 +281,10 @@ def merge_provider_info_with_hybrid_smart_chunking(one_to_one_results, filename) ] # remove any group Names from other Names # Filter out records with NO_IDENTIFIERS_FOUND - provider_list = [p for p in provider_list if p.get('NAME') != 'NO_IDENTIFIERS_FOUND'] - + provider_list = [ + p for p in provider_list if p.get("NAME") != "NO_IDENTIFIERS_FOUND" + ] + # Deduplicate provider_list by NAME, keeping records with actual TIN/NPI values provider_list = deduplicate_providers_by_name(provider_list) @@ -415,11 +424,9 @@ def deduplicate_providers( valid_providers.append(provider) return valid_providers + def get_provider_info( - text_dict: dict, - page_num: str, - filename: str, - payer_name:str + text_dict: dict, page_num: str, filename: str, payer_name: str ) -> list: """ Extracts provider information from a specified page in a document using a language model. @@ -442,11 +449,16 @@ def get_provider_info( provider_fields = FieldSet( file_path=config.FIELD_JSON_PATH, field_type="provider_info" ) - instruction, prompt = prompt_templates.TIN_NPI_TEMPLATE( + prompt = prompt_templates.TIN_NPI_TEMPLATE( chunk, provider_fields.print_prompt_dict(), payer_name ) claude_answer_raw = llm_utils.invoke_claude( - prompt, "sonnet_latest", filename, max_tokens=8192, cache=True, instruction=instruction + prompt, + "sonnet_latest", + filename, + max_tokens=8192, + cache=True, + instruction=prompt_templates.TIN_NPI_TEMPLATE_INSTRUCTION(), ) # Sometimes rosters can have 50+ provider logging.debug( @@ -466,13 +478,7 @@ def get_provider_info( logging.warning( f"Warning: Unexpected format in provider info response: {type(providers)}" ) - providers = [ - { - "TIN": "UNKNOWN", - "NPI": "UNKNOWN", - "NAME": "PARSING_ERROR" - } - ] + providers = [{"TIN": "UNKNOWN", "NPI": "UNKNOWN", "NAME": "PARSING_ERROR"}] # VALIDATION LAYER - Cross-check with regex findings page_text = text_dict[page_num] @@ -525,25 +531,16 @@ def get_provider_info( ) return providers - + except ValueError as e: # Handle JSON parsing error logging.error(f"Error parsing JSON response from LLM: {str(e)}") logging.error(f"Raw response: {claude_answer_raw}") # Return a default value - return [ - { - "TIN": "UNKNOWN", - "NPI": "UNKNOWN", - "NAME": "PARSING_ERROR" - } - ] - + return [{"TIN": "UNKNOWN", "NPI": "UNKNOWN", "NAME": "PARSING_ERROR"}] + def run_provider_info_fields( - contract_text: str, - text_dict: dict, - filename: str, - payer_name: str + contract_text: str, text_dict: dict, filename: str, payer_name: str ): """ Extracts provider information from a contract text using regex-based identifier extraction, @@ -600,9 +597,9 @@ def run_provider_info_fields( # If there are no identifiers, return early with default values if not all_tins and not all_npis: # if there are no TINs or NPIs, we need to extract signature pages - relevant_pages = list(string_utils.extract_signature_page( - text_dict, filename - ).keys()) + relevant_pages = list( + string_utils.extract_signature_page(text_dict, filename).keys() + ) else: # Identify relevant pages containing either NPIs or TINs (with or without hyphen formatting, e.g., 68-0640053) relevant_pages = [ @@ -638,7 +635,9 @@ def run_provider_info_fields( # Process each page separately and combine results combined_provider_info = [] for page_num in relevant_pages: - page_provider_info = get_provider_info(text_dict, page_num, filename, payer_name) + page_provider_info = get_provider_info( + text_dict, page_num, filename, payer_name + ) combined_provider_info.extend(page_provider_info) # Clean and standardize results @@ -679,9 +678,12 @@ def deduplicate_providers_by_name(provider_list: list[dict]) -> list[dict]: seen_names = set() deduplicated_list = [] # Sort so providers with actual TIN/NPI values come first - for provider in sorted(provider_list, key=lambda p: (p.get('TIN') == 'UNKNOWN', p.get('NPI') == 'UNKNOWN')): - name = provider.get('NAME') + for provider in sorted( + provider_list, + key=lambda p: (p.get("TIN") == "UNKNOWN", p.get("NPI") == "UNKNOWN"), + ): + name = provider.get("NAME") if name not in seen_names: seen_names.add(name) deduplicated_list.append(provider) - return deduplicated_list \ No newline at end of file + return deduplicated_list diff --git a/fieldExtraction/src/investment/vision_funcs.py b/src/pipelines/shared/extraction/vision_funcs.py similarity index 100% rename from fieldExtraction/src/investment/vision_funcs.py rename to src/pipelines/shared/extraction/vision_funcs.py diff --git a/src/pipelines/shared/postprocessing/__init__.py b/src/pipelines/shared/postprocessing/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/pipelines/shared/postprocessing/__init__.py @@ -0,0 +1 @@ + diff --git a/fieldExtraction/src/investment/aarete_derived.py b/src/pipelines/shared/postprocessing/aarete_derived.py similarity index 76% rename from fieldExtraction/src/investment/aarete_derived.py rename to src/pipelines/shared/postprocessing/aarete_derived.py index 1bbdbeb..6e7cb78 100644 --- a/fieldExtraction/src/investment/aarete_derived.py +++ b/src/pipelines/shared/postprocessing/aarete_derived.py @@ -5,8 +5,8 @@ from collections import defaultdict import pandas as pd import src.config as config import src.utils.string_utils as string_utils -from constants.constants import Constants -from constants.delimiters import Delimiter +from src.constants.constants import Constants +from src.constants.delimiters import Delimiter from src.crosswalk.crosswalk_builder import CrosswalkBuilder from src.prompts.fieldset import FieldSet from src.utils.crosswalk_utils import apply_crosswalk @@ -35,15 +35,19 @@ def fill_na_mapping(answer_dicts): for answer_dict in answer_dicts: # Collect all AARETE_DERIVED_LOB values from different sources all_lob_values = set() - + # Get existing AARETE_DERIVED_LOB values (if any) existing_lob = answer_dict.get("AARETE_DERIVED_LOB", "") if not string_utils.is_empty(existing_lob): if "|" in existing_lob: - all_lob_values.update(v.strip() for v in existing_lob.split("|") if v.strip() and v.strip() != "N/A") + all_lob_values.update( + v.strip() + for v in existing_lob.split("|") + if v.strip() and v.strip() != "N/A" + ) elif existing_lob.strip() and existing_lob.strip() != "N/A": all_lob_values.add(existing_lob.strip()) - + # Get AARETE_DERIVED_LOB from AARETE_DERIVED_PROGRAM crosswalk (always check if PROGRAM exists) program_lob_values = set() if not string_utils.is_empty(answer_dict.get("AARETE_DERIVED_PROGRAM")): @@ -51,15 +55,25 @@ def fill_na_mapping(answer_dicts): answer_dict, "AARETE_DERIVED_LOB", "AARETE_DERIVED_PROGRAM", - "constants/mappings/crosswalk_program_lob.json", + "src/constants/mappings/crosswalk_program_lob.json", ) - if not string_utils.is_empty(program_filled_value) and program_filled_value != "N/A": + if ( + not string_utils.is_empty(program_filled_value) + and program_filled_value != "N/A" + ): if "|" in program_filled_value: - program_lob_values = set(v.strip() for v in program_filled_value.split("|") if v.strip() and v.strip() != "N/A") - elif program_filled_value.strip() and program_filled_value.strip() != "N/A": + program_lob_values = set( + v.strip() + for v in program_filled_value.split("|") + if v.strip() and v.strip() != "N/A" + ) + elif ( + program_filled_value.strip() + and program_filled_value.strip() != "N/A" + ): program_lob_values = {program_filled_value.strip()} all_lob_values.update(program_lob_values) - + # Get AARETE_DERIVED_LOB from PRODUCT crosswalk (always check if PRODUCT exists) product_lob_values = set() if not string_utils.is_empty(answer_dict.get("PRODUCT")): @@ -67,15 +81,25 @@ def fill_na_mapping(answer_dicts): answer_dict, "AARETE_DERIVED_LOB", "PRODUCT", - "constants/mappings/crosswalk_product_lob.json", + "src/constants/mappings/crosswalk_product_lob.json", ) - if not string_utils.is_empty(product_filled_value) and product_filled_value != "N/A": + if ( + not string_utils.is_empty(product_filled_value) + and product_filled_value != "N/A" + ): if "|" in product_filled_value: - product_lob_values = set(v.strip() for v in product_filled_value.split("|") if v.strip() and v.strip() != "N/A") - elif product_filled_value.strip() and product_filled_value.strip() != "N/A": + product_lob_values = set( + v.strip() + for v in product_filled_value.split("|") + if v.strip() and v.strip() != "N/A" + ) + elif ( + product_filled_value.strip() + and product_filled_value.strip() != "N/A" + ): product_lob_values = {product_filled_value.strip()} all_lob_values.update(product_lob_values) - + # Set the merged, deduplicated value if all_lob_values: answer_dict["AARETE_DERIVED_LOB"] = "|".join(sorted(all_lob_values)) @@ -96,18 +120,18 @@ def fill_na_mapping(answer_dicts): elif string_utils.is_empty(answer_dict.get("AARETE_DERIVED_LOB")): # If still empty after all attempts, keep it as is (will be N/A or empty) pass - + # Handle cases where PROGRAM/PRODUCT is NA/blank (LLM was bypassed) # Set relationship to "Exclusive" as default when PROGRAM/PRODUCT is missing and relationship is not set # This covers both cases: LOB exists but PROGRAM/PRODUCT is NA, or both LOB and PROGRAM/PRODUCT are NA if string_utils.is_empty(answer_dict.get("AARETE_DERIVED_PROGRAM")): if string_utils.is_empty(answer_dict.get("LOB_PROGRAM_RELATIONSHIP")): answer_dict["LOB_PROGRAM_RELATIONSHIP"] = "Exclusive" - + if string_utils.is_empty(answer_dict.get("AARETE_DERIVED_PRODUCT")): if string_utils.is_empty(answer_dict.get("LOB_PRODUCT_RELATIONSHIP")): answer_dict["LOB_PRODUCT_RELATIONSHIP"] = "Exclusive" - + return answer_dicts @@ -137,20 +161,26 @@ def get_crosswalk_fields(answer_dicts: list, constants: Constants): # Map each value in the list to_field_answer_list = [] for individual_from_field_value in from_field_value_list: - individual_from_field_value = individual_from_field_value.strip() + individual_from_field_value = ( + individual_from_field_value.strip() + ) if individual_from_field_value in crosswalk.mapping.keys(): # Value is a key in the mapping - map it to the target value - to_field_answer_list.append(crosswalk.mapping.get( - individual_from_field_value - )) + to_field_answer_list.append( + crosswalk.mapping.get(individual_from_field_value) + ) elif individual_from_field_value in crosswalk.mapping.values(): # Value is already in the target format (e.g., "CHIP" when target is "CHIP") # Keep it as-is for AARETE_DERIVED fields, or use reverse mapping for others if "AARETE_DERIVED" in to_field_name: to_field_answer_list.append(individual_from_field_value) else: - to_field_answer_list.append(crosswalk.create_reverse_mapping().get(individual_from_field_value)) + to_field_answer_list.append( + crosswalk.create_reverse_mapping().get( + individual_from_field_value + ) + ) answer_dict[to_field_name] = "|".join(to_field_answer_list) return answer_dicts diff --git a/fieldExtraction/src/investment/postprocess.py b/src/pipelines/shared/postprocessing/postprocess.py similarity index 92% rename from fieldExtraction/src/investment/postprocess.py rename to src/pipelines/shared/postprocessing/postprocess.py index c292306..0000d04 100644 --- a/fieldExtraction/src/investment/postprocess.py +++ b/src/pipelines/shared/postprocessing/postprocess.py @@ -1,7 +1,7 @@ import src.config as config -from constants.constants import Constants -from constants.investment_columns import COLUMN_ORDER -from src.investment import postprocessing_funcs +from src.constants.constants import Constants +from src.constants.investment_columns import COLUMN_ORDER +from src.pipelines.shared.postprocessing import postprocessing_funcs def postprocess(df, constants: Constants): @@ -41,15 +41,12 @@ def postprocess(df, constants: Constants): df[col] = df[col].apply(postprocessing_funcs.remove_hyphens) # Apply the flatten_singleton_string_list function to the 'CPT' column if "_CD" in col and "CPT" not in col: - df[col] = df[col].apply( - postprocessing_funcs.flatten_singleton_string_list - ) + df[col] = df[col].apply(postprocessing_funcs.flatten_singleton_string_list) # Convert DATE to YYYY/MM/DD format if "_DT" in col or "DATE" in col: df[col] = df[col].apply(postprocessing_funcs.validate_and_reformat_date) if "CPT" in col: df[col] = df[col].apply(postprocessing_funcs.normalize_cpt_fields) - # Deduplicate provider fields - remove GROUP values from OTHER fields and deduplicate OTHER lists df = postprocessing_funcs.deduplicate_provider_columns(df) @@ -64,9 +61,9 @@ def postprocess(df, constants: Constants): df = postprocessing_funcs.standardize_reimb_method_and_fee_schedule( df, constants.VALID_UNIT_OF_MEASURE ) - + # Add AARETE_DERIVED_SIGNATORY_COMPLETE_IND based on 2 signatory fields - df = postprocessing_funcs.add_aarete_derived_signatory_complete_ind(df) + df = postprocessing_funcs.add_aarete_derived_signatory_complete_ind(df) # update reimb_pct_rate df = postprocessing_funcs.fill_empty_reimb_pct_rate(df) @@ -96,4 +93,3 @@ def postprocess(df, constants: Constants): df = postprocessing_funcs.reorder_columns(df, COLUMN_ORDER) return df - diff --git a/fieldExtraction/src/investment/postprocessing_funcs.py b/src/pipelines/shared/postprocessing/postprocessing_funcs.py similarity index 93% rename from fieldExtraction/src/investment/postprocessing_funcs.py rename to src/pipelines/shared/postprocessing/postprocessing_funcs.py index 78e2be1..7a0ca41 100644 --- a/fieldExtraction/src/investment/postprocessing_funcs.py +++ b/src/pipelines/shared/postprocessing/postprocessing_funcs.py @@ -8,7 +8,7 @@ import json import pandas as pd import src.prompts.prompt_templates as prompt_templates import src.utils.llm_utils as llm_utils -from constants.delimiters import Delimiter +from src.constants.delimiters import Delimiter from src.utils import string_utils # Determine the base directory for the project @@ -580,7 +580,7 @@ def fill_empty_reimb_pct_rate(df): pct_empty = string_utils.is_empty(df["REIMB_PCT_RATE"]) fee_empty = string_utils.is_empty(df["REIMB_FEE_RATE"]) conversion_empty = string_utils.is_empty(df["REIMB_CONVERSION_FACTOR"]) - applicable_methods = ["Billed Charges", "Fee Schedule", "Case Rate", "Cost"] + applicable_methods = ["Billed Charges", "Fee Schedule", "Case Rate", "Cost"] method_applicable = df["AARETE_DERIVED_REIMB_METHOD"].isin(applicable_methods) fill_mask = pct_empty & fee_empty & conversion_empty & method_applicable @@ -619,51 +619,57 @@ def remove_redundant_reimb_info(df): df.loc[mask, reimb_col] = "" return df + def replace_provider_name_from_hybrid_smart_chunking(df): """ Replaces PROV_GROUP_NAME_FULL with PROVIDER_NAME for rows where PROVIDER_NAME is not empty/N/A, then removes the PROVIDER_NAME column. - + This function is used in postprocessing after the Hybrid Smart Chunking provider name extraction. The RAG method may produce a more accurate provider name than the initial extraction, so we use it to override PROV_GROUP_NAME_FULL when available. - + Args: df (pd.DataFrame): DataFrame containing contract data - + Returns: pd.DataFrame: DataFrame with PROV_GROUP_NAME_FULL updated and PROVIDER_NAME removed """ # Check if both columns exist if "PROVIDER_NAME" not in df.columns: - logging.debug("PROVIDER_NAME column not found in DataFrame, skipping replacement") + logging.debug( + "PROVIDER_NAME column not found in DataFrame, skipping replacement" + ) return df - + if "PROV_GROUP_NAME_FULL" not in df.columns: logging.debug("PROV_GROUP_NAME_FULL column not found in DataFrame") # Just remove PROVIDER_NAME if it exists df = df.drop(columns=["PROVIDER_NAME"]) return df - + # Create a mask for rows where PROVIDER_NAME should replace PROV_GROUP_NAME_FULL # Replace when PROVIDER_NAME is not empty mask = ~string_utils.is_empty(df["PROVIDER_NAME"], pd_mask=True) - + # Count how many rows will be updated num_replacements = mask.sum() - + if num_replacements > 0: # Replace PROV_GROUP_NAME_FULL with PROVIDER_NAME for matching rows df.loc[mask, "PROV_GROUP_NAME_FULL"] = df.loc[mask, "PROVIDER_NAME"] - logging.debug(f"Replaced PROV_GROUP_NAME_FULL with PROVIDER_NAME for {num_replacements} rows") + logging.debug( + f"Replaced PROV_GROUP_NAME_FULL with PROVIDER_NAME for {num_replacements} rows" + ) else: logging.debug("No valid PROVIDER_NAME values to replace PROV_GROUP_NAME_FULL") - + # Remove the PROVIDER_NAME column df = df.drop(columns=["PROVIDER_NAME"]) - + return df + def deduplicate_provider_columns(df: pd.DataFrame) -> pd.DataFrame: """Deduplicate provider fields in the DataFrame. @@ -795,91 +801,114 @@ def update_grouper_base_rate_and_grouper_pct_rate(df): return df + def fill_empty_dynamic(df): """ For specified columns, fills NA values with the common value from the same EXHIBIT_PAGE group. - + If all rows with the same EXHIBIT_PAGE value have only one unique non-NA value for a column, this function fills any NA values in that column with that unique value. - + Args: df (pd.DataFrame): DataFrame with at least an EXHIBIT_PAGE column - + Returns: pd.DataFrame: DataFrame with filled values """ if "EXHIBIT_PAGE" not in df.columns or df.empty: return df - + # List of columns to check for filling columns_to_fill = [ "AARETE_DERIVED_LOB", "AARETE_DERIVED_PROGRAM", "AARETE_DERIVED_PRODUCT", - "AARETE_DERIVED_NETWORK" + "AARETE_DERIVED_NETWORK", ] - + # Only process columns that actually exist in the dataframe columns_to_fill = [col for col in columns_to_fill if col in df.columns] - + # Make a copy to avoid SettingWithCopyWarning result_df = df.copy() - + # Check if AARETE_DERIVED_LOB column exists has_lob_column = "AARETE_DERIVED_LOB" in result_df.columns # First, handle AARETE_DERIVED_LOB by grouping on FILE_NAME and EXHIBIT_PAGE only if has_lob_column: - for (file_name, exhibit_page), group in result_df.groupby(["FILE_NAME", "EXHIBIT_PAGE"]): + for (file_name, exhibit_page), group in result_df.groupby( + ["FILE_NAME", "EXHIBIT_PAGE"] + ): # Get non-NA LOB values column = "AARETE_DERIVED_LOB" - non_na_values = [val for val in group[column].unique() if not string_utils.is_empty(val)] + non_na_values = [ + val for val in group[column].unique() if not string_utils.is_empty(val) + ] # If there's exactly one unique non-NA value, fill NA values with it if len(non_na_values) == 1: fill_value = non_na_values[0] # Only apply to rows with this FILE_NAME and EXHIBIT_PAGE combination - mask = (result_df["FILE_NAME"] == file_name) & \ - (result_df["EXHIBIT_PAGE"] == exhibit_page) & \ - result_df[column].apply(string_utils.is_empty) + mask = ( + (result_df["FILE_NAME"] == file_name) + & (result_df["EXHIBIT_PAGE"] == exhibit_page) + & result_df[column].apply(string_utils.is_empty) + ) result_df.loc[mask, column] = fill_value # Then, handle other columns by grouping on FILE_NAME, EXHIBIT_PAGE, and AARETE_DERIVED_LOB (if it exists) if has_lob_column: - for (file_name, exhibit_page, lob), group in result_df.groupby(["FILE_NAME", "EXHIBIT_PAGE", "AARETE_DERIVED_LOB"]): + for (file_name, exhibit_page, lob), group in result_df.groupby( + ["FILE_NAME", "EXHIBIT_PAGE", "AARETE_DERIVED_LOB"] + ): for column in columns_to_fill: # Skip AARETE_DERIVED_LOB as we already processed it if column == "AARETE_DERIVED_LOB": continue # Get non-NA values - non_na_values = [val for val in group[column].unique() if not string_utils.is_empty(val)] + non_na_values = [ + val + for val in group[column].unique() + if not string_utils.is_empty(val) + ] # If there's exactly one unique non-NA value, fill NA values with it if len(non_na_values) == 1: fill_value = non_na_values[0] # Only apply to rows with this FILE_NAME, EXHIBIT_PAGE, and LOB combination - mask = (result_df["FILE_NAME"] == file_name) & \ - (result_df["EXHIBIT_PAGE"] == exhibit_page) & \ - (result_df["AARETE_DERIVED_LOB"] == lob) & \ - result_df[column].apply(string_utils.is_empty) + mask = ( + (result_df["FILE_NAME"] == file_name) + & (result_df["EXHIBIT_PAGE"] == exhibit_page) + & (result_df["AARETE_DERIVED_LOB"] == lob) + & result_df[column].apply(string_utils.is_empty) + ) result_df.loc[mask, column] = fill_value else: # No LOB column, just group by FILE_NAME and EXHIBIT_PAGE - for (file_name, exhibit_page), group in result_df.groupby(["FILE_NAME", "EXHIBIT_PAGE"]): + for (file_name, exhibit_page), group in result_df.groupby( + ["FILE_NAME", "EXHIBIT_PAGE"] + ): for column in columns_to_fill: # Get non-NA values - non_na_values = [val for val in group[column].unique() if not string_utils.is_empty(val)] + non_na_values = [ + val + for val in group[column].unique() + if not string_utils.is_empty(val) + ] # If there's exactly one unique non-NA value, fill NA values with it if len(non_na_values) == 1: fill_value = non_na_values[0] # Only apply to rows with this FILE_NAME and EXHIBIT_PAGE combination - mask = (result_df["FILE_NAME"] == file_name) & \ - (result_df["EXHIBIT_PAGE"] == exhibit_page) & \ - result_df[column].apply(string_utils.is_empty) + mask = ( + (result_df["FILE_NAME"] == file_name) + & (result_df["EXHIBIT_PAGE"] == exhibit_page) + & result_df[column].apply(string_utils.is_empty) + ) result_df.loc[mask, column] = fill_value - + return result_df @@ -905,14 +934,14 @@ def attach_sid_column(df: pd.DataFrame) -> pd.DataFrame: DataFrame with all original columns plus a new 'AARETE_DERIVED_SID' column. """ sid_cols = [ - 'CLIENT_NAME', - 'PAYER_NAME', - 'PROV_GROUP_TIN', - 'DOCUMENT_TYPE', - 'AARETE_DERIVED_AMENDMENT_NUM', - 'AARETE_DERIVED_CLAIM_TYPE_CD', - 'AARETE_DERIVED_LOB', - 'AARETE_DERIVED_EFFECTIVE_DT' + "CLIENT_NAME", + "PAYER_NAME", + "PROV_GROUP_TIN", + "DOCUMENT_TYPE", + "AARETE_DERIVED_AMENDMENT_NUM", + "AARETE_DERIVED_CLAIM_TYPE_CD", + "AARETE_DERIVED_LOB", + "AARETE_DERIVED_EFFECTIVE_DT", ] # Make a copy to avoid mutating the original DataFrame @@ -920,21 +949,22 @@ def attach_sid_column(df: pd.DataFrame) -> pd.DataFrame: # Ensure all SID columns exist; create missing ones filled with 'xx' for col in sid_cols: if col not in df.columns: - df[col] = '' + df[col] = "" # Create the concatenated SID column (replace blanks/NaN only here) if df.empty: - df['AARETE_DERIVED_SID'] = pd.Series(dtype=str) + df["AARETE_DERIVED_SID"] = pd.Series(dtype=str) else: - sid_df = df[sid_cols].fillna('').astype(str) - df['AARETE_DERIVED_SID'] = sid_df.apply( - lambda row: '__'.join(val if val.strip() else 'xx' for val in row), + sid_df = df[sid_cols].fillna("").astype(str) + df["AARETE_DERIVED_SID"] = sid_df.apply( + lambda row: "__".join(val if val.strip() else "xx" for val in row), axis=1, - result_type='reduce' + result_type="reduce", ) return df + def add_aarete_derived_signatory_complete_ind(df: pd.DataFrame) -> pd.DataFrame: """ Add a derived indicator column to the DataFrame indicating whether all signatory lines are signed. @@ -958,7 +988,7 @@ def add_aarete_derived_signatory_complete_ind(df: pd.DataFrame) -> pd.DataFrame: try: required_cols = [ "NUM_AVAILABLE_SIGNATORY_LINE_COUNT", - "NUM_SIGNED_SIGNATORY_LINE_COUNT" + "NUM_SIGNED_SIGNATORY_LINE_COUNT", ] # Validate required columns @@ -982,4 +1012,3 @@ def add_aarete_derived_signatory_complete_ind(df: pd.DataFrame) -> pd.DataFrame: except Exception: # Return df unchanged on any exception return df - \ No newline at end of file diff --git a/src/pipelines/shared/preprocessing/__init__.py b/src/pipelines/shared/preprocessing/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/pipelines/shared/preprocessing/__init__.py @@ -0,0 +1 @@ + diff --git a/fieldExtraction/src/investment/hybrid_smart_chunking_funcs.py b/src/pipelines/shared/preprocessing/hybrid_smart_chunking_funcs.py similarity index 83% rename from fieldExtraction/src/investment/hybrid_smart_chunking_funcs.py rename to src/pipelines/shared/preprocessing/hybrid_smart_chunking_funcs.py index bc2bcb9..68dac05 100644 --- a/fieldExtraction/src/investment/hybrid_smart_chunking_funcs.py +++ b/src/pipelines/shared/preprocessing/hybrid_smart_chunking_funcs.py @@ -11,20 +11,22 @@ import logging import re from typing import List, Tuple, Dict -from langchain.schema import Document +from langchain_core.documents import Document from langchain_text_splitters import RecursiveCharacterTextSplitter import src.utils.llm_utils as llm_utils import src.utils.string_utils as string_utils import src.utils.timing_utils as timing_utils -import src.investment.preprocessing_funcs as preprocessing_funcs -import src.investment.hybrid_smart_chunking_preprocessing as hybrid_smart_chunking_preprocessing -from constants.constants import Constants -from constants.delimiters import Delimiter +import src.pipelines.shared.preprocessing.preprocessing_funcs as preprocessing_funcs +import src.pipelines.shared.preprocessing.hybrid_smart_chunking_preprocessing as hybrid_smart_chunking_preprocessing +from src.constants.constants import Constants +from src.constants.delimiters import Delimiter from src import config from src.prompts import prompt_templates from src.prompts.fieldset import FieldSet, Field -from src.investment.one_to_one_funcs import check_and_update_effective_date +from src.pipelines.shared.extraction.one_to_one_funcs import ( + check_and_update_effective_date, +) from src.utils.rag_utils import ( RAGConfig, HSC_CONFIG, @@ -37,7 +39,9 @@ from src.utils.rag_utils import ( ) -def process_single_field(field, retriever, reranker, rag_config, text_dict, constants, filename): +def process_single_field( + field, retriever, reranker, rag_config, text_dict, constants, filename +): """Process a single field in parallel for HSC.""" try: retrieval_query = field.retrieval_question @@ -46,7 +50,9 @@ def process_single_field(field, retriever, reranker, rag_config, text_dict, cons return (field.field_name, "N/A", field) # Retrieve + rerank using retrieval question - with timing_utils.timed_block(f"hsc.field.{field.field_name}.retrieval", context=filename): + with timing_utils.timed_block( + f"hsc.field.{field.field_name}.retrieval", context=filename + ): retrieved = retriever.invoke(retrieval_query)[: rag_config.ENSEMBLE_TOP_K] reranked = rerank_documents( retrieval_query, @@ -67,7 +73,9 @@ def process_single_field(field, retriever, reranker, rag_config, text_dict, cons ) return (field.field_name, "N/A", field) - llm_prompt = field.get_prompt_dict(constants) # Returns dict of {field_name : prompt} + llm_prompt = field.get_prompt_dict( + constants + ) # Returns dict of {field_name : prompt} prompt = prompt_templates.ONE_TO_ONE_SINGLE_FIELD_TEMPLATE(context, llm_prompt) logging.debug(f"Field: {field.field_name}") @@ -75,7 +83,9 @@ def process_single_field(field, retriever, reranker, rag_config, text_dict, cons logging.debug(f"LLM prompt: {llm_prompt}") # LLM call - with timing_utils.timed_block(f"hsc.field.{field.field_name}.llm_call", context=filename): + with timing_utils.timed_block( + f"hsc.field.{field.field_name}.llm_call", context=filename + ): raw = llm_utils.invoke_claude( prompt, "sonnet_latest", filename, max_tokens=8192 ) @@ -92,7 +102,10 @@ def process_single_field(field, retriever, reranker, rag_config, text_dict, cons if field_value == "N/A": field.field_type = "full_context" if field.field_name == "PAYER_NAME": - field.prompt = field.prompt + prompt_templates.FULL_CONTEXT_PAYER_NAME_ADDITIONAL_INSTRUCTION() + field.prompt = ( + field.prompt + + prompt_templates.FULL_CONTEXT_PAYER_NAME_ADDITIONAL_INSTRUCTION() + ) logging.warning( f"Obtained N/A for {field.field_name}, marking as full_context" ) @@ -254,12 +267,16 @@ def run_hybrid_smart_chunked_fields( # Collect fields that have retrieval questions defined # Only process fields that have the retrieval_question attribute set fields_to_process = [ - field for field in one_to_one_fields.fields - if field.field_type == "smart_chunked" and not string_utils.is_empty(field.retrieval_question) + field + for field in one_to_one_fields.fields + if field.field_type == "smart_chunked" + and not string_utils.is_empty(field.retrieval_question) ] if not fields_to_process: - logging.debug(f"No fields with retrieval questions found | Filename: {filename}") + logging.debug( + f"No fields with retrieval questions found | Filename: {filename}" + ) return {} try: @@ -293,10 +310,23 @@ def run_hybrid_smart_chunked_fields( retriever = create_hybrid_retriever(chunks, vectorstore, rag_config) answers_dict = {} - with timing_utils.timed_block("hsc.parallel_field_processing", context=filename): - with concurrent.futures.ThreadPoolExecutor(max_workers=min(len(fields_to_process), 20)) as executor: + with timing_utils.timed_block( + "hsc.parallel_field_processing", context=filename + ): + with concurrent.futures.ThreadPoolExecutor( + max_workers=min(len(fields_to_process), 20) + ) as executor: futures = [ - executor.submit(process_single_field, field, retriever, reranker, rag_config, text_dict, constants, filename) + executor.submit( + process_single_field, + field, + retriever, + reranker, + rag_config, + text_dict, + constants, + filename, + ) for field in fields_to_process ] @@ -336,8 +366,10 @@ def run_hybrid_smart_chunked_fields( value="full_context", ) - # Normalize PROVIDER_STATE - answers_dict = string_utils.normalize_state_field(answers_dict, field_name="PROVIDER_STATE") + # Normalize PROVIDER_STATE + answers_dict = string_utils.normalize_state_field( + answers_dict, field_name="PROVIDER_STATE" + ) # Normalize PAYER_STATE to standardized two-letter abbreviation for state_field in ["PAYER_STATE"]: @@ -347,8 +379,10 @@ def run_hybrid_smart_chunked_fields( answers_dict[state_field] ) ) - # Normalize PAYER_STATE - answers_dict = string_utils.normalize_state_field(answers_dict, field_name="PAYER_STATE") + # Normalize PAYER_STATE + answers_dict = string_utils.normalize_state_field( + answers_dict, field_name="PAYER_STATE" + ) return answers_dict except Exception as e: diff --git a/fieldExtraction/src/investment/hybrid_smart_chunking_preprocessing.py b/src/pipelines/shared/preprocessing/hybrid_smart_chunking_preprocessing.py similarity index 99% rename from fieldExtraction/src/investment/hybrid_smart_chunking_preprocessing.py rename to src/pipelines/shared/preprocessing/hybrid_smart_chunking_preprocessing.py index de327f8..fb559bd 100644 --- a/fieldExtraction/src/investment/hybrid_smart_chunking_preprocessing.py +++ b/src/pipelines/shared/preprocessing/hybrid_smart_chunking_preprocessing.py @@ -301,4 +301,4 @@ def get_section_info(sections): } info["total_characters"] += char_count - return info \ No newline at end of file + return info diff --git a/fieldExtraction/src/investment/preprocess.py b/src/pipelines/shared/preprocessing/preprocess.py similarity index 60% rename from fieldExtraction/src/investment/preprocess.py rename to src/pipelines/shared/preprocessing/preprocess.py index 26e59e5..8b666cc 100644 --- a/fieldExtraction/src/investment/preprocess.py +++ b/src/pipelines/shared/preprocessing/preprocess.py @@ -1,7 +1,11 @@ import logging +from typing import TYPE_CHECKING from src import config -from src.investment import preprocessing_funcs +from src.pipelines.shared.preprocessing import preprocessing_funcs + +if TYPE_CHECKING: + from src.pipelines.shared.extraction.page_funcs import Page def clean_text(contract_text): @@ -42,31 +46,91 @@ def split_text(contract_text): return text_dict, top_sheet_dict +def split_text_with_pages( + contract_text: str, +) -> tuple[dict[str, "Page"], dict[str, str]]: + """ + Split text into pages and convert to Page objects with table splitting. + + This function extends split_text() by converting the text dictionary to Page objects + and splitting large tables into sub-pages. + + Args: + contract_text: The full text of the contract to be processed + + Returns: + tuple: (pages_dict, top_sheet_dict) where: + - pages_dict: Dictionary mapping page numbers to Page objects + - top_sheet_dict: Dictionary of pages identified as Quick Review + """ + # First, split into text_dict (existing logic) + text_dict, top_sheet_dict = split_text(contract_text) + + # Then, convert to Page objects and split large tables + pages_dict = preprocessing_funcs.split_large_tables(text_dict) + + return pages_dict, top_sheet_dict + + def one_to_n_exhibit_chunking( - text_dict, EXHIBIT_HEADER_MARKERS, filename + text_dict=None, + pages_dict=None, + EXHIBIT_HEADER_MARKERS=None, + filename=None, ) -> tuple[dict, dict]: """ - Process the text dictionary to identify and chunk exhibits. + Process the text dictionary or pages dictionary to identify and chunk exhibits. + This function extracts exhibit pages, maps them to their respective chunks, and identifies reimbursement exhibits using LLM. Args: - text_dict (dict): A dictionary where keys are page numbers and values are the text on those pages. - filename (str): The name of the file being processed. + text_dict: A dictionary where keys are page numbers and values are the text + on those pages (for backward compatibility) + pages_dict: A dictionary where keys are page numbers and values are Page objects + (preferred) + EXHIBIT_HEADER_MARKERS: List of markers to identify exhibit headers + filename: The name of the file being processed. + Returns: tuple: A tuple containing: - - dict: A dictionary where keys are exhibit page numbers and values are the corresponding exhibit text chunks. - - dict: A dictionary where keys are exhibit page numbers and values are the exhibit headers. + - dict: A dictionary where keys are exhibit page numbers and values are + lists of page numbers that belong to that exhibit. + - dict: A dictionary where keys are exhibit page numbers and values are + the exhibit headers. + + Note: + Either text_dict or pages_dict must be provided. If both are provided, + pages_dict takes precedence. """ - exhibit_pages, all_exhibit_headers = preprocessing_funcs.get_exhibit_pages( - text_dict, EXHIBIT_HEADER_MARKERS, filename - ) - exhibit_pages, all_exhibit_headers = preprocessing_funcs.link_exhibit_pages( - all_exhibit_headers, text_dict, filename - ) - exhibit_chunk_mapping = preprocessing_funcs.chunk_by_exhibit( - text_dict, exhibit_pages - ) + # Determine which dictionary to use + if pages_dict is not None: + exhibit_pages, all_exhibit_headers = preprocessing_funcs.get_exhibit_pages( + pages_dict=pages_dict, + EXHIBIT_HEADER_MARKERS=EXHIBIT_HEADER_MARKERS, + filename=filename, + ) + exhibit_pages, all_exhibit_headers = preprocessing_funcs.link_exhibit_pages( + all_exhibit_headers, pages_dict=pages_dict, filename=filename + ) + exhibit_chunk_mapping = preprocessing_funcs.chunk_by_exhibit( + pages_dict=pages_dict, exhibit_pages=exhibit_pages + ) + elif text_dict is not None: + exhibit_pages, all_exhibit_headers = preprocessing_funcs.get_exhibit_pages( + text_dict=text_dict, + EXHIBIT_HEADER_MARKERS=EXHIBIT_HEADER_MARKERS, + filename=filename, + ) + exhibit_pages, all_exhibit_headers = preprocessing_funcs.link_exhibit_pages( + all_exhibit_headers, text_dict=text_dict, filename=filename + ) + exhibit_chunk_mapping = preprocessing_funcs.chunk_by_exhibit( + text_dict=text_dict, exhibit_pages=exhibit_pages + ) + else: + raise ValueError("Either text_dict or pages_dict must be provided") + return exhibit_chunk_mapping, all_exhibit_headers diff --git a/src/pipelines/shared/preprocessing/preprocessing_funcs.py b/src/pipelines/shared/preprocessing/preprocessing_funcs.py new file mode 100644 index 0000000..13c88c6 --- /dev/null +++ b/src/pipelines/shared/preprocessing/preprocessing_funcs.py @@ -0,0 +1,579 @@ +import logging +import re +from typing import TYPE_CHECKING, Optional + +import src.utils.string_utils as string_utils +from src.pipelines.saas.prompts import prompt_calls +from src import config + +if TYPE_CHECKING: + from src.pipelines.shared.extraction.page_funcs import Page + from src.pipelines.shared.extraction.exhibit_funcs import Exhibit + + +def remove_page_indicators(contract_text: str) -> str: + """Clean textract output by removing page number indicators in the form of "Page X of Y" + + This function processes input text to remove lines that indicate page numbers (e.g. 'Page 1 of 10') + + Args: + contract_text (str): Raw text output from Textract to be cleaned + + Returns: + str: cleaned text with newlines and page number indicators removed + """ + + if contract_text: + cleaned_text = re.sub(r"Page [0-9]+ of [0-9]+\n\n", " ", contract_text) + else: + cleaned_text = contract_text + return cleaned_text + + +def split_text(text: str) -> dict[str, str]: + """Split text on pages by the string `Start of Page No. = ' + + Args: + text (str): Raw text output from Textract to be split + + Returns: + dict[str, str]: A dictionary, keyed by the string page number and valued by the page text. + """ + temp_list = text.split("Start of Page No. = ") + text_list = re.split(r"Start of Page No. = [0-9]+\n", text) + + text_dict = {} + for i in range(len(text_list)): + if temp_list[i]: + text_dict[temp_list[i].split()[0]] = text_list[ + i + ] # splits on whitespace characters, which includes spaces, tabs, and newline characters + + return {k: v for k, v in text_dict.items() if k != "Document"} + + +def clean_law_symbols(contract_text): + if not contract_text: + return contract_text + # First correction: Replace '$$' with '$' + contract_text = contract_text.replace("$$", "$") + + contract_text = re.sub( + r"(U\.?S\.?C\.?) \$", r"\1§", contract_text + ) # replaces $ with § when it follows abbreviations like "U.S.C." (United States Code). + contract_text = re.sub( + r"(C\.?F\.?R\.?) \$", r"\1§", contract_text + ) # replaces $ with § when it follows abbreviations like "C.F.R." (Code of Federal Regulations). + + # Second correction: Replace '$' with '§' when followed by a number with three decimal places + contract_text = re.sub(r"\$(?=\d+\.\d{3})", "§", contract_text) + + return contract_text + + +def clean_newlines(contract_text: str) -> str: + """Clean textract output by removing newlines and page number indicators. + + This function processes input text to: + 1. Remove all newline characters. + 2. Remove lines that indicate page numbers (e.g. 'Page 1 of 10') + + Args: + contract_text (str): Raw text output from Textract to be cleaned + + Returns: + str: cleaned text with newlines and page number indicators removed + """ + cleaned_text = re.sub(r"(? tuple[list[str], dict[str, str]]: + """ + Identify exhibit pages from the text dictionary or pages dictionary. + + This function processes the dictionary to identify pages that are considered exhibits. + It uses the first page as an exhibit and checks subsequent pages for exhibit headers. + If a page is identified as an exhibit, it is added to the exhibit pages list and its + header is stored in the exhibit header dictionary. + If a page does not have a header or is not an exhibit, it is skipped. + + Args: + text_dict: A dictionary where keys are page numbers (as strings) and values are + the text of those pages (for backward compatibility) + pages_dict: A dictionary where keys are page numbers and values are Page objects + (preferred) + EXHIBIT_HEADER_MARKERS: List of markers to identify exhibit headers + filename: The name of the file being processed, used for logging and LLM invocation. + + Returns: + tuple[list[str], dict[str, str]]: A tuple containing: + - A list of page numbers (as strings) that are identified as exhibit pages. + - A dictionary where keys are page numbers and values are the headers of those exhibits. + + Note: + Either text_dict or pages_dict must be provided. If both are provided, + pages_dict takes precedence. + """ + if EXHIBIT_HEADER_MARKERS is None: + EXHIBIT_HEADER_MARKERS = [] + if filename is None: + filename = "" + + # Determine which dictionary to use + if pages_dict is not None: + page_dict = pages_dict + use_pages = True + elif text_dict is not None: + page_dict = text_dict + use_pages = False + else: + raise ValueError("Either text_dict or pages_dict must be provided") + + sorted_pages = sorted(page_dict.keys(), key=string_utils.page_key_sort) + exhibit_pages = [] + exhibit_header_dict = {} + + for page_num in sorted_pages: + # Get page content - handle both Page objects and strings + if use_pages: + page_obj = page_dict[page_num] + page_content = page_obj.get_text() + else: + page_content = page_dict[page_num] + + if "." not in page_num or ".0" in page_num: + exhibit_header = prompt_calls.prompt_exhibit_header( + page_content, EXHIBIT_HEADER_MARKERS, filename + ) + if "N/A" in exhibit_header: + is_exhibit = False + else: + exhibit_pages.append(page_num) + exhibit_header_dict[page_num] = exhibit_header + is_exhibit = True + elif is_exhibit == True: + exhibit_pages.append(page_num) + return exhibit_pages, exhibit_header_dict + + +def link_exhibit_pages( + all_exhibit_headers: dict[str, str], + text_dict: Optional[dict[str, str]] = None, + pages_dict: Optional[dict[str, "Page"]] = None, + filename: Optional[str] = None, +): + """ + Filters exhibit pages to include only those with meaningfully different headers. + + This function processes exhibit headers sequentially and uses literal comparison and + LLM-based semantic comparison to determine when exhibits represent continuation pages + vs. distinct exhibits. Continuation pages are filtered out of the headers list and + mapping, and when used downstream are included in their parent exhibit's text chunk. + Links exhibit pages based on their headers. If the header of a page is identical + (either literally or semantically) to the previous page's header, it is not added + to the final list of exhibit pages. + This function will link contiguous header pages together, so that the final list of + exhibit pages will only contain pages that are meaningfully different from the + previous page. E.g. "1" with header {"Exhibit 1"} and "2" with header {"Continued + exhibit 1"} will be linked together, but "3" with header {"Exhibit 2"} will not be + linked to either of them. + + Args: + all_exhibit_headers: A dictionary mapping page numbers (as strings) to their + exhibit headers. Expected to be in chronological order + text_dict: A dictionary mapping page numbers to their text content + (for backward compatibility) + pages_dict: A dictionary mapping page numbers to Page objects (preferred) + filename: The name of the file being processed, used for logging and LLM invocation. + + Returns: + tuple[list[str], dict[str, str]]: A tuple containing: + - A list of page numbers (as strings) that are identified as exhibit pages. + - A dictionary where keys are page numbers and values are the headers of those exhibits. + + Example: + Input: {"1": "Exhibit A", "2": "Exhibit A (continued)", "3": "Exhibit B"} + Output (["1", "3"], {"1": "Exhibit A", "3": "Exhibit B"}) + + Notes: + - First exhibit page is always included. + - Literal header comparison is performed first to optimize LLM usage and latency. + - Uses `EXHIBIT_LINKAGE` prompt for semantic similarity assessment + - Expects LLM to return "Y" or "N" enclosed in pipe delimiters + - Pages with non-distinct headers are excluded from the final results. + - Either text_dict or pages_dict must be provided (pages_dict takes precedence). + """ + if filename is None: + filename = "" + first_exhibit = True + final_exhibit_pages = [] + final_exhibit_headers = {} + for page_num, page_header in all_exhibit_headers.items(): + if first_exhibit: + exhibit_is_different = "N" + previous_header = page_header + final_exhibit_pages.append(page_num) + final_exhibit_headers[page_num] = page_header + first_exhibit = False + else: + # If literally identical, skip prompt (unless it has a table) + if page_header.upper().strip() == previous_header.upper().strip(): + exhibit_is_different = "N" + elif string_utils.is_empty(previous_header): + exhibit_is_different = "Y" + previous_header = page_header + else: + exhibit_is_different = prompt_calls.prompt_exhibit_linkage( + page_header, previous_header, filename + ) + previous_header = page_header + + # If the prompt has identified that the current exhibit is meaningfully different than the previous + if "Y" in exhibit_is_different: + final_exhibit_pages.append(page_num) + final_exhibit_headers[page_num] = page_header + + return final_exhibit_pages, final_exhibit_headers + + +def chunk_by_exhibit( + text_dict: Optional[dict[str, str]] = None, + pages_dict: Optional[dict[str, "Page"]] = None, + exhibit_pages: Optional[list] = None, + *args, # For backward compatibility with positional arguments +) -> dict: + """ + Organizes pages into groups based on their association with specific exhibits. + + This function assigns each page number from the dictionary to an exhibit + based on the `exhibit_pages` list. Pages are grouped under the nearest preceding + page number in `exhibit_pages`. If a page number is itself in `exhibit_pages`, + it starts a new exhibit group. + + Parameters: + text_dict: A dictionary where keys are page numbers and values are page text + (for backward compatibility) + pages_dict: A dictionary where keys are page numbers and values are Page objects + (preferred) + exhibit_pages: A list of page numbers that mark the beginning of a new exhibit. + + Returns: + dict: A dictionary where keys are exhibit identifiers (page numbers from exhibit_pages) + and values are lists of page numbers that belong to that exhibit. + Example: {'1': ['1', '2'], '3': ['3', '4', '5']} + + Note: + Either text_dict or pages_dict must be provided. If both are provided, + pages_dict takes precedence. + For backward compatibility: can be called as chunk_by_exhibit(text_dict, exhibit_pages) + """ + # Backward compatibility: detect when called with old positional signature + # Old signature: chunk_by_exhibit(text_dict, exhibit_pages) + # When called positionally, Python binds: text_dict=dict, pages_dict=list, exhibit_pages=None + if ( + pages_dict is not None + and isinstance(pages_dict, list) + and exhibit_pages is None + ): + # This is the old signature - pages_dict is actually exhibit_pages + exhibit_pages = pages_dict + pages_dict = None + + if exhibit_pages is None: + exhibit_pages = [] + + # Determine which dictionary to use + if pages_dict is not None: + if not isinstance(pages_dict, dict): + raise TypeError(f"pages_dict must be a dict, got {type(pages_dict)}") + page_dict = pages_dict + elif text_dict is not None: + if not isinstance(text_dict, dict): + raise TypeError(f"text_dict must be a dict, got {type(text_dict)}") + page_dict = text_dict + else: + raise ValueError("Either text_dict or pages_dict must be provided") + + if len(exhibit_pages) == 0: + return {key: [key] for key in page_dict.keys()} + + exhibit_chunk_mapping = {} + current_exhibit = list(page_dict.keys())[0] + + for page_num in page_dict.keys(): + if page_num in exhibit_pages: + current_exhibit = page_num + # Initialize the list for this exhibit if not already present + if current_exhibit not in exhibit_chunk_mapping: + exhibit_chunk_mapping[current_exhibit] = [] + + # Add the page to the current exhibit's list + if current_exhibit not in exhibit_chunk_mapping: + exhibit_chunk_mapping[current_exhibit] = [] + exhibit_chunk_mapping[current_exhibit].append(page_num) + + return exhibit_chunk_mapping + + +def simplify_exhibit( + text_dict: Optional[dict[str, str]] = None, + pages_dict: Optional[dict[str, "Page"]] = None, + exhibit: Optional["Exhibit"] = None, + exhibit_page_nums: Optional[list[str]] = None, + current_page_num: Optional[str] = None, +) -> str: + """ + Simplify exhibit text by replacing table content with 'Table X' placeholders on all pages + except the current page being processed. + + Args: + text_dict: Dictionary mapping page numbers to page text (for backward compatibility) + pages_dict: Dictionary mapping page numbers to Page objects (preferred) + exhibit: Exhibit object (preferred - uses exhibit.pages and exhibit.exhibit_page_nums) + exhibit_page_nums: List of page numbers that belong to this exhibit + (required if exhibit is not provided) + current_page_num: The current page being processed (will NOT be simplified) + (required if exhibit is not provided) + + Returns: + str: The exhibit text with tables simplified on all pages except current_page_num + + Note: + Either (exhibit) or (text_dict/pages_dict + exhibit_page_nums + current_page_num) must be provided. + If exhibit is provided, it takes precedence. + """ + # Check if any parameter that should be a dict is actually an Exhibit object + if text_dict is not None and hasattr(text_dict, "pages"): + # text_dict is actually an Exhibit object + exhibit = text_dict + text_dict = None + elif pages_dict is not None and hasattr(pages_dict, "pages"): + # pages_dict is actually an Exhibit object + exhibit = pages_dict + pages_dict = None + + # Handle Exhibit object (preferred approach) - but only if it's actually an Exhibit + if exhibit is not None and hasattr(exhibit, "pages"): + if exhibit.pages is not None: + pages_dict = exhibit.pages + else: + # Fall back to text_dict if pages not available + text_dict = { + page_id: exhibit.get_page_text(page_id) + for page_id in exhibit.exhibit_page_nums + } + exhibit_page_nums = exhibit.exhibit_page_nums + # For current_page_num, we need to determine which base page the current_page_num belongs to + # If current_page_num is a sub-page like "27.1", the base page is "27" + if current_page_num is None: + # Try to infer from exhibit_page_nums - use first page as default + current_page_num = exhibit_page_nums[0] if exhibit_page_nums else "" + else: + # Extract base page if it's a sub-page + if "." in current_page_num and not current_page_num.startswith("."): + current_page_num = current_page_num.rsplit(".", 1)[0] + + # Validate required parameters + if exhibit_page_nums is None: + raise ValueError( + "exhibit_page_nums must be provided if exhibit is not provided" + ) + if current_page_num is None: + raise ValueError("current_page_num must be provided if exhibit is not provided") + + # Determine which dictionary to use + use_pages = False + if pages_dict is not None: + page_dict = pages_dict + use_pages = True + elif text_dict is not None: + page_dict = text_dict + use_pages = False + else: + raise ValueError("Either text_dict, pages_dict, or exhibit must be provided") + + def replace_tables_with_placeholder( + page_text: str, starting_table_num: int + ) -> tuple[str, int]: + """Replace table blocks with 'Table X' labels and return next table number.""" + if not page_text: + return page_text, starting_table_num + + start_marker = "-------Table Start--------" + end_marker = "-------Table End--------" + result = [] + pos = 0 + table_num = starting_table_num + + while True: + start_idx = page_text.find(start_marker, pos) + if start_idx == -1: + # No more tables, append remaining text + result.append(page_text[pos:]) + break + + # Append text before table + result.append(page_text[pos:start_idx]) + + # Find end of table + end_idx = page_text.find(end_marker, start_idx + len(start_marker)) + + # Replace table with placeholder + result.append(f"Table {table_num}") + table_num += 1 + + # Move position past the table end marker + if end_idx != -1: + pos = end_idx + len(end_marker) + else: + # No end marker found, stop processing + break + + return "".join(result), table_num + + # Process each page/sub-page in the exhibit + simplified_exhibit_pages = [] + table_counter = 1 + + # Extract base page from current_page_num if it's a sub-page + current_base_page = current_page_num + if "." in current_page_num and not current_page_num.startswith("."): + current_base_page = current_page_num.rsplit(".", 1)[0] + + for page_id in exhibit_page_nums: + # Extract base page for comparison + base_page = page_id + if "." in page_id and not page_id.startswith("."): + base_page = page_id.rsplit(".", 1)[0] + + # Get page text + if use_pages: + # Handle sub-pages: "27.1" means get sub-page "1" from page "27" + if "." in page_id and not page_id.startswith("."): + base_page_num, sub_page = page_id.rsplit(".", 1) + if base_page_num in page_dict: + page_text = page_dict[base_page_num].get_text(sub_page) + else: + page_text = "" + elif page_id in page_dict: + page_text = page_dict[page_id].get_text() + else: + page_text = "" + else: + page_text = page_dict.get(page_id, "") + + # Check if this is the current page (match base page) + if base_page == current_base_page: + # Don't simplify the current page - keep it as-is + simplified_exhibit_pages.append(page_text) + # But still need to count tables to keep numbering consistent + if "-------Table Start--------" in page_text: + _, table_counter = replace_tables_with_placeholder( + page_text, table_counter + ) + else: + # Simplify other pages by replacing tables with placeholders + if "-------Table Start--------" in page_text: + simplified_page, table_counter = replace_tables_with_placeholder( + page_text, table_counter + ) + simplified_exhibit_pages.append(simplified_page) + else: + simplified_exhibit_pages.append(page_text) + + return "\n".join(simplified_exhibit_pages) + + +def split_large_tables( + text_dict: dict[str, str], + max_cells: Optional[int] = None, + min_rows_to_split: Optional[int] = None, +) -> dict[str, "Page"]: + """ + Identify and split large tables into sub-pages. + + This function converts a text dictionary to Page objects and splits + large tables based on cell count (rows × columns). + + Args: + text_dict: Original page number to text mapping + max_cells: Maximum cells (rows × columns) per table sub-page. + If None, uses config.MAX_TABLE_CELLS_PER_SUBPAGE + min_rows_to_split: Minimum rows to trigger splitting. + If None, uses config.MIN_TABLE_ROWS_TO_SPLIT + + Returns: + dict mapping page numbers to Page objects + """ + from src.pipelines.shared.extraction.page_funcs import Page + + if not config.TABLE_SPLITTING_ENABLED: + # If table splitting is disabled, create Page objects without splitting + return { + page_num: Page(page_num, page_text) + for page_num, page_text in text_dict.items() + } + + if max_cells is None: + max_cells = config.MAX_TABLE_CELLS_PER_SUBPAGE + if min_rows_to_split is None: + min_rows_to_split = config.MIN_TABLE_ROWS_TO_SPLIT + + pages_dict = {} + + for page_num, page_text in text_dict.items(): + page = Page(page_num, page_text) + + # Check if page has a table and if it needs splitting + if page.has_table(): + # Split table if it exceeds thresholds + page.split_table(max_cells=max_cells, min_rows_to_split=min_rows_to_split) + + pages_dict[page_num] = page + + return pages_dict diff --git a/src/prompts/bcbs_promise_prompts.json b/src/prompts/bcbs_promise_prompts.json new file mode 100644 index 0000000..c87a2b5 --- /dev/null +++ b/src/prompts/bcbs_promise_prompts.json @@ -0,0 +1,31 @@ +[ + { + "field_name": "OFFSET_TERM", + "relationship": "one_to_one", + "field_type": "smart_chunked", + "prompt": "Extract the full text of any offset or recoupment provisions related to provider payments from this contract.\n\nLook for language containing these concepts:\n- Overpayment offset (plan may deduct prior overpayments from future claims)\n- Cross-plan offset (plan may recover overpayments owed under one plan from payments due under another)\n- Mutual offset (either party may offset amounts owed)\n- Prohibited/limited offset (offsets are banned, capped, or require consent)\n\nINSTRUCTIONS:\n1. Extract the COMPLETE paragraph or clause text for each offset/recoupment provision found\n2. Include the full context - do not truncate or summarize\n3. If multiple offset provisions exist in the contract, concatenate them separated by ' | '\n4. Preserve the exact wording from the contract\n\nIf no offset or recoupment provision is found, return 'N/A'.", + "keywords": [ + "offset", + "setoff", + "set-off", + "recoup", + "recoupment", + "withhold", + "withholding", + "net against", + "adjust future payments", + "recover overpayments", + "recovery of funds", + "cross-plan", + "cross plan", + "mutual offset", + "prohibited", + "no offset", + "deduct from future", + "amounts owed", + "right to deduct", + "right to recover" + ], + "retrieval_question": "What are the offset, setoff, recoupment, or withholding provisions in this contract? Plan may offset amounts owed. Right to deduct overpayments from future claims. Right to recoup. Deduct from future reimbursement. Recover amounts owed under this agreement. Cross-plan offset recovery. Net against future payments. Withhold payment. No offset without consent. Offset prohibited. Provider agrees Plan may deduct. Amounts due under any other agreement." + } +] diff --git a/src/prompts/clover_prompts.json b/src/prompts/clover_prompts.json new file mode 100644 index 0000000..f915421 --- /dev/null +++ b/src/prompts/clover_prompts.json @@ -0,0 +1,74 @@ +[ + { + "field_name": "CLAIMS_TIMELY_FILING_DAYS", + "relationship": "one_to_one", + "field_type": "full_context", + "prompt": "What is the Claims Timely Filing requirement in days? Look for language specifying the number of days within which a claim must be submitted after the date of service. Common phrases include:\n\n- 'claims must be submitted within X days'\n- 'timely filing limit of X days'\n- 'claims received after X days will be denied'\n- 'X days from the date of service'\n- 'claims filing deadline'\n- 'claim submission deadline'\n\nExtract ONLY the numeric value representing the number of days. If the timely filing requirement is expressed in months, convert to days (1 month = 30 days). If a range is provided, extract the maximum number of days allowed.\n\nDo NOT include:\n- Appeal filing deadlines (these are separate from initial claim submission)\n- Corrected claim deadlines\n- Reconsideration deadlines\n\nIf no claims timely filing requirement is found, return 'N/A'." + }, + { + "field_name": "APPEALS_TIMELY_FILING_DAYS", + "relationship": "one_to_one", + "field_type": "full_context", + "prompt": "What is the Appeals Timely Filing requirement in days? Look for language specifying the number of days within which an appeal must be filed after a claim denial, adverse determination, or payment dispute. Common phrases include:\n\n- 'appeals must be submitted within X days'\n- 'X days to file an appeal'\n- 'appeal deadline of X days'\n- 'X days from the date of denial'\n- 'X days from the date of the adverse determination'\n- 'X days from the Explanation of Benefits (EOB)'\n- 'X days from the remittance advice'\n\nExtract ONLY the numeric value representing the number of days. If the appeals filing requirement is expressed in months, convert to days (1 month = 30 days). If multiple appeal levels exist with different deadlines, extract the deadline for the first level of appeal.\n\nDo NOT include:\n- Initial claim submission deadlines\n- Corrected claim deadlines\n- Grievance filing deadlines (unless explicitly tied to payment appeals)\n\nIf no appeals timely filing requirement is found, return 'N/A'." + }, + { + "field_name": "SIGNATURE_DT_PROV", + "relationship": "one_to_one", + "field_type": "full_context", + "prompt": "In the signature section, there may be two people signing. Look for the provider representative's date (NOT the Plan President or health plan officer). Common provider titles include: VP, Director, Administrator. Extract their date in MM/DD/YYYY format. If year is 2 digits, convert to 4 digits (e.g., 19 → 2019). If no date is found, respond with 'N/A'." + }, + { + "field_name": "SIGNATURE_DT_PAYOR", + "relationship": "one_to_one", + "field_type": "full_context", + "prompt": "In the signature section, look for the payor/health plan representative's date. Common payor titles include: Plan President, CEO, Health Plan Officer. Extract their date in MM/DD/YYYY format. If year is 2 digits, convert to 4 digits (e.g., 19 → 2019). If no date is found, respond with 'N/A'." + }, + { + "field_name": "NON_STANDARD_LANGUAGE_DIFFERENTIATION", + "relationship": "one_to_one", + "field_type": "full_context", + "prompt": "Identify any portions of the contract that contain non-standard, non-templated, or custom language that differs from the payer’s standard boilerplate terms. Provide a concise summary of these deviations and cite the section(s) where they occur." + }, + { + "field_name": "PAYMENT_INTEGRITY_LOOKBACK_PERIOD", + "relationship": "one_to_one", + "field_type": "full_context", + "prompt": "Extract the look-back period associated with payment integrity, claim review, or audit rights. Return the specific date range, number of months/years, or any defined retroactive period mentioned. If no look-back period is found, return 'N/A'." + }, + { + "field_name": "PREPAY_AUDIT_LIMITATIONS", + "relationship": "one_to_one", + "field_type": "full_context", + "prompt": "Identify any stated limitations or restrictions on prepay audits, including scope, timing, volume, frequency, or conditions under which prepay audits may occur. Return all explicit limitations. If no limitations are found, return 'N/A'." + }, + { + "field_name": "MEDICAL_RECORD_REIMBURSEMENT", + "relationship": "one_to_one", + "field_type": "full_context", + "prompt": "Extract any provisions describing reimbursement, fees, payment responsibilities, or cost coverage for supplying medical records. Include dollar amounts, conditions, and which party is responsible. If no provisions are found, return 'N/A'." + }, + { + "field_name": "AUDIT_VOLUME_LIMITATIONS", + "relationship": "one_to_one", + "field_type": "full_context", + "prompt": "Identify whether the contract defines limits on the number or percentage of claims that may be audited (audit volume caps). Return the specific thresholds, time periods, and any exceptions. If no limitations are found, return 'N/A'." + }, + { + "field_name": "AUDIT_TYPE_LIMITATION", + "relationship": "one_to_one", + "field_type": "full_context", + "prompt": "Extract any limitations on the type(s) of audits permitted (e.g., clinical audits, coding audits, desk audits, on-site audits, prepay vs post-pay). Include any categories that are explicitly prohibited or restricted. If no limitations are found, return 'N/A'." + }, + { + "field_name": "CA_TERM", + "relationship": "one_to_one", + "field_type": "full_context", + "prompt": "Extract the full contract language related to the Clover Assistant (CA) term. Include the entire clause or section where CA terms are defined, including any references to rates, reimbursement terms, obligations, duration, conditions, reasons for the term, or modifications tied to CA participation. Return the full original text of this CA-related section. If no CA term is found, return 'N/A'." + }, + { + "field_name": "CLOVER_ASSISTANT", + "relationship": "one_to_one", + "field_type": "full_context", + "prompt": "Determine whether the contract includes participation in or use of Clover Assistant (CA). Return 'Y' if participation is included or required, otherwise return 'N'." + } +] \ No newline at end of file diff --git a/fieldExtraction/src/prompts/document_classification_prompts.json b/src/prompts/document_classification_prompts.json similarity index 100% rename from fieldExtraction/src/prompts/document_classification_prompts.json rename to src/prompts/document_classification_prompts.json diff --git a/src/prompts/fieldset.py b/src/prompts/fieldset.py new file mode 100644 index 0000000..5f9d21c --- /dev/null +++ b/src/prompts/fieldset.py @@ -0,0 +1,380 @@ +import json +from threading import Lock + +import src.utils.string_utils as string_utils +from src.constants.constants import Constants + +# =================================================================== +# FILE CACHING IMPLEMENTATION +# =================================================================== +# +# PROBLEM: In concurrent processing, multiple threads create many FieldSet +# and Field instances that all read the same JSON files (e.g. investment_prompts.json). +# This causes "too many open files" errors when we exceed the system limit (~1024). +# +# SOLUTION: Cache the parsed JSON data at the module level so each file is +# only read ONCE per process, then reused across all instances. +# +# HOW IT WORKS: +# - First FieldSet/Field that needs "investment_prompts.json" → reads file, caches data +# - All subsequent instances → use cached data (no file I/O) +# - Thread-safe with _cache_lock to prevent race conditions +# +# BENEFITS: +# - Eliminates "too many open files" errors +# - Performance improvement (no repeated JSON parsing) +# - No changes needed to existing code +# +# NOTE FOR DEVELOPERS: +# - The cache persists for the entire process lifetime +# - Each unique file path gets its own cache entry +# - Filtering still works normally - each FieldSet can filter the same cached data differently +# =================================================================== + +# Module-level cache - shared across ALL FieldSet and Field instances +_field_data_cache = {} +_cache_lock = Lock() + + +class Field: + def __init__(self, field_dict): + # Base Attributes + self.field_name = field_dict["field_name"] + self.relationship = field_dict["relationship"] + self.field_type = field_dict["field_type"] + self.prompt = field_dict["prompt"] if "prompt" in field_dict else None + self.valid_values = ( + field_dict["valid_values"] if "valid_values" in field_dict else None + ) + # AArete-Derived Attributes + self.base_field = ( + field_dict["base_field"] if "base_field" in field_dict else None + ) + self.crosswalk = field_dict["crosswalk"] if "crosswalk" in field_dict else None + # Smart Chunking Attributes + self.keywords = field_dict["keywords"] if "keywords" in field_dict else None + self.methodology = ( + field_dict["methodology"] if "methodology" in field_dict else None + ) + self.case_sensitive = ( + field_dict["case_sensitive"] if "case_sensitive" in field_dict else False + ) + self.regex_pattern = ( + field_dict["regex_pattern"] if "regex_pattern" in field_dict else None + ) + self.retrieved_text = None + self.format = field_dict["format"] if "format" in field_dict else None + self.allow_na = field_dict["allow_na"] if "allow_na" in field_dict else True + self.breakout_template = ( + field_dict["breakout_template"] + if "breakout_template" in field_dict + else None + ) + # RAG Retrieval Attributes + self.retrieval_question = ( + field_dict["retrieval_question"] + if "retrieval_question" in field_dict + else None + ) + + def __repr__(self): + """Returns a string representation of the Field object.""" + return self.field_name + + @classmethod + def load_from_file(cls, file_path, field_name): + """ + Reads a JSON file with caching and creates a Field object + + CACHING BEHAVIOR: + - First call with a file_path: Reads file and caches the parsed JSON + - Subsequent calls with same file_path: Uses cached data (no file I/O) + - Thread-safe: Multiple threads can safely call this simultaneously + + :param file_path: Path to the JSON file. + :param field_name: The field name to look for in the JSON data. + :return: A Field object if found, otherwise raises a ValueError. + """ + # Thread-safe cache access + with _cache_lock: + if file_path not in _field_data_cache: + # CACHE MISS: Load the file and cache its content + with open(file_path, "r") as file: + _field_data_cache[file_path] = json.load(file) + + # CACHE HIT: Use cached data + data = _field_data_cache[file_path] + + # Filtering logic uses the cached data and filters to a specific field + for field_dict in data: + if field_dict.get("field_name") == field_name: + return cls(field_dict) + + raise ValueError(f"Field '{field_name}' not found in {file_path}") + + @classmethod + def from_values(cls, **kwargs): + """Creates a Field instance from given keyword arguments.""" + return cls(kwargs) + + def to_dict(self): + """Converts the Field instance to a dictionary.""" + return { + "field_name": self.field_name, + "base_field": self.base_field, + "relationship": self.relationship, + "field_type": self.field_type, + "prompt": self.prompt, + "valid_values": self.valid_values, + "keywords": self.keywords, + "methodology": self.methodology, + "case_sensitive": self.case_sensitive, + "regex_pattern": self.regex_pattern, + "format": self.format, + } + + def print(self): + """Prints the details of a FieldInfo object in a readable format.""" + print(f"Field Name: {self.field_name}") + print(f"Relationship: {self.relationship}") + print(f"Field Type: {self.field_type}") + print(f"Prompt: {self.prompt}") + print( + f"Valid Values: {'None specified' if not self.valid_values else self.valid_values}" + ) + print(f"Keywords: {'None specified' if not self.keywords else self.keywords}") + print( + f"Methodology: {'None specified' if not self.methodology else self.methodology}" + ) + print(f"Case Sensitive: {self.case_sensitive}") + print( + f"Regex Pattern: {'None specified' if not self.regex_pattern else self.regex_pattern}" + ) + + def get_prompt_dict(self, constants: Constants = None): + """Returns a dictionary with the field name as the key and its prompt as the value.""" + return {self.field_name: self.get_prompt(constants)} + + def get_prompt(self, constants: Constants = None): + """Resolves placeholders in the prompt using the valid_values property.""" + + # If no valid_values to resolve + if string_utils.is_empty(self.valid_values): # + return self.prompt + + if not string_utils.is_empty(self.valid_values) and not constants: + raise AttributeError( + "Must pass Constants object to resolve placeholders for fields with valid_values" + ) + + resolved_prompt = self.prompt + if "{valid_values}" in resolved_prompt: + resolved_value = self.valid_values + if hasattr(constants, resolved_value): + try: + resolved_prompt = resolved_prompt.replace( + "{valid_values}", str(constants.get_constant(resolved_value)) + ) + except: + resolved_prompt = resolved_prompt.replace( + "{valid_values}", str(resolved_value) + ) + else: + resolved_prompt = resolved_prompt.replace( + "{valid_values}", str(resolved_value) + ) + # Return the updated Field object + return resolved_prompt + + def update_valid_values(self, new_valid): + self.valid_values = str(new_valid) + + def get_breakout_template(self): + import src.prompts.prompt_templates as prompt_templates + + if hasattr(prompt_templates, self.breakout_template): + return getattr(prompt_templates, self.breakout_template) + else: + raise AttributeError( + f"Breakout template '{self.breakout_template}' not found in prompt_templates module" + ) + + def get_valid_values(self, constants: Constants): + return constants.get_constant(self.valid_values) + + +class FieldSet: + def __init__(self, file_path=None, fields=None, **filters): + """ + Initialize the FieldSet instance with optional filters, file loading, and a list of fields. + + USAGE EXAMPLES: + # These all use the SAME cached data for investment_prompts.json: + FieldSet(file_path="investment_prompts.json", relationship="one_to_one") + FieldSet(file_path="investment_prompts.json", relationship="one_to_n", field_type="exhibit_level") + FieldSet(file_path="investment_prompts.json", field_type="reimbursement_level") + + # Now supports lists for any attribute: + FieldSet(file_path="investment_prompts.json", field_name=["LOB", "PROGRAM"]) + FieldSet(file_path="investment_prompts.json", field_type=["exhibit_level", "reimbursement_level"]) + + :param file_path: Path to a JSON file to load fields from (default: None). + :param fields: List of Field objects to initialize the FieldSet instance with (default: None). + :param filters: Key-value pairs for filtering fields based on their attributes. + Each value can be a single value or a list of values. + """ + self.fields = fields if fields is not None else [] + if file_path: + self.load_from_file(file_path, **filters) + + def load_from_file(self, file_path, **filters): + """Loads Fields from an external JSON file with caching and dynamic filtering + + CACHING BEHAVIOR: + - First FieldSet to load a file: Reads file and caches the parsed JSON + - Subsequent FieldSets with same file: Use cached data (no file I/O) + - Each FieldSet can still apply different filters to the same cached data + - Thread-safe: Multiple threads can safely call this simultaneously + + FILTERING BEHAVIOR: + - Single values: Field attribute must match exactly + - Lists: Field attribute must match any value in the list + - True: Field attribute must exist (not None) + + PERFORMANCE IMPACT: + - Before caching: 1000+ file reads for the same JSON → "too many open files" + - After caching: 1 file read per unique path → fast and efficient + """ + + # Thread-safe cache access + with _cache_lock: + if file_path not in _field_data_cache: + # CACHE MISS: Load the file and cache its content + with open(file_path, "r", encoding="utf-8") as file: + _field_data_cache[file_path] = json.load(file) + + # CACHE HIT: Use cached data + data = _field_data_cache[file_path] + + # Apply filters to cached data with enhanced list support + self.fields = [] + for field_dict in data: + # Check if this field_dict matches all filters + matches_all_filters = True + + for attr, filter_value in filters.items(): + field_value = field_dict.get(attr) + + # Handle special case for True filter (check if attribute exists) + if filter_value is True: + if field_value is None: + matches_all_filters = False + break + # Handle list-based filters (match any value in the list) + elif isinstance(filter_value, list): + if field_value not in filter_value: + matches_all_filters = False + break + # Handle single value filters (exact match) + elif field_value != filter_value: + matches_all_filters = False + break + + # If all filters matched, add this field + if matches_all_filters: + self.fields.append(Field(field_dict)) + + def add_field(self, field): + """Adds a new field manually to the FieldSet instance. + If field is already in the FieldSet instance, do nothing + """ + if field.field_name not in [field.field_name for field in self.fields]: + self.fields.append(field) + + def get_field(self, field_name) -> Field: + for field in self.fields: + if field.field_name == field_name: + return field + raise ValueError(f"Field '{field_name}' not found in object") + + def list_fields(self): + return [field.field_name for field in self.fields] + + def remove_field(self, field_name): + self.fields = [field for field in self.fields if field.field_name != field_name] + + def update_field_attr(self, field_name, attr, value): + for field in self.fields: + if field.field_name == field_name: + setattr(field, attr, value) + + def get_prompt_dict( + self, constants: Constants = None, field_type=None, relationship=None + ): + return { + field.field_name: field.get_prompt(constants) + for field in self.fields + if (field_type is None or field.field_type == field_type) + and (relationship is None or field.relationship == relationship) + } + + def print_prompt_dict(self, constants: Constants = None): + return "\n".join( + [ + f"{field.field_name} : {field.get_prompt(constants)}" + for field in self.fields + ] + ) + + def print(self): + """Prints all FieldInfo objects in the Prompts instance.""" + if not self.fields: + print("No fields loaded.") + return + for field in self.fields: + field.print() + + def __repr__(self): + """Returns a string representation of all fields in the FieldSet.""" + if not self.fields: + return "FieldSet: No fields loaded" + return str([field.field_name for field in self.fields]) + + def print_fields(self): + if not self.fields: + print("No fields loaded.") + return + print([field.field_name for field in self.fields]) + + def filter(self, **criteria): + """ + Filters the fields in the FieldSet based on the provided criteria. + + :param criteria: Key-value pairs where the key is the attribute name and the value is the value to filter by. + :return: A new FieldSet object containing only the fields that meet the filter criteria. + """ + filtered_fields = self.fields + for attr, value in criteria.items(): + filtered_fields = [ + field for field in filtered_fields if getattr(field, attr) == value + ] + + return FieldSet(fields=filtered_fields) + + def contains_fields(self): + return len(self.fields) > 0 + + def combine(self, other, inplace=False): + """ + Combines the fields from another FieldSet into this one, avoiding duplicates. + """ + if inplace: + for field in other.fields: + if field.field_name not in self.list_fields(): + self.fields.append(field) + else: + combined_fields = self.fields.copy() + for field in other.fields: + if field.field_name not in self.list_fields(): + combined_fields.append(field) + return FieldSet(fields=combined_fields) diff --git a/fieldExtraction/src/prompts/investment_prompts.json b/src/prompts/investment_prompts.json similarity index 100% rename from fieldExtraction/src/prompts/investment_prompts.json rename to src/prompts/investment_prompts.json diff --git a/fieldExtraction/src/prompts/prompt_templates.py b/src/prompts/prompt_templates.py similarity index 80% rename from fieldExtraction/src/prompts/prompt_templates.py rename to src/prompts/prompt_templates.py index 322184f..43763b8 100644 --- a/fieldExtraction/src/prompts/prompt_templates.py +++ b/src/prompts/prompt_templates.py @@ -1,18 +1,15 @@ - import src.config as config from src.prompts.fieldset import FieldSet from src.utils import string_utils PIPE_FORMAT_INSTRUCTIONS = "Briefly explain your answer, then enclose your final answer in |pipes|. If the requested information doesn't apply to this context, return |N/A|. If the information should exist but cannot be clearly identified, return |UNKNOWN|." -def get_cacheable_instructions(constants=None): + +def get_cacheable_instructions(): """ Returns a dictionary of all cacheable instructions for cache warming. This should be called once before parallel processing starts. - Args: - constants: Constants object (optional, needed for field prompts) - Returns: dict: Dictionary mapping cache keys to instruction text """ @@ -20,89 +17,120 @@ def get_cacheable_instructions(constants=None): cacheable_instructions = {} # REIMBURSEMENT_PRIMARY instruction - if config.FIELDS in ['all', 'one_to_n']: + if config.FIELDS in ["all", "one_to_n"]: try: - reimbursement_fields = FieldSet( - config.FIELD_JSON_PATH, field_type="reimbursement_primary" + cacheable_instructions["REIMBURSEMENT_PRIMARY"] = ( + REIMBURSEMENT_PRIMARY_INSTRUCTION() ) - if constants: - field_prompts = reimbursement_fields.print_prompt_dict(constants) - else: - field_prompts = reimbursement_fields.print_prompt_dict() - - instruction, _ = REIMBURSEMENT_PRIMARY("", field_prompts) - cacheable_instructions["REIMBURSEMENT_PRIMARY"] = instruction except Exception as e: pass # Skip if fields not available # METHODOLOGY_BREAKOUT instruction - if config.FIELDS in ['all', 'one_to_n']: + if config.FIELDS in ["all", "one_to_n"]: try: - methodology_fields = FieldSet( - config.FIELD_JSON_PATH, field_type="methodology_breakout" + cacheable_instructions["METHODOLOGY_BREAKOUT"] = ( + METHODOLOGY_BREAKOUT_INSTRUCTION() ) - if constants: - field_prompts = methodology_fields.print_prompt_dict(constants) - else: - field_prompts = methodology_fields.print_prompt_dict() + except Exception: + pass - instruction, _ = METHODOLOGY_BREAKOUT("", field_prompts) - cacheable_instructions["METHODOLOGY_BREAKOUT"] = instruction - except Exception as e: + # Secondary breakout instructions + if config.FIELDS in ["all", "one_to_n"]: + try: + cacheable_instructions["FEE_SCHEDULE_BREAKOUT"] = ( + FEE_SCHEDULE_BREAKOUT_INSTRUCTION() + ) + cacheable_instructions["GROUPER_BREAKOUT"] = GROUPER_BREAKOUT_INSTRUCTION() + except Exception: pass # OUTLIER_BREAKOUT instruction - if config.FIELDS in ['all', 'one_to_n']: + if config.FIELDS in ["all", "one_to_n"]: try: - instruction, _ = OUTLIER_BREAKOUT("") - cacheable_instructions["OUTLIER_BREAKOUT"] = instruction + cacheable_instructions["OUTLIER_BREAKOUT"] = OUTLIER_BREAKOUT_INSTRUCTION() except Exception as e: pass - + # EXHIBIT_LEVEL + LESSER_OF - if config.FIELDS in ['all', 'one_to_n']: + if config.FIELDS in ["all", "one_to_n"]: try: cacheable_instructions["EXHIBIT_LEVEL"] = EXHIBIT_LEVEL_INSTRUCTION() - cacheable_instructions["EXHIBIT_LEVEL_LESSER_OF"] = EXHIBIT_LEVEL_LESSER_OF_INSTRUCTION() + cacheable_instructions["EXHIBIT_LEVEL_LESSER_OF"] = ( + EXHIBIT_LEVEL_LESSER_OF_INSTRUCTION() + ) except Exception: pass # Validation / split / checks / relationships - if config.FIELDS in ['all', 'one_to_n']: + if config.FIELDS in ["all", "one_to_n"]: try: - cacheable_instructions["VALIDATE_REIMBURSEMENTS"] = VALIDATE_REIMBURSEMENTS_INSTRUCTION() - cacheable_instructions["SPLIT_REIMBURSEMENTS"] = SPLIT_REIMBURSEMENTS_INSTRUCTION() - cacheable_instructions["CHECK_REDUNDANT_LESSER"] = CHECK_REDUNDANT_LESSER_INSTRUCTION() + cacheable_instructions["VALIDATE_REIMBURSEMENTS"] = ( + VALIDATE_REIMBURSEMENTS_INSTRUCTION() + ) + cacheable_instructions["CHECK_REDUNDANT_LESSER"] = ( + CHECK_REDUNDANT_LESSER_INSTRUCTION() + ) cacheable_instructions["LOB_RELATIONSHIP"] = LOB_RELATIONSHIP_INSTRUCTION() except Exception: pass # Dynamic primary + carveout - if config.FIELDS in ['all', 'one_to_n']: + if config.FIELDS in ["all", "one_to_n"]: try: cacheable_instructions["DYNAMIC_PRIMARY"] = DYNAMIC_PRIMARY_INSTRUCTION() cacheable_instructions["CARVEOUT_CHECK"] = CARVEOUT_CHECK_INSTRUCTION() + cacheable_instructions["DYNAMIC_ASSIGNMENT"] = ( + DYNAMIC_ASSIGNMENT_INSTRUCTION() + ) + cacheable_instructions["LESSER_OF_DISTRIBUTION"] = ( + LESSER_OF_DISTRIBUTION_INSTRUCTION() + ) + cacheable_instructions["LESSER_OF_CHECK"] = LESSER_OF_CHECK_INSTRUCTION() except Exception: pass # TIN_NPI_TEMPLATE instruction - if config.FIELDS in ['all', 'one_to_one']: + if config.FIELDS in ["all", "one_to_one"]: try: - provider_fields = FieldSet(config.FIELD_JSON_PATH, field_type="provider_info") - field_prompts = provider_fields.print_prompt_dict() - instruction, _ = TIN_NPI_TEMPLATE("", field_prompts) - cacheable_instructions["TIN_NPI_TEMPLATE"] = instruction + cacheable_instructions["TIN_NPI_TEMPLATE"] = TIN_NPI_TEMPLATE_INSTRUCTION() except Exception as e: pass # ONE_TO_ONE templates (single and multi-field) - if config.FIELDS in ['all', 'one_to_one']: + if config.FIELDS in ["all", "one_to_one"]: try: - cacheable_instructions["ONE_TO_ONE_SINGLE_FIELD"] = ONE_TO_ONE_SINGLE_FIELD_INSTRUCTION() - cacheable_instructions["ONE_TO_ONE_MULTI_FIELD"] = ONE_TO_ONE_MULTI_FIELD_INSTRUCTION() + cacheable_instructions["ONE_TO_ONE_SINGLE_FIELD"] = ( + ONE_TO_ONE_SINGLE_FIELD_INSTRUCTION() + ) + cacheable_instructions["ONE_TO_ONE_MULTI_FIELD"] = ( + ONE_TO_ONE_MULTI_FIELD_INSTRUCTION() + ) except Exception: pass + # Preprocessing instructions (exhibit headers, linkage) + try: + cacheable_instructions["EXHIBIT_HEADER"] = EXHIBIT_HEADER_INSTRUCTION() + cacheable_instructions["EXHIBIT_LINKAGE"] = EXHIBIT_LINKAGE_INSTRUCTION() + cacheable_instructions["EXHIBIT_TITLE_MATCH"] = ( + EXHIBIT_TITLE_MATCH_INSTRUCTION() + ) + except Exception: + pass + + # Utility instructions (date fixes, provider matching) + try: + cacheable_instructions["DATE_FIX"] = DATE_FIX_INSTRUCTION() + cacheable_instructions["DERIVED_TERM_DATE"] = DERIVED_TERM_DATE_INSTRUCTION() + cacheable_instructions["CHECK_PROVIDER_NAME_MATCH"] = ( + CHECK_PROVIDER_NAME_MATCH_INSTRUCTION() + ) + cacheable_instructions["SPECIAL_CASE_ASSIGNMENT"] = ( + SPECIAL_CASE_ASSIGNMENT_INSTRUCTION() + ) + except Exception: + pass + return cacheable_instructions @@ -228,14 +256,28 @@ Here is the text to analyze: Briefly explain your answer before putting the final answer in |pipes|. """ -def REIMB_DATES_ASSIGNMENT(service_term: str, reimb_term: str, field_prompt: str, exhibit_text_simplified: str, page_num: str): + +def DYNAMIC_PRIMARY_INSTRUCTION() -> str: + return ( + "[OBJECTIVE]\n" + "Extract attribute values for dynamic fields from contract text. Use exact values and return in pipes where instructed." + ) + + +def REIMB_DATES_ASSIGNMENT( + service_term: str, + reimb_term: str, + field_prompt: str, + exhibit_text_simplified: str, + page_num: str, +): """ Specialized prompt for assigning REIMB_DATES to specific reimbursement terms. - - This is MORE SPECIFIC than the discovery prompt and focuses on assigning the + + This is MORE SPECIFIC than the discovery prompt and focuses on assigning the correct date range to each individual reimbursement term based on context. """ - + prompt = f"""[OBJECTIVE] Identify which date range applies to a specific Reimbursement Term. @@ -316,14 +358,12 @@ Then, return a properly-formatted JSON object where the key is "REIMB_DATES" and Return ONLY the single date range that applies to this term. Do NOT return multiple date ranges separated by commas. If there is no date range for this term, return "N/A". """ - + return prompt -def DYNAMIC_ASSIGNMENT(service_term: str, reimb_term: str, field_name: str, field_prompt: str, exhibit_text_simplified: str, page_num: str): - - # Set up as prompt, instruction to allow for Page-level caching later - prompt = f"""[OBJECTIVE] +def DYNAMIC_ASSIGNMENT_INSTRUCTION() -> str: + return """[OBJECTIVE] Identify which field value is associated with a given Reimbursement Term. [INSTRUCTIONS] @@ -331,7 +371,7 @@ You will be shown a Reimbursement Term, and the section of a contract from which Closely examine the contract text, find the Reimbursement Term, and decide which field value or values apply to the Reimbursement Term. CRITICAL CONSIDERATIONS: -1. Look for what {field_name} the Service actually *applies to*. This is not the same as the Schedule used as a basis for calculation. For example, many LOBs use Medicaid as a basis for their calculation. The presence of 'Medicaid' as a rate does not on it's own guarantee that the Reimbursement Term is 'Medicaid'. +1. Look for what field the Service actually *applies to*. This is not the same as the Schedule used as a basis for calculation. For example, many LOBs use Medicaid as a basis for their calculation. The presence of 'Medicaid' as a rate does not on it's own guarantee that the Reimbursement Term is 'Medicaid'. 2. USE THE SERVICE_TERM AS PRIMARY CONTEXT: The Service Term shows which programs are mentioned together. If the Service Term explicitly lists specific programs (e.g., "STAR, CHIP HMO, CHIP PERINATE, and STAR+PLUS"), those are the programs that apply to reimbursement terms in that section. Do NOT assign programs that are mentioned in completely separate sections of the contract. @@ -339,18 +379,31 @@ CRITICAL CONSIDERATIONS: 4. AVOID CROSS-CONTAMINATION: If the Service Term mentions Medicaid programs (STAR, CHIP, CHIPP, STAR+PLUS, etc.), do NOT assign Medicare programs (MA, MASNP) unless they are explicitly mentioned together in the same context. Similarly, if the Service Term mentions Medicare programs, do NOT assign Medicaid programs unless explicitly mentioned together. -5. "ALL PROGRAMS" AMBIGUITY - CRITICAL: If you see phrases like "for all Health Plan products & programs" in a table or section, this phrase means "all programs in THIS SECTION", NOT "all programs in the entire document". +5. "ALL PROGRAMS" AMBIGUITY - CRITICAL: If you see phrases like "for all Health Plan products & programs" in a table or section, this phrase means "all programs in THIS SECTION", NOT "all programs in the entire document". - If the table appears AFTER a section that says "STAR, CHIP HMO, CHIP PERINATE, and STAR+PLUS" and BEFORE a section that says "Medicare Advantage", the table applies ONLY to the Medicaid programs (STAR, CHIP, CHIPP, STAR+PLUS) mentioned in that section. - If the table appears AFTER a section that says "Medicare Advantage", the table applies ONLY to the Medicare programs mentioned in that section. - - NEVER assign programs from separate sections just because you see "all programs" - always determine which section the reimbursement term belongs to based on its position in the document. + - NEVER assign programs from separate sections just because you see "all programs" - always determine which section the reimbursement term belongs to based on its position in the document.""" -[CONTEXT] + +def DYNAMIC_ASSIGNMENT( + service_term: str, + reimb_term: str, + field_name: str, + field_prompt: str, + exhibit_text_simplified: str, + page_num: str, +): + """ + Returns prompt for dynamic assignment extraction. + Call DYNAMIC_ASSIGNMENT_INSTRUCTION() separately for the cached instruction. + """ + return f"""[CONTEXT] Here is the section of the contract. Examine this section closely and pick the correct answer or answers for the given Reimbursement Term. [START CONTEXT] {exhibit_text_simplified} [END CONTEXT] -""" - instruction = f"""[REIMBURSEMENT_TERM] + +[REIMBURSEMENT_TERM] Here is the Reimbursement Term to analyze. You can find it on page {page_num} of the text. Service Term: "{service_term}" Reimbursement Term: "{reimb_term}" @@ -361,13 +414,25 @@ Here is the definition and valid values. Use this information to help you find t [OUTPUT FORMAT] Briefly explain your answer, return a properly-formatted JSON object where the key is the field name `{field_name}` and the value is the correct answer. If there is more than one correct answer, return them in a comma-separated list. If there is no correct answer, return 'N/A' - """ - - return prompt + instruction +""" def REIMBURSEMENT_PRIMARY(context): - instruction = f"""[OBJECTIVE] + """ + Returns prompt for reimbursement primary extraction. + Call REIMBURSEMENT_PRIMARY_INSTRUCTION() separately for the cached instruction. + """ + return f""" +[START CONTEXT] +{context.replace('"', "'")} +[END CONTEXT] + +Briefly talk through your reasoning. Then return a properly formatted JSON list of dictionaries with all extracted SERVICE_TERM AND REIMB_TERM values. +""" + + +def REIMBURSEMENT_PRIMARY_INSTRUCTION() -> str: + return """[OBJECTIVE] Extract Reimbursement Terms from a section of a payer-provider contract The output from this prompt will be used to populate downstream fields in the system. @@ -387,7 +452,7 @@ REIMB_TERM: Describes the method by which the price of the Service is calculated - ALWAYS include all relevant percentages and dollar values. If there's even a slight chance that the number is relevant, include it. - For each REIMB_TERM, include any additional information mentioned that will be useful in determining reimbursement for the service, e.g., "payment amount will be determined by multiplying it by the DRG weight". It should be appended to relevant REIMB_TERM and not added as a separate entry. - If different reimbursement percentages or dollar values are mentioned for different effective dates, create separate entries for each effective date. -- For the tables: Extract EVERY ROW as a separate entry, including all line items, subtotals, totals, adjustments, charges, and calculated ratios. When rows involve different providers/entities, create separate entries for EACH provider/entity and include the provider/entity name in the SERVICE_TERM (e.g., “Provider Name – Service Category”). +- For the tables: Extract EVERY ROW as a separate entry, including all line items, subtotals, totals, adjustments, charges, and calculated ratios. When rows involve different providers/entities, create separate entries for EACH provider/entity and include the provider/entity name in the SERVICE_TERM (e.g., "Provider Name – Service Category"). [EXCLUSIONS] - NEVER return reimbursement terms that are labeled as Examples or appear in an EXAMPLE section. These are not actual reimbursements and should not be included in the output. @@ -400,97 +465,210 @@ Some types of Reimbursements are special and require additional thought. [ANALYSIS CONTEXT]""" - prompt = f""" -[START CONTEXT] -{context.replace('"', "'")} -[END CONTEXT] -Briefly talk through your reasoning. Then return a properly formatted JSON list of dictionaries with all extracted SERVICE_TERM AND REIMB_TERM values. +def LESSER_OF_DISTRIBUTION_INSTRUCTION() -> str: + return """TASK: Identify "lesser of" or "not to exceed" statements that apply to a service. + +DEFINITIONS: +"Lesser of" / "not to exceed" = overarching payment rules specifying payment at the lesser of multiple values or capped amounts. +Examples: "lesser of rates below and billed charges", "shall not exceed 110% of Medicare" + +DECISION LOGIC: + +0. UNDERSTAND THE TASK + + We are looking for overarching "lesser of" or "not to exceed" constraints that apply to SERVICE. + METHODOLOGY is the base rate — we may wrap it with constraints we find. + +1. COLLECT APPLICABLE STATEMENTS + + From cross-exhibit templates (if provided): + → Include these—they're already verified to apply. + + From intra-exhibit text: + → INCLUDE statements referencing "this exhibit", "rates below", "contracted rates" (generic) + → EXCLUDE any statement that references a specific exhibit name (Attachment A, Schedule B, Exhibit 2, etc.) + + CRITICAL: If a lesser-of statement mentions "Attachment A", "Schedule B", or any exhibit name → IGNORE IT. + Example to IGNORE: "lesser of payment rates established in Attachment A or 100% of Medicare" + Example to USE: "lesser of contracted rates or billed charges" + +2. FILTER BY SERVICE SCOPE + + Keep only statements whose scope matches SERVICE: + - "All services in this exhibit" → applies to any service + - "Inpatient services only" → does NOT apply to outpatient services + + If nothing applies → return N/A + +3. COMBINE & FORMAT + + Substitution rules: + - Replace generic "rates" / "contracted rates" with METHODOLOGY value + - Preserve original "lesser of" phrasing (don't add if not present) + - Join multiple terms: "lesser of X, Y, or Z" + +OUTPUT FORMAT: +|[SERVICE] paid at [combined statement]| + +Examples: +- |Lab Test paid at lesser of $100, billed charges, or 110% Medicare| +- |Radiology paid at $250 or charges| +- |N/A| + +Example — Intra-exhibit statement references another exhibit → N/A: +- METHODOLOGY: "per visit basis at payment rates established in Attachment A" +- CROSS-EXHIBIT TEMPLATES: None +- EXHIBIT TEXT contains: "lesser of payment rates established in Attachment A or 100% of Medicare" +- Analysis: The only lesser-of statement found references "Attachment A" → IGNORE IT +- Result: |N/A| (no applicable statements remain) + +RETURN N/A WHEN: +- No applicable lesser-of statements found +- All statements found reference other exhibits by name (and no cross-exhibit templates provided) +- Statements found but scoped to different service types""" + + +def LESSER_OF_DISTRIBUTION( + service_term: str, + reimb_term: str, + page_num: str, + exhibit_text: str, + cross_exhibit_lesser_of: list[dict], +): + """ + Returns prompt for lesser-of distribution. + Call LESSER_OF_DISTRIBUTION_INSTRUCTION() separately for the cached instruction. + """ + # Format cross-exhibit templates + if cross_exhibit_lesser_of: + cross_exhibit_text = "\n".join( + [ + f"- {stmt['reimb_term']} (scope: {stmt['scope']}, page {stmt.get('page_num', 'unknown')})" + for stmt in cross_exhibit_lesser_of + ] + ) + cross_exhibit_section = f""" +CROSS-EXHIBIT TEMPLATES (pre-verified, include if applicable): +{cross_exhibit_text} +""" + else: + cross_exhibit_section = "CROSS-EXHIBIT TEMPLATES: None" + + return f"""INPUTS: +- SERVICE: {service_term} +- METHODOLOGY: {reimb_term} +- PAGE: {page_num} +- {cross_exhibit_section} + +EXHIBIT TEXT: +{exhibit_text} + +--- + +Analyze the inputs above. Briefly explain your reasoning, then provide your final answer in pipes. """ - return instruction, prompt -def LESSER_OF_DISTRIBUTION(service_term: str, reimb_term: str, exhibit_text_simplified: str, page_num: str): - return f"""[OBJECTIVE] -Examine an Exhibit of a Payer-Provider contract. Find any overarching 'Lesser of' or 'not to exceed' statements that apply to the given Reimbursement Term. +def LESSER_OF_CHECK_INSTRUCTION() -> str: + return """Classify lesser-of payment statements from healthcare contracts. -['LESSER OF' OR 'NOT TO EXCEED' LANGUAGE] -They specify that a given medical Service should be paid at the lesser of two or more values or should not exceed a value (e.g. billed charges). Sometimes they are written clearly, other times there will be one sentence that applies to the entire Exhibit, or a portion of the Exhibit. Your job is to find such a statement (if it exists) and determine if it applies to the given Service. +**IMPORTANT: Check BOTH Service AND Reimbursement fields for exhibit references.** -This involves 3 steps: -[1. IDENTIFY OVERARCHING 'LESSER OF' OR 'NOT TO EXCEED' STATEMENTS] -There may be one or more overarching 'Lesser of' statements. Such statements will include language like: -- '...lesser of the rates listed below and ...' -- 'All services under this exhibit are subject to the lesser of...' -- 'Except as otherwise provided in this Exhibit, the Allowed Amount for Covered Services shall be the lesser of...' -- 'Payment for any service in this exhibit shall not exceed...' -- 'At no time shall Plan pay an amount that exceeds...' +**Classification Rules (check in order):** -[2. DETERMINE IF THE STATEMENT APPLIES TO THE SERVICE] -If there are multiple overarching lesser of/ not to exceed statements, it is crucial to NOT assign the one that doesn't apply to this particular service. -Look carefully to ensure that the intended meaning of the text is to apply a Lesser of/ not to exceed to the given Service. +1. **EXHIBIT_SPECIFIC (OTHER)** - References a different specific exhibit + - Check BOTH fields for: "contained in [Exhibit]", "in Attachment [X]", "for [Schedule] services", "described in [Appendix]" + - Extract exact exhibit name → exhibit_reference -[3. DISTRIBUTE THE LESSER OF/ NOT TO EXCEED STATEMENT to THE SERVICE AND METHODOLOGY PAIR] -If you find that an overarching 'Lesser of' or 'not to exceed' statement applies to the given Service, you'll need to perform a concatenation (or substitution if required) to create one meaningful statement. This is the 'Lesser of'/ 'not to exceed' distribution. +2. **EXHIBIT_SPECIFIC (CURRENT)** - References only this exhibit + - Phrases: "this exhibit", "rates below", "in this schedule" -For example, if you see "The Services in this exhibit will be paid at the lesser of the rates listed below and 100% of Billed Charges" -and you determine that the above statement applies to the terms below: -SERVICE: "Radiology Services" -METHODOLOGY:"$100" -then you need to concatenate the SERVICE and METHODOLOGY values appropriately, for a final answer of: -"Radiology Services will be paid at the lesser of $100 and 100% of Billed Charges" +3. **STANDALONE** - Complete rate with both options AND a specific service/CPT code + - Both amounts/rates fully specified + - Service is specific (e.g., "MRI", "CPT 70450", "Office Visit Level 3") + - NOT generic terms like "All Services", "Covered Services", "Services" + - No external references -[CONTEXT] -Here is the Service and Methodology to evaluate: -SERVICE: {service_term} -METHODOLOGY: {reimb_term} +4. **GLOBAL** - Applies to entire contract + - Phrases: "all services under this Agreement", "unless otherwise specified" + - NO specific exhibit/attachment/schedule mentions in EITHER field -Here is the Exhibit Text (the Service can be found on page {page_num}): -[START TEXT] -{exhibit_text_simplified} -[END TEXT] +**Examples:** -[OUTPUT FORMAT] -If there is no overarching lesser of Statement, return 'N/A' -If there is an overarching lesser of Statement, but it doesn't apply to the Service, return 'N/A'. -If there is an overarching lesser of Statement that applies, return the full Statement with the Service and Methodology appropriately concatenated. +Service: "services described in Attachment B - Facility Services" +Reimbursement: "payment shall be at lesser of contracted rates or 100% of billed charges" +→ EXHIBIT_SPECIFIC (OTHER), exhibit_reference: "Attachment B - Facility Services" -Briefly explain your answer, then put your final answer in pipes. -""" +Service: "services contained in Attachment A - Professional Services" +Reimbursement: "payment shall not exceed 110% Medicare" +→ EXHIBIT_SPECIFIC (OTHER), exhibit_reference: "Attachment A - Professional Services" -def LESSER_OF_CHECK(service_term: str, reimb_term: str): - return f"""[OBJECTIVE] -Examine the following 'lesser of' statement, taken from the Compensation Schedule of a Payer-Provider contract. -Determine if the statement is an overarching 'lesser of' +Service: "All covered services" +Reimbursement: "All services under this Agreement paid at lesser of rates or charges" +→ GLOBAL (no exhibit mentioned in either field) + +Service: "Services" +Reimbursement: "Services in this exhibit: lesser of rates below or Medicare" +→ EXHIBIT_SPECIFIC (CURRENT) + +Service: "MRI" +Reimbursement: "lesser of $1000 or Medicare" +→ STANDALONE + +**CRITICAL: If you see ANY exhibit/attachment/schedule name in EITHER the Service OR Reimbursement field, it CANNOT be GLOBAL - it must be EXHIBIT_SPECIFIC (OTHER).**""" + + +def LESSER_OF_CHECK(service_term: str, reimb_term: str, exhibit_title: str): + """ + Returns prompt for lesser-of check classification. + Call LESSER_OF_CHECK_INSTRUCTION() separately for the cached instruction. + """ + return f"""**Current Exhibit:** {exhibit_title} +**Service:** {service_term} +**Reimbursement:** {reimb_term} + +**Output JSON in |pipes|:** +{{ + "service_term": "{service_term}", + "reimb_term": "{reimb_term}", + "scope": "GLOBAL" | "EXHIBIT_SPECIFIC" | "STANDALONE", + "target_exhibit": "ALL" | "CURRENT" | "OTHER" | null, + "exhibit_reference": "" +}} + +Briefly explain, then return JSON in |pipes|.""" + + +def EXHIBIT_TITLE_MATCH_INSTRUCTION() -> str: + return ( + "[OBJECTIVE]\n" + "Determine if two exhibit references refer to the same exhibit. Consider exact, partial, and descriptive matches.\n" + "Return YES or NO in pipes." + ) + + +def EXHIBIT_TITLE_MATCH(current_exhibit_title: str, target_exhibit_reference: str): + """ + Returns prompt for exhibit title matching. + Call EXHIBIT_TITLE_MATCH_INSTRUCTION() separately for the cached instruction. + """ + return f"""[CONTEXT] +Current Exhibit Title: "{current_exhibit_title}" +Target Exhibit Reference: "{target_exhibit_reference}" [INSTRUCTIONS] -Overarching 'Lesser of' statements are those which do not stand alone as a meaningful statement and instead refer to Services elsewhere in the document. -They may include language like "for all Services in this Exhibit...", "for the rates listed below...", and other language that refers specifically to Services located in other part of the Exhibit. -This is in contrast to a Stand-Alone 'lesser of' statement, which makes sense as a complete statement by itself. - -The distinction between the two options can be subtle. Here are two examples to illustrate: -[Y Example] -Service: "Covered Services" -Reimbursement: "Covered Services in this Exhibit will be paid at the lesser of a) the rates listed below or b) 100% of the Medicare fee schedule. -Answer: "Y" -This is an overarching lesser of because it makes specific references to rates elsewhere in the document. - -[N Example] -Service: "Covered Services" -Reimbursement: "Except as otherwise mentioned, Covered Services in this Exhibit will be paid at the lesser of a) Allowable Charges or b) 100% of the Medicare fee schedule" -Answer: "N" -This is not an overarching lesser of because both rates presented are present in the Reimbursement itself. There are no references to rates elsewhere (the 'except as otherwise mentioned' clause is an exclusion, which is different) - - -[CONTEXT] -Service: {service_term} -Reimbursement: {reimb_term} +Determine if these refer to the same exhibit. Consider: +- Exact matches: "Exhibit B" matches "Exhibit B" +- Partial matches: "Exhibit B" matches "Exhibit B - Outpatient Services" +- Descriptive matches: "Outpatient Services" matches "Exhibit B - Outpatient Services" +- Different identifiers: "Exhibit A" does NOT match "Exhibit B" +- Different services: "Inpatient Services" does NOT match "Outpatient Services" [OUTPUT FORMAT] -- If the Service and Reimbursement Term represent an overarching 'lesser of', return 'Y' -- If the Service and Reimbursement Term are a stand-alone 'lesser of', return 'N' +Return ONLY "YES" or "NO" in |pipes|. -Briefly explain your answer, then put your final answer in |pipes|. +Briefly explain your reasoning, then return your answer in |pipes|. """ @@ -498,14 +676,29 @@ Briefly explain your answer, then put your final answer in |pipes|. ################################# BREAKOUT PROMPTS ################################## ##################################################################################### + def METHODOLOGY_BREAKOUT(service_term: str, reimb_term: str, questions: str): """ - This prompt is used for the fields with field_type="methodology_breakout" + any other fields we need to run based on the result of special case. + Returns prompt for methodology breakout extraction. + Call METHODOLOGY_BREAKOUT_INSTRUCTION() separately for the cached instruction. All fields run by this prompt will end up becoming their own row, rather than being distributed across the rows of the exhibit """ + prompt = f"""Here is the text to analyze and respond to: +Service Term: {service_term} +Reimbursement Term: {reimb_term} - instruction = f"""[OBJECTIVE] +[OUTPUT FORMAT] +Explain your reasoning as you work through the context. After your explanation, include the heading "FINAL REIMBURSEMENT METHODOLOGY:" followed by a properly formatted JSON list with your final output.""" + + # Include dynamic fields in the prompt (not instruction) for cache reuse + prompt += f"\n\n[FIELDS]\nPopulate a list of JSON dictionaries with the following fields:\n{questions}\n" + + return prompt + + +def METHODOLOGY_BREAKOUT_INSTRUCTION() -> str: + return """[OBJECTIVE] Analyze a given term from a Payer-Provider contract and extract key fields. [INSTRUCTION] @@ -531,17 +724,13 @@ For any fields that don't apply to a particular methodology, use "N/A" as the va [CONTEXT]""" - prompt = f"""Here is the text to analyze and respond to: -Service Term: {service_term} -Reimbursement Term: {reimb_term} -[OUTPUT FORMAT] -Explain your reasoning as you work through the context. After your explanation, include the heading "FINAL REIMBURSEMENT METHODOLOGY:" followed by a properly formatted JSON list with your final output.""" - - # Include dynamic fields in the prompt (not instruction) for cache reuse - prompt += f"\n\n[FIELDS]\nPopulate a list of JSON dictionaries with the following fields:\n{questions}\n" - - return instruction, prompt +def FEE_SCHEDULE_BREAKOUT_INSTRUCTION() -> str: + return ( + "[OBJECTIVE]\n" + "Extract fee schedule-specific attributes from a reimbursement methodology into JSON fields.\n" + "Use explicit contract language only and return 'N/A' when information is missing." + ) def FEE_SCHEDULE_BREAKOUT(methodology, fee_schedule, questions): @@ -562,6 +751,14 @@ Write your JSON dictionary below: """ +def GROUPER_BREAKOUT_INSTRUCTION() -> str: + return ( + "[OBJECTIVE]\n" + "Extract grouper-based reimbursement attributes from service and reimbursement terms into JSON fields.\n" + "Use exact contract terminology and return 'N/A' when information is missing." + ) + + def GROUPER_BREAKOUT(service, term, questions): return f"""[OBJECTIVE] Analyze the given service and reimbursement term to identify grouper-based reimbursement information, and answer the following question(s): @@ -630,24 +827,32 @@ def TRIGGER_CAP_BREAKOUT(term): return SPECIAL_CASE_BREAKOUT(term, questions) +def OUTLIER_BREAKOUT_INSTRUCTION() -> str: + return ( + "[OBJECTIVE]\n" + "Analyze a healthcare payer-provider contract to extract outlier payment information. " + "Outlier payments are additional supplemental reimbursements triggered when claims exceed " + "predetermined thresholds for cost, length of stay, or resource utilization.\n\n" + "**Extraction Guidelines:**\n" + "- Extract exact field values (numbers, percentages, dollar amounts) as specified\n" + "- Convert time units to days when requested (e.g., 'two weeks' = '14')\n" + "- Include code types when extracting exclusions (e.g., 'CPT 12345')\n" + "- For frequency fields, use exact contract language (e.g., 'per admission', 'per day')\n" + "- Base answers ONLY on information explicitly stated or directly inferable from the contract text" + ) + + def OUTLIER_BREAKOUT(term): + """ + Returns prompt for outlier breakout extraction. + Call OUTLIER_BREAKOUT_INSTRUCTION() separately for the cached instruction. + """ questions = FieldSet( config.FIELD_JSON_PATH, field_type="outlier_breakout" ).print_prompt_dict() - instruction = f"""[OBJECTIVE] -Analyze a healthcare payer-provider contract to extract outlier payment information. Outlier payments are additional supplemental reimbursements triggered when claims exceed predetermined thresholds for cost, length of stay, or resource utilization. - -**Extraction Guidelines:** -- Extract exact field values (numbers, percentages, dollar amounts) as specified -- Convert time units to days when requested (e.g., 'two weeks' = '14') -- Include code types when extracting exclusions (e.g., 'CPT 12345') -- For frequency fields, use exact contract language (e.g., 'per admission', 'per day') -- Base answers ONLY on information explicitly stated or directly inferable from the contract text -""" - - prompt = f""" -[FIELDS] + return f"""[FIELDS] +Populate a JSON dictionary with the following fields: {questions} [CONTEXT] @@ -657,7 +862,6 @@ Here is the text to analyze and respond to: [OUTPUT FORMAT] Briefly explain your answer, then provide the extracted outlier payment information in JSON format. For any information not found in the Term, return 'N/A'""" - return instruction, prompt def FACILITY_ADJUSTMENT_BREAKOUT(term): questions = FieldSet( @@ -826,7 +1030,7 @@ def FILL_BILL_TYPE(service, choices, reimb_term=None, exhibit_text=None): Here is the Reimbursement Term associated with the Service Term: {reimb_term.replace('"', "'")} """ - + # Build exhibit context section conditionally exhibit_context_section = "" if exhibit_text: @@ -835,7 +1039,7 @@ Here is the Reimbursement Term associated with the Service Term: If the Service Term and Reimbursement Term together do not provide sufficient information, examine the following exhibit text for additional context about where the service is performed: {exhibit_text.replace('"', "'")} """ - + return f"""Analyze a given medical Service Term. What Bill Type Code Description does the Service Term fall under? @@ -887,17 +1091,13 @@ def ONE_TO_ONE_SINGLE_FIELD_INSTRUCTION() -> str: ) -def TIN_NPI_TEMPLATE(context, questions, payer_name): - payer_instruction = "" - if not string_utils.is_empty(payer_name): - payer_instruction = f'\n\nIMPORTANT: "{payer_name}" is the PAYER (insurance company) in this contract. Do NOT extract TIN or NPI information for "{payer_name}" - only extract information for healthcare providers who deliver services.' - - instruction = f""" +def TIN_NPI_TEMPLATE_INSTRUCTION() -> str: + return """ Analyze the following healthcare payer-provider contract text and extract provider entities - these are healthcare providers who deliver services, NOT payers/insurance companies who reimburse for services. IMPORTANT DISTINCTION: - Providers: Physicians, physician groups, hospitals, clinics who DELIVER healthcare -- Payers: Insurance companies, health plans who PAY for healthcare services{payer_instruction} +- Payers: Insurance companies, health plans who PAY for healthcare services CRITICAL: If a provider has multiple TINs or NPIs, include ALL of them separated by pipes (|) in the same provider record. Do NOT create separate records for the same provider entity. @@ -910,7 +1110,7 @@ Briefly explain your reasoning. After your explanation, include the heading "FIN [EXTRACTION AND FORMATTING INSTRUCTIONS] - First, analyze the text thoroughly and identify all provider entities - Return TIN and NPIs that are found on the page even if they aren't explicitly labeled as such. -- IMPORTANT VALIDATION REQUIREMENTS: +- IMPORTANT VALIDATION REQUIREMENTS: * TIN must be exactly 9 digits (no more, no less) * NPI must be exactly 10 digits (no more, no less) * Double-check the digit count for each TIN and NPI before including them in the response @@ -926,26 +1126,38 @@ Briefly explain your reasoning. After your explanation, include the heading "FIN Example of correct format: FINAL PROVIDER INFO: [ - {{ + { "TIN": "123456789", "NPI": "1234567890", "NAME": "Main Provider Group" - }}, - {{ + }, + { "TIN": "987654321", "NPI": null, "NAME": "Dr. John Smith", - }}, - {{ + }, + { "TIN": null, "NPI": "1234567890", "NAME": "Jane Doe, CRNA" - }} + } ] Contract text:""" - prompt = f""" + +def TIN_NPI_TEMPLATE(context, questions, payer_name): + """ + Returns prompt for TIN/NPI extraction. + Call TIN_NPI_TEMPLATE_INSTRUCTION() separately for the cached instruction. + """ + # Build payer-specific instruction for the prompt + payer_instruction = "" + if not string_utils.is_empty(payer_name): + payer_instruction = f'\n\nIMPORTANT: "{payer_name}" is the PAYER (insurance company) in this contract. Do NOT extract TIN or NPI information for "{payer_name}" - only extract information for healthcare providers who deliver services.' + + return f"""[PAYER CONTEXT]{payer_instruction} + [FIELDS TO EXTRACT] {questions} @@ -953,8 +1165,6 @@ Contract text: {context.replace('"', "'" )} """ - return instruction, prompt - def GROUP_TIN_NPI_TEMPLATE(key_sections: str, provider_list: str) -> str: return f""" @@ -988,20 +1198,39 @@ def GROUP_TIN_NPI_TEMPLATE(key_sections: str, provider_list: str) -> str: Feel free to justify your answer, but enclose your final answer in |pipes|. """ + + def FULL_CONTEXT_CLAIM_TYPES_ADDITIONAL_INSTRUCTION(): return "Additionally Check the contract text for the provider name from the preamble or signature section to help determine the claim type." + def FULL_CONTEXT_ADDITIONAL_INSTRUCTIONS(allow_na): if allow_na: return " Only provide an answer if that answer clearly applies to the ENTIRE contract. Otherwise, answer N/A. If there are multiple correct answers, return them in a pipe (|) separated list." else: return " Do NOT leave this field N/A. Choose the most appropriate answer based on the context. If there are multiple answers, return them in a pipe (|) separated list." + def FULL_CONTEXT_PAYER_NAME_ADDITIONAL_INSTRUCTION(): return " Additionally check the contract text for the payer name or payer organization name or payer entity or name of organization issuing the health plan/policy and Choose the most appropriate answer based on the context." -def CHECK_PROVIDER_NAME_MATCH_PROMPT(provider_name: str, hybrid_smart_chunking_provider_group_name: str) -> str: - """Create prompt for LLM-based provider name matching.""" + +def CHECK_PROVIDER_NAME_MATCH_INSTRUCTION() -> str: + return ( + "[OBJECTIVE]\n" + "Determine if two provider names refer to the same healthcare organization.\n" + "Consider legal suffixes, D/B/A variations, acronyms, and common word variations.\n" + "Return Y or N in pipes." + ) + + +def CHECK_PROVIDER_NAME_MATCH_PROMPT( + provider_name: str, hybrid_smart_chunking_provider_group_name: str +) -> str: + """ + Create prompt for LLM-based provider name matching. + Call CHECK_PROVIDER_NAME_MATCH_INSTRUCTION() separately for the cached instruction. + """ return f"""Determine if the provider name matches any of the healthcare organizations listed. PROVIDER NAME A: {provider_name} @@ -1024,6 +1253,7 @@ CRITICAL - DO NOT MATCH: Briefly explain your reasoning. Then return ONLY 'Y' (match found) or 'N' (no match found). Enclose your final answer in |pipes|""" + def ONE_TO_ONE_MULTI_FIELD_TEMPLATE(context, questions: dict[str, str]): return f"""The following is a contract (or excerpt thereof). Answer the following questions: {questions} @@ -1064,7 +1294,19 @@ def ONE_TO_ONE_MULTI_FIELD_INSTRUCTION() -> str: ##################################################################################### +def EXHIBIT_HEADER_INSTRUCTION() -> str: + return ( + "[OBJECTIVE]\n" + "Extract exhibit/attachment header identifiers from contract page excerpts.\n" + "Return full header text in pipes, or N/A if no header found." + ) + + def EXHIBIT_HEADER(context, EXHIBIT_HEADER_MARKERS): + """ + Returns prompt for exhibit header extraction. + Call EXHIBIT_HEADER_INSTRUCTION() separately for the cached instruction. + """ return f"""Analyze the following contract excerpt and extract the full header found. Capture the complete hierarchy of document identifiers present in the text. The following keywords and phrases should be considered as exhibit/attachment headers: @@ -1098,9 +1340,20 @@ Enclose your final answer in |pipes|, followed by a brief explanation. """ -def EXHIBIT_LINKAGE(header1, header2): - return f""" +def EXHIBIT_LINKAGE_INSTRUCTION() -> str: + return ( + "[OBJECTIVE]\n" + "Determine if two exhibit headers are meaningfully different from each other.\n" + "Return Y if different, N if same or continuation. Answer in pipes." + ) + +def EXHIBIT_LINKAGE(header1, header2): + """ + Returns prompt for exhibit linkage comparison. + Call EXHIBIT_LINKAGE_INSTRUCTION() separately for the cached instruction. + """ + return f""" [INSTRUCTIONS] * Determine whether the two Headers are meaningfully different from each other. * The headers may refer to Attachment, Exhibit, Schedule, Addendum, or similar. If the highest-level number is identical, then the Headers ARE meaningfully different. For example, "Exhibit B-1" and "Exhibit B-2" are meaningfully different because they are both Exhibit B but have different sub-exhibits. @@ -1190,6 +1443,10 @@ def VALIDATE_REIMBURSEMENTS_INSTRUCTION() -> str: def DATE_FIX_PROMPT(context: str) -> str: + """ + Returns prompt for date formatting. + Call DATE_FIX_INSTRUCTION() separately for the cached instruction. + """ return f"""Given a date string, convert it to YYYY/MM/DD format following these rules: Input: Text potentially containing a date Output: Date in YYYY/MM/DD format, or input if it's a duration, or "N/A" if ambiguous/incomplete @@ -1235,6 +1492,14 @@ Please analyze this date: """ +def DATE_FIX_INSTRUCTION() -> str: + return ( + "[OBJECTIVE]\n" + "Convert date strings to YYYY/MM/DD format. Handle durations, ambiguous dates, and American format assumptions.\n" + "Return result in pipes." + ) + + def CHECK_REDUNDANT_LESSER(reimb_term, exhibit_lesser_of): return f"""You are analyzing whether an exhibit-level lesser-of constraint is semantically redundant with a reimbursement methodology. @@ -1263,8 +1528,16 @@ Answer YES only if the exhibit constraint adds NO additional limitation beyond w Briefly explain your reasoning, then return YES or NO in |pipes|.""" +def CHECK_REDUNDANT_LESSER_INSTRUCTION() -> str: + return ( + "[OBJECTIVE]\n" + "Decide if two texts are semantically redundant with respect to 'lesser of' meaning. Return YES/NO in pipes." + ) -def CARVEOUT_CHECK(service_term: str, reimb_term: str, carveout_definitions, special_case_definitions): + +def CARVEOUT_CHECK( + service_term: str, reimb_term: str, carveout_definitions, special_case_definitions +): return f""" [OBJECTIVE] Examine the Reimbursement Term and identify which case it falls under. @@ -1291,10 +1564,10 @@ Briefly explain your answer (including why it was one of carveout cases or speci """ -def CHECK_REDUNDANT_LESSER_INSTRUCTION() -> str: +def CARVEOUT_CHECK_INSTRUCTION() -> str: return ( "[OBJECTIVE]\n" - "Decide if two texts are semantically redundant with respect to 'lesser of' meaning. Return YES/NO in pipes." + "Determine if a carve-out applies for a service given a base reimbursement. Return result in pipes as instructed." ) @@ -1371,27 +1644,6 @@ Return the dates in the following JSON format: Note: Use "N/A" for dates that cannot be determined or extracted from the input text.""" -def SPLIT_REIMBURSEMENTS_INSTRUCTION() -> str: - return ( - "[OBJECTIVE]\n" - "Split a compound reimbursement term into distinct components using only explicit contract text." - ) - - -def DYNAMIC_PRIMARY_INSTRUCTION() -> str: - return ( - "[OBJECTIVE]\n" - "Extract attribute values for dynamic fields from contract text. Use exact values and return in pipes where instructed." - ) - - -def CARVEOUT_CHECK_INSTRUCTION() -> str: - return ( - "[OBJECTIVE]\n" - "Determine if a carve-out applies for a service given a base reimbursement. Return result in pipes as instructed." - ) - - def LOB_RELATIONSHIP(exhibit_text, dynamic_primary_values): return f"""Analyze the exhibit from a Payer-Provider contract. @@ -1423,22 +1675,6 @@ Your final answer MUST be enclosed in pipe delimiters: |Inclusive| or |Exclusive """ -def DERIVED_TERM_DATE_PROMPT( - effective_date: str = None, termination_information: str = None -) -> str: - """ - Generates a prompt to extract the termination date from a legal contract. - - Args: - effective_date (str, optional): The effective date of the contract. Defaults to None. - termination_information (str, optional): Information regarding the termination of the contract. Defaults to None. - - Returns: - str: A formatted string prompt requesting the termination date of the contract. - """ - return f"The following are excerpts from a legal contract related to effective and termination dates. Determine the initial termination date of the contract, excluding any renewals or extensions.\nIf termination information comes in as a duration, derive the termination date exclusive of the final day. For example, if effective date is 2023/02/01 and termination information is 'two years', termination date would be 2025/01/31 and not 2025/02/01. If effective date is 2023/02/01 and termination information is 'year-to-year', termination date would be 2024/01/31.\nIf the termination information comes in as a date, return that date. For example, if effective date is 2023/02/01 and termination information is 2024/07/01, return 2024/07/01.\nEffective Date: {effective_date}\nTermination Information: {termination_information}\nOnly provide the first termination date, ignoring any automatic or optional renewals. Provide the date in YYYY/MM/DD format only. \n{PIPE_FORMAT_INSTRUCTIONS}" - - def LOB_RELATIONSHIP_INSTRUCTION() -> str: return ( "[OBJECTIVE]\n" @@ -1452,9 +1688,38 @@ def LOB_RELATIONSHIP_INSTRUCTION() -> str: ) +def DERIVED_TERM_DATE_PROMPT( + effective_date: str = None, termination_information: str = None +) -> str: + """ + Generates a prompt to extract the termination date from a legal contract. + Call DERIVED_TERM_DATE_INSTRUCTION() separately for the cached instruction. + + Args: + effective_date (str, optional): The effective date of the contract. Defaults to None. + termination_information (str, optional): Information regarding the termination of the contract. Defaults to None. + + Returns: + str: A formatted string prompt requesting the termination date of the contract. + """ + return f"The following are excerpts from a legal contract related to effective and termination dates. Determine the initial termination date of the contract, excluding any renewals or extensions.\nIf termination information comes in as a duration, derive the termination date exclusive of the final day. For example, if effective date is 2023/02/01 and termination information is 'two years', termination date would be 2025/01/31 and not 2025/02/01. If effective date is 2023/02/01 and termination information is 'year-to-year', termination date would be 2024/01/31.\nIf the termination information comes in as a date, return that date. For example, if effective date is 2023/02/01 and termination information is 2024/07/01, return 2024/07/01.\nEffective Date: {effective_date}\nTermination Information: {termination_information}\nOnly provide the first termination date, ignoring any automatic or optional renewals. Provide the date in YYYY/MM/DD format only. \n{PIPE_FORMAT_INSTRUCTIONS}" + + +def DERIVED_TERM_DATE_INSTRUCTION() -> str: + return ( + "[OBJECTIVE]\n" + "Calculate contract termination date from effective date and term duration.\n" + "Return date in YYYY/MM/DD format in pipes." + ) + + def SPECIAL_CASE_ASSIGNMENT( exhibit_text, reimbursement_dict, special_case_dicts, special_case_term ): + """ + Returns prompt for special case assignment. + Call SPECIAL_CASE_ASSIGNMENT_INSTRUCTION() separately for the cached instruction. + """ return f"""[OBJECTIVE] Analyze a section of a contract. Determine which of {special_case_term} values are associated with the REIMBURSEMENT TERM shown. @@ -1473,3 +1738,11 @@ Return the integer of the {special_case_term} that is most associated with the R {PIPE_FORMAT_INSTRUCTIONS} """ + + +def SPECIAL_CASE_ASSIGNMENT_INSTRUCTION() -> str: + return ( + "[OBJECTIVE]\n" + "Determine which special case term value is associated with a reimbursement term based on contract context.\n" + "Return the integer index of the matching term in pipes." + ) diff --git a/fieldExtraction/src/qc_qa/__init__.py b/src/qc_qa/__init__.py similarity index 100% rename from fieldExtraction/src/qc_qa/__init__.py rename to src/qc_qa/__init__.py diff --git a/fieldExtraction/src/qc_qa/__main__.py b/src/qc_qa/__main__.py similarity index 95% rename from fieldExtraction/src/qc_qa/__main__.py rename to src/qc_qa/__main__.py index f970b1a..22860d3 100644 --- a/fieldExtraction/src/qc_qa/__main__.py +++ b/src/qc_qa/__main__.py @@ -57,7 +57,9 @@ def main(): if stats_file: logging.info(f"Stats file: {stats_file}") if output_file: - logging.info(f"Legacy output file (will also save to qa_qc_output): {output_file}") + logging.info( + f"Legacy output file (will also save to qa_qc_output): {output_file}" + ) # Convert Excel if needed logging.info("\nConverting input file if needed...") @@ -120,7 +122,7 @@ def main(): logging.info("QC/QA Validation Complete!") logging.info(f"\nOutputs saved to:") - logging.info(f" - Local: qa_qc_output/{run_timestamp}/") + logging.info(f" - Local: {config.QC_QA_OUTPUT_DIRECTORY}/{run_timestamp}/") if config.WRITE_TO_S3: logging.info( f" - S3: s3://{config.S3_OUTPUT_BUCKET}/{config.BATCH_ID}/{run_timestamp}/automation_qa-qc/" diff --git a/fieldExtraction/src/qc_qa/pipeline.py b/src/qc_qa/pipeline.py similarity index 96% rename from fieldExtraction/src/qc_qa/pipeline.py rename to src/qc_qa/pipeline.py index b87c86b..d3523f7 100644 --- a/fieldExtraction/src/qc_qa/pipeline.py +++ b/src/qc_qa/pipeline.py @@ -49,7 +49,9 @@ def read_file_by_extension(file_path: str) -> pd.DataFrame: else: return pd.read_excel(file_path) else: - raise ValueError(f"Unsupported file extension: {file_ext}. Supported: .csv, .xlsx, .xls, .xlsm, .xlsb") + raise ValueError( + f"Unsupported file extension: {file_ext}. Supported: .csv, .xlsx, .xls, .xlsm, .xlsb" + ) def write_file_by_extension(df: pd.DataFrame, file_path: str) -> None: @@ -67,7 +69,9 @@ def write_file_by_extension(df: pd.DataFrame, file_path: str) -> None: elif file_ext in [".xlsx", ".xls"]: df.to_excel(file_path, index=False) else: - raise ValueError(f"Unsupported file extension: {file_ext}. Supported: .csv, .xlsx, .xls") + raise ValueError( + f"Unsupported file extension: {file_ext}. Supported: .csv, .xlsx, .xls" + ) def convert_excel_to_csv(input_file: str) -> str: @@ -145,6 +149,9 @@ def run_qc_qa_pipeline( """ logging.info("Starting QC/QA validation pipeline...") + # Reset index to avoid "cannot reindex on an axis with duplicate labels" errors + df = df.reset_index(drop=True) + # Step 1: Clean contract names if qc.QC_CONTRACT_NAME in df.columns: df[qc.QC_CONTRACT_NAME] = ( @@ -409,7 +416,9 @@ def run_qc_qa_pipeline( elif cell_length < float(mean_val) - 2 * float(std_val): df.at[idx, "Manual Review Flag (Invalid)"] += f"{col}-LOW|" else: - logging.info(f"Column {col} skipped - all zero/empty values or missing stats") + logging.info( + f"Column {col} skipped - all zero/empty values or missing stats" + ) if new_col in df.columns: df.drop(columns=[new_col], inplace=True) @@ -612,13 +621,13 @@ def save_qc_qa_outputs( # Save validated data locally io_utils.write_local(validated_df, "", run_timestamp, "qc_qa_validated") logging.info( - f"Saved QC/QA validated data to: qa_qc_output/{run_timestamp}/{config.BATCH_ID}-QC-QA-VALIDATED.csv" + f"Saved QC/QA validated data to: {config.QC_QA_OUTPUT_DIRECTORY}/{run_timestamp}/{config.BATCH_ID}-QC-QA-VALIDATED.csv" ) # Save statistics locally io_utils.write_local(stats_df, "", run_timestamp, "qc_qa_stats") logging.info( - f"Saved QC/QA statistics to: qa_qc_output/{run_timestamp}/{config.BATCH_ID}-QC-QA-STATS.csv" + f"Saved QC/QA statistics to: {config.QC_QA_OUTPUT_DIRECTORY}/{run_timestamp}/{config.BATCH_ID}-QC-QA-STATS.csv" ) # Upload to S3 if enabled diff --git a/fieldExtraction/scripts/compare_output.py b/src/scripts/compare_output.py similarity index 100% rename from fieldExtraction/scripts/compare_output.py rename to src/scripts/compare_output.py diff --git a/fieldExtraction/scripts/create_code_embeddings.py b/src/scripts/create_code_embeddings.py similarity index 53% rename from fieldExtraction/scripts/create_code_embeddings.py rename to src/scripts/create_code_embeddings.py index 843a3be..db47385 100644 --- a/fieldExtraction/scripts/create_code_embeddings.py +++ b/src/scripts/create_code_embeddings.py @@ -1,4 +1,3 @@ - import src.utils.embedding_utils as embedding_utils from src.utils.crosswalk_utils import CrosswalkBuilder import src.codes.code_funcs as code_funcs @@ -18,13 +17,15 @@ for filename in os.listdir(mapping_dir): print(f"Creating embeddings for {filename}") stripped_filename = filename.replace(".csv", "") mapping_df = pd.read_csv(os.path.join(mapping_dir, filename)) - proc_crosswalk = CrosswalkBuilder().from_df(mapping_df, from_col="Code", to_col="Description") + proc_crosswalk = CrosswalkBuilder().from_df( + mapping_df, from_col="Code", to_col="Description" + ) proc_choices = [x for x in proc_crosswalk.mapping.values()] os.makedirs(os.path.join(pkl_dir, stripped_filename), exist_ok=True) - proc_index = embedding_utils.create_faiss_index(choices=proc_choices, - model=roberta_model, - save_path=os.path.join(pkl_dir, stripped_filename, "faiss_index.bin"), - embedding_path=os.path.join(pkl_dir, stripped_filename, "embeddings.npy"), - choices_path=os.path.join(pkl_dir, stripped_filename, "choices.pkl") - ) - + proc_index = embedding_utils.create_faiss_index( + choices=proc_choices, + model=roberta_model, + save_path=os.path.join(pkl_dir, stripped_filename, "faiss_index.bin"), + embedding_path=os.path.join(pkl_dir, stripped_filename, "embeddings.npy"), + choices_path=os.path.join(pkl_dir, stripped_filename, "choices.pkl"), + ) diff --git a/fieldExtraction/scripts/detect_complex.py b/src/scripts/detect_complex.py similarity index 100% rename from fieldExtraction/scripts/detect_complex.py rename to src/scripts/detect_complex.py diff --git a/fieldExtraction/scripts/file_counting.py b/src/scripts/file_counting.py similarity index 100% rename from fieldExtraction/scripts/file_counting.py rename to src/scripts/file_counting.py diff --git a/fieldExtraction/scripts/investment_field_testing/testing.ipynb b/src/scripts/investment_field_testing/testing.ipynb similarity index 97% rename from fieldExtraction/scripts/investment_field_testing/testing.ipynb rename to src/scripts/investment_field_testing/testing.ipynb index 643298d..5398e18 100644 --- a/fieldExtraction/scripts/investment_field_testing/testing.ipynb +++ b/src/scripts/investment_field_testing/testing.ipynb @@ -100,11 +100,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "#### MAIN IMPORTS ####\n", - "\n", - "from src.investment.main import main as investment_main" - ] + "source": "#### MAIN IMPORTS ####\n\nfrom src.pipelines.saas.main import main as investment_main" }, { "cell_type": "code", @@ -155,4 +151,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/fieldExtraction/scripts/merge_issue_regex.py b/src/scripts/merge_issue_regex.py similarity index 100% rename from fieldExtraction/scripts/merge_issue_regex.py rename to src/scripts/merge_issue_regex.py diff --git a/fieldExtraction/scripts/missingness_analysis.py b/src/scripts/missingness_analysis.py similarity index 79% rename from fieldExtraction/scripts/missingness_analysis.py rename to src/scripts/missingness_analysis.py index d2dc856..bdd0cb4 100644 --- a/fieldExtraction/scripts/missingness_analysis.py +++ b/src/scripts/missingness_analysis.py @@ -1,5 +1,3 @@ - - import src.config as config from datetime import datetime import pandas as pd @@ -9,88 +7,87 @@ import io def find_inv_test_results(): """ - Efficiently find the 30 most recent directories containing 'inv-test' + Efficiently find the 30 most recent directories containing 'inv-test' and list their RESULTS.csv files. - + Strategy: Only list top-level directories first, filter for 'inv-test', then search only those directories for RESULTS.csv files. """ s3_client = config.S3_CLIENT bucket_name = config.S3_OUTPUT_BUCKET - + print(f"\nSearching for 'inv-test' directories in bucket: {bucket_name}") print("=" * 80) - + # Step 1: Get only top-level directories (much faster than scanning all files) print("Step 1: Listing top-level directories...") - response = s3_client.list_objects_v2( - Bucket=bucket_name, - Delimiter='/' - ) - - if 'CommonPrefixes' not in response: + response = s3_client.list_objects_v2(Bucket=bucket_name, Delimiter="/") + + if "CommonPrefixes" not in response: print("No directories found in bucket") return [] - - all_top_level_dirs = [prefix['Prefix'].rstrip('/') for prefix in response['CommonPrefixes']] + + all_top_level_dirs = [ + prefix["Prefix"].rstrip("/") for prefix in response["CommonPrefixes"] + ] print(f"Found {len(all_top_level_dirs)} total top-level directories") - + # Step 2: Filter for 'inv-test' directories only - inv_test_dirs = [d for d in all_top_level_dirs if 'inv-test' in d] + inv_test_dirs = [d for d in all_top_level_dirs if "inv-test" in d] print(f"Found {len(inv_test_dirs)} directories containing 'inv-test'") - + if not inv_test_dirs: print("No 'inv-test' directories found") return [] - + # Step 3: Get timestamps for inv-test directories only (not all files in bucket) print("\nStep 2: Getting timestamps for inv-test directories...") dir_timestamps = [] - + for dir_name in inv_test_dirs: # Get just the first file in each directory to get a timestamp response = s3_client.list_objects_v2( - Bucket=bucket_name, - Prefix=f"{dir_name}/", - MaxKeys=1 + Bucket=bucket_name, Prefix=f"{dir_name}/", MaxKeys=1 ) - - if 'Contents' in response and len(response['Contents']) > 0: - timestamp = response['Contents'][0]['LastModified'] + + if "Contents" in response and len(response["Contents"]) > 0: + timestamp = response["Contents"][0]["LastModified"] dir_timestamps.append((dir_name, timestamp)) - + # Sort by timestamp (most recent first) dir_timestamps.sort(key=lambda x: x[1], reverse=True) - + # Get the 30 most recent recent_inv_test_dirs = dir_timestamps[:30] - - print(f"\nStep 3: Searching 30 most recent 'inv-test' directories for RESULTS.csv files:") + + print( + f"\nStep 3: Searching 30 most recent 'inv-test' directories for RESULTS.csv files:" + ) print("=" * 80) - + total_results_files = 0 all_results_files = {} # Dictionary to store directory -> list of file paths - + for i, (dir_name, timestamp) in enumerate(recent_inv_test_dirs, 1): print(f"\n[{i}/30] Directory: {dir_name}") print(f" Last Modified: {timestamp.strftime('%Y-%m-%d %H:%M:%S')}") - + # Search only this directory for RESULTS.csv files results_files = [] - paginator = s3_client.get_paginator('list_objects_v2') - + paginator = s3_client.get_paginator("list_objects_v2") + for page in paginator.paginate(Bucket=bucket_name, Prefix=f"{dir_name}/"): - if 'Contents' not in page: + if "Contents" not in page: continue - - for obj in page['Contents']: - key = obj['Key'] + + for obj in page["Contents"]: + key = obj["Key"] # Ignore files in subdirectories named "individual" - if '/individual/' in key: + if "/individual/" in key: continue - if key.endswith('-RESULTS.csv'): + if key.endswith("-RESULTS.csv"): results_files.append(key) - + if results_files: print(f" Found {len(results_files)} RESULTS.csv file(s):") for file_key in results_files: @@ -99,25 +96,25 @@ def find_inv_test_results(): all_results_files[dir_name] = results_files else: print(f" ✗ No -RESULTS.csv files found") - + print("\n" + "=" * 80) print(f"Summary:") print(f" - Searched 30 most recent 'inv-test' directories") print(f" - Total -RESULTS.csv files found: {total_results_files}") print("=" * 80) - + # Step 4: Generate missingness report if total_results_files > 0: print(f"\nStep 4: Generating missingness report...") generate_missingness_report(s3_client, bucket_name, all_results_files) - + return recent_inv_test_dirs def generate_missingness_report(s3_client, bucket_name, results_files_dict): """ Generate a missingness report for all RESULTS.csv files. - + Args: s3_client: S3 client object bucket_name: S3 bucket name @@ -126,59 +123,61 @@ def generate_missingness_report(s3_client, bucket_name, results_files_dict): print("=" * 80) print("Generating Missingness Report") print("=" * 80) - + missingness_data = [] - + for dir_name, file_paths in results_files_dict.items(): for file_path in file_paths: print(f"\nProcessing: {file_path}") - + try: # Read CSV from S3 response = s3_client.get_object(Bucket=bucket_name, Key=file_path) - csv_content = response['Body'].read().decode('utf-8') + csv_content = response["Body"].read().decode("utf-8") df = pd.read_csv(io.StringIO(csv_content)) - + if df.empty: print(f" ⚠ File is empty, skipping") continue - + # Calculate missingness for each column - row_data = {'csv_file': file_path} - + row_data = {"csv_file": file_path} + for column in df.columns: empty_mask = string_utils.is_empty(df[column], pd_mask=True) missingness_pct = (empty_mask.sum() / len(df)) * 100 row_data[column] = round(missingness_pct, 2) - + missingness_data.append(row_data) print(f" ✓ Processed {len(df)} rows, {len(df.columns)} columns") - + except Exception as e: print(f" ✗ Error processing file: {e}") continue - + if not missingness_data: print("\nNo valid data to create report") return - + # Create missingness DataFrame missingness_df = pd.DataFrame(missingness_data) - + # Set csv_file as index for better readability - missingness_df.set_index('csv_file', inplace=True) - + missingness_df.set_index("csv_file", inplace=True) + # Save report - output_filename = f"missingness_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" + output_filename = ( + f"missingness_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" + ) missingness_df.to_csv(output_filename) - + print("\n" + "=" * 80) print(f"Missingness Report Summary:") print(f" - Total CSV files processed: {len(missingness_data)}") print(f" - Total columns analyzed: {len(missingness_df.columns)}") print(f" - Report saved to: {output_filename}") print("=" * 80) - + # Display sample of the report print("\nSample of Missingness Report (first 5 columns):") print("-" * 80) @@ -192,18 +191,3 @@ def generate_missingness_report(s3_client, bucket_name, results_files_dict): if __name__ == "__main__": find_inv_test_results() - - - - - - - - - - - - - - - diff --git a/fieldExtraction/scripts/postprocess_existing_output.py b/src/scripts/postprocess_existing_output.py similarity index 99% rename from fieldExtraction/scripts/postprocess_existing_output.py rename to src/scripts/postprocess_existing_output.py index d420a4a..40c2356 100644 --- a/fieldExtraction/scripts/postprocess_existing_output.py +++ b/src/scripts/postprocess_existing_output.py @@ -23,9 +23,3 @@ print(f"Processing complete. Output has {len(df_processed)} rows") print(f"Writing CSV file: {output_csv_path}") df_processed.to_csv(output_csv_path, index=False) print("Done!") - - - - - - diff --git a/fieldExtraction/scripts/prerun.py b/src/scripts/prerun.py similarity index 100% rename from fieldExtraction/scripts/prerun.py rename to src/scripts/prerun.py diff --git a/fieldExtraction/scripts/qa_qc.py b/src/scripts/qa_qc.py similarity index 91% rename from fieldExtraction/scripts/qa_qc.py rename to src/scripts/qa_qc.py index 4fd31ee..8271734 100644 --- a/fieldExtraction/scripts/qa_qc.py +++ b/src/scripts/qa_qc.py @@ -8,13 +8,11 @@ from openpyxl.utils.dataframe import dataframe_to_rows import argparse import boto3 from botocore.exceptions import ClientError + sys.path.append("src") import utils import config -from qa_qc_helpers import ( - perform_qc_qa, - save_qcqa_wb - ) +from qa_qc_helpers import perform_qc_qa, save_qcqa_wb from consolidate_output import consolidate_output @@ -25,6 +23,7 @@ You should have both input and output (input is local or s3, ouput is just an em The final report will be saved in the parent directory of when you are running under reports/ Run this from the base folder of the repo.""" + def main(): timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") script_dir = os.path.dirname(os.path.abspath(__file__)) @@ -68,7 +67,7 @@ def main(): lambda x: utils.remove_txt_extension(str(x)).lower() ) ac_filenames = set(ac_df[file_name_column]) - + if b_df is not None: b_df = utils.remove_unnamed_columns(b_df) b_filenames = set(b_df[file_name_column]) @@ -76,11 +75,12 @@ def main(): lambda x: utils.remove_txt_extension(str(x)).lower() ) - if ac_df is not None and b_df is not None: unmatched_b_filenames = b_filenames - ac_filenames unmatched_b_df = pd.DataFrame({file_name_column: list(unmatched_b_filenames)}) - unmatched_b_output_path = os.path.join(config.OUTPUT_DIRECTORY, "unmatched_B_filenames.csv") + unmatched_b_output_path = os.path.join( + config.OUTPUT_DIRECTORY, "unmatched_B_filenames.csv" + ) unmatched_b_df.to_csv(unmatched_b_output_path, index=False) print(f"Unmatched B filenames saved to '{unmatched_b_output_path}'") @@ -97,11 +97,12 @@ def main(): print(f"Rows in merged DataFrame: {merged_rows}") print(f"Unique filenames in B not found in AC: {unmatched_b_count}") - merged_output_path = os.path.join(config.OUTPUT_DIRECTORY, "DOCZYAI_merged_results.csv") + merged_output_path = os.path.join( + config.OUTPUT_DIRECTORY, "DOCZYAI_merged_results.csv" + ) merged_df.to_csv(merged_output_path, index=False) print(f"Merged data saved to '{merged_output_path}'") - wb = perform_qc_qa(ac_df, b_df, merged_df, input_dict) save_qcqa_wb(wb, timestamp) diff --git a/fieldExtraction/scripts/table_analysis.py b/src/scripts/table_analysis.py similarity index 100% rename from fieldExtraction/scripts/table_analysis.py rename to src/scripts/table_analysis.py diff --git a/fieldExtraction/scripts/textract_template.py b/src/scripts/textract_template.py similarity index 99% rename from fieldExtraction/scripts/textract_template.py rename to src/scripts/textract_template.py index 9a4ef6a..93162ef 100644 --- a/fieldExtraction/scripts/textract_template.py +++ b/src/scripts/textract_template.py @@ -2,7 +2,7 @@ This script was written to extract .txt files from pdf for adhoc client runs. Ensure you have permissions for API gateway, S3, Lambda function and SQS to execute this (DEVELOPER & above roles in DEV & UAT for Doczy should suffice) If you have Analyst / Test roles and need the permissions to be elevated or policies to be updated then please ask Sannan Iqbal to make the changes. - + The flow to execute the pipeline is: Create batch using api req Add files to the newly created batch along with the batch id as the tag diff --git a/fieldExtraction/scripts/tin_pull.py b/src/scripts/tin_pull.py similarity index 100% rename from fieldExtraction/scripts/tin_pull.py rename to src/scripts/tin_pull.py diff --git a/fieldExtraction/src/testbed/add_reimb_id_to_testbed.py b/src/testbed/add_reimb_id_to_testbed.py similarity index 79% rename from fieldExtraction/src/testbed/add_reimb_id_to_testbed.py rename to src/testbed/add_reimb_id_to_testbed.py index 257e383..0273cb8 100644 --- a/fieldExtraction/src/testbed/add_reimb_id_to_testbed.py +++ b/src/testbed/add_reimb_id_to_testbed.py @@ -9,9 +9,11 @@ Run it with `poetry run python -m src.testbed.add_reimb_id_to_testbed` # Imports import pandas as pd -from constants.investment_columns import COLUMN_ORDER -from src.investment.postprocessing_funcs import (generate_reimb_ids, - reorder_columns) +from src.constants.investment_columns import COLUMN_ORDER +from src.pipelines.shared.postprocessing.postprocessing_funcs import ( + generate_reimb_ids, + reorder_columns, +) # Read the testbed file testbed = pd.read_excel("Doczy-Testbed.xlsx") diff --git a/fieldExtraction/src/testbed/model_evaluation.py b/src/testbed/model_evaluation.py similarity index 62% rename from fieldExtraction/src/testbed/model_evaluation.py rename to src/testbed/model_evaluation.py index 61c07b3..5ef7122 100644 --- a/fieldExtraction/src/testbed/model_evaluation.py +++ b/src/testbed/model_evaluation.py @@ -2,20 +2,29 @@ import pandas as pd import concurrent.futures import threading from src.utils import io_utils, llm_utils -from src.investment import preprocess -from constants.constants import Constants +from src.pipelines.shared.preprocessing import preprocess +from src.constants.constants import Constants from src.testbed import model_evaluation_utils from src import config -from src.prompts.fieldset import FieldSet +from src.core.fieldset import FieldSet prompt = "This is a test prompt. Write 'test', nothing else." -def process_file(filename, contract_text, model_id_dict, testbed_df, dynamic_primary_fields, reimbursement_primary_fields, constants): + +def process_file( + filename, + contract_text, + model_id_dict, + testbed_df, + dynamic_primary_fields, + reimbursement_primary_fields, + constants, +): """Process a single file and return its statistics.""" print(f"Processing: {filename}") - testbed_df = testbed_df[testbed_df["FILE_NAME"] == filename] - + testbed_df = testbed_df[testbed_df["FILE_NAME"] == filename] + # Preprocess the contract contract_text = preprocess.clean_text(contract_text) text_dict, top_sheet_dict = preprocess.split_text(contract_text) @@ -34,18 +43,20 @@ def process_file(filename, contract_text, model_id_dict, testbed_df, dynamic_pri testbed_df, dynamic_primary_fields, constants, - filename - ) # list of dicts + filename, + ) # list of dicts # Evaluate Reimbursement Primary - reimbursement_primary_stats_dict = model_evaluation_utils.evaluate_reimbursement_primary( - exhibit_dict, - model_id_dict, - testbed_df, - reimbursement_primary_fields, - constants, - filename - ) # dict + reimbursement_primary_stats_dict = ( + model_evaluation_utils.evaluate_reimbursement_primary( + exhibit_dict, + model_id_dict, + testbed_df, + reimbursement_primary_fields, + constants, + filename, + ) + ) # dict return dynamic_primary_stats_dicts, reimbursement_primary_stats_dict @@ -59,9 +70,9 @@ reimbursement_primary_fields = FieldSet( ) model_id_dict = { - "SONNET_37" : "sonnet_37", - "SONNET_4" : "sonnet_4", - "SONNET_45" : "sonnet_45" + "SONNET_37": "sonnet_37", + "SONNET_4": "sonnet_4", + "SONNET_45": "sonnet_45", } input_dict = io_utils.read_input() testbed_df = pd.read_excel("Doczy-Testbed.xlsx") @@ -69,7 +80,10 @@ testbed_files = list(testbed_df["FILE_NAME"]) constants = Constants() # Initialize dynamic primary stats for each model -dynamic_primary = [{"Model": model_name, "TP": 0, "TN": 0, "FP": 0, "FN": 0} for model_name in model_id_dict.keys()] +dynamic_primary = [ + {"Model": model_name, "TP": 0, "TN": 0, "FP": 0, "FN": 0} + for model_name in model_id_dict.keys() +] # Initialize list to collect all reimbursement primary stats reimbursement_primary_stats_list = [] @@ -77,10 +91,11 @@ reimbursement_primary_stats_list = [] # Lock for thread-safe updates to stats stats_lock = threading.Lock() + # Function to update global stats with results from one file def update_stats(results): dynamic_primary_stats_dicts, reimbursement_primary_stats_dict = results - + with stats_lock: # Update dynamic primary stats for file_stats_dict in dynamic_primary_stats_dicts: @@ -90,30 +105,34 @@ def update_stats(results): for metric in ["TP", "TN", "FP", "FN"]: model_stats[metric] += file_stats_dict.get(metric, 0) break - + # Add reimbursement primary stats to the list if reimbursement_primary_stats_dict: reimbursement_primary_stats_list.append(reimbursement_primary_stats_dict) + # Process files in parallel -filtered_input = {filename: text for filename, text in input_dict.items() if filename in testbed_files} +filtered_input = { + filename: text for filename, text in input_dict.items() if filename in testbed_files +} # Use ThreadPoolExecutor for parallel processing with concurrent.futures.ThreadPoolExecutor(max_workers=config.MAX_WORKERS) as executor: # Submit all file processing tasks future_to_file = { executor.submit( - process_file, - filename, - contract_text, - model_id_dict, - testbed_df, - dynamic_primary_fields, + process_file, + filename, + contract_text, + model_id_dict, + testbed_df, + dynamic_primary_fields, reimbursement_primary_fields, - constants - ): filename for filename, contract_text in filtered_input.items() + constants, + ): filename + for filename, contract_text in filtered_input.items() } - + # Process results as they complete for future in concurrent.futures.as_completed(future_to_file): filename = future_to_file[future] @@ -124,82 +143,112 @@ with concurrent.futures.ThreadPoolExecutor(max_workers=config.MAX_WORKERS) as ex except Exception as e: print(f"Error processing {filename}: {e}") + # Generate Excel report with two sheets def generate_excel_report(output_path="model_evaluation_results.xlsx"): # Create Excel writer - with pd.ExcelWriter(output_path, engine='xlsxwriter') as writer: - + with pd.ExcelWriter(output_path, engine="xlsxwriter") as writer: + # Sheet 1: Dynamic Primary Stats dynamic_primary_df = pd.DataFrame(dynamic_primary) - + # Calculate additional metrics for each model for idx, row in dynamic_primary_df.iterrows(): tp = row["TP"] tn = 0 fp = row["FP"] fn = row["FN"] - + # Add calculated metrics - dynamic_primary_df.loc[idx, "Accuracy"] = (tp + tn) / (tp + tn + fp + fn) if (tp + tn + fp + fn) > 0 else 0 - dynamic_primary_df.loc[idx, "Precision"] = tp / (tp + fp) if (tp + fp) > 0 else 0 - dynamic_primary_df.loc[idx, "Recall"] = tp / (tp + fn) if (tp + fn) > 0 else 0 + dynamic_primary_df.loc[idx, "Accuracy"] = ( + (tp + tn) / (tp + tn + fp + fn) if (tp + tn + fp + fn) > 0 else 0 + ) + dynamic_primary_df.loc[idx, "Precision"] = ( + tp / (tp + fp) if (tp + fp) > 0 else 0 + ) + dynamic_primary_df.loc[idx, "Recall"] = ( + tp / (tp + fn) if (tp + fn) > 0 else 0 + ) precision = dynamic_primary_df.loc[idx, "Precision"] recall = dynamic_primary_df.loc[idx, "Recall"] - dynamic_primary_df.loc[idx, "F1"] = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0 - + dynamic_primary_df.loc[idx, "F1"] = ( + 2 * precision * recall / (precision + recall) + if (precision + recall) > 0 + else 0 + ) + # Write to Excel - dynamic_primary_df.to_excel(writer, sheet_name='Dynamic Primary Stats', index=False) - + dynamic_primary_df.to_excel( + writer, sheet_name="Dynamic Primary Stats", index=False + ) + # Sheet 2: Reimbursement Primary Stats if reimbursement_primary_stats_list: # Combine all reimbursement stats into a DataFrame reimbursement_df = pd.DataFrame(reimbursement_primary_stats_list) - + # Write individual file stats - reimbursement_df.to_excel(writer, sheet_name='Reimbursement Stats', index=False) - + reimbursement_df.to_excel( + writer, sheet_name="Reimbursement Stats", index=False + ) + # Get a reference to the worksheet to add summary statistics - worksheet = writer.sheets['Reimbursement Stats'] - + worksheet = writer.sheets["Reimbursement Stats"] + # Add a summary section summary_row = len(reimbursement_df) + 3 # Leave a gap of 2 rows - + # Add headers for the summary section worksheet.write(summary_row, 0, "Summary Statistics") worksheet.write(summary_row + 1, 0, "Model") worksheet.write(summary_row + 1, 1, "Average Row Count Diff") worksheet.write(summary_row + 1, 2, "Average Row Count Pct Diff") - + # Add summary data row_offset = summary_row + 2 - + # Add model stats - only proceed if we have testbed data - if 'Testbed' in reimbursement_df.columns: + if "Testbed" in reimbursement_df.columns: for model_name in model_id_dict.keys(): if model_name in reimbursement_df.columns: # Calculate the absolute difference between model and testbed row counts - reimbursement_df['Abs_Diff'] = abs(reimbursement_df[model_name] - reimbursement_df['Testbed']) - + reimbursement_df["Abs_Diff"] = abs( + reimbursement_df[model_name] - reimbursement_df["Testbed"] + ) + # Calculate the percentage difference - reimbursement_df['Pct_Diff'] = reimbursement_df['Abs_Diff'] / reimbursement_df['Testbed'] * 100 - reimbursement_df['Pct_Diff'] = reimbursement_df['Pct_Diff'].fillna(0) # Handle division by zero - + reimbursement_df["Pct_Diff"] = ( + reimbursement_df["Abs_Diff"] + / reimbursement_df["Testbed"] + * 100 + ) + reimbursement_df["Pct_Diff"] = reimbursement_df[ + "Pct_Diff" + ].fillna( + 0 + ) # Handle division by zero + # Calculate averages - avg_abs_diff = reimbursement_df['Abs_Diff'].mean() - avg_pct_diff = reimbursement_df['Pct_Diff'].mean() - + avg_abs_diff = reimbursement_df["Abs_Diff"].mean() + avg_pct_diff = reimbursement_df["Pct_Diff"].mean() + # Write to summary worksheet.write(row_offset, 0, model_name) worksheet.write(row_offset, 1, avg_abs_diff) worksheet.write(row_offset, 2, f"{avg_pct_diff:.2f}%") - + row_offset += 1 - + # Remove the temporary columns from the DataFrame before writing - if 'Abs_Diff' in reimbursement_df.columns: - reimbursement_df = reimbursement_df.drop(['Abs_Diff', 'Pct_Diff'], axis=1) + if "Abs_Diff" in reimbursement_df.columns: + reimbursement_df = reimbursement_df.drop( + ["Abs_Diff", "Pct_Diff"], axis=1 + ) # We need to write the dataframe again since we modified it - reimbursement_df.to_excel(writer, sheet_name='Reimbursement Stats', index=False) + reimbursement_df.to_excel( + writer, sheet_name="Reimbursement Stats", index=False + ) + # Call the report generation function after all processing is complete generate_excel_report() diff --git a/fieldExtraction/src/testbed/model_evaluation_utils.py b/src/testbed/model_evaluation_utils.py similarity index 69% rename from fieldExtraction/src/testbed/model_evaluation_utils.py rename to src/testbed/model_evaluation_utils.py index e19e5d8..ae6ac8e 100644 --- a/fieldExtraction/src/testbed/model_evaluation_utils.py +++ b/src/testbed/model_evaluation_utils.py @@ -1,36 +1,43 @@ - import pandas as pd -from src.prompts.fieldset import FieldSet +from src.core.fieldset import FieldSet from src.utils import llm_utils, string_utils from src.prompts import prompt_templates -from constants.constants import Constants -from src.investment import aarete_derived, one_to_n_funcs +from src.constants.constants import Constants +from src.pipelines.shared.postprocessing import aarete_derived +from src.pipelines.shared.extraction import one_to_n_funcs from src import config -def prompt_dynamic_primary(exhibit_dict: dict[str, str], model_id_dict: dict[str, str], dynamic_primary_fields: FieldSet, constants: Constants, filename: str): +def prompt_dynamic_primary( + exhibit_dict: dict[str, str], + model_id_dict: dict[str, str], + dynamic_primary_fields: FieldSet, + constants: Constants, + filename: str, +): model_answer_dicts = {} for model_name, model_id in model_id_dict.items(): answer_dicts = [] for exhibit_page, exhibit_text in exhibit_dict.items(): answer_dict = {} for field in dynamic_primary_fields.fields: - prompt = prompt_templates.DYNAMIC_PRIMARY_TEXT(exhibit_text, field.field_name, field.get_prompt(constants)) + prompt = prompt_templates.DYNAMIC_PRIMARY_TEXT( + exhibit_text, field.field_name, field.get_prompt(constants) + ) llm_answer_raw = llm_utils.invoke_claude( - prompt=prompt, - model_id=model_id, - filename=filename + prompt=prompt, model_id=model_id, filename=filename ) llm_answer_final = string_utils.extract_text_from_delimiters( llm_answer_raw, string_utils.Delimiter.PIPE ) answer_dict[field.field_name] = llm_answer_final answer_dicts.append(answer_dict) - + answer_dicts = aarete_derived.get_crosswalk_fields(answer_dicts, constants) model_answer_dicts[model_name] = answer_dicts return model_answer_dicts + def consolidate_dynamic_primary(model_answer_dicts: dict): consolidated_answer_dicts = {} for model_name, answer_dicts in model_answer_dicts.items(): @@ -45,35 +52,46 @@ def consolidate_dynamic_primary(model_answer_dicts: dict): # Split pipe-separated values and add each individually if isinstance(value, str) and "|" in value: for split_value in value.split("|"): - split_value = split_value.strip() # Remove any extra whitespace + split_value = ( + split_value.strip() + ) # Remove any extra whitespace if not string_utils.is_empty(split_value): unique_values[field_name].add(split_value) else: unique_values[field_name].add(value) - consolidated_answer_dicts[model_name] = {k: list(v) for k, v in unique_values.items()} - + consolidated_answer_dicts[model_name] = { + k: list(v) for k, v in unique_values.items() + } + return consolidated_answer_dicts -def generate_dynamic_primary_stats(consolidated_answer_dicts: dict[str, dict], testbed_df: pd.DataFrame, filename: str): + +def generate_dynamic_primary_stats( + consolidated_answer_dicts: dict[str, dict], testbed_df: pd.DataFrame, filename: str +): """ Generate confusion matrix statistics for dynamic primary field extraction. - + Args: consolidated_answer_dicts: Dictionary with model names as keys and dictionaries of field values as values testbed_df: DataFrame containing the ground truth data filename: Name of the file being evaluated - + Returns: List of dictionaries with confusion matrix statistics for each model """ # Extract all unique ground truth values from testbed_df ground_truth_values = set() - aarete_cols = ["AARETE_DERIVED_LOB", "AARETE_DERIVED_PROGRAM", "AARETE_DERIVED_NETWORK"] - + aarete_cols = [ + "AARETE_DERIVED_LOB", + "AARETE_DERIVED_PROGRAM", + "AARETE_DERIVED_NETWORK", + ] + # Only include columns that actually exist in the DataFrame aarete_cols = [col for col in aarete_cols if col in testbed_df.columns] - + # Collect unique values from each column for col in aarete_cols: # Handle potential pipe-separated values @@ -87,7 +105,7 @@ def generate_dynamic_primary_stats(consolidated_answer_dicts: dict[str, dict], t else: if not string_utils.is_empty(value): ground_truth_values.add(value) - + stats_dicts = [] for model_name, field_dict in consolidated_answer_dicts.items(): # Collect all unique values predicted by this model @@ -99,48 +117,64 @@ def generate_dynamic_primary_stats(consolidated_answer_dicts: dict[str, dict], t TP = len([v for v in model_values if v in ground_truth_values]) FP = len([v for v in model_values if v not in ground_truth_values]) FN = len([v for v in ground_truth_values if v not in model_values]) - stats_dicts.append({"Model" : model_name, "TP" : TP, "FP" : FP, "FN" : FN}) + stats_dicts.append({"Model": model_name, "TP": TP, "FP": FP, "FN": FN}) return stats_dicts - -def evaluate_dynamic_primary(exhibit_dict: dict[str, str], model_id_dict: dict[str, str], testbed_df: pd.DataFrame, dynamic_primary_fields: FieldSet, constants: Constants, filename: str): + + +def evaluate_dynamic_primary( + exhibit_dict: dict[str, str], + model_id_dict: dict[str, str], + testbed_df: pd.DataFrame, + dynamic_primary_fields: FieldSet, + constants: Constants, + filename: str, +): ## Prompt for model_answer_dicts dynamic_answer_dicts = prompt_dynamic_primary( - exhibit_dict, - model_id_dict, - dynamic_primary_fields, - constants, - filename + exhibit_dict, model_id_dict, dynamic_primary_fields, constants, filename ) # Consolidate model_answer_dicts consolidated_answer_dicts = consolidate_dynamic_primary(dynamic_answer_dicts) # Generate stats - stats_dicts = generate_dynamic_primary_stats(consolidated_answer_dicts, testbed_df, filename) - + stats_dicts = generate_dynamic_primary_stats( + consolidated_answer_dicts, testbed_df, filename + ) + return stats_dicts - -def evaluate_reimbursement_primary(exhibit_dict: dict[str, str], model_id_dict: dict[str, str], testbed_df: pd.DataFrame, reimbursement_primary_fields: FieldSet, constants: Constants, filename: str) -> dict[str, object]: + + +def evaluate_reimbursement_primary( + exhibit_dict: dict[str, str], + model_id_dict: dict[str, str], + testbed_df: pd.DataFrame, + reimbursement_primary_fields: FieldSet, + constants: Constants, + filename: str, +) -> dict[str, object]: # Create two separate dictionaries and merge them at the end metadata: dict[str, str] = {"FILE_NAME": filename} - + # Create a numeric counts dictionary with explicit types counts: dict[str, int] = {} - num_lesser = len(testbed_df[testbed_df['LESSER_OF_IND'] == 'Y']) - counts["Testbed"] = int(num_lesser/2) + (len(testbed_df)-num_lesser) - + num_lesser = len(testbed_df[testbed_df["LESSER_OF_IND"] == "Y"]) + counts["Testbed"] = int(num_lesser / 2) + (len(testbed_df) - num_lesser) + # Initialize model counts for model_name in model_id_dict: counts[model_name] = 0 - + # Process each model for model_name, model_id in model_id_dict.items(): seen_pairs = set() for exhibit_page, exhibit_text in exhibit_dict.items(): field_prompts = reimbursement_primary_fields.print_prompt_dict(constants) - instruction, prompt = prompt_templates.REIMBURSEMENT_PRIMARY(exhibit_text, field_prompts) + instruction, prompt = prompt_templates.REIMBURSEMENT_PRIMARY( + exhibit_text, field_prompts + ) llm_answer_raw = llm_utils.invoke_claude( prompt, model_id, @@ -153,31 +187,27 @@ def evaluate_reimbursement_primary(exhibit_dict: dict[str, str], model_id_dict: # Check for the special "no results" case if "NO_REIMBURSEMENT_TERMS_FOUND" in llm_answer_raw: continue - + try: llm_answer_final = string_utils.universal_json_load(llm_answer_raw) - reimbursement_primary_answers = one_to_n_funcs.clean_reimbursement_primary( - llm_answer_final, - "", - seen_pairs, - exhibit_page, - constants, - filename + reimbursement_primary_answers = ( + one_to_n_funcs.clean_reimbursement_primary( + llm_answer_final, + "", + seen_pairs, + exhibit_page, + constants, + filename, + ) ) counts[model_name] += len(reimbursement_primary_answers) except Exception as e: pass - + # Merge the dictionaries before returning result: dict[str, object] = {} result.update(metadata) result.update(counts) - + return result - - - - - - diff --git a/fieldExtraction/src/testbed/one_to_n_comparison.py b/src/testbed/one_to_n_comparison.py similarity index 100% rename from fieldExtraction/src/testbed/one_to_n_comparison.py rename to src/testbed/one_to_n_comparison.py diff --git a/fieldExtraction/src/testbed/one_to_one_comparison.py b/src/testbed/one_to_one_comparison.py similarity index 99% rename from fieldExtraction/src/testbed/one_to_one_comparison.py rename to src/testbed/one_to_one_comparison.py index 468f4b8..63e6473 100644 --- a/fieldExtraction/src/testbed/one_to_one_comparison.py +++ b/src/testbed/one_to_one_comparison.py @@ -1,6 +1,6 @@ import pandas as pd from src import config -from src.prompts.fieldset import FieldSet +from src.core.fieldset import FieldSet script_config = { "labels_location_dates": "/home/arg/20250219_test_bed_facilitation/fieldExtraction/src/testbed/labeled_files/Document_Dates_2-13.xlsx", diff --git a/fieldExtraction/src/testbed/testbed_metrics.py b/src/testbed/testbed_metrics.py similarity index 91% rename from fieldExtraction/src/testbed/testbed_metrics.py rename to src/testbed/testbed_metrics.py index d1d1dd8..62de5e0 100644 --- a/fieldExtraction/src/testbed/testbed_metrics.py +++ b/src/testbed/testbed_metrics.py @@ -9,8 +9,10 @@ warnings.filterwarnings("ignore") ########################## READ AND PREPROCESS ########################## # Read files -testbed = pd.read_excel("Doczy-Testbed.xlsx") # This is the testbed -results = pd.read_excel("Doczy-Results.xlsx") # This is the doczy output +testbed = pd.read_csv("Doczy-Testbed-Official.csv") # This is the testbed +results = pd.read_csv( + "inv-test-20260122-generic-RESULTS.csv" +) # This is the doczy output ########################## Preprocess ########################## testbed = testbed_utils.testbed_preprocess(testbed) diff --git a/fieldExtraction/src/testbed/testbed_postprocess.py b/src/testbed/testbed_postprocess.py similarity index 100% rename from fieldExtraction/src/testbed/testbed_postprocess.py rename to src/testbed/testbed_postprocess.py diff --git a/fieldExtraction/src/testbed/testbed_utils.py b/src/testbed/testbed_utils.py similarity index 99% rename from fieldExtraction/src/testbed/testbed_utils.py rename to src/testbed/testbed_utils.py index d743e54..86bfd8a 100644 --- a/fieldExtraction/src/testbed/testbed_utils.py +++ b/src/testbed/testbed_utils.py @@ -5,11 +5,12 @@ from collections import Counter import pandas as pd import src.config as config import src.utils.string_utils as string_utils -from constants.investment_columns import COLUMN_ORDER +from src.constants.investment_columns import COLUMN_ORDER from rapidfuzz import fuzz + # Imports for the testbed postprocessing functions -from src.investment import postprocessing_funcs -from src.prompts.fieldset import FieldSet +from src.pipelines.shared.postprocessing import postprocessing_funcs +from src.core.fieldset import FieldSet def filter_file_names(testbed, results): @@ -17,7 +18,7 @@ def filter_file_names(testbed, results): common_file_names = set(testbed["FILE_NAME"]).intersection( set(results["FILE_NAME"]) ) - + files_to_remove = [ "86-0898663-Founder Health, LLC dba Preferred Homecare-ICMProviderAgreement_120661" ] @@ -25,7 +26,7 @@ def filter_file_names(testbed, results): for filename in files_to_remove: if filename in common_file_names: common_file_names.remove(filename.upper()) - + testbed = testbed[testbed["FILE_NAME"].isin(common_file_names)] results = results[results["FILE_NAME"].isin(common_file_names)] return testbed, results @@ -1171,6 +1172,7 @@ def normalize_page(page_str): except (ValueError, TypeError): return str(page_str).strip() + def get_one_to_one_analysis(testbed, results): print("\n*************** One-to-One Stats ****************") one_to_one_fields = ( diff --git a/fieldExtraction/tests/test_calculate_progress_stats.py b/src/tests/test_calculate_progress_stats.py similarity index 93% rename from fieldExtraction/tests/test_calculate_progress_stats.py rename to src/tests/test_calculate_progress_stats.py index 2aab301..2ca7dac 100644 --- a/fieldExtraction/tests/test_calculate_progress_stats.py +++ b/src/tests/test_calculate_progress_stats.py @@ -2,7 +2,7 @@ import os import sys import unittest -from src.tracking.tracking_utils import calculate_progress_stats +from src.utils.tracking_utils import calculate_progress_stats class TestCalculateProgressStats(unittest.TestCase): diff --git a/fieldExtraction/tests/test_code_funcs.py b/src/tests/test_code_funcs.py similarity index 98% rename from fieldExtraction/tests/test_code_funcs.py rename to src/tests/test_code_funcs.py index 343b7d6..5802c2c 100644 --- a/fieldExtraction/tests/test_code_funcs.py +++ b/src/tests/test_code_funcs.py @@ -5,8 +5,8 @@ from unittest.mock import MagicMock, patch import pandas as pd import src.codes.code_funcs as code_funcs -from constants.constants import Constants -from constants.delimiters import Delimiter +from src.constants.constants import Constants +from src.constants.delimiters import Delimiter class TestCodeFuncs(unittest.TestCase): @@ -87,7 +87,9 @@ class TestCodeFuncs(unittest.TestCase): mock_json_load.return_value = {"PROCEDURE_CD": "12345"} # Test successful extraction - result = code_funcs.code_explicit("TEST SERVICE","TEST_METHODOLOGY", "test.pdf") + result = code_funcs.code_explicit( + "TEST SERVICE", "TEST_METHODOLOGY", "test.pdf" + ) self.assertEqual(result, {"PROCEDURE_CD": "12345"}) mock_invoke_claude.assert_called_once() diff --git a/fieldExtraction/tests/test_crosswalk_utils.py b/src/tests/test_crosswalk_utils.py similarity index 100% rename from fieldExtraction/tests/test_crosswalk_utils.py rename to src/tests/test_crosswalk_utils.py diff --git a/fieldExtraction/tests/test_document_classification.py b/src/tests/test_document_classification.py similarity index 54% rename from fieldExtraction/tests/test_document_classification.py rename to src/tests/test_document_classification.py index ce428b1..5dfae06 100644 --- a/fieldExtraction/tests/test_document_classification.py +++ b/src/tests/test_document_classification.py @@ -24,7 +24,7 @@ from src.utils import io_utils class TestCallLLM(unittest.TestCase): """Test the call_llm function that wraps llm_utils.invoke_claude.""" - @patch('src.document_classification.main.llm_utils.invoke_claude') + @patch("src.document_classification.main.llm_utils.invoke_claude") def test_call_llm_success(self, mock_invoke): """Test successful LLM call returns cleaned response.""" mock_invoke.return_value = " YES \n" @@ -32,34 +32,32 @@ class TestCallLLM(unittest.TestCase): result = dtc_main.call_llm( filename="test.txt", context="This is a Service Agreement...", - question="Is this a contract?" + question="Is this a contract?", ) self.assertEqual(result, "YES") mock_invoke.assert_called_once() call_args = mock_invoke.call_args - self.assertIn("This is a Service Agreement", call_args.kwargs['prompt']) - self.assertEqual(call_args.kwargs['model_id'], "sonnet_latest") - self.assertEqual(call_args.kwargs['filename'], "test.txt") - self.assertEqual(call_args.kwargs['max_tokens'], 8192) + self.assertIn("This is a Service Agreement", call_args.kwargs["prompt"]) + self.assertEqual(call_args.kwargs["model_id"], "sonnet_latest") + self.assertEqual(call_args.kwargs["filename"], "test.txt") + self.assertEqual(call_args.kwargs["max_tokens"], 8192) - @patch('src.document_classification.main.llm_utils.invoke_claude') - @patch('src.document_classification.main.logging') + @patch("src.document_classification.main.llm_utils.invoke_claude") + @patch("src.document_classification.main.logging") def test_call_llm_error_handling(self, mock_logging, mock_invoke): """Test error handling returns ERROR and logs the exception.""" mock_invoke.side_effect = Exception("API timeout") result = dtc_main.call_llm( - filename="test.txt", - context="Document text", - question="Question" + filename="test.txt", context="Document text", question="Question" ) self.assertEqual(result, "ERROR") mock_logging.error.assert_called_once() self.assertIn("test.txt", mock_logging.error.call_args[0][0]) - @patch('src.document_classification.main.llm_utils.invoke_claude') + @patch("src.document_classification.main.llm_utils.invoke_claude") def test_call_llm_prompt_format(self, mock_invoke): """Test that prompt is correctly formatted with context and question.""" mock_invoke.return_value = "Answer" @@ -68,7 +66,7 @@ class TestCallLLM(unittest.TestCase): dtc_main.call_llm("test.txt", context, question) - prompt = mock_invoke.call_args.kwargs['prompt'] + prompt = mock_invoke.call_args.kwargs["prompt"] self.assertIn("Document text:", prompt) self.assertIn(context, prompt) self.assertIn(question, prompt) @@ -84,6 +82,7 @@ class TestSaveResultToJson(unittest.TestCase): def tearDown(self): """Clean up temporary directory.""" import shutil + shutil.rmtree(self.temp_dir, ignore_errors=True) def test_save_result_creates_folder(self): @@ -92,9 +91,7 @@ class TestSaveResultToJson(unittest.TestCase): self.assertFalse(os.path.exists(json_folder)) io_utils.save_result_to_json( - filename="test.txt", - result={"is_contract": "YES"}, - json_folder=json_folder + filename="test.txt", result={"is_contract": "YES"}, json_folder=json_folder ) self.assertTrue(os.path.exists(json_folder)) @@ -104,23 +101,21 @@ class TestSaveResultToJson(unittest.TestCase): result = { "is_contract": "YES", "contract_type": "Service Agreement", - "found_on_page": 1 + "found_on_page": 1, } io_utils.save_result_to_json( - filename="contract123.txt", - result=result, - json_folder=self.temp_dir + filename="contract123.txt", result=result, json_folder=self.temp_dir ) json_file = os.path.join(self.temp_dir, "contract123.txt.json") self.assertTrue(os.path.exists(json_file)) - with open(json_file, 'r') as f: + with open(json_file, "r") as f: saved_data = json.load(f) - self.assertEqual(saved_data['filename'], "contract123.txt") - self.assertEqual(saved_data['result'], result) + self.assertEqual(saved_data["filename"], "contract123.txt") + self.assertEqual(saved_data["result"], result) def test_save_result_sanitizes_filename(self): """Test that invalid filename characters are replaced.""" @@ -129,7 +124,7 @@ class TestSaveResultToJson(unittest.TestCase): io_utils.save_result_to_json( filename="path/to/file:with:colons.txt", result=result, - json_folder=self.temp_dir + json_folder=self.temp_dir, ) # Should replace / : \ with _ @@ -142,7 +137,7 @@ class TestSaveResultToJson(unittest.TestCase): io_utils.save_result_to_json( filename="test.txt", result={"is_contract": "YES"}, - json_folder=self.temp_dir + json_folder=self.temp_dir, ) json_file = os.path.join(self.temp_dir, "test.txt.json") @@ -159,20 +154,22 @@ class TestProcessSingleFile(unittest.TestCase): def tearDown(self): """Clean up temporary directory.""" import shutil + shutil.rmtree(self.temp_dir, ignore_errors=True) - @patch('src.document_classification.main.call_llm') - @patch('src.document_classification.main.split_text') - @patch('src.document_classification.main.clean_law_symbols') - @patch('src.document_classification.main.clean_newlines') - def test_process_contract_found_first_page(self, mock_clean_nl, mock_clean_law, - mock_split, mock_llm): + @patch("src.document_classification.main.call_llm") + @patch("src.document_classification.main.split_text") + @patch("src.document_classification.main.clean_law_symbols") + @patch("src.document_classification.main.clean_newlines") + def test_process_contract_found_first_page( + self, mock_clean_nl, mock_clean_law, mock_split, mock_llm + ): """Test processing when contract is found on first page.""" mock_clean_nl.return_value = "cleaned text" mock_clean_law.return_value = "cleaned text" mock_split.return_value = { "1": "This is a Service Agreement between parties...", - "2": "Page 2 content" + "2": "Page 2 content", } # First call: is_contract check returns YES @@ -182,30 +179,31 @@ class TestProcessSingleFile(unittest.TestCase): filename, result = dtc_main.process_single_file( filename="contract.txt", contract_text="raw contract text", - json_folder=self.temp_dir + json_folder=self.temp_dir, ) self.assertEqual(filename, "contract.txt") - self.assertEqual(result['is_contract'], "YES") - self.assertEqual(result['contract_type'], "Service Agreement") - self.assertEqual(result['non_contract_type'], "N/A") - self.assertEqual(result['found_on_page'], 1) + self.assertEqual(result["is_contract"], "YES") + self.assertEqual(result["contract_type"], "Service Agreement") + self.assertEqual(result["non_contract_type"], "N/A") + self.assertEqual(result["found_on_page"], 1) # Should make 2 LLM calls (is_contract + contract_type) self.assertEqual(mock_llm.call_count, 2) - @patch('src.document_classification.main.call_llm') - @patch('src.document_classification.main.split_text') - @patch('src.document_classification.main.clean_law_symbols') - @patch('src.document_classification.main.clean_newlines') - def test_process_non_contract(self, mock_clean_nl, mock_clean_law, - mock_split, mock_llm): + @patch("src.document_classification.main.call_llm") + @patch("src.document_classification.main.split_text") + @patch("src.document_classification.main.clean_law_symbols") + @patch("src.document_classification.main.clean_newlines") + def test_process_non_contract( + self, mock_clean_nl, mock_clean_law, mock_split, mock_llm + ): """Test processing when document is not a contract.""" mock_clean_nl.return_value = "cleaned text" mock_clean_law.return_value = "cleaned text" mock_split.return_value = { "1": "This is an email from John...", - "2": "Email continues..." + "2": "Email continues...", } # First call: is_contract returns NO @@ -213,23 +211,22 @@ class TestProcessSingleFile(unittest.TestCase): mock_llm.side_effect = ["NO", "NO", "Email"] filename, result = dtc_main.process_single_file( - filename="email.txt", - contract_text="email text", - json_folder=self.temp_dir + filename="email.txt", contract_text="email text", json_folder=self.temp_dir ) - self.assertEqual(result['is_contract'], "NO") - self.assertEqual(result['contract_type'], "N/A") - self.assertEqual(result['non_contract_type'], "Email") - self.assertEqual(result['found_on_page'], 1) + self.assertEqual(result["is_contract"], "NO") + self.assertEqual(result["contract_type"], "N/A") + self.assertEqual(result["non_contract_type"], "Email") + self.assertEqual(result["found_on_page"], 1) - @patch('src.document_classification.main.call_llm') - @patch('src.document_classification.main.split_text') - @patch('src.document_classification.main.clean_law_symbols') - @patch('src.document_classification.main.clean_newlines') - @patch('src.document_classification.main.config.DTC_MAX_PAGES_TO_CHECK', 3) - def test_process_contract_found_later_page(self, mock_clean_nl, mock_clean_law, - mock_split, mock_llm): + @patch("src.document_classification.main.call_llm") + @patch("src.document_classification.main.split_text") + @patch("src.document_classification.main.clean_law_symbols") + @patch("src.document_classification.main.clean_newlines") + @patch("src.document_classification.main.config.DTC_MAX_PAGES_TO_CHECK", 3) + def test_process_contract_found_later_page( + self, mock_clean_nl, mock_clean_law, mock_split, mock_llm + ): """Test when contract signature is found on page 3.""" mock_clean_nl.return_value = "cleaned" mock_clean_law.return_value = "cleaned" @@ -237,50 +234,48 @@ class TestProcessSingleFile(unittest.TestCase): "1": "Cover page", "2": "Table of contents", "3": "SERVICE AGREEMENT between parties", - "4": "More content" + "4": "More content", } # Page 1: NO, Page 2: NO, Page 3: YES, then get type mock_llm.side_effect = ["NO", "NO", "YES", "Service Agreement"] filename, result = dtc_main.process_single_file( - filename="contract.txt", - contract_text="text", - json_folder=self.temp_dir + filename="contract.txt", contract_text="text", json_folder=self.temp_dir ) - self.assertEqual(result['is_contract'], "YES") - self.assertEqual(result['found_on_page'], 3) + self.assertEqual(result["is_contract"], "YES") + self.assertEqual(result["found_on_page"], 3) - @patch('src.document_classification.main.call_llm') - @patch('src.document_classification.main.split_text') - @patch('src.document_classification.main.clean_law_symbols') - @patch('src.document_classification.main.clean_newlines') - @patch('src.document_classification.main.logging') - def test_process_error_handling(self, mock_logging, mock_clean_nl, - mock_clean_law, mock_split, mock_llm): + @patch("src.document_classification.main.call_llm") + @patch("src.document_classification.main.split_text") + @patch("src.document_classification.main.clean_law_symbols") + @patch("src.document_classification.main.clean_newlines") + @patch("src.document_classification.main.logging") + def test_process_error_handling( + self, mock_logging, mock_clean_nl, mock_clean_law, mock_split, mock_llm + ): """Test error handling returns error result.""" mock_clean_nl.side_effect = Exception("Processing error") filename, result = dtc_main.process_single_file( - filename="bad.txt", - contract_text="text", - json_folder=self.temp_dir + filename="bad.txt", contract_text="text", json_folder=self.temp_dir ) - self.assertEqual(result['is_contract'], "ERROR") - self.assertEqual(result['contract_type'], "ERROR") - self.assertEqual(result['non_contract_type'], "ERROR") - self.assertEqual(result['found_on_page'], "ERROR") + self.assertEqual(result["is_contract"], "ERROR") + self.assertEqual(result["contract_type"], "ERROR") + self.assertEqual(result["non_contract_type"], "ERROR") + self.assertEqual(result["found_on_page"], "ERROR") mock_logging.error.assert_called_once() - @patch('src.document_classification.main.call_llm') - @patch('src.document_classification.main.split_text') - @patch('src.document_classification.main.clean_law_symbols') - @patch('src.document_classification.main.clean_newlines') - @patch('src.document_classification.main.config.DTC_MAX_PAGES_TO_CHECK', 2) - def test_process_handles_fewer_pages(self, mock_clean_nl, mock_clean_law, - mock_split, mock_llm): + @patch("src.document_classification.main.call_llm") + @patch("src.document_classification.main.split_text") + @patch("src.document_classification.main.clean_law_symbols") + @patch("src.document_classification.main.clean_newlines") + @patch("src.document_classification.main.config.DTC_MAX_PAGES_TO_CHECK", 2) + def test_process_handles_fewer_pages( + self, mock_clean_nl, mock_clean_law, mock_split, mock_llm + ): """Test when document has fewer pages than MAX_PAGES_TO_CHECK.""" mock_clean_nl.return_value = "cleaned" mock_clean_law.return_value = "cleaned" @@ -289,13 +284,11 @@ class TestProcessSingleFile(unittest.TestCase): mock_llm.side_effect = ["NO", "Memo"] filename, result = dtc_main.process_single_file( - filename="short.txt", - contract_text="text", - json_folder=self.temp_dir + filename="short.txt", contract_text="text", json_folder=self.temp_dir ) # Should only check page 1, not error on page 2 - self.assertEqual(result['is_contract'], "NO") + self.assertEqual(result["is_contract"], "NO") class TestRunDTCClassification(unittest.TestCase): @@ -308,30 +301,45 @@ class TestRunDTCClassification(unittest.TestCase): def tearDown(self): """Clean up temporary directory.""" import shutil + shutil.rmtree(self.temp_dir, ignore_errors=True) - @patch('src.document_classification.main.io_utils.write_s3') - @patch('src.document_classification.main.io_utils.write_local') - @patch('src.document_classification.main.process_single_file') - @patch('src.document_classification.main.config.WRITE_TO_S3', False) - @patch('src.document_classification.main.config.BATCH_ID', 'test_batch') - @patch('src.document_classification.main.logging') - def test_main_local(self, mock_logging, - mock_process, mock_write_local, - mock_write_s3): + @patch("src.document_classification.main.io_utils.write_s3") + @patch("src.document_classification.main.io_utils.write_local") + @patch("src.document_classification.main.process_single_file") + @patch("src.document_classification.main.config.WRITE_TO_S3", False) + @patch("src.document_classification.main.config.BATCH_ID", "test_batch") + @patch("src.document_classification.main.logging") + def test_main_local( + self, mock_logging, mock_process, mock_write_local, mock_write_s3 + ): """Test full DTC run with local file output.""" # Mock process_single_file to return results mock_process.side_effect = [ - ("file1.txt", {"is_contract": "YES", "contract_type": "Service Agreement", - "non_contract_type": "N/A", "found_on_page": 1}), - ("file2.txt", {"is_contract": "NO", "contract_type": "N/A", - "non_contract_type": "Email", "found_on_page": 1}) + ( + "file1.txt", + { + "is_contract": "YES", + "contract_type": "Service Agreement", + "non_contract_type": "N/A", + "found_on_page": 1, + }, + ), + ( + "file2.txt", + { + "is_contract": "NO", + "contract_type": "N/A", + "non_contract_type": "Email", + "found_on_page": 1, + }, + ), ] input_dict = { "file1.txt": "Service Agreement text...", - "file2.txt": "Email text..." + "file2.txt": "Email text...", } run_timestamp = "run_20250106_10-30_test" @@ -361,21 +369,23 @@ class TestRunDTCClassification(unittest.TestCase): self.assertIsInstance(summary_df, pd.DataFrame) self.assertEqual(second_call_args[0][3], "dtc_summary") - @patch('src.document_classification.main.io_utils.write_s3') - @patch('src.document_classification.main.io_utils.write_local') - @patch('src.document_classification.main.process_single_file') - @patch('src.document_classification.main.config.WRITE_TO_S3', True) - @patch('src.document_classification.main.config.BATCH_ID', 'test_batch') - @patch('src.document_classification.main.logging') - def test_main_s3(self, mock_logging, - mock_process, mock_write_local, - mock_write_s3): + @patch("src.document_classification.main.io_utils.write_s3") + @patch("src.document_classification.main.io_utils.write_local") + @patch("src.document_classification.main.process_single_file") + @patch("src.document_classification.main.config.WRITE_TO_S3", True) + @patch("src.document_classification.main.config.BATCH_ID", "test_batch") + @patch("src.document_classification.main.logging") + def test_main_s3(self, mock_logging, mock_process, mock_write_local, mock_write_s3): """Test full DTC run with S3 upload.""" mock_process.return_value = ( "file1.txt", - {"is_contract": "YES", "contract_type": "MSA", - "non_contract_type": "N/A", "found_on_page": 2} + { + "is_contract": "YES", + "contract_type": "MSA", + "non_contract_type": "N/A", + "found_on_page": 2, + }, ) input_dict = {"file1.txt": "Master Service Agreement..."} @@ -397,25 +407,54 @@ class TestRunDTCClassification(unittest.TestCase): self.assertEqual(second_call[0][2], run_timestamp) self.assertEqual(second_call[0][3], "dtc_summary") - @patch('src.document_classification.main.io_utils.write_local') - @patch('src.document_classification.main.process_single_file') - @patch('src.document_classification.main.config.WRITE_TO_S3', False) - @patch('src.document_classification.main.config.BATCH_ID', 'test_batch') - @patch('src.document_classification.main.logging') - def test_run_dtc_summary_statistics(self, mock_logging, - mock_process, mock_write_local): + @patch("src.document_classification.main.io_utils.write_local") + @patch("src.document_classification.main.process_single_file") + @patch("src.document_classification.main.config.WRITE_TO_S3", False) + @patch("src.document_classification.main.config.BATCH_ID", "test_batch") + @patch("src.document_classification.main.logging") + def test_run_dtc_summary_statistics( + self, mock_logging, mock_process, mock_write_local + ): """Test that summary statistics are logged correctly.""" # 2 contracts, 1 non-contract, 1 error mock_process.side_effect = [ - ("f1.txt", {"is_contract": "YES", "contract_type": "Service Agreement", - "non_contract_type": "N/A", "found_on_page": 1}), - ("f2.txt", {"is_contract": "YES", "contract_type": "MSA", - "non_contract_type": "N/A", "found_on_page": 1}), - ("f3.txt", {"is_contract": "NO", "contract_type": "N/A", - "non_contract_type": "Email", "found_on_page": 1}), - ("f4.txt", {"is_contract": "ERROR", "contract_type": "ERROR", - "non_contract_type": "ERROR", "found_on_page": "ERROR"}) + ( + "f1.txt", + { + "is_contract": "YES", + "contract_type": "Service Agreement", + "non_contract_type": "N/A", + "found_on_page": 1, + }, + ), + ( + "f2.txt", + { + "is_contract": "YES", + "contract_type": "MSA", + "non_contract_type": "N/A", + "found_on_page": 1, + }, + ), + ( + "f3.txt", + { + "is_contract": "NO", + "contract_type": "N/A", + "non_contract_type": "Email", + "found_on_page": 1, + }, + ), + ( + "f4.txt", + { + "is_contract": "ERROR", + "contract_type": "ERROR", + "non_contract_type": "ERROR", + "found_on_page": "ERROR", + }, + ), ] input_dict = {f"f{i}.txt": "text" for i in range(1, 5)} @@ -433,21 +472,35 @@ class TestRunDTCClassification(unittest.TestCase): self.assertIn("1 non-contracts", summary_str) self.assertIn("1 errors", summary_str) - - @patch('src.document_classification.main.io_utils.write_local') - @patch('src.document_classification.main.process_single_file') - @patch('src.document_classification.main.config.WRITE_TO_S3', False) - @patch('src.document_classification.main.config.BATCH_ID', 'test_batch') - @patch('src.document_classification.main.logging') - def test_run_dtc_no_contracts_summary(self, mock_logging, - mock_process, mock_write_local): + @patch("src.document_classification.main.io_utils.write_local") + @patch("src.document_classification.main.process_single_file") + @patch("src.document_classification.main.config.WRITE_TO_S3", False) + @patch("src.document_classification.main.config.BATCH_ID", "test_batch") + @patch("src.document_classification.main.logging") + def test_run_dtc_no_contracts_summary( + self, mock_logging, mock_process, mock_write_local + ): """Test summary when there are no contracts (covers else block).""" # All non-contracts mock_process.side_effect = [ - ("f1.txt", {"is_contract": "NO", "contract_type": "N/A", - "non_contract_type": "Email", "found_on_page": 1}), - ("f2.txt", {"is_contract": "NO", "contract_type": "N/A", - "non_contract_type": "Form", "found_on_page": 1}), + ( + "f1.txt", + { + "is_contract": "NO", + "contract_type": "N/A", + "non_contract_type": "Email", + "found_on_page": 1, + }, + ), + ( + "f2.txt", + { + "is_contract": "NO", + "contract_type": "N/A", + "non_contract_type": "Form", + "found_on_page": 1, + }, + ), ] input_dict = {f"f{i}.txt": "text" for i in range(1, 3)} @@ -458,31 +511,37 @@ class TestRunDTCClassification(unittest.TestCase): # Check summary DataFrame summary_df = mock_write_local.call_args_list[1][0][0] - self.assertEqual(summary_df['contracts'].iloc[0], 0) - self.assertEqual(summary_df['non_contracts'].iloc[0], 2) - self.assertEqual(summary_df['most_common_contract_type'].iloc[0], "N/A") + self.assertEqual(summary_df["contracts"].iloc[0], 0) + self.assertEqual(summary_df["non_contracts"].iloc[0], 2) + self.assertEqual(summary_df["most_common_contract_type"].iloc[0], "N/A") - @patch('src.document_classification.main.io_utils.write_local') - @patch('src.document_classification.main.process_single_file') - @patch('src.document_classification.main.config.WRITE_TO_S3', False) - @patch('src.document_classification.main.config.BATCH_ID', 'test_batch') - @patch('src.document_classification.main.logging') - def test_run_dtc_future_exception(self, mock_logging, - mock_process, mock_write_local): + @patch("src.document_classification.main.io_utils.write_local") + @patch("src.document_classification.main.process_single_file") + @patch("src.document_classification.main.config.WRITE_TO_S3", False) + @patch("src.document_classification.main.config.BATCH_ID", "test_batch") + @patch("src.document_classification.main.logging") + def test_run_dtc_future_exception( + self, mock_logging, mock_process, mock_write_local + ): """Test exception handling in futures loop (covers lines 244-246).""" + # Simulate an exception being raised by a future def raise_exception(filename, text, folder): if filename == "bad.txt": raise ValueError("Simulated processing error") - return (filename, {"is_contract": "YES", "contract_type": "MSA", - "non_contract_type": "N/A", "found_on_page": 1}) + return ( + filename, + { + "is_contract": "YES", + "contract_type": "MSA", + "non_contract_type": "N/A", + "found_on_page": 1, + }, + ) mock_process.side_effect = raise_exception - input_dict = { - "good.txt": "text", - "bad.txt": "text" - } + input_dict = {"good.txt": "text", "bad.txt": "text"} results = dtc_main.main(input_dict, "run_test") @@ -491,17 +550,21 @@ class TestRunDTCClassification(unittest.TestCase): self.assertEqual(results["bad.txt"]["is_contract"], "ERROR") # Verify error was logged - error_logs = [call for call in mock_logging.error.call_args_list - if "Exception occurred" in str(call)] + error_logs = [ + call + for call in mock_logging.error.call_args_list + if "Exception occurred" in str(call) + ] self.assertTrue(len(error_logs) > 0) - @patch('src.document_classification.main.call_llm') - @patch('src.document_classification.main.split_text') - @patch('src.document_classification.main.clean_law_symbols') - @patch('src.document_classification.main.clean_newlines') - @patch('src.document_classification.main.config.DTC_MAX_PAGES_TO_CHECK', 10) - def test_process_progress_logging_every_5(self, mock_clean_nl, mock_clean_law, - mock_split, mock_llm): + @patch("src.document_classification.main.call_llm") + @patch("src.document_classification.main.split_text") + @patch("src.document_classification.main.clean_law_symbols") + @patch("src.document_classification.main.clean_newlines") + @patch("src.document_classification.main.config.DTC_MAX_PAGES_TO_CHECK", 10) + def test_process_progress_logging_every_5( + self, mock_clean_nl, mock_clean_law, mock_split, mock_llm + ): """Test that progress is logged every 5 files (covers line 169).""" temp_dir = tempfile.mkdtemp() try: @@ -512,14 +575,13 @@ class TestRunDTCClassification(unittest.TestCase): # Set up progress counter to trigger line 169 from src.document_classification.main import progress_counter, progress_lock + with progress_lock: progress_counter["total"] = 10 progress_counter["completed"] = 4 # Next will be 5 filename, result = dtc_main.process_single_file( - filename="file5.txt", - contract_text="text", - json_folder=temp_dir + filename="file5.txt", contract_text="text", json_folder=temp_dir ) # Verify file was processed @@ -527,8 +589,9 @@ class TestRunDTCClassification(unittest.TestCase): self.assertEqual(result["is_contract"], "YES") finally: import shutil + shutil.rmtree(temp_dir, ignore_errors=True) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/fieldExtraction/tests/test_dynamic.py b/src/tests/test_dynamic.py similarity index 93% rename from fieldExtraction/tests/test_dynamic.py rename to src/tests/test_dynamic.py index e337e29..e7f1266 100644 --- a/fieldExtraction/tests/test_dynamic.py +++ b/src/tests/test_dynamic.py @@ -4,8 +4,9 @@ import unittest from unittest.mock import MagicMock, patch import pandas as pd -from constants.constants import Constants -from src.investment import dynamic_funcs, prompt_calls +from src.constants.constants import Constants +from src.pipelines.shared import dynamic_funcs +from src.pipelines.saas.prompts import prompt_calls from src.prompts.fieldset import Field, FieldSet @@ -139,7 +140,7 @@ class TestDynamicFuncsWithRealConstants(unittest.TestCase): self.assertEqual(result.fields[0].field_name, "TEST_FIELD") self.assertEqual(result.fields[0].field_type, "smart_chunked") self.assertEqual(result.fields[0].relationship, "one_to_one") - + def test_add_full_context_field_program_with_single_lob(self): """Test that program fields are added when only one LOB exists.""" # Setup @@ -183,8 +184,8 @@ class TestDynamicFuncsWithRealConstants(unittest.TestCase): self.assertEqual(len(result.fields), 1) # Field should be added self.assertEqual(result.fields[0].field_name, "PROGRAM") - @patch("src.investment.dynamic_funcs.Field.load_from_file") - @patch("src.investment.dynamic_funcs.FieldSet") + @patch("src.pipelines.shared.extraction.dynamic_funcs.Field.load_from_file") + @patch("src.pipelines.shared.extraction.dynamic_funcs.FieldSet") def test_get_dynamic_one_to_one_fields_any_empty( self, mock_fieldset_class, mock_load_field ): @@ -207,8 +208,8 @@ class TestDynamicFuncsWithRealConstants(unittest.TestCase): mock_all_empty_fields, mock_any_empty_fields, mock_one_to_one_fields, - MagicMock(), # extra FieldSet() call safeguard - MagicMock(), # optional safety if code evolves + MagicMock(), # extra FieldSet() call safeguard + MagicMock(), # optional safety if code evolves ] # Configure mock for loading fields @@ -221,9 +222,11 @@ class TestDynamicFuncsWithRealConstants(unittest.TestCase): mock_load_field.return_value = escalator_statement_field # Execute - result = dynamic_funcs.get_dynamic_one_to_one_fields(self.answer_dicts, self.constants) - - @patch("src.investment.prompt_calls.prompt_dynamic") + result = dynamic_funcs.get_dynamic_one_to_one_fields( + self.answer_dicts, self.constants + ) + + @patch("src.pipelines.saas.prompts.prompt_calls.prompt_dynamic") def test_dynamic_with_real_constants(self, mock_prompt_dynamic): """Test dynamic function with real Constants object.""" # Setup @@ -272,7 +275,7 @@ class TestDynamicFuncsWithRealConstants(unittest.TestCase): # Verify that prompt_dynamic was called twice self.assertEqual(mock_prompt_dynamic.call_count, 2) - @patch("src.investment.prompt_calls.prompt_dynamic") + @patch("src.pipelines.saas.prompts.prompt_calls.prompt_dynamic") def test_dynamic_with_no_fields(self, mock_prompt_dynamic): """Test dynamic function with an empty fieldset.""" # Setup @@ -296,7 +299,7 @@ class TestDynamicFuncsWithRealConstants(unittest.TestCase): self.assertEqual(len(updated_reimbursement_fields.fields), 0) mock_prompt_dynamic.assert_not_called() - @patch("src.investment.prompt_calls.prompt_dynamic") + @patch("src.pipelines.saas.prompts.prompt_calls.prompt_dynamic") def test_dynamic_with_no_answers(self, mock_prompt_dynamic): """Test dynamic function when neither header nor text contains answers.""" # Setup diff --git a/src/tests/test_exhibit_funcs.py b/src/tests/test_exhibit_funcs.py new file mode 100644 index 0000000..84e32ae --- /dev/null +++ b/src/tests/test_exhibit_funcs.py @@ -0,0 +1,467 @@ +import sys + +# Disable S3 writes for these tests +if "write_to_s3=False" not in sys.argv: + sys.argv.append("write_to_s3=False") +import unittest +from unittest.mock import patch, Mock + +from src.pipelines.shared.extraction.exhibit_funcs import Exhibit, get_exhibit_list +from src.pipelines.shared.extraction.page_funcs import Page +from src.prompts.fieldset import FieldSet + + +class TestExhibitFuncs(unittest.TestCase): + + def test_add_reimbursement_rows_sets_flag(self): + exhibit = Exhibit( + exhibit_page="1", + exhibit_page_nums=["1"], + exhibit_header="H", + exhibit_text="text", + ) + exhibit.add_reimbursement_rows([{"a": 1}], []) + self.assertTrue(exhibit.has_reimbursements) + self.assertEqual(len(exhibit.reimbursement_rows), 1) + + def test_set_exhibit_level_and_previous_dynamic_fields(self): + prev = Exhibit( + exhibit_page="1", + exhibit_page_nums=["1"], + exhibit_header="H1", + exhibit_text="text1", + ) + dyn_fields = FieldSet() + prev.dynamic_primary_fields = dyn_fields + current = Exhibit( + exhibit_page="2", + exhibit_page_nums=["2"], + exhibit_header="H2", + exhibit_text="text2", + prev_exhibit=prev, + ) + + current.set_exhibit_level_data({"X": "Y"}, FieldSet()) + self.assertEqual(current.exhibit_level_answers["X"], "Y") + self.assertIs(current.get_previous_exhibit_dynamic_fields(), dyn_fields) + + def test_get_exhibit_list_links_previous(self): + text_dict = {"1": "A", "2": "B"} + mapping = {"1": ["1"], "2": ["2"]} + headers = {"1": "H1", "2": "H2"} + exhibits = get_exhibit_list( + text_dict=text_dict, + exhibit_chunk_mapping=mapping, + all_exhibit_headers=headers, + ) + self.assertEqual(len(exhibits), 2) + self.assertIs(exhibits[1].prev_exhibit, exhibits[0]) + + def test_get_cross_exhibit_lesser_of_returns_global(self): + """Test retrieval of GLOBAL statement from previous exhibit.""" + exhibit_a = Exhibit( + exhibit_page="10", + exhibit_page_nums=["10", "11"], + exhibit_header="Exhibit A", + exhibit_text="text a", + ) + exhibit_b = Exhibit( + exhibit_page="20", + exhibit_page_nums=["20", "21"], + exhibit_header="Exhibit B", + exhibit_text="text b", + prev_exhibit=exhibit_a, + ) + + exhibit_a.add_lesser_of_statement( + { + "reimb_term": "All services: lesser of rates or charges", + "scope": "GLOBAL", + "target_exhibit": "ALL", + "exhibit_reference": None, + "page_num": "10", + } + ) + + result = exhibit_b.get_cross_exhibit_lesser_of() + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]["scope"], "GLOBAL") + + def test_get_cross_exhibit_lesser_of_returns_matching_other(self): + """Test retrieval of cross-exhibit (OTHER) targeting this exhibit.""" + exhibit_a = Exhibit( + exhibit_page="10", + exhibit_page_nums=["10"], + exhibit_header="Exhibit A", + exhibit_text="text", + ) + exhibit_b = Exhibit( + exhibit_page="20", + exhibit_page_nums=["20"], + exhibit_header="Exhibit B - Outpatient", + exhibit_text="text", + prev_exhibit=exhibit_a, + ) + + exhibit_a.add_lesser_of_statement( + { + "reimb_term": "For Exhibit B: not to exceed Medicare", + "scope": "EXHIBIT_SPECIFIC", + "target_exhibit": "OTHER", + "exhibit_reference": "Exhibit B", + "page_num": "10", + } + ) + + with patch.object(exhibit_b, "_title_matches", return_value=True): + result = exhibit_b.get_cross_exhibit_lesser_of() + + self.assertEqual(len(result), 1) + self.assertEqual(result[0]["scope"], "EXHIBIT_SPECIFIC") + self.assertEqual(result[0]["exhibit_reference"], "Exhibit B") + + def test_get_cross_exhibit_lesser_of_excludes_non_matching_other(self): + """Test that non-matching cross-exhibit references are excluded.""" + exhibit_a = Exhibit( + exhibit_page="10", + exhibit_page_nums=["10"], + exhibit_header="Exhibit A", + exhibit_text="text", + ) + exhibit_b = Exhibit( + exhibit_page="20", + exhibit_page_nums=["20"], + exhibit_header="Exhibit B", + exhibit_text="text", + prev_exhibit=exhibit_a, + ) + + exhibit_a.add_lesser_of_statement( + { + "reimb_term": "For Exhibit C: not to exceed Medicare", + "scope": "EXHIBIT_SPECIFIC", + "target_exhibit": "OTHER", + "exhibit_reference": "Exhibit C", + "page_num": "10", + } + ) + + with patch.object(exhibit_b, "_title_matches", return_value=False): + result = exhibit_b.get_cross_exhibit_lesser_of() + + self.assertEqual(len(result), 0) + + def test_get_cross_exhibit_lesser_of_excludes_current(self): + """Test that EXHIBIT_SPECIFIC (CURRENT) is NOT returned.""" + exhibit_a = Exhibit( + exhibit_page="10", + exhibit_page_nums=["10"], + exhibit_header="Exhibit A", + exhibit_text="text", + ) + exhibit_b = Exhibit( + exhibit_page="20", + exhibit_page_nums=["20"], + exhibit_header="Exhibit B", + exhibit_text="text", + prev_exhibit=exhibit_a, + ) + + exhibit_a.add_lesser_of_statement( + { + "reimb_term": "Services in this exhibit: lesser of rates or charges", + "scope": "EXHIBIT_SPECIFIC", + "target_exhibit": "CURRENT", + "exhibit_reference": None, + "page_num": "10", + } + ) + + result = exhibit_b.get_cross_exhibit_lesser_of() + + self.assertEqual(len(result), 0) + + def test_get_cross_exhibit_lesser_of_multiple_exhibits(self): + """Test retrieval across multiple exhibits in chain.""" + exhibit_a = Exhibit( + exhibit_page="10", + exhibit_page_nums=["10"], + exhibit_header="Exhibit A", + exhibit_text="text", + ) + exhibit_b = Exhibit( + exhibit_page="20", + exhibit_page_nums=["20"], + exhibit_header="Exhibit B", + exhibit_text="text", + prev_exhibit=exhibit_a, + ) + exhibit_c = Exhibit( + exhibit_page="30", + exhibit_page_nums=["30"], + exhibit_header="Exhibit C", + exhibit_text="text", + prev_exhibit=exhibit_b, + ) + + exhibit_a.add_lesser_of_statement( + { + "reimb_term": "All services: lesser of rates or charges", + "scope": "GLOBAL", + "target_exhibit": "ALL", + "page_num": "10", + } + ) + + exhibit_b.add_lesser_of_statement( + { + "reimb_term": "For Exhibit C: not to exceed Medicare", + "scope": "EXHIBIT_SPECIFIC", + "target_exhibit": "OTHER", + "exhibit_reference": "Exhibit C", + "page_num": "20", + } + ) + + with patch.object(exhibit_c, "_title_matches", return_value=True): + result = exhibit_c.get_cross_exhibit_lesser_of() + + self.assertEqual(len(result), 2) + self.assertEqual(result[0]["scope"], "GLOBAL") + self.assertEqual(result[1]["scope"], "EXHIBIT_SPECIFIC") + + def test_get_cross_exhibit_lesser_of_empty_chain(self): + """Test that first exhibit with no previous returns empty.""" + exhibit_a = Exhibit( + exhibit_page="10", + exhibit_page_nums=["10"], + exhibit_header="Exhibit A", + exhibit_text="text", + ) + + result = exhibit_a.get_cross_exhibit_lesser_of() + + self.assertEqual(len(result), 0) + + +def test_set_exhibit_level_and_previous_dynamic_fields(): + prev = Exhibit( + exhibit_page="1", + exhibit_page_nums=["1"], + exhibit_header="H1", + exhibit_text="text1", + ) + dyn_fields = FieldSet() + prev.dynamic_primary_fields = dyn_fields + current = Exhibit( + exhibit_page="2", + exhibit_page_nums=["2"], + exhibit_header="H2", + exhibit_text="text2", + prev_exhibit=prev, + ) + + current.set_exhibit_level_data({"X": "Y"}, FieldSet()) + assert current.exhibit_level_answers["X"] == "Y" + assert current.get_previous_exhibit_dynamic_fields() is dyn_fields + + +def test_get_exhibit_list_links_previous(): + text_dict = {"1": "A", "2": "B"} + mapping = {"1": ["1"], "2": ["2"]} + headers = {"1": "H1", "2": "H2"} + exhibits = get_exhibit_list( + text_dict=text_dict, exhibit_chunk_mapping=mapping, all_exhibit_headers=headers + ) + assert len(exhibits) == 2 + assert exhibits[1].prev_exhibit is exhibits[0] + + +def test_exhibit_with_pages_dict(): + """Test Exhibit creation with Page objects.""" + page1 = Page("1", "Page 1 text") + page2 = Page("2", "Page 2 text") + pages_dict = {"1": page1, "2": page2} + + exhibit = Exhibit( + exhibit_page="1", + exhibit_page_nums=["1", "2"], + exhibit_header="Exhibit 1", + pages=pages_dict, + ) + + assert exhibit.pages == pages_dict + assert exhibit.exhibit_text == "Page 1 text\nPage 2 text" + assert exhibit.exhibit_page_nums == ["1", "2"] + + +def test_exhibit_backward_compatibility(): + """Test Exhibit backward compatibility with exhibit_text.""" + exhibit = Exhibit( + exhibit_page="1", + exhibit_page_nums=["1"], + exhibit_header="Exhibit 1", + exhibit_text="Some text", + ) + + assert exhibit.pages is None + assert exhibit.exhibit_text == "Some text" + assert exhibit.exhibit_page_nums == ["1"] + + +def test_exhibit_with_split_table(): + """Test Exhibit with split table pages.""" + # Create a page with a split table + rows = [f"['Service {i}', '$100']" for i in range(15)] + table_content = f"[{', '.join(rows)}]" + text = ( + "Text before\n" + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------\n" + "Text after" + ) + page = Page("27", text) + page.split_table(max_cells=10, min_rows_to_split=5) + + pages_dict = {"27": page} + + exhibit = Exhibit( + exhibit_page="27", + exhibit_page_nums=["27.1", "27.2", "27.3"], # Sub-pages from split + exhibit_header="Exhibit 27", + pages=pages_dict, + ) + + assert exhibit.pages == pages_dict + # exhibit_text should include all sub-pages + assert "Text before" in exhibit.exhibit_text + assert "Text after" in exhibit.exhibit_text + assert len(exhibit.get_all_page_nums()) == 3 + + +def test_exhibit_get_page_text(): + """Test Exhibit.get_page_text() method.""" + page1 = Page("1", "Page 1 text") + page2 = Page("2", "Page 2 text") + pages_dict = {"1": page1, "2": page2} + + exhibit = Exhibit( + exhibit_page="1", + exhibit_page_nums=["1", "2"], + exhibit_header="Exhibit 1", + pages=pages_dict, + ) + + assert exhibit.get_page_text("1") == "Page 1 text" + assert exhibit.get_page_text("2") == "Page 2 text" + assert exhibit.get_page_text("3") == "" # Non-existent page + + +def test_exhibit_get_page_text_split_table(): + """Test Exhibit.get_page_text() with split table sub-pages.""" + rows = [f"['Service {i}', '$100']" for i in range(10)] + table_content = f"[{', '.join(rows)}]" + text = ( + "-------Table Start--------\n" f"{table_content}\n" "-------Table End--------" + ) + page = Page("27", text) + page.split_table(max_cells=10, min_rows_to_split=5) + + pages_dict = {"27": page} + + exhibit = Exhibit( + exhibit_page="27", + exhibit_page_nums=["27.1", "27.2"], + exhibit_header="Exhibit 27", + pages=pages_dict, + ) + + # Get specific sub-page + sub_page_text = exhibit.get_page_text("27.1") + assert "-------Table Start--------" in sub_page_text + + # Get base page (should return combined text) + base_page_text = exhibit.get_page_text("27") + assert "-------Table Start--------" in base_page_text + + +def test_get_exhibit_list_with_pages(): + """Test get_exhibit_list() with Page objects.""" + page1 = Page("1", "Page 1 text") + page2 = Page("2", "Page 2 text") + pages_dict = {"1": page1, "2": page2} + + mapping = {"1": ["1"], "2": ["2"]} + headers = {"1": "H1", "2": "H2"} + + exhibits = get_exhibit_list( + pages_dict=pages_dict, + exhibit_chunk_mapping=mapping, + all_exhibit_headers=headers, + ) + + assert len(exhibits) == 2 + assert exhibits[0].pages == {"1": page1} + assert exhibits[1].pages == {"2": page2} + assert exhibits[0].exhibit_text == "Page 1 text" + assert exhibits[1].exhibit_text == "Page 2 text" + + +def test_get_exhibit_list_backward_compatibility(): + """Test get_exhibit_list() backward compatibility with text_dict.""" + text_dict = {"1": "A", "2": "B"} + mapping = {"1": ["1"], "2": ["2"]} + headers = {"1": "H1", "2": "H2"} + + exhibits = get_exhibit_list( + text_dict=text_dict, + exhibit_chunk_mapping=mapping, + all_exhibit_headers=headers, + ) + + assert len(exhibits) == 2 + assert exhibits[0].exhibit_text == "A" + assert exhibits[1].exhibit_text == "B" + assert exhibits[0].pages is None + assert exhibits[1].pages is None + + +def test_get_exhibit_list_with_split_tables(): + """Test get_exhibit_list() with split table pages.""" + # Create a page with a split table + rows = [f"['Service {i}', '$100']" for i in range(15)] + table_content = f"[{', '.join(rows)}]" + text = ( + "Text before\n" + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------\n" + "Text after" + ) + page = Page("27", text) + page.split_table(max_cells=10, min_rows_to_split=5) + + pages_dict = {"27": page} + mapping = {"27": ["27"]} + headers = {"27": "Exhibit 27"} + + exhibits = get_exhibit_list( + pages_dict=pages_dict, + exhibit_chunk_mapping=mapping, + all_exhibit_headers=headers, + ) + + assert len(exhibits) == 1 + exhibit = exhibits[0] + assert "27" in exhibit.pages + # exhibit_page_nums should include sub-pages + assert len(exhibit.exhibit_page_nums) == 3 # 27.1, 27.2, 27.3 + assert "27.1" in exhibit.exhibit_page_nums + assert "27.2" in exhibit.exhibit_page_nums + assert "27.3" in exhibit.exhibit_page_nums + + +if __name__ == "__main__": + unittest.main() diff --git a/fieldExtraction/tests/test_fieldset.py b/src/tests/test_fieldset.py similarity index 99% rename from fieldExtraction/tests/test_fieldset.py rename to src/tests/test_fieldset.py index 0eea129..aedc8be 100644 --- a/fieldExtraction/tests/test_fieldset.py +++ b/src/tests/test_fieldset.py @@ -3,9 +3,8 @@ import os import unittest from unittest.mock import mock_open, patch -from constants.constants import Constants -from src.prompts.fieldset import (Field, FieldSet, _cache_lock, - _field_data_cache) +from src.constants.constants import Constants +from src.prompts.fieldset import Field, FieldSet, _cache_lock, _field_data_cache class TestFieldWithRealConstants(unittest.TestCase): diff --git a/fieldExtraction/tests/test_hybrid_smart_chunking_funcs.py b/src/tests/test_hybrid_smart_chunking_funcs.py similarity index 81% rename from fieldExtraction/tests/test_hybrid_smart_chunking_funcs.py rename to src/tests/test_hybrid_smart_chunking_funcs.py index 706cf87..f34823e 100644 --- a/fieldExtraction/tests/test_hybrid_smart_chunking_funcs.py +++ b/src/tests/test_hybrid_smart_chunking_funcs.py @@ -1,5 +1,5 @@ """ -Unit tests for src.investment.hybrid_smart_chunking_funcs module +Unit tests for src.pipelines.shared.preprocessing.hybrid_smart_chunking_funcs module Tests hybrid smart chunking functions including: - Context clipping by token count @@ -11,8 +11,8 @@ Tests hybrid smart chunking functions including: import pytest from unittest.mock import Mock, patch, MagicMock -from langchain.schema import Document -from src.investment.hybrid_smart_chunking_funcs import ( +from langchain_core.documents import Document +from src.pipelines.shared.preprocessing.hybrid_smart_chunking_funcs import ( clip_context_by_tokens, prepare_documents_for_chunking, format_chunks_for_llm, @@ -93,12 +93,7 @@ class TestPrepareDocumentsForChunking: def test_single_section(self): """Test preparing a single section""" - sections = { - "Section 1": { - "content": "Section content here", - "pages": [1, 2] - } - } + sections = {"Section 1": {"content": "Section content here", "pages": [1, 2]}} filename = "test_contract.pdf" docs = prepare_documents_for_chunking(sections, filename) @@ -114,7 +109,7 @@ class TestPrepareDocumentsForChunking: sections = { "Section 1": {"content": "Content 1", "pages": [1]}, "Section 2": {"content": "Content 2", "pages": [2, 3]}, - "Section 3": {"content": "Content 3", "pages": [4]} + "Section 3": {"content": "Content 3", "pages": [4]}, } docs = prepare_documents_for_chunking(sections) @@ -133,10 +128,7 @@ class TestPrepareDocumentsForChunking: def test_section_metadata(self): """Test that metadata is correctly set""" sections = { - "Test Section": { - "content": "This is test content", - "pages": [5, 6, 7] - } + "Test Section": {"content": "This is test content", "pages": [5, 6, 7]} } filename = "contract.pdf" @@ -150,9 +142,7 @@ class TestPrepareDocumentsForChunking: def test_default_filename(self): """Test default filename when not provided""" - sections = { - "Section": {"content": "Content", "pages": [1]} - } + sections = {"Section": {"content": "Content", "pages": [1]}} docs = prepare_documents_for_chunking(sections) @@ -172,16 +162,8 @@ class TestFormatChunksForLLM: def test_single_document(self): """Test with single document""" - text_dict = { - "1": "Page 1 content", - "2": "Page 2 content" - } - docs = [ - Document( - page_content="chunk1", - metadata={"pages": [1]} - ) - ] + text_dict = {"1": "Page 1 content", "2": "Page 2 content"} + docs = [Document(page_content="chunk1", metadata={"pages": [1]})] result = format_chunks_for_llm(text_dict, docs) @@ -193,11 +175,11 @@ class TestFormatChunksForLLM: text_dict = { "1": "Page 1 content", "2": "Page 2 content", - "3": "Page 3 content" + "3": "Page 3 content", } docs = [ Document(page_content="chunk1", metadata={"pages": [1]}), - Document(page_content="chunk2", metadata={"pages": [3]}) + Document(page_content="chunk2", metadata={"pages": [3]}), ] result = format_chunks_for_llm(text_dict, docs) @@ -208,13 +190,10 @@ class TestFormatChunksForLLM: def test_overlapping_pages(self): """Test with documents that reference overlapping pages""" - text_dict = { - "1": "Page 1 content", - "2": "Page 2 content" - } + text_dict = {"1": "Page 1 content", "2": "Page 2 content"} docs = [ Document(page_content="chunk1", metadata={"pages": [1, 2]}), - Document(page_content="chunk2", metadata={"pages": [2]}) + Document(page_content="chunk2", metadata={"pages": [2]}), ] result = format_chunks_for_llm(text_dict, docs) @@ -225,12 +204,8 @@ class TestFormatChunksForLLM: def test_missing_page_in_text_dict(self): """Test when document references page not in text_dict""" - text_dict = { - "1": "Page 1 content" - } - docs = [ - Document(page_content="chunk", metadata={"pages": [1, 99]}) - ] + text_dict = {"1": "Page 1 content"} + docs = [Document(page_content="chunk", metadata={"pages": [1, 99]})] result = format_chunks_for_llm(text_dict, docs) @@ -239,14 +214,8 @@ class TestFormatChunksForLLM: def test_none_values_in_text_dict(self): """Test handling of None values in text_dict""" - text_dict = { - "1": "Page 1 content", - "2": None, - "3": "Page 3 content" - } - docs = [ - Document(page_content="chunk", metadata={"pages": [1, 2, 3]}) - ] + text_dict = {"1": "Page 1 content", "2": None, "3": "Page 3 content"} + docs = [Document(page_content="chunk", metadata={"pages": [1, 2, 3]})] result = format_chunks_for_llm(text_dict, docs) @@ -257,16 +226,16 @@ class TestFormatChunksForLLM: def test_document_without_pages_metadata(self): """Test document without pages in metadata""" text_dict = {"1": "Page 1 content"} - docs = [ - Document(page_content="chunk", metadata={}) - ] + docs = [Document(page_content="chunk", metadata={})] result = format_chunks_for_llm(text_dict, docs) # Should return empty or handle gracefully assert isinstance(result, str) - @patch('src.investment.hybrid_smart_chunking_funcs.clip_context_by_tokens') + @patch( + "src.pipelines.shared.preprocessing.hybrid_smart_chunking_funcs.clip_context_by_tokens" + ) def test_calls_clip_context(self, mock_clip): """Test that format_chunks_for_llm calls clip_context_by_tokens""" mock_clip.return_value = "clipped context" @@ -280,13 +249,8 @@ class TestFormatChunksForLLM: def test_integer_page_numbers(self): """Test handling of integer page numbers (converted to strings)""" - text_dict = { - "1": "Page 1 content", - "2": "Page 2 content" - } - docs = [ - Document(page_content="chunk", metadata={"pages": [1, 2]}) # Integers - ] + text_dict = {"1": "Page 1 content", "2": "Page 2 content"} + docs = [Document(page_content="chunk", metadata={"pages": [1, 2]})] # Integers result = format_chunks_for_llm(text_dict, docs) @@ -314,7 +278,7 @@ class TestAddPageNumbersToChunks: """Test multiple sections with page markers""" sections = { "Section 1": "Start of Page No. = 5\nContent", - "Section 2": "Start of Page No. = 6\nMore content\nStart of Page No. = 7\nEven more" + "Section 2": "Start of Page No. = 6\nMore content\nStart of Page No. = 7\nEven more", } result = add_page_numbers_to_chunks(sections) @@ -327,7 +291,7 @@ class TestAddPageNumbersToChunks: """Test section without page markers""" sections = { "Section 1": "Start of Page No. = 1\nContent", - "Section 2": "Content without markers" + "Section 2": "Content without markers", } result = add_page_numbers_to_chunks(sections) @@ -367,9 +331,7 @@ class TestAddPageNumbersToChunks: def test_alternative_marker_format(self): """Test alternative page marker format without period""" - sections = { - "Section 1": "Start of Page No = 10\nContent" - } + sections = {"Section 1": "Start of Page No = 10\nContent"} result = add_page_numbers_to_chunks(sections) @@ -379,8 +341,12 @@ class TestAddPageNumbersToChunks: class TestPreprocessingPipeline: """Test preprocessing_pipeline function""" - @patch('src.investment.hybrid_smart_chunking_funcs.hybrid_smart_chunking_preprocessing.split_contract_text_into_sections') - @patch('src.investment.hybrid_smart_chunking_funcs.add_page_numbers_to_chunks') + @patch( + "src.pipelines.shared.preprocessing.hybrid_smart_chunking_funcs.hybrid_smart_chunking_preprocessing.split_contract_text_into_sections" + ) + @patch( + "src.pipelines.shared.preprocessing.hybrid_smart_chunking_funcs.add_page_numbers_to_chunks" + ) def test_pipeline_calls_functions(self, mock_add_pages, mock_split): """Test that pipeline calls the necessary functions""" contract_text = "Test contract text" @@ -388,12 +354,15 @@ class TestPreprocessingPipeline: # Mock split_contract_text_into_sections return mock_sections = {"Section 1": "content"} mock_verification = (True, "Perfect preservation") - mock_split.return_value = (mock_sections, contract_text, "\n", mock_verification) + mock_split.return_value = ( + mock_sections, + contract_text, + "\n", + mock_verification, + ) # Mock add_page_numbers_to_chunks return - mock_sections_with_pages = { - "Section 1": {"content": "content", "pages": [1]} - } + mock_sections_with_pages = {"Section 1": {"content": "content", "pages": [1]}} mock_add_pages.return_value = mock_sections_with_pages sections, is_preserved = preprocessing_pipeline(contract_text) @@ -403,8 +372,12 @@ class TestPreprocessingPipeline: assert is_preserved is True assert sections == mock_sections_with_pages - @patch('src.investment.hybrid_smart_chunking_funcs.hybrid_smart_chunking_preprocessing.split_contract_text_into_sections') - @patch('src.investment.hybrid_smart_chunking_funcs.add_page_numbers_to_chunks') + @patch( + "src.pipelines.shared.preprocessing.hybrid_smart_chunking_funcs.hybrid_smart_chunking_preprocessing.split_contract_text_into_sections" + ) + @patch( + "src.pipelines.shared.preprocessing.hybrid_smart_chunking_funcs.add_page_numbers_to_chunks" + ) def test_pipeline_returns_preservation_status(self, mock_add_pages, mock_split): """Test that pipeline returns preservation status""" # Test successful preservation @@ -421,8 +394,12 @@ class TestPreprocessingPipeline: sections, is_preserved = preprocessing_pipeline("text") assert is_preserved is False - @patch('src.investment.hybrid_smart_chunking_funcs.hybrid_smart_chunking_preprocessing.split_contract_text_into_sections') - @patch('src.investment.hybrid_smart_chunking_funcs.add_page_numbers_to_chunks') + @patch( + "src.pipelines.shared.preprocessing.hybrid_smart_chunking_funcs.hybrid_smart_chunking_preprocessing.split_contract_text_into_sections" + ) + @patch( + "src.pipelines.shared.preprocessing.hybrid_smart_chunking_funcs.add_page_numbers_to_chunks" + ) def test_pipeline_with_real_text(self, mock_add_pages, mock_split): """Test pipeline with realistic contract text""" contract_text = """1 Definitions @@ -432,13 +409,13 @@ Terms content""" mock_sections = { "1 Definitions": "Definition content", - "2 Terms": "Terms content" + "2 Terms": "Terms content", } mock_split.return_value = (mock_sections, contract_text, "\n", (True, "OK")) mock_sections_with_pages = { "1 Definitions": {"content": "Definition content", "pages": [1]}, - "2 Terms": {"content": "Terms content", "pages": [2]} + "2 Terms": {"content": "Terms content", "pages": [2]}, } mock_add_pages.return_value = mock_sections_with_pages diff --git a/fieldExtraction/tests/test_hybrid_smart_chunking_preprocessing.py b/src/tests/test_hybrid_smart_chunking_preprocessing.py similarity index 80% rename from fieldExtraction/tests/test_hybrid_smart_chunking_preprocessing.py rename to src/tests/test_hybrid_smart_chunking_preprocessing.py index ba33686..bc26ac2 100644 --- a/fieldExtraction/tests/test_hybrid_smart_chunking_preprocessing.py +++ b/src/tests/test_hybrid_smart_chunking_preprocessing.py @@ -1,5 +1,5 @@ """ -Unit tests for src.investment.hybrid_smart_chunking_preprocessing module +Unit tests for src.pipelines.shared.preprocessing.hybrid_smart_chunking_preprocessing module Tests contract text preprocessing and section splitting functionality including: - Section identification based on various heading patterns @@ -8,7 +8,7 @@ Tests contract text preprocessing and section splitting functionality including: """ import pytest -from src.investment.hybrid_smart_chunking_preprocessing import ( +from src.pipelines.shared.preprocessing.hybrid_smart_chunking_preprocessing import ( split_contract_text_into_sections, verify_preservation, get_section_info, @@ -21,7 +21,9 @@ class TestSplitContractTextIntoSections: def test_simple_text_no_headings(self): """Test text with no recognizable headings""" text = "This is a simple contract text.\nWith no headings at all." - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert "Preamble" in sections assert sections["Preamble"] == text @@ -31,8 +33,12 @@ class TestSplitContractTextIntoSections: def test_arabic_numbered_headings(self): """Test single-digit arabic numbered headings (1. Title)""" - text = "Preamble text\n1 Definitions\nDefinition content\n2 Terms\nTerms content" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + text = ( + "Preamble text\n1 Definitions\nDefinition content\n2 Terms\nTerms content" + ) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert "Preamble" in sections assert "1 Definitions" in sections @@ -42,7 +48,9 @@ class TestSplitContractTextIntoSections: def test_sub_arabic_numbered_headings(self): """Test multi-level arabic numbered headings (1.1, 1.2, etc.)""" text = "1.1 First Section\nContent A\n1.2 Second Section\nContent B" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert "1.1 First Section" in sections assert "1.2 Second Section" in sections @@ -51,7 +59,9 @@ class TestSplitContractTextIntoSections: def test_roman_numeral_headings(self): """Test roman numeral headings (I. Title, II. Title)""" text = "I Introduction\nIntro content\nII Background\nBackground content" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert "I Introduction" in sections assert "II Background" in sections @@ -60,7 +70,9 @@ class TestSplitContractTextIntoSections: def test_article_headings(self): """Test ARTICLE headings (ARTICLE I Title)""" text = "ARTICLE I Definitions\nDef content\nARTICLE II Terms\nTerms content" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert "ARTICLE I Definitions" in sections assert "ARTICLE II Terms" in sections @@ -69,7 +81,9 @@ class TestSplitContractTextIntoSections: def test_exhibit_headings(self): """Test EXHIBIT headings (EXHIBIT A, EXHIBIT B Title)""" text = "Main text\nEXHIBIT A\nExhibit A content\nEXHIBIT B Schedule\nExhibit B content" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert "EXHIBIT A" in sections assert "EXHIBIT B Schedule" in sections @@ -78,7 +92,9 @@ class TestSplitContractTextIntoSections: def test_attachment_headings(self): """Test Attachment headings""" text = "Contract text\nAttachment 1\nAttachment content" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert "Attachment 1" in sections assert verification[0] is True @@ -86,7 +102,9 @@ class TestSplitContractTextIntoSections: def test_recitals_and_agreement_keywords(self): """Test RECITALS and AGREEMENT keyword headings""" text = "RECITALS:\nRecital text\nAGREEMENT\nAgreement text" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert "RECITALS" in sections assert "AGREEMENT" in sections @@ -95,7 +113,9 @@ class TestSplitContractTextIntoSections: def test_in_witness_whereof_heading(self): """Test IN WITNESS WHEREOF heading""" text = "Contract body\nIN WITNESS WHEREOF\nSignature section" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert "IN WITNESS WHEREOF" in sections assert verification[0] is True @@ -103,7 +123,9 @@ class TestSplitContractTextIntoSections: def test_signatory_headings(self): """Test signatory block headings (PROVIDER:, ICM:)""" text = "Agreement text\nPROVIDER:\nBy: John Doe\nICM:\nBy: Jane Smith" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert "PROVIDER" in sections or "ICM" in sections assert verification[0] is True @@ -111,7 +133,9 @@ class TestSplitContractTextIntoSections: def test_multi_line_headings(self): """Test headings that span multiple lines""" text = "1\nDefinitions and Terms\nContent here\n2\nOther Section\nMore content" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) # Should combine multi-line headings assert any("Definitions" in key for key in sections.keys()) @@ -120,7 +144,9 @@ class TestSplitContractTextIntoSections: def test_duplicate_section_titles(self): """Test handling of duplicate section titles""" text = "1 Terms\nFirst terms\n1 Terms\nSecond terms" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) # Should have unique keys (second occurrence gets suffix) assert "1 Terms" in sections @@ -130,7 +156,9 @@ class TestSplitContractTextIntoSections: def test_windows_line_endings(self): """Test text with Windows line endings (\\r\\n)""" text = "Section 1\r\nContent A\r\nSection 2\r\nContent B" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert line_ending == "\r\n" assert verification[0] is True @@ -138,7 +166,9 @@ class TestSplitContractTextIntoSections: def test_unix_line_endings(self): """Test text with Unix line endings (\\n)""" text = "Section 1\nContent A\nSection 2\nContent B" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert line_ending == "\n" assert verification[0] is True @@ -146,7 +176,9 @@ class TestSplitContractTextIntoSections: def test_no_line_endings(self): """Test text with no line endings""" text = "Single line of text with no breaks" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert line_ending == "" assert "Preamble" in sections @@ -155,7 +187,9 @@ class TestSplitContractTextIntoSections: def test_empty_text(self): """Test empty text input""" text = "" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) # Should handle empty text gracefully assert isinstance(sections, dict) @@ -171,7 +205,9 @@ ARTICLE I Scope Scope content EXHIBIT A Exhibit content""" - sections, original, line_ending, verification = split_contract_text_into_sections(text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(text) + ) assert "RECITALS" in sections assert "1 Definitions" in sections @@ -244,7 +280,7 @@ class TestGetSectionInfo: """Test extracting basic section information""" sections = { "Section 1": "This is section one content", - "Section 2": "This is section two\nWith multiple lines" + "Section 2": "This is section two\nWith multiple lines", } info = get_section_info(sections) @@ -279,7 +315,7 @@ class TestGetSectionInfo: sections = { "Section 1": "12345", # 5 chars "Section 2": "67890", # 5 chars - "Section 3": "ABCDE" # 5 chars + "Section 3": "ABCDE", # 5 chars } info = get_section_info(sections) @@ -290,7 +326,7 @@ class TestGetSectionInfo: """Test line count is calculated correctly""" sections = { "Single Line": "One line only", - "Multi Line": "Line 1\nLine 2\nLine 3" + "Multi Line": "Line 1\nLine 2\nLine 3", } info = get_section_info(sections) @@ -334,7 +370,9 @@ By: _______________ Name: John Doe """ - sections, original, line_ending, verification = split_contract_text_into_sections(contract_text) + sections, original, line_ending, verification = ( + split_contract_text_into_sections(contract_text) + ) # Verify major sections are identified assert "RECITALS" in sections diff --git a/fieldExtraction/tests/test_io_utils.py b/src/tests/test_io_utils.py similarity index 94% rename from fieldExtraction/tests/test_io_utils.py rename to src/tests/test_io_utils.py index 3d4d5cd..a94b427 100644 --- a/fieldExtraction/tests/test_io_utils.py +++ b/src/tests/test_io_utils.py @@ -4,10 +4,18 @@ import os import pandas as pd import pytest from botocore.exceptions import ClientError -from src.utils.io_utils import (filter_already_processed, list_s3_files, - read_input, read_input_csv, read_local, - read_s3, read_s3_csv, read_xlsb, - remove_txt_extension, write_s3) +from src.utils.io_utils import ( + filter_already_processed, + list_s3_files, + read_input, + read_input_csv, + read_local, + read_s3, + read_s3_csv, + read_xlsb, + remove_txt_extension, + write_s3, +) class TestIOUtils: @@ -16,6 +24,7 @@ class TestIOUtils: """Ensure config patches are cleaned up after each test to prevent leakage.""" # Store original config values before test import src.config as config_module + original_values = {} config_attrs = [ "S3_CLIENT", @@ -39,6 +48,7 @@ class TestIOUtils: # Restore original values after test for attr, value in original_values.items(): setattr(config_module, attr, value) + # Fixtures for reusable test data @pytest.fixture def mock_csv_data(self): @@ -211,7 +221,7 @@ class TestIOUtils: mock_batch_id = "mock_batch_123" mocker.patch("src.config.BATCH_ID", mock_batch_id) mock_get_processed_files = mocker.patch( - "src.tracking.tracking_utils.get_processed_files", + "src.utils.tracking_utils.get_processed_files", return_value=(set(["file1.txt"]), set([])), ) mock_write_to_s3 = mocker.patch("src.config.WRITE_TO_S3", True) @@ -221,7 +231,7 @@ class TestIOUtils: assert result_ac == {"file2.txt": "content2"} assert result_b == {"file1.txt": "content1", "file2.txt": "content2"} - # Verify src.tracking.tracking_utils.get_processed_files was called + # Verify src.utils.tracking_utils.get_processed_files was called mock_get_processed_files.assert_called_once_with(mock_batch_id) def test_filter_already_processed_local(self, mocker): @@ -342,7 +352,10 @@ class TestIOUtils: mock_s3_client.put_object.assert_called_once() call_kwargs = mock_s3_client.put_object.call_args[1] assert call_kwargs["Bucket"] == "test-bucket" - assert call_kwargs["Key"] == "test_batch_123/20240101120000/test_batch_123-RESULTS.csv" + assert ( + call_kwargs["Key"] + == "test_batch_123/20240101120000/test_batch_123-RESULTS.csv" + ) assert isinstance(call_kwargs["Body"], bytes) assert b"col1,col2" in call_kwargs["Body"] @@ -358,7 +371,10 @@ class TestIOUtils: write_s3(df, "", "20240101120000", "error") call_kwargs = mock_s3_client.put_object.call_args[1] - assert call_kwargs["Key"] == "test_batch_123/20240101120000/test_batch_123-ERRORS.csv" + assert ( + call_kwargs["Key"] + == "test_batch_123/20240101120000/test_batch_123-ERRORS.csv" + ) def test_write_s3_usage(self, mocker): """Test write_s3 with usage output_type as used in main.py.""" @@ -372,7 +388,10 @@ class TestIOUtils: write_s3(df, "", "20240101120000", "usage") call_kwargs = mock_s3_client.put_object.call_args[1] - assert call_kwargs["Key"] == "test_batch_123/20240101120000/tracking/test_batch_123-USAGE.csv" + assert ( + call_kwargs["Key"] + == "test_batch_123/20240101120000/tracking/test_batch_123-USAGE.csv" + ) def test_write_s3_usage_summary(self, mocker): """Test write_s3 with usage_summary output_type as used in main.py.""" @@ -386,7 +405,10 @@ class TestIOUtils: write_s3(df, "", "20240101120000", "usage_summary") call_kwargs = mock_s3_client.put_object.call_args[1] - assert call_kwargs["Key"] == "test_batch_123/20240101120000/tracking/test_batch_123-USAGE-SUMMARY.csv" + assert ( + call_kwargs["Key"] + == "test_batch_123/20240101120000/tracking/test_batch_123-USAGE-SUMMARY.csv" + ) def test_write_s3_client_error(self, mocker): """Test write_s3 error handling when S3 upload fails.""" @@ -476,8 +498,8 @@ class TestIOUtils: mock_to_csv.assert_called_once() call_args = mock_to_csv.call_args[0][0] - # Check output path includes qa_qc_output folder - assert "qa_qc_output" in call_args + # Check output path includes outputs/qc_qa folder + assert "outputs/qc_qa" in call_args assert "QC-QA-VALIDATED.csv" in call_args def test_write_local_qc_qa_stats(self, mocker, tmp_path): @@ -494,6 +516,6 @@ class TestIOUtils: mock_to_csv.assert_called_once() call_args = mock_to_csv.call_args[0][0] - # Check output path includes qa_qc_output folder and correct filename - assert "qa_qc_output" in call_args + # Check output path includes outputs/qc_qa folder and correct filename + assert "outputs/qc_qa" in call_args assert "QC-QA-STATS.csv" in call_args diff --git a/fieldExtraction/tests/test_llm_utils.py b/src/tests/test_llm_utils.py similarity index 84% rename from fieldExtraction/tests/test_llm_utils.py rename to src/tests/test_llm_utils.py index b789e0f..06d5030 100644 --- a/fieldExtraction/tests/test_llm_utils.py +++ b/src/tests/test_llm_utils.py @@ -29,13 +29,15 @@ class TestLLMUtils(unittest.TestCase): """Test cache key includes instruction parameter.""" model_id = "test_model" instruction = "You are a helpful assistant." - + key1 = llm_utils.get_cache_key(self.prompt, model_id, instruction=instruction) - key2 = llm_utils.get_cache_key(self.prompt, model_id, instruction="Different instruction") - + key2 = llm_utils.get_cache_key( + self.prompt, model_id, instruction="Different instruction" + ) + # Keys should be different when instruction differs self.assertNotEqual(key1, key2) - + # Same instruction should produce same key key3 = llm_utils.get_cache_key(self.prompt, model_id, instruction=instruction) self.assertEqual(key1, key3) @@ -43,13 +45,13 @@ class TestLLMUtils(unittest.TestCase): def test_get_cache_key_with_max_tokens(self): """Test cache key includes max_tokens parameter.""" model_id = "test_model" - + key1 = llm_utils.get_cache_key(self.prompt, model_id, max_tokens=100) key2 = llm_utils.get_cache_key(self.prompt, model_id, max_tokens=200) - + # Keys should be different when max_tokens differs self.assertNotEqual(key1, key2) - + # Same max_tokens should produce same key key3 = llm_utils.get_cache_key(self.prompt, model_id, max_tokens=100) self.assertEqual(key1, key3) @@ -57,10 +59,10 @@ class TestLLMUtils(unittest.TestCase): def test_get_cache_key_with_cache_flag(self): """Test cache key includes cache flag.""" model_id = "test_model" - + key1 = llm_utils.get_cache_key(self.prompt, model_id, cache=False) key2 = llm_utils.get_cache_key(self.prompt, model_id, cache=True) - + # Keys should be different when cache flag differs self.assertNotEqual(key1, key2) @@ -69,20 +71,32 @@ class TestLLMUtils(unittest.TestCase): model_id = "test_model" instruction = "You are helpful" max_tokens = 100 - + key1 = llm_utils.get_cache_key( - self.prompt, model_id, instruction=instruction, max_tokens=max_tokens, cache=True + self.prompt, + model_id, + instruction=instruction, + max_tokens=max_tokens, + cache=True, ) key2 = llm_utils.get_cache_key( - self.prompt, model_id, instruction=instruction, max_tokens=max_tokens, cache=True + self.prompt, + model_id, + instruction=instruction, + max_tokens=max_tokens, + cache=True, ) - + # Same parameters should produce same key self.assertEqual(key1, key2) - + # Different parameters should produce different keys key3 = llm_utils.get_cache_key( - self.prompt, model_id, instruction="Different", max_tokens=max_tokens, cache=True + self.prompt, + model_id, + instruction="Different", + max_tokens=max_tokens, + cache=True, ) self.assertNotEqual(key1, key3) @@ -90,17 +104,17 @@ class TestLLMUtils(unittest.TestCase): """Test cache key generation for image arrays.""" model_id = "test_model" image_list = ["base64_image1", "base64_image2"] - + key1 = llm_utils.get_cache_key_with_image_array( self.prompt, model_id, image_list, max_tokens=100 ) key2 = llm_utils.get_cache_key_with_image_array( self.prompt, model_id, image_list, max_tokens=200 ) - + # Keys should be different when max_tokens differs self.assertNotEqual(key1, key2) - + # Same parameters should produce same key key3 = llm_utils.get_cache_key_with_image_array( self.prompt, model_id, image_list, max_tokens=100 @@ -111,13 +125,13 @@ class TestLLMUtils(unittest.TestCase): """Test thread safety with concurrent cache reads.""" model_id = "test_model" cache_key = llm_utils.get_cache_key(self.prompt, model_id) - + # Pre-populate cache llm_utils.claude_cache[cache_key] = self.response - + results = [] errors = [] - + def read_cache(): try: # Simulate cache read @@ -127,17 +141,17 @@ class TestLLMUtils(unittest.TestCase): results.append(result) except Exception as e: errors.append(e) - + # Create multiple threads reading from cache threads = [] for _ in range(10): thread = threading.Thread(target=read_cache) threads.append(thread) thread.start() - + for thread in threads: thread.join() - + # Verify no errors and all reads succeeded self.assertEqual(len(errors), 0) self.assertEqual(len(results), 10) @@ -147,28 +161,28 @@ class TestLLMUtils(unittest.TestCase): """Test thread safety with concurrent cache writes.""" model_id = "test_model" num_threads = 10 - + def write_to_cache(thread_id): prompt = f"prompt_{thread_id}" response = f"response_{thread_id}" cache_key = llm_utils.get_cache_key(prompt, model_id) - + # Simulate cache write with lock with llm_utils._cache_lock: if len(llm_utils.claude_cache) >= llm_utils.CACHE_LIMIT: llm_utils.claude_cache.popitem(last=False) llm_utils.claude_cache[cache_key] = response llm_utils.claude_cache.move_to_end(cache_key) - + threads = [] for i in range(num_threads): thread = threading.Thread(target=write_to_cache, args=(i,)) threads.append(thread) thread.start() - + for thread in threads: thread.join() - + # Verify all writes succeeded (cache should have entries) self.assertGreater(len(llm_utils.claude_cache), 0) self.assertLessEqual(len(llm_utils.claude_cache), num_threads) @@ -178,40 +192,40 @@ class TestLLMUtils(unittest.TestCase): model_id = "test_model" initial_key = llm_utils.get_cache_key("initial_prompt", model_id) llm_utils.claude_cache[initial_key] = "initial_response" - + read_count = [0] write_count = [0] - + def read_operation(): with llm_utils._cache_lock: if initial_key in llm_utils.claude_cache: _ = llm_utils.claude_cache[initial_key] read_count[0] += 1 - + def write_operation(thread_id): prompt = f"write_prompt_{thread_id}" response = f"write_response_{thread_id}" cache_key = llm_utils.get_cache_key(prompt, model_id) - + with llm_utils._cache_lock: if len(llm_utils.claude_cache) >= llm_utils.CACHE_LIMIT: llm_utils.claude_cache.popitem(last=False) llm_utils.claude_cache[cache_key] = response write_count[0] += 1 - + threads = [] # Mix of read and write threads for i in range(5): threads.append(threading.Thread(target=read_operation)) for i in range(5): threads.append(threading.Thread(target=write_operation, args=(i,))) - + for thread in threads: thread.start() - + for thread in threads: thread.join() - + # Verify operations completed without errors self.assertEqual(read_count[0], 5) self.assertEqual(write_count[0], 5) @@ -224,7 +238,9 @@ class TestLLMUtils(unittest.TestCase): config.RUN_MODE = "local" model_id = config.MODEL_ID_CLAUDE35_SONNET - with patch("src.utils.llm_utils.local_claude_3_and_up", return_value=self.response): + with patch( + "src.utils.llm_utils.local_claude_3_and_up", return_value=self.response + ): response = llm_utils.invoke_claude(self.prompt, model_id, self.filename) self.assertEqual(response, self.response) finally: @@ -241,18 +257,28 @@ class TestLLMUtils(unittest.TestCase): max_tokens = 100 cache = True - with patch("src.utils.llm_utils.local_claude_3_and_up", return_value=self.response): + with patch( + "src.utils.llm_utils.local_claude_3_and_up", return_value=self.response + ): # First call should not use cache (cache is empty) response1 = llm_utils.invoke_claude( - self.prompt, model_id, self.filename, - max_tokens=max_tokens, cache=cache, instruction=instruction + self.prompt, + model_id, + self.filename, + max_tokens=max_tokens, + cache=cache, + instruction=instruction, ) - + # Second call with same parameters should use cache with patch("src.utils.llm_utils.local_claude_3_and_up") as mock_local: response2 = llm_utils.invoke_claude( - self.prompt, model_id, self.filename, - max_tokens=max_tokens, cache=cache, instruction=instruction + self.prompt, + model_id, + self.filename, + max_tokens=max_tokens, + cache=cache, + instruction=instruction, ) # Should not call local_claude_3_and_up again (cache hit) mock_local.assert_not_called() @@ -265,7 +291,7 @@ class TestLLMUtils(unittest.TestCase): """Test that token tracking uses exact API response counts, not estimates.""" # This test verifies that we're using usage_tracking.extract_usage_from_response() # which gets exact counts from API, not estimated counts like len(prompt.split()) - + # Mock API response with exact token counts mock_response_body = { "usage": { @@ -275,19 +301,20 @@ class TestLLMUtils(unittest.TestCase): "cache_read_input_tokens": 30, } } - + # Verify extract_usage_from_response extracts exact counts import src.utils.usage_tracking as usage_tracking + input_tokens, output_tokens, cache_creation, cache_read = ( usage_tracking.extract_usage_from_response(mock_response_body) ) - + # Should match exact API response, not estimates self.assertEqual(input_tokens, 150) self.assertEqual(output_tokens, 75) self.assertEqual(cache_creation, 20) self.assertEqual(cache_read, 30) - + # Verify these are not estimated (e.g., len(prompt.split())) # Exact counts from API are integers, not based on string length self.assertIsInstance(input_tokens, int) @@ -297,8 +324,7 @@ class TestLLMUtils(unittest.TestCase): """Test that deprecated Claude 2 models raise ValueError.""" with self.assertRaises(ValueError) as context: llm_utils._validate_model_support( - "anthropic.claude-instant-v1", - "anthropic.claude-instant-v1" + "anthropic.claude-instant-v1", "anthropic.claude-instant-v1" ) self.assertIn("Claude 2 is no longer supported", str(context.exception)) @@ -307,19 +333,19 @@ class TestLLMUtils(unittest.TestCase): # Should not raise an exception try: llm_utils._validate_model_support( - config.MODEL_ID_CLAUDE45_HAIKU, - config.MODEL_ID_CLAUDE45_HAIKU + config.MODEL_ID_CLAUDE45_HAIKU, config.MODEL_ID_CLAUDE45_HAIKU ) except ValueError: - self.fail("_validate_model_support raised ValueError for supported Claude 3 Haiku model") + self.fail( + "_validate_model_support raised ValueError for supported Claude 3 Haiku model" + ) def test_validate_model_support_supported_model(self): """Test that supported models pass validation.""" # Should not raise an exception try: llm_utils._validate_model_support( - config.MODEL_ID_CLAUDE35_SONNET, - config.MODEL_ID_CLAUDE35_SONNET + config.MODEL_ID_CLAUDE35_SONNET, config.MODEL_ID_CLAUDE35_SONNET ) except ValueError: self.fail("_validate_model_support raised ValueError for supported model") @@ -327,10 +353,7 @@ class TestLLMUtils(unittest.TestCase): def test_validate_model_support_unsupported_model(self): """Test that unsupported models raise ValueError.""" with self.assertRaises(ValueError) as context: - llm_utils._validate_model_support( - "unknown.model.id", - "unknown.model.id" - ) + llm_utils._validate_model_support("unknown.model.id", "unknown.model.id") self.assertIn("Only Claude 3+ models are supported", str(context.exception)) self.assertIn("Haiku", str(context.exception)) @@ -338,9 +361,7 @@ class TestLLMUtils(unittest.TestCase): """Test that context parameter is included in error messages.""" with self.assertRaises(ValueError) as context: llm_utils._validate_model_support( - "unknown.model.id", - "unknown.model.id", - context="for image array" + "unknown.model.id", "unknown.model.id", context="for image array" ) self.assertIn("for image array", str(context.exception)) @@ -348,31 +369,37 @@ class TestLLMUtils(unittest.TestCase): """Test that models supporting prompt cache return True.""" # Test Claude 3.7 Sonnet if config.MODEL_ID_CLAUDE37_SONNET: - self.assertTrue(llm_utils._supports_prompt_cache(config.MODEL_ID_CLAUDE37_SONNET)) - + self.assertTrue( + llm_utils._supports_prompt_cache(config.MODEL_ID_CLAUDE37_SONNET) + ) + # Test Claude 4 Sonnet if config.MODEL_ID_CLAUDE4_SONNET: - self.assertTrue(llm_utils._supports_prompt_cache(config.MODEL_ID_CLAUDE4_SONNET)) - + self.assertTrue( + llm_utils._supports_prompt_cache(config.MODEL_ID_CLAUDE4_SONNET) + ) + # Test Claude 4.5 Sonnet if config.MODEL_ID_CLAUDE45_SONNET: - self.assertTrue(llm_utils._supports_prompt_cache(config.MODEL_ID_CLAUDE45_SONNET)) + self.assertTrue( + llm_utils._supports_prompt_cache(config.MODEL_ID_CLAUDE45_SONNET) + ) def test_supports_prompt_cache_unsupported_models(self): """Test that models not supporting prompt cache return False.""" # Claude 3.5 Sonnet v1 doesn't support caching (only v2+) if config.MODEL_ID_CLAUDE35_SONNET: - self.assertFalse(llm_utils._supports_prompt_cache(config.MODEL_ID_CLAUDE35_SONNET)) - + self.assertFalse( + llm_utils._supports_prompt_cache(config.MODEL_ID_CLAUDE35_SONNET) + ) + # Unknown model self.assertFalse(llm_utils._supports_prompt_cache("unknown.model.id")) def test_build_claude_3_request_body_basic(self): """Test building request body without instruction.""" - body = llm_utils._build_claude_3_request_body( - "test prompt", max_tokens=100 - ) - + body = llm_utils._build_claude_3_request_body("test prompt", max_tokens=100) + self.assertEqual(body["anthropic_version"], "bedrock-2023-05-31") self.assertEqual(body["max_tokens"], 100) self.assertEqual(body["temperature"], 0.0) @@ -386,7 +413,7 @@ class TestLLMUtils(unittest.TestCase): body = llm_utils._build_claude_3_request_body( "test prompt", max_tokens=100, instruction=instruction, cache=False ) - + self.assertEqual(body["system"], instruction) self.assertNotIsInstance(body["system"], list) @@ -394,13 +421,16 @@ class TestLLMUtils(unittest.TestCase): """Test building request body with caching enabled for supported model.""" instruction = "You are a helpful assistant." model_id = config.MODEL_ID_CLAUDE37_SONNET or config.MODEL_ID_CLAUDE4_SONNET - + if model_id and llm_utils._supports_prompt_cache(model_id): body = llm_utils._build_claude_3_request_body( - "test prompt", max_tokens=100, instruction=instruction, - cache=True, model_id=model_id + "test prompt", + max_tokens=100, + instruction=instruction, + cache=True, + model_id=model_id, ) - + # Should use array format with cache_control self.assertIsInstance(body["system"], list) self.assertEqual(len(body["system"]), 1) @@ -412,13 +442,16 @@ class TestLLMUtils(unittest.TestCase): """Test building request body with caching enabled for unsupported model.""" instruction = "You are a helpful assistant." model_id = config.MODEL_ID_CLAUDE35_SONNET # v1 doesn't support caching - + if model_id: body = llm_utils._build_claude_3_request_body( - "test prompt", max_tokens=100, instruction=instruction, - cache=True, model_id=model_id + "test prompt", + max_tokens=100, + instruction=instruction, + cache=True, + model_id=model_id, ) - + # Should use simple string format (no cache_control) self.assertEqual(body["system"], instruction) self.assertNotIsInstance(body["system"], list) diff --git a/src/tests/test_one_to_n.py b/src/tests/test_one_to_n.py new file mode 100644 index 0000000..7af43e8 --- /dev/null +++ b/src/tests/test_one_to_n.py @@ -0,0 +1,1068 @@ +import unittest +from unittest.mock import Mock, patch, MagicMock +from src.pipelines.shared import one_to_n_funcs +from src.pipelines.saas.prompts import prompt_calls +from src.prompts.fieldset import FieldSet +from src.constants.constants import Constants +import json + + +class TestOneToNFuncs(unittest.TestCase): + """Test suite for one_to_n_funcs.py functions.""" + + def setUp(self): + """Set up test fixtures.""" + self.constants = Constants() + self.filename = "test_contract.pdf" + self.exhibit_text = "This is a sample exhibit text with reimbursement terms." + self.exhibit_header = "Exhibit A - Fee Schedule" + self.exhibit_page = "1" + + # ==================== exhibit_level Tests ==================== + + @patch("src.utils.llm_utils.invoke_claude") # Mock at the invoke_claude level + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.dynamic_funcs.dynamic_primary" + ) + def test_exhibit_level_basic(self, mock_dynamic_primary, mock_invoke_claude): + """Test basic exhibit level processing.""" + # Mock LLM response for dynamic_primary call + mock_invoke_claude.return_value = ( + '{"AARETE_DERIVED_LOB": "Medicaid", "AARETE_DERIVED_NETWORK": "In-Network"}' + ) + + # Mock dynamic primary returning updated answers and fields + mock_dynamic_fields = Mock(spec=FieldSet) + mock_dynamic_primary.return_value = ( + { + "SERVICE_CATEGORY_CD": "INPATIENT", + "PROV_TYPE_CD": "HOSPITAL", + "AARETE_DERIVED_LOB": "Medicaid", + }, + mock_dynamic_fields, + ) + + exhibit_level_answers, dynamic_fields = one_to_n_funcs.exhibit_level( + self.exhibit_text, + self.exhibit_header, + self.exhibit_page, + self.constants, + self.filename, + ) + + # Assertions + assert exhibit_level_answers is not None + mock_invoke_claude.assert_called() + + # ==================== reimbursement_level Tests ==================== + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_reimbursement_primary" + ) + @patch("src.pipelines.shared.extraction.one_to_n_funcs.clean_reimbursement_primary") + def test_reimbursement_level_with_results(self, mock_clean, mock_prompt_reimb): + """Test reimbursement level extraction with valid results.""" + mock_prompt_reimb.return_value = [ + {"SERVICE_TERM": "Lab Services", "REIMB_TERM": "100% of Medicare"}, + {"SERVICE_TERM": "Radiology", "REIMB_TERM": "90% of billed charges"}, + ] + mock_clean.return_value = mock_prompt_reimb.return_value + + page_text = "Lab Services will be reimbursed at 100% of Medicare." + result = one_to_n_funcs.reimbursement_level( + page_text, self.constants, self.filename + ) + + self.assertEqual(len(result), 2) + mock_prompt_reimb.assert_called_once_with(page_text, self.filename) + mock_clean.assert_called_once() + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_reimbursement_primary" + ) + def test_reimbursement_level_no_results(self, mock_prompt_reimb): + """Test reimbursement level when no reimbursements found.""" + mock_prompt_reimb.return_value = None + + page_text = "This page has no reimbursement information." + result = one_to_n_funcs.reimbursement_level( + page_text, self.constants, self.filename + ) + + self.assertIsNone(result) + + # ==================== clean_reimbursement_primary Tests ==================== + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.filter_services_without_reimbursements" + ) + def test_clean_reimbursement_primary_basic(self, mock_filter): + """Test basic cleaning of reimbursement primary answers.""" + input_answers = [ + {"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"}, + {"SERVICE_TERM": "X-Ray", "REIMB_TERM": "Fee schedule"}, + ] + mock_filter.return_value = input_answers + + result = one_to_n_funcs.clean_reimbursement_primary( + input_answers, self.constants, self.filename + ) + + self.assertEqual(len(result), 2) + mock_filter.assert_called_once_with(input_answers, self.filename) + + def test_clean_reimbursement_primary_empty_input(self): + """Test cleaning with empty input.""" + result = one_to_n_funcs.clean_reimbursement_primary( + [], self.constants, self.filename + ) + self.assertEqual(result, []) + + def test_clean_reimbursement_primary_none_input(self): + """Test cleaning with None input.""" + result = one_to_n_funcs.clean_reimbursement_primary( + None, self.constants, self.filename + ) + self.assertEqual(result, []) + + # ==================== methodology_breakout Tests ==================== + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.methodology_breakout_single_row" + ) + def test_methodology_breakout_multiple_rows(self, mock_single_row): + """Test methodology breakout with multiple rows.""" + mock_single_row.side_effect = [ + [{"SERVICE_TERM": "Labs", "AARETE_DERIVED_REIMB_METHOD": "Fee Schedule"}], + [{"SERVICE_TERM": "Surgery", "AARETE_DERIVED_REIMB_METHOD": "Grouper"}], + ] + + input_answers = [ + {"SERVICE_TERM": "Labs", "REIMB_TERM": "Medicare fee schedule"}, + {"SERVICE_TERM": "Surgery", "REIMB_TERM": "MS-DRG"}, + ] + + result = one_to_n_funcs.methodology_breakout( + input_answers, self.constants, self.filename + ) + + self.assertEqual(len(result), 2) + self.assertEqual(mock_single_row.call_count, 2) + + # ==================== methodology_breakout_single_row Tests ==================== + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_methodology_breakout" + ) + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.methodology_breakout_secondary" + ) + def test_methodology_breakout_single_row_basic(self, mock_secondary, mock_prompt): + """Test single row methodology breakout.""" + mock_prompt.return_value = { + "AARETE_DERIVED_REIMB_METHOD": "Fee Schedule", + "REIMB_FEE_RATE": "N/A", + "REIMB_PCT_RATE": "100", + } + mock_secondary.return_value = {"FEE_SCHEDULE": "Medicare"} + + answer_dict = {"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"} + + result = one_to_n_funcs.methodology_breakout_single_row( + answer_dict, self.constants, self.filename + ) + + self.assertEqual(len(result), 1) + self.assertIn("AARETE_DERIVED_REIMB_METHOD", result[0]) + self.assertIn("FEE_SCHEDULE", result[0]) + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_methodology_breakout" + ) + def test_methodology_breakout_single_row_no_reimb_term(self, mock_prompt): + """Test single row breakout when REIMB_TERM is missing.""" + answer_dict = {"SERVICE_TERM": "Labs"} + + result = one_to_n_funcs.methodology_breakout_single_row( + answer_dict, self.constants, self.filename + ) + + self.assertEqual(result, [answer_dict]) + mock_prompt.assert_not_called() + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_methodology_breakout" + ) + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.methodology_breakout_secondary" + ) + def test_methodology_breakout_single_row_list_output( + self, mock_secondary, mock_prompt + ): + """Test single row breakout when LLM returns list of methodologies.""" + mock_prompt.return_value = [ + {"AARETE_DERIVED_REIMB_METHOD": "Fee Schedule"}, + {"AARETE_DERIVED_REIMB_METHOD": "Per Diem"}, + ] + mock_secondary.side_effect = [ + {"FEE_SCHEDULE": "Medicare"}, + {"FEE_SCHEDULE": "N/A"}, + ] + + answer_dict = {"SERVICE_TERM": "Labs", "REIMB_TERM": "Medicare or $500 per day"} + + result = one_to_n_funcs.methodology_breakout_single_row( + answer_dict, self.constants, self.filename + ) + + self.assertEqual(len(result), 2) + self.assertEqual(mock_secondary.call_count, 2) + + # ==================== methodology_breakout_secondary Tests ==================== + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_fee_schedule_breakout" + ) + def test_methodology_breakout_secondary_fee_schedule(self, mock_fs_breakout): + """Test secondary breakout for Fee Schedule methodology.""" + mock_fs_breakout.return_value = { + "FEE_SCHEDULE": "Medicare", + "FEE_SCHEDULE_VERSION": "2024", + } + + methodology_dict = {"AARETE_DERIVED_REIMB_METHOD": "Fee Schedule"} + + with patch( + "src.pipelines.shared.extraction.one_to_n_funcs.FieldSet" + ) as mock_fieldset: + mock_grouper_fields = Mock() + mock_grouper_fields.list_fields.return_value = [ + "GROUPER_TYPE", + "DRG_WEIGHT_TYPE", + ] + mock_fieldset.return_value = mock_grouper_fields + + result = one_to_n_funcs.methodology_breakout_secondary( + methodology_dict, + "Labs", + "Medicare fee schedule", + Mock(), + mock_grouper_fields, + self.constants, + self.filename, + ) + + self.assertIn("FEE_SCHEDULE", result) + self.assertEqual(result["GROUPER_TYPE"], "N/A") + self.assertEqual(result["DRG_WEIGHT_TYPE"], "N/A") + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_grouper_breakout" + ) + def test_methodology_breakout_secondary_grouper(self, mock_grouper_breakout): + """Test secondary breakout for Grouper methodology.""" + mock_grouper_breakout.return_value = { + "GROUPER_TYPE": "MS-DRG", + "DRG_WEIGHT_TYPE": "CMS", + } + + methodology_dict = {"AARETE_DERIVED_REIMB_METHOD": "Grouper"} + + with patch( + "src.pipelines.shared.extraction.one_to_n_funcs.FieldSet" + ) as mock_fieldset: + mock_fs_fields = Mock() + mock_fs_fields.list_fields.return_value = [ + "FEE_SCHEDULE", + "FEE_SCHEDULE_VERSION", + ] + mock_fieldset.return_value = mock_fs_fields + + result = one_to_n_funcs.methodology_breakout_secondary( + methodology_dict, + "Surgery", + "MS-DRG", + mock_fs_fields, + Mock(), + self.constants, + self.filename, + ) + + self.assertIn("GROUPER_TYPE", result) + self.assertEqual(result["FEE_SCHEDULE"], "N/A") + self.assertEqual(result["FEE_SCHEDULE_VERSION"], "N/A") + + def test_methodology_breakout_secondary_other_methodology(self): + """Test secondary breakout for non-FS, non-Grouper methodology.""" + methodology_dict = {"AARETE_DERIVED_REIMB_METHOD": "Per Diem"} + + with patch( + "src.pipelines.shared.extraction.one_to_n_funcs.FieldSet" + ) as mock_fieldset: + mock_fields = Mock() + mock_fields.list_fields.return_value = ["FEE_SCHEDULE", "GROUPER_TYPE"] + mock_fieldset.return_value = mock_fields + + result = one_to_n_funcs.methodology_breakout_secondary( + methodology_dict, + "Inpatient", + "$500 per day", + mock_fields, + mock_fields, + self.constants, + self.filename, + ) + + self.assertEqual(result["FEE_SCHEDULE"], "N/A") + self.assertEqual(result["GROUPER_TYPE"], "N/A") + + # ==================== carveout_and_special_case Tests ==================== + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_carveout_check" + ) + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_special_case_breakout" + ) + def test_carveout_and_special_case_base_covered( + self, mock_special_breakout, mock_carveout_check + ): + """Test carveout check for BASE_COVERED_SERVICES.""" + mock_carveout_check.return_value = "BASE_COVERED_SERVICES" + + input_answers = [{"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"}] + + reimb_answers, special_answers = one_to_n_funcs.carveout_and_special_case( + input_answers, self.constants, self.filename + ) + + self.assertEqual(len(reimb_answers), 1) + self.assertEqual(len(special_answers), 0) + self.assertEqual(reimb_answers[0]["CARVEOUT_CD"], "BASE_COVERED_SERVICES") + self.assertEqual(reimb_answers[0]["CARVEOUT_IND"], "N") + self.assertEqual(reimb_answers[0]["DEFAULT_IND"], "N") + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_carveout_check" + ) + def test_carveout_and_special_case_default_term(self, mock_carveout_check): + """Test carveout check for DEFAULT_TERM.""" + mock_carveout_check.return_value = "DEFAULT_TERM" + + input_answers = [ + {"SERVICE_TERM": "All other services", "REIMB_TERM": "As negotiated"} + ] + + reimb_answers, special_answers = one_to_n_funcs.carveout_and_special_case( + input_answers, self.constants, self.filename + ) + + self.assertEqual(reimb_answers[0]["CARVEOUT_CD"], "DEFAULT_TERM") + self.assertEqual(reimb_answers[0]["CARVEOUT_IND"], "N") + self.assertEqual(reimb_answers[0]["DEFAULT_IND"], "Y") + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_carveout_check" + ) + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_special_case_breakout" + ) + def test_carveout_and_special_case_trigger_cap( + self, mock_special_breakout, mock_carveout_check + ): + """Test carveout check for TRIGGER_CAP with breakout.""" + mock_carveout_check.return_value = "TRIGGER_CAP" + mock_special_breakout.return_value = { + "TRIGGER_AMOUNT": "$10000", + "CAP_AMOUNT": "$50000", + } + + input_answers = [ + {"SERVICE_TERM": "Surgery", "REIMB_TERM": "Trigger at $10k, cap at $50k"} + ] + + reimb_answers, special_answers = one_to_n_funcs.carveout_and_special_case( + input_answers, self.constants, self.filename + ) + + self.assertEqual(reimb_answers[0]["CARVEOUT_CD"], "TRIGGER_CAP") + self.assertEqual(reimb_answers[0]["CARVEOUT_IND"], "Y") + self.assertEqual(reimb_answers[0]["DEFAULT_IND"], "N") + self.assertIn("TRIGGER_AMOUNT", reimb_answers[0]) + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_carveout_check" + ) + def test_carveout_and_special_case_special_case_field(self, mock_carveout_check): + """Test when result is a special case field, not a carveout.""" + mock_carveout_check.return_value = "OUTLIER_TERM" + + input_answers = [ + { + "SERVICE_TERM": "High-cost cases", + "REIMB_TERM": "Outlier payment above $25,000", + } + ] + + reimb_answers, special_answers = one_to_n_funcs.carveout_and_special_case( + input_answers, self.constants, self.filename + ) + + self.assertEqual(len(reimb_answers), 0) + self.assertEqual(len(special_answers), 1) + self.assertIn("OUTLIER_TERM", special_answers[0]) + self.assertNotIn("SERVICE_TERM", special_answers[0]) + self.assertNotIn("REIMB_TERM", special_answers[0]) + + # ==================== special_case_breakout Tests ==================== + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_special_case_breakout" + ) + def test_special_case_breakout_outlier(self, mock_breakout): + """Test special case breakout for outlier terms.""" + mock_breakout.return_value = { + "OUTLIER_THRESHOLD": "$25000", + "OUTLIER_PAYMENT_METHOD": "Cost-based", + } + + input_answers = [ + {"OUTLIER_TERM": "Outlier payment for cases exceeding $25,000"} + ] + + with patch( + "src.pipelines.shared.extraction.one_to_n_funcs.FieldSet" + ) as mock_fieldset: + mock_field = Mock() + mock_field.get_breakout_template.return_value = "OUTLIER_BREAKOUT template" + + mock_fields = Mock() + mock_fields.get_field.return_value = mock_field + mock_fieldset.return_value = mock_fields + + result = one_to_n_funcs.special_case_breakout(input_answers, self.filename) + + self.assertEqual(len(result), 1) + self.assertIn("OUTLIER_THRESHOLD", result[0]) + self.assertIn("OUTLIER_PAYMENT_METHOD", result[0]) + + # ==================== filter_services_without_reimbursements Tests ==================== + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.validate_reimbursements_for_llm" + ) + def test_filter_services_all_valid(self, mock_validate): + """Test filtering when all services have valid reimbursements.""" + mock_validate.return_value = True + + input_answers = [ + {"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"}, + {"SERVICE_TERM": "X-Ray", "REIMB_TERM": "Fee schedule"}, + ] + + result = one_to_n_funcs.filter_services_without_reimbursements( + input_answers, self.filename + ) + + self.assertEqual(len(result), 2) + self.assertEqual(mock_validate.call_count, 2) + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.validate_reimbursements_for_llm" + ) + def test_filter_services_some_invalid(self, mock_validate): + """Test filtering when some services lack reimbursements.""" + mock_validate.side_effect = [True, False, True] + + input_answers = [ + {"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"}, + { + "SERVICE_TERM": "Definitions", + "REIMB_TERM": "Standard eyeglass lenses as defined by DMAP", + }, + {"SERVICE_TERM": "Surgery", "REIMB_TERM": "MS-DRG"}, + ] + + result = one_to_n_funcs.filter_services_without_reimbursements( + input_answers, self.filename + ) + + self.assertEqual(len(result), 2) + self.assertEqual(result[0]["SERVICE_TERM"], "Labs") + self.assertEqual(result[1]["SERVICE_TERM"], "Surgery") + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.validate_reimbursements_for_llm" + ) + def test_filter_services_all_invalid(self, mock_validate): + """Test filtering when all services are invalid.""" + mock_validate.return_value = False + + input_answers = [ + {"SERVICE_TERM": "Admin", "REIMB_TERM": "Administrative terms apply"}, + {"SERVICE_TERM": "Definitions", "REIMB_TERM": "See glossary"}, + ] + + result = one_to_n_funcs.filter_services_without_reimbursements( + input_answers, self.filename + ) + + self.assertEqual(len(result), 0) + + # ==================== split_reimb_dates Tests ==================== + + @patch("src.pipelines.shared.extraction.one_to_n_funcs.llm_utils.invoke_claude") + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.string_utils.universal_json_load" + ) + def test_split_reimb_dates_valid_range(self, mock_json_load, mock_invoke): + """Test splitting valid date range.""" + mock_invoke.return_value = ( + '{"start_date": "2024-01-01", "end_date": "2024-12-31"}' + ) + mock_json_load.return_value = { + "start_date": "2024-01-01", + "end_date": "2024-12-31", + } + + input_data = [ + { + "SERVICE_TERM": "Labs", + "REIMB_DATES": "January 1, 2024 through December 31, 2024", + } + ] + + result = one_to_n_funcs.split_reimb_dates(input_data, self.filename) + + self.assertEqual(result[0]["REIMB_EFFECTIVE_DT"], "2024-01-01") + self.assertEqual(result[0]["REIMB_TERMINATION_DT"], "2024-12-31") + self.assertNotIn("REIMB_DATES", result[0]) + + def test_split_reimb_dates_no_dates(self): + """Test splitting when no REIMB_DATES field exists.""" + input_data = [{"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"}] + + result = one_to_n_funcs.split_reimb_dates(input_data, self.filename) + + self.assertIsNone(result[0]["REIMB_EFFECTIVE_DT"]) + self.assertIsNone(result[0]["REIMB_TERMINATION_DT"]) + + def test_split_reimb_dates_empty_dates(self): + """Test splitting when REIMB_DATES is empty string.""" + input_data = [{"SERVICE_TERM": "Labs", "REIMB_DATES": ""}] + + result = one_to_n_funcs.split_reimb_dates(input_data, self.filename) + + self.assertIsNone(result[0]["REIMB_EFFECTIVE_DT"]) + self.assertIsNone(result[0]["REIMB_TERMINATION_DT"]) + self.assertNotIn("REIMB_DATES", result[0]) + + def test_split_reimb_dates_empty_input(self): + """Test splitting with empty input list.""" + result = one_to_n_funcs.split_reimb_dates([], self.filename) + self.assertEqual(result, []) + + def test_split_reimb_dates_none_input(self): + """Test splitting with None input.""" + result = one_to_n_funcs.split_reimb_dates(None, self.filename) + self.assertIsNone(result) + + @patch("src.pipelines.shared.extraction.one_to_n_funcs.llm_utils.invoke_claude") + def test_split_reimb_dates_llm_error(self, mock_invoke): + """Test splitting when LLM call fails.""" + mock_invoke.side_effect = Exception("LLM API error") + + input_data = [ + { + "SERVICE_TERM": "Labs", + "REIMB_DATES": "January 1, 2024 through December 31, 2024", + } + ] + + result = one_to_n_funcs.split_reimb_dates(input_data, self.filename) + + # Should still remove REIMB_DATES and initialize new fields + self.assertIsNone(result[0]["REIMB_EFFECTIVE_DT"]) + self.assertIsNone(result[0]["REIMB_TERMINATION_DT"]) + self.assertNotIn("REIMB_DATES", result[0]) + + # ==================== get_lob_relationship Tests ==================== + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lob_relationship" + ) + @patch("src.pipelines.shared.extraction.one_to_n_funcs.string_utils.is_empty") + def test_get_lob_relationship_with_program(self, mock_is_empty, mock_prompt_lob): + """Test LOB-Program relationship extraction.""" + mock_is_empty.side_effect = [ + False, + False, + True, + ] # LOB not empty, PROGRAM not empty, PRODUCT empty + mock_prompt_lob.return_value = "PROGRAM_SPECIFIC" + + input_data = [ + {"AARETE_DERIVED_LOB": "Medicaid", "AARETE_DERIVED_PROGRAM": "CHIP"} + ] + + result = one_to_n_funcs.get_lob_relationship( + input_data, self.exhibit_text, self.filename + ) + + self.assertEqual(result[0]["LOB_PROGRAM_RELATIONSHIP"], "PROGRAM_SPECIFIC") + mock_prompt_lob.assert_called_once() + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lob_relationship" + ) + @patch("src.pipelines.shared.extraction.one_to_n_funcs.string_utils.is_empty") + def test_get_lob_relationship_with_product(self, mock_is_empty, mock_prompt_lob): + """Test LOB-Product relationship extraction.""" + mock_is_empty.side_effect = [ + False, + True, + False, + ] # LOB not empty, PROGRAM empty, PRODUCT not empty + mock_prompt_lob.return_value = "PRODUCT_SPECIFIC" + + input_data = [ + {"AARETE_DERIVED_LOB": "Commercial", "AARETE_DERIVED_PRODUCT": "HMO"} + ] + + result = one_to_n_funcs.get_lob_relationship( + input_data, self.exhibit_text, self.filename + ) + + self.assertEqual(result[0]["LOB_PRODUCT_RELATIONSHIP"], "PRODUCT_SPECIFIC") + mock_prompt_lob.assert_called_once() + + @patch("src.pipelines.shared.extraction.one_to_n_funcs.string_utils.is_empty") + def test_get_lob_relationship_no_lob(self, mock_is_empty): + """Test relationship extraction when LOB is empty.""" + mock_is_empty.return_value = True + + input_data = [{"AARETE_DERIVED_PROGRAM": "CHIP"}] + + result = one_to_n_funcs.get_lob_relationship( + input_data, self.exhibit_text, self.filename + ) + + # Should skip processing and return unchanged + self.assertEqual(result, input_data) + + # ==================== one_to_n_cleaning Tests ==================== + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.aarete_derived.get_crosswalk_fields" + ) + @patch("src.pipelines.shared.extraction.one_to_n_funcs.get_lob_relationship") + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.aarete_derived.fill_na_mapping" + ) + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.postprocessing_funcs.update_lob_for_duals" + ) + @patch("src.pipelines.shared.extraction.one_to_n_funcs.split_reimb_dates") + def test_one_to_n_cleaning_full_pipeline( + self, + mock_split_dates, + mock_update_duals, + mock_fill_na, + mock_get_lob, + mock_crosswalk, + ): + """Test full one-to-n cleaning pipeline.""" + input_data = [{"SERVICE_TERM": "Labs", "REIMB_TERM": "100% of Medicare"}] + + mock_crosswalk.return_value = input_data + mock_get_lob.return_value = input_data + mock_fill_na.return_value = input_data + mock_update_duals.return_value = input_data + mock_split_dates.return_value = input_data + + result = one_to_n_funcs.one_to_n_cleaning( + input_data, self.exhibit_text, self.constants, self.filename + ) + + # Verify all cleaning steps were called + mock_crosswalk.assert_called_once() + mock_get_lob.assert_called_once() + mock_fill_na.assert_called_once() + mock_update_duals.assert_called_once() + mock_split_dates.assert_called_once() + + self.assertEqual(result, input_data) + + # ==================== lesser_of_distribution Tests ==================== + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lesser_of_check" + ) + def test_lesser_of_distribution_global_stored_AND_in_results( + self, mock_lesser_check + ): + """Test that GLOBAL statements are stored AND kept in final results (UPDATED).""" + mock_exhibit = Mock() + mock_exhibit.exhibit_header = "Exhibit A" + mock_exhibit.get_cross_exhibit_lesser_of.return_value = [] + + mock_lesser_check.return_value = { + "service_term": "All Services", + "reimb_term": "All services: lesser of rates or charges", + "scope": "GLOBAL", + "target_exhibit": "ALL", + "exhibit_reference": None, + "page_num": "5", + } + + input_answers = [ + { + "SERVICE_TERM": "All Services", + "REIMB_TERM": "All services: lesser of rates or charges", + } + ] + + result = one_to_n_funcs.lesser_of_distribution( + input_answers, + "exhibit text", + "5", + self.constants, + self.filename, + mock_exhibit, + ) + + # Template should be stored + mock_exhibit.add_lesser_of_statement.assert_called_once() + # AND should be in final results (CHANGED from old test) + self.assertEqual(len(result), 1) + self.assertEqual( + result[0]["REIMB_TERM"], "All services: lesser of rates or charges" + ) + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lesser_of_distribution" + ) + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lesser_of_check" + ) + def test_lesser_of_distribution_cross_exhibit_stored_not_in_results( + self, mock_lesser_check, mock_lesser_dist + ): + """Test that EXHIBIT_SPECIFIC (OTHER) is stored but NOT in final results.""" + mock_exhibit = Mock() + mock_exhibit.exhibit_header = "Exhibit A" + mock_exhibit.get_cross_exhibit_lesser_of.return_value = [] + + mock_lesser_check.return_value = { + "service_term": "Outpatient Services", + "reimb_term": "For Exhibit B: not exceed Medicare", + "scope": "EXHIBIT_SPECIFIC", + "target_exhibit": "OTHER", + "exhibit_reference": "Exhibit B", + "page_num": "10", + } + + # Mock for the rate without "less" (if any) + mock_lesser_dist.return_value = "$150" + + input_answers = [ + { + "SERVICE_TERM": "Outpatient Services", + "REIMB_TERM": "For Exhibit B: not to exceed Medicare", + } + ] + + result = one_to_n_funcs.lesser_of_distribution( + input_answers, + "exhibit text", + "10", + self.constants, + self.filename, + mock_exhibit, + ) + + # Template should be stored + mock_exhibit.add_lesser_of_statement.assert_called_once() + stored_dict = mock_exhibit.add_lesser_of_statement.call_args[0][0] + self.assertEqual(stored_dict["exhibit_reference"], "Exhibit B") + + # But NOT in final results + self.assertEqual(len(result), 0) + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lesser_of_check" + ) + def test_lesser_of_distribution_current_kept_in_results(self, mock_lesser_check): + """Test that EXHIBIT_SPECIFIC (CURRENT) is kept in final results.""" + mock_exhibit = Mock() + mock_exhibit.exhibit_header = "Exhibit A" + mock_exhibit.get_cross_exhibit_lesser_of.return_value = [] + + mock_lesser_check.return_value = { + "service_term": "Services", + "reimb_term": "Services in this exhibit: lesser of rates or charges", + "scope": "EXHIBIT_SPECIFIC", + "target_exhibit": "CURRENT", + "exhibit_reference": None, + "page_num": "10", + } + + input_answers = [ + { + "SERVICE_TERM": "Services", + "REIMB_TERM": "Services in this exhibit: lesser of rates or charges", + } + ] + + result = one_to_n_funcs.lesser_of_distribution( + input_answers, + "exhibit text", + "10", + self.constants, + self.filename, + mock_exhibit, + ) + + # CURRENT should be in final results + self.assertEqual(len(result), 1) + self.assertEqual( + result[0]["REIMB_TERM"], + "Services in this exhibit: lesser of rates or charges", + ) + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lesser_of_check" + ) + def test_lesser_of_distribution_standalone_kept_in_results(self, mock_lesser_check): + """Test that STANDALONE statements are kept in final results.""" + mock_exhibit = Mock() + mock_exhibit.exhibit_header = "Exhibit A" + mock_exhibit.get_cross_exhibit_lesser_of.return_value = [] + + mock_lesser_check.return_value = { + "service_term": "MRI", + "reimb_term": "lesser of $1000 or Medicare", + "scope": "STANDALONE", + "target_exhibit": None, + "exhibit_reference": None, + "page_num": "10", + } + + input_answers = [ + {"SERVICE_TERM": "MRI", "REIMB_TERM": "lesser of $1000 or Medicare"} + ] + + result = one_to_n_funcs.lesser_of_distribution( + input_answers, + "exhibit text", + "10", + self.constants, + self.filename, + mock_exhibit, + ) + + # STANDALONE should be in final results + self.assertEqual(len(result), 1) + self.assertEqual(result[0]["REIMB_TERM"], "lesser of $1000 or Medicare") + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lesser_of_distribution" + ) + def test_lesser_of_distribution_applies_cross_exhibit_template( + self, mock_lesser_dist + ): + """Test that cross-exhibit templates are retrieved and applied.""" + mock_exhibit = Mock() + mock_exhibit.exhibit_header = "Exhibit B" + + # Mock cross-exhibit templates from Exhibit A + cross_exhibit_templates = [ + { + "reimb_term": "not exceed Medicare", + "scope": "EXHIBIT_SPECIFIC", + "target_exhibit": "OTHER", + "exhibit_reference": "Exhibit B", + "page_num": "5", + } + ] + mock_exhibit.get_cross_exhibit_lesser_of.return_value = cross_exhibit_templates + + mock_lesser_dist.return_value = "lesser of $150 or Medicare" + + input_answers = [{"SERVICE_TERM": "Office Visit", "REIMB_TERM": "$150"}] + + result = one_to_n_funcs.lesser_of_distribution( + input_answers, + "exhibit text", + "10", + self.constants, + self.filename, + mock_exhibit, + ) + + # Should apply cross-exhibit template + self.assertEqual(len(result), 1) + self.assertEqual(result[0]["REIMB_TERM"], "lesser of $150 or Medicare") + + # Verify cross-exhibit templates were passed to prompt + mock_lesser_dist.assert_called_once() + call_args = mock_lesser_dist.call_args[0] + self.assertEqual(call_args[4], cross_exhibit_templates) # 5th argument + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lesser_of_distribution" + ) + def test_lesser_of_distribution_applies_global_from_other_exhibit( + self, mock_lesser_dist + ): + """Test that GLOBAL templates from previous exhibits are applied.""" + mock_exhibit = Mock() + mock_exhibit.exhibit_header = "Exhibit B" + + # Mock GLOBAL template from Exhibit A + global_templates = [ + { + "reimb_term": "All services: lesser of rates or billed charges", + "scope": "GLOBAL", + "target_exhibit": "ALL", + "exhibit_reference": None, + "page_num": "3", + } + ] + mock_exhibit.get_cross_exhibit_lesser_of.return_value = global_templates + + mock_lesser_dist.return_value = "lesser of $500 or billed charges" + + input_answers = [{"SERVICE_TERM": "CT Scan", "REIMB_TERM": "$500"}] + + result = one_to_n_funcs.lesser_of_distribution( + input_answers, + "exhibit text", + "20", + self.constants, + self.filename, + mock_exhibit, + ) + + # Should apply GLOBAL template + self.assertEqual(len(result), 1) + self.assertEqual(result[0]["REIMB_TERM"], "lesser of $500 or billed charges") + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lesser_of_distribution" + ) + def test_lesser_of_distribution_no_templates_no_change(self, mock_lesser_dist): + """Test rate without 'less' and no applicable templates stays unchanged.""" + mock_exhibit = Mock() + mock_exhibit.exhibit_header = "Exhibit A" + mock_exhibit.get_cross_exhibit_lesser_of.return_value = [] + + # Mock returns original term (N/A case) + mock_lesser_dist.return_value = "$100" + + input_answers = [{"SERVICE_TERM": "Lab", "REIMB_TERM": "$100"}] + + result = one_to_n_funcs.lesser_of_distribution( + input_answers, + "exhibit text", + "10", + self.constants, + self.filename, + mock_exhibit, + ) + + # Should keep original rate + self.assertEqual(len(result), 1) + self.assertEqual(result[0]["REIMB_TERM"], "$100") + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lesser_of_check" + ) + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lesser_of_distribution" + ) + def test_lesser_of_distribution_mixed_statements( + self, mock_lesser_dist, mock_lesser_check + ): + """Test mix of stored templates and applied rates (UPDATED).""" + mock_exhibit = Mock() + mock_exhibit.exhibit_header = "Exhibit A" + mock_exhibit.get_cross_exhibit_lesser_of.return_value = [] + + # First call: GLOBAL template (stored AND kept in results now) + mock_lesser_check.return_value = { + "service_term": "All Services", + "reimb_term": "All services: lesser of rates or charges", + "scope": "GLOBAL", + "target_exhibit": "ALL", + "exhibit_reference": None, + "page_num": "5", + } + + mock_lesser_dist.return_value = "$100" # No change + + input_answers = [ + { + "SERVICE_TERM": "All Services", + "REIMB_TERM": "All services: lesser of rates or charges", + }, + {"SERVICE_TERM": "Lab", "REIMB_TERM": "$100"}, + ] + + result = one_to_n_funcs.lesser_of_distribution( + input_answers, + "exhibit text", + "5", + self.constants, + self.filename, + mock_exhibit, + ) + + # GLOBAL kept, rate included (CHANGED from 1 to 2) + self.assertEqual(len(result), 2) + self.assertEqual(result[0]["SERVICE_TERM"], "All Services") + self.assertEqual(result[1]["SERVICE_TERM"], "Lab") + + @patch( + "src.pipelines.shared.extraction.one_to_n_funcs.prompt_calls.prompt_lesser_of_check" + ) + def test_lesser_of_distribution_not_exceed_trigger(self, mock_lesser_check): + """Test that 'not to exceed' triggers lesser-of logic (UPDATED trigger).""" + mock_exhibit = Mock() + mock_exhibit.exhibit_header = "Exhibit A" + mock_exhibit.get_cross_exhibit_lesser_of.return_value = [] + + mock_lesser_check.return_value = { + "service_term": "Surgery", + "reimb_term": "rate shall not to exceed $200", + "scope": "STANDALONE", + "target_exhibit": None, + "exhibit_reference": None, + "page_num": "10", + } + + input_answers = [ + { + "SERVICE_TERM": "Surgery", + "REIMB_TERM": "rate shall not to exceed $200", # Changed: removed "to" + } + ] + + result = one_to_n_funcs.lesser_of_distribution( + input_answers, + "exhibit text", + "10", + self.constants, + self.filename, + mock_exhibit, + ) + + # Should call lesser_of_check + mock_lesser_check.assert_called_once() + + # STANDALONE should be in results + self.assertEqual(len(result), 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/src/tests/test_page_funcs.py b/src/tests/test_page_funcs.py new file mode 100644 index 0000000..7860ae5 --- /dev/null +++ b/src/tests/test_page_funcs.py @@ -0,0 +1,731 @@ +""" +Comprehensive tests for Page class and table splitting functionality. + +This file contains all tests for the table sub-page feature, including: +- Page class unit tests +- Table parsing and splitting logic tests +- Preprocessing integration tests (split_large_tables function) +- End-to-end integration tests (split_text_with_pages function) + +NOTE ON SAMPLE DOCUMENT TEST: +The test_bloomsburg_document_table_splitting() test is commented out because it +requires a real document file. To run it individually: +1. Uncomment the test +2. Ensure the sample document exists at: data/test/Bloomsburg_000390003_HOSP_AGR_COMM_TRAD_04012002.txt +3. Run: pytest tests/test_page_funcs.py::TestSampleDocument::test_bloomsburg_document_table_splitting -v +""" + +import sys +import pytest + +# Disable S3 writes for these tests since they're unrelated to S3 functionality +# get_arg_value reads from sys.argv, so we need to add it as a command line arg +if "write_to_s3=False" not in sys.argv: + sys.argv.append("write_to_s3=False") + +from src.pipelines.shared.extraction.page_funcs import ( + Page, + detect_table_in_text, + parse_table_rows, + split_table_by_cell_count, +) +from src.pipelines.shared import preprocessing_funcs, preprocess + + +class TestPage: + """Test cases for Page class.""" + + def test_page_initialization(self): + """Test basic Page initialization.""" + page = Page("1", "This is page text") + assert page.page_num == "1" + assert page.text == "This is page text" + assert page.original_text == "This is page text" + assert page.is_split is False + assert page.sub_pages == {} + + def test_has_table_with_table(self): + """Test has_table() returns True when table markers are present.""" + text = "Some text\n-------Table Start--------\nTable content\n-------Table End--------\nMore text" + page = Page("1", text) + assert page.has_table() is True + + def test_has_table_without_table(self): + """Test has_table() returns False when no table markers.""" + page = Page("1", "Regular page text without tables") + assert page.has_table() is False + + def test_has_table_only_start_marker(self): + """Test has_table() returns False when only start marker present.""" + text = "Some text\n-------Table Start--------\nTable content" + page = Page("1", text) + assert page.has_table() is False + + def test_get_text_regular_page(self): + """Test get_text() for regular (non-split) page.""" + page = Page("1", "Regular page text") + assert page.get_text() == "Regular page text" + assert page.get_text(None) == "Regular page text" + + def test_get_all_sub_pages_regular_page(self): + """Test get_all_sub_pages() for regular page.""" + page = Page("1", "Regular page text") + result = page.get_all_sub_pages() + assert result == {"1": "Regular page text"} + + def test_get_all_page_identifiers_regular_page(self): + """Test get_all_page_identifiers() for regular page.""" + page = Page("1", "Regular page text") + assert page.get_all_page_identifiers() == ["1"] + + def test_split_table_small_table(self): + """Test split_table() doesn't split small tables.""" + text = ( + "Text before\n" + "-------Table Start--------\n" + "[['Service', 'Payment'], ['Item 1', '$100']]\n" + "-------Table End--------\n" + "Text after" + ) + page = Page("1", text) + page.split_table(max_cells=40, min_rows_to_split=20) + assert page.is_split is False + assert page.sub_pages == {} + + def test_split_table_large_table(self): + """Test split_table() splits large tables correctly based on cell count.""" + # Create a table with 25 rows and 2 columns (50 cells total) + # With max_cells=40, we should get: max_rows = 40/2 = 20 rows per chunk + # So 25 rows / 20 = 2 chunks + rows = [f"['Service {i}', '$100']" for i in range(25)] + table_content = "\n".join(rows) + text = ( + "Text before table\n" + "-------Table Start--------\n" + f"[{', '.join(rows)}]\n" + "-------Table End--------\n" + "Text after table" + ) + page = Page("1", text) + page.split_table(max_cells=40, min_rows_to_split=5) + assert page.is_split is True + # 25 rows × 2 cols = 50 cells, max_cells=40, so max_rows=20 + # 25 rows / 20 = 2 chunks + assert len(page.sub_pages) == 2 + + def test_split_table_preserves_context(self): + """Test split_table() preserves text before and after table.""" + rows = [f"['Service {i}', '$100']" for i in range(15)] + table_content = f"[{', '.join(rows)}]" + text = ( + "Text before table\n" + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------\n" + "Text after table" + ) + page = Page("1", text) + # 15 rows × 2 cols = 30 cells, max_cells=10, so max_rows=5 + # 15 rows / 5 = 3 chunks + page.split_table(max_cells=10, min_rows_to_split=5) + + # First sub-page should have text before + first_sub_page = page.sub_pages["1.1"] + assert "Text before table" in first_sub_page + assert "-------Table Start--------" in first_sub_page + + # Last sub-page should have text after + last_sub_page = page.sub_pages["1.3"] + assert "Text after table" in last_sub_page + assert "-------Table End--------" in last_sub_page + + def test_get_text_split_page(self): + """Test get_text() for split page.""" + rows = [f"['Service {i}', '$100']" for i in range(15)] + table_content = f"[{', '.join(rows)}]" + text = ( + "Text before\n" + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------\n" + "Text after" + ) + page = Page("1", text) + page.split_table(max_cells=10, min_rows_to_split=5) + + # Get specific sub-page + sub_page_text = page.get_text("1") + assert "-------Table Start--------" in sub_page_text + + # Get all text (combined) + all_text = page.get_text() + assert "Text before" in all_text + assert "Text after" in all_text + + def test_get_all_sub_pages_split_page(self): + """Test get_all_sub_pages() for split page.""" + rows = [f"['Service {i}', '$100']" for i in range(10)] + table_content = f"[{', '.join(rows)}]" + text = ( + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------" + ) + page = Page("1", text) + # 10 rows × 2 cols = 20 cells, max_cells=10, so max_rows=5 + # 10 rows / 5 = 2 chunks + page.split_table(max_cells=10, min_rows_to_split=5) + + result = page.get_all_sub_pages() + assert len(result) == 2 + assert "1.1" in result + assert "1.2" in result + + def test_get_all_page_identifiers_split_page(self): + """Test get_all_page_identifiers() for split page.""" + rows = [f"['Service {i}', '$100']" for i in range(10)] + table_content = f"[{', '.join(rows)}]" + text = ( + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------" + ) + page = Page("1", text) + page.split_table(max_cells=10, min_rows_to_split=5) + + identifiers = page.get_all_page_identifiers() + assert len(identifiers) == 2 + assert "1.1" in identifiers + assert "1.2" in identifiers + + def test_repr_regular_page(self): + """Test __repr__ for regular page.""" + page = Page("1", "Text") + repr_str = repr(page) + assert "page_num=1" in repr_str + assert "is_split=False" in repr_str + + def test_repr_split_page(self): + """Test __repr__ for split page.""" + rows = [f"['Service {i}', '$100']" for i in range(10)] + table_content = f"[{', '.join(rows)}]" + text = ( + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------" + ) + page = Page("1", text) + page.split_table(max_cells=10, min_rows_to_split=5) + + repr_str = repr(page) + assert "is_split=True" in repr_str + assert "sub_pages=2" in repr_str + + def test_split_table_many_columns_fewer_rows(self): + """Test that tables with many columns split with fewer rows per chunk.""" + # Create a table with 20 rows and 10 columns (200 cells total) + # With max_cells=40, we should get: max_rows = 40/10 = 4 rows per chunk + # So 20 rows / 4 = 5 chunks + rows_data = [] + for i in range(20): + row = [f"Col{j}_{i}" for j in range(10)] + rows_data.append(f"[{', '.join(repr(c) for c in row)}]") + table_content = f"[{', '.join(rows_data)}]" + text = ( + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------" + ) + page = Page("1", text) + page.split_table(max_cells=40, min_rows_to_split=5) + + assert page.is_split is True + # 20 rows × 10 cols = 200 cells, max_cells=40, so max_rows=4 + # 20 rows / 4 = 5 chunks + assert len(page.sub_pages) == 5 + + +class TestDetectTableInText: + """Test cases for detect_table_in_text() function.""" + + def test_detect_table_with_markers(self): + """Test detection of table with both markers.""" + text = ( + "Text before\n" + "-------Table Start--------\n" + "Table content here\n" + "-------Table End--------\n" + "Text after" + ) + result = detect_table_in_text(text) + assert result is not None + table_text, text_before, text_after = result + assert "Table content here" in table_text + assert "Text before" in text_before + assert "Text after" in text_after + + def test_detect_table_no_markers(self): + """Test detection returns None when no markers.""" + text = "Regular text without tables" + result = detect_table_in_text(text) + assert result is None + + def test_detect_table_only_start_marker(self): + """Test detection returns None when only start marker.""" + text = "Text\n-------Table Start--------\nTable content" + result = detect_table_in_text(text) + assert result is None + + def test_detect_table_empty_content(self): + """Test detection with empty table content.""" + text = ( + "Text before\n" + "-------Table Start--------\n" + "-------Table End--------\n" + "Text after" + ) + result = detect_table_in_text(text) + assert result is not None + table_text, _, _ = result + assert table_text.strip() == "" + + +class TestParseTableRows: + """Test cases for parse_table_rows() function.""" + + def test_parse_list_format(self): + """Test parsing Python list format (expected Textract format).""" + table_text = "[['Service', 'Payment'], ['Item 1', '$100'], ['Item 2', '$200']]" + rows, num_columns = parse_table_rows(table_text, "1") + assert len(rows) == 3 + assert num_columns == 2 + assert "Service | Payment" in rows[0] + assert "Item 1 | $100" in rows[1] + + def test_parse_unexpected_format_warning(self, caplog): + """Test that unexpected format logs warning and returns empty.""" + import logging + + caplog.set_level(logging.WARNING) + + # Line-by-line format (not expected - no list structure) + table_text = "Service | Payment\nItem 1 | $100\nItem 2 | $200" + rows, num_columns = parse_table_rows(table_text, "1") + assert len(rows) == 0 + assert num_columns == 0 + assert "does not contain a list structure" in caplog.text.lower() + + def test_parse_mixed_format_warning(self, caplog): + """Test that mixed format extracts list structure correctly.""" + import logging + + caplog.set_level(logging.WARNING) + + # Mixed format - has valid list structure, should parse it + # Extra text after list is ignored (not part of table structure) + table_text = "[['Service', 'Payment']]\nItem 1 | $100\nItem 2 | $200" + rows, num_columns = parse_table_rows(table_text, "1") + # Should successfully parse the list structure + assert len(rows) == 1 + assert num_columns == 2 + assert "Service | Payment" in rows[0] + + def test_parse_empty_table(self): + """Test parsing empty table.""" + rows, num_columns = parse_table_rows("", "1") + assert rows == [] + assert num_columns == 0 + + def test_parse_table_with_notes(self): + """Test parsing table with notes or descriptive text before list.""" + # Table with notes before the list structure (like "Table 1.") + table_text = "Table 1.\n[['Service', 'Rate'], ['Item 1', '50%']]" + rows, num_columns = parse_table_rows(table_text, "1") + assert len(rows) == 2 + assert num_columns == 2 + assert "Service | Rate" in rows[0] + assert "Item 1 | 50%" in rows[1] + + def test_parse_table_many_columns(self): + """Test parsing table with many columns.""" + table_text = "[['Col1', 'Col2', 'Col3', 'Col4', 'Col5'], ['Val1', 'Val2', 'Val3', 'Val4', 'Val5']]" + rows, num_columns = parse_table_rows(table_text, "1") + assert len(rows) == 2 + assert num_columns == 5 + + def test_parse_non_list_format_warning(self, caplog): + """Test that non-list format logs warning.""" + import logging + + caplog.set_level(logging.WARNING) + + # Not a list + table_text = "Just some text" + rows, num_columns = parse_table_rows(table_text, "1") + assert len(rows) == 0 + assert num_columns == 0 + assert "does not contain a list structure" in caplog.text.lower() + + def test_parse_empty_list_warning(self, caplog): + """Test that empty list logs warning.""" + import logging + + caplog.set_level(logging.WARNING) + + table_text = "[]" + rows, num_columns = parse_table_rows(table_text, "1") + assert len(rows) == 0 + assert num_columns == 0 + assert "not in expected format" in caplog.text.lower() + + +class TestSplitTableByCellCount: + """Test cases for split_table_by_cell_count() function.""" + + def test_split_even_chunks(self): + """Test splitting into even chunks based on cell count.""" + rows = [f"Row {i}" for i in range(10)] + num_columns = 2 + chunks = split_table_by_cell_count(rows, num_columns, max_cells=20) + # max_rows = 20 / 2 = 10, so 10 rows / 10 = 1 chunk + assert len(chunks) == 1 + assert len(chunks[0].split("\n")) == 10 + + def test_split_many_columns(self): + """Test splitting with many columns results in fewer rows per chunk.""" + rows = [f"Row {i}" for i in range(20)] + num_columns = 10 # 10 columns + chunks = split_table_by_cell_count(rows, num_columns, max_cells=40) + # max_rows = 40 / 10 = 4, so 20 rows / 4 = 5 chunks + assert len(chunks) == 5 + assert len(chunks[0].split("\n")) == 4 + + def test_split_few_columns(self): + """Test splitting with few columns allows more rows per chunk.""" + rows = [f"Row {i}" for i in range(20)] + num_columns = 2 # 2 columns + chunks = split_table_by_cell_count(rows, num_columns, max_cells=40) + # max_rows = 40 / 2 = 20, so 20 rows / 20 = 1 chunk + assert len(chunks) == 1 + assert len(chunks[0].split("\n")) == 20 + + def test_split_uneven_chunks(self): + """Test splitting into uneven chunks.""" + rows = [f"Row {i}" for i in range(11)] + num_columns = 2 + chunks = split_table_by_cell_count(rows, num_columns, max_cells=10) + # max_rows = 10 / 2 = 5, so 11 rows / 5 = 3 chunks + assert len(chunks) == 3 + assert len(chunks[0].split("\n")) == 5 + assert len(chunks[1].split("\n")) == 5 + assert len(chunks[2].split("\n")) == 1 + + def test_split_single_chunk(self): + """Test splitting when all rows fit in one chunk.""" + rows = [f"Row {i}" for i in range(5)] + num_columns = 2 + chunks = split_table_by_cell_count(rows, num_columns, max_cells=40) + # max_rows = 40 / 2 = 20, so 5 rows / 20 = 1 chunk + assert len(chunks) == 1 + assert len(chunks[0].split("\n")) == 5 + + def test_split_empty_rows(self): + """Test splitting empty row list.""" + chunks = split_table_by_cell_count([], num_columns=2, max_cells=40) + assert chunks == [] + + def test_split_columns_exceed_max_cells(self): + """Test splitting when columns exceed max_cells (should use 1 row minimum).""" + rows = [f"Row {i}" for i in range(10)] + num_columns = 50 # More columns than max_cells + chunks = split_table_by_cell_count(rows, num_columns, max_cells=40) + # max_rows = max(1, 40 / 50) = 1, so 10 rows / 1 = 10 chunks + assert len(chunks) == 10 + assert len(chunks[0].split("\n")) == 1 + + +class TestSplitLargeTables: + """Test cases for split_large_tables() function.""" + + def test_split_large_tables_no_tables(self): + """Test with pages that have no tables.""" + text_dict = { + "1": "Regular page text without tables", + "2": "Another regular page", + } + pages_dict = preprocessing_funcs.split_large_tables(text_dict) + + assert len(pages_dict) == 2 + assert "1" in pages_dict + assert "2" in pages_dict + assert isinstance(pages_dict["1"], Page) + assert isinstance(pages_dict["2"], Page) + assert not pages_dict["1"].is_split + assert not pages_dict["2"].is_split + + def test_split_large_tables_small_table(self): + """Test with pages that have small tables (should not split).""" + text_dict = { + "1": ( + "Text before\n" + "-------Table Start--------\n" + "[['Service', 'Payment'], ['Item 1', '$100']]\n" + "-------Table End--------\n" + "Text after" + ), + } + pages_dict = preprocessing_funcs.split_large_tables( + text_dict, max_cells=40, min_rows_to_split=20 + ) + + assert len(pages_dict) == 1 + assert "1" in pages_dict + assert isinstance(pages_dict["1"], Page) + assert not pages_dict["1"].is_split # Small table, shouldn't split + + def test_split_large_tables_large_table(self): + """Test with pages that have large tables (should split).""" + # Create a table with 25 rows and 2 columns (50 cells total) + rows = [f"['Service {i}', '$100']" for i in range(25)] + table_content = f"[{', '.join(rows)}]" + text_dict = { + "1": ( + "Text before\n" + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------\n" + "Text after" + ), + } + pages_dict = preprocessing_funcs.split_large_tables( + text_dict, max_cells=40, min_rows_to_split=5 + ) + + assert len(pages_dict) == 1 + assert "1" in pages_dict + page = pages_dict["1"] + assert isinstance(page, Page) + assert page.is_split # Large table, should split + # 25 rows × 2 cols = 50 cells, max_cells=40, so max_rows=20 + # 25 rows / 20 = 2 chunks + assert len(page.sub_pages) == 2 + + def test_split_large_tables_mixed_pages(self): + """Test with mix of pages with and without tables.""" + rows = [f"['Service {i}', '$100']" for i in range(15)] + table_content = f"[{', '.join(rows)}]" + text_dict = { + "1": "Regular page without tables", + "2": ( + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------" + ), + "3": "Another regular page", + } + pages_dict = preprocessing_funcs.split_large_tables( + text_dict, max_cells=10, min_rows_to_split=5 + ) + + assert len(pages_dict) == 3 + assert not pages_dict["1"].is_split + assert pages_dict["2"].is_split # Has large table + assert not pages_dict["3"].is_split + + def test_split_large_tables_disabled(self): + """Test that splitting is skipped when TABLE_SPLITTING_ENABLED is False.""" + from src import config + + # Temporarily disable table splitting + original_value = config.TABLE_SPLITTING_ENABLED + config.TABLE_SPLITTING_ENABLED = False + + try: + rows = [f"['Service {i}', '$100']" for i in range(25)] + table_content = f"[{', '.join(rows)}]" + text_dict = { + "1": ( + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------" + ), + } + pages_dict = preprocessing_funcs.split_large_tables(text_dict) + + assert len(pages_dict) == 1 + assert "1" in pages_dict + assert isinstance(pages_dict["1"], Page) + assert not pages_dict["1"].is_split # Should not split when disabled + finally: + # Restore original value + config.TABLE_SPLITTING_ENABLED = original_value + + def test_split_large_tables_custom_parameters(self): + """Test with custom max_cells and min_rows_to_split parameters.""" + rows = [f"['Service {i}', '$100']" for i in range(10)] + table_content = f"[{', '.join(rows)}]" + text_dict = { + "1": ( + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------" + ), + } + # Custom parameters: max_cells=10, min_rows_to_split=5 + # 10 rows × 2 cols = 20 cells, max_cells=10, so max_rows=5 + # 10 rows / 5 = 2 chunks + pages_dict = preprocessing_funcs.split_large_tables( + text_dict, max_cells=10, min_rows_to_split=5 + ) + + assert len(pages_dict) == 1 + page = pages_dict["1"] + assert page.is_split + assert len(page.sub_pages) == 2 + + +class TestPreprocessingIntegration: + """Integration tests for preprocessing pipeline with table splitting.""" + + def test_split_text_with_pages_no_tables(self): + """Test split_text_with_pages with contract that has no tables.""" + contract_text = ( + "Start of Page No. = 1\n" + "This is page 1 content\n" + "Start of Page No. = 2\n" + "This is page 2 content\n" + ) + pages_dict, top_sheet_dict = preprocess.split_text_with_pages(contract_text) + + assert len(pages_dict) == 2 + assert "1" in pages_dict + assert "2" in pages_dict + assert isinstance(pages_dict["1"], Page) + assert isinstance(pages_dict["2"], Page) + assert not pages_dict["1"].is_split + assert not pages_dict["2"].is_split + + def test_split_text_with_pages_with_table(self): + """Test split_text_with_pages with contract that has a large table.""" + # Create a contract with a large table + rows = [f"['Service {i}', '$100']" for i in range(25)] + table_content = f"[{', '.join(rows)}]" + contract_text = ( + "Start of Page No. = 1\n" + "Regular page content\n" + "Start of Page No. = 2\n" + "Text before table\n" + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------\n" + "Text after table\n" + ) + pages_dict, top_sheet_dict = preprocess.split_text_with_pages(contract_text) + + assert len(pages_dict) == 2 + assert "1" in pages_dict + assert "2" in pages_dict + assert not pages_dict["1"].is_split # No table + assert pages_dict["2"].is_split # Has large table + # Verify sub-pages were created + assert len(pages_dict["2"].sub_pages) > 1 + + def test_split_text_with_pages_preserves_top_sheets(self): + """Test that top_sheet_dict is still returned correctly.""" + contract_text = ( + "Start of Page No. = 1\n" + "QUICK REVIEW\n" + "This is a top sheet\n" + "Start of Page No. = 2\n" + "Regular page content\n" + ) + pages_dict, top_sheet_dict = preprocess.split_text_with_pages(contract_text) + + # Top sheet should be filtered out + assert "1" not in pages_dict or "1" in top_sheet_dict + assert "2" in pages_dict + + def test_split_text_with_pages_backward_compatibility(self): + """Test that split_text() still works for backward compatibility.""" + contract_text = ( + "Start of Page No. = 1\n" + "Page 1 content\n" + "Start of Page No. = 2\n" + "Page 2 content\n" + ) + text_dict, top_sheet_dict = preprocess.split_text(contract_text) + + # Should return dict[str, str] as before + assert isinstance(text_dict, dict) + assert "1" in text_dict + assert isinstance(text_dict["1"], str) + assert "Page 1 content" in text_dict["1"] + + +class TestSampleDocument: + """Test table splitting with actual sample document.""" + + # def test_bloomsburg_document_table_splitting(self): + # """ + # Test that the Bloomsburg document table is detected and can be split. + # + # NOTE: This test requires the actual sample document file. + # To run this test: + # 1. Ensure the file exists at: data/test/Bloomsburg_000390003_HOSP_AGR_COMM_TRAD_04012002.txt + # 2. Uncomment this test + # 3. Run: pytest tests/test_page_funcs.py::TestSampleDocument::test_bloomsburg_document_table_splitting -v + # """ + # import os + # # Read the sample document + # # Try multiple possible paths + # possible_paths = [ + # "data/test/Bloomsburg_000390003_HOSP_AGR_COMM_TRAD_04012002.txt", + # "../data/test/Bloomsburg_000390003_HOSP_AGR_COMM_TRAD_04012002.txt", + # os.path.join(os.path.dirname(__file__), "..", "..", "data", "test", + # "Bloomsburg_000390003_HOSP_AGR_COMM_TRAD_04012002.txt"), + # ] + # + # contract_text = None + # for path in possible_paths: + # abs_path = os.path.abspath(path) + # if os.path.exists(abs_path): + # with open(abs_path, "r", encoding="utf-8") as f: + # contract_text = f.read() + # break + # + # if contract_text is None: + # pytest.skip("Sample file not found in any expected location") + # + # # Process with table splitting + # pages_dict, top_sheet_dict = preprocess.split_text_with_pages(contract_text) + # + # # Find page 27 which has the table + # page_27 = pages_dict.get("27") + # if page_27: + # # Check if table was detected + # assert page_27.has_table() + # assert isinstance(page_27, Page) + # + # # Note: The actual table in this document has extra text before the list format, + # # which causes parsing to fail (expected behavior - we log a warning). + # # This test verifies that: + # # 1. Tables are detected + # # 2. Page objects are created correctly + # # 3. The system handles unexpected formats gracefully + # + # # Verify that if we had a properly formatted table, splitting would work + # # Create a test page with properly formatted table + # test_table_text = ( + # "-------Table Start--------\n" + # "[['Service', 'Payment'], ['Item 1', '$100'], ['Item 2', '$200'], " + # "['Item 3', '$300'], ['Item 4', '$400'], ['Item 5', '$500'], " + # "['Item 6', '$600'], ['Item 7', '$700'], ['Item 8', '$800'], " + # "['Item 9', '$900'], ['Item 10', '$1000']]\n" + # "-------Table End--------" + # ) + # test_page = Page("test", test_table_text) + # test_page.split_table(max_cells=10, min_rows_to_split=5) + # # 11 rows × 2 cols = 22 cells, max_cells=10, so max_rows=5 + # # 11 rows / 5 = 3 chunks + # assert test_page.is_split + # assert len(test_page.sub_pages) == 3 diff --git a/src/tests/test_phase5_integration.py b/src/tests/test_phase5_integration.py new file mode 100644 index 0000000..ed6979c --- /dev/null +++ b/src/tests/test_phase5_integration.py @@ -0,0 +1,280 @@ +""" +Unit tests for Phase 5: Code Path Updates with Page objects and split tables. + +This file tests the integration of Page objects and split tables into the +reimbursement extraction pipeline. +""" + +import sys + +# Disable S3 writes for these tests +if "write_to_s3=False" not in sys.argv: + sys.argv.append("write_to_s3=False") + +import pytest + +from src.pipelines.shared.extraction.exhibit_funcs import Exhibit, get_exhibit_list +from src.pipelines.shared.extraction.page_funcs import Page +from src.pipelines.shared import preprocessing_funcs +from src.pipelines.saas import file_processing +from src.pipelines.shared import dynamic_funcs +from src.prompts.fieldset import FieldSet + + +class TestSimplifyExhibitWithPages: + """Test simplify_exhibit() with Page objects.""" + + def test_simplify_exhibit_with_exhibit_object(self): + """Test simplify_exhibit() using Exhibit object.""" + # Create pages with tables + page1 = Page( + "1", + "Text before\n-------Table Start--------\n[['A', 'B']]\n-------Table End--------\nText after", + ) + page2 = Page( + "2", + "Text before\n-------Table Start--------\n[['C', 'D']]\n-------Table End--------\nText after", + ) + pages_dict = {"1": page1, "2": page2} + + exhibit = Exhibit( + exhibit_page="1", + exhibit_page_nums=["1", "2"], + exhibit_header="Exhibit 1", + pages=pages_dict, + ) + + # Simplify exhibit for page 1 (page 1 should not be simplified) + simplified = preprocessing_funcs.simplify_exhibit( + exhibit=exhibit, + current_page_num="1", + ) + + # Page 1 should have full table, page 2 should have placeholder + assert "-------Table Start--------" in simplified + assert "[['A', 'B']]" in simplified # Page 1 table preserved + assert "Table 2" in simplified # Page 2 table replaced (Table 1 was on page 1) + assert "[['C', 'D']]" not in simplified # Page 2 table removed + + def test_simplify_exhibit_with_pages_dict(self): + """Test simplify_exhibit() using pages_dict.""" + page1 = Page( + "1", "Text\n-------Table Start--------\n[['A']]\n-------Table End--------" + ) + page2 = Page( + "2", "Text\n-------Table Start--------\n[['B']]\n-------Table End--------" + ) + pages_dict = {"1": page1, "2": page2} + + simplified = preprocessing_funcs.simplify_exhibit( + pages_dict=pages_dict, + exhibit_page_nums=["1", "2"], + current_page_num="1", + ) + + assert "[['A']]" in simplified # Current page preserved + assert "Table 2" in simplified # Other page simplified (Table 1 was on page 1) + assert "[['B']]" not in simplified + + def test_simplify_exhibit_with_split_tables(self): + """Test simplify_exhibit() with split table pages.""" + # Create a page with a split table + rows = [f"['Service {i}', '$100']" for i in range(15)] + table_content = f"[{', '.join(rows)}]" + text = ( + "Text before\n" + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------\n" + "Text after" + ) + page = Page("27", text) + page.split_table(max_cells=10, min_rows_to_split=5) + + pages_dict = {"27": page} + exhibit = Exhibit( + exhibit_page="27", + exhibit_page_nums=["27.1", "27.2", "27.3"], + exhibit_header="Exhibit 27", + pages=pages_dict, + ) + + # Simplify for sub-page 27.1 + simplified = preprocessing_funcs.simplify_exhibit( + exhibit=exhibit, + current_page_num="27.1", + ) + + # Should contain the table from 27.1 (not simplified) + assert "-------Table Start--------" in simplified + # Other sub-pages should be simplified + assert "Table" in simplified + + def test_simplify_exhibit_backward_compatibility(self): + """Test simplify_exhibit() backward compatibility with text_dict.""" + text_dict = { + "1": "Text\n-------Table Start--------\n[['A']]\n-------Table End--------", + "2": "Text\n-------Table Start--------\n[['B']]\n-------Table End--------", + } + + simplified = preprocessing_funcs.simplify_exhibit( + text_dict=text_dict, + exhibit_page_nums=["1", "2"], + current_page_num="1", + ) + + assert "[['A']]" in simplified + assert "Table 2" in simplified # Table 1 was on page 1 (current page) + assert "[['B']]" not in simplified + + +class TestProcessPageReimbursements: + """Test process_page_reimbursements() with Page objects.""" + + def test_process_page_reimbursements_with_exhibit_pages(self): + """Test process_page_reimbursements() using exhibit.pages.""" + page1 = Page("1", "Some text on page 1") + pages_dict = {"1": page1} + + exhibit = Exhibit( + exhibit_page="1", + exhibit_page_nums=["1"], + exhibit_header="Exhibit 1", + pages=pages_dict, + ) + + # Mock the functions to avoid actual LLM calls + # This test verifies the function can access page text correctly + page_text = exhibit.get_page_text("1") + assert page_text == "Some text on page 1" + + def test_process_page_reimbursements_with_split_table(self): + """Test process_page_reimbursements() with split table sub-page.""" + # Create a page with a split table + rows = [f"['Service {i}', '$100']" for i in range(10)] + table_content = f"[{', '.join(rows)}]" + text = ( + "Text before\n" + "-------Table Start--------\n" + f"{table_content}\n" + "-------Table End--------\n" + "Text after" + ) + page = Page("27", text) + page.split_table(max_cells=10, min_rows_to_split=5) + + pages_dict = {"27": page} + exhibit = Exhibit( + exhibit_page="27", + exhibit_page_nums=["27.1", "27.2"], + exhibit_header="Exhibit 27", + pages=pages_dict, + ) + + # Get text for sub-page 27.1 + page_text = exhibit.get_page_text("27.1") + assert "-------Table Start--------" in page_text + assert "Text before" in page_text + + # Get text for sub-page 27.2 + page_text_2 = exhibit.get_page_text("27.2") + assert "-------Table Start--------" in page_text_2 + assert "Text after" in page_text_2 + + +class TestDynamicAssignmentWithPages: + """Test dynamic_assignment() with Page objects.""" + + def test_dynamic_assignment_with_exhibit_object(self): + """Test dynamic_assignment() using Exhibit object.""" + page1 = Page( + "1", "Text\n-------Table Start--------\n[['A']]\n-------Table End--------" + ) + page2 = Page( + "2", "Text\n-------Table Start--------\n[['B']]\n-------Table End--------" + ) + pages_dict = {"1": page1, "2": page2} + + exhibit = Exhibit( + exhibit_page="1", + exhibit_page_nums=["1", "2"], + exhibit_header="Exhibit 1", + pages=pages_dict, + ) + + # Create mock reimbursement rows + reimbursement_rows = [ + {"REIMB_PAGE": "1", "SERVICE_TERM": "Service A", "REIMB_TERM": "$100"}, + ] + + # Empty FieldSet (no dynamic fields to assign) + dynamic_fields = FieldSet() + + # Should return rows unchanged when no dynamic fields + result = dynamic_funcs.dynamic_assignment( + reimbursement_rows, + dynamic_fields, + pages_dict=pages_dict, + exhibit=exhibit, + constants=None, + filename="test", + ) + + assert len(result) == 1 + assert result[0]["REIMB_PAGE"] == "1" + + def test_dynamic_assignment_requires_exhibit(self): + """Test that dynamic_assignment() requires exhibit parameter.""" + reimbursement_rows = [{"REIMB_PAGE": "1"}] + dynamic_fields = FieldSet() + + with pytest.raises(ValueError, match="exhibit must be provided"): + dynamic_funcs.dynamic_assignment( + reimbursement_rows, + dynamic_fields, + pages_dict={}, + exhibit=None, + constants=None, + filename="test", + ) + + +class TestRunOneToNPromptsWithPages: + """Test run_one_to_n_prompts() with Page objects.""" + + def test_run_one_to_n_prompts_with_pages_dict(self): + """Test run_one_to_n_prompts() accepts pages_dict.""" + page1 = Page("1", "Page 1 text") + page2 = Page("2", "Page 2 text") + pages_dict = {"1": page1, "2": page2} + + exhibit_chunk_mapping = {"1": ["1", "2"]} + all_exhibit_headers = {"1": "Exhibit 1"} + + # This will create exhibits but won't process them (no actual LLM calls) + # We're just testing that the function accepts pages_dict + exhibits = get_exhibit_list( + pages_dict=pages_dict, + exhibit_chunk_mapping=exhibit_chunk_mapping, + all_exhibit_headers=all_exhibit_headers, + ) + + assert len(exhibits) == 1 + assert exhibits[0].pages == {"1": page1, "2": page2} + assert exhibits[0].exhibit_text == "Page 1 text\nPage 2 text" + + def test_run_one_to_n_prompts_backward_compatibility(self): + """Test run_one_to_n_prompts() backward compatibility with text_dict.""" + text_dict = {"1": "Page 1", "2": "Page 2"} + exhibit_chunk_mapping = {"1": ["1", "2"]} + all_exhibit_headers = {"1": "Exhibit 1"} + + exhibits = get_exhibit_list( + text_dict=text_dict, + exhibit_chunk_mapping=exhibit_chunk_mapping, + all_exhibit_headers=all_exhibit_headers, + ) + + assert len(exhibits) == 1 + assert exhibits[0].exhibit_text == "Page 1\nPage 2" + assert exhibits[0].pages is None diff --git a/fieldExtraction/tests/test_postprocess.py b/src/tests/test_postprocess.py similarity index 81% rename from fieldExtraction/tests/test_postprocess.py rename to src/tests/test_postprocess.py index d4fc89f..339db12 100644 --- a/fieldExtraction/tests/test_postprocess.py +++ b/src/tests/test_postprocess.py @@ -3,13 +3,20 @@ from unittest.mock import MagicMock, patch import pandas as pd import pytest -from src.investment.postprocessing_funcs import ( +from src.pipelines.shared.postprocessing.postprocessing_funcs import ( deduplicate_provider_columns, - flatten_singleton_string_list, format_rate_fields_with_commas, - normalize_auto_renewal_term, normalize_cpt_fields, - normalize_indicator_field, process_patient_age_range, remove_hyphens, - remove_redundant_reimb_info, rename_columns, validate_and_reformat_date, - fill_empty_dynamic) + flatten_singleton_string_list, + format_rate_fields_with_commas, + normalize_auto_renewal_term, + normalize_cpt_fields, + normalize_indicator_field, + process_patient_age_range, + remove_hyphens, + remove_redundant_reimb_info, + rename_columns, + validate_and_reformat_date, + fill_empty_dynamic, +) class TestPostprocessFunctions(unittest.TestCase): @@ -425,10 +432,10 @@ class TestPostprocessFunctions(unittest.TestCase): result_df7 = deduplicate_provider_columns(input_df7) pd.testing.assert_frame_equal(result_df7, input_df7) - + def test_fill_empty_dynamic(self): """Tests the fill_empty_dynamic function that fills NA values with common values from the same EXHIBIT_PAGE group. - + Tests: 1. Basic filling - fills NA values with the common value for the same EXHIBIT_PAGE 2. Multiple columns - correctly fills multiple columns independently @@ -438,96 +445,150 @@ class TestPostprocessFunctions(unittest.TestCase): 6. Missing columns - returns unchanged DataFrame when key columns are missing """ # Test case 1: Basic filling for a single column - input_df1 = pd.DataFrame({ - "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], - "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], - "AARETE_DERIVED_LOB": ["Commercial", "", None] - }) - - expected_df1 = pd.DataFrame({ - "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], - "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], - "AARETE_DERIVED_LOB": ["Commercial", "Commercial", "Commercial"] - }) - + input_df1 = pd.DataFrame( + { + "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], + "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], + "AARETE_DERIVED_LOB": ["Commercial", "", None], + } + ) + + expected_df1 = pd.DataFrame( + { + "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], + "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], + "AARETE_DERIVED_LOB": ["Commercial", "Commercial", "Commercial"], + } + ) + result_df1 = fill_empty_dynamic(input_df1) pd.testing.assert_frame_equal(result_df1, expected_df1) - + # Test case 2: Multiple columns - input_df2 = pd.DataFrame({ - "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], - "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], - "AARETE_DERIVED_LOB": ["Commercial", "", None], - "AARETE_DERIVED_PRODUCT": ["Product A", None, ""] - }) - - expected_df2 = pd.DataFrame({ - "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], - "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], - "AARETE_DERIVED_LOB": ["Commercial", "Commercial", "Commercial"], - "AARETE_DERIVED_PRODUCT": ["Product A", "Product A", "Product A"] - }) - + input_df2 = pd.DataFrame( + { + "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], + "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], + "AARETE_DERIVED_LOB": ["Commercial", "", None], + "AARETE_DERIVED_PRODUCT": ["Product A", None, ""], + } + ) + + expected_df2 = pd.DataFrame( + { + "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], + "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], + "AARETE_DERIVED_LOB": ["Commercial", "Commercial", "Commercial"], + "AARETE_DERIVED_PRODUCT": ["Product A", "Product A", "Product A"], + } + ) + result_df2 = fill_empty_dynamic(input_df2) pd.testing.assert_frame_equal(result_df2, expected_df2) - + # Test case 3: Multiple file/page combinations - input_df3 = pd.DataFrame({ - "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf", "file1.pdf", "file2.pdf", "file2.pdf"], - "EXHIBIT_PAGE": ["1.0", "1.0", "2.0", "2.0", "1.0", "1.0"], - "AARETE_DERIVED_LOB": ["Commercial", "", "Medicare", None, "Medicaid", ""] - }) - - expected_df3 = pd.DataFrame({ - "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf", "file1.pdf", "file2.pdf", "file2.pdf"], - "EXHIBIT_PAGE": ["1.0", "1.0", "2.0", "2.0", "1.0", "1.0"], - "AARETE_DERIVED_LOB": ["Commercial", "Commercial", "Medicare", "Medicare", "Medicaid", "Medicaid"] - }) - + input_df3 = pd.DataFrame( + { + "FILE_NAME": [ + "file1.pdf", + "file1.pdf", + "file1.pdf", + "file1.pdf", + "file2.pdf", + "file2.pdf", + ], + "EXHIBIT_PAGE": ["1.0", "1.0", "2.0", "2.0", "1.0", "1.0"], + "AARETE_DERIVED_LOB": [ + "Commercial", + "", + "Medicare", + None, + "Medicaid", + "", + ], + } + ) + + expected_df3 = pd.DataFrame( + { + "FILE_NAME": [ + "file1.pdf", + "file1.pdf", + "file1.pdf", + "file1.pdf", + "file2.pdf", + "file2.pdf", + ], + "EXHIBIT_PAGE": ["1.0", "1.0", "2.0", "2.0", "1.0", "1.0"], + "AARETE_DERIVED_LOB": [ + "Commercial", + "Commercial", + "Medicare", + "Medicare", + "Medicaid", + "Medicaid", + ], + } + ) + result_df3 = fill_empty_dynamic(input_df3) pd.testing.assert_frame_equal(result_df3, expected_df3) - + # Test case 4: No common value (multiple non-NA values exist) - input_df4 = pd.DataFrame({ - "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], - "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], - "AARETE_DERIVED_LOB": ["Commercial", "Medicare", None] - }) - - expected_df4 = pd.DataFrame({ - "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], - "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], - "AARETE_DERIVED_LOB": ["Commercial", "Medicare", None] # Should remain unchanged - }) - + input_df4 = pd.DataFrame( + { + "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], + "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], + "AARETE_DERIVED_LOB": ["Commercial", "Medicare", None], + } + ) + + expected_df4 = pd.DataFrame( + { + "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], + "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], + "AARETE_DERIVED_LOB": [ + "Commercial", + "Medicare", + None, + ], # Should remain unchanged + } + ) + result_df4 = fill_empty_dynamic(input_df4) pd.testing.assert_frame_equal(result_df4, expected_df4) - + # Test case 5: All NA values - input_df5 = pd.DataFrame({ - "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], - "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], - "AARETE_DERIVED_LOB": [None, "", None] - }) - - expected_df5 = pd.DataFrame({ - "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], - "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], - "AARETE_DERIVED_LOB": [None, "", None] # Should remain unchanged - }) - + input_df5 = pd.DataFrame( + { + "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], + "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], + "AARETE_DERIVED_LOB": [None, "", None], + } + ) + + expected_df5 = pd.DataFrame( + { + "FILE_NAME": ["file1.pdf", "file1.pdf", "file1.pdf"], + "EXHIBIT_PAGE": ["1.0", "1.0", "1.0"], + "AARETE_DERIVED_LOB": [None, "", None], # Should remain unchanged + } + ) + result_df5 = fill_empty_dynamic(input_df5) pd.testing.assert_frame_equal(result_df5, expected_df5) - + # Test case 6: Missing EXHIBIT_PAGE column - input_df6 = pd.DataFrame({ - "FILE_NAME": ["file1.pdf", "file1.pdf"], - "AARETE_DERIVED_LOB": ["Commercial", None] - }) - + input_df6 = pd.DataFrame( + { + "FILE_NAME": ["file1.pdf", "file1.pdf"], + "AARETE_DERIVED_LOB": ["Commercial", None], + } + ) + result_df6 = fill_empty_dynamic(input_df6) pd.testing.assert_frame_equal(result_df6, input_df6) # Should remain unchanged - + # Test case 7: Empty DataFrame empty_df = pd.DataFrame() result_empty = fill_empty_dynamic(empty_df) diff --git a/fieldExtraction/tests/test_preprocessing_funcs.py b/src/tests/test_preprocessing_funcs.py similarity index 83% rename from fieldExtraction/tests/test_preprocessing_funcs.py rename to src/tests/test_preprocessing_funcs.py index 3708752..3bcc500 100644 --- a/fieldExtraction/tests/test_preprocessing_funcs.py +++ b/src/tests/test_preprocessing_funcs.py @@ -1,9 +1,11 @@ import pytest -from src.investment.preprocessing_funcs import (chunk_by_exhibit, - clean_law_symbols, - filter_quick_review, - remove_page_indicators, - simplify_exhibit) +from src.pipelines.shared.preprocessing.preprocessing_funcs import ( + chunk_by_exhibit, + clean_law_symbols, + filter_quick_review, + remove_page_indicators, + simplify_exhibit, +) class TestPreprocessingFuncs: @@ -88,45 +90,51 @@ class TestPreprocessingFuncs: """Test basic exhibit chunking functionality.""" text_dict = {"1": "Page 1", "2": "Page 2", "3": "Page 3", "4": "Page 4"} exhibit_pages = ["1", "3"] - + result = chunk_by_exhibit(text_dict, exhibit_pages) - + assert result == {"1": ["1", "2"], "3": ["3", "4"]} def test_chunk_by_exhibit_single_exhibit(self): """Test chunking when all pages belong to one exhibit.""" text_dict = {"1": "Page 1", "2": "Page 2", "3": "Page 3"} exhibit_pages = ["1"] - + result = chunk_by_exhibit(text_dict, exhibit_pages) - + assert result == {"1": ["1", "2", "3"]} def test_chunk_by_exhibit_empty_exhibit_pages(self): """Test chunking when exhibit_pages is empty - each page becomes its own exhibit.""" text_dict = {"1": "Page 1", "2": "Page 2", "3": "Page 3"} exhibit_pages = [] - + result = chunk_by_exhibit(text_dict, exhibit_pages) - + assert result == {"1": ["1"], "2": ["2"], "3": ["3"]} def test_chunk_by_exhibit_exhibit_at_start(self): """Test chunking when exhibit starts at first page.""" text_dict = {"1": "Page 1", "2": "Page 2", "3": "Page 3"} exhibit_pages = ["1", "2"] - + result = chunk_by_exhibit(text_dict, exhibit_pages) - + assert result == {"1": ["1"], "2": ["2", "3"]} def test_chunk_by_exhibit_multiple_exhibits(self): """Test chunking with multiple exhibits.""" - text_dict = {"1": "Page 1", "2": "Page 2", "3": "Page 3", "4": "Page 4", "5": "Page 5"} + text_dict = { + "1": "Page 1", + "2": "Page 2", + "3": "Page 3", + "4": "Page 4", + "5": "Page 5", + } exhibit_pages = ["1", "3", "5"] - + result = chunk_by_exhibit(text_dict, exhibit_pages) - + assert result == {"1": ["1", "2"], "3": ["3", "4"], "5": ["5"]} # Test cases for simplify_exhibit @@ -135,22 +143,30 @@ class TestPreprocessingFuncs: text_dict = {"1": "Page 1 content", "2": "Page 2 content"} exhibit_page_nums = ["1", "2"] current_page_num = "1" - - result = simplify_exhibit(text_dict, exhibit_page_nums, current_page_num) - + + result = simplify_exhibit( + text_dict=text_dict, + exhibit_page_nums=exhibit_page_nums, + current_page_num=current_page_num, + ) + assert result == "Page 1 content\nPage 2 content" def test_simplify_exhibit_with_tables_current_page_preserved(self): """Test that current page tables are preserved while others are simplified.""" text_dict = { "1": "Before table-------Table Start--------Table content-------Table End--------After", - "2": "Before table-------Table Start--------Table content-------Table End--------After" + "2": "Before table-------Table Start--------Table content-------Table End--------After", } exhibit_page_nums = ["1", "2"] current_page_num = "1" - - result = simplify_exhibit(text_dict, exhibit_page_nums, current_page_num) - + + result = simplify_exhibit( + text_dict=text_dict, + exhibit_page_nums=exhibit_page_nums, + current_page_num=current_page_num, + ) + # Current page (1) should have full table content assert "-------Table Start--------" in result.split("\n")[0] # Other page (2) should have table replaced with placeholder @@ -163,19 +179,23 @@ class TestPreprocessingFuncs: text_dict = { "1": "Text-------Table Start--------Table 1-------Table End--------Text", "2": "Text-------Table Start--------Table 2-------Table End--------Text", - "3": "Text-------Table Start--------Table 3-------Table End--------Text" + "3": "Text-------Table Start--------Table 3-------Table End--------Text", } exhibit_page_nums = ["1", "2", "3"] current_page_num = "2" - - result = simplify_exhibit(text_dict, exhibit_page_nums, current_page_num) + + result = simplify_exhibit( + text_dict=text_dict, + exhibit_page_nums=exhibit_page_nums, + current_page_num=current_page_num, + ) result_pages = result.split("\n") - + # Page 1 (simplified) should have "Table 1" assert "Table 1" in result_pages[0] # Page 2 (current, preserved) should have full table content assert "-------Table Start--------" in result_pages[1] - # Page 3 (simplified) should have "Table 3" + # Page 3 (simplified) should have "Table 3" # (counter is 2 after page 1, then incremented to 3 when counting page 2's table) assert "Table 3" in result_pages[2] @@ -183,14 +203,18 @@ class TestPreprocessingFuncs: """Test simplify_exhibit with multiple tables on a page.""" text_dict = { "1": "Text-------Table Start--------T1-------Table End--------Text-------Table Start--------T2-------Table End--------", - "2": "Text-------Table Start--------T3-------Table End--------" + "2": "Text-------Table Start--------T3-------Table End--------", } exhibit_page_nums = ["1", "2"] current_page_num = "2" - - result = simplify_exhibit(text_dict, exhibit_page_nums, current_page_num) + + result = simplify_exhibit( + text_dict=text_dict, + exhibit_page_nums=exhibit_page_nums, + current_page_num=current_page_num, + ) result_pages = result.split("\n") - + # Page 1 should have both tables replaced: "Table 1" and "Table 2" assert "Table 1" in result_pages[0] assert "Table 2" in result_pages[0] @@ -202,9 +226,13 @@ class TestPreprocessingFuncs: text_dict = {"1": "Page 1 content"} exhibit_page_nums = ["1", "2"] current_page_num = "1" - - result = simplify_exhibit(text_dict, exhibit_page_nums, current_page_num) - + + result = simplify_exhibit( + text_dict=text_dict, + exhibit_page_nums=exhibit_page_nums, + current_page_num=current_page_num, + ) + # Should handle missing page gracefully (empty string) assert "Page 1 content" in result assert result.count("\n") == 1 # Two pages separated by newline @@ -213,12 +241,16 @@ class TestPreprocessingFuncs: """Test simplify_exhibit when table has no end marker.""" text_dict = { "1": "Text-------Table Start--------Table content without end", - "2": "Page 2 content" + "2": "Page 2 content", } exhibit_page_nums = ["1", "2"] current_page_num = "2" - - result = simplify_exhibit(text_dict, exhibit_page_nums, current_page_num) - + + result = simplify_exhibit( + text_dict=text_dict, + exhibit_page_nums=exhibit_page_nums, + current_page_num=current_page_num, + ) + # Should still process and replace table, stopping at end of text assert "Table 1" in result or "-------Table Start--------" in result diff --git a/src/tests/test_prompt_caching.py b/src/tests/test_prompt_caching.py new file mode 100644 index 0000000..89b62cc --- /dev/null +++ b/src/tests/test_prompt_caching.py @@ -0,0 +1,274 @@ +""" +Unit tests for prompt template caching standardization. +Tests that prompts return strings and _INSTRUCTION() functions +return static instruction text for caching. +""" + +import unittest + +import src.prompts.prompt_templates as prompt_templates + + +class TestPromptTemplatesReturnStrings(unittest.TestCase): + """Test that prompt templates return prompt strings (not tuples).""" + + def test_reimbursement_primary_returns_string(self): + """Test REIMBURSEMENT_PRIMARY returns a prompt string.""" + result = prompt_templates.REIMBURSEMENT_PRIMARY("test context") + + self.assertIsInstance(result, str) + self.assertIn("test context", result) + + def test_methodology_breakout_returns_string(self): + """Test METHODOLOGY_BREAKOUT returns a prompt string.""" + result = prompt_templates.METHODOLOGY_BREAKOUT( + "service term", "reimb term", "questions" + ) + + self.assertIsInstance(result, str) + self.assertIn("service term", result) + self.assertIn("reimb term", result) + + def test_dynamic_assignment_returns_string(self): + """Test DYNAMIC_ASSIGNMENT returns a prompt string.""" + result = prompt_templates.DYNAMIC_ASSIGNMENT( + "service term", "reimb term", "LOB", "field prompt", "exhibit text", "42" + ) + + self.assertIsInstance(result, str) + self.assertIn("service term", result) + self.assertIn("reimb term", result) + self.assertIn("LOB", result) + + def test_lesser_of_distribution_returns_string(self): + """Test LESSER_OF_DISTRIBUTION returns a prompt string.""" + result = prompt_templates.LESSER_OF_DISTRIBUTION( + "service term", "reimb term", "42", "exhibit text", [] + ) + + self.assertIsInstance(result, str) + self.assertIn("service term", result) + self.assertIn("reimb term", result) + + def test_lesser_of_check_returns_string(self): + """Test LESSER_OF_CHECK returns a prompt string.""" + result = prompt_templates.LESSER_OF_CHECK( + "service term", "reimb term", "exhibit title" + ) + + self.assertIsInstance(result, str) + self.assertIn("service term", result) + self.assertIn("reimb term", result) + + def test_fee_schedule_breakout_returns_string(self): + """Test FEE_SCHEDULE_BREAKOUT returns a prompt string.""" + result = prompt_templates.FEE_SCHEDULE_BREAKOUT( + "methodology", "fee schedule", "questions" + ) + + self.assertIsInstance(result, str) + self.assertIn("methodology", result) + self.assertIn("fee schedule", result) + + def test_grouper_breakout_returns_string(self): + """Test GROUPER_BREAKOUT returns a prompt string.""" + result = prompt_templates.GROUPER_BREAKOUT("service", "term", "questions") + + self.assertIsInstance(result, str) + self.assertIn("service", result) + self.assertIn("term", result) + + def test_validate_reimbursements_prompt_returns_string(self): + """Test VALIDATE_REIMBURSEMENTS_PROMPT returns a prompt string.""" + result = prompt_templates.VALIDATE_REIMBURSEMENTS_PROMPT( + "service term", "reimb term" + ) + + self.assertIsInstance(result, str) + self.assertIn("service term", result) + self.assertIn("reimb term", result) + + def test_outlier_breakout_returns_string(self): + """Test OUTLIER_BREAKOUT returns a prompt string.""" + result = prompt_templates.OUTLIER_BREAKOUT("term") + + self.assertIsInstance(result, str) + self.assertIn("term", result) + + def test_tin_npi_template_returns_string(self): + """Test TIN_NPI_TEMPLATE returns a prompt string.""" + result = prompt_templates.TIN_NPI_TEMPLATE( + "contract context", "questions", "Payer Name" + ) + + self.assertIsInstance(result, str) + self.assertIn("Payer Name", result) + self.assertIn("contract context", result) + + +class TestInstructionFunctions(unittest.TestCase): + """Test that _INSTRUCTION() functions return static instruction text.""" + + def test_dynamic_assignment_instruction_returns_string(self): + """Test DYNAMIC_ASSIGNMENT_INSTRUCTION returns a string.""" + result = prompt_templates.DYNAMIC_ASSIGNMENT_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("[OBJECTIVE]", result) + # Verify no dynamic variables in instruction + self.assertNotIn("{", result) + self.assertNotIn("}", result) + + def test_fee_schedule_breakout_instruction_returns_string(self): + """Test FEE_SCHEDULE_BREAKOUT_INSTRUCTION returns a string.""" + result = prompt_templates.FEE_SCHEDULE_BREAKOUT_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("[OBJECTIVE]", result) + + def test_grouper_breakout_instruction_returns_string(self): + """Test GROUPER_BREAKOUT_INSTRUCTION returns a string.""" + result = prompt_templates.GROUPER_BREAKOUT_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("[OBJECTIVE]", result) + + def test_validate_reimbursements_instruction_returns_string(self): + """Test VALIDATE_REIMBURSEMENTS_INSTRUCTION returns a string.""" + result = prompt_templates.VALIDATE_REIMBURSEMENTS_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("[OBJECTIVE]", result) + + def test_outlier_breakout_instruction_returns_string(self): + """Test OUTLIER_BREAKOUT_INSTRUCTION returns a string.""" + result = prompt_templates.OUTLIER_BREAKOUT_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("[OBJECTIVE]", result) + # Verify no dynamic variables in instruction + self.assertNotIn("{", result) + self.assertNotIn("}", result) + + def test_reimbursement_primary_instruction_returns_string(self): + """Test REIMBURSEMENT_PRIMARY_INSTRUCTION returns a string.""" + result = prompt_templates.REIMBURSEMENT_PRIMARY_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("[OBJECTIVE]", result) + # Verify no dynamic variables in instruction + self.assertNotIn("{", result) + self.assertNotIn("}", result) + + def test_methodology_breakout_instruction_returns_string(self): + """Test METHODOLOGY_BREAKOUT_INSTRUCTION returns a string.""" + result = prompt_templates.METHODOLOGY_BREAKOUT_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("[OBJECTIVE]", result) + # Verify no dynamic variables in instruction + self.assertNotIn("{", result) + self.assertNotIn("}", result) + + def test_tin_npi_template_instruction_returns_string(self): + """Test TIN_NPI_TEMPLATE_INSTRUCTION returns a string.""" + result = prompt_templates.TIN_NPI_TEMPLATE_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("Analyze", result) + # Note: This instruction contains JSON examples with curly braces, + # so we don't check for absence of { } here + + def test_lesser_of_distribution_instruction_returns_string(self): + """Test LESSER_OF_DISTRIBUTION_INSTRUCTION returns a string.""" + result = prompt_templates.LESSER_OF_DISTRIBUTION_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("TASK", result) + # Verify no dynamic variables in instruction + self.assertNotIn("{", result) + self.assertNotIn("}", result) + + def test_lesser_of_check_instruction_returns_string(self): + """Test LESSER_OF_CHECK_INSTRUCTION returns a string.""" + result = prompt_templates.LESSER_OF_CHECK_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("Classify", result) + # Verify no dynamic variables in instruction + self.assertNotIn("{", result) + self.assertNotIn("}", result) + + def test_exhibit_header_instruction_returns_string(self): + """Test EXHIBIT_HEADER_INSTRUCTION returns a string.""" + result = prompt_templates.EXHIBIT_HEADER_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("OBJECTIVE", result) + + def test_exhibit_linkage_instruction_returns_string(self): + """Test EXHIBIT_LINKAGE_INSTRUCTION returns a string.""" + result = prompt_templates.EXHIBIT_LINKAGE_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("OBJECTIVE", result) + + def test_exhibit_title_match_instruction_returns_string(self): + """Test EXHIBIT_TITLE_MATCH_INSTRUCTION returns a string.""" + result = prompt_templates.EXHIBIT_TITLE_MATCH_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("OBJECTIVE", result) + + def test_date_fix_instruction_returns_string(self): + """Test DATE_FIX_INSTRUCTION returns a string.""" + result = prompt_templates.DATE_FIX_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("OBJECTIVE", result) + + def test_derived_term_date_instruction_returns_string(self): + """Test DERIVED_TERM_DATE_INSTRUCTION returns a string.""" + result = prompt_templates.DERIVED_TERM_DATE_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("OBJECTIVE", result) + + def test_check_provider_name_match_instruction_returns_string(self): + """Test CHECK_PROVIDER_NAME_MATCH_INSTRUCTION returns a string.""" + result = prompt_templates.CHECK_PROVIDER_NAME_MATCH_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("OBJECTIVE", result) + + def test_special_case_assignment_instruction_returns_string(self): + """Test SPECIAL_CASE_ASSIGNMENT_INSTRUCTION returns a string.""" + result = prompt_templates.SPECIAL_CASE_ASSIGNMENT_INSTRUCTION() + self.assertIsInstance(result, str) + self.assertIn("OBJECTIVE", result) + + +class TestGetCacheableInstructions(unittest.TestCase): + """Test get_cacheable_instructions function returns expected instructions.""" + + def test_get_cacheable_instructions_returns_dict(self): + """Test get_cacheable_instructions returns a dictionary.""" + result = prompt_templates.get_cacheable_instructions() + self.assertIsInstance(result, dict) + + def test_get_cacheable_instructions_contains_expected_keys(self): + """Test get_cacheable_instructions contains expected cache keys.""" + result = prompt_templates.get_cacheable_instructions() + + # These keys should be present when FIELDS is 'all' or 'one_to_n' + expected_keys = [ + "FEE_SCHEDULE_BREAKOUT", + "GROUPER_BREAKOUT", + "VALIDATE_REIMBURSEMENTS", + "DYNAMIC_ASSIGNMENT", + "REIMBURSEMENT_PRIMARY", + "METHODOLOGY_BREAKOUT", + "OUTLIER_BREAKOUT", + "LESSER_OF_DISTRIBUTION", + "LESSER_OF_CHECK", + "EXHIBIT_HEADER", + "EXHIBIT_LINKAGE", + "EXHIBIT_TITLE_MATCH", + "DATE_FIX", + "DERIVED_TERM_DATE", + "CHECK_PROVIDER_NAME_MATCH", + "SPECIAL_CASE_ASSIGNMENT", + ] + + for key in expected_keys: + if key in result: + self.assertIsInstance(result[key], str) + self.assertTrue(len(result[key]) > 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/fieldExtraction/tests/test_qc_qa_pipeline.py b/src/tests/test_qc_qa_pipeline.py similarity index 85% rename from fieldExtraction/tests/test_qc_qa_pipeline.py rename to src/tests/test_qc_qa_pipeline.py index f4ca425..5acd397 100644 --- a/fieldExtraction/tests/test_qc_qa_pipeline.py +++ b/src/tests/test_qc_qa_pipeline.py @@ -259,7 +259,9 @@ class TestPipelineFunctions: # Verify Manual Review Flag columns are added flag_columns = [col for col in result.columns if "Manual Review Flag" in col] - assert len(flag_columns) >= 1, "At least one Manual Review Flag column should be present" + assert ( + len(flag_columns) >= 1 + ), "At least one Manual Review Flag column should be present" # Verify original data is preserved (length) assert len(result) == len(sample_dataframe) @@ -295,107 +297,121 @@ class TestPipelineFunctions: def test_run_qc_qa_pipeline_invalid_tin(self): """Test pipeline flags invalid TINs.""" - df = pd.DataFrame( - {"FILE_NAME": ["test.pdf"], "TIN": ["12345"]} # Too short - ) + df = pd.DataFrame({"FILE_NAME": ["test.pdf"], "TIN": ["12345"]}) # Too short result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Invalid)" in result.columns def test_run_qc_qa_pipeline_invalid_npi(self): """Test pipeline flags invalid NPIs.""" - df = pd.DataFrame( - {"FILE_NAME": ["test.pdf"], "NPI": ["123"]} # Too short - ) + df = pd.DataFrame({"FILE_NAME": ["test.pdf"], "NPI": ["123"]}) # Too short result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Invalid)" in result.columns def test_run_qc_qa_pipeline_cpt_code_cleaning(self): """Test CPT code parsing and cleaning.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "CPT4_PROC_CD": ["99213, 99214, INVALID"], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "CPT4_PROC_CD": ["99213, 99214, INVALID"], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "CPT4_PROC_CD_CLEANED" in result.columns assert "Manual Review Flag (Invalid)" in result.columns def test_run_qc_qa_pipeline_modifier_validation(self): """Test CPT modifier validation.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "CPT4_PROC_MOD": ["25, 59, TOOLONG"], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "CPT4_PROC_MOD": ["25, 59, TOOLONG"], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "CPT4_PROC_MOD_CLEANED" in result.columns def test_run_qc_qa_pipeline_revenue_code_cleaning(self): """Test revenue code parsing and cleaning.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "REVENUE_CD": ["0450, 0360, INVALID"], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "REVENUE_CD": ["0450, 0360, INVALID"], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "REVENUE_CD_CLEANED" in result.columns def test_run_qc_qa_pipeline_diagnosis_code_cleaning(self): """Test diagnosis code parsing and cleaning.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "DIAG_CD": ["A00.0, B01.1"], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "DIAG_CD": ["A00.0, B01.1"], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "DIAG_CD_CLEANED" in result.columns def test_run_qc_qa_pipeline_tin_validation(self): """Test TIN formatting and validation.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "TIN": ["123456789"], - "PROV_GROUP_TIN": ["12-3456789"], - "REIMB_PROV_TIN": ["invalid"], - "PROV_OTHER_TIN": ["987654321"], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "TIN": ["123456789"], + "PROV_GROUP_TIN": ["12-3456789"], + "REIMB_PROV_TIN": ["invalid"], + "PROV_OTHER_TIN": ["987654321"], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Invalid)" in result.columns def test_run_qc_qa_pipeline_npi_cleaning(self): """Test NPI cleaning and validation.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "PROV_GROUP_NPI": ["1234567890"], - "REIMB_PROV_NPI": ["1234567890|9876543210"], - "PROV_OTHER_NPI": ["invalid"], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "PROV_GROUP_NPI": ["1234567890"], + "REIMB_PROV_NPI": ["1234567890|9876543210"], + "PROV_OTHER_NPI": ["invalid"], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) # Should clean and validate NPIs assert "Manual Review Flag (Invalid)" in result.columns def test_run_qc_qa_pipeline_lob_cleaning(self): """Test LOB standardization.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "LOB": ["Medicare Advantage"], - "AARETE_DERIVED_LINE_OF_BUSINESS": ["commercial"], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "LOB": ["Medicare Advantage"], + "AARETE_DERIVED_LINE_OF_BUSINESS": ["commercial"], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) # LOB values should be standardized assert "LOB" in result.columns def test_run_qc_qa_pipeline_value_based_flag(self): """Test flagging value-based contracts.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "CONTRACT_NAME": ["Value Based Care Agreement"], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "CONTRACT_NAME": ["Value Based Care Agreement"], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Other)" in result.columns def test_run_qc_qa_pipeline_duplicate_detection(self): """Test duplicate row detection.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf", "test.pdf"], - "RATE": [100, 100], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf", "test.pdf"], + "RATE": [100, 100], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) # Should flag duplicates flag_col = result["Manual Review Flag (Other)"] @@ -403,127 +419,157 @@ class TestPipelineFunctions: def test_run_qc_qa_pipeline_json_validation(self): """Test JSON format validation.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf", "test2.pdf"], - "PROV_INFO_JSON": ['[{"key": "value"}]', 'invalid json'], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf", "test2.pdf"], + "PROV_INFO_JSON": ['[{"key": "value"}]', "invalid json"], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Invalid)" in result.columns def test_run_qc_qa_pipeline_negative_rate_flag(self): """Test flagging negative rates.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "REIMB_PCT_RATE": [-10.5], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "REIMB_PCT_RATE": [-10.5], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) # Should flag negative rates - assert "Manual Review Flag (NegRate)" in result.columns or "Manual Review Flag (Invalid)" in result.columns + assert ( + "Manual Review Flag (NegRate)" in result.columns + or "Manual Review Flag (Invalid)" in result.columns + ) def test_run_qc_qa_pipeline_mandatory_blank_check(self): """Test mandatory field blank check.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "PROVIDER_INFO_JSON": [""], - "AARETE_DERIVED_REIMB_METHOD": [""], - "CARVEOUT_CD": [""], - "REIMB_LESSER_OF_ID": [""], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "PROVIDER_INFO_JSON": [""], + "AARETE_DERIVED_REIMB_METHOD": [""], + "CARVEOUT_CD": [""], + "REIMB_LESSER_OF_ID": [""], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Blank)" in result.columns def test_run_qc_qa_pipeline_fee_schedule_mandatory(self): """Test Fee Schedule mandatory fields check.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "AARETE_DERIVED_REIMB_METHOD": ["Fee Schedule"], - "AARETE_DERIVED_FEE_SCHEDULE": [""], - "REIMB_PCT_RATE": [""], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "AARETE_DERIVED_REIMB_METHOD": ["Fee Schedule"], + "AARETE_DERIVED_FEE_SCHEDULE": [""], + "REIMB_PCT_RATE": [""], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Blank)" in result.columns def test_run_qc_qa_pipeline_flat_rate_mandatory(self): """Test Flat Rate mandatory fields check.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "AARETE_DERIVED_REIMB_METHOD": ["Flat Rate"], - "REIMB_FEE_RATE": [""], - "CPT4_PROC_CD": [""], - "REVENUE_CD": [""], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "AARETE_DERIVED_REIMB_METHOD": ["Flat Rate"], + "REIMB_FEE_RATE": [""], + "CPT4_PROC_CD": [""], + "REVENUE_CD": [""], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Blank)" in result.columns def test_run_qc_qa_pipeline_per_diem_mandatory(self): """Test Per Diem mandatory fields check.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "AARETE_DERIVED_REIMB_METHOD": ["Per Diem"], - "REIMB_FEE_RATE": [""], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "AARETE_DERIVED_REIMB_METHOD": ["Per Diem"], + "REIMB_FEE_RATE": [""], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Blank)" in result.columns def test_run_qc_qa_pipeline_grouper_mandatory(self): """Test Grouper mandatory fields check.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "AARETE_DERIVED_REIMB_METHOD": ["Grouper"], - "GROUPER_TYPE": [""], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "AARETE_DERIVED_REIMB_METHOD": ["Grouper"], + "GROUPER_TYPE": [""], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Blank)" in result.columns def test_run_qc_qa_pipeline_billed_charges_mandatory(self): """Test Billed Charges mandatory fields check.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "AARETE_DERIVED_REIMB_METHOD": ["Billed Charges"], - "REIMB_PCT_RATE": [""], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "AARETE_DERIVED_REIMB_METHOD": ["Billed Charges"], + "REIMB_PCT_RATE": [""], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Blank)" in result.columns def test_run_qc_qa_pipeline_stats_outlier_detection(self): """Test outlier detection with stats DataFrame.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf", "test2.pdf"], - "REIMB_TERM": ["short", "This is an extremely long reimbursement term that exceeds normal length bounds"], - }) - stats_df = pd.DataFrame({ - "COL_NAME": ["REIMB_TERM"], - "MEAN_VALUE": [10.0], - "STD_VALUE": [2.0], - "MAX_LENGTH": [50], - "MIN_LENGTH": [5], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf", "test2.pdf"], + "REIMB_TERM": [ + "short", + "This is an extremely long reimbursement term that exceeds normal length bounds", + ], + } + ) + stats_df = pd.DataFrame( + { + "COL_NAME": ["REIMB_TERM"], + "MEAN_VALUE": [10.0], + "STD_VALUE": [2.0], + "MAX_LENGTH": [50], + "MIN_LENGTH": [5], + } + ) result = run_qc_qa_pipeline(df, stats_df=stats_df) # Should detect outliers based on stats assert "Manual Review Flag (Invalid)" in result.columns def test_run_qc_qa_pipeline_lob_derivation_check(self): """Test LOB derivation missing check.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "LOB": ["Commercial"], - "PROGRAM": ["HMO"], - "PRODUCT": ["Gold"], - "AARETE_DERIVED_LOB": [""], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "LOB": ["Commercial"], + "PROGRAM": ["HMO"], + "PRODUCT": ["Gold"], + "AARETE_DERIVED_LOB": [""], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Blank)" in result.columns def test_run_qc_qa_pipeline_reimb_fields_all_blank(self): """Test all reimbursement fields blank check.""" - df = pd.DataFrame({ - "FILE_NAME": ["test.pdf"], - "AARETE_DERIVED_REIMB_METHOD": [""], - "REIMB_TERM": [""], - "LESSER_OF_IND": [""], - "REIMB_PCT_RATE": [""], - "REIMB_FEE_RATE": [""], - }) + df = pd.DataFrame( + { + "FILE_NAME": ["test.pdf"], + "AARETE_DERIVED_REIMB_METHOD": [""], + "REIMB_TERM": [""], + "LESSER_OF_IND": [""], + "REIMB_PCT_RATE": [""], + "REIMB_FEE_RATE": [""], + } + ) result = run_qc_qa_pipeline(df, stats_df=None) assert "Manual Review Flag (Blank)" in result.columns @@ -795,7 +841,9 @@ class TestQAQCUtils: # Tests for append_flag def test_append_flag_new_flag(self): """Test adding flag with append_flag function.""" - df = pd.DataFrame({"COL": [1, 2, 3], "Manual Review Flag (Invalid)": ["", "", ""]}) + df = pd.DataFrame( + {"COL": [1, 2, 3], "Manual Review Flag (Invalid)": ["", "", ""]} + ) mask = pd.Series([True, False, True]) result = append_flag(df, mask, "Manual Review Flag (Invalid)", "Invalid value") @@ -806,7 +854,9 @@ class TestQAQCUtils: def test_append_flag_append_to_existing(self): """Test appending to existing flag.""" - df = pd.DataFrame({"COL": [1], "Manual Review Flag (Invalid)": ["Existing flag"]}) + df = pd.DataFrame( + {"COL": [1], "Manual Review Flag (Invalid)": ["Existing flag"]} + ) mask = pd.Series([True]) result = append_flag(df, mask, "Manual Review Flag (Invalid)", "New issue") @@ -913,6 +963,7 @@ class TestCLIIntegration: with pytest.raises(SystemExit) as exc_info: from src.qc_qa.__main__ import main + main() assert exc_info.value.code == 1 @@ -922,12 +973,17 @@ class TestCLIIntegration: non_existent = str(tmp_path / "does_not_exist.csv") def mock_get_arg(key, default=None): - return {"input_file": non_existent, "output_file": None, "stats_file": None}.get(key, default) + return { + "input_file": non_existent, + "output_file": None, + "stats_file": None, + }.get(key, default) mocker.patch("src.qc_qa.__main__.get_arg_value", side_effect=mock_get_arg) with pytest.raises(SystemExit) as exc_info: from src.qc_qa.__main__ import main + main() assert exc_info.value.code == 1 @@ -944,7 +1000,7 @@ class TestCLIIntegration: values = { "input_file": str(input_file), "output_file": str(output_file), - "stats_file": None + "stats_file": None, } return values.get(key, default) @@ -954,6 +1010,7 @@ class TestCLIIntegration: mocker.patch("src.qc_qa.__main__.save_qc_qa_outputs") from src.qc_qa.__main__ import main + main() # Should complete without error # Verify output was created @@ -965,7 +1022,9 @@ class TestCLIIntegration: input_file.write_text("FILE_NAME,REIMB_TERM\ntest.pdf,some term\n") stats_file = tmp_path / "stats.csv" - stats_file.write_text("COL_NAME,MEAN_VALUE,STD_VALUE,MAX_LENGTH,MIN_LENGTH\nREIMB_TERM,10,2,50,5\n") + stats_file.write_text( + "COL_NAME,MEAN_VALUE,STD_VALUE,MAX_LENGTH,MIN_LENGTH\nREIMB_TERM,10,2,50,5\n" + ) output_file = tmp_path / "output.csv" @@ -973,7 +1032,7 @@ class TestCLIIntegration: values = { "input_file": str(input_file), "output_file": str(output_file), - "stats_file": str(stats_file) + "stats_file": str(stats_file), } return values.get(key, default) @@ -983,6 +1042,7 @@ class TestCLIIntegration: mocker.patch("src.qc_qa.__main__.save_qc_qa_outputs") from src.qc_qa.__main__ import main + main() assert output_file.exists() @@ -998,7 +1058,7 @@ class TestCLIIntegration: values = { "input_file": str(input_file), "output_file": str(output_file), - "stats_file": None + "stats_file": None, } return values.get(key, default) @@ -1008,6 +1068,7 @@ class TestCLIIntegration: mocker.patch("src.qc_qa.__main__.save_qc_qa_outputs") from src.qc_qa.__main__ import main + main() assert output_file.exists() @@ -1026,17 +1087,21 @@ class TestCLIIntegration: values = { "input_file": str(input_file), "output_file": str(output_file), - "stats_file": None + "stats_file": None, } return values.get(key, default) mocker.patch("src.qc_qa.__main__.get_arg_value", side_effect=mock_get_arg) mocker.patch("src.qc_qa.__main__.config.WRITE_TO_S3", False) mocker.patch("src.qc_qa.__main__.config.BATCH_ID", "test_batch") - mocker.patch("src.qc_qa.__main__.run_qc_qa_pipeline", side_effect=Exception("Pipeline error")) + mocker.patch( + "src.qc_qa.__main__.run_qc_qa_pipeline", + side_effect=Exception("Pipeline error"), + ) with pytest.raises(SystemExit) as exc_info: from src.qc_qa.__main__ import main + main() assert exc_info.value.code == 1 diff --git a/fieldExtraction/tests/test_rag_utils.py b/src/tests/test_rag_utils.py similarity index 79% rename from fieldExtraction/tests/test_rag_utils.py rename to src/tests/test_rag_utils.py index 738697d..8beed9d 100644 --- a/fieldExtraction/tests/test_rag_utils.py +++ b/src/tests/test_rag_utils.py @@ -11,7 +11,7 @@ Tests RAG (Retrieval-Augmented Generation) utility functions including: import pytest from unittest.mock import Mock, patch, MagicMock -from langchain.schema import Document +from langchain_core.documents import Document from src.utils.rag_utils import ( RAGConfig, HSC_CONFIG, @@ -44,11 +44,7 @@ class TestRAGConfig: def test_custom_config(self): """Test creating custom RAGConfig""" - custom_config = RAGConfig( - CHUNK_SIZE=1000, - CHUNK_OVERLAP=100, - RERANKER="cohere" - ) + custom_config = RAGConfig(CHUNK_SIZE=1000, CHUNK_OVERLAP=100, RERANKER="cohere") assert custom_config.CHUNK_SIZE == 1000 assert custom_config.CHUNK_OVERLAP == 100 assert custom_config.RERANKER == "cohere" @@ -74,11 +70,12 @@ class TestRAGConfig: class TestClientFunctions: """Test client initialization and caching functions""" - @patch('src.utils.rag_utils.boto3.client') + @patch("src.utils.rag_utils.boto3.client") def test_get_bedrock_client(self, mock_boto_client): """Test Bedrock client creation and caching""" # Reset module-level cache import src.utils.rag_utils as rag_utils + rag_utils._bedrock_client = None mock_client = Mock() @@ -87,18 +84,21 @@ class TestClientFunctions: # First call should create client client1 = get_bedrock_client() assert client1 == mock_client - mock_boto_client.assert_called_once_with("bedrock-runtime", region_name="us-east-1") + mock_boto_client.assert_called_once_with( + "bedrock-runtime", region_name="us-east-1" + ) # Second call should return cached client client2 = get_bedrock_client() assert client2 == mock_client assert mock_boto_client.call_count == 1 # Should not create new client - @patch('src.utils.rag_utils.boto3.client') + @patch("src.utils.rag_utils.boto3.client") def test_get_reranker_client_amazon(self, mock_boto_client): """Test Amazon reranker client creation""" # Reset module-level cache import src.utils.rag_utils as rag_utils + rag_utils._reranker_clients = {} mock_client = Mock() @@ -108,11 +108,12 @@ class TestClientFunctions: assert client == mock_client mock_boto_client.assert_called_with("bedrock-runtime", region_name="us-west-2") - @patch('src.utils.rag_utils.boto3.client') + @patch("src.utils.rag_utils.boto3.client") def test_get_reranker_client_cohere(self, mock_boto_client): """Test Cohere reranker client creation""" # Reset module-level cache import src.utils.rag_utils as rag_utils + rag_utils._reranker_clients = {} mock_client = Mock() @@ -122,12 +123,13 @@ class TestClientFunctions: assert client == mock_client mock_boto_client.assert_called_with("bedrock-runtime", region_name="us-east-1") - @patch('src.utils.rag_utils.get_bedrock_client') - @patch('src.utils.rag_utils.BedrockEmbeddings') + @patch("src.utils.rag_utils.get_bedrock_client") + @patch("src.utils.rag_utils.BedrockEmbeddings") def test_get_embeddings(self, mock_embeddings_class, mock_get_client): """Test embeddings model creation and caching""" # Reset module-level cache import src.utils.rag_utils as rag_utils + rag_utils._embeddings = None mock_client = Mock() @@ -139,8 +141,7 @@ class TestClientFunctions: embeddings1 = get_embeddings() assert embeddings1 == mock_embeddings mock_embeddings_class.assert_called_once_with( - model_id="amazon.titan-embed-text-v2:0", - client=mock_client + model_id="amazon.titan-embed-text-v2:0", client=mock_client ) # Second call should return cached embeddings @@ -152,7 +153,7 @@ class TestClientFunctions: class TestVectorstoreFunctions: """Test vectorstore and retriever creation functions""" - @patch('src.utils.rag_utils.FAISS.from_documents') + @patch("src.utils.rag_utils.FAISS.from_documents") def test_create_vectorstore(self, mock_faiss): """Test FAISS vectorstore creation""" mock_vectorstore = Mock() @@ -161,7 +162,7 @@ class TestVectorstoreFunctions: chunks = [ Document(page_content="test content 1"), - Document(page_content="test content 2") + Document(page_content="test content 2"), ] result = create_vectorstore(chunks, mock_embeddings) @@ -173,8 +174,8 @@ class TestVectorstoreFunctions: assert call_args[0][0] == chunks assert call_args[0][1] == mock_embeddings - @patch('src.utils.rag_utils.BM25Retriever.from_documents') - @patch('src.utils.rag_utils.EnsembleRetriever') + @patch("src.utils.rag_utils.BM25Retriever.from_documents") + @patch("src.utils.rag_utils.EnsembleRetriever") def test_create_hybrid_retriever(self, mock_ensemble, mock_bm25): """Test hybrid retriever creation with BM25 and semantic search""" # Setup mocks @@ -199,7 +200,7 @@ class TestVectorstoreFunctions: mock_vectorstore.as_retriever.assert_called_once() # Verify ensemble was created with correct weights call_args = mock_ensemble.call_args[1] - assert call_args['weights'] == [config.VECTOR_WEIGHT, config.BM25_WEIGHT] + assert call_args["weights"] == [config.VECTOR_WEIGHT, config.BM25_WEIGHT] class TestRerankDocuments: @@ -210,33 +211,27 @@ class TestRerankDocuments: result = rerank_documents("query", [], Mock()) assert result == [] - @patch('src.utils.rag_utils.json.loads') + @patch("src.utils.rag_utils.json.loads") def test_rerank_amazon_model(self, mock_json_loads): """Test reranking with Amazon model""" # Setup mock_client = Mock() - mock_response = { - "body": Mock(read=Mock(return_value=b'{}')) - } + mock_response = {"body": Mock(read=Mock(return_value=b"{}"))} mock_client.invoke_model.return_value = mock_response mock_json_loads.return_value = { "results": [ {"index": 0, "relevance_score": 0.9}, - {"index": 1, "relevance_score": 0.7} + {"index": 1, "relevance_score": 0.7}, ] } docs = [ Document(page_content="doc1", metadata={"source": "test"}), - Document(page_content="doc2", metadata={"source": "test"}) + Document(page_content="doc2", metadata={"source": "test"}), ] result = rerank_documents( - query="test query", - docs=docs, - client=mock_client, - top_k=2, - model="amazon" + query="test query", docs=docs, client=mock_client, top_k=2, model="amazon" ) # Verify results @@ -246,32 +241,23 @@ class TestRerankDocuments: assert result[1].page_content == "doc2" assert result[1].metadata["rerank_score"] == 0.7 - @patch('src.utils.rag_utils.json.loads') + @patch("src.utils.rag_utils.json.loads") def test_rerank_cohere_model(self, mock_json_loads): """Test reranking with Cohere model""" mock_client = Mock() - mock_response = { - "body": Mock(read=Mock(return_value=b'{}')) - } + mock_response = {"body": Mock(read=Mock(return_value=b"{}"))} mock_client.invoke_model.return_value = mock_response mock_json_loads.return_value = { "results": [ {"index": 1, "relevance_score": 0.8}, - {"index": 0, "relevance_score": 0.6} + {"index": 0, "relevance_score": 0.6}, ] } - docs = [ - Document(page_content="doc1"), - Document(page_content="doc2") - ] + docs = [Document(page_content="doc1"), Document(page_content="doc2")] result = rerank_documents( - query="test query", - docs=docs, - client=mock_client, - top_k=2, - model="cohere" + query="test query", docs=docs, client=mock_client, top_k=2, model="cohere" ) # Verify reranked order (doc2 should be first due to higher score) @@ -279,21 +265,15 @@ class TestRerankDocuments: assert result[0].page_content == "doc2" assert result[1].page_content == "doc1" - @patch('src.utils.rag_utils.json.loads', side_effect=Exception("API Error")) - @patch('src.utils.rag_utils.logging') + @patch("src.utils.rag_utils.json.loads", side_effect=Exception("API Error")) + @patch("src.utils.rag_utils.logging") def test_rerank_error_handling(self, mock_logging, mock_json_loads): """Test that reranking failures return top_k documents""" - docs = [ - Document(page_content=f"doc{i}") for i in range(10) - ] + docs = [Document(page_content=f"doc{i}") for i in range(10)] mock_client = Mock() result = rerank_documents( - query="test", - docs=docs, - client=mock_client, - top_k=3, - model="amazon" + query="test", docs=docs, client=mock_client, top_k=3, model="amazon" ) # Should return first top_k docs on error @@ -306,27 +286,27 @@ class TestRerankDocuments: """Test that reranking respects top_k limit""" mock_client = Mock() mock_response = { - "body": Mock(read=Mock(return_value=b'{"results": [{"index": 0, "relevance_score": 0.9}, {"index": 1, "relevance_score": 0.8}, {"index": 2, "relevance_score": 0.7}]}')) + "body": Mock( + read=Mock( + return_value=b'{"results": [{"index": 0, "relevance_score": 0.9}, {"index": 1, "relevance_score": 0.8}, {"index": 2, "relevance_score": 0.7}]}' + ) + ) } mock_client.invoke_model.return_value = mock_response docs = [Document(page_content=f"doc{i}") for i in range(3)] - with patch('src.utils.rag_utils.json.loads') as mock_json: + with patch("src.utils.rag_utils.json.loads") as mock_json: mock_json.return_value = { "results": [ {"index": 0, "relevance_score": 0.9}, {"index": 1, "relevance_score": 0.8}, - {"index": 2, "relevance_score": 0.7} + {"index": 2, "relevance_score": 0.7}, ] } result = rerank_documents( - query="test", - docs=docs, - client=mock_client, - top_k=2, - model="amazon" + query="test", docs=docs, client=mock_client, top_k=2, model="amazon" ) assert len(result) == 2 diff --git a/fieldExtraction/tests/test_string_utils.py b/src/tests/test_string_utils.py similarity index 68% rename from fieldExtraction/tests/test_string_utils.py rename to src/tests/test_string_utils.py index 029edc7..6765d6c 100644 --- a/fieldExtraction/tests/test_string_utils.py +++ b/src/tests/test_string_utils.py @@ -3,14 +3,22 @@ import json import pandas as pd import numpy as np from src.utils import string_utils -from constants.delimiters import Delimiter +from src.constants.delimiters import Delimiter + class TestStringUtils(unittest.TestCase): def test_extract_text_from_delimiters_pipe(self): s = "foo |bar| baz |qux|" - self.assertEqual(string_utils.extract_text_from_delimiters(s, Delimiter.PIPE), "qux") - self.assertEqual(string_utils.extract_text_from_delimiters(s, Delimiter.PIPE, 0), "bar") - self.assertEqual(string_utils.extract_text_from_delimiters("no delimiters", Delimiter.PIPE), "N/A") + self.assertEqual( + string_utils.extract_text_from_delimiters(s, Delimiter.PIPE), "qux" + ) + self.assertEqual( + string_utils.extract_text_from_delimiters(s, Delimiter.PIPE, 0), "bar" + ) + self.assertEqual( + string_utils.extract_text_from_delimiters("no delimiters", Delimiter.PIPE), + "N/A", + ) with self.assertRaises(TypeError): string_utils.extract_text_from_delimiters(123, Delimiter.PIPE) with self.assertRaises(TypeError): @@ -18,11 +26,16 @@ class TestStringUtils(unittest.TestCase): def test_extract_text_from_delimiters_backtick(self): s = "foo `bar` baz `qux`" - self.assertEqual(string_utils.extract_text_from_delimiters(s, Delimiter.BACKTICK), "qux") + self.assertEqual( + string_utils.extract_text_from_delimiters(s, Delimiter.BACKTICK), "qux" + ) def test_extract_text_from_delimiters_triple_backtick(self): s = "foo ```bar``` baz ```qux```" - self.assertEqual(string_utils.extract_text_from_delimiters(s, Delimiter.TRIPLE_BACKTICK), "qux") + self.assertEqual( + string_utils.extract_text_from_delimiters(s, Delimiter.TRIPLE_BACKTICK), + "qux", + ) def test_page_key_sort(self): keys = ["10", "2", "A", "1", "B", "1.5"] @@ -40,48 +53,63 @@ class TestStringUtils(unittest.TestCase): s = '{"a": 1, "b": 2}' self.assertEqual(string_utils.universal_json_load(s), {"a": 1, "b": 2}) # Simple list - s = '[1, 2, 3]' + s = "[1, 2, 3]" self.assertEqual(string_utils.universal_json_load(s), [1, 2, 3]) # Nested dict s = '{"a": {"b": [1, 2, {"c": "d"}]}}' - self.assertEqual(string_utils.universal_json_load(s), {"a": {"b": [1, 2, {"c": "d"}]}}) + self.assertEqual( + string_utils.universal_json_load(s), {"a": {"b": [1, 2, {"c": "d"}]}} + ) # List of dicts s = '[{"x": 1}, {"y": 2}]' self.assertEqual(string_utils.universal_json_load(s), [{"x": 1}, {"y": 2}]) # Dict of lists s = '{"a": [1, 2], "b": [3, 4]}' - self.assertEqual(string_utils.universal_json_load(s), {"a": [1, 2], "b": [3, 4]}) + self.assertEqual( + string_utils.universal_json_load(s), {"a": [1, 2], "b": [3, 4]} + ) # List of strings s = '["foo", "bar", "baz"]' self.assertEqual(string_utils.universal_json_load(s), ["foo", "bar", "baz"]) # JSON with text before/after s = 'start {"field": "value"} end' self.assertEqual(string_utils.universal_json_load(s), {"field": "value"}) - s = 'before [1, 2, 3] after' + s = "before [1, 2, 3] after" self.assertEqual(string_utils.universal_json_load(s), [1, 2, 3]) # Multiple objects, last wins s = 'first {"a": 1} middle {"b": 2} last {"c": 3}' self.assertEqual(string_utils.universal_json_load(s), {"c": 3}) # Multiple arrays, last wins - s = 'first [1] middle [2] last [3]' + s = "first [1] middle [2] last [3]" self.assertEqual(string_utils.universal_json_load(s), [3]) # Nested JSON with text 1 s = 'junk {"outer": {"inner": [1, 2, {"deep": true}]}} more junk' - self.assertEqual(string_utils.universal_json_load(s), {"outer": {"inner": [1, 2, {"deep": True}]}}) + self.assertEqual( + string_utils.universal_json_load(s), + {"outer": {"inner": [1, 2, {"deep": True}]}}, + ) # Nested JSON with text 2 s = 'junk [{"dict1_key": "dict1_val"}, {"dict2_key" : "dict2_val"}] more junk' - self.assertEqual(string_utils.universal_json_load(s), [{"dict1_key": "dict1_val"}, {"dict2_key" : "dict2_val"}]) + self.assertEqual( + string_utils.universal_json_load(s), + [{"dict1_key": "dict1_val"}, {"dict2_key": "dict2_val"}], + ) # List of dicts s = 'junk```json[{"a1": "value_a1","b1": "value_b1"},{"a2": "value_a2","b2": "value_b2"}]```' - self.assertEqual(string_utils.universal_json_load(s), [{"a1": "value_a1","b1": "value_b1"},{"a2": "value_a2","b2": "value_b2"}]) + self.assertEqual( + string_utils.universal_json_load(s), + [ + {"a1": "value_a1", "b1": "value_b1"}, + {"a2": "value_a2", "b2": "value_b2"}, + ], + ) # Boolean and null values s = '{"ok": true, "val": null}' - self.assertEqual(string_utils.universal_json_load(s), {"ok": True, "val": None}) - + self.assertEqual(string_utils.universal_json_load(s), {"ok": True, "val": None}) def test_universal_json_load_invalid(self): # No valid JSON - s = 'no json here' + s = "no json here" with self.assertRaises(ValueError): string_utils.universal_json_load(s) # Broken JSON @@ -96,20 +124,20 @@ class TestStringUtils(unittest.TestCase): with self.assertRaises(ValueError): string_utils.universal_json_load(s) # Empty string - s = '' + s = "" with self.assertRaises(ValueError): string_utils.universal_json_load(s) def test_universal_json_load_edge_cases(self): # Empty object - s = 'text {} more text' + s = "text {} more text" self.assertEqual(string_utils.universal_json_load(s), {}) # Empty array - s = 'text [] more text' + s = "text [] more text" self.assertEqual(string_utils.universal_json_load(s), []) # Large object large = {f"k{i}": i for i in range(100)} - s = f'before {json.dumps(large)} after' + s = f"before {json.dumps(large)} after" self.assertEqual(string_utils.universal_json_load(s), large) def test_contains_reimbursement(self): @@ -139,8 +167,12 @@ class TestStringUtils(unittest.TestCase): self.assertTrue(mask.iloc[2]) self.assertTrue(mask.iloc[3]) self.assertFalse(mask.iloc[0]) - self.assertFalse(string_utils.is_empty(pd.Series(["valid", None]), pd_mask=False)) - self.assertTrue(string_utils.is_empty(pd.Series([None, "", "N/A"]), pd_mask=False)) + self.assertFalse( + string_utils.is_empty(pd.Series(["valid", None]), pd_mask=False) + ) + self.assertTrue( + string_utils.is_empty(pd.Series([None, "", "N/A"]), pd_mask=False) + ) def test_datetime_str(self): result = string_utils.datetime_str() @@ -148,41 +180,71 @@ class TestStringUtils(unittest.TestCase): self.assertTrue(result.endswith("]")) def test_extract_signature_page(self): - text_dict = {"1": "Contract page 1", "2": "This page has 2 signatures at the bottom", "3": "Final page"} + text_dict = { + "1": "Contract page 1", + "2": "This page has 2 signatures at the bottom", + "3": "Final page", + } result = string_utils.extract_signature_page(text_dict, "test.pdf") self.assertIn("2", result) self.assertEqual(result["2"], "This page has 2 signatures at the bottom") - text_dict = {"1": "Contract page 1", "2": "In Witness Whereof", "3": "Final page"} + text_dict = { + "1": "Contract page 1", + "2": "In Witness Whereof", + "3": "Final page", + } result = string_utils.extract_signature_page(text_dict, "test.pdf") self.assertIn("2", result) self.assertEqual(result["2"], "In Witness Whereof") - text_dict = {"1": "Contract page 1", "2": "Signature page follows this section", "3": "signature page"} + text_dict = { + "1": "Contract page 1", + "2": "Signature page follows this section", + "3": "signature page", + } result = string_utils.extract_signature_page(text_dict, "test.pdf") self.assertIn("3", result) def test_extract_effective_date_pages(self): - text_dict = {"1": "Contract effective date: January 1, 2024", "2": "General terms and conditions", "3": "This page has 1 signature"} + text_dict = { + "1": "Contract effective date: January 1, 2024", + "2": "General terms and conditions", + "3": "This page has 1 signature", + } result = string_utils.extract_effective_date_pages(text_dict, "test.pdf") self.assertIn("1", result) self.assertIn("3", result) self.assertEqual(len(result), 2) def test_normalize_state_to_abbreviation(self): - self.assertEqual(string_utils.normalize_state_to_abbreviation("California"), "CA") + self.assertEqual( + string_utils.normalize_state_to_abbreviation("California"), "CA" + ) self.assertEqual(string_utils.normalize_state_to_abbreviation("ca"), "CA") self.assertEqual(string_utils.normalize_state_to_abbreviation("N.Y."), "NY") - self.assertEqual(string_utils.normalize_state_to_abbreviation("Unknown State"), "Unknown State") + self.assertEqual( + string_utils.normalize_state_to_abbreviation("Unknown State"), + "Unknown State", + ) self.assertEqual(string_utils.normalize_state_to_abbreviation("N/A"), "N/A") def test_flatten_to_strings(self): - self.assertEqual(string_utils.flatten_to_strings(["a", ["b", "c"], "d"]), ["a", "b", "c", "d"]) + self.assertEqual( + string_utils.flatten_to_strings(["a", ["b", "c"], "d"]), + ["a", "b", "c", "d"], + ) self.assertEqual(string_utils.flatten_to_strings("single"), ["single"]) - self.assertEqual(string_utils.flatten_to_strings([1, [2, 3], "text"]), ["1", "2", "3", "text"]) - self.assertEqual(string_utils.flatten_to_strings([" text ", [" nested "]]), ["text", "nested"]) + self.assertEqual( + string_utils.flatten_to_strings([1, [2, 3], "text"]), + ["1", "2", "3", "text"], + ) + self.assertEqual( + string_utils.flatten_to_strings([" text ", [" nested "]]), + ["text", "nested"], + ) def test_universal_json_load_multiple_invalid(self): # Multiple invalid JSON objects - s = '{broken: true} some text {not: valid} more text' + s = "{broken: true} some text {not: valid} more text" with self.assertRaises(ValueError): string_utils.universal_json_load(s) @@ -199,27 +261,39 @@ class TestStringUtils(unittest.TestCase): def test_universal_json_load_last_nested(self): # Multiple, with the last one being nested s = '{"simple": true} middle {"outer": {"inner": [1, 2]}} end' - self.assertEqual(string_utils.universal_json_load(s), {"outer": {"inner": [1, 2]}}) + self.assertEqual( + string_utils.universal_json_load(s), {"outer": {"inner": [1, 2]}} + ) def test_universal_json_load_brackets_in_strings(self): # Brackets inside string values should be ignored during bracket matching s = '{"text": "array [1] and {2}"}' - self.assertEqual(string_utils.universal_json_load(s), {"text": "array [1] and {2}"}) + self.assertEqual( + string_utils.universal_json_load(s), {"text": "array [1] and {2}"} + ) # Double brackets in strings (the original bug case) s = '{"field": "Exhibit [[ to Attachment ]"}' - self.assertEqual(string_utils.universal_json_load(s), {"field": "Exhibit [[ to Attachment ]"}) + self.assertEqual( + string_utils.universal_json_load(s), {"field": "Exhibit [[ to Attachment ]"} + ) # Unbalanced brackets in strings s = '{"text": "missing close [ bracket"}' - self.assertEqual(string_utils.universal_json_load(s), {"text": "missing close [ bracket"}) + self.assertEqual( + string_utils.universal_json_load(s), {"text": "missing close [ bracket"} + ) # Curly braces in strings s = '{"text": "object {key: value} here"}' - self.assertEqual(string_utils.universal_json_load(s), {"text": "object {key: value} here"}) + self.assertEqual( + string_utils.universal_json_load(s), {"text": "object {key: value} here"} + ) # Escaped quotes should not break string detection s = '{"text": "say \\"hello\\""}' self.assertEqual(string_utils.universal_json_load(s), {"text": 'say "hello"'}) # Escaped quotes with brackets s = '{"text": "say \\"hello [world]\\"" }' - self.assertEqual(string_utils.universal_json_load(s), {"text": 'say "hello [world]"'}) + self.assertEqual( + string_utils.universal_json_load(s), {"text": 'say "hello [world]"'} + ) # Real-world LLM response case with markdown and brackets in JSON strings raw_input = 'Here is the analysis:\n\n```json\n[{"SERVICE_TERM": "Inpatient services", "REIMB_TERM": "100% of rates in Exhibit [[ to Attachment ]"}, {"SERVICE_TERM": "Outpatient services", "REIMB_TERM": "63% of rates in Exhibit [[ to Attachment ]"}]\n```' result = string_utils.universal_json_load(raw_input) @@ -227,7 +301,6 @@ class TestStringUtils(unittest.TestCase): self.assertEqual(result[0]["SERVICE_TERM"], "Inpatient services") self.assertIn("Exhibit [[", result[0]["REIMB_TERM"]) + if __name__ == "__main__": unittest.main() - - diff --git a/fieldExtraction/tests/test_timing_utils.py b/src/tests/test_timing_utils.py similarity index 100% rename from fieldExtraction/tests/test_timing_utils.py rename to src/tests/test_timing_utils.py diff --git a/fieldExtraction/tests/test_tin_npi_funcs.py b/src/tests/test_tin_npi_funcs.py similarity index 91% rename from fieldExtraction/tests/test_tin_npi_funcs.py rename to src/tests/test_tin_npi_funcs.py index 8a8dbe6..b46ff5a 100644 --- a/fieldExtraction/tests/test_tin_npi_funcs.py +++ b/src/tests/test_tin_npi_funcs.py @@ -2,9 +2,9 @@ import json import re from unittest.mock import MagicMock, patch -import constants.regex_patterns as regex_patterns +import src.constants.regex_patterns as regex_patterns import pytest -import src.investment.tin_npi_funcs as tin_npi_funcs +import src.pipelines.shared.extraction.tin_npi_funcs as tin_npi_funcs from src.prompts.fieldset import FieldSet @@ -67,32 +67,39 @@ class TestTinNpiFuncs: assert result[1]["NPI"] == "UNKNOWN" assert result[1]["NAME"] == "UNKNOWN" - @patch("src.investment.prompt_calls.provider_name_match_check") - def test_merge_provider_info_with_hybrid_smart_chunking(self, mock_name_match_check): + @patch("src.pipelines.saas.prompts.prompt_calls.provider_name_match_check") + def test_merge_provider_info_with_hybrid_smart_chunking( + self, mock_name_match_check + ): """Test merge_provider_info_with_hybrid_smart_chunking with name matching logic""" + # Mock the name matching to return True for "Group Provider" def name_match_side_effect(provider_name, name, filename): return name == "Group Provider" - + mock_name_match_check.side_effect = name_match_side_effect one_to_one_results = { "PROVIDER_NAME": "Group Provider", - "PROV_INFO_JSON": json.dumps([ - { - "TIN": "123456789", - "NPI": "1234567890", - "NAME": "Group Provider", - }, - { - "TIN": "987654321", - "NPI": "9876543210", - "NAME": "Other Provider", - }, - ]) + "PROV_INFO_JSON": json.dumps( + [ + { + "TIN": "123456789", + "NPI": "1234567890", + "NAME": "Group Provider", + }, + { + "TIN": "987654321", + "NPI": "9876543210", + "NAME": "Other Provider", + }, + ] + ), } - result = tin_npi_funcs.merge_provider_info_with_hybrid_smart_chunking(one_to_one_results, "test.pdf") + result = tin_npi_funcs.merge_provider_info_with_hybrid_smart_chunking( + one_to_one_results, "test.pdf" + ) # Check that IS_GROUP flags were added correctly prov_info = json.loads(result["PROV_INFO_JSON"]) @@ -108,17 +115,12 @@ class TestTinNpiFuncs: @patch("src.utils.llm_utils.invoke_claude") def test_get_provider_info(self, mock_invoke_claude, sample_text_dict): mock_invoke_claude.return_value = json.dumps( - [ - { - "TIN": "123456789", - "NPI": "1234567890", - "NAME": "Test Provider" - - } - ] + [{"TIN": "123456789", "NPI": "1234567890", "NAME": "Test Provider"}] ) - result = tin_npi_funcs.get_provider_info(sample_text_dict, "1", "test.pdf", payer_name="Test Payer") + result = tin_npi_funcs.get_provider_info( + sample_text_dict, "1", "test.pdf", payer_name="Test Payer" + ) assert len(result) == 1 @patch("src.utils.llm_utils.invoke_claude") @@ -332,7 +334,7 @@ class TestTinNpiFuncs: contract_text = "Contract with corrupted TIN 12345678O and NPI 123456789O" results = tin_npi_funcs.run_provider_info_fields( - contract_text, sample_text_dict, "test.pdf", "Test Payer" + contract_text, sample_text_dict, "test.pdf", "Test Payer" ) # Should find OCR-corrected values diff --git a/fieldExtraction/tests/test_usage_tracking.py b/src/tests/test_usage_tracking.py similarity index 93% rename from fieldExtraction/tests/test_usage_tracking.py rename to src/tests/test_usage_tracking.py index 9dc5429..525dea1 100644 --- a/fieldExtraction/tests/test_usage_tracking.py +++ b/src/tests/test_usage_tracking.py @@ -120,7 +120,9 @@ class TestExtractUsageFromResponse: (None, (0, 0, 0, 0)), ], ) - def test_extract_usage_from_response_missing_usage(self, response_body, expected, caplog): + def test_extract_usage_from_response_missing_usage( + self, response_body, expected, caplog + ): """Test extraction when usage data is missing.""" with caplog.at_level(logging.DEBUG): result = usage_tracking.extract_usage_from_response(response_body) @@ -206,9 +208,13 @@ class TestGetCostPerToken: ): """Test cost calculation for valid model IDs.""" # Mock resolve_model_id to return the model_id as-is - mocker.patch("src.utils.usage_tracking.config.resolve_model_id", return_value=model_id) + mocker.patch( + "src.utils.usage_tracking.config.resolve_model_id", return_value=model_id + ) - input_cost, output_cost, cache_read_cost = usage_tracking.get_cost_per_token(model_id) + input_cost, output_cost, cache_read_cost = usage_tracking.get_cost_per_token( + model_id + ) assert abs(input_cost - expected_input) < 1e-10 assert abs(output_cost - expected_output) < 1e-10 @@ -219,12 +225,13 @@ class TestGetCostPerToken: unknown_model = "unknown.model.id" # Mock resolve_model_id to return the unknown model mocker.patch( - "src.utils.usage_tracking.config.resolve_model_id", return_value=unknown_model + "src.utils.usage_tracking.config.resolve_model_id", + return_value=unknown_model, ) with caplog.at_level(logging.WARNING): - input_cost, output_cost, cache_read_cost = usage_tracking.get_cost_per_token( - unknown_model + input_cost, output_cost, cache_read_cost = ( + usage_tracking.get_cost_per_token(unknown_model) ) # Should use default pricing (Claude 3.5 Sonnet) @@ -247,7 +254,9 @@ class TestGetCostPerToken: "src.utils.usage_tracking.config.resolve_model_id", return_value=resolved_id ) - input_cost, output_cost, cache_read_cost = usage_tracking.get_cost_per_token(alias) + input_cost, output_cost, cache_read_cost = usage_tracking.get_cost_per_token( + alias + ) # Should use Claude 3.7 Sonnet pricing expected_input = 0.003 / 1000.0 @@ -261,9 +270,13 @@ class TestGetCostPerToken: def test_get_cost_per_token_conversion(self, mocker): """Test that per-1k costs are correctly converted to per-token.""" model_id = "anthropic.claude-3-5-sonnet-20240620-v1:0" - mocker.patch("src.utils.usage_tracking.config.resolve_model_id", return_value=model_id) + mocker.patch( + "src.utils.usage_tracking.config.resolve_model_id", return_value=model_id + ) - input_cost, output_cost, cache_read_cost = usage_tracking.get_cost_per_token(model_id) + input_cost, output_cost, cache_read_cost = usage_tracking.get_cost_per_token( + model_id + ) # Verify conversion: per-1k / 1000 = per-token assert input_cost == 0.003 / 1000.0 @@ -331,7 +344,10 @@ class TestTrackUsage: assert file_data["output_tokens"] == output_tokens assert file_data["cache_creation_tokens"] == cache_creation assert file_data["cache_read_tokens"] == cache_read - assert file_data["total_tokens"] == input_tokens + output_tokens + cache_creation + cache_read + assert ( + file_data["total_tokens"] + == input_tokens + output_tokens + cache_creation + cache_read + ) assert file_data["request_count"] == 1 # Verify cost calculation @@ -340,14 +356,19 @@ class TestTrackUsage: model_id_lower = model_id.lower() if any( x in model_id_lower - for x in ["claude-3-5-sonnet", "claude-3-7-sonnet", "claude-sonnet-4", "claude-4-sonnet"] + for x in [ + "claude-3-5-sonnet", + "claude-3-7-sonnet", + "claude-sonnet-4", + "claude-4-sonnet", + ] ): cache_creation_cost = input_cost * 1.25 # Sonnet: 25% higher elif "haiku" in model_id_lower: cache_creation_cost = input_cost * 1.20 # Haiku: 20% higher else: cache_creation_cost = input_cost # Others: same as input - + expected_cost = ( (input_tokens * input_cost) + (cache_creation * cache_creation_cost) @@ -360,9 +381,15 @@ class TestTrackUsage: global_data = usage_data["global"] assert global_data["total_fresh_input_tokens"] == input_tokens assert global_data["total_cache_tokens"] == cache_creation + cache_read - assert global_data["total_input_tokens"] == input_tokens + cache_creation + cache_read + assert ( + global_data["total_input_tokens"] + == input_tokens + cache_creation + cache_read + ) assert global_data["total_output_tokens"] == output_tokens - assert global_data["total_tokens"] == input_tokens + output_tokens + cache_creation + cache_read + assert ( + global_data["total_tokens"] + == input_tokens + output_tokens + cache_creation + cache_read + ) assert abs(global_data["total_cost"] - expected_cost) < 1e-10 assert global_data["total_requests"] == 1 @@ -440,7 +467,9 @@ class TestTrackUsage: # Verify global totals (sum of all) global_data = usage_data["global"] assert global_data["total_fresh_input_tokens"] == 450 # 100 + 200 + 150 - assert global_data["total_cache_tokens"] == 120 # (10+20) + (20+30) + (15+25) = 30 + 50 + 40 + assert ( + global_data["total_cache_tokens"] == 120 + ) # (10+20) + (20+30) + (15+25) = 30 + 50 + 40 assert global_data["total_requests"] == 3 @pytest.mark.parametrize( @@ -483,7 +512,12 @@ class TestTrackUsage: with caplog.at_level(logging.WARNING): usage_tracking.track_usage( - filename, "model1", input_tokens, output_tokens, cache_creation, cache_read + filename, + "model1", + input_tokens, + output_tokens, + cache_creation, + cache_read, ) final_data = usage_tracking.get_usage_data() @@ -549,7 +583,10 @@ class TestTrackUsage: global_data = usage_data["global"] assert global_data["total_requests"] == expected_requests assert global_data["total_fresh_input_tokens"] == expected_input - assert global_data["total_cache_tokens"] == expected_cache_creation + expected_cache_read + assert ( + global_data["total_cache_tokens"] + == expected_cache_creation + expected_cache_read + ) def test_track_usage_cost_calculation(self, mocker): """Test that cost calculation is correct for all token types.""" @@ -570,7 +607,12 @@ class TestTrackUsage: cache_read_tokens = 300 # Charged at cache read rate usage_tracking.track_usage( - filename, model_id, input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens + filename, + model_id, + input_tokens, + output_tokens, + cache_creation_tokens, + cache_read_tokens, ) usage_data = usage_tracking.get_usage_data() @@ -589,7 +631,9 @@ class TestTrackUsage: # Verify cache creation uses input rate, not cache read rate cache_creation_cost = cache_creation_tokens * input_cost cache_read_cost_calc = cache_read_tokens * cache_read_cost - assert cache_creation_cost > cache_read_cost_calc # Input rate > cache read rate + assert ( + cache_creation_cost > cache_read_cost_calc + ) # Input rate > cache read rate class TestGetUsageData: @@ -630,7 +674,10 @@ class TestGetUsageData: assert "global" in usage_data assert "file1.txt" in usage_data["per_file_per_model"] assert "model1" in usage_data["per_file_per_model"]["file1.txt"] - assert usage_data["per_file_per_model"]["file1.txt"]["model1"]["input_tokens"] == 100 + assert ( + usage_data["per_file_per_model"]["file1.txt"]["model1"]["input_tokens"] + == 100 + ) assert usage_data["global"]["total_fresh_input_tokens"] == 100 def test_get_usage_data_multiple_files_single_model(self, mocker): @@ -711,7 +758,10 @@ class TestGetUsageData: # Get fresh data and verify original values are unchanged fresh_data = usage_tracking.get_usage_data() - assert fresh_data["per_file_per_model"]["file1.txt"]["model1"]["input_tokens"] == 100 + assert ( + fresh_data["per_file_per_model"]["file1.txt"]["model1"]["input_tokens"] + == 100 + ) assert fresh_data["global"]["total_tokens"] == 150 # 100 + 50 def test_get_usage_data_thread_safety(self, mocker): @@ -999,7 +1049,9 @@ class TestGeneratePerFilePerModelDf: return_value=(input_cost, output_cost, cache_read_cost), ) - usage_tracking.track_usage("file1.txt", "anthropic.claude-3-5-sonnet-20240620-v1:0", 100, 50, 10, 20) + usage_tracking.track_usage( + "file1.txt", "anthropic.claude-3-5-sonnet-20240620-v1:0", 100, 50, 10, 20 + ) run_id = "test_batch" timestamp = "run_20240101_12-00_test_batch" @@ -1069,7 +1121,10 @@ class TestGeneratePerFilePerModelDf: df = usage_tracking._generate_per_file_per_model_df(run_id, timestamp) assert len(df) == 2 - assert set(df["model_name"].values) == {"Claude Unknown", "Claude Unknown"} # Fallback for unknown models + assert set(df["model_name"].values) == { + "Claude Unknown", + "Claude Unknown", + } # Fallback for unknown models def test_generate_per_file_per_model_df_cost_calculation(self, mocker): """Test cost_per_token calculation and rounding.""" @@ -1098,7 +1153,10 @@ class TestGeneratePerFilePerModelDf: expected_cost_per_token = total_cost / total_tokens # Allow for floating point precision (rounding happens in the function) - assert abs(df["cost_per_token"].iloc[0] - round(expected_cost_per_token, 8)) < 1e-10 + assert ( + abs(df["cost_per_token"].iloc[0] - round(expected_cost_per_token, 8)) + < 1e-10 + ) assert df["cost_per_token"].iloc[0] == round(expected_cost_per_token, 8) assert df["total_cost"].iloc[0] == round(total_cost, 6) @@ -1343,7 +1401,8 @@ class TestExportUsageCostCsvsLocal: return_value=(input_cost, output_cost, cache_read_cost), ) mocker.patch( - "src.utils.usage_tracking.config.CONSOLIDATED_OUTPUT_DIRECTORY", str(tmp_path) + "src.utils.usage_tracking.config.CONSOLIDATED_OUTPUT_DIRECTORY", + str(tmp_path), ) usage_tracking.track_usage("file1.txt", "model1", 100, 50, 10, 20) @@ -1380,7 +1439,8 @@ class TestExportUsageCostCsvsLocal: def test_export_usage_cost_csvs_local_empty_data(self, mocker, tmp_path, caplog): """Test exporting CSV files with empty usage data.""" mocker.patch( - "src.utils.usage_tracking.config.CONSOLIDATED_OUTPUT_DIRECTORY", str(tmp_path) + "src.utils.usage_tracking.config.CONSOLIDATED_OUTPUT_DIRECTORY", + str(tmp_path), ) run_id = "test_batch" @@ -1413,7 +1473,8 @@ class TestExportUsageCostCsvsLocal: return_value=(input_cost, output_cost, cache_read_cost), ) mocker.patch( - "src.utils.usage_tracking.config.CONSOLIDATED_OUTPUT_DIRECTORY", str(tmp_path) + "src.utils.usage_tracking.config.CONSOLIDATED_OUTPUT_DIRECTORY", + str(tmp_path), ) usage_tracking.track_usage("file1.txt", "model1", 100, 50, 0, 0) @@ -1440,7 +1501,8 @@ class TestExportUsageCostCsvsLocal: return_value=(input_cost, output_cost, cache_read_cost), ) mocker.patch( - "src.utils.usage_tracking.config.CONSOLIDATED_OUTPUT_DIRECTORY", str(tmp_path) + "src.utils.usage_tracking.config.CONSOLIDATED_OUTPUT_DIRECTORY", + str(tmp_path), ) usage_tracking.track_usage("file1.txt", "model1", 100, 50, 0, 0) @@ -1473,21 +1535,33 @@ class TestGetModelName: ("anthropic.claude-3-5-sonnet-20240620-v1:0", "Claude 3.5 Sonnet"), ("anthropic.claude-3-5-sonnet-20241022-v2:0", "Claude 3.5 Sonnet"), ("anthropic.claude-3.5-sonnet-20240620-v1:0", "Claude 3.5 Sonnet"), - ("Anthropic.Claude-3-5-Sonnet-20240620-V1:0", "Claude 3.5 Sonnet"), # Mixed case + ( + "Anthropic.Claude-3-5-Sonnet-20240620-V1:0", + "Claude 3.5 Sonnet", + ), # Mixed case # Claude 3.7 Sonnet ("us.anthropic.claude-3-7-sonnet-20250219-v1:0", "Claude 3.7 Sonnet"), ("us.anthropic.claude-3.7-sonnet-20250219-v1:0", "Claude 3.7 Sonnet"), - ("US.ANTHROPIC.CLAUDE-3-7-SONNET-20250219-V1:0", "Claude 3.7 Sonnet"), # Uppercase + ( + "US.ANTHROPIC.CLAUDE-3-7-SONNET-20250219-V1:0", + "Claude 3.7 Sonnet", + ), # Uppercase # Claude 4 Sonnet ("us.anthropic.claude-sonnet-4-20250514-v1:0", "Claude 4 Sonnet"), ("us.anthropic.claude-4-sonnet-20250514-v1:0", "Claude 4 Sonnet"), - ("US.ANTHROPIC.CLAUDE-SONNET-4-20250514-V1:0", "Claude 4 Sonnet"), # Uppercase + ( + "US.ANTHROPIC.CLAUDE-SONNET-4-20250514-V1:0", + "Claude 4 Sonnet", + ), # Uppercase # Claude 4.5 Sonnet ("us.anthropic.claude-sonnet-4-5-20250929-v1:0", "Claude 4.5 Sonnet"), ("us.anthropic.claude-sonnet-4.5-20250929-v1:0", "Claude 4.5 Sonnet"), # Note: claude-4-5-sonnet and claude-4.5-sonnet don't match the pattern # They need claude-sonnet-4 or claude-4-sonnet structure - ("US.ANTHROPIC.CLAUDE-SONNET-4-5-20250929-V1:0", "Claude 4.5 Sonnet"), # Uppercase + ( + "US.ANTHROPIC.CLAUDE-SONNET-4-5-20250929-V1:0", + "Claude 4.5 Sonnet", + ), # Uppercase ], ) def test_get_model_name_valid_models(self, model_id, expected_name): @@ -1560,9 +1634,18 @@ class TestGetModelName: # Test models that should trigger fallback extraction # Fallback extracts: model_id.split('.')[-1].split('-')[0] test_cases = [ - ("anthropic.claude-5-sonnet-v1:0", "Claude claude"), # Extracts "claude" from "claude-5-sonnet-v1:0" - ("anthropic.claude-10-v1:0", "Claude claude"), # Extracts "claude" from "claude-10-v1:0" - ("some.prefix.model-7-v1:0", "Claude model"), # Extracts "model" from "model-7-v1:0" + ( + "anthropic.claude-5-sonnet-v1:0", + "Claude claude", + ), # Extracts "claude" from "claude-5-sonnet-v1:0" + ( + "anthropic.claude-10-v1:0", + "Claude claude", + ), # Extracts "claude" from "claude-10-v1:0" + ( + "some.prefix.model-7-v1:0", + "Claude model", + ), # Extracts "model" from "model-7-v1:0" ] for model_id, expected in test_cases: @@ -1574,7 +1657,10 @@ class TestGetModelName: # Model IDs without dots should return "Claude Unknown" # BUT: if they match known patterns (like "claude-3-5-sonnet"), they still work test_cases = [ - ("claude-3-5-sonnet", "Claude 3.5 Sonnet"), # Matches pattern even without dot + ( + "claude-3-5-sonnet", + "Claude 3.5 Sonnet", + ), # Matches pattern even without dot ("claude-instant-v1", "Claude Unknown"), # Claude 2 support removed ("anthropic-claude-3", "Claude Unknown"), # No dot, doesn't match pattern ("just-text", "Claude Unknown"), # No dot, doesn't match pattern @@ -1598,5 +1684,6 @@ class TestGetModelName: for model_id, expected_name in supported_models.items(): result = usage_tracking.get_model_name(model_id) - assert result == expected_name, f"Failed for {model_id}: got {result}, expected {expected_name}" - + assert ( + result == expected_name + ), f"Failed for {model_id}: got {result}, expected {expected_name}" diff --git a/streamlit/__init__.py b/src/tracking/__init__.py similarity index 100% rename from streamlit/__init__.py rename to src/tracking/__init__.py diff --git a/fieldExtraction/src/tracking/batch_tracking.py b/src/tracking/batch_tracking.py similarity index 100% rename from fieldExtraction/src/tracking/batch_tracking.py rename to src/tracking/batch_tracking.py diff --git a/src/utils/__init__.py b/src/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fieldExtraction/src/utils/crosswalk_utils.py b/src/utils/crosswalk_utils.py similarity index 99% rename from fieldExtraction/src/utils/crosswalk_utils.py rename to src/utils/crosswalk_utils.py index f62fb2c..673487d 100644 --- a/fieldExtraction/src/utils/crosswalk_utils.py +++ b/src/utils/crosswalk_utils.py @@ -18,7 +18,7 @@ def apply_crosswalk(val: str, mapping: dict[str, str], default: str = "N/A") -> # Handle None or blank values defensively if val is None: return default - + # Store original for fallback original_val = str(val).strip() diff --git a/fieldExtraction/src/utils/embedding_utils.py b/src/utils/embedding_utils.py similarity index 100% rename from fieldExtraction/src/utils/embedding_utils.py rename to src/utils/embedding_utils.py diff --git a/fieldExtraction/src/utils/io_utils.py b/src/utils/io_utils.py similarity index 97% rename from fieldExtraction/src/utils/io_utils.py rename to src/utils/io_utils.py index 0f95986..739f0dd 100644 --- a/fieldExtraction/src/utils/io_utils.py +++ b/src/utils/io_utils.py @@ -7,12 +7,13 @@ import json from threading import Lock import pandas as pd -import src.tracking.tracking_utils as tracking_utils +import src.utils.tracking_utils as tracking_utils from botocore.exceptions import ClientError from pyxlsb import open_workbook from src import config from pathlib import Path from typing import Optional + # Thread-safe lock for JSON file operations json_write_lock = Lock() @@ -381,8 +382,10 @@ def write_local( quoting=1, ) if config.PERFORM_PARENT_CHILD_MAPPING: - return os.path.join(config.OUTPUT_DIRECTORY, f"{base_filename}_-RESULTS.csv") - + return os.path.join( + config.OUTPUT_DIRECTORY, f"{base_filename}_-RESULTS.csv" + ) + return None elif output_type == "parent_child": output_dir = os.path.join(config.CONSOLIDATED_OUTPUT_DIRECTORY, run_timestamp) @@ -445,8 +448,8 @@ def write_local( ) return None elif output_type == "qc_qa_validated": - # QC/QA validated output goes to qa_qc_output folder in fieldExtraction - output_dir = os.path.join("qa_qc_output", run_timestamp) + # QC/QA validated output goes to outputs/qc_qa folder + output_dir = os.path.join(config.QC_QA_OUTPUT_DIRECTORY, run_timestamp) os.makedirs(output_dir, exist_ok=True) df.to_csv( os.path.join(output_dir, f"{config.BATCH_ID}-QC-QA-VALIDATED.csv"), @@ -455,8 +458,8 @@ def write_local( ) return None elif output_type == "qc_qa_stats": - # QC/QA statistics output goes to qa_qc_output folder in fieldExtraction - output_dir = os.path.join("qa_qc_output", run_timestamp) + # QC/QA statistics output goes to outputs/qc_qa folder + output_dir = os.path.join(config.QC_QA_OUTPUT_DIRECTORY, run_timestamp) os.makedirs(output_dir, exist_ok=True) df.to_csv( os.path.join(output_dir, f"{config.BATCH_ID}-QC-QA-STATS.csv"), @@ -544,7 +547,7 @@ def write_s3( elif output_type == "individual": logging.info(f"Saved individual output file: {output_path}") elif output_type == "parent_child": - logging.info(f"Saved parent_child output file: {output_path}") + logging.info(f"Saved parent_child output file: {output_path}") elif output_type == "error": logging.info(f"Saved error output file: {output_path}") elif output_type == "usage": @@ -561,10 +564,10 @@ def write_s3( logging.info(f"Saved QC/QA statistics file: {output_path}") else: logging.info(f"Saved unknown output type file: {output_path}") - + if config.PERFORM_PARENT_CHILD_MAPPING: return f"s3://{config.S3_OUTPUT_BUCKET}/{output_path}" - + return None except ClientError as e: logging.error(f"Error uploading to S3: {e}") @@ -624,9 +627,9 @@ def read_DataFrame(file_path: str) -> pd.DataFrame: Supports reading from local file system and only CSV from S3. """ - is_s3 = file_path.startswith('s3://') + is_s3 = file_path.startswith("s3://") - if is_s3: + if is_s3: file = read_s3_csv(file_path) return file file = read_local(file_path) @@ -648,4 +651,4 @@ def convert_json_to_dict(json_file_path: str) -> dict: } return converted except json.JSONDecodeError: - return {} \ No newline at end of file + return {} diff --git a/fieldExtraction/src/utils/llm_utils.py b/src/utils/llm_utils.py similarity index 95% rename from fieldExtraction/src/utils/llm_utils.py rename to src/utils/llm_utils.py index ec5b0a5..5d107ab 100644 --- a/fieldExtraction/src/utils/llm_utils.py +++ b/src/utils/llm_utils.py @@ -45,30 +45,36 @@ _DEPRECATED_PATTERNS = [ ] -def _validate_model_support(model_id: str, resolved_model_id: str, context: str = "") -> None: +def _validate_model_support( + model_id: str, resolved_model_id: str, context: str = "" +) -> None: """Validate that a model is supported and not deprecated. - + Checks both exact model IDs and pattern matching for deprecated models. Raises ValueError with warning if model is deprecated or unsupported. - + Args: model_id: Original model ID (may be alias) resolved_model_id: Resolved model ID from config.resolve_model_id() context: Additional context for error message (e.g., "for image array") """ model_id_lower = resolved_model_id.lower() - + # Check for deprecated patterns (fuzzy match) for pattern in _DEPRECATED_PATTERNS: if pattern in model_id_lower: # Determine appropriate error message based on pattern if "claude-2" in pattern or "claude-instant" in pattern: - deprecation_msg = "Claude 2 is no longer supported. Please use Claude 3+ models." + deprecation_msg = ( + "Claude 2 is no longer supported. Please use Claude 3+ models." + ) supported_models = "Haiku, Sonnet 3.5/3.7/4/4.5" else: - deprecation_msg = "This model is no longer supported. Please use Claude 3+ models." + deprecation_msg = ( + "This model is no longer supported. Please use Claude 3+ models." + ) supported_models = "Haiku, Sonnet 3.5/3.7/4/4.5" - + warning_msg = ( f"Deprecated model detected: {model_id} (resolved: {resolved_model_id}). " f"{deprecation_msg}" @@ -83,7 +89,7 @@ def _validate_model_support(model_id: str, resolved_model_id: str, context: str f"Unsupported model_id{(' ' + context) if context else ''}: {model_id}. " f"{deprecation_msg} Supported models: {supported_models}." ) - + # Check if supported (exact match) supported_set = {m for m in _SUPPORTED_MODELS if m is not None} if resolved_model_id not in supported_set: @@ -113,9 +119,11 @@ def _supports_prompt_cache(model_id: str) -> bool: return model_id in {m for m in supported_ids if m is not None} -def _track_usage_from_response(response_body: dict, filename: str, model_id: str) -> None: +def _track_usage_from_response( + response_body: dict, filename: str, model_id: str +) -> None: """Extract and track usage from API response. - + Args: response_body: Parsed JSON response from Bedrock API filename: Name of file being processed @@ -123,14 +131,14 @@ def _track_usage_from_response(response_body: dict, filename: str, model_id: str """ if not filename: return - + ( input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens, ) = usage_tracking.extract_usage_from_response(response_body) - + if ( input_tokens > 0 or output_tokens > 0 @@ -155,14 +163,14 @@ def _build_claude_3_request_body( model_id: str = None, ) -> dict: """Build request body for Claude 3+ API calls. - + Args: prompt: Input text prompt max_tokens: Maximum tokens to generate instruction: Optional system instruction cache: Whether to enable prompt caching model_id: Model ID to check for cache support - + Returns: Dictionary ready for JSON serialization """ @@ -171,7 +179,7 @@ def _build_claude_3_request_body( "max_tokens": max_tokens, "temperature": 0.0, } - + if instruction: if cache and model_id and _supports_prompt_cache(model_id): request_body["system"] = [ @@ -183,17 +191,17 @@ def _build_claude_3_request_body( ] else: request_body["system"] = instruction - + request_body["messages"] = [ {"role": "user", "content": [{"type": "text", "text": prompt}]} ] - + return request_body def _store_in_cache(cache_key: str, response: str) -> None: """Thread-safe cache storage with LRU eviction. - + Args: cache_key: Unique cache key for this response response: Response text to cache @@ -216,14 +224,14 @@ _CLAUDE_3_AND_UP_MODELS = {m for m in _SUPPORTED_MODELS if m is not None} def get_cache_key(prompt, model_id, instruction=None, max_tokens=None, cache=False): """Generates a unique hash key for caching. - + Args: prompt (str): The input prompt. model_id (str): The model identifier. instruction (str, optional): System instruction for caching. Defaults to None. max_tokens (int, optional): Maximum tokens to generate. Defaults to None. cache (bool, optional): Whether caching is enabled. Defaults to False. - + Returns: str: SHA256 hash of the cache key components. """ @@ -278,7 +286,9 @@ def invoke_claude( except Exception: usage_label = "UNLABELED" - cache_key = get_cache_key(prompt, model_id, instruction=instruction, max_tokens=max_tokens, cache=cache) + cache_key = get_cache_key( + prompt, model_id, instruction=instruction, max_tokens=max_tokens, cache=cache + ) # Check cache first - thread-safe access with _cache_lock: @@ -291,7 +301,7 @@ def invoke_claude( # Validate model support (checks for deprecated and unsupported models) _validate_model_support(model_id, resolved_model_id) - + if config.RUN_MODE == "local": response = local_claude_3_and_up( prompt, @@ -322,9 +332,11 @@ def invoke_claude( return response -def get_cache_key_with_image_array(prompt, model_id, image_base64_list, instruction=None, max_tokens=None, cache=False): +def get_cache_key_with_image_array( + prompt, model_id, image_base64_list, instruction=None, max_tokens=None, cache=False +): """Generates a unique hash key for caching with a list of base64 images. - + Args: prompt (str): The input prompt. model_id (str): The model identifier. @@ -332,11 +344,13 @@ def get_cache_key_with_image_array(prompt, model_id, image_base64_list, instruct instruction (str, optional): System instruction for caching. Defaults to None. max_tokens (int, optional): Maximum tokens to generate. Defaults to None. cache (bool, optional): Whether caching is enabled. Defaults to False. - + Returns: str: SHA256 hash of the cache key components. """ - combined_images = ":".join(image_base64_list) # Combine all base64 images into a single string + combined_images = ":".join( + image_base64_list + ) # Combine all base64 images into a single string # Build cache key from all relevant parameters key_parts = [model_id, prompt, combined_images] if instruction is not None: @@ -352,7 +366,9 @@ def invoke_claude_with_image_array( prompt, model_id, filename, base64_images, max_tokens=4096 ): usage_label = inspect.stack()[1].function - cache_key = get_cache_key_with_image_array(prompt, model_id, base64_images, max_tokens=max_tokens) + cache_key = get_cache_key_with_image_array( + prompt, model_id, base64_images, max_tokens=max_tokens + ) # Check cache first - thread-safe access with _cache_lock: if cache_key in claude_cache: @@ -364,7 +380,7 @@ def invoke_claude_with_image_array( # Validate model support (checks for deprecated and unsupported models) _validate_model_support(model_id, resolved_model_id, context="for image array") - + if config.RUN_MODE == "local": if resolved_model_id == config.MODEL_ID_CLAUDE35_SONNET: response = local_claude_3_and_up_with_image_array( @@ -410,6 +426,7 @@ def invoke_claude_with_image_array( # Claude calls # Note: local_claude_2() and ec2_claude2() have been removed as Claude 2 is no longer supported + def local_claude_3_and_up( prompt: str, model_id: str, @@ -762,7 +779,12 @@ def get_image_array_answer(prompt, filename, base64_images): return response_dict -def warm_prompt_cache(instruction: str, cache_key: str, model_id: str = "sonnet_latest", max_tokens: int = 10): +def warm_prompt_cache( + instruction: str, + cache_key: str, + model_id: str = "sonnet_latest", + max_tokens: int = 10, +): """ Warms the prompt cache by sending a minimal request with the instruction. This should be called once before parallel processing to ensure the cache is registered. @@ -798,7 +820,11 @@ def warm_prompt_cache(instruction: str, cache_key: str, model_id: str = "sonnet_ try: # Build request with caching enabled request_body = _build_claude_3_request_body( - minimal_prompt, max_tokens, instruction=instruction, cache=True, model_id=resolved_model_id + minimal_prompt, + max_tokens, + instruction=instruction, + cache=True, + model_id=resolved_model_id, ) body = json.dumps(request_body) @@ -833,7 +859,9 @@ def warm_prompt_cache(instruction: str, cache_key: str, model_id: str = "sonnet_ if "usage" in response_body: usage = response_body["usage"] if "cache_creation_input_tokens" in usage: - logging.info(f"Cache created with {usage.get('cache_creation_input_tokens', 0)} tokens for {cache_key}") + logging.info( + f"Cache created with {usage.get('cache_creation_input_tokens', 0)} tokens for {cache_key}" + ) return True diff --git a/fieldExtraction/src/utils/logging_utils.py b/src/utils/logging_utils.py similarity index 99% rename from fieldExtraction/src/utils/logging_utils.py rename to src/utils/logging_utils.py index 63711bf..b5f9845 100644 --- a/fieldExtraction/src/utils/logging_utils.py +++ b/src/utils/logging_utils.py @@ -198,7 +198,7 @@ def setup_per_file_logging() -> None: console_formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") console_handler.setFormatter(console_formatter) logger.addHandler(console_handler) - + # Prevent propagation to avoid duplicate console output logger.propagate = False diff --git a/fieldExtraction/src/utils/qa_qc_utils.py b/src/utils/qa_qc_utils.py similarity index 98% rename from fieldExtraction/src/utils/qa_qc_utils.py rename to src/utils/qa_qc_utils.py index fc79b37..227b80a 100644 --- a/fieldExtraction/src/utils/qa_qc_utils.py +++ b/src/utils/qa_qc_utils.py @@ -9,10 +9,14 @@ import src.utils.string_utils as string_utils from openpyxl import Workbook from openpyxl.utils.dataframe import dataframe_to_rows from src import config -from src.investment import preprocessing_funcs +from src.pipelines.shared import preprocessing_funcs # Suppress pandas regex UserWarnings about match groups -warnings.filterwarnings('ignore', message='This pattern is interpreted as a regular expression', category=UserWarning) +warnings.filterwarnings( + "ignore", + message="This pattern is interpreted as a regular expression", + category=UserWarning, +) def detect_date_anomalies(series, field_name, is_merged=False): @@ -1052,7 +1056,8 @@ def format_date_series(series: pd.Series, col_name: str) -> Tuple[pd.Series, pd. # Outlier = parsed but absurd year (<1900 or > today) today = datetime.now().date() outlier_mask = (~parsed_dates.isna()) & ( - (parsed_dates.apply(lambda d: d.year if d else 0) < 1900) | (parsed_dates > today) + (parsed_dates.apply(lambda d: d.year if d else 0) < 1900) + | (parsed_dates > today) ) flags = pd.Series("", index=series.index, dtype="object") @@ -1217,17 +1222,13 @@ def parse_cpt_hcpcs_or_revenue(cell) -> List[str]: if pd.isna(cell): return [] tokens = _normalize_cell(cell) - only_revenue = len(tokens) > 0 and all( - QC_RE_REVENUE4.fullmatch(t) for t in tokens - ) + only_revenue = len(tokens) > 0 and all(QC_RE_REVENUE4.fullmatch(t) for t in tokens) if only_revenue: return tokens kept = [] for t in tokens: clean = t.replace(" ", "") - if QC_RE_RANGE_CPT.fullmatch( - clean - ) or QC_RE_RANGE_HCPCS.fullmatch(clean): + if QC_RE_RANGE_CPT.fullmatch(clean) or QC_RE_RANGE_HCPCS.fullmatch(clean): kept.append(clean) elif QC_RE_CPT5.fullmatch(clean) or QC_RE_HCPCS.fullmatch(clean): kept.append(clean) @@ -1388,7 +1389,9 @@ def check_hallucination(df: pd.DataFrame) -> pd.DataFrame: # Various hallucination checks mask_start = col_vals.str.lower().str.startswith(("it seems like"), na=False) - mask_pattern = col_vals.str.contains(pattern_between_stars, na=False, regex=True) + mask_pattern = col_vals.str.contains( + pattern_between_stars, na=False, regex=True + ) mask_json_blob = col_vals.str.contains(pattern_json_like, na=False, regex=True) mask_canned = col_vals.str.contains(QC_CANNED_RGX, na=False, regex=True) mask_generic = col_vals.str.contains(QC_GENERIC_RGX, na=False, regex=True) diff --git a/fieldExtraction/src/utils/rag_utils.py b/src/utils/rag_utils.py similarity index 97% rename from fieldExtraction/src/utils/rag_utils.py rename to src/utils/rag_utils.py index fff6540..b8b1506 100644 --- a/fieldExtraction/src/utils/rag_utils.py +++ b/src/utils/rag_utils.py @@ -11,8 +11,8 @@ from dataclasses import dataclass from typing import Any, List, Dict import boto3 -from langchain.retrievers import EnsembleRetriever -from langchain.schema import Document +from langchain_classic.retrievers import EnsembleRetriever +from langchain_core.documents import Document from langchain_aws import BedrockEmbeddings from langchain_community.retrievers import BM25Retriever from langchain_community.vectorstores import FAISS diff --git a/fieldExtraction/src/utils/string_utils.py b/src/utils/string_utils.py similarity index 95% rename from fieldExtraction/src/utils/string_utils.py rename to src/utils/string_utils.py index b9e309c..5ad35f6 100644 --- a/fieldExtraction/src/utils/string_utils.py +++ b/src/utils/string_utils.py @@ -9,9 +9,12 @@ from typing import Literal, overload import numpy as np import pandas as pd -from constants.delimiters import Delimiter -from constants.regex_patterns import (BACKTICK_PATTERN, PIPE_PATTERN, - TRIPLE_BACKTICK_PATTERN) +from src.constants.delimiters import Delimiter +from src.constants.regex_patterns import ( + BACKTICK_PATTERN, + PIPE_PATTERN, + TRIPLE_BACKTICK_PATTERN, +) def extract_text_from_delimiters( @@ -194,7 +197,7 @@ def universal_json_load(s: str): found = [] i = 0 while i < len(s): - if s[i] in '{[': + if s[i] in "{[": start = i stack = [s[i]] j = i + 1 @@ -203,22 +206,24 @@ def universal_json_load(s: str): if s[j] == '"': j += 1 while j < len(s): - if s[j] == '\\' and j + 1 < len(s): + if s[j] == "\\" and j + 1 < len(s): j += 2 # Skip escaped character continue if s[j] == '"': break j += 1 - elif s[j] in '{[': + elif s[j] in "{[": stack.append(s[j]) - elif s[j] in '}]': + elif s[j] in "}]": if not stack: break open_bracket = stack.pop() - if (open_bracket == '{' and s[j] != '}') or (open_bracket == '[' and s[j] != ']'): + if (open_bracket == "{" and s[j] != "}") or ( + open_bracket == "[" and s[j] != "]" + ): break if not stack: - candidate = s[start:j+1] + candidate = s[start : j + 1] # Only consider top-level objects (not nested) # Check if start is not inside another object # This is guaranteed by stack being empty only at top-level @@ -245,7 +250,7 @@ reimbursement_strings = [ # These are for `method='keyword'` "billed charges", "compensation", "reimbursement", - "fee schedule" + "fee schedule", ] reimb_regex = r"(? bool | pd.S if not value or value.isspace(): return True lower_stripped = value.lower().strip() - if lower_stripped in ["n/a", "na", "null", "none", "nan", "no_identifiers_found"]: + if lower_stripped in [ + "n/a", + "na", + "null", + "none", + "nan", + "no_identifiers_found", + ]: return True return value in empty_values @@ -418,7 +430,7 @@ def extract_signature_page(text_dict: dict, filename: str) -> dict: next_page_num = str(int(page_num) + 1) if next_page_num in text_dict: signature_pages[next_page_num] = text_dict[next_page_num] - + return signature_pages @@ -593,6 +605,7 @@ def flatten_to_strings(items) -> list[str]: return result + def parse_state_field_to_list(raw_value): """ Convert PROVIDER_STATE raw input into a clean list of state strings. @@ -627,7 +640,9 @@ def parse_state_field_to_list(raw_value): else: return [parsed] except Exception as e: - logging.debug(f"Failed JSON parse for state list: {e}. Falling back to comma split.") + logging.debug( + f"Failed JSON parse for state list: {e}. Falling back to comma split." + ) # fallback: treat as comma-separated # Comma-separated list @@ -644,6 +659,7 @@ def parse_state_field_to_list(raw_value): logging.error(f"Could not convert value to string: {raw_value!r}") return [] + def normalize_state_field(answers_dict: dict, field_name: str = "PROVIDER_STATE"): if field_name not in answers_dict or not answers_dict[field_name]: answers_dict[field_name] = [] @@ -660,7 +676,9 @@ def normalize_state_field(answers_dict: dict, field_name: str = "PROVIDER_STATE" try: normalized_states.append(normalize_state_to_abbreviation(state)) except Exception as e: - logging.warning(f"Failed to normalize state '{state}': {e}. Keeping original.") + logging.warning( + f"Failed to normalize state '{state}': {e}. Keeping original." + ) normalized_states.append(state) answers_dict[field_name] = normalized_states @@ -674,29 +692,29 @@ def parse_raw_state_value(raw_value): """ if not raw_value: return [] - + # If it's a string that looks like a list, try to parse it if isinstance(raw_value, str): stripped = raw_value.strip() - + # Try to parse as Python literal (handles "[['NC', 'WA'], 'CA|UT']") - if stripped.startswith('['): + if stripped.startswith("["): try: parsed = ast.literal_eval(stripped) return parse_raw_state_value(parsed) # Recursive call with parsed list except (ValueError, SyntaxError): pass # Not valid Python literal, continue with string parsing - + # Regular string splitting on delimiters (not whitespace - state names can have spaces like "West Virginia") - states = re.split(r'[|,;]+', stripped) + states = re.split(r"[|,;]+", stripped) return [s.strip() for s in states if s.strip()] - + if isinstance(raw_value, list): result = [] for item in raw_value: result.extend(parse_raw_state_value(item)) # Recursive call return result - + return [str(raw_value)] @@ -705,11 +723,11 @@ def normalize_to_json_list(val): Normalizes a value to a JSON list format. Handles: pipe-delimited strings, string representations of Python lists, actual lists with pipe-delimited items, and single values. - """ + """ # Handle None and empty values first if is_empty(val): return val - + # Handle pandas NA/NaN - check for scalar first try: if pd.isna(val): @@ -717,7 +735,7 @@ def normalize_to_json_list(val): except (ValueError, TypeError): # pd.isna fails on arrays/lists, which is fine - we'll handle them below pass - + if isinstance(val, str): # Check if it's a string representation of a Python list (e.g., "['item1', 'item2']") if val.startswith("[") and val.endswith("]"): @@ -730,7 +748,7 @@ def normalize_to_json_list(val): parsed = ast.literal_eval(val) except (ValueError, SyntaxError): return val - + if isinstance(parsed, list): expanded = [] for item in parsed: @@ -741,16 +759,16 @@ def normalize_to_json_list(val): result = json.dumps(expanded) return result return val - + # Pipe-delimited format - convert to JSON list if "|" in val: result = json.dumps(val.split("|")) return result - + # Single value - convert to JSON list result = json.dumps([val]) return result - + if isinstance(val, list): # Check if list contains pipe-delimited strings and expand them expanded = [] @@ -761,4 +779,4 @@ def normalize_to_json_list(val): expanded.append(item) result = json.dumps(expanded) return result - return val \ No newline at end of file + return val diff --git a/fieldExtraction/src/utils/timing_utils.py b/src/utils/timing_utils.py similarity index 90% rename from fieldExtraction/src/utils/timing_utils.py rename to src/utils/timing_utils.py index 80b70d0..3d3fbb7 100644 --- a/fieldExtraction/src/utils/timing_utils.py +++ b/src/utils/timing_utils.py @@ -18,10 +18,11 @@ from collections import defaultdict @dataclass class TimingStats: """Statistics for a timed operation.""" + name: str count: int = 0 total_time: float = 0.0 - min_time: float = float('inf') + min_time: float = float("inf") max_time: float = 0.0 times: List[float] = field(default_factory=list) @@ -87,8 +88,12 @@ class TimingTracker: return # Filter and sort by total time - filtered_stats = [s for s in self._stats.values() if s.total_time >= min_time] - sorted_stats = sorted(filtered_stats, key=lambda s: s.total_time, reverse=True) + filtered_stats = [ + s for s in self._stats.values() if s.total_time >= min_time + ] + sorted_stats = sorted( + filtered_stats, key=lambda s: s.total_time, reverse=True + ) logging.info("=" * 80) logging.info("TIMING SUMMARY (sorted by total time)") @@ -113,7 +118,7 @@ class TimingTracker: # Group stats by top-level component components = defaultdict(list) for name, stat in self._stats.items(): - component = name.split('.')[0] + component = name.split(".")[0] components[component].append(stat) logging.info("=" * 80) @@ -125,16 +130,20 @@ class TimingTracker: comp: sum(s.total_time for s in stats) for comp, stats in components.items() } - sorted_components = sorted(component_totals.items(), key=lambda x: x[1], reverse=True) + sorted_components = sorted( + component_totals.items(), key=lambda x: x[1], reverse=True + ) for component, total_time in sorted_components: logging.info(f"\n{component}: {total_time:.2f}s total") logging.info("-" * 60) # Sort stats within component by total time - sorted_stats = sorted(components[component], key=lambda s: s.total_time, reverse=True) + sorted_stats = sorted( + components[component], key=lambda s: s.total_time, reverse=True + ) for stat in sorted_stats: - indent = " " * (stat.name.count('.')) + indent = " " * (stat.name.count(".")) logging.info(f"{indent}{stat}") logging.info("=" * 80) @@ -185,7 +194,9 @@ def timed_block(name: str, context: Optional[str] = None, log_level: str = "DEBU log_func(f"⏱️ {full_name}: {duration:.2f}s") -def timed(name: Optional[str] = None, context: Optional[str] = None, log_level: str = "DEBUG"): +def timed( + name: Optional[str] = None, context: Optional[str] = None, log_level: str = "DEBUG" +): """ Decorator for timing function execution. @@ -195,6 +206,7 @@ def timed(name: Optional[str] = None, context: Optional[str] = None, log_level: # function code pass """ + def decorator(func: Callable) -> Callable: func_name = name or func.__name__ @@ -214,6 +226,7 @@ def timed(name: Optional[str] = None, context: Optional[str] = None, log_level: log_func(f"⏱️ {full_name}: {duration:.2f}s") return wrapper + return decorator diff --git a/fieldExtraction/src/tracking/tracking_utils.py b/src/utils/tracking_utils.py similarity index 93% rename from fieldExtraction/src/tracking/tracking_utils.py rename to src/utils/tracking_utils.py index f2f8c00..ae55c7e 100644 --- a/fieldExtraction/src/tracking/tracking_utils.py +++ b/src/utils/tracking_utils.py @@ -39,16 +39,16 @@ def initialize_tracking_stats(): def write_stats_to_csv(filename=config.TRACKING_FILE, run_id=None, timestamp=None): """Write model and global stats to CSV file with retry logic. - + DEPRECATED: This function now uses usage_tracking.py as the data source instead of config.MODEL_STATS/config.GLOBAL_STATS. The legacy CSV format is maintained for backward compatibility. - + Args: filename (str): Output CSV file path. Defaults to config.TRACKING_FILE. run_id (str, optional): Run identifier (typically BATCH_ID). Defaults to config.BATCH_ID. timestamp (str, optional): Timestamp string for this run. Defaults to current timestamp. - + Note: - This function now reads from usage_tracking.py instead of config.MODEL_STATS/GLOBAL_STATS - Timing information (Total Time, Avg Time) is not available in the new system and will be 0 @@ -59,15 +59,17 @@ def write_stats_to_csv(filename=config.TRACKING_FILE, run_id=None, timestamp=Non run_id = config.BATCH_ID if timestamp is None: timestamp = datetime.now().strftime(f"run_%Y%m%d_%H-%M_{config.BATCH_ID}") - + max_retries = 5 for attempt in range(max_retries): try: # Get usage data from usage_tracking.py - per_file_df, summary_df = usage_tracking.get_usage_dataframes(run_id, timestamp) + per_file_df, summary_df = usage_tracking.get_usage_dataframes( + run_id, timestamp + ) # Also get raw usage data to access request_count usage_data = usage_tracking.get_usage_data() - + with open(filename, "w", newline="") as csvfile: writer = csv.writer(csvfile) writer.writerow( @@ -82,7 +84,7 @@ def write_stats_to_csv(filename=config.TRACKING_FILE, run_id=None, timestamp=Non "Claude 3.5 Requests", ] ) - + # Transform per-file, per-model data to per-file aggregated data if not per_file_df.empty: # Aggregate by filename @@ -92,15 +94,17 @@ def write_stats_to_csv(filename=config.TRACKING_FILE, run_id=None, timestamp=Non model_name = row["model_name"] input_tokens = row["input_tokens"] output_tokens = row["output_tokens"] - + # Get request_count from raw usage data # Find the model_id from model_name by checking usage_data request_count = 1 # Default - for model_id, usage_info in usage_data["per_file_per_model"].get(file_name, {}).items(): + for model_id, usage_info in ( + usage_data["per_file_per_model"].get(file_name, {}).items() + ): if usage_tracking.get_model_name(model_id) == model_name: request_count = usage_info.get("request_count", 1) break - + if file_name not in file_aggregates: file_aggregates[file_name] = { "requests": 0, @@ -109,19 +113,28 @@ def write_stats_to_csv(filename=config.TRACKING_FILE, run_id=None, timestamp=Non "claude3_requests": 0, "claude35_requests": 0, } - + # Aggregate tokens (tokens_sent = fresh input tokens only, not cache) file_aggregates[file_name]["tokens_sent"] += input_tokens file_aggregates[file_name]["tokens_received"] += output_tokens file_aggregates[file_name]["requests"] += request_count - + # Count requests by model type # Note: Claude 2 support has been removed - if "Claude 3" in model_name and "3.5" not in model_name and "3.7" not in model_name and "Haiku" not in model_name: - file_aggregates[file_name]["claude3_requests"] += request_count + if ( + "Claude 3" in model_name + and "3.5" not in model_name + and "3.7" not in model_name + and "Haiku" not in model_name + ): + file_aggregates[file_name][ + "claude3_requests" + ] += request_count elif "Claude 3.5" in model_name or "Claude 3.7" in model_name: - file_aggregates[file_name]["claude35_requests"] += request_count - + file_aggregates[file_name][ + "claude35_requests" + ] += request_count + # Write per-file rows for file_name, stats in file_aggregates.items(): avg_time = 0.0 # Not available in new system @@ -137,22 +150,26 @@ def write_stats_to_csv(filename=config.TRACKING_FILE, run_id=None, timestamp=Non stats["claude35_requests"], ] ) - + # Write global stats from usage_data writer.writerow([]) writer.writerow(["GLOBAL STATS", "Value"]) - + global_data = usage_data["global"] # Map new format to legacy format global_stats = { "total_requests": int(global_data.get("total_requests", 0)), - "total_tokens_sent": int(global_data.get("total_fresh_input_tokens", 0)), - "total_tokens_received": int(global_data.get("total_output_tokens", 0)), + "total_tokens_sent": int( + global_data.get("total_fresh_input_tokens", 0) + ), + "total_tokens_received": int( + global_data.get("total_output_tokens", 0) + ), "total_time": 0.0, # Not available in new system "total_claude3_requests": 0, "total_claude35_requests": 0, } - + # Calculate model-specific request counts from usage_data for file_name, models_dict in usage_data["per_file_per_model"].items(): for model_id, usage_info in models_dict.items(): @@ -161,16 +178,21 @@ def write_stats_to_csv(filename=config.TRACKING_FILE, run_id=None, timestamp=Non model_name = usage_tracking.get_model_name(model_id) request_count = usage_info.get("request_count", 1) # Note: Claude 2 support has been removed - if "Claude 3" in model_name and "3.5" not in model_name and "3.7" not in model_name and "Haiku" not in model_name: + if ( + "Claude 3" in model_name + and "3.5" not in model_name + and "3.7" not in model_name + and "Haiku" not in model_name + ): global_stats["total_claude3_requests"] += request_count elif "Claude 3.5" in model_name or "Claude 3.7" in model_name: global_stats["total_claude35_requests"] += request_count - + for stat_name, stat_value in global_stats.items(): if "time" in stat_name.lower(): stat_value = round(stat_value, 2) writer.writerow([stat_name, stat_value]) - + # Total files processed num_files = len(file_aggregates) if not per_file_df.empty else 0 writer.writerow(["Total Files Processed", num_files]) diff --git a/fieldExtraction/src/utils/usage_tracking.py b/src/utils/usage_tracking.py similarity index 86% rename from fieldExtraction/src/utils/usage_tracking.py rename to src/utils/usage_tracking.py index 6f08651..0242246 100644 --- a/fieldExtraction/src/utils/usage_tracking.py +++ b/src/utils/usage_tracking.py @@ -39,6 +39,10 @@ COST_PER_1K_TOKENS = { # Claude 4.5 Sonnet # Note: cache_creation uses 0.00375 (25% higher than input), handled in track_usage() "us.anthropic.claude-sonnet-4-5-20250929-v1:0": (0.003, 0.015, 0.0003), + # Claude 4.5 Haiku + # cache_read: 0.0001 (from pricing table) + # Note: cache_creation is 20% higher than input (0.0012 vs 0.001), handled in track_usage() + "us.anthropic.claude-haiku-4-5-20251001-v1:0": (0.001, 0.005, 0.0001), # Default fallback (Claude 3.5 Sonnet pricing) "_default": (0.003, 0.015, 0.0003), } @@ -56,15 +60,19 @@ _usage_lock = threading.Lock() # "total_cost": float, # "request_count": int # } -USAGE_DATA = defaultdict(lambda: defaultdict(lambda: { - "input_tokens": 0, - "output_tokens": 0, - "cache_creation_tokens": 0, - "cache_read_tokens": 0, - "total_tokens": 0, - "total_cost": 0.0, - "request_count": 0, -})) +USAGE_DATA = defaultdict( + lambda: defaultdict( + lambda: { + "input_tokens": 0, + "output_tokens": 0, + "cache_creation_tokens": 0, + "cache_read_tokens": 0, + "total_tokens": 0, + "total_cost": 0.0, + "request_count": 0, + } + ) +) # Global usage totals # Note: total_input_tokens = fresh_input_tokens + cache_tokens @@ -91,7 +99,9 @@ def get_model_name(model_id: str) -> str: Human-readable model name (e.g., "Claude 3.5 Sonnet") """ model_id_lower = model_id.lower() - if "claude-3-haiku" in model_id_lower or "claude-3.5-haiku" in model_id_lower: + if "claude-haiku-4-5" in model_id_lower or "claude-4.5-haiku" in model_id_lower: + return "Claude 4.5 Haiku" + elif "claude-3-haiku" in model_id_lower or "claude-3.5-haiku" in model_id_lower: return "Claude 3 Haiku" elif "claude-3-5-sonnet" in model_id_lower or "claude-3.5-sonnet" in model_id_lower: return "Claude 3.5 Sonnet" @@ -122,9 +132,14 @@ def get_cost_per_token(model_id: str) -> tuple[float, float, float]: resolved_model_id = config.resolve_model_id(model_id) # Look up cost from centralized constants - cost_per_1k = COST_PER_1K_TOKENS.get(resolved_model_id, COST_PER_1K_TOKENS["_default"]) + cost_per_1k = COST_PER_1K_TOKENS.get( + resolved_model_id, COST_PER_1K_TOKENS["_default"] + ) - if cost_per_1k == COST_PER_1K_TOKENS["_default"] and resolved_model_id not in COST_PER_1K_TOKENS: + if ( + cost_per_1k == COST_PER_1K_TOKENS["_default"] + and resolved_model_id not in COST_PER_1K_TOKENS + ): logging.warning( f"Unknown model {resolved_model_id} (original: {model_id}), " f"using default pricing" @@ -176,11 +191,13 @@ def track_usage( return # Total tokens includes all types - total_tokens = input_tokens + output_tokens + cache_creation_tokens + cache_read_tokens + total_tokens = ( + input_tokens + output_tokens + cache_creation_tokens + cache_read_tokens + ) # Get cost per token - input_cost_per_token, output_cost_per_token, cache_read_cost_per_token = get_cost_per_token( - model_id + input_cost_per_token, output_cost_per_token, cache_read_cost_per_token = ( + get_cost_per_token(model_id) ) # Calculate cache creation cost per token @@ -190,7 +207,12 @@ def track_usage( model_id_lower = model_id.lower() if any( x in model_id_lower - for x in ["claude-3-5-sonnet", "claude-3-7-sonnet", "claude-sonnet-4", "claude-4-sonnet"] + for x in [ + "claude-3-5-sonnet", + "claude-3-7-sonnet", + "claude-sonnet-4", + "claude-4-sonnet", + ] ): # Sonnet models: cache creation is 25% higher than input rate (0.00375 vs 0.003) cache_creation_cost_per_token = input_cost_per_token * 1.25 @@ -277,8 +299,10 @@ def get_usage_data() -> dict: with _usage_lock: # Deep copy the nested defaultdict structure to regular dicts per_file_data = { - filename: {model_id: dict(usage_info) for model_id, usage_info in models.items()} - for filename, models in USAGE_DATA.items() + filename: { + model_id: dict(usage_info) for model_id, usage_info in models.items() + } + for filename, models in USAGE_DATA.items() } return { "per_file_per_model": per_file_data, @@ -290,15 +314,19 @@ def reset_usage_data() -> None: """Reset all usage tracking data. Useful for testing.""" global USAGE_DATA, GLOBAL_USAGE with _usage_lock: - USAGE_DATA = defaultdict(lambda: defaultdict(lambda: { - "input_tokens": 0, - "output_tokens": 0, - "cache_creation_tokens": 0, - "cache_read_tokens": 0, - "total_tokens": 0, - "total_cost": 0.0, - "request_count": 0, - })) + USAGE_DATA = defaultdict( + lambda: defaultdict( + lambda: { + "input_tokens": 0, + "output_tokens": 0, + "cache_creation_tokens": 0, + "cache_read_tokens": 0, + "total_tokens": 0, + "total_cost": 0.0, + "request_count": 0, + } + ) + ) GLOBAL_USAGE = { "total_input_tokens": 0, "total_output_tokens": 0, @@ -310,7 +338,9 @@ def reset_usage_data() -> None: } -def get_usage_dataframes(run_id: str, timestamp: str) -> tuple[pd.DataFrame, pd.DataFrame]: +def get_usage_dataframes( + run_id: str, timestamp: str +) -> tuple[pd.DataFrame, pd.DataFrame]: """Get usage and cost DataFrames ready for export. Returns the formatted DataFrames that can be passed to S3 upload functions @@ -372,19 +402,21 @@ def _generate_per_file_per_model_df(run_id: str, timestamp: str) -> pd.DataFrame # Calculate average cost per token (for this file/model combination) cost_per_token = total_cost / total_tokens if total_tokens > 0 else 0.0 - rows.append({ - "run_id": run_id, - "timestamp": timestamp, - "file_name": filename, - "model_name": model_name, - "input_tokens": input_tokens, - "output_tokens": output_tokens, - "cache_creation_tokens": cache_creation_tokens, - "cache_read_tokens": cache_read_tokens, - "total_tokens": total_tokens, - "cost_per_token": round(cost_per_token, 8), - "total_cost": round(total_cost, 6), - }) + rows.append( + { + "run_id": run_id, + "timestamp": timestamp, + "file_name": filename, + "model_name": model_name, + "input_tokens": input_tokens, + "output_tokens": output_tokens, + "cache_creation_tokens": cache_creation_tokens, + "cache_read_tokens": cache_read_tokens, + "total_tokens": total_tokens, + "cost_per_token": round(cost_per_token, 8), + "total_cost": round(total_cost, 6), + } + ) return pd.DataFrame(rows) @@ -419,21 +451,11 @@ def _generate_batch_summary_df(run_id: str, timestamp: str) -> pd.DataFrame: average_fresh_input_tokens = ( fresh_input_tokens / total_files if total_files > 0 else 0 ) - average_cache_tokens = ( - cache_tokens / total_files if total_files > 0 else 0 - ) - average_input_tokens = ( - total_input_tokens / total_files if total_files > 0 else 0 - ) - average_output_tokens = ( - total_output_tokens / total_files if total_files > 0 else 0 - ) - average_total_tokens = ( - total_tokens / total_files if total_files > 0 else 0 - ) - average_cost = ( - total_cost / total_files if total_files > 0 else 0 - ) + average_cache_tokens = cache_tokens / total_files if total_files > 0 else 0 + average_input_tokens = total_input_tokens / total_files if total_files > 0 else 0 + average_output_tokens = total_output_tokens / total_files if total_files > 0 else 0 + average_total_tokens = total_tokens / total_files if total_files > 0 else 0 + average_cost = total_cost / total_files if total_files > 0 else 0 # Determine region mode region_mode = "cross-region" if config.ENABLE_RUNTIME_ROTATION else "single-region" @@ -497,4 +519,3 @@ def export_usage_cost_csvs_local(run_id: str, run_timestamp: str) -> None: logging.info(f"Saved usage summary to: {summary_path}") else: logging.warning("No summary data to export (summary CSV empty)") - diff --git a/textract-pipeline/src/lambda/tiff-to-pdf/.python-version b/textract-pipeline/src/lambda/tiff-to-pdf/.python-version deleted file mode 100644 index 56bb660..0000000 --- a/textract-pipeline/src/lambda/tiff-to-pdf/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.12.7 diff --git a/textract-pipeline/src/lambda/trigger-pipeline/.python-version b/textract-pipeline/src/lambda/trigger-pipeline/.python-version deleted file mode 100644 index 56bb660..0000000 --- a/textract-pipeline/src/lambda/trigger-pipeline/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.12.7 diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..4f40448 --- /dev/null +++ b/uv.lock @@ -0,0 +1,4253 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" +resolution-markers = [ + "python_full_version >= '3.14'", + "python_full_version == '3.13.*'", + "python_full_version < '3.13'", +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/be/4fc11f202955a69e0db803a12a062b8379c970c7c84f4882b6da17337cc1/aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c", size = 739732, upload-time = "2026-01-03T17:30:14.23Z" }, + { url = "https://files.pythonhosted.org/packages/97/2c/621d5b851f94fa0bb7430d6089b3aa970a9d9b75196bc93bb624b0db237a/aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168", size = 494293, upload-time = "2026-01-03T17:30:15.96Z" }, + { url = "https://files.pythonhosted.org/packages/5d/43/4be01406b78e1be8320bb8316dc9c42dbab553d281c40364e0f862d5661c/aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d", size = 493533, upload-time = "2026-01-03T17:30:17.431Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a8/5a35dc56a06a2c90d4742cbf35294396907027f80eea696637945a106f25/aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29", size = 1737839, upload-time = "2026-01-03T17:30:19.422Z" }, + { url = "https://files.pythonhosted.org/packages/bf/62/4b9eeb331da56530bf2e198a297e5303e1c1ebdceeb00fe9b568a65c5a0c/aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3", size = 1703932, upload-time = "2026-01-03T17:30:21.756Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f6/af16887b5d419e6a367095994c0b1332d154f647e7dc2bd50e61876e8e3d/aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d", size = 1771906, upload-time = "2026-01-03T17:30:23.932Z" }, + { url = "https://files.pythonhosted.org/packages/ce/83/397c634b1bcc24292fa1e0c7822800f9f6569e32934bdeef09dae7992dfb/aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463", size = 1871020, upload-time = "2026-01-03T17:30:26Z" }, + { url = "https://files.pythonhosted.org/packages/86/f6/a62cbbf13f0ac80a70f71b1672feba90fdb21fd7abd8dbf25c0105fb6fa3/aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc", size = 1755181, upload-time = "2026-01-03T17:30:27.554Z" }, + { url = "https://files.pythonhosted.org/packages/0a/87/20a35ad487efdd3fba93d5843efdfaa62d2f1479eaafa7453398a44faf13/aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf", size = 1561794, upload-time = "2026-01-03T17:30:29.254Z" }, + { url = "https://files.pythonhosted.org/packages/de/95/8fd69a66682012f6716e1bc09ef8a1a2a91922c5725cb904689f112309c4/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033", size = 1697900, upload-time = "2026-01-03T17:30:31.033Z" }, + { url = "https://files.pythonhosted.org/packages/e5/66/7b94b3b5ba70e955ff597672dad1691333080e37f50280178967aff68657/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f", size = 1728239, upload-time = "2026-01-03T17:30:32.703Z" }, + { url = "https://files.pythonhosted.org/packages/47/71/6f72f77f9f7d74719692ab65a2a0252584bf8d5f301e2ecb4c0da734530a/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679", size = 1740527, upload-time = "2026-01-03T17:30:34.695Z" }, + { url = "https://files.pythonhosted.org/packages/fa/b4/75ec16cbbd5c01bdaf4a05b19e103e78d7ce1ef7c80867eb0ace42ff4488/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423", size = 1554489, upload-time = "2026-01-03T17:30:36.864Z" }, + { url = "https://files.pythonhosted.org/packages/52/8f/bc518c0eea29f8406dcf7ed1f96c9b48e3bc3995a96159b3fc11f9e08321/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce", size = 1767852, upload-time = "2026-01-03T17:30:39.433Z" }, + { url = "https://files.pythonhosted.org/packages/9d/f2/a07a75173124f31f11ea6f863dc44e6f09afe2bca45dd4e64979490deab1/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a", size = 1722379, upload-time = "2026-01-03T17:30:41.081Z" }, + { url = "https://files.pythonhosted.org/packages/3c/4a/1a3fee7c21350cac78e5c5cef711bac1b94feca07399f3d406972e2d8fcd/aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046", size = 428253, upload-time = "2026-01-03T17:30:42.644Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b7/76175c7cb4eb73d91ad63c34e29fc4f77c9386bba4a65b53ba8e05ee3c39/aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57", size = 455407, upload-time = "2026-01-03T17:30:44.195Z" }, + { url = "https://files.pythonhosted.org/packages/97/8a/12ca489246ca1faaf5432844adbfce7ff2cc4997733e0af120869345643a/aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c", size = 734190, upload-time = "2026-01-03T17:30:45.832Z" }, + { url = "https://files.pythonhosted.org/packages/32/08/de43984c74ed1fca5c014808963cc83cb00d7bb06af228f132d33862ca76/aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9", size = 491783, upload-time = "2026-01-03T17:30:47.466Z" }, + { url = "https://files.pythonhosted.org/packages/17/f8/8dd2cf6112a5a76f81f81a5130c57ca829d101ad583ce57f889179accdda/aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3", size = 490704, upload-time = "2026-01-03T17:30:49.373Z" }, + { url = "https://files.pythonhosted.org/packages/6d/40/a46b03ca03936f832bc7eaa47cfbb1ad012ba1be4790122ee4f4f8cba074/aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf", size = 1720652, upload-time = "2026-01-03T17:30:50.974Z" }, + { url = "https://files.pythonhosted.org/packages/f7/7e/917fe18e3607af92657e4285498f500dca797ff8c918bd7d90b05abf6c2a/aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6", size = 1692014, upload-time = "2026-01-03T17:30:52.729Z" }, + { url = "https://files.pythonhosted.org/packages/71/b6/cefa4cbc00d315d68973b671cf105b21a609c12b82d52e5d0c9ae61d2a09/aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d", size = 1759777, upload-time = "2026-01-03T17:30:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e3/e06ee07b45e59e6d81498b591fc589629be1553abb2a82ce33efe2a7b068/aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261", size = 1861276, upload-time = "2026-01-03T17:30:56.512Z" }, + { url = "https://files.pythonhosted.org/packages/7c/24/75d274228acf35ceeb2850b8ce04de9dd7355ff7a0b49d607ee60c29c518/aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0", size = 1743131, upload-time = "2026-01-03T17:30:58.256Z" }, + { url = "https://files.pythonhosted.org/packages/04/98/3d21dde21889b17ca2eea54fdcff21b27b93f45b7bb94ca029c31ab59dc3/aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730", size = 1556863, upload-time = "2026-01-03T17:31:00.445Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/da0c3ab1192eaf64782b03971ab4055b475d0db07b17eff925e8c93b3aa5/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91", size = 1682793, upload-time = "2026-01-03T17:31:03.024Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0f/5802ada182f575afa02cbd0ec5180d7e13a402afb7c2c03a9aa5e5d49060/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3", size = 1716676, upload-time = "2026-01-03T17:31:04.842Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8c/714d53bd8b5a4560667f7bbbb06b20c2382f9c7847d198370ec6526af39c/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4", size = 1733217, upload-time = "2026-01-03T17:31:06.868Z" }, + { url = "https://files.pythonhosted.org/packages/7d/79/e2176f46d2e963facea939f5be2d26368ce543622be6f00a12844d3c991f/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998", size = 1552303, upload-time = "2026-01-03T17:31:08.958Z" }, + { url = "https://files.pythonhosted.org/packages/ab/6a/28ed4dea1759916090587d1fe57087b03e6c784a642b85ef48217b0277ae/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0", size = 1763673, upload-time = "2026-01-03T17:31:10.676Z" }, + { url = "https://files.pythonhosted.org/packages/e8/35/4a3daeb8b9fab49240d21c04d50732313295e4bd813a465d840236dd0ce1/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591", size = 1721120, upload-time = "2026-01-03T17:31:12.575Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9f/d643bb3c5fb99547323e635e251c609fbbc660d983144cfebec529e09264/aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf", size = 427383, upload-time = "2026-01-03T17:31:14.382Z" }, + { url = "https://files.pythonhosted.org/packages/4e/f1/ab0395f8a79933577cdd996dd2f9aa6014af9535f65dddcf88204682fe62/aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e", size = 453899, upload-time = "2026-01-03T17:31:15.958Z" }, + { url = "https://files.pythonhosted.org/packages/99/36/5b6514a9f5d66f4e2597e40dea2e3db271e023eb7a5d22defe96ba560996/aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808", size = 737238, upload-time = "2026-01-03T17:31:17.909Z" }, + { url = "https://files.pythonhosted.org/packages/f7/49/459327f0d5bcd8c6c9ca69e60fdeebc3622861e696490d8674a6d0cb90a6/aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415", size = 492292, upload-time = "2026-01-03T17:31:19.919Z" }, + { url = "https://files.pythonhosted.org/packages/e8/0b/b97660c5fd05d3495b4eb27f2d0ef18dc1dc4eff7511a9bf371397ff0264/aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f", size = 493021, upload-time = "2026-01-03T17:31:21.636Z" }, + { url = "https://files.pythonhosted.org/packages/54/d4/438efabdf74e30aeceb890c3290bbaa449780583b1270b00661126b8aae4/aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6", size = 1717263, upload-time = "2026-01-03T17:31:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/71/f2/7bddc7fd612367d1459c5bcf598a9e8f7092d6580d98de0e057eb42697ad/aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687", size = 1669107, upload-time = "2026-01-03T17:31:25.334Z" }, + { url = "https://files.pythonhosted.org/packages/00/5a/1aeaecca40e22560f97610a329e0e5efef5e0b5afdf9f857f0d93839ab2e/aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26", size = 1760196, upload-time = "2026-01-03T17:31:27.394Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f8/0ff6992bea7bd560fc510ea1c815f87eedd745fe035589c71ce05612a19a/aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a", size = 1843591, upload-time = "2026-01-03T17:31:29.238Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d1/e30e537a15f53485b61f5be525f2157da719819e8377298502aebac45536/aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1", size = 1720277, upload-time = "2026-01-03T17:31:31.053Z" }, + { url = "https://files.pythonhosted.org/packages/84/45/23f4c451d8192f553d38d838831ebbc156907ea6e05557f39563101b7717/aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25", size = 1548575, upload-time = "2026-01-03T17:31:32.87Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ed/0a42b127a43712eda7807e7892c083eadfaf8429ca8fb619662a530a3aab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603", size = 1679455, upload-time = "2026-01-03T17:31:34.76Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b5/c05f0c2b4b4fe2c9d55e73b6d3ed4fd6c9dc2684b1d81cbdf77e7fad9adb/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a", size = 1687417, upload-time = "2026-01-03T17:31:36.699Z" }, + { url = "https://files.pythonhosted.org/packages/c9/6b/915bc5dad66aef602b9e459b5a973529304d4e89ca86999d9d75d80cbd0b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926", size = 1729968, upload-time = "2026-01-03T17:31:38.622Z" }, + { url = "https://files.pythonhosted.org/packages/11/3b/e84581290a9520024a08640b63d07673057aec5ca548177a82026187ba73/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba", size = 1545690, upload-time = "2026-01-03T17:31:40.57Z" }, + { url = "https://files.pythonhosted.org/packages/f5/04/0c3655a566c43fd647c81b895dfe361b9f9ad6d58c19309d45cff52d6c3b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c", size = 1746390, upload-time = "2026-01-03T17:31:42.857Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/71165b26978f719c3419381514c9690bd5980e764a09440a10bb816ea4ab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43", size = 1702188, upload-time = "2026-01-03T17:31:44.984Z" }, + { url = "https://files.pythonhosted.org/packages/29/a7/cbe6c9e8e136314fa1980da388a59d2f35f35395948a08b6747baebb6aa6/aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1", size = 433126, upload-time = "2026-01-03T17:31:47.463Z" }, + { url = "https://files.pythonhosted.org/packages/de/56/982704adea7d3b16614fc5936014e9af85c0e34b58f9046655817f04306e/aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984", size = 459128, upload-time = "2026-01-03T17:31:49.2Z" }, + { url = "https://files.pythonhosted.org/packages/6c/2a/3c79b638a9c3d4658d345339d22070241ea341ed4e07b5ac60fb0f418003/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c", size = 769512, upload-time = "2026-01-03T17:31:51.134Z" }, + { url = "https://files.pythonhosted.org/packages/29/b9/3e5014d46c0ab0db8707e0ac2711ed28c4da0218c358a4e7c17bae0d8722/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592", size = 506444, upload-time = "2026-01-03T17:31:52.85Z" }, + { url = "https://files.pythonhosted.org/packages/90/03/c1d4ef9a054e151cd7839cdc497f2638f00b93cbe8043983986630d7a80c/aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f", size = 510798, upload-time = "2026-01-03T17:31:54.91Z" }, + { url = "https://files.pythonhosted.org/packages/ea/76/8c1e5abbfe8e127c893fe7ead569148a4d5a799f7cf958d8c09f3eedf097/aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29", size = 1868835, upload-time = "2026-01-03T17:31:56.733Z" }, + { url = "https://files.pythonhosted.org/packages/8e/ac/984c5a6f74c363b01ff97adc96a3976d9c98940b8969a1881575b279ac5d/aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc", size = 1720486, upload-time = "2026-01-03T17:31:58.65Z" }, + { url = "https://files.pythonhosted.org/packages/b2/9a/b7039c5f099c4eb632138728828b33428585031a1e658d693d41d07d89d1/aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2", size = 1847951, upload-time = "2026-01-03T17:32:00.989Z" }, + { url = "https://files.pythonhosted.org/packages/3c/02/3bec2b9a1ba3c19ff89a43a19324202b8eb187ca1e928d8bdac9bbdddebd/aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587", size = 1941001, upload-time = "2026-01-03T17:32:03.122Z" }, + { url = "https://files.pythonhosted.org/packages/37/df/d879401cedeef27ac4717f6426c8c36c3091c6e9f08a9178cc87549c537f/aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8", size = 1797246, upload-time = "2026-01-03T17:32:05.255Z" }, + { url = "https://files.pythonhosted.org/packages/8d/15/be122de1f67e6953add23335c8ece6d314ab67c8bebb3f181063010795a7/aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632", size = 1627131, upload-time = "2026-01-03T17:32:07.607Z" }, + { url = "https://files.pythonhosted.org/packages/12/12/70eedcac9134cfa3219ab7af31ea56bc877395b1ac30d65b1bc4b27d0438/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64", size = 1795196, upload-time = "2026-01-03T17:32:09.59Z" }, + { url = "https://files.pythonhosted.org/packages/32/11/b30e1b1cd1f3054af86ebe60df96989c6a414dd87e27ad16950eee420bea/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0", size = 1782841, upload-time = "2026-01-03T17:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/88/0d/d98a9367b38912384a17e287850f5695c528cff0f14f791ce8ee2e4f7796/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56", size = 1795193, upload-time = "2026-01-03T17:32:13.705Z" }, + { url = "https://files.pythonhosted.org/packages/43/a5/a2dfd1f5ff5581632c7f6a30e1744deda03808974f94f6534241ef60c751/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72", size = 1621979, upload-time = "2026-01-03T17:32:15.965Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f0/12973c382ae7c1cccbc4417e129c5bf54c374dfb85af70893646e1f0e749/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df", size = 1822193, upload-time = "2026-01-03T17:32:18.219Z" }, + { url = "https://files.pythonhosted.org/packages/3c/5f/24155e30ba7f8c96918af1350eb0663e2430aad9e001c0489d89cd708ab1/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa", size = 1769801, upload-time = "2026-01-03T17:32:20.25Z" }, + { url = "https://files.pythonhosted.org/packages/eb/f8/7314031ff5c10e6ece114da79b338ec17eeff3a079e53151f7e9f43c4723/aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767", size = 466523, upload-time = "2026-01-03T17:32:22.215Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/278a98c715ae467624eafe375542d8ba9b4383a016df8fdefe0ae28382a7/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344", size = 499694, upload-time = "2026-01-03T17:32:24.546Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anthropic" +version = "0.75.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "docstring-parser" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/1f/08e95f4b7e2d35205ae5dcbb4ae97e7d477fc521c275c02609e2931ece2d/anthropic-0.75.0.tar.gz", hash = "sha256:e8607422f4ab616db2ea5baacc215dd5f028da99ce2f022e33c7c535b29f3dfb", size = 439565, upload-time = "2025-11-24T20:41:45.28Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/1c/1cd02b7ae64302a6e06724bf80a96401d5313708651d277b1458504a1730/anthropic-0.75.0-py3-none-any.whl", hash = "sha256:ea8317271b6c15d80225a9f3c670152746e88805a7a61e14d4a374577164965b", size = 388164, upload-time = "2025-11-24T20:41:43.587Z" }, +] + +[[package]] +name = "anyio" +version = "4.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, +] + +[[package]] +name = "appnope" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, +] + +[[package]] +name = "argon2-cffi" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argon2-cffi-bindings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, +] + +[[package]] +name = "argon2-cffi-bindings" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441, upload-time = "2025-07-30T10:02:05.147Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/97/3c0a35f46e52108d4707c44b95cfe2afcafc50800b5450c197454569b776/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:3d3f05610594151994ca9ccb3c771115bdb4daef161976a266f0dd8aa9996b8f", size = 54393, upload-time = "2025-07-30T10:01:40.97Z" }, + { url = "https://files.pythonhosted.org/packages/9d/f4/98bbd6ee89febd4f212696f13c03ca302b8552e7dbf9c8efa11ea4a388c3/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8b8efee945193e667a396cbc7b4fb7d357297d6234d30a489905d96caabde56b", size = 29328, upload-time = "2025-07-30T10:01:41.916Z" }, + { url = "https://files.pythonhosted.org/packages/43/24/90a01c0ef12ac91a6be05969f29944643bc1e5e461155ae6559befa8f00b/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3c6702abc36bf3ccba3f802b799505def420a1b7039862014a65db3205967f5a", size = 31269, upload-time = "2025-07-30T10:01:42.716Z" }, + { url = "https://files.pythonhosted.org/packages/d4/d3/942aa10782b2697eee7af5e12eeff5ebb325ccfb86dd8abda54174e377e4/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1c70058c6ab1e352304ac7e3b52554daadacd8d453c1752e547c76e9c99ac44", size = 86558, upload-time = "2025-07-30T10:01:43.943Z" }, + { url = "https://files.pythonhosted.org/packages/0d/82/b484f702fec5536e71836fc2dbc8c5267b3f6e78d2d539b4eaa6f0db8bf8/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2fd3bfbff3c5d74fef31a722f729bf93500910db650c925c2d6ef879a7e51cb", size = 92364, upload-time = "2025-07-30T10:01:44.887Z" }, + { url = "https://files.pythonhosted.org/packages/c9/c1/a606ff83b3f1735f3759ad0f2cd9e038a0ad11a3de3b6c673aa41c24bb7b/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4f9665de60b1b0e99bcd6be4f17d90339698ce954cfd8d9cf4f91c995165a92", size = 85637, upload-time = "2025-07-30T10:01:46.225Z" }, + { url = "https://files.pythonhosted.org/packages/44/b4/678503f12aceb0262f84fa201f6027ed77d71c5019ae03b399b97caa2f19/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ba92837e4a9aa6a508c8d2d7883ed5a8f6c308c89a4790e1e447a220deb79a85", size = 91934, upload-time = "2025-07-30T10:01:47.203Z" }, + { url = "https://files.pythonhosted.org/packages/f0/c7/f36bd08ef9bd9f0a9cff9428406651f5937ce27b6c5b07b92d41f91ae541/argon2_cffi_bindings-25.1.0-cp314-cp314t-win32.whl", hash = "sha256:84a461d4d84ae1295871329b346a97f68eade8c53b6ed9a7ca2d7467f3c8ff6f", size = 28158, upload-time = "2025-07-30T10:01:48.341Z" }, + { url = "https://files.pythonhosted.org/packages/b3/80/0106a7448abb24a2c467bf7d527fe5413b7fdfa4ad6d6a96a43a62ef3988/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b55aec3565b65f56455eebc9b9f34130440404f27fe21c3b375bf1ea4d8fbae6", size = 32597, upload-time = "2025-07-30T10:01:49.112Z" }, + { url = "https://files.pythonhosted.org/packages/05/b8/d663c9caea07e9180b2cb662772865230715cbd573ba3b5e81793d580316/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:87c33a52407e4c41f3b70a9c2d3f6056d88b10dad7695be708c5021673f55623", size = 28231, upload-time = "2025-07-30T10:01:49.92Z" }, + { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121, upload-time = "2025-07-30T10:01:50.815Z" }, + { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177, upload-time = "2025-07-30T10:01:51.681Z" }, + { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090, upload-time = "2025-07-30T10:01:53.184Z" }, + { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246, upload-time = "2025-07-30T10:01:54.145Z" }, + { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126, upload-time = "2025-07-30T10:01:55.074Z" }, + { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343, upload-time = "2025-07-30T10:01:56.007Z" }, + { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777, upload-time = "2025-07-30T10:01:56.943Z" }, + { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180, upload-time = "2025-07-30T10:01:57.759Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715, upload-time = "2025-07-30T10:01:58.56Z" }, + { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, +] + +[[package]] +name = "arrow" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, +] + +[[package]] +name = "async-lru" +version = "2.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380, upload-time = "2025-03-16T17:25:36.919Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069, upload-time = "2025-03-16T17:25:35.422Z" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, +] + +[[package]] +name = "black" +version = "25.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "pytokens" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/d9/07b458a3f1c525ac392b5edc6b191ff140b596f9d77092429417a54e249d/black-25.12.0.tar.gz", hash = "sha256:8d3dd9cea14bff7ddc0eb243c811cdb1a011ebb4800a5f0335a01a68654796a7", size = 659264, upload-time = "2025-12-08T01:40:52.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/bd/26083f805115db17fda9877b3c7321d08c647df39d0df4c4ca8f8450593e/black-25.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:31f96b7c98c1ddaeb07dc0f56c652e25bdedaac76d5b68a059d998b57c55594a", size = 1924178, upload-time = "2025-12-08T01:49:51.048Z" }, + { url = "https://files.pythonhosted.org/packages/89/6b/ea00d6651561e2bdd9231c4177f4f2ae19cc13a0b0574f47602a7519b6ca/black-25.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05dd459a19e218078a1f98178c13f861fe6a9a5f88fc969ca4d9b49eb1809783", size = 1742643, upload-time = "2025-12-08T01:49:59.09Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f3/360fa4182e36e9875fabcf3a9717db9d27a8d11870f21cff97725c54f35b/black-25.12.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1f68c5eff61f226934be6b5b80296cf6939e5d2f0c2f7d543ea08b204bfaf59", size = 1800158, upload-time = "2025-12-08T01:44:27.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/08/2c64830cb6616278067e040acca21d4f79727b23077633953081c9445d61/black-25.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:274f940c147ddab4442d316b27f9e332ca586d39c85ecf59ebdea82cc9ee8892", size = 1426197, upload-time = "2025-12-08T01:45:51.198Z" }, + { url = "https://files.pythonhosted.org/packages/d4/60/a93f55fd9b9816b7432cf6842f0e3000fdd5b7869492a04b9011a133ee37/black-25.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:169506ba91ef21e2e0591563deda7f00030cb466e747c4b09cb0a9dae5db2f43", size = 1237266, upload-time = "2025-12-08T01:45:10.556Z" }, + { url = "https://files.pythonhosted.org/packages/c8/52/c551e36bc95495d2aa1a37d50566267aa47608c81a53f91daa809e03293f/black-25.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a05ddeb656534c3e27a05a29196c962877c83fa5503db89e68857d1161ad08a5", size = 1923809, upload-time = "2025-12-08T01:46:55.126Z" }, + { url = "https://files.pythonhosted.org/packages/a0/f7/aac9b014140ee56d247e707af8db0aae2e9efc28d4a8aba92d0abd7ae9d1/black-25.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9ec77439ef3e34896995503865a85732c94396edcc739f302c5673a2315e1e7f", size = 1742384, upload-time = "2025-12-08T01:49:37.022Z" }, + { url = "https://files.pythonhosted.org/packages/74/98/38aaa018b2ab06a863974c12b14a6266badc192b20603a81b738c47e902e/black-25.12.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e509c858adf63aa61d908061b52e580c40eae0dfa72415fa47ac01b12e29baf", size = 1798761, upload-time = "2025-12-08T01:46:05.386Z" }, + { url = "https://files.pythonhosted.org/packages/16/3a/a8ac542125f61574a3f015b521ca83b47321ed19bb63fe6d7560f348bfe1/black-25.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:252678f07f5bac4ff0d0e9b261fbb029fa530cfa206d0a636a34ab445ef8ca9d", size = 1429180, upload-time = "2025-12-08T01:45:34.903Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2d/bdc466a3db9145e946762d52cd55b1385509d9f9004fec1c97bdc8debbfb/black-25.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bc5b1c09fe3c931ddd20ee548511c64ebf964ada7e6f0763d443947fd1c603ce", size = 1239350, upload-time = "2025-12-08T01:46:09.458Z" }, + { url = "https://files.pythonhosted.org/packages/35/46/1d8f2542210c502e2ae1060b2e09e47af6a5e5963cb78e22ec1a11170b28/black-25.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:0a0953b134f9335c2434864a643c842c44fba562155c738a2a37a4d61f00cad5", size = 1917015, upload-time = "2025-12-08T01:53:27.987Z" }, + { url = "https://files.pythonhosted.org/packages/41/37/68accadf977672beb8e2c64e080f568c74159c1aaa6414b4cd2aef2d7906/black-25.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2355bbb6c3b76062870942d8cc450d4f8ac71f9c93c40122762c8784df49543f", size = 1741830, upload-time = "2025-12-08T01:54:36.861Z" }, + { url = "https://files.pythonhosted.org/packages/ac/76/03608a9d8f0faad47a3af3a3c8c53af3367f6c0dd2d23a84710456c7ac56/black-25.12.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9678bd991cc793e81d19aeeae57966ee02909877cb65838ccffef24c3ebac08f", size = 1791450, upload-time = "2025-12-08T01:44:52.581Z" }, + { url = "https://files.pythonhosted.org/packages/06/99/b2a4bd7dfaea7964974f947e1c76d6886d65fe5d24f687df2d85406b2609/black-25.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:97596189949a8aad13ad12fcbb4ae89330039b96ad6742e6f6b45e75ad5cfd83", size = 1452042, upload-time = "2025-12-08T01:46:13.188Z" }, + { url = "https://files.pythonhosted.org/packages/b2/7c/d9825de75ae5dd7795d007681b752275ea85a1c5d83269b4b9c754c2aaab/black-25.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:778285d9ea197f34704e3791ea9404cd6d07595745907dd2ce3da7a13627b29b", size = 1267446, upload-time = "2025-12-08T01:46:14.497Z" }, + { url = "https://files.pythonhosted.org/packages/68/11/21331aed19145a952ad28fca2756a1433ee9308079bd03bd898e903a2e53/black-25.12.0-py3-none-any.whl", hash = "sha256:48ceb36c16dbc84062740049eef990bb2ce07598272e673c17d1a7720c71c828", size = 206191, upload-time = "2025-12-08T01:40:50.963Z" }, +] + +[[package]] +name = "bleach" +version = "6.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533, upload-time = "2025-10-27T17:57:39.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437, upload-time = "2025-10-27T17:57:37.538Z" }, +] + +[package.optional-dependencies] +css = [ + { name = "tinycss2" }, +] + +[[package]] +name = "boto3" +version = "1.42.24" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "jmespath" }, + { name = "s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ee/21/8be0e3685c3a4868be48d8d2f6e5b4641727e1d8a5d396b8b401d2b5f06e/boto3-1.42.24.tar.gz", hash = "sha256:c47a2f40df933e3861fc66fd8d6b87ee36d4361663a7e7ba39a87f5a78b2eae1", size = 112788, upload-time = "2026-01-07T20:30:51.019Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/75/bbfccb268f9faa4f59030888e859dca9797a980b77d6a074113af73bd4bf/boto3-1.42.24-py3-none-any.whl", hash = "sha256:8ed6ad670a5a2d7f66c1b0d3362791b48392c7a08f78479f5d8ab319a4d9118f", size = 140572, upload-time = "2026-01-07T20:30:49.431Z" }, +] + +[[package]] +name = "botocore" +version = "1.42.24" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/12/d7/bb4a4e839b238ffb67b002d7326b328ebe5eb23ed5180f2ca10399a802de/botocore-1.42.24.tar.gz", hash = "sha256:be8d1bea64fb91eea08254a1e5fea057e4428d08e61f4e11083a02cafc1f8cc6", size = 14878455, upload-time = "2026-01-07T20:30:40.379Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/d4/f2655d777eed8b069ecab3761454cb83f830f8be8b5b0d292e4b3a980d00/botocore-1.42.24-py3-none-any.whl", hash = "sha256:8fca9781d7c84f7ad070fceffaff7179c4aa7a5ffb27b43df9d1d957801e0a8d", size = 14551806, upload-time = "2026-01-07T20:30:38.103Z" }, +] + +[[package]] +name = "certifi" +version = "2026.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "comm" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, +] + +[[package]] +name = "coverage" +version = "7.13.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/f9/e92df5e07f3fc8d4c7f9a0f146ef75446bf870351cd37b788cf5897f8079/coverage-7.13.1.tar.gz", hash = "sha256:b7593fe7eb5feaa3fbb461ac79aac9f9fc0387a5ca8080b0c6fe2ca27b091afd", size = 825862, upload-time = "2025-12-28T15:42:56.969Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/8a/87af46cccdfa78f53db747b09f5f9a21d5fc38d796834adac09b30a8ce74/coverage-7.13.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6f34591000f06e62085b1865c9bc5f7858df748834662a51edadfd2c3bfe0dd3", size = 218927, upload-time = "2025-12-28T15:40:52.814Z" }, + { url = "https://files.pythonhosted.org/packages/82/a8/6e22fdc67242a4a5a153f9438d05944553121c8f4ba70cb072af4c41362e/coverage-7.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b67e47c5595b9224599016e333f5ec25392597a89d5744658f837d204e16c63e", size = 219288, upload-time = "2025-12-28T15:40:54.262Z" }, + { url = "https://files.pythonhosted.org/packages/d0/0a/853a76e03b0f7c4375e2ca025df45c918beb367f3e20a0a8e91967f6e96c/coverage-7.13.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e7b8bd70c48ffb28461ebe092c2345536fb18bbbf19d287c8913699735f505c", size = 250786, upload-time = "2025-12-28T15:40:56.059Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b4/694159c15c52b9f7ec7adf49d50e5f8ee71d3e9ef38adb4445d13dd56c20/coverage-7.13.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c223d078112e90dc0e5c4e35b98b9584164bea9fbbd221c0b21c5241f6d51b62", size = 253543, upload-time = "2025-12-28T15:40:57.585Z" }, + { url = "https://files.pythonhosted.org/packages/96/b2/7f1f0437a5c855f87e17cf5d0dc35920b6440ff2b58b1ba9788c059c26c8/coverage-7.13.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:794f7c05af0763b1bbd1b9e6eff0e52ad068be3b12cd96c87de037b01390c968", size = 254635, upload-time = "2025-12-28T15:40:59.443Z" }, + { url = "https://files.pythonhosted.org/packages/e9/d1/73c3fdb8d7d3bddd9473c9c6a2e0682f09fc3dfbcb9c3f36412a7368bcab/coverage-7.13.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0642eae483cc8c2902e4af7298bf886d605e80f26382124cddc3967c2a3df09e", size = 251202, upload-time = "2025-12-28T15:41:01.328Z" }, + { url = "https://files.pythonhosted.org/packages/66/3c/f0edf75dcc152f145d5598329e864bbbe04ab78660fe3e8e395f9fff010f/coverage-7.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f5e772ed5fef25b3de9f2008fe67b92d46831bd2bc5bdc5dd6bfd06b83b316f", size = 252566, upload-time = "2025-12-28T15:41:03.319Z" }, + { url = "https://files.pythonhosted.org/packages/17/b3/e64206d3c5f7dcbceafd14941345a754d3dbc78a823a6ed526e23b9cdaab/coverage-7.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:45980ea19277dc0a579e432aef6a504fe098ef3a9032ead15e446eb0f1191aee", size = 250711, upload-time = "2025-12-28T15:41:06.411Z" }, + { url = "https://files.pythonhosted.org/packages/dc/ad/28a3eb970a8ef5b479ee7f0c484a19c34e277479a5b70269dc652b730733/coverage-7.13.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f18eca6028ffa62adbd185a8f1e1dd242f2e68164dba5c2b74a5204850b4cf", size = 250278, upload-time = "2025-12-28T15:41:08.285Z" }, + { url = "https://files.pythonhosted.org/packages/54/e3/c8f0f1a93133e3e1291ca76cbb63565bd4b5c5df63b141f539d747fff348/coverage-7.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8dca5590fec7a89ed6826fce625595279e586ead52e9e958d3237821fbc750c", size = 252154, upload-time = "2025-12-28T15:41:09.969Z" }, + { url = "https://files.pythonhosted.org/packages/d0/bf/9939c5d6859c380e405b19e736321f1c7d402728792f4c752ad1adcce005/coverage-7.13.1-cp312-cp312-win32.whl", hash = "sha256:ff86d4e85188bba72cfb876df3e11fa243439882c55957184af44a35bd5880b7", size = 221487, upload-time = "2025-12-28T15:41:11.468Z" }, + { url = "https://files.pythonhosted.org/packages/fa/dc/7282856a407c621c2aad74021680a01b23010bb8ebf427cf5eacda2e876f/coverage-7.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:16cc1da46c04fb0fb128b4dc430b78fa2aba8a6c0c9f8eb391fd5103409a6ac6", size = 222299, upload-time = "2025-12-28T15:41:13.386Z" }, + { url = "https://files.pythonhosted.org/packages/10/79/176a11203412c350b3e9578620013af35bcdb79b651eb976f4a4b32044fa/coverage-7.13.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d9bc218650022a768f3775dd7fdac1886437325d8d295d923ebcfef4892ad5c", size = 220941, upload-time = "2025-12-28T15:41:14.975Z" }, + { url = "https://files.pythonhosted.org/packages/a3/a4/e98e689347a1ff1a7f67932ab535cef82eb5e78f32a9e4132e114bbb3a0a/coverage-7.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cb237bfd0ef4d5eb6a19e29f9e528ac67ac3be932ea6b44fb6cc09b9f3ecff78", size = 218951, upload-time = "2025-12-28T15:41:16.653Z" }, + { url = "https://files.pythonhosted.org/packages/32/33/7cbfe2bdc6e2f03d6b240d23dc45fdaf3fd270aaf2d640be77b7f16989ab/coverage-7.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1dcb645d7e34dcbcc96cd7c132b1fc55c39263ca62eb961c064eb3928997363b", size = 219325, upload-time = "2025-12-28T15:41:18.609Z" }, + { url = "https://files.pythonhosted.org/packages/59/f6/efdabdb4929487baeb7cb2a9f7dac457d9356f6ad1b255be283d58b16316/coverage-7.13.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3d42df8201e00384736f0df9be2ced39324c3907607d17d50d50116c989d84cd", size = 250309, upload-time = "2025-12-28T15:41:20.629Z" }, + { url = "https://files.pythonhosted.org/packages/12/da/91a52516e9d5aea87d32d1523f9cdcf7a35a3b298e6be05d6509ba3cfab2/coverage-7.13.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa3edde1aa8807de1d05934982416cb3ec46d1d4d91e280bcce7cca01c507992", size = 252907, upload-time = "2025-12-28T15:41:22.257Z" }, + { url = "https://files.pythonhosted.org/packages/75/38/f1ea837e3dc1231e086db1638947e00d264e7e8c41aa8ecacf6e1e0c05f4/coverage-7.13.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9edd0e01a343766add6817bc448408858ba6b489039eaaa2018474e4001651a4", size = 254148, upload-time = "2025-12-28T15:41:23.87Z" }, + { url = "https://files.pythonhosted.org/packages/7f/43/f4f16b881aaa34954ba446318dea6b9ed5405dd725dd8daac2358eda869a/coverage-7.13.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:985b7836931d033570b94c94713c6dba5f9d3ff26045f72c3e5dbc5fe3361e5a", size = 250515, upload-time = "2025-12-28T15:41:25.437Z" }, + { url = "https://files.pythonhosted.org/packages/84/34/8cba7f00078bd468ea914134e0144263194ce849ec3baad187ffb6203d1c/coverage-7.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ffed1e4980889765c84a5d1a566159e363b71d6b6fbaf0bebc9d3c30bc016766", size = 252292, upload-time = "2025-12-28T15:41:28.459Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a4/cffac66c7652d84ee4ac52d3ccb94c015687d3b513f9db04bfcac2ac800d/coverage-7.13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8842af7f175078456b8b17f1b73a0d16a65dcbdc653ecefeb00a56b3c8c298c4", size = 250242, upload-time = "2025-12-28T15:41:30.02Z" }, + { url = "https://files.pythonhosted.org/packages/f4/78/9a64d462263dde416f3c0067efade7b52b52796f489b1037a95b0dc389c9/coverage-7.13.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ccd7a6fca48ca9c131d9b0a2972a581e28b13416fc313fb98b6d24a03ce9a398", size = 250068, upload-time = "2025-12-28T15:41:32.007Z" }, + { url = "https://files.pythonhosted.org/packages/69/c8/a8994f5fece06db7c4a97c8fc1973684e178599b42e66280dded0524ef00/coverage-7.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0403f647055de2609be776965108447deb8e384fe4a553c119e3ff6bfbab4784", size = 251846, upload-time = "2025-12-28T15:41:33.946Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f7/91fa73c4b80305c86598a2d4e54ba22df6bf7d0d97500944af7ef155d9f7/coverage-7.13.1-cp313-cp313-win32.whl", hash = "sha256:549d195116a1ba1e1ae2f5ca143f9777800f6636eab917d4f02b5310d6d73461", size = 221512, upload-time = "2025-12-28T15:41:35.519Z" }, + { url = "https://files.pythonhosted.org/packages/45/0b/0768b4231d5a044da8f75e097a8714ae1041246bb765d6b5563bab456735/coverage-7.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:5899d28b5276f536fcf840b18b61a9fce23cc3aec1d114c44c07fe94ebeaa500", size = 222321, upload-time = "2025-12-28T15:41:37.371Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b8/bdcb7253b7e85157282450262008f1366aa04663f3e3e4c30436f596c3e2/coverage-7.13.1-cp313-cp313-win_arm64.whl", hash = "sha256:868a2fae76dfb06e87291bcbd4dcbcc778a8500510b618d50496e520bd94d9b9", size = 220949, upload-time = "2025-12-28T15:41:39.553Z" }, + { url = "https://files.pythonhosted.org/packages/70/52/f2be52cc445ff75ea8397948c96c1b4ee14f7f9086ea62fc929c5ae7b717/coverage-7.13.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:67170979de0dacac3f3097d02b0ad188d8edcea44ccc44aaa0550af49150c7dc", size = 219643, upload-time = "2025-12-28T15:41:41.567Z" }, + { url = "https://files.pythonhosted.org/packages/47/79/c85e378eaa239e2edec0c5523f71542c7793fe3340954eafb0bc3904d32d/coverage-7.13.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f80e2bb21bfab56ed7405c2d79d34b5dc0bc96c2c1d2a067b643a09fb756c43a", size = 219997, upload-time = "2025-12-28T15:41:43.418Z" }, + { url = "https://files.pythonhosted.org/packages/fe/9b/b1ade8bfb653c0bbce2d6d6e90cc6c254cbb99b7248531cc76253cb4da6d/coverage-7.13.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f83351e0f7dcdb14d7326c3d8d8c4e915fa685cbfdc6281f9470d97a04e9dfe4", size = 261296, upload-time = "2025-12-28T15:41:45.207Z" }, + { url = "https://files.pythonhosted.org/packages/1f/af/ebf91e3e1a2473d523e87e87fd8581e0aa08741b96265730e2d79ce78d8d/coverage-7.13.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb3f6562e89bad0110afbe64e485aac2462efdce6232cdec7862a095dc3412f6", size = 263363, upload-time = "2025-12-28T15:41:47.163Z" }, + { url = "https://files.pythonhosted.org/packages/c4/8b/fb2423526d446596624ac7fde12ea4262e66f86f5120114c3cfd0bb2befa/coverage-7.13.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77545b5dcda13b70f872c3b5974ac64c21d05e65b1590b441c8560115dc3a0d1", size = 265783, upload-time = "2025-12-28T15:41:49.03Z" }, + { url = "https://files.pythonhosted.org/packages/9b/26/ef2adb1e22674913b89f0fe7490ecadcef4a71fa96f5ced90c60ec358789/coverage-7.13.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4d240d260a1aed814790bbe1f10a5ff31ce6c21bc78f0da4a1e8268d6c80dbd", size = 260508, upload-time = "2025-12-28T15:41:51.035Z" }, + { url = "https://files.pythonhosted.org/packages/ce/7d/f0f59b3404caf662e7b5346247883887687c074ce67ba453ea08c612b1d5/coverage-7.13.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d2287ac9360dec3837bfdad969963a5d073a09a85d898bd86bea82aa8876ef3c", size = 263357, upload-time = "2025-12-28T15:41:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b1/29896492b0b1a047604d35d6fa804f12818fa30cdad660763a5f3159e158/coverage-7.13.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0d2c11f3ea4db66b5cbded23b20185c35066892c67d80ec4be4bab257b9ad1e0", size = 260978, upload-time = "2025-12-28T15:41:54.589Z" }, + { url = "https://files.pythonhosted.org/packages/48/f2/971de1238a62e6f0a4128d37adadc8bb882ee96afbe03ff1570291754629/coverage-7.13.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:3fc6a169517ca0d7ca6846c3c5392ef2b9e38896f61d615cb75b9e7134d4ee1e", size = 259877, upload-time = "2025-12-28T15:41:56.263Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fc/0474efcbb590ff8628830e9aaec5f1831594874360e3251f1fdec31d07a3/coverage-7.13.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d10a2ed46386e850bb3de503a54f9fe8192e5917fcbb143bfef653a9355e9a53", size = 262069, upload-time = "2025-12-28T15:41:58.093Z" }, + { url = "https://files.pythonhosted.org/packages/88/4f/3c159b7953db37a7b44c0eab8a95c37d1aa4257c47b4602c04022d5cb975/coverage-7.13.1-cp313-cp313t-win32.whl", hash = "sha256:75a6f4aa904301dab8022397a22c0039edc1f51e90b83dbd4464b8a38dc87842", size = 222184, upload-time = "2025-12-28T15:41:59.763Z" }, + { url = "https://files.pythonhosted.org/packages/58/a5/6b57d28f81417f9335774f20679d9d13b9a8fb90cd6160957aa3b54a2379/coverage-7.13.1-cp313-cp313t-win_amd64.whl", hash = "sha256:309ef5706e95e62578cda256b97f5e097916a2c26247c287bbe74794e7150df2", size = 223250, upload-time = "2025-12-28T15:42:01.52Z" }, + { url = "https://files.pythonhosted.org/packages/81/7c/160796f3b035acfbb58be80e02e484548595aa67e16a6345e7910ace0a38/coverage-7.13.1-cp313-cp313t-win_arm64.whl", hash = "sha256:92f980729e79b5d16d221038dbf2e8f9a9136afa072f9d5d6ed4cb984b126a09", size = 221521, upload-time = "2025-12-28T15:42:03.275Z" }, + { url = "https://files.pythonhosted.org/packages/aa/8e/ba0e597560c6563fc0adb902fda6526df5d4aa73bb10adf0574d03bd2206/coverage-7.13.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:97ab3647280d458a1f9adb85244e81587505a43c0c7cff851f5116cd2814b894", size = 218996, upload-time = "2025-12-28T15:42:04.978Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8e/764c6e116f4221dc7aa26c4061181ff92edb9c799adae6433d18eeba7a14/coverage-7.13.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8f572d989142e0908e6acf57ad1b9b86989ff057c006d13b76c146ec6a20216a", size = 219326, upload-time = "2025-12-28T15:42:06.691Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a6/6130dc6d8da28cdcbb0f2bf8865aeca9b157622f7c0031e48c6cf9a0e591/coverage-7.13.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d72140ccf8a147e94274024ff6fd8fb7811354cf7ef88b1f0a988ebaa5bc774f", size = 250374, upload-time = "2025-12-28T15:42:08.786Z" }, + { url = "https://files.pythonhosted.org/packages/82/2b/783ded568f7cd6b677762f780ad338bf4b4750205860c17c25f7c708995e/coverage-7.13.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d3c9f051b028810f5a87c88e5d6e9af3c0ff32ef62763bf15d29f740453ca909", size = 252882, upload-time = "2025-12-28T15:42:10.515Z" }, + { url = "https://files.pythonhosted.org/packages/cd/b2/9808766d082e6a4d59eb0cc881a57fc1600eb2c5882813eefff8254f71b5/coverage-7.13.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f398ba4df52d30b1763f62eed9de5620dcde96e6f491f4c62686736b155aa6e4", size = 254218, upload-time = "2025-12-28T15:42:12.208Z" }, + { url = "https://files.pythonhosted.org/packages/44/ea/52a985bb447c871cb4d2e376e401116520991b597c85afdde1ea9ef54f2c/coverage-7.13.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:132718176cc723026d201e347f800cd1a9e4b62ccd3f82476950834dad501c75", size = 250391, upload-time = "2025-12-28T15:42:14.21Z" }, + { url = "https://files.pythonhosted.org/packages/7f/1d/125b36cc12310718873cfc8209ecfbc1008f14f4f5fa0662aa608e579353/coverage-7.13.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e549d642426e3579b3f4b92d0431543b012dcb6e825c91619d4e93b7363c3f9", size = 252239, upload-time = "2025-12-28T15:42:16.292Z" }, + { url = "https://files.pythonhosted.org/packages/6a/16/10c1c164950cade470107f9f14bbac8485f8fb8515f515fca53d337e4a7f/coverage-7.13.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:90480b2134999301eea795b3a9dbf606c6fbab1b489150c501da84a959442465", size = 250196, upload-time = "2025-12-28T15:42:18.54Z" }, + { url = "https://files.pythonhosted.org/packages/2a/c6/cd860fac08780c6fd659732f6ced1b40b79c35977c1356344e44d72ba6c4/coverage-7.13.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e825dbb7f84dfa24663dd75835e7257f8882629fc11f03ecf77d84a75134b864", size = 250008, upload-time = "2025-12-28T15:42:20.365Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/a8c58d3d38f82a5711e1e0a67268362af48e1a03df27c03072ac30feefcf/coverage-7.13.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:623dcc6d7a7ba450bbdbeedbaa0c42b329bdae16491af2282f12a7e809be7eb9", size = 251671, upload-time = "2025-12-28T15:42:22.114Z" }, + { url = "https://files.pythonhosted.org/packages/f0/bc/fd4c1da651d037a1e3d53e8cb3f8182f4b53271ffa9a95a2e211bacc0349/coverage-7.13.1-cp314-cp314-win32.whl", hash = "sha256:6e73ebb44dca5f708dc871fe0b90cf4cff1a13f9956f747cc87b535a840386f5", size = 221777, upload-time = "2025-12-28T15:42:23.919Z" }, + { url = "https://files.pythonhosted.org/packages/4b/50/71acabdc8948464c17e90b5ffd92358579bd0910732c2a1c9537d7536aa6/coverage-7.13.1-cp314-cp314-win_amd64.whl", hash = "sha256:be753b225d159feb397bd0bf91ae86f689bad0da09d3b301478cd39b878ab31a", size = 222592, upload-time = "2025-12-28T15:42:25.619Z" }, + { url = "https://files.pythonhosted.org/packages/f7/c8/a6fb943081bb0cc926499c7907731a6dc9efc2cbdc76d738c0ab752f1a32/coverage-7.13.1-cp314-cp314-win_arm64.whl", hash = "sha256:228b90f613b25ba0019361e4ab81520b343b622fc657daf7e501c4ed6a2366c0", size = 221169, upload-time = "2025-12-28T15:42:27.629Z" }, + { url = "https://files.pythonhosted.org/packages/16/61/d5b7a0a0e0e40d62e59bc8c7aa1afbd86280d82728ba97f0673b746b78e2/coverage-7.13.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:60cfb538fe9ef86e5b2ab0ca8fc8d62524777f6c611dcaf76dc16fbe9b8e698a", size = 219730, upload-time = "2025-12-28T15:42:29.306Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2c/8881326445fd071bb49514d1ce97d18a46a980712b51fee84f9ab42845b4/coverage-7.13.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:57dfc8048c72ba48a8c45e188d811e5efd7e49b387effc8fb17e97936dde5bf6", size = 220001, upload-time = "2025-12-28T15:42:31.319Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d7/50de63af51dfa3a7f91cc37ad8fcc1e244b734232fbc8b9ab0f3c834a5cd/coverage-7.13.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3f2f725aa3e909b3c5fdb8192490bdd8e1495e85906af74fe6e34a2a77ba0673", size = 261370, upload-time = "2025-12-28T15:42:32.992Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2c/d31722f0ec918fd7453b2758312729f645978d212b410cd0f7c2aed88a94/coverage-7.13.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ee68b21909686eeb21dfcba2c3b81fee70dcf38b140dcd5aa70680995fa3aa5", size = 263485, upload-time = "2025-12-28T15:42:34.759Z" }, + { url = "https://files.pythonhosted.org/packages/fa/7a/2c114fa5c5fc08ba0777e4aec4c97e0b4a1afcb69c75f1f54cff78b073ab/coverage-7.13.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:724b1b270cb13ea2e6503476e34541a0b1f62280bc997eab443f87790202033d", size = 265890, upload-time = "2025-12-28T15:42:36.517Z" }, + { url = "https://files.pythonhosted.org/packages/65/d9/f0794aa1c74ceabc780fe17f6c338456bbc4e96bd950f2e969f48ac6fb20/coverage-7.13.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:916abf1ac5cf7eb16bc540a5bf75c71c43a676f5c52fcb9fe75a2bd75fb944e8", size = 260445, upload-time = "2025-12-28T15:42:38.646Z" }, + { url = "https://files.pythonhosted.org/packages/49/23/184b22a00d9bb97488863ced9454068c79e413cb23f472da6cbddc6cfc52/coverage-7.13.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:776483fd35b58d8afe3acbd9988d5de592ab6da2d2a865edfdbc9fdb43e7c486", size = 263357, upload-time = "2025-12-28T15:42:40.788Z" }, + { url = "https://files.pythonhosted.org/packages/7d/bd/58af54c0c9199ea4190284f389005779d7daf7bf3ce40dcd2d2b2f96da69/coverage-7.13.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b6f3b96617e9852703f5b633ea01315ca45c77e879584f283c44127f0f1ec564", size = 260959, upload-time = "2025-12-28T15:42:42.808Z" }, + { url = "https://files.pythonhosted.org/packages/4b/2a/6839294e8f78a4891bf1df79d69c536880ba2f970d0ff09e7513d6e352e9/coverage-7.13.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd63e7b74661fed317212fab774e2a648bc4bb09b35f25474f8e3325d2945cd7", size = 259792, upload-time = "2025-12-28T15:42:44.818Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c3/528674d4623283310ad676c5af7414b9850ab6d55c2300e8aa4b945ec554/coverage-7.13.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:933082f161bbb3e9f90d00990dc956120f608cdbcaeea15c4d897f56ef4fe416", size = 262123, upload-time = "2025-12-28T15:42:47.108Z" }, + { url = "https://files.pythonhosted.org/packages/06/c5/8c0515692fb4c73ac379d8dc09b18eaf0214ecb76ea6e62467ba7a1556ff/coverage-7.13.1-cp314-cp314t-win32.whl", hash = "sha256:18be793c4c87de2965e1c0f060f03d9e5aff66cfeae8e1dbe6e5b88056ec153f", size = 222562, upload-time = "2025-12-28T15:42:49.144Z" }, + { url = "https://files.pythonhosted.org/packages/05/0e/c0a0c4678cb30dac735811db529b321d7e1c9120b79bd728d4f4d6b010e9/coverage-7.13.1-cp314-cp314t-win_amd64.whl", hash = "sha256:0e42e0ec0cd3e0d851cb3c91f770c9301f48647cb2877cb78f74bdaa07639a79", size = 223670, upload-time = "2025-12-28T15:42:51.218Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5f/b177aa0011f354abf03a8f30a85032686d290fdeed4222b27d36b4372a50/coverage-7.13.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eaecf47ef10c72ece9a2a92118257da87e460e113b83cc0d2905cbbe931792b4", size = 221707, upload-time = "2025-12-28T15:42:53.034Z" }, + { url = "https://files.pythonhosted.org/packages/cc/48/d9f421cb8da5afaa1a64570d9989e00fb7955e6acddc5a12979f7666ef60/coverage-7.13.1-py3-none-any.whl", hash = "sha256:2016745cb3ba554469d02819d78958b571792bb68e31302610e898f80dd3a573", size = 210722, upload-time = "2025-12-28T15:42:54.901Z" }, +] + +[[package]] +name = "dataclasses-json" +version = "0.6.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "marshmallow" }, + { name = "typing-inspect" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/a4/f71d9cf3a5ac257c993b5ca3f93df5f7fb395c725e7f1e6479d2514173c3/dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0", size = 32227, upload-time = "2024-06-09T16:20:19.103Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686, upload-time = "2024-06-09T16:20:16.715Z" }, +] + +[[package]] +name = "debugpy" +version = "1.8.19" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/73/75/9e12d4d42349b817cd545b89247696c67917aab907012ae5b64bbfea3199/debugpy-1.8.19.tar.gz", hash = "sha256:eea7e5987445ab0b5ed258093722d5ecb8bb72217c5c9b1e21f64efe23ddebdb", size = 1644590, upload-time = "2025-12-15T21:53:28.044Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/15/d762e5263d9e25b763b78be72dc084c7a32113a0bac119e2f7acae7700ed/debugpy-1.8.19-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:bccb1540a49cde77edc7ce7d9d075c1dbeb2414751bc0048c7a11e1b597a4c2e", size = 2549995, upload-time = "2025-12-15T21:53:43.773Z" }, + { url = "https://files.pythonhosted.org/packages/a7/88/f7d25c68b18873b7c53d7c156ca7a7ffd8e77073aa0eac170a9b679cf786/debugpy-1.8.19-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:e9c68d9a382ec754dc05ed1d1b4ed5bd824b9f7c1a8cd1083adb84b3c93501de", size = 4309891, upload-time = "2025-12-15T21:53:45.26Z" }, + { url = "https://files.pythonhosted.org/packages/c5/4f/a65e973aba3865794da65f71971dca01ae66666132c7b2647182d5be0c5f/debugpy-1.8.19-cp312-cp312-win32.whl", hash = "sha256:6599cab8a783d1496ae9984c52cb13b7c4a3bd06a8e6c33446832a5d97ce0bee", size = 5286355, upload-time = "2025-12-15T21:53:46.763Z" }, + { url = "https://files.pythonhosted.org/packages/d8/3a/d3d8b48fec96e3d824e404bf428276fb8419dfa766f78f10b08da1cb2986/debugpy-1.8.19-cp312-cp312-win_amd64.whl", hash = "sha256:66e3d2fd8f2035a8f111eb127fa508469dfa40928a89b460b41fd988684dc83d", size = 5328239, upload-time = "2025-12-15T21:53:48.868Z" }, + { url = "https://files.pythonhosted.org/packages/71/3d/388035a31a59c26f1ecc8d86af607d0c42e20ef80074147cd07b180c4349/debugpy-1.8.19-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:91e35db2672a0abaf325f4868fcac9c1674a0d9ad9bb8a8c849c03a5ebba3e6d", size = 2538859, upload-time = "2025-12-15T21:53:50.478Z" }, + { url = "https://files.pythonhosted.org/packages/4a/19/c93a0772d0962294f083dbdb113af1a7427bb632d36e5314297068f55db7/debugpy-1.8.19-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:85016a73ab84dea1c1f1dcd88ec692993bcbe4532d1b49ecb5f3c688ae50c606", size = 4292575, upload-time = "2025-12-15T21:53:51.821Z" }, + { url = "https://files.pythonhosted.org/packages/5c/56/09e48ab796b0a77e3d7dc250f95251832b8bf6838c9632f6100c98bdf426/debugpy-1.8.19-cp313-cp313-win32.whl", hash = "sha256:b605f17e89ba0ecee994391194285fada89cee111cfcd29d6f2ee11cbdc40976", size = 5286209, upload-time = "2025-12-15T21:53:53.602Z" }, + { url = "https://files.pythonhosted.org/packages/fb/4e/931480b9552c7d0feebe40c73725dd7703dcc578ba9efc14fe0e6d31cfd1/debugpy-1.8.19-cp313-cp313-win_amd64.whl", hash = "sha256:c30639998a9f9cd9699b4b621942c0179a6527f083c72351f95c6ab1728d5b73", size = 5328206, upload-time = "2025-12-15T21:53:55.433Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b9/cbec520c3a00508327476c7fce26fbafef98f412707e511eb9d19a2ef467/debugpy-1.8.19-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:1e8c4d1bd230067bf1bbcdbd6032e5a57068638eb28b9153d008ecde288152af", size = 2537372, upload-time = "2025-12-15T21:53:57.318Z" }, + { url = "https://files.pythonhosted.org/packages/88/5e/cf4e4dc712a141e10d58405c58c8268554aec3c35c09cdcda7535ff13f76/debugpy-1.8.19-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:d40c016c1f538dbf1762936e3aeb43a89b965069d9f60f9e39d35d9d25e6b809", size = 4268729, upload-time = "2025-12-15T21:53:58.712Z" }, + { url = "https://files.pythonhosted.org/packages/82/a3/c91a087ab21f1047db328c1d3eb5d1ff0e52de9e74f9f6f6fa14cdd93d58/debugpy-1.8.19-cp314-cp314-win32.whl", hash = "sha256:0601708223fe1cd0e27c6cce67a899d92c7d68e73690211e6788a4b0e1903f5b", size = 5286388, upload-time = "2025-12-15T21:54:00.687Z" }, + { url = "https://files.pythonhosted.org/packages/17/b8/bfdc30b6e94f1eff09f2dc9cc1f9cd1c6cde3d996bcbd36ce2d9a4956e99/debugpy-1.8.19-cp314-cp314-win_amd64.whl", hash = "sha256:8e19a725f5d486f20e53a1dde2ab8bb2c9607c40c00a42ab646def962b41125f", size = 5327741, upload-time = "2025-12-15T21:54:02.148Z" }, + { url = "https://files.pythonhosted.org/packages/25/3e/e27078370414ef35fafad2c06d182110073daaeb5d3bf734b0b1eeefe452/debugpy-1.8.19-py2.py3-none-any.whl", hash = "sha256:360ffd231a780abbc414ba0f005dad409e71c78637efe8f2bd75837132a41d38", size = 5292321, upload-time = "2025-12-15T21:54:16.024Z" }, +] + +[[package]] +name = "decorator" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, +] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, +] + +[[package]] +name = "docstring-parser" +version = "0.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" }, +] + +[[package]] +name = "doczy-field-extraction" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "anthropic" }, + { name = "boto3" }, + { name = "faiss-cpu" }, + { name = "langchain" }, + { name = "langchain-aws" }, + { name = "langchain-classic" }, + { name = "langchain-community" }, + { name = "langchain-text-splitters" }, + { name = "langchainhub" }, + { name = "nltk" }, + { name = "openpyxl" }, + { name = "orjson" }, + { name = "pandas" }, + { name = "pillow" }, + { name = "psutil" }, + { name = "pymupdf" }, + { name = "python-dotenv" }, + { name = "pyxlsb" }, + { name = "rank-bm25" }, + { name = "rapidfuzz" }, + { name = "sentence-transformers" }, + { name = "word2number" }, + { name = "xlsxwriter" }, +] + +[package.dev-dependencies] +dev = [ + { name = "black" }, + { name = "isort" }, + { name = "jupyter" }, + { name = "mypy" }, + { name = "pytest" }, + { name = "pytest-mock" }, +] +test = [ + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-mock" }, +] + +[package.metadata] +requires-dist = [ + { name = "anthropic", specifier = ">=0.36.0" }, + { name = "boto3", specifier = ">=1.35.40" }, + { name = "faiss-cpu", specifier = ">=1.10.0" }, + { name = "langchain", specifier = ">=0.3.14" }, + { name = "langchain-aws", specifier = ">=0.2.11" }, + { name = "langchain-classic", specifier = ">=1.0.1" }, + { name = "langchain-community", specifier = ">=0.3.15" }, + { name = "langchain-text-splitters", specifier = ">=0.3.5" }, + { name = "langchainhub", specifier = ">=0.1.21" }, + { name = "nltk", specifier = ">=3.9.1" }, + { name = "openpyxl", specifier = ">=3.1.5" }, + { name = "orjson", specifier = ">=3.10.16" }, + { name = "pandas", specifier = ">=2.2.3" }, + { name = "pillow", specifier = ">=11.2.1" }, + { name = "psutil", specifier = ">=6.1.0" }, + { name = "pymupdf", specifier = ">=1.25.5" }, + { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "pyxlsb", specifier = ">=1.0.10" }, + { name = "rank-bm25", specifier = ">=0.2.2" }, + { name = "rapidfuzz", specifier = ">=3.10.1" }, + { name = "sentence-transformers", specifier = ">=3.4.1" }, + { name = "word2number", specifier = ">=1.1" }, + { name = "xlsxwriter", specifier = ">=3.2.9" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "black", specifier = ">=24.10.0" }, + { name = "isort", specifier = ">=5.13.2" }, + { name = "jupyter", specifier = ">=1.1.1" }, + { name = "mypy", specifier = ">=1.12.0" }, + { name = "pytest", specifier = ">=8.3.3" }, + { name = "pytest-mock", specifier = ">=3.14.0" }, +] +test = [ + { name = "pytest", specifier = ">=8.3.3" }, + { name = "pytest-cov", specifier = ">=6.0.0" }, + { name = "pytest-mock", specifier = ">=3.14.0" }, +] + +[[package]] +name = "et-xmlfile" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/38/af70d7ab1ae9d4da450eeec1fa3918940a5fafb9055e934af8d6eb0c2313/et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54", size = 17234, upload-time = "2024-10-25T17:25:40.039Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" }, +] + +[[package]] +name = "executing" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, +] + +[[package]] +name = "faiss-cpu" +version = "1.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "packaging" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/c9/671f66f6b31ec48e5825d36435f0cb91189fa8bb6b50724029dbff4ca83c/faiss_cpu-1.13.2-cp310-abi3-macosx_14_0_arm64.whl", hash = "sha256:a9064eb34f8f64438dd5b95c8f03a780b1a3f0b99c46eeacb1f0b5d15fc02dc1", size = 3452776, upload-time = "2025-12-24T10:27:01.419Z" }, + { url = "https://files.pythonhosted.org/packages/5a/4a/97150aa1582fb9c2bca95bd8fc37f27d3b470acec6f0a6833844b21e4b40/faiss_cpu-1.13.2-cp310-abi3-macosx_14_0_x86_64.whl", hash = "sha256:c8d097884521e1ecaea6467aeebbf1aa56ee4a36350b48b2ca6b39366565c317", size = 7896434, upload-time = "2025-12-24T10:27:03.592Z" }, + { url = "https://files.pythonhosted.org/packages/0b/d0/0940575f059591ca31b63a881058adb16a387020af1709dcb7669460115c/faiss_cpu-1.13.2-cp310-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ee330a284042c2480f2e90450a10378fd95655d62220159b1408f59ee83ebf1", size = 11485825, upload-time = "2025-12-24T10:27:05.681Z" }, + { url = "https://files.pythonhosted.org/packages/e7/e1/a5acac02aa593809f0123539afe7b4aff61d1db149e7093239888c9053e1/faiss_cpu-1.13.2-cp310-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ab88ee287c25a119213153d033f7dd64c3ccec466ace267395872f554b648cd7", size = 23845772, upload-time = "2025-12-24T10:27:08.194Z" }, + { url = "https://files.pythonhosted.org/packages/9c/7b/49dcaf354834ec457e85ca769d50bc9b5f3003fab7c94a9dcf08cf742793/faiss_cpu-1.13.2-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:85511129b34f890d19c98b82a0cd5ffb27d89d1cec2ee41d2621ee9f9ef8cf3f", size = 13477567, upload-time = "2025-12-24T10:27:10.822Z" }, + { url = "https://files.pythonhosted.org/packages/f7/6b/12bb4037921c38bb2c0b4cfc213ca7e04bbbebbfea89b0b5746248ce446e/faiss_cpu-1.13.2-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b32eb4065bac352b52a9f5ae07223567fab0a976c7d05017c01c45a1c24264f", size = 25102239, upload-time = "2025-12-24T10:27:13.476Z" }, + { url = "https://files.pythonhosted.org/packages/87/ff/35ed875423200c17bdd594ce921abfc1812ddd21e09355290b9a94e170ab/faiss_cpu-1.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:b82c01d30430dd7b1fa442001b9099735d1a82f6bb72033acdc9206d5ac66a64", size = 18890300, upload-time = "2025-12-24T10:27:24.194Z" }, + { url = "https://files.pythonhosted.org/packages/c5/3a/bbdf5deaf6feb34b46b469c0a0acd40216c3d3c6ecf5aeb71d56b8a650e3/faiss_cpu-1.13.2-cp312-cp312-win_arm64.whl", hash = "sha256:2c4f696ae76e7c97cbc12311db83aaf1e7f4f7be06a3ffea7e5b0e8ec1fd805b", size = 8553157, upload-time = "2025-12-24T10:27:26.38Z" }, + { url = "https://files.pythonhosted.org/packages/60/4b/903d85bf3a8264d49964ec799e45c7ffc91098606b8bc9ef2c904c1a56cb/faiss_cpu-1.13.2-cp313-cp313-win_amd64.whl", hash = "sha256:cb4b5ee184816a4b099162ac93c0d7f0033d81a88e7c1291d0a9cc41ec348984", size = 18891330, upload-time = "2025-12-24T10:27:28.806Z" }, + { url = "https://files.pythonhosted.org/packages/b2/52/5d10642da628f63544aab27e48416be4a7ea25c6b81d8bd65016d8538b00/faiss_cpu-1.13.2-cp313-cp313-win_arm64.whl", hash = "sha256:1243967eeb2298791ff7f3683a4abd2100d7e6ec7542ca05c3b75d47a7f621e5", size = 8553088, upload-time = "2025-12-24T10:27:31.325Z" }, + { url = "https://files.pythonhosted.org/packages/b0/b1/daaab8046f56c60079648bd83774f61b283b59a9930a2f60790ee4cdedfe/faiss_cpu-1.13.2-cp314-cp314-win_amd64.whl", hash = "sha256:c8b645e7d56591aa35dc75415bb53a62e4a494dba010e16f4b67daeffd830bd7", size = 18892621, upload-time = "2025-12-24T10:27:33.923Z" }, + { url = "https://files.pythonhosted.org/packages/06/6f/5eaf3e249c636e616ebb52e369a4a2f1d32b1caf9a611b4f917b3dd21423/faiss_cpu-1.13.2-cp314-cp314-win_arm64.whl", hash = "sha256:8113a2a80b59fe5653cf66f5c0f18be0a691825601a52a614c30beb1fca9bc7c", size = 8556374, upload-time = "2025-12-24T10:27:36.653Z" }, +] + +[[package]] +name = "fastjsonschema" +version = "2.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130, upload-time = "2025-08-14T18:49:36.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, +] + +[[package]] +name = "filelock" +version = "3.20.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c1/e0/a75dbe4bca1e7d41307323dad5ea2efdd95408f74ab2de8bd7dba9b51a1a/filelock-3.20.2.tar.gz", hash = "sha256:a2241ff4ddde2a7cebddf78e39832509cb045d18ec1a09d7248d6bfc6bfbbe64", size = 19510, upload-time = "2026-01-02T15:33:32.582Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/30/ab407e2ec752aa541704ed8f93c11e2a5d92c168b8a755d818b74a3c5c2d/filelock-3.20.2-py3-none-any.whl", hash = "sha256:fbba7237d6ea277175a32c54bb71ef814a8546d8601269e1bfc388de333974e8", size = 16697, upload-time = "2026-01-02T15:33:31.133Z" }, +] + +[[package]] +name = "fqdn" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, +] + +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" }, + { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" }, + { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" }, + { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" }, + { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" }, + { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" }, + { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" }, + { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" }, + { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" }, + { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" }, + { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" }, + { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" }, + { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" }, + { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" }, + { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" }, + { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" }, + { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" }, + { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" }, + { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" }, + { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" }, + { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" }, + { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" }, + { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" }, + { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" }, + { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" }, + { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" }, + { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" }, + { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" }, + { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" }, + { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" }, + { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" }, + { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" }, + { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" }, + { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" }, + { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" }, + { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" }, + { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" }, + { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" }, + { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" }, + { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" }, + { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" }, + { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" }, + { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" }, + { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" }, + { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" }, + { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" }, + { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" }, + { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, +] + +[[package]] +name = "fsspec" +version = "2025.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/27/954057b0d1f53f086f681755207dda6de6c660ce133c829158e8e8fe7895/fsspec-2025.12.0.tar.gz", hash = "sha256:c505de011584597b1060ff778bb664c1bc022e87921b0e4f10cc9c44f9635973", size = 309748, upload-time = "2025-12-03T15:23:42.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/c7/b64cae5dba3a1b138d7123ec36bb5ccd39d39939f18454407e5468f4763f/fsspec-2025.12.0-py3-none-any.whl", hash = "sha256:8bf1fe301b7d8acfa6e8571e3b1c3d158f909666642431cc78a1b7b4dbc5ec5b", size = 201422, upload-time = "2025-12-03T15:23:41.434Z" }, +] + +[[package]] +name = "greenlet" +version = "3.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651, upload-time = "2025-12-04T14:49:44.05Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/0a/a3871375c7b9727edaeeea994bfff7c63ff7804c9829c19309ba2e058807/greenlet-3.3.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:b01548f6e0b9e9784a2c99c5651e5dc89ffcbe870bc5fb2e5ef864e9cc6b5dcb", size = 276379, upload-time = "2025-12-04T14:23:30.498Z" }, + { url = "https://files.pythonhosted.org/packages/43/ab/7ebfe34dce8b87be0d11dae91acbf76f7b8246bf9d6b319c741f99fa59c6/greenlet-3.3.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349345b770dc88f81506c6861d22a6ccd422207829d2c854ae2af8025af303e3", size = 597294, upload-time = "2025-12-04T14:50:06.847Z" }, + { url = "https://files.pythonhosted.org/packages/a4/39/f1c8da50024feecd0793dbd5e08f526809b8ab5609224a2da40aad3a7641/greenlet-3.3.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e8e18ed6995e9e2c0b4ed264d2cf89260ab3ac7e13555b8032b25a74c6d18655", size = 607742, upload-time = "2025-12-04T14:57:42.349Z" }, + { url = "https://files.pythonhosted.org/packages/77/cb/43692bcd5f7a0da6ec0ec6d58ee7cddb606d055ce94a62ac9b1aa481e969/greenlet-3.3.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c024b1e5696626890038e34f76140ed1daf858e37496d33f2af57f06189e70d7", size = 622297, upload-time = "2025-12-04T15:07:13.552Z" }, + { url = "https://files.pythonhosted.org/packages/75/b0/6bde0b1011a60782108c01de5913c588cf51a839174538d266de15e4bf4d/greenlet-3.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:047ab3df20ede6a57c35c14bf5200fcf04039d50f908270d3f9a7a82064f543b", size = 609885, upload-time = "2025-12-04T14:26:02.368Z" }, + { url = "https://files.pythonhosted.org/packages/49/0e/49b46ac39f931f59f987b7cd9f34bfec8ef81d2a1e6e00682f55be5de9f4/greenlet-3.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d9ad37fc657b1102ec880e637cccf20191581f75c64087a549e66c57e1ceb53", size = 1567424, upload-time = "2025-12-04T15:04:23.757Z" }, + { url = "https://files.pythonhosted.org/packages/05/f5/49a9ac2dff7f10091935def9165c90236d8f175afb27cbed38fb1d61ab6b/greenlet-3.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83cd0e36932e0e7f36a64b732a6f60c2fc2df28c351bae79fbaf4f8092fe7614", size = 1636017, upload-time = "2025-12-04T14:27:29.688Z" }, + { url = "https://files.pythonhosted.org/packages/6c/79/3912a94cf27ec503e51ba493692d6db1e3cd8ac7ac52b0b47c8e33d7f4f9/greenlet-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7a34b13d43a6b78abf828a6d0e87d3385680eaf830cd60d20d52f249faabf39", size = 301964, upload-time = "2025-12-04T14:36:58.316Z" }, + { url = "https://files.pythonhosted.org/packages/02/2f/28592176381b9ab2cafa12829ba7b472d177f3acc35d8fbcf3673d966fff/greenlet-3.3.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739", size = 275140, upload-time = "2025-12-04T14:23:01.282Z" }, + { url = "https://files.pythonhosted.org/packages/2c/80/fbe937bf81e9fca98c981fe499e59a3f45df2a04da0baa5c2be0dca0d329/greenlet-3.3.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808", size = 599219, upload-time = "2025-12-04T14:50:08.309Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ff/7c985128f0514271b8268476af89aee6866df5eec04ac17dcfbc676213df/greenlet-3.3.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54", size = 610211, upload-time = "2025-12-04T14:57:43.968Z" }, + { url = "https://files.pythonhosted.org/packages/79/07/c47a82d881319ec18a4510bb30463ed6891f2ad2c1901ed5ec23d3de351f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492", size = 624311, upload-time = "2025-12-04T15:07:14.697Z" }, + { url = "https://files.pythonhosted.org/packages/fd/8e/424b8c6e78bd9837d14ff7df01a9829fc883ba2ab4ea787d4f848435f23f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527", size = 612833, upload-time = "2025-12-04T14:26:03.669Z" }, + { url = "https://files.pythonhosted.org/packages/b5/ba/56699ff9b7c76ca12f1cdc27a886d0f81f2189c3455ff9f65246780f713d/greenlet-3.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39", size = 1567256, upload-time = "2025-12-04T15:04:25.276Z" }, + { url = "https://files.pythonhosted.org/packages/1e/37/f31136132967982d698c71a281a8901daf1a8fbab935dce7c0cf15f942cc/greenlet-3.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8", size = 1636483, upload-time = "2025-12-04T14:27:30.804Z" }, + { url = "https://files.pythonhosted.org/packages/7e/71/ba21c3fb8c5dce83b8c01f458a42e99ffdb1963aeec08fff5a18588d8fd7/greenlet-3.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:9ee1942ea19550094033c35d25d20726e4f1c40d59545815e1128ac58d416d38", size = 301833, upload-time = "2025-12-04T14:32:23.929Z" }, + { url = "https://files.pythonhosted.org/packages/d7/7c/f0a6d0ede2c7bf092d00bc83ad5bafb7e6ec9b4aab2fbdfa6f134dc73327/greenlet-3.3.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f", size = 275671, upload-time = "2025-12-04T14:23:05.267Z" }, + { url = "https://files.pythonhosted.org/packages/44/06/dac639ae1a50f5969d82d2e3dd9767d30d6dbdbab0e1a54010c8fe90263c/greenlet-3.3.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365", size = 646360, upload-time = "2025-12-04T14:50:10.026Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/0fb76fe6c5369fba9bf98529ada6f4c3a1adf19e406a47332245ef0eb357/greenlet-3.3.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3", size = 658160, upload-time = "2025-12-04T14:57:45.41Z" }, + { url = "https://files.pythonhosted.org/packages/93/79/d2c70cae6e823fac36c3bbc9077962105052b7ef81db2f01ec3b9bf17e2b/greenlet-3.3.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45", size = 671388, upload-time = "2025-12-04T15:07:15.789Z" }, + { url = "https://files.pythonhosted.org/packages/b8/14/bab308fc2c1b5228c3224ec2bf928ce2e4d21d8046c161e44a2012b5203e/greenlet-3.3.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955", size = 660166, upload-time = "2025-12-04T14:26:05.099Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d2/91465d39164eaa0085177f61983d80ffe746c5a1860f009811d498e7259c/greenlet-3.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55", size = 1615193, upload-time = "2025-12-04T15:04:27.041Z" }, + { url = "https://files.pythonhosted.org/packages/42/1b/83d110a37044b92423084d52d5d5a3b3a73cafb51b547e6d7366ff62eff1/greenlet-3.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc", size = 1683653, upload-time = "2025-12-04T14:27:32.366Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/9030e6f9aa8fd7808e9c31ba4c38f87c4f8ec324ee67431d181fe396d705/greenlet-3.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:73f51dd0e0bdb596fb0417e475fa3c5e32d4c83638296e560086b8d7da7c4170", size = 305387, upload-time = "2025-12-04T14:26:51.063Z" }, + { url = "https://files.pythonhosted.org/packages/a0/66/bd6317bc5932accf351fc19f177ffba53712a202f9df10587da8df257c7e/greenlet-3.3.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931", size = 282638, upload-time = "2025-12-04T14:25:20.941Z" }, + { url = "https://files.pythonhosted.org/packages/30/cf/cc81cb030b40e738d6e69502ccbd0dd1bced0588e958f9e757945de24404/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388", size = 651145, upload-time = "2025-12-04T14:50:11.039Z" }, + { url = "https://files.pythonhosted.org/packages/9c/ea/1020037b5ecfe95ca7df8d8549959baceb8186031da83d5ecceff8b08cd2/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3", size = 654236, upload-time = "2025-12-04T14:57:47.007Z" }, + { url = "https://files.pythonhosted.org/packages/69/cc/1e4bae2e45ca2fa55299f4e85854606a78ecc37fead20d69322f96000504/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221", size = 662506, upload-time = "2025-12-04T15:07:16.906Z" }, + { url = "https://files.pythonhosted.org/packages/57/b9/f8025d71a6085c441a7eaff0fd928bbb275a6633773667023d19179fe815/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b", size = 653783, upload-time = "2025-12-04T14:26:06.225Z" }, + { url = "https://files.pythonhosted.org/packages/f6/c7/876a8c7a7485d5d6b5c6821201d542ef28be645aa024cfe1145b35c120c1/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd", size = 1614857, upload-time = "2025-12-04T15:04:28.484Z" }, + { url = "https://files.pythonhosted.org/packages/4f/dc/041be1dff9f23dac5f48a43323cd0789cb798342011c19a248d9c9335536/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9", size = 1676034, upload-time = "2025-12-04T14:27:33.531Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "hf-xet" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/a5/85ef910a0aa034a2abcfadc360ab5ac6f6bc4e9112349bd40ca97551cff0/hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649", size = 2861870, upload-time = "2025-10-24T19:04:11.422Z" }, + { url = "https://files.pythonhosted.org/packages/ea/40/e2e0a7eb9a51fe8828ba2d47fe22a7e74914ea8a0db68a18c3aa7449c767/hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813", size = 2717584, upload-time = "2025-10-24T19:04:09.586Z" }, + { url = "https://files.pythonhosted.org/packages/a5/7d/daf7f8bc4594fdd59a8a596f9e3886133fdc68e675292218a5e4c1b7e834/hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc", size = 3315004, upload-time = "2025-10-24T19:04:00.314Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ba/45ea2f605fbf6d81c8b21e4d970b168b18a53515923010c312c06cd83164/hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5", size = 3222636, upload-time = "2025-10-24T19:03:58.111Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1d/04513e3cab8f29ab8c109d309ddd21a2705afab9d52f2ba1151e0c14f086/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f", size = 3408448, upload-time = "2025-10-24T19:04:20.951Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7c/60a2756d7feec7387db3a1176c632357632fbe7849fce576c5559d4520c7/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832", size = 3503401, upload-time = "2025-10-24T19:04:22.549Z" }, + { url = "https://files.pythonhosted.org/packages/4e/64/48fffbd67fb418ab07451e4ce641a70de1c40c10a13e25325e24858ebe5a/hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382", size = 2900866, upload-time = "2025-10-24T19:04:33.461Z" }, + { url = "https://files.pythonhosted.org/packages/e2/51/f7e2caae42f80af886db414d4e9885fac959330509089f97cccb339c6b87/hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e", size = 2861861, upload-time = "2025-10-24T19:04:19.01Z" }, + { url = "https://files.pythonhosted.org/packages/6e/1d/a641a88b69994f9371bd347f1dd35e5d1e2e2460a2e350c8d5165fc62005/hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8", size = 2717699, upload-time = "2025-10-24T19:04:17.306Z" }, + { url = "https://files.pythonhosted.org/packages/df/e0/e5e9bba7d15f0318955f7ec3f4af13f92e773fbb368c0b8008a5acbcb12f/hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0", size = 3314885, upload-time = "2025-10-24T19:04:07.642Z" }, + { url = "https://files.pythonhosted.org/packages/21/90/b7fe5ff6f2b7b8cbdf1bd56145f863c90a5807d9758a549bf3d916aa4dec/hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090", size = 3221550, upload-time = "2025-10-24T19:04:05.55Z" }, + { url = "https://files.pythonhosted.org/packages/6f/cb/73f276f0a7ce46cc6a6ec7d6c7d61cbfe5f2e107123d9bbd0193c355f106/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a", size = 3408010, upload-time = "2025-10-24T19:04:28.598Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1e/d642a12caa78171f4be64f7cd9c40e3ca5279d055d0873188a58c0f5fbb9/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f", size = 3503264, upload-time = "2025-10-24T19:04:30.397Z" }, + { url = "https://files.pythonhosted.org/packages/17/b5/33764714923fa1ff922770f7ed18c2daae034d21ae6e10dbf4347c854154/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc", size = 2901071, upload-time = "2025-10-24T19:04:37.463Z" }, + { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" }, + { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" }, + { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" }, + { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" }, + { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" }, + { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" }, + { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "httpx-sse" +version = "0.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/4c/751061ffa58615a32c31b2d82e8482be8dd4a89154f003147acee90f2be9/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d", size = 15943, upload-time = "2025-10-10T21:48:22.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "0.36.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358, upload-time = "2025-10-23T12:12:01.413Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094, upload-time = "2025-10-23T12:11:59.557Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "ipykernel" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "appnope", marker = "sys_platform == 'darwin'" }, + { name = "comm" }, + { name = "debugpy" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "matplotlib-inline" }, + { name = "nest-asyncio" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579, upload-time = "2025-10-27T09:46:39.471Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968, upload-time = "2025-10-27T09:46:37.805Z" }, +] + +[[package]] +name = "ipython" +version = "9.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "ipython-pygments-lexers" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/dd/fb08d22ec0c27e73c8bc8f71810709870d51cadaf27b7ddd3f011236c100/ipython-9.9.0.tar.gz", hash = "sha256:48fbed1b2de5e2c7177eefa144aba7fcb82dac514f09b57e2ac9da34ddb54220", size = 4425043, upload-time = "2026-01-05T12:36:46.233Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/92/162cfaee4ccf370465c5af1ce36a9eacec1becb552f2033bb3584e6f640a/ipython-9.9.0-py3-none-any.whl", hash = "sha256:b457fe9165df2b84e8ec909a97abcf2ed88f565970efba16b1f7229c283d252b", size = 621431, upload-time = "2026-01-05T12:36:44.669Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, +] + +[[package]] +name = "ipywidgets" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "comm" }, + { name = "ipython" }, + { name = "jupyterlab-widgets" }, + { name = "traitlets" }, + { name = "widgetsnbextension" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739, upload-time = "2025-11-01T21:18:12.393Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808, upload-time = "2025-11-01T21:18:10.956Z" }, +] + +[[package]] +name = "isoduration" +version = "20.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "arrow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" }, +] + +[[package]] +name = "isort" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/53/4f3c058e3bace40282876f9b553343376ee687f3c35a525dc79dbd450f88/isort-7.0.0.tar.gz", hash = "sha256:5513527951aadb3ac4292a41a16cbc50dd1642432f5e8c20057d414bdafb4187", size = 805049, upload-time = "2025-10-11T13:30:59.107Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/ed/e3705d6d02b4f7aea715a353c8ce193efd0b5db13e204df895d38734c244/isort-7.0.0-py3-none-any.whl", hash = "sha256:1bcabac8bc3c36c7fb7b98a76c8abb18e0f841a3ba81decac7691008592499c1", size = 94672, upload-time = "2025-10-11T13:30:57.665Z" }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jiter" +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294, upload-time = "2025-11-09T20:49:23.302Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/c9/5b9f7b4983f1b542c64e84165075335e8a236fa9e2ea03a0c79780062be8/jiter-0.12.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:305e061fa82f4680607a775b2e8e0bcb071cd2205ac38e6ef48c8dd5ebe1cf37", size = 314449, upload-time = "2025-11-09T20:47:22.999Z" }, + { url = "https://files.pythonhosted.org/packages/98/6e/e8efa0e78de00db0aee82c0cf9e8b3f2027efd7f8a71f859d8f4be8e98ef/jiter-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c1860627048e302a528333c9307c818c547f214d8659b0705d2195e1a94b274", size = 319855, upload-time = "2025-11-09T20:47:24.779Z" }, + { url = "https://files.pythonhosted.org/packages/20/26/894cd88e60b5d58af53bec5c6759d1292bd0b37a8b5f60f07abf7a63ae5f/jiter-0.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df37577a4f8408f7e0ec3205d2a8f87672af8f17008358063a4d6425b6081ce3", size = 350171, upload-time = "2025-11-09T20:47:26.469Z" }, + { url = "https://files.pythonhosted.org/packages/f5/27/a7b818b9979ac31b3763d25f3653ec3a954044d5e9f5d87f2f247d679fd1/jiter-0.12.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75fdd787356c1c13a4f40b43c2156276ef7a71eb487d98472476476d803fb2cf", size = 365590, upload-time = "2025-11-09T20:47:27.918Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7e/e46195801a97673a83746170b17984aa8ac4a455746354516d02ca5541b4/jiter-0.12.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1eb5db8d9c65b112aacf14fcd0faae9913d07a8afea5ed06ccdd12b724e966a1", size = 479462, upload-time = "2025-11-09T20:47:29.654Z" }, + { url = "https://files.pythonhosted.org/packages/ca/75/f833bfb009ab4bd11b1c9406d333e3b4357709ed0570bb48c7c06d78c7dd/jiter-0.12.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73c568cc27c473f82480abc15d1301adf333a7ea4f2e813d6a2c7d8b6ba8d0df", size = 378983, upload-time = "2025-11-09T20:47:31.026Z" }, + { url = "https://files.pythonhosted.org/packages/71/b3/7a69d77943cc837d30165643db753471aff5df39692d598da880a6e51c24/jiter-0.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4321e8a3d868919bcb1abb1db550d41f2b5b326f72df29e53b2df8b006eb9403", size = 361328, upload-time = "2025-11-09T20:47:33.286Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ac/a78f90caf48d65ba70d8c6efc6f23150bc39dc3389d65bbec2a95c7bc628/jiter-0.12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0a51bad79f8cc9cac2b4b705039f814049142e0050f30d91695a2d9a6611f126", size = 386740, upload-time = "2025-11-09T20:47:34.703Z" }, + { url = "https://files.pythonhosted.org/packages/39/b6/5d31c2cc8e1b6a6bcf3c5721e4ca0a3633d1ab4754b09bc7084f6c4f5327/jiter-0.12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2a67b678f6a5f1dd6c36d642d7db83e456bc8b104788262aaefc11a22339f5a9", size = 520875, upload-time = "2025-11-09T20:47:36.058Z" }, + { url = "https://files.pythonhosted.org/packages/30/b5/4df540fae4e9f68c54b8dab004bd8c943a752f0b00efd6e7d64aa3850339/jiter-0.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efe1a211fe1fd14762adea941e3cfd6c611a136e28da6c39272dbb7a1bbe6a86", size = 511457, upload-time = "2025-11-09T20:47:37.932Z" }, + { url = "https://files.pythonhosted.org/packages/07/65/86b74010e450a1a77b2c1aabb91d4a91dd3cd5afce99f34d75fd1ac64b19/jiter-0.12.0-cp312-cp312-win32.whl", hash = "sha256:d779d97c834b4278276ec703dc3fc1735fca50af63eb7262f05bdb4e62203d44", size = 204546, upload-time = "2025-11-09T20:47:40.47Z" }, + { url = "https://files.pythonhosted.org/packages/1c/c7/6659f537f9562d963488e3e55573498a442503ced01f7e169e96a6110383/jiter-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e8269062060212b373316fe69236096aaf4c49022d267c6736eebd66bbbc60bb", size = 205196, upload-time = "2025-11-09T20:47:41.794Z" }, + { url = "https://files.pythonhosted.org/packages/21/f4/935304f5169edadfec7f9c01eacbce4c90bb9a82035ac1de1f3bd2d40be6/jiter-0.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:06cb970936c65de926d648af0ed3d21857f026b1cf5525cb2947aa5e01e05789", size = 186100, upload-time = "2025-11-09T20:47:43.007Z" }, + { url = "https://files.pythonhosted.org/packages/3d/a6/97209693b177716e22576ee1161674d1d58029eb178e01866a0422b69224/jiter-0.12.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6cc49d5130a14b732e0612bc76ae8db3b49898732223ef8b7599aa8d9810683e", size = 313658, upload-time = "2025-11-09T20:47:44.424Z" }, + { url = "https://files.pythonhosted.org/packages/06/4d/125c5c1537c7d8ee73ad3d530a442d6c619714b95027143f1b61c0b4dfe0/jiter-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:37f27a32ce36364d2fa4f7fdc507279db604d27d239ea2e044c8f148410defe1", size = 318605, upload-time = "2025-11-09T20:47:45.973Z" }, + { url = "https://files.pythonhosted.org/packages/99/bf/a840b89847885064c41a5f52de6e312e91fa84a520848ee56c97e4fa0205/jiter-0.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbc0944aa3d4b4773e348cda635252824a78f4ba44328e042ef1ff3f6080d1cf", size = 349803, upload-time = "2025-11-09T20:47:47.535Z" }, + { url = "https://files.pythonhosted.org/packages/8a/88/e63441c28e0db50e305ae23e19c1d8fae012d78ed55365da392c1f34b09c/jiter-0.12.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da25c62d4ee1ffbacb97fac6dfe4dcd6759ebdc9015991e92a6eae5816287f44", size = 365120, upload-time = "2025-11-09T20:47:49.284Z" }, + { url = "https://files.pythonhosted.org/packages/0a/7c/49b02714af4343970eb8aca63396bc1c82fa01197dbb1e9b0d274b550d4e/jiter-0.12.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:048485c654b838140b007390b8182ba9774621103bd4d77c9c3f6f117474ba45", size = 479918, upload-time = "2025-11-09T20:47:50.807Z" }, + { url = "https://files.pythonhosted.org/packages/69/ba/0a809817fdd5a1db80490b9150645f3aae16afad166960bcd562be194f3b/jiter-0.12.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:635e737fbb7315bef0037c19b88b799143d2d7d3507e61a76751025226b3ac87", size = 379008, upload-time = "2025-11-09T20:47:52.211Z" }, + { url = "https://files.pythonhosted.org/packages/5f/c3/c9fc0232e736c8877d9e6d83d6eeb0ba4e90c6c073835cc2e8f73fdeef51/jiter-0.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e017c417b1ebda911bd13b1e40612704b1f5420e30695112efdbed8a4b389ed", size = 361785, upload-time = "2025-11-09T20:47:53.512Z" }, + { url = "https://files.pythonhosted.org/packages/96/61/61f69b7e442e97ca6cd53086ddc1cf59fb830549bc72c0a293713a60c525/jiter-0.12.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:89b0bfb8b2bf2351fba36bb211ef8bfceba73ef58e7f0c68fb67b5a2795ca2f9", size = 386108, upload-time = "2025-11-09T20:47:54.893Z" }, + { url = "https://files.pythonhosted.org/packages/e9/2e/76bb3332f28550c8f1eba3bf6e5efe211efda0ddbbaf24976bc7078d42a5/jiter-0.12.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:f5aa5427a629a824a543672778c9ce0c5e556550d1569bb6ea28a85015287626", size = 519937, upload-time = "2025-11-09T20:47:56.253Z" }, + { url = "https://files.pythonhosted.org/packages/84/d6/fa96efa87dc8bff2094fb947f51f66368fa56d8d4fc9e77b25d7fbb23375/jiter-0.12.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed53b3d6acbcb0fd0b90f20c7cb3b24c357fe82a3518934d4edfa8c6898e498c", size = 510853, upload-time = "2025-11-09T20:47:58.32Z" }, + { url = "https://files.pythonhosted.org/packages/8a/28/93f67fdb4d5904a708119a6ab58a8f1ec226ff10a94a282e0215402a8462/jiter-0.12.0-cp313-cp313-win32.whl", hash = "sha256:4747de73d6b8c78f2e253a2787930f4fffc68da7fa319739f57437f95963c4de", size = 204699, upload-time = "2025-11-09T20:47:59.686Z" }, + { url = "https://files.pythonhosted.org/packages/c4/1f/30b0eb087045a0abe2a5c9c0c0c8da110875a1d3be83afd4a9a4e548be3c/jiter-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:e25012eb0c456fcc13354255d0338cd5397cce26c77b2832b3c4e2e255ea5d9a", size = 204258, upload-time = "2025-11-09T20:48:01.01Z" }, + { url = "https://files.pythonhosted.org/packages/2c/f4/2b4daf99b96bce6fc47971890b14b2a36aef88d7beb9f057fafa032c6141/jiter-0.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:c97b92c54fe6110138c872add030a1f99aea2401ddcdaa21edf74705a646dd60", size = 185503, upload-time = "2025-11-09T20:48:02.35Z" }, + { url = "https://files.pythonhosted.org/packages/39/ca/67bb15a7061d6fe20b9b2a2fd783e296a1e0f93468252c093481a2f00efa/jiter-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:53839b35a38f56b8be26a7851a48b89bc47e5d88e900929df10ed93b95fea3d6", size = 317965, upload-time = "2025-11-09T20:48:03.783Z" }, + { url = "https://files.pythonhosted.org/packages/18/af/1788031cd22e29c3b14bc6ca80b16a39a0b10e611367ffd480c06a259831/jiter-0.12.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94f669548e55c91ab47fef8bddd9c954dab1938644e715ea49d7e117015110a4", size = 345831, upload-time = "2025-11-09T20:48:05.55Z" }, + { url = "https://files.pythonhosted.org/packages/05/17/710bf8472d1dff0d3caf4ced6031060091c1320f84ee7d5dcbed1f352417/jiter-0.12.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:351d54f2b09a41600ffea43d081522d792e81dcfb915f6d2d242744c1cc48beb", size = 361272, upload-time = "2025-11-09T20:48:06.951Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f1/1dcc4618b59761fef92d10bcbb0b038b5160be653b003651566a185f1a5c/jiter-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2a5e90604620f94bf62264e7c2c038704d38217b7465b863896c6d7c902b06c7", size = 204604, upload-time = "2025-11-09T20:48:08.328Z" }, + { url = "https://files.pythonhosted.org/packages/d9/32/63cb1d9f1c5c6632a783c0052cde9ef7ba82688f7065e2f0d5f10a7e3edb/jiter-0.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:88ef757017e78d2860f96250f9393b7b577b06a956ad102c29c8237554380db3", size = 185628, upload-time = "2025-11-09T20:48:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/a8/99/45c9f0dbe4a1416b2b9a8a6d1236459540f43d7fb8883cff769a8db0612d/jiter-0.12.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c46d927acd09c67a9fb1416df45c5a04c27e83aae969267e98fba35b74e99525", size = 312478, upload-time = "2025-11-09T20:48:10.898Z" }, + { url = "https://files.pythonhosted.org/packages/4c/a7/54ae75613ba9e0f55fcb0bc5d1f807823b5167cc944e9333ff322e9f07dd/jiter-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:774ff60b27a84a85b27b88cd5583899c59940bcc126caca97eb2a9df6aa00c49", size = 318706, upload-time = "2025-11-09T20:48:12.266Z" }, + { url = "https://files.pythonhosted.org/packages/59/31/2aa241ad2c10774baf6c37f8b8e1f39c07db358f1329f4eb40eba179c2a2/jiter-0.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5433fab222fb072237df3f637d01b81f040a07dcac1cb4a5c75c7aa9ed0bef1", size = 351894, upload-time = "2025-11-09T20:48:13.673Z" }, + { url = "https://files.pythonhosted.org/packages/54/4f/0f2759522719133a9042781b18cc94e335b6d290f5e2d3e6899d6af933e3/jiter-0.12.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8c593c6e71c07866ec6bfb790e202a833eeec885022296aff6b9e0b92d6a70e", size = 365714, upload-time = "2025-11-09T20:48:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/dc/6f/806b895f476582c62a2f52c453151edd8a0fde5411b0497baaa41018e878/jiter-0.12.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90d32894d4c6877a87ae00c6b915b609406819dce8bc0d4e962e4de2784e567e", size = 478989, upload-time = "2025-11-09T20:48:16.706Z" }, + { url = "https://files.pythonhosted.org/packages/86/6c/012d894dc6e1033acd8db2b8346add33e413ec1c7c002598915278a37f79/jiter-0.12.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:798e46eed9eb10c3adbbacbd3bdb5ecd4cf7064e453d00dbef08802dae6937ff", size = 378615, upload-time = "2025-11-09T20:48:18.614Z" }, + { url = "https://files.pythonhosted.org/packages/87/30/d718d599f6700163e28e2c71c0bbaf6dace692e7df2592fd793ac9276717/jiter-0.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3f1368f0a6719ea80013a4eb90ba72e75d7ea67cfc7846db2ca504f3df0169a", size = 364745, upload-time = "2025-11-09T20:48:20.117Z" }, + { url = "https://files.pythonhosted.org/packages/8f/85/315b45ce4b6ddc7d7fceca24068543b02bdc8782942f4ee49d652e2cc89f/jiter-0.12.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65f04a9d0b4406f7e51279710b27484af411896246200e461d80d3ba0caa901a", size = 386502, upload-time = "2025-11-09T20:48:21.543Z" }, + { url = "https://files.pythonhosted.org/packages/74/0b/ce0434fb40c5b24b368fe81b17074d2840748b4952256bab451b72290a49/jiter-0.12.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:fd990541982a24281d12b67a335e44f117e4c6cbad3c3b75c7dea68bf4ce3a67", size = 519845, upload-time = "2025-11-09T20:48:22.964Z" }, + { url = "https://files.pythonhosted.org/packages/e8/a3/7a7a4488ba052767846b9c916d208b3ed114e3eb670ee984e4c565b9cf0d/jiter-0.12.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:b111b0e9152fa7df870ecaebb0bd30240d9f7fff1f2003bcb4ed0f519941820b", size = 510701, upload-time = "2025-11-09T20:48:24.483Z" }, + { url = "https://files.pythonhosted.org/packages/c3/16/052ffbf9d0467b70af24e30f91e0579e13ded0c17bb4a8eb2aed3cb60131/jiter-0.12.0-cp314-cp314-win32.whl", hash = "sha256:a78befb9cc0a45b5a5a0d537b06f8544c2ebb60d19d02c41ff15da28a9e22d42", size = 205029, upload-time = "2025-11-09T20:48:25.749Z" }, + { url = "https://files.pythonhosted.org/packages/e4/18/3cf1f3f0ccc789f76b9a754bdb7a6977e5d1d671ee97a9e14f7eb728d80e/jiter-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:e1fe01c082f6aafbe5c8faf0ff074f38dfb911d53f07ec333ca03f8f6226debf", size = 204960, upload-time = "2025-11-09T20:48:27.415Z" }, + { url = "https://files.pythonhosted.org/packages/02/68/736821e52ecfdeeb0f024b8ab01b5a229f6b9293bbdb444c27efade50b0f/jiter-0.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:d72f3b5a432a4c546ea4bedc84cce0c3404874f1d1676260b9c7f048a9855451", size = 185529, upload-time = "2025-11-09T20:48:29.125Z" }, + { url = "https://files.pythonhosted.org/packages/30/61/12ed8ee7a643cce29ac97c2281f9ce3956eb76b037e88d290f4ed0d41480/jiter-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e6ded41aeba3603f9728ed2b6196e4df875348ab97b28fc8afff115ed42ba7a7", size = 318974, upload-time = "2025-11-09T20:48:30.87Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c6/f3041ede6d0ed5e0e79ff0de4c8f14f401bbf196f2ef3971cdbe5fd08d1d/jiter-0.12.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a947920902420a6ada6ad51892082521978e9dd44a802663b001436e4b771684", size = 345932, upload-time = "2025-11-09T20:48:32.658Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5d/4d94835889edd01ad0e2dbfc05f7bdfaed46292e7b504a6ac7839aa00edb/jiter-0.12.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:add5e227e0554d3a52cf390a7635edaffdf4f8fce4fdbcef3cc2055bb396a30c", size = 367243, upload-time = "2025-11-09T20:48:34.093Z" }, + { url = "https://files.pythonhosted.org/packages/fd/76/0051b0ac2816253a99d27baf3dda198663aff882fa6ea7deeb94046da24e/jiter-0.12.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9b1cda8fcb736250d7e8711d4580ebf004a46771432be0ae4796944b5dfa5d", size = 479315, upload-time = "2025-11-09T20:48:35.507Z" }, + { url = "https://files.pythonhosted.org/packages/70/ae/83f793acd68e5cb24e483f44f482a1a15601848b9b6f199dacb970098f77/jiter-0.12.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deeb12a2223fe0135c7ff1356a143d57f95bbf1f4a66584f1fc74df21d86b993", size = 380714, upload-time = "2025-11-09T20:48:40.014Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/4808a88338ad2c228b1126b93fcd8ba145e919e886fe910d578230dabe3b/jiter-0.12.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c596cc0f4cb574877550ce4ecd51f8037469146addd676d7c1a30ebe6391923f", size = 365168, upload-time = "2025-11-09T20:48:41.462Z" }, + { url = "https://files.pythonhosted.org/packages/0c/d4/04619a9e8095b42aef436b5aeb4c0282b4ff1b27d1db1508df9f5dc82750/jiter-0.12.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ab4c823b216a4aeab3fdbf579c5843165756bd9ad87cc6b1c65919c4715f783", size = 387893, upload-time = "2025-11-09T20:48:42.921Z" }, + { url = "https://files.pythonhosted.org/packages/17/ea/d3c7e62e4546fdc39197fa4a4315a563a89b95b6d54c0d25373842a59cbe/jiter-0.12.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e427eee51149edf962203ff8db75a7514ab89be5cb623fb9cea1f20b54f1107b", size = 520828, upload-time = "2025-11-09T20:48:44.278Z" }, + { url = "https://files.pythonhosted.org/packages/cc/0b/c6d3562a03fd767e31cb119d9041ea7958c3c80cb3d753eafb19b3b18349/jiter-0.12.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:edb868841f84c111255ba5e80339d386d937ec1fdce419518ce1bd9370fac5b6", size = 511009, upload-time = "2025-11-09T20:48:45.726Z" }, + { url = "https://files.pythonhosted.org/packages/aa/51/2cb4468b3448a8385ebcd15059d325c9ce67df4e2758d133ab9442b19834/jiter-0.12.0-cp314-cp314t-win32.whl", hash = "sha256:8bbcfe2791dfdb7c5e48baf646d37a6a3dcb5a97a032017741dea9f817dca183", size = 205110, upload-time = "2025-11-09T20:48:47.033Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c5/ae5ec83dec9c2d1af805fd5fe8f74ebded9c8670c5210ec7820ce0dbeb1e/jiter-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2fa940963bf02e1d8226027ef461e36af472dea85d36054ff835aeed944dd873", size = 205223, upload-time = "2025-11-09T20:48:49.076Z" }, + { url = "https://files.pythonhosted.org/packages/97/9a/3c5391907277f0e55195550cf3fa8e293ae9ee0c00fb402fec1e38c0c82f/jiter-0.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:506c9708dd29b27288f9f8f1140c3cb0e3d8ddb045956d7757b1fa0e0f39a473", size = 185564, upload-time = "2025-11-09T20:48:50.376Z" }, + { url = "https://files.pythonhosted.org/packages/cb/f5/12efb8ada5f5c9edc1d4555fe383c1fb2eac05ac5859258a72d61981d999/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:e8547883d7b96ef2e5fe22b88f8a4c8725a56e7f4abafff20fd5272d634c7ecb", size = 309974, upload-time = "2025-11-09T20:49:17.187Z" }, + { url = "https://files.pythonhosted.org/packages/85/15/d6eb3b770f6a0d332675141ab3962fd4a7c270ede3515d9f3583e1d28276/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:89163163c0934854a668ed783a2546a0617f71706a2551a4a0666d91ab365d6b", size = 304233, upload-time = "2025-11-09T20:49:18.734Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3e/e7e06743294eea2cf02ced6aa0ff2ad237367394e37a0e2b4a1108c67a36/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d96b264ab7d34bbb2312dedc47ce07cd53f06835eacbc16dde3761f47c3a9e7f", size = 338537, upload-time = "2025-11-09T20:49:20.317Z" }, + { url = "https://files.pythonhosted.org/packages/2f/9c/6753e6522b8d0ef07d3a3d239426669e984fb0eba15a315cdbc1253904e4/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24e864cb30ab82311c6425655b0cdab0a98c5d973b065c66a3f020740c2324c", size = 346110, upload-time = "2025-11-09T20:49:21.817Z" }, +] + +[[package]] +name = "jmespath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, +] + +[[package]] +name = "joblib" +version = "1.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" }, +] + +[[package]] +name = "json5" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/77/e8/a3f261a66e4663f22700bc8a17c08cb83e91fbf086726e7a228398968981/json5-0.13.0.tar.gz", hash = "sha256:b1edf8d487721c0bf64d83c28e91280781f6e21f4a797d3261c7c828d4c165bf", size = 52441, upload-time = "2026-01-01T19:42:14.99Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl", hash = "sha256:9a08e1dd65f6a4d4c6fa82d216cf2477349ec2346a38fd70cc11d2557499fbcc", size = 36163, upload-time = "2026-01-01T19:42:13.962Z" }, +] + +[[package]] +name = "jsonpatch" +version = "1.33" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpointer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade", size = 12898, upload-time = "2023-06-16T21:01:28.466Z" }, +] + +[[package]] +name = "jsonpointer" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, +] + +[package.optional-dependencies] +format-nongpl = [ + { name = "fqdn" }, + { name = "idna" }, + { name = "isoduration" }, + { name = "jsonpointer" }, + { name = "rfc3339-validator" }, + { name = "rfc3986-validator" }, + { name = "rfc3987-syntax" }, + { name = "uri-template" }, + { name = "webcolors" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "jupyter" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipykernel" }, + { name = "ipywidgets" }, + { name = "jupyter-console" }, + { name = "jupyterlab" }, + { name = "nbconvert" }, + { name = "notebook" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, +] + +[[package]] +name = "jupyter-client" +version = "8.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-core" }, + { name = "python-dateutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/e4/ba649102a3bc3fbca54e7239fb924fd434c766f855693d86de0b1f2bec81/jupyter_client-8.8.0.tar.gz", hash = "sha256:d556811419a4f2d96c869af34e854e3f059b7cc2d6d01a9cd9c85c267691be3e", size = 348020, upload-time = "2026-01-08T13:55:47.938Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl", hash = "sha256:f93a5b99c5e23a507b773d3a1136bd6e16c67883ccdbd9a829b0bbdb98cd7d7a", size = 107371, upload-time = "2026-01-08T13:55:45.562Z" }, +] + +[[package]] +name = "jupyter-console" +version = "6.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipykernel" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "pyzmq" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, +] + +[[package]] +name = "jupyter-core" +version = "5.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "platformdirs" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, +] + +[[package]] +name = "jupyter-events" +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema", extra = ["format-nongpl"] }, + { name = "packaging" }, + { name = "python-json-logger" }, + { name = "pyyaml" }, + { name = "referencing" }, + { name = "rfc3339-validator" }, + { name = "rfc3986-validator" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" }, +] + +[[package]] +name = "jupyter-lsp" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823, upload-time = "2025-08-27T17:47:34.671Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687, upload-time = "2025-08-27T17:47:33.15Z" }, +] + +[[package]] +name = "jupyter-server" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "argon2-cffi" }, + { name = "jinja2" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "jupyter-events" }, + { name = "jupyter-server-terminals" }, + { name = "nbconvert" }, + { name = "nbformat" }, + { name = "packaging" }, + { name = "prometheus-client" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "pyzmq" }, + { name = "send2trash" }, + { name = "terminado" }, + { name = "tornado" }, + { name = "traitlets" }, + { name = "websocket-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949, upload-time = "2025-08-21T14:42:54.042Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221, upload-time = "2025-08-21T14:42:52.034Z" }, +] + +[[package]] +name = "jupyter-server-terminals" +version = "0.5.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "terminado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430, upload-time = "2024-03-12T14:37:03.049Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656, upload-time = "2024-03-12T14:37:00.708Z" }, +] + +[[package]] +name = "jupyterlab" +version = "4.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "async-lru" }, + { name = "httpx" }, + { name = "ipykernel" }, + { name = "jinja2" }, + { name = "jupyter-core" }, + { name = "jupyter-lsp" }, + { name = "jupyter-server" }, + { name = "jupyterlab-server" }, + { name = "notebook-shim" }, + { name = "packaging" }, + { name = "setuptools" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/21/413d142686a4e8f4268d985becbdb4daf060524726248e73be4773786987/jupyterlab-4.5.1.tar.gz", hash = "sha256:09da1ddfbd9eec18b5101dbb8515612aa1e47443321fb99503725a88e93d20d9", size = 23992251, upload-time = "2025-12-15T16:58:59.361Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/c3/acced767eecc11a70c65c45295db5396c4f0c1937874937d5a76d7b177b6/jupyterlab-4.5.1-py3-none-any.whl", hash = "sha256:31b059de96de0754ff1f2ce6279774b6aab8c34d7082e9752db58207c99bd514", size = 12384821, upload-time = "2025-12-15T16:58:55.563Z" }, +] + +[[package]] +name = "jupyterlab-pygments" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, +] + +[[package]] +name = "jupyterlab-server" +version = "2.28.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "jinja2" }, + { name = "json5" }, + { name = "jsonschema" }, + { name = "jupyter-server" }, + { name = "packaging" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996, upload-time = "2025-10-22T13:59:18.37Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830, upload-time = "2025-10-22T13:59:16.767Z" }, +] + +[[package]] +name = "jupyterlab-widgets" +version = "3.0.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423, upload-time = "2025-11-01T21:11:29.724Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" }, +] + +[[package]] +name = "langchain" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/f0/9b4a23b59fbf2c61d8590bb58ef1c7428132602cdceef0430dd82706b2e9/langchain-1.2.2.tar.gz", hash = "sha256:3f49321cfbf821b3f541aa8a504c35b48ef5e9518a948efa8eeb20cb16eb95a8", size = 546512, upload-time = "2026-01-07T22:53:54.861Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/51/671b998b8b828603d7c3af854295a73f08731ff06e15dd94cdb68db5ee82/langchain-1.2.2-py3-none-any.whl", hash = "sha256:1aed3d6a3d7180d0db9b8789f38ea1c4f8c883248e86501ed580e7f5c3ca939f", size = 105837, upload-time = "2026-01-07T22:53:53.944Z" }, +] + +[[package]] +name = "langchain-aws" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "boto3" }, + { name = "langchain-core" }, + { name = "numpy" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cc/1a/fc980e450ca748fa4ca62b450e636e6d2abd6401b300cd44743edf8e407b/langchain_aws-1.2.0.tar.gz", hash = "sha256:d208c218c930fcd48cab877dc97670a1c938e4fe3a0287ea3e5409f77a8b744a", size = 405345, upload-time = "2025-12-31T22:19:01.235Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/78/8b6b809fef93489e90f80959990b671ba515868abb43dc6411b05f43243b/langchain_aws-1.2.0-py3-none-any.whl", hash = "sha256:4848a7b620a56c7a8febbedf5aee043c62672341e57dccfed680c2fce3ca0cab", size = 153539, upload-time = "2025-12-31T22:18:59.906Z" }, +] + +[[package]] +name = "langchain-classic" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langchain-text-splitters" }, + { name = "langsmith" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "sqlalchemy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/4b/bd03518418ece4c13192a504449b58c28afee915dc4a6f4b02622458cb1b/langchain_classic-1.0.1.tar.gz", hash = "sha256:40a499684df36b005a1213735dc7f8dca8f5eb67978d6ec763e7a49780864fdc", size = 10516020, upload-time = "2025-12-23T22:55:22.615Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/0f/eab87f017d7fe28e8c11fff614f4cdbfae32baadb77d0f79e9f922af1df2/langchain_classic-1.0.1-py3-none-any.whl", hash = "sha256:131d83a02bb80044c68fedc1ab4ae885d5b8f8c2c742d8ab9e7534ad9cda8e80", size = 1040666, upload-time = "2025-12-23T22:55:21.025Z" }, +] + +[[package]] +name = "langchain-community" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "dataclasses-json" }, + { name = "httpx-sse" }, + { name = "langchain-classic" }, + { name = "langchain-core" }, + { name = "langsmith" }, + { name = "numpy" }, + { name = "pydantic-settings" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "sqlalchemy" }, + { name = "tenacity" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/53/97/a03585d42b9bdb6fbd935282d6e3348b10322a24e6ce12d0c99eb461d9af/langchain_community-0.4.1.tar.gz", hash = "sha256:f3b211832728ee89f169ddce8579b80a085222ddb4f4ed445a46e977d17b1e85", size = 33241144, upload-time = "2025-10-27T15:20:32.504Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/a4/c4fde67f193401512337456cabc2148f2c43316e445f5decd9f8806e2992/langchain_community-0.4.1-py3-none-any.whl", hash = "sha256:2135abb2c7748a35c84613108f7ebf30f8505b18c3c18305ffaecfc7651f6c6a", size = 2533285, upload-time = "2025-10-27T15:20:30.767Z" }, +] + +[[package]] +name = "langchain-core" +version = "1.2.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpatch" }, + { name = "langsmith" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "tenacity" }, + { name = "typing-extensions" }, + { name = "uuid-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/ce/ba5ed5ea6df22965b2893c2ed28ebb456204962723d408904c4acfa5e942/langchain_core-1.2.6.tar.gz", hash = "sha256:b4e7841dd7f8690375aa07c54739178dc2c635147d475e0c2955bf82a1afa498", size = 833343, upload-time = "2026-01-02T21:35:44.749Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/40/0655892c245d8fbe6bca6d673ab5927e5c3ab7be143de40b52289a0663bc/langchain_core-1.2.6-py3-none-any.whl", hash = "sha256:aa6ed954b4b1f4504937fe75fdf674317027e9a91ba7a97558b0de3dc8004e34", size = 489096, upload-time = "2026-01-02T21:35:43.391Z" }, +] + +[[package]] +name = "langchain-text-splitters" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/41/42/c178dcdc157b473330eb7cc30883ea69b8ec60078c7b85e2d521054c4831/langchain_text_splitters-1.1.0.tar.gz", hash = "sha256:75e58acb7585dc9508f3cd9d9809cb14751283226c2d6e21fb3a9ae57582ca22", size = 272230, upload-time = "2025-12-14T01:15:38.659Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/1a/a84ed1c046deecf271356b0179c1b9fba95bfdaa6f934e1849dee26fad7b/langchain_text_splitters-1.1.0-py3-none-any.whl", hash = "sha256:f00341fe883358786104a5f881375ac830a4dd40253ecd42b4c10536c6e4693f", size = 34182, upload-time = "2025-12-14T01:15:37.382Z" }, +] + +[[package]] +name = "langchainhub" +version = "0.1.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "requests" }, + { name = "types-requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/50/76719d356d80b00761d9680e3eb5df0f5ca8587e79b60ae6dcb678828cdd/langchainhub-0.1.21.tar.gz", hash = "sha256:723383b3964a47dbaea6ad5d0ef728accefbc9d2c07480e800bdec43510a8c10", size = 4481, upload-time = "2024-08-11T20:21:42.305Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/63/40328157ddee807991f2f1992c2ad88f479b2472dc9e40d08ccf10700735/langchainhub-0.1.21-py3-none-any.whl", hash = "sha256:1cc002dc31e0d132a776afd044361e2b698743df5202618cf2bad399246b895f", size = 5203, upload-time = "2024-08-11T20:21:40.892Z" }, +] + +[[package]] +name = "langgraph" +version = "1.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, + { name = "langgraph-prebuilt" }, + { name = "langgraph-sdk" }, + { name = "pydantic" }, + { name = "xxhash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/47/28f4d4d33d88f69de26f7a54065961ac0c662cec2479b36a2db081ef5cb6/langgraph-1.0.5.tar.gz", hash = "sha256:7f6ae59622386b60fe9fa0ad4c53f42016b668455ed604329e7dc7904adbf3f8", size = 493969, upload-time = "2025-12-12T23:05:48.224Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/23/1b/e318ee76e42d28f515d87356ac5bd7a7acc8bad3b8f54ee377bef62e1cbf/langgraph-1.0.5-py3-none-any.whl", hash = "sha256:b4cfd173dca3c389735b47228ad8b295e6f7b3df779aba3a1e0c23871f81281e", size = 157056, upload-time = "2025-12-12T23:05:46.499Z" }, +] + +[[package]] +name = "langgraph-checkpoint" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "ormsgpack" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0f/07/2b1c042fa87d40cf2db5ca27dc4e8dd86f9a0436a10aa4361a8982718ae7/langgraph_checkpoint-3.0.1.tar.gz", hash = "sha256:59222f875f85186a22c494aedc65c4e985a3df27e696e5016ba0b98a5ed2cee0", size = 137785, upload-time = "2025-11-04T21:55:47.774Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/e3/616e3a7ff737d98c1bbb5700dd62278914e2a9ded09a79a1fa93cf24ce12/langgraph_checkpoint-3.0.1-py3-none-any.whl", hash = "sha256:9b04a8d0edc0474ce4eaf30c5d731cee38f11ddff50a6177eead95b5c4e4220b", size = 46249, upload-time = "2025-11-04T21:55:46.472Z" }, +] + +[[package]] +name = "langgraph-prebuilt" +version = "1.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/f9/54f8891b32159e4542236817aea2ee83de0de18bce28e9bdba08c7f93001/langgraph_prebuilt-1.0.5.tar.gz", hash = "sha256:85802675ad778cc7240fd02d47db1e0b59c0c86d8369447d77ce47623845db2d", size = 144453, upload-time = "2025-11-20T16:47:39.23Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/5e/aeba4a5b39fe6e874e0dd003a82da71c7153e671312671a8dacc5cb7c1af/langgraph_prebuilt-1.0.5-py3-none-any.whl", hash = "sha256:22369563e1848862ace53fbc11b027c28dd04a9ac39314633bb95f2a7e258496", size = 35072, upload-time = "2025-11-20T16:47:38.187Z" }, +] + +[[package]] +name = "langgraph-sdk" +version = "0.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "orjson" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/d3/b6be0b0aba2a53a8920a2b0b4328a83121ec03eea9952e576d06a4182f6f/langgraph_sdk-0.3.1.tar.gz", hash = "sha256:f6dadfd2444eeff3e01405a9005c95fb3a028d4bd954ebec80ea6150084f92bb", size = 130312, upload-time = "2025-12-18T22:11:47.42Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/fe/0c1c9c01a154eba62b20b02fabe811fd94a2b810061ae9e4d8462b8cf85a/langgraph_sdk-0.3.1-py3-none-any.whl", hash = "sha256:0b856923bfd20bf3441ce9d03bef488aa333fb610e972618799a9d584436acad", size = 66517, upload-time = "2025-12-18T22:11:46.625Z" }, +] + +[[package]] +name = "langsmith" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "requests-toolbelt" }, + { name = "uuid-utils" }, + { name = "zstandard" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6f/a3/d36a9935fd1215e21d022a5773b243b6eec12ba11fde3eb8ba1f8384b01e/langsmith-0.6.1.tar.gz", hash = "sha256:bf35f9ffa592d602d5b11d23890d51342f321ac7f5e0cb6a22ab48fbdb88853a", size = 884701, upload-time = "2026-01-06T20:15:38.25Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/01/9a3f0ff60afcb30383ea9775e9f9a233c0127bad7c786d878f78b487bebb/langsmith-0.6.1-py3-none-any.whl", hash = "sha256:cad1f0a5cb8baf01490d2d90b7515d2cecc31648237bf070d2e6c0e7d58a2079", size = 282977, upload-time = "2026-01-06T20:15:36.579Z" }, +] + +[[package]] +name = "lark" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732, upload-time = "2025-10-27T18:25:56.653Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, +] + +[[package]] +name = "librt" +version = "0.7.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/29/47f29026ca17f35cf299290292d5f8331f5077364974b7675a353179afa2/librt-0.7.7.tar.gz", hash = "sha256:81d957b069fed1890953c3b9c3895c7689960f233eea9a1d9607f71ce7f00b2c", size = 145910, upload-time = "2026-01-01T23:52:22.87Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/72/1cd9d752070011641e8aee046c851912d5f196ecd726fffa7aed2070f3e0/librt-0.7.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2a85a1fc4ed11ea0eb0a632459ce004a2d14afc085a50ae3463cd3dfe1ce43fc", size = 55687, upload-time = "2026-01-01T23:51:16.291Z" }, + { url = "https://files.pythonhosted.org/packages/50/aa/d5a1d4221c4fe7e76ae1459d24d6037783cb83c7645164c07d7daf1576ec/librt-0.7.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c87654e29a35938baead1c4559858f346f4a2a7588574a14d784f300ffba0efd", size = 57136, upload-time = "2026-01-01T23:51:17.363Z" }, + { url = "https://files.pythonhosted.org/packages/23/6f/0c86b5cb5e7ef63208c8cc22534df10ecc5278efc0d47fb8815577f3ca2f/librt-0.7.7-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c9faaebb1c6212c20afd8043cd6ed9de0a47d77f91a6b5b48f4e46ed470703fe", size = 165320, upload-time = "2026-01-01T23:51:18.455Z" }, + { url = "https://files.pythonhosted.org/packages/16/37/df4652690c29f645ffe405b58285a4109e9fe855c5bb56e817e3e75840b3/librt-0.7.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1908c3e5a5ef86b23391448b47759298f87f997c3bd153a770828f58c2bb4630", size = 174216, upload-time = "2026-01-01T23:51:19.599Z" }, + { url = "https://files.pythonhosted.org/packages/9a/d6/d3afe071910a43133ec9c0f3e4ce99ee6df0d4e44e4bddf4b9e1c6ed41cc/librt-0.7.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dbc4900e95a98fc0729523be9d93a8fedebb026f32ed9ffc08acd82e3e181503", size = 189005, upload-time = "2026-01-01T23:51:21.052Z" }, + { url = "https://files.pythonhosted.org/packages/d5/18/74060a870fe2d9fd9f47824eba6717ce7ce03124a0d1e85498e0e7efc1b2/librt-0.7.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a7ea4e1fbd253e5c68ea0fe63d08577f9d288a73f17d82f652ebc61fa48d878d", size = 183961, upload-time = "2026-01-01T23:51:22.493Z" }, + { url = "https://files.pythonhosted.org/packages/7c/5e/918a86c66304af66a3c1d46d54df1b2d0b8894babc42a14fb6f25511497f/librt-0.7.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ef7699b7a5a244b1119f85c5bbc13f152cd38240cbb2baa19b769433bae98e50", size = 177610, upload-time = "2026-01-01T23:51:23.874Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d7/b5e58dc2d570f162e99201b8c0151acf40a03a39c32ab824dd4febf12736/librt-0.7.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:955c62571de0b181d9e9e0a0303c8bc90d47670a5eff54cf71bf5da61d1899cf", size = 199272, upload-time = "2026-01-01T23:51:25.341Z" }, + { url = "https://files.pythonhosted.org/packages/18/87/8202c9bd0968bdddc188ec3811985f47f58ed161b3749299f2c0dd0f63fb/librt-0.7.7-cp312-cp312-win32.whl", hash = "sha256:1bcd79be209313b270b0e1a51c67ae1af28adad0e0c7e84c3ad4b5cb57aaa75b", size = 43189, upload-time = "2026-01-01T23:51:26.799Z" }, + { url = "https://files.pythonhosted.org/packages/61/8d/80244b267b585e7aa79ffdac19f66c4861effc3a24598e77909ecdd0850e/librt-0.7.7-cp312-cp312-win_amd64.whl", hash = "sha256:4353ee891a1834567e0302d4bd5e60f531912179578c36f3d0430f8c5e16b456", size = 49462, upload-time = "2026-01-01T23:51:27.813Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1f/75db802d6a4992d95e8a889682601af9b49d5a13bbfa246d414eede1b56c/librt-0.7.7-cp312-cp312-win_arm64.whl", hash = "sha256:a76f1d679beccccdf8c1958e732a1dfcd6e749f8821ee59d7bec009ac308c029", size = 42828, upload-time = "2026-01-01T23:51:28.804Z" }, + { url = "https://files.pythonhosted.org/packages/8d/5e/d979ccb0a81407ec47c14ea68fb217ff4315521730033e1dd9faa4f3e2c1/librt-0.7.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f4a0b0a3c86ba9193a8e23bb18f100d647bf192390ae195d84dfa0a10fb6244", size = 55746, upload-time = "2026-01-01T23:51:29.828Z" }, + { url = "https://files.pythonhosted.org/packages/f5/2c/3b65861fb32f802c3783d6ac66fc5589564d07452a47a8cf9980d531cad3/librt-0.7.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5335890fea9f9e6c4fdf8683061b9ccdcbe47c6dc03ab8e9b68c10acf78be78d", size = 57174, upload-time = "2026-01-01T23:51:31.226Z" }, + { url = "https://files.pythonhosted.org/packages/50/df/030b50614b29e443607220097ebaf438531ea218c7a9a3e21ea862a919cd/librt-0.7.7-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9b4346b1225be26def3ccc6c965751c74868f0578cbcba293c8ae9168483d811", size = 165834, upload-time = "2026-01-01T23:51:32.278Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e1/bd8d1eacacb24be26a47f157719553bbd1b3fe812c30dddf121c0436fd0b/librt-0.7.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a10b8eebdaca6e9fdbaf88b5aefc0e324b763a5f40b1266532590d5afb268a4c", size = 174819, upload-time = "2026-01-01T23:51:33.461Z" }, + { url = "https://files.pythonhosted.org/packages/46/7d/91d6c3372acf54a019c1ad8da4c9ecf4fc27d039708880bf95f48dbe426a/librt-0.7.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:067be973d90d9e319e6eb4ee2a9b9307f0ecd648b8a9002fa237289a4a07a9e7", size = 189607, upload-time = "2026-01-01T23:51:34.604Z" }, + { url = "https://files.pythonhosted.org/packages/fa/ac/44604d6d3886f791fbd1c6ae12d5a782a8f4aca927484731979f5e92c200/librt-0.7.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:23d2299ed007812cccc1ecef018db7d922733382561230de1f3954db28433977", size = 184586, upload-time = "2026-01-01T23:51:35.845Z" }, + { url = "https://files.pythonhosted.org/packages/5c/26/d8a6e4c17117b7f9b83301319d9a9de862ae56b133efb4bad8b3aa0808c9/librt-0.7.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6b6f8ea465524aa4c7420c7cc4ca7d46fe00981de8debc67b1cc2e9957bb5b9d", size = 178251, upload-time = "2026-01-01T23:51:37.018Z" }, + { url = "https://files.pythonhosted.org/packages/99/ab/98d857e254376f8e2f668e807daccc1f445e4b4fc2f6f9c1cc08866b0227/librt-0.7.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8df32a99cc46eb0ee90afd9ada113ae2cafe7e8d673686cf03ec53e49635439", size = 199853, upload-time = "2026-01-01T23:51:38.195Z" }, + { url = "https://files.pythonhosted.org/packages/7c/55/4523210d6ae5134a5da959900be43ad8bab2e4206687b6620befddb5b5fd/librt-0.7.7-cp313-cp313-win32.whl", hash = "sha256:86f86b3b785487c7760247bcdac0b11aa8bf13245a13ed05206286135877564b", size = 43247, upload-time = "2026-01-01T23:51:39.629Z" }, + { url = "https://files.pythonhosted.org/packages/25/40/3ec0fed5e8e9297b1cf1a3836fb589d3de55f9930e3aba988d379e8ef67c/librt-0.7.7-cp313-cp313-win_amd64.whl", hash = "sha256:4862cb2c702b1f905c0503b72d9d4daf65a7fdf5a9e84560e563471e57a56949", size = 49419, upload-time = "2026-01-01T23:51:40.674Z" }, + { url = "https://files.pythonhosted.org/packages/1c/7a/aab5f0fb122822e2acbc776addf8b9abfb4944a9056c00c393e46e543177/librt-0.7.7-cp313-cp313-win_arm64.whl", hash = "sha256:0996c83b1cb43c00e8c87835a284f9057bc647abd42b5871e5f941d30010c832", size = 42828, upload-time = "2026-01-01T23:51:41.731Z" }, + { url = "https://files.pythonhosted.org/packages/69/9c/228a5c1224bd23809a635490a162e9cbdc68d99f0eeb4a696f07886b8206/librt-0.7.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:23daa1ab0512bafdd677eb1bfc9611d8ffbe2e328895671e64cb34166bc1b8c8", size = 55188, upload-time = "2026-01-01T23:51:43.14Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c2/0e7c6067e2b32a156308205e5728f4ed6478c501947e9142f525afbc6bd2/librt-0.7.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:558a9e5a6f3cc1e20b3168fb1dc802d0d8fa40731f6e9932dcc52bbcfbd37111", size = 56895, upload-time = "2026-01-01T23:51:44.534Z" }, + { url = "https://files.pythonhosted.org/packages/0e/77/de50ff70c80855eb79d1d74035ef06f664dd073fb7fb9d9fb4429651b8eb/librt-0.7.7-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2567cb48dc03e5b246927ab35cbb343376e24501260a9b5e30b8e255dca0d1d2", size = 163724, upload-time = "2026-01-01T23:51:45.571Z" }, + { url = "https://files.pythonhosted.org/packages/6e/19/f8e4bf537899bdef9e0bb9f0e4b18912c2d0f858ad02091b6019864c9a6d/librt-0.7.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6066c638cdf85ff92fc6f932d2d73c93a0e03492cdfa8778e6d58c489a3d7259", size = 172470, upload-time = "2026-01-01T23:51:46.823Z" }, + { url = "https://files.pythonhosted.org/packages/42/4c/dcc575b69d99076768e8dd6141d9aecd4234cba7f0e09217937f52edb6ed/librt-0.7.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a609849aca463074c17de9cda173c276eb8fee9e441053529e7b9e249dc8b8ee", size = 186806, upload-time = "2026-01-01T23:51:48.009Z" }, + { url = "https://files.pythonhosted.org/packages/fe/f8/4094a2b7816c88de81239a83ede6e87f1138477d7ee956c30f136009eb29/librt-0.7.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:add4e0a000858fe9bb39ed55f31085506a5c38363e6eb4a1e5943a10c2bfc3d1", size = 181809, upload-time = "2026-01-01T23:51:49.35Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ac/821b7c0ab1b5a6cd9aee7ace8309c91545a2607185101827f79122219a7e/librt-0.7.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a3bfe73a32bd0bdb9a87d586b05a23c0a1729205d79df66dee65bb2e40d671ba", size = 175597, upload-time = "2026-01-01T23:51:50.636Z" }, + { url = "https://files.pythonhosted.org/packages/71/f9/27f6bfbcc764805864c04211c6ed636fe1d58f57a7b68d1f4ae5ed74e0e0/librt-0.7.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0ecce0544d3db91a40f8b57ae26928c02130a997b540f908cefd4d279d6c5848", size = 196506, upload-time = "2026-01-01T23:51:52.535Z" }, + { url = "https://files.pythonhosted.org/packages/46/ba/c9b9c6fc931dd7ea856c573174ccaf48714905b1a7499904db2552e3bbaf/librt-0.7.7-cp314-cp314-win32.whl", hash = "sha256:8f7a74cf3a80f0c3b0ec75b0c650b2f0a894a2cec57ef75f6f72c1e82cdac61d", size = 39747, upload-time = "2026-01-01T23:51:53.683Z" }, + { url = "https://files.pythonhosted.org/packages/c5/69/cd1269337c4cde3ee70176ee611ab0058aa42fc8ce5c9dce55f48facfcd8/librt-0.7.7-cp314-cp314-win_amd64.whl", hash = "sha256:3d1fe2e8df3268dd6734dba33ededae72ad5c3a859b9577bc00b715759c5aaab", size = 45971, upload-time = "2026-01-01T23:51:54.697Z" }, + { url = "https://files.pythonhosted.org/packages/79/fd/e0844794423f5583108c5991313c15e2b400995f44f6ec6871f8aaf8243c/librt-0.7.7-cp314-cp314-win_arm64.whl", hash = "sha256:2987cf827011907d3dfd109f1be0d61e173d68b1270107bb0e89f2fca7f2ed6b", size = 39075, upload-time = "2026-01-01T23:51:55.726Z" }, + { url = "https://files.pythonhosted.org/packages/42/02/211fd8f7c381e7b2a11d0fdfcd410f409e89967be2e705983f7c6342209a/librt-0.7.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8e92c8de62b40bfce91d5e12c6e8b15434da268979b1af1a6589463549d491e6", size = 57368, upload-time = "2026-01-01T23:51:56.706Z" }, + { url = "https://files.pythonhosted.org/packages/4c/b6/aca257affae73ece26041ae76032153266d110453173f67d7603058e708c/librt-0.7.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f683dcd49e2494a7535e30f779aa1ad6e3732a019d80abe1309ea91ccd3230e3", size = 59238, upload-time = "2026-01-01T23:51:58.066Z" }, + { url = "https://files.pythonhosted.org/packages/96/47/7383a507d8e0c11c78ca34c9d36eab9000db5989d446a2f05dc40e76c64f/librt-0.7.7-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9b15e5d17812d4d629ff576699954f74e2cc24a02a4fc401882dd94f81daba45", size = 183870, upload-time = "2026-01-01T23:51:59.204Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b8/50f3d8eec8efdaf79443963624175c92cec0ba84827a66b7fcfa78598e51/librt-0.7.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c084841b879c4d9b9fa34e5d5263994f21aea7fd9c6add29194dbb41a6210536", size = 194608, upload-time = "2026-01-01T23:52:00.419Z" }, + { url = "https://files.pythonhosted.org/packages/23/d9/1b6520793aadb59d891e3b98ee057a75de7f737e4a8b4b37fdbecb10d60f/librt-0.7.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10c8fb9966f84737115513fecbaf257f9553d067a7dd45a69c2c7e5339e6a8dc", size = 206776, upload-time = "2026-01-01T23:52:01.705Z" }, + { url = "https://files.pythonhosted.org/packages/ff/db/331edc3bba929d2756fa335bfcf736f36eff4efcb4f2600b545a35c2ae58/librt-0.7.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9b5fb1ecb2c35362eab2dbd354fd1efa5a8440d3e73a68be11921042a0edc0ff", size = 203206, upload-time = "2026-01-01T23:52:03.315Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e1/6af79ec77204e85f6f2294fc171a30a91bb0e35d78493532ed680f5d98be/librt-0.7.7-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:d1454899909d63cc9199a89fcc4f81bdd9004aef577d4ffc022e600c412d57f3", size = 196697, upload-time = "2026-01-01T23:52:04.857Z" }, + { url = "https://files.pythonhosted.org/packages/f3/46/de55ecce4b2796d6d243295c221082ca3a944dc2fb3a52dcc8660ce7727d/librt-0.7.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7ef28f2e7a016b29792fe0a2dd04dec75725b32a1264e390c366103f834a9c3a", size = 217193, upload-time = "2026-01-01T23:52:06.159Z" }, + { url = "https://files.pythonhosted.org/packages/41/61/33063e271949787a2f8dd33c5260357e3d512a114fc82ca7890b65a76e2d/librt-0.7.7-cp314-cp314t-win32.whl", hash = "sha256:5e419e0db70991b6ba037b70c1d5bbe92b20ddf82f31ad01d77a347ed9781398", size = 40277, upload-time = "2026-01-01T23:52:07.625Z" }, + { url = "https://files.pythonhosted.org/packages/06/21/1abd972349f83a696ea73159ac964e63e2d14086fdd9bc7ca878c25fced4/librt-0.7.7-cp314-cp314t-win_amd64.whl", hash = "sha256:d6b7d93657332c817b8d674ef6bf1ab7796b4f7ce05e420fd45bd258a72ac804", size = 46765, upload-time = "2026-01-01T23:52:08.647Z" }, + { url = "https://files.pythonhosted.org/packages/51/0e/b756c7708143a63fca65a51ca07990fa647db2cc8fcd65177b9e96680255/librt-0.7.7-cp314-cp314t-win_arm64.whl", hash = "sha256:142c2cd91794b79fd0ce113bd658993b7ede0fe93057668c2f98a45ca00b7e91", size = 39724, upload-time = "2026-01-01T23:52:09.745Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "marshmallow" +version = "3.26.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/79/de6c16cc902f4fc372236926b0ce2ab7845268dcc30fb2fbb7f71b418631/marshmallow-3.26.2.tar.gz", hash = "sha256:bbe2adb5a03e6e3571b573f42527c6fe926e17467833660bebd11593ab8dfd57", size = 222095, upload-time = "2025-12-22T06:53:53.309Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl", hash = "sha256:013fa8a3c4c276c24d26d84ce934dc964e2aa794345a0f8c7e5a7191482c8a73", size = 50964, upload-time = "2025-12-22T06:53:51.801Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, +] + +[[package]] +name = "mistune" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/55/d01f0c4b45ade6536c51170b9043db8b2ec6ddf4a35c7ea3f5f559ac935b/mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a", size = 95467, upload-time = "2025-12-23T11:36:34.994Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "multidict" +version = "6.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/9e/9f61ac18d9c8b475889f32ccfa91c9f59363480613fc807b6e3023d6f60b/multidict-6.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8a3862568a36d26e650a19bb5cbbba14b71789032aebc0423f8cc5f150730184", size = 76877, upload-time = "2025-10-06T14:49:20.884Z" }, + { url = "https://files.pythonhosted.org/packages/38/6f/614f09a04e6184f8824268fce4bc925e9849edfa654ddd59f0b64508c595/multidict-6.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:960c60b5849b9b4f9dcc9bea6e3626143c252c74113df2c1540aebce70209b45", size = 45467, upload-time = "2025-10-06T14:49:22.054Z" }, + { url = "https://files.pythonhosted.org/packages/b3/93/c4f67a436dd026f2e780c433277fff72be79152894d9fc36f44569cab1a6/multidict-6.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2049be98fb57a31b4ccf870bf377af2504d4ae35646a19037ec271e4c07998aa", size = 43834, upload-time = "2025-10-06T14:49:23.566Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f5/013798161ca665e4a422afbc5e2d9e4070142a9ff8905e482139cd09e4d0/multidict-6.7.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0934f3843a1860dd465d38895c17fce1f1cb37295149ab05cd1b9a03afacb2a7", size = 250545, upload-time = "2025-10-06T14:49:24.882Z" }, + { url = "https://files.pythonhosted.org/packages/71/2f/91dbac13e0ba94669ea5119ba267c9a832f0cb65419aca75549fcf09a3dc/multidict-6.7.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3e34f3a1b8131ba06f1a73adab24f30934d148afcd5f5de9a73565a4404384e", size = 258305, upload-time = "2025-10-06T14:49:26.778Z" }, + { url = "https://files.pythonhosted.org/packages/ef/b0/754038b26f6e04488b48ac621f779c341338d78503fb45403755af2df477/multidict-6.7.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:efbb54e98446892590dc2458c19c10344ee9a883a79b5cec4bc34d6656e8d546", size = 242363, upload-time = "2025-10-06T14:49:28.562Z" }, + { url = "https://files.pythonhosted.org/packages/87/15/9da40b9336a7c9fa606c4cf2ed80a649dffeb42b905d4f63a1d7eb17d746/multidict-6.7.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a35c5fc61d4f51eb045061e7967cfe3123d622cd500e8868e7c0c592a09fedc4", size = 268375, upload-time = "2025-10-06T14:49:29.96Z" }, + { url = "https://files.pythonhosted.org/packages/82/72/c53fcade0cc94dfaad583105fd92b3a783af2091eddcb41a6d5a52474000/multidict-6.7.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29fe6740ebccba4175af1b9b87bf553e9c15cd5868ee967e010efcf94e4fd0f1", size = 269346, upload-time = "2025-10-06T14:49:31.404Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e2/9baffdae21a76f77ef8447f1a05a96ec4bc0a24dae08767abc0a2fe680b8/multidict-6.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:123e2a72e20537add2f33a79e605f6191fba2afda4cbb876e35c1a7074298a7d", size = 256107, upload-time = "2025-10-06T14:49:32.974Z" }, + { url = "https://files.pythonhosted.org/packages/3c/06/3f06f611087dc60d65ef775f1fb5aca7c6d61c6db4990e7cda0cef9b1651/multidict-6.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b284e319754366c1aee2267a2036248b24eeb17ecd5dc16022095e747f2f4304", size = 253592, upload-time = "2025-10-06T14:49:34.52Z" }, + { url = "https://files.pythonhosted.org/packages/20/24/54e804ec7945b6023b340c412ce9c3f81e91b3bf5fa5ce65558740141bee/multidict-6.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:803d685de7be4303b5a657b76e2f6d1240e7e0a8aa2968ad5811fa2285553a12", size = 251024, upload-time = "2025-10-06T14:49:35.956Z" }, + { url = "https://files.pythonhosted.org/packages/14/48/011cba467ea0b17ceb938315d219391d3e421dfd35928e5dbdc3f4ae76ef/multidict-6.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c04a328260dfd5db8c39538f999f02779012268f54614902d0afc775d44e0a62", size = 251484, upload-time = "2025-10-06T14:49:37.631Z" }, + { url = "https://files.pythonhosted.org/packages/0d/2f/919258b43bb35b99fa127435cfb2d91798eb3a943396631ef43e3720dcf4/multidict-6.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8a19cdb57cd3df4cd865849d93ee14920fb97224300c88501f16ecfa2604b4e0", size = 263579, upload-time = "2025-10-06T14:49:39.502Z" }, + { url = "https://files.pythonhosted.org/packages/31/22/a0e884d86b5242b5a74cf08e876bdf299e413016b66e55511f7a804a366e/multidict-6.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b2fd74c52accced7e75de26023b7dccee62511a600e62311b918ec5c168fc2a", size = 259654, upload-time = "2025-10-06T14:49:41.32Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/17e10e1b5c5f5a40f2fcbb45953c9b215f8a4098003915e46a93f5fcaa8f/multidict-6.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e8bfdd0e487acf992407a140d2589fe598238eaeffa3da8448d63a63cd363f8", size = 251511, upload-time = "2025-10-06T14:49:46.021Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9a/201bb1e17e7af53139597069c375e7b0dcbd47594604f65c2d5359508566/multidict-6.7.0-cp312-cp312-win32.whl", hash = "sha256:dd32a49400a2c3d52088e120ee00c1e3576cbff7e10b98467962c74fdb762ed4", size = 41895, upload-time = "2025-10-06T14:49:48.718Z" }, + { url = "https://files.pythonhosted.org/packages/46/e2/348cd32faad84eaf1d20cce80e2bb0ef8d312c55bca1f7fa9865e7770aaf/multidict-6.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:92abb658ef2d7ef22ac9f8bb88e8b6c3e571671534e029359b6d9e845923eb1b", size = 46073, upload-time = "2025-10-06T14:49:50.28Z" }, + { url = "https://files.pythonhosted.org/packages/25/ec/aad2613c1910dce907480e0c3aa306905830f25df2e54ccc9dea450cb5aa/multidict-6.7.0-cp312-cp312-win_arm64.whl", hash = "sha256:490dab541a6a642ce1a9d61a4781656b346a55c13038f0b1244653828e3a83ec", size = 43226, upload-time = "2025-10-06T14:49:52.304Z" }, + { url = "https://files.pythonhosted.org/packages/d2/86/33272a544eeb36d66e4d9a920602d1a2f57d4ebea4ef3cdfe5a912574c95/multidict-6.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bee7c0588aa0076ce77c0ea5d19a68d76ad81fcd9fe8501003b9a24f9d4000f6", size = 76135, upload-time = "2025-10-06T14:49:54.26Z" }, + { url = "https://files.pythonhosted.org/packages/91/1c/eb97db117a1ebe46d457a3d235a7b9d2e6dcab174f42d1b67663dd9e5371/multidict-6.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7ef6b61cad77091056ce0e7ce69814ef72afacb150b7ac6a3e9470def2198159", size = 45117, upload-time = "2025-10-06T14:49:55.82Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d8/6c3442322e41fb1dd4de8bd67bfd11cd72352ac131f6368315617de752f1/multidict-6.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c0359b1ec12b1d6849c59f9d319610b7f20ef990a6d454ab151aa0e3b9f78ca", size = 43472, upload-time = "2025-10-06T14:49:57.048Z" }, + { url = "https://files.pythonhosted.org/packages/75/3f/e2639e80325af0b6c6febdf8e57cc07043ff15f57fa1ef808f4ccb5ac4cd/multidict-6.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cd240939f71c64bd658f186330603aac1a9a81bf6273f523fca63673cb7378a8", size = 249342, upload-time = "2025-10-06T14:49:58.368Z" }, + { url = "https://files.pythonhosted.org/packages/5d/cc/84e0585f805cbeaa9cbdaa95f9a3d6aed745b9d25700623ac89a6ecff400/multidict-6.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60a4d75718a5efa473ebd5ab685786ba0c67b8381f781d1be14da49f1a2dc60", size = 257082, upload-time = "2025-10-06T14:49:59.89Z" }, + { url = "https://files.pythonhosted.org/packages/b0/9c/ac851c107c92289acbbf5cfb485694084690c1b17e555f44952c26ddc5bd/multidict-6.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53a42d364f323275126aff81fb67c5ca1b7a04fda0546245730a55c8c5f24bc4", size = 240704, upload-time = "2025-10-06T14:50:01.485Z" }, + { url = "https://files.pythonhosted.org/packages/50/cc/5f93e99427248c09da95b62d64b25748a5f5c98c7c2ab09825a1d6af0e15/multidict-6.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3b29b980d0ddbecb736735ee5bef69bb2ddca56eff603c86f3f29a1128299b4f", size = 266355, upload-time = "2025-10-06T14:50:02.955Z" }, + { url = "https://files.pythonhosted.org/packages/ec/0c/2ec1d883ceb79c6f7f6d7ad90c919c898f5d1c6ea96d322751420211e072/multidict-6.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8a93b1c0ed2d04b97a5e9336fd2d33371b9a6e29ab7dd6503d63407c20ffbaf", size = 267259, upload-time = "2025-10-06T14:50:04.446Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2d/f0b184fa88d6630aa267680bdb8623fb69cb0d024b8c6f0d23f9a0f406d3/multidict-6.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ff96e8815eecacc6645da76c413eb3b3d34cfca256c70b16b286a687d013c32", size = 254903, upload-time = "2025-10-06T14:50:05.98Z" }, + { url = "https://files.pythonhosted.org/packages/06/c9/11ea263ad0df7dfabcad404feb3c0dd40b131bc7f232d5537f2fb1356951/multidict-6.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7516c579652f6a6be0e266aec0acd0db80829ca305c3d771ed898538804c2036", size = 252365, upload-time = "2025-10-06T14:50:07.511Z" }, + { url = "https://files.pythonhosted.org/packages/41/88/d714b86ee2c17d6e09850c70c9d310abac3d808ab49dfa16b43aba9d53fd/multidict-6.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:040f393368e63fb0f3330e70c26bfd336656bed925e5cbe17c9da839a6ab13ec", size = 250062, upload-time = "2025-10-06T14:50:09.074Z" }, + { url = "https://files.pythonhosted.org/packages/15/fe/ad407bb9e818c2b31383f6131ca19ea7e35ce93cf1310fce69f12e89de75/multidict-6.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b3bc26a951007b1057a1c543af845f1c7e3e71cc240ed1ace7bf4484aa99196e", size = 249683, upload-time = "2025-10-06T14:50:10.714Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a4/a89abdb0229e533fb925e7c6e5c40201c2873efebc9abaf14046a4536ee6/multidict-6.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7b022717c748dd1992a83e219587aabe45980d88969f01b316e78683e6285f64", size = 261254, upload-time = "2025-10-06T14:50:12.28Z" }, + { url = "https://files.pythonhosted.org/packages/8d/aa/0e2b27bd88b40a4fb8dc53dd74eecac70edaa4c1dd0707eb2164da3675b3/multidict-6.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9600082733859f00d79dee64effc7aef1beb26adb297416a4ad2116fd61374bd", size = 257967, upload-time = "2025-10-06T14:50:14.16Z" }, + { url = "https://files.pythonhosted.org/packages/d0/8e/0c67b7120d5d5f6d874ed85a085f9dc770a7f9d8813e80f44a9fec820bb7/multidict-6.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94218fcec4d72bc61df51c198d098ce2b378e0ccbac41ddbed5ef44092913288", size = 250085, upload-time = "2025-10-06T14:50:15.639Z" }, + { url = "https://files.pythonhosted.org/packages/ba/55/b73e1d624ea4b8fd4dd07a3bb70f6e4c7c6c5d9d640a41c6ffe5cdbd2a55/multidict-6.7.0-cp313-cp313-win32.whl", hash = "sha256:a37bd74c3fa9d00be2d7b8eca074dc56bd8077ddd2917a839bd989612671ed17", size = 41713, upload-time = "2025-10-06T14:50:17.066Z" }, + { url = "https://files.pythonhosted.org/packages/32/31/75c59e7d3b4205075b4c183fa4ca398a2daf2303ddf616b04ae6ef55cffe/multidict-6.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:30d193c6cc6d559db42b6bcec8a5d395d34d60c9877a0b71ecd7c204fcf15390", size = 45915, upload-time = "2025-10-06T14:50:18.264Z" }, + { url = "https://files.pythonhosted.org/packages/31/2a/8987831e811f1184c22bc2e45844934385363ee61c0a2dcfa8f71b87e608/multidict-6.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:ea3334cabe4d41b7ccd01e4d349828678794edbc2d3ae97fc162a3312095092e", size = 43077, upload-time = "2025-10-06T14:50:19.853Z" }, + { url = "https://files.pythonhosted.org/packages/e8/68/7b3a5170a382a340147337b300b9eb25a9ddb573bcdfff19c0fa3f31ffba/multidict-6.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ad9ce259f50abd98a1ca0aa6e490b58c316a0fce0617f609723e40804add2c00", size = 83114, upload-time = "2025-10-06T14:50:21.223Z" }, + { url = "https://files.pythonhosted.org/packages/55/5c/3fa2d07c84df4e302060f555bbf539310980362236ad49f50eeb0a1c1eb9/multidict-6.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07f5594ac6d084cbb5de2df218d78baf55ef150b91f0ff8a21cc7a2e3a5a58eb", size = 48442, upload-time = "2025-10-06T14:50:22.871Z" }, + { url = "https://files.pythonhosted.org/packages/fc/56/67212d33239797f9bd91962bb899d72bb0f4c35a8652dcdb8ed049bef878/multidict-6.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0591b48acf279821a579282444814a2d8d0af624ae0bc600aa4d1b920b6e924b", size = 46885, upload-time = "2025-10-06T14:50:24.258Z" }, + { url = "https://files.pythonhosted.org/packages/46/d1/908f896224290350721597a61a69cd19b89ad8ee0ae1f38b3f5cd12ea2ac/multidict-6.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:749a72584761531d2b9467cfbdfd29487ee21124c304c4b6cb760d8777b27f9c", size = 242588, upload-time = "2025-10-06T14:50:25.716Z" }, + { url = "https://files.pythonhosted.org/packages/ab/67/8604288bbd68680eee0ab568fdcb56171d8b23a01bcd5cb0c8fedf6e5d99/multidict-6.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b4c3d199f953acd5b446bf7c0de1fe25d94e09e79086f8dc2f48a11a129cdf1", size = 249966, upload-time = "2025-10-06T14:50:28.192Z" }, + { url = "https://files.pythonhosted.org/packages/20/33/9228d76339f1ba51e3efef7da3ebd91964d3006217aae13211653193c3ff/multidict-6.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9fb0211dfc3b51efea2f349ec92c114d7754dd62c01f81c3e32b765b70c45c9b", size = 228618, upload-time = "2025-10-06T14:50:29.82Z" }, + { url = "https://files.pythonhosted.org/packages/f8/2d/25d9b566d10cab1c42b3b9e5b11ef79c9111eaf4463b8c257a3bd89e0ead/multidict-6.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a027ec240fe73a8d6281872690b988eed307cd7d91b23998ff35ff577ca688b5", size = 257539, upload-time = "2025-10-06T14:50:31.731Z" }, + { url = "https://files.pythonhosted.org/packages/b6/b1/8d1a965e6637fc33de3c0d8f414485c2b7e4af00f42cab3d84e7b955c222/multidict-6.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1d964afecdf3a8288789df2f5751dc0a8261138c3768d9af117ed384e538fad", size = 256345, upload-time = "2025-10-06T14:50:33.26Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/06b5a8adbdeedada6f4fb8d8f193d44a347223b11939b42953eeb6530b6b/multidict-6.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caf53b15b1b7df9fbd0709aa01409000a2b4dd03a5f6f5cc548183c7c8f8b63c", size = 247934, upload-time = "2025-10-06T14:50:34.808Z" }, + { url = "https://files.pythonhosted.org/packages/8f/31/b2491b5fe167ca044c6eb4b8f2c9f3b8a00b24c432c365358eadac5d7625/multidict-6.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:654030da3197d927f05a536a66186070e98765aa5142794c9904555d3a9d8fb5", size = 245243, upload-time = "2025-10-06T14:50:36.436Z" }, + { url = "https://files.pythonhosted.org/packages/61/1a/982913957cb90406c8c94f53001abd9eafc271cb3e70ff6371590bec478e/multidict-6.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2090d3718829d1e484706a2f525e50c892237b2bf9b17a79b059cb98cddc2f10", size = 235878, upload-time = "2025-10-06T14:50:37.953Z" }, + { url = "https://files.pythonhosted.org/packages/be/c0/21435d804c1a1cf7a2608593f4d19bca5bcbd7a81a70b253fdd1c12af9c0/multidict-6.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d2cfeec3f6f45651b3d408c4acec0ebf3daa9bc8a112a084206f5db5d05b754", size = 243452, upload-time = "2025-10-06T14:50:39.574Z" }, + { url = "https://files.pythonhosted.org/packages/54/0a/4349d540d4a883863191be6eb9a928846d4ec0ea007d3dcd36323bb058ac/multidict-6.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ef089f985b8c194d341eb2c24ae6e7408c9a0e2e5658699c92f497437d88c3c", size = 252312, upload-time = "2025-10-06T14:50:41.612Z" }, + { url = "https://files.pythonhosted.org/packages/26/64/d5416038dbda1488daf16b676e4dbfd9674dde10a0cc8f4fc2b502d8125d/multidict-6.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e93a0617cd16998784bf4414c7e40f17a35d2350e5c6f0bd900d3a8e02bd3762", size = 246935, upload-time = "2025-10-06T14:50:43.972Z" }, + { url = "https://files.pythonhosted.org/packages/9f/8c/8290c50d14e49f35e0bd4abc25e1bc7711149ca9588ab7d04f886cdf03d9/multidict-6.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0feece2ef8ebc42ed9e2e8c78fc4aa3cf455733b507c09ef7406364c94376c6", size = 243385, upload-time = "2025-10-06T14:50:45.648Z" }, + { url = "https://files.pythonhosted.org/packages/ef/a0/f83ae75e42d694b3fbad3e047670e511c138be747bc713cf1b10d5096416/multidict-6.7.0-cp313-cp313t-win32.whl", hash = "sha256:19a1d55338ec1be74ef62440ca9e04a2f001a04d0cc49a4983dc320ff0f3212d", size = 47777, upload-time = "2025-10-06T14:50:47.154Z" }, + { url = "https://files.pythonhosted.org/packages/dc/80/9b174a92814a3830b7357307a792300f42c9e94664b01dee8e457551fa66/multidict-6.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3da4fb467498df97e986af166b12d01f05d2e04f978a9c1c680ea1988e0bc4b6", size = 53104, upload-time = "2025-10-06T14:50:48.851Z" }, + { url = "https://files.pythonhosted.org/packages/cc/28/04baeaf0428d95bb7a7bea0e691ba2f31394338ba424fb0679a9ed0f4c09/multidict-6.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b4121773c49a0776461f4a904cdf6264c88e42218aaa8407e803ca8025872792", size = 45503, upload-time = "2025-10-06T14:50:50.16Z" }, + { url = "https://files.pythonhosted.org/packages/e2/b1/3da6934455dd4b261d4c72f897e3a5728eba81db59959f3a639245891baa/multidict-6.7.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bab1e4aff7adaa34410f93b1f8e57c4b36b9af0426a76003f441ee1d3c7e842", size = 75128, upload-time = "2025-10-06T14:50:51.92Z" }, + { url = "https://files.pythonhosted.org/packages/14/2c/f069cab5b51d175a1a2cb4ccdf7a2c2dabd58aa5bd933fa036a8d15e2404/multidict-6.7.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b8512bac933afc3e45fb2b18da8e59b78d4f408399a960339598374d4ae3b56b", size = 44410, upload-time = "2025-10-06T14:50:53.275Z" }, + { url = "https://files.pythonhosted.org/packages/42/e2/64bb41266427af6642b6b128e8774ed84c11b80a90702c13ac0a86bb10cc/multidict-6.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:79dcf9e477bc65414ebfea98ffd013cb39552b5ecd62908752e0e413d6d06e38", size = 43205, upload-time = "2025-10-06T14:50:54.911Z" }, + { url = "https://files.pythonhosted.org/packages/02/68/6b086fef8a3f1a8541b9236c594f0c9245617c29841f2e0395d979485cde/multidict-6.7.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:31bae522710064b5cbeddaf2e9f32b1abab70ac6ac91d42572502299e9953128", size = 245084, upload-time = "2025-10-06T14:50:56.369Z" }, + { url = "https://files.pythonhosted.org/packages/15/ee/f524093232007cd7a75c1d132df70f235cfd590a7c9eaccd7ff422ef4ae8/multidict-6.7.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a0df7ff02397bb63e2fd22af2c87dfa39e8c7f12947bc524dbdc528282c7e34", size = 252667, upload-time = "2025-10-06T14:50:57.991Z" }, + { url = "https://files.pythonhosted.org/packages/02/a5/eeb3f43ab45878f1895118c3ef157a480db58ede3f248e29b5354139c2c9/multidict-6.7.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a0222514e8e4c514660e182d5156a415c13ef0aabbd71682fc714e327b95e99", size = 233590, upload-time = "2025-10-06T14:50:59.589Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/76d02f8270b97269d7e3dbd45644b1785bda457b474315f8cf999525a193/multidict-6.7.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2397ab4daaf2698eb51a76721e98db21ce4f52339e535725de03ea962b5a3202", size = 264112, upload-time = "2025-10-06T14:51:01.183Z" }, + { url = "https://files.pythonhosted.org/packages/76/0b/c28a70ecb58963847c2a8efe334904cd254812b10e535aefb3bcce513918/multidict-6.7.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8891681594162635948a636c9fe0ff21746aeb3dd5463f6e25d9bea3a8a39ca1", size = 261194, upload-time = "2025-10-06T14:51:02.794Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/2ab26e4209773223159b83aa32721b4021ffb08102f8ac7d689c943fded1/multidict-6.7.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18706cc31dbf402a7945916dd5cddf160251b6dab8a2c5f3d6d5a55949f676b3", size = 248510, upload-time = "2025-10-06T14:51:04.724Z" }, + { url = "https://files.pythonhosted.org/packages/93/cd/06c1fa8282af1d1c46fd55c10a7930af652afdce43999501d4d68664170c/multidict-6.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f844a1bbf1d207dd311a56f383f7eda2d0e134921d45751842d8235e7778965d", size = 248395, upload-time = "2025-10-06T14:51:06.306Z" }, + { url = "https://files.pythonhosted.org/packages/99/ac/82cb419dd6b04ccf9e7e61befc00c77614fc8134362488b553402ecd55ce/multidict-6.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4393e3581e84e5645506923816b9cc81f5609a778c7e7534054091acc64d1c6", size = 239520, upload-time = "2025-10-06T14:51:08.091Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f3/a0f9bf09493421bd8716a362e0cd1d244f5a6550f5beffdd6b47e885b331/multidict-6.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fbd18dc82d7bf274b37aa48d664534330af744e03bccf696d6f4c6042e7d19e7", size = 245479, upload-time = "2025-10-06T14:51:10.365Z" }, + { url = "https://files.pythonhosted.org/packages/8d/01/476d38fc73a212843f43c852b0eee266b6971f0e28329c2184a8df90c376/multidict-6.7.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b6234e14f9314731ec45c42fc4554b88133ad53a09092cc48a88e771c125dadb", size = 258903, upload-time = "2025-10-06T14:51:12.466Z" }, + { url = "https://files.pythonhosted.org/packages/49/6d/23faeb0868adba613b817d0e69c5f15531b24d462af8012c4f6de4fa8dc3/multidict-6.7.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:08d4379f9744d8f78d98c8673c06e202ffa88296f009c71bbafe8a6bf847d01f", size = 252333, upload-time = "2025-10-06T14:51:14.48Z" }, + { url = "https://files.pythonhosted.org/packages/1e/cc/48d02ac22b30fa247f7dad82866e4b1015431092f4ba6ebc7e77596e0b18/multidict-6.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fe04da3f79387f450fd0061d4dd2e45a72749d31bf634aecc9e27f24fdc4b3f", size = 243411, upload-time = "2025-10-06T14:51:16.072Z" }, + { url = "https://files.pythonhosted.org/packages/4a/03/29a8bf5a18abf1fe34535c88adbdfa88c9fb869b5a3b120692c64abe8284/multidict-6.7.0-cp314-cp314-win32.whl", hash = "sha256:fbafe31d191dfa7c4c51f7a6149c9fb7e914dcf9ffead27dcfd9f1ae382b3885", size = 40940, upload-time = "2025-10-06T14:51:17.544Z" }, + { url = "https://files.pythonhosted.org/packages/82/16/7ed27b680791b939de138f906d5cf2b4657b0d45ca6f5dd6236fdddafb1a/multidict-6.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:2f67396ec0310764b9222a1728ced1ab638f61aadc6226f17a71dd9324f9a99c", size = 45087, upload-time = "2025-10-06T14:51:18.875Z" }, + { url = "https://files.pythonhosted.org/packages/cd/3c/e3e62eb35a1950292fe39315d3c89941e30a9d07d5d2df42965ab041da43/multidict-6.7.0-cp314-cp314-win_arm64.whl", hash = "sha256:ba672b26069957ee369cfa7fc180dde1fc6f176eaf1e6beaf61fbebbd3d9c000", size = 42368, upload-time = "2025-10-06T14:51:20.225Z" }, + { url = "https://files.pythonhosted.org/packages/8b/40/cd499bd0dbc5f1136726db3153042a735fffd0d77268e2ee20d5f33c010f/multidict-6.7.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:c1dcc7524066fa918c6a27d61444d4ee7900ec635779058571f70d042d86ed63", size = 82326, upload-time = "2025-10-06T14:51:21.588Z" }, + { url = "https://files.pythonhosted.org/packages/13/8a/18e031eca251c8df76daf0288e6790561806e439f5ce99a170b4af30676b/multidict-6.7.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:27e0b36c2d388dc7b6ced3406671b401e84ad7eb0656b8f3a2f46ed0ce483718", size = 48065, upload-time = "2025-10-06T14:51:22.93Z" }, + { url = "https://files.pythonhosted.org/packages/40/71/5e6701277470a87d234e433fb0a3a7deaf3bcd92566e421e7ae9776319de/multidict-6.7.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a7baa46a22e77f0988e3b23d4ede5513ebec1929e34ee9495be535662c0dfe2", size = 46475, upload-time = "2025-10-06T14:51:24.352Z" }, + { url = "https://files.pythonhosted.org/packages/fe/6a/bab00cbab6d9cfb57afe1663318f72ec28289ea03fd4e8236bb78429893a/multidict-6.7.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bf77f54997a9166a2f5675d1201520586439424c2511723a7312bdb4bcc034e", size = 239324, upload-time = "2025-10-06T14:51:25.822Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5f/8de95f629fc22a7769ade8b41028e3e5a822c1f8904f618d175945a81ad3/multidict-6.7.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e011555abada53f1578d63389610ac8a5400fc70ce71156b0aa30d326f1a5064", size = 246877, upload-time = "2025-10-06T14:51:27.604Z" }, + { url = "https://files.pythonhosted.org/packages/23/b4/38881a960458f25b89e9f4a4fdcb02ac101cfa710190db6e5528841e67de/multidict-6.7.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:28b37063541b897fd6a318007373930a75ca6d6ac7c940dbe14731ffdd8d498e", size = 225824, upload-time = "2025-10-06T14:51:29.664Z" }, + { url = "https://files.pythonhosted.org/packages/1e/39/6566210c83f8a261575f18e7144736059f0c460b362e96e9cf797a24b8e7/multidict-6.7.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05047ada7a2fde2631a0ed706f1fd68b169a681dfe5e4cf0f8e4cb6618bbc2cd", size = 253558, upload-time = "2025-10-06T14:51:31.684Z" }, + { url = "https://files.pythonhosted.org/packages/00/a3/67f18315100f64c269f46e6c0319fa87ba68f0f64f2b8e7fd7c72b913a0b/multidict-6.7.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:716133f7d1d946a4e1b91b1756b23c088881e70ff180c24e864c26192ad7534a", size = 252339, upload-time = "2025-10-06T14:51:33.699Z" }, + { url = "https://files.pythonhosted.org/packages/c8/2a/1cb77266afee2458d82f50da41beba02159b1d6b1f7973afc9a1cad1499b/multidict-6.7.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1bed1b467ef657f2a0ae62844a607909ef1c6889562de5e1d505f74457d0b96", size = 244895, upload-time = "2025-10-06T14:51:36.189Z" }, + { url = "https://files.pythonhosted.org/packages/dd/72/09fa7dd487f119b2eb9524946ddd36e2067c08510576d43ff68469563b3b/multidict-6.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ca43bdfa5d37bd6aee89d85e1d0831fb86e25541be7e9d376ead1b28974f8e5e", size = 241862, upload-time = "2025-10-06T14:51:41.291Z" }, + { url = "https://files.pythonhosted.org/packages/65/92/bc1f8bd0853d8669300f732c801974dfc3702c3eeadae2f60cef54dc69d7/multidict-6.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:44b546bd3eb645fd26fb949e43c02a25a2e632e2ca21a35e2e132c8105dc8599", size = 232376, upload-time = "2025-10-06T14:51:43.55Z" }, + { url = "https://files.pythonhosted.org/packages/09/86/ac39399e5cb9d0c2ac8ef6e10a768e4d3bc933ac808d49c41f9dc23337eb/multidict-6.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6ef16328011d3f468e7ebc326f24c1445f001ca1dec335b2f8e66bed3006394", size = 240272, upload-time = "2025-10-06T14:51:45.265Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b6/fed5ac6b8563ec72df6cb1ea8dac6d17f0a4a1f65045f66b6d3bf1497c02/multidict-6.7.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5aa873cbc8e593d361ae65c68f85faadd755c3295ea2c12040ee146802f23b38", size = 248774, upload-time = "2025-10-06T14:51:46.836Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8d/b954d8c0dc132b68f760aefd45870978deec6818897389dace00fcde32ff/multidict-6.7.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3d7b6ccce016e29df4b7ca819659f516f0bc7a4b3efa3bb2012ba06431b044f9", size = 242731, upload-time = "2025-10-06T14:51:48.541Z" }, + { url = "https://files.pythonhosted.org/packages/16/9d/a2dac7009125d3540c2f54e194829ea18ac53716c61b655d8ed300120b0f/multidict-6.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:171b73bd4ee683d307599b66793ac80981b06f069b62eea1c9e29c9241aa66b0", size = 240193, upload-time = "2025-10-06T14:51:50.355Z" }, + { url = "https://files.pythonhosted.org/packages/39/ca/c05f144128ea232ae2178b008d5011d4e2cea86e4ee8c85c2631b1b94802/multidict-6.7.0-cp314-cp314t-win32.whl", hash = "sha256:b2d7f80c4e1fd010b07cb26820aae86b7e73b681ee4889684fb8d2d4537aab13", size = 48023, upload-time = "2025-10-06T14:51:51.883Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8f/0a60e501584145588be1af5cc829265701ba3c35a64aec8e07cbb71d39bb/multidict-6.7.0-cp314-cp314t-win_amd64.whl", hash = "sha256:09929cab6fcb68122776d575e03c6cc64ee0b8fca48d17e135474b042ce515cd", size = 53507, upload-time = "2025-10-06T14:51:53.672Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ae/3148b988a9c6239903e786eac19c889fab607c31d6efa7fb2147e5680f23/multidict-6.7.0-cp314-cp314t-win_arm64.whl", hash = "sha256:cc41db090ed742f32bd2d2c721861725e6109681eddf835d0a82bd3a5c382827", size = 44804, upload-time = "2025-10-06T14:51:55.415Z" }, + { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, +] + +[[package]] +name = "mypy" +version = "1.19.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/8a/19bfae96f6615aa8a0604915512e0289b1fad33d5909bf7244f02935d33a/mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1", size = 13206053, upload-time = "2025-12-15T05:03:46.622Z" }, + { url = "https://files.pythonhosted.org/packages/a5/34/3e63879ab041602154ba2a9f99817bb0c85c4df19a23a1443c8986e4d565/mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e", size = 12219134, upload-time = "2025-12-15T05:03:24.367Z" }, + { url = "https://files.pythonhosted.org/packages/89/cc/2db6f0e95366b630364e09845672dbee0cbf0bbe753a204b29a944967cd9/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2", size = 12731616, upload-time = "2025-12-15T05:02:44.725Z" }, + { url = "https://files.pythonhosted.org/packages/00/be/dd56c1fd4807bc1eba1cf18b2a850d0de7bacb55e158755eb79f77c41f8e/mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8", size = 13620847, upload-time = "2025-12-15T05:03:39.633Z" }, + { url = "https://files.pythonhosted.org/packages/6d/42/332951aae42b79329f743bf1da088cd75d8d4d9acc18fbcbd84f26c1af4e/mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a", size = 13834976, upload-time = "2025-12-15T05:03:08.786Z" }, + { url = "https://files.pythonhosted.org/packages/6f/63/e7493e5f90e1e085c562bb06e2eb32cae27c5057b9653348d38b47daaecc/mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13", size = 10118104, upload-time = "2025-12-15T05:03:10.834Z" }, + { url = "https://files.pythonhosted.org/packages/de/9f/a6abae693f7a0c697dbb435aac52e958dc8da44e92e08ba88d2e42326176/mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250", size = 13201927, upload-time = "2025-12-15T05:02:29.138Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a4/45c35ccf6e1c65afc23a069f50e2c66f46bd3798cbe0d680c12d12935caa/mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b", size = 12206730, upload-time = "2025-12-15T05:03:01.325Z" }, + { url = "https://files.pythonhosted.org/packages/05/bb/cdcf89678e26b187650512620eec8368fded4cfd99cfcb431e4cdfd19dec/mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e", size = 12724581, upload-time = "2025-12-15T05:03:20.087Z" }, + { url = "https://files.pythonhosted.org/packages/d1/32/dd260d52babf67bad8e6770f8e1102021877ce0edea106e72df5626bb0ec/mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef", size = 13616252, upload-time = "2025-12-15T05:02:49.036Z" }, + { url = "https://files.pythonhosted.org/packages/71/d0/5e60a9d2e3bd48432ae2b454b7ef2b62a960ab51292b1eda2a95edd78198/mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75", size = 13840848, upload-time = "2025-12-15T05:02:55.95Z" }, + { url = "https://files.pythonhosted.org/packages/98/76/d32051fa65ecf6cc8c6610956473abdc9b4c43301107476ac03559507843/mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd", size = 10135510, upload-time = "2025-12-15T05:02:58.438Z" }, + { url = "https://files.pythonhosted.org/packages/de/eb/b83e75f4c820c4247a58580ef86fcd35165028f191e7e1ba57128c52782d/mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1", size = 13199744, upload-time = "2025-12-15T05:03:30.823Z" }, + { url = "https://files.pythonhosted.org/packages/94/28/52785ab7bfa165f87fcbb61547a93f98bb20e7f82f90f165a1f69bce7b3d/mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718", size = 12215815, upload-time = "2025-12-15T05:02:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/0a/c6/bdd60774a0dbfb05122e3e925f2e9e846c009e479dcec4821dad881f5b52/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b", size = 12740047, upload-time = "2025-12-15T05:03:33.168Z" }, + { url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" }, + { url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" }, + { url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "nbclient" +version = "0.10.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "nbformat" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/56/91/1c1d5a4b9a9ebba2b4e32b8c852c2975c872aec1fe42ab5e516b2cecd193/nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9", size = 62554, upload-time = "2025-12-23T07:45:46.369Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440", size = 25465, upload-time = "2025-12-23T07:45:44.51Z" }, +] + +[[package]] +name = "nbconvert" +version = "7.16.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "bleach", extra = ["css"] }, + { name = "defusedxml" }, + { name = "jinja2" }, + { name = "jupyter-core" }, + { name = "jupyterlab-pygments" }, + { name = "markupsafe" }, + { name = "mistune" }, + { name = "nbclient" }, + { name = "nbformat" }, + { name = "packaging" }, + { name = "pandocfilters" }, + { name = "pygments" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715, upload-time = "2025-01-28T09:29:14.724Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525, upload-time = "2025-01-28T09:29:12.551Z" }, +] + +[[package]] +name = "nbformat" +version = "5.10.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fastjsonschema" }, + { name = "jsonschema" }, + { name = "jupyter-core" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, +] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, +] + +[[package]] +name = "networkx" +version = "3.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" }, +] + +[[package]] +name = "nltk" +version = "3.9.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "joblib" }, + { name = "regex" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f9/76/3a5e4312c19a028770f86fd7c058cf9f4ec4321c6cf7526bab998a5b683c/nltk-3.9.2.tar.gz", hash = "sha256:0f409e9b069ca4177c1903c3e843eef90c7e92992fa4931ae607da6de49e1419", size = 2887629, upload-time = "2025-10-01T07:19:23.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/90/81ac364ef94209c100e12579629dc92bf7a709a84af32f8c551b02c07e94/nltk-3.9.2-py3-none-any.whl", hash = "sha256:1e209d2b3009110635ed9709a67a1a3e33a10f799490fa71cf4bec218c11c88a", size = 1513404, upload-time = "2025-10-01T07:19:21.648Z" }, +] + +[[package]] +name = "notebook" +version = "7.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, + { name = "jupyterlab" }, + { name = "jupyterlab-server" }, + { name = "notebook-shim" }, + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/a9/882707b0aa639e6d7d3e7df4bfbe07479d832e9a8f02d8471002a4ea6d65/notebook-7.5.1.tar.gz", hash = "sha256:b2fb4cef4d47d08c33aecce1c6c6e84be05436fbd791f88fce8df9fbca088b75", size = 14058696, upload-time = "2025-12-16T07:38:59.223Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/86/ca516cb58ad2cb2064124d31cf0fd8b012fca64bebeb26da2d2ddf03fc79/notebook-7.5.1-py3-none-any.whl", hash = "sha256:f4e2451c19910c33b88709b84537e11f6368c1cdff1aa0c43db701aea535dd44", size = 14468080, upload-time = "2025-12-16T07:38:55.644Z" }, +] + +[[package]] +name = "notebook-shim" +version = "0.2.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a4/7a/6a3d14e205d292b738db449d0de649b373a59edb0d0b4493821d0a3e8718/numpy-2.4.0.tar.gz", hash = "sha256:6e504f7b16118198f138ef31ba24d985b124c2c469fe8467007cf30fd992f934", size = 20685720, upload-time = "2025-12-20T16:18:19.023Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/ff/f6400ffec95de41c74b8e73df32e3fff1830633193a7b1e409be7fb1bb8c/numpy-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2a8b6bb8369abefb8bd1801b054ad50e02b3275c8614dc6e5b0373c305291037", size = 16653117, upload-time = "2025-12-20T16:16:06.709Z" }, + { url = "https://files.pythonhosted.org/packages/fd/28/6c23e97450035072e8d830a3c411bf1abd1f42c611ff9d29e3d8f55c6252/numpy-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e284ca13d5a8367e43734148622caf0b261b275673823593e3e3634a6490f83", size = 12369711, upload-time = "2025-12-20T16:16:08.758Z" }, + { url = "https://files.pythonhosted.org/packages/bc/af/acbef97b630ab1bb45e6a7d01d1452e4251aa88ce680ac36e56c272120ec/numpy-2.4.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:49ff32b09f5aa0cd30a20c2b39db3e669c845589f2b7fc910365210887e39344", size = 5198355, upload-time = "2025-12-20T16:16:10.902Z" }, + { url = "https://files.pythonhosted.org/packages/c1/c8/4e0d436b66b826f2e53330adaa6311f5cac9871a5b5c31ad773b27f25a74/numpy-2.4.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:36cbfb13c152b1c7c184ddac43765db8ad672567e7bafff2cc755a09917ed2e6", size = 6545298, upload-time = "2025-12-20T16:16:12.607Z" }, + { url = "https://files.pythonhosted.org/packages/ef/27/e1f5d144ab54eac34875e79037011d511ac57b21b220063310cb96c80fbc/numpy-2.4.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:35ddc8f4914466e6fc954c76527aa91aa763682a4f6d73249ef20b418fe6effb", size = 14398387, upload-time = "2025-12-20T16:16:14.257Z" }, + { url = "https://files.pythonhosted.org/packages/67/64/4cb909dd5ab09a9a5d086eff9586e69e827b88a5585517386879474f4cf7/numpy-2.4.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc578891de1db95b2a35001b695451767b580bb45753717498213c5ff3c41d63", size = 16363091, upload-time = "2025-12-20T16:16:17.32Z" }, + { url = "https://files.pythonhosted.org/packages/9d/9c/8efe24577523ec6809261859737cf117b0eb6fdb655abdfdc81b2e468ce4/numpy-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98e81648e0b36e325ab67e46b5400a7a6d4a22b8a7c8e8bbfe20e7db7906bf95", size = 16176394, upload-time = "2025-12-20T16:16:19.524Z" }, + { url = "https://files.pythonhosted.org/packages/61/f0/1687441ece7b47a62e45a1f82015352c240765c707928edd8aef875d5951/numpy-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d57b5046c120561ba8fa8e4030fbb8b822f3063910fa901ffadf16e2b7128ad6", size = 18287378, upload-time = "2025-12-20T16:16:22.866Z" }, + { url = "https://files.pythonhosted.org/packages/d3/6f/f868765d44e6fc466467ed810ba9d8d6db1add7d4a748abfa2a4c99a3194/numpy-2.4.0-cp312-cp312-win32.whl", hash = "sha256:92190db305a6f48734d3982f2c60fa30d6b5ee9bff10f2887b930d7b40119f4c", size = 5955432, upload-time = "2025-12-20T16:16:25.06Z" }, + { url = "https://files.pythonhosted.org/packages/d4/b5/94c1e79fcbab38d1ca15e13777477b2914dd2d559b410f96949d6637b085/numpy-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:680060061adb2d74ce352628cb798cfdec399068aa7f07ba9fb818b2b3305f98", size = 12306201, upload-time = "2025-12-20T16:16:26.979Z" }, + { url = "https://files.pythonhosted.org/packages/70/09/c39dadf0b13bb0768cd29d6a3aaff1fb7c6905ac40e9aaeca26b1c086e06/numpy-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:39699233bc72dd482da1415dcb06076e32f60eddc796a796c5fb6c5efce94667", size = 10308234, upload-time = "2025-12-20T16:16:29.417Z" }, + { url = "https://files.pythonhosted.org/packages/a7/0d/853fd96372eda07c824d24adf02e8bc92bb3731b43a9b2a39161c3667cc4/numpy-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a152d86a3ae00ba5f47b3acf3b827509fd0b6cb7d3259665e63dafbad22a75ea", size = 16649088, upload-time = "2025-12-20T16:16:31.421Z" }, + { url = "https://files.pythonhosted.org/packages/e3/37/cc636f1f2a9f585434e20a3e6e63422f70bfe4f7f6698e941db52ea1ac9a/numpy-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:39b19251dec4de8ff8496cd0806cbe27bf0684f765abb1f4809554de93785f2d", size = 12364065, upload-time = "2025-12-20T16:16:33.491Z" }, + { url = "https://files.pythonhosted.org/packages/ed/69/0b78f37ca3690969beee54103ce5f6021709134e8020767e93ba691a72f1/numpy-2.4.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:009bd0ea12d3c784b6639a8457537016ce5172109e585338e11334f6a7bb88ee", size = 5192640, upload-time = "2025-12-20T16:16:35.636Z" }, + { url = "https://files.pythonhosted.org/packages/1d/2a/08569f8252abf590294dbb09a430543ec8f8cc710383abfb3e75cc73aeda/numpy-2.4.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5fe44e277225fd3dff6882d86d3d447205d43532c3627313d17e754fb3905a0e", size = 6541556, upload-time = "2025-12-20T16:16:37.276Z" }, + { url = "https://files.pythonhosted.org/packages/93/e9/a949885a4e177493d61519377952186b6cbfdf1d6002764c664ba28349b5/numpy-2.4.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f935c4493eda9069851058fa0d9e39dbf6286be690066509305e52912714dbb2", size = 14396562, upload-time = "2025-12-20T16:16:38.953Z" }, + { url = "https://files.pythonhosted.org/packages/99/98/9d4ad53b0e9ef901c2ef1d550d2136f5ac42d3fd2988390a6def32e23e48/numpy-2.4.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8cfa5f29a695cb7438965e6c3e8d06e0416060cf0d709c1b1c1653a939bf5c2a", size = 16351719, upload-time = "2025-12-20T16:16:41.503Z" }, + { url = "https://files.pythonhosted.org/packages/28/de/5f3711a38341d6e8dd619f6353251a0cdd07f3d6d101a8fd46f4ef87f895/numpy-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ba0cb30acd3ef11c94dc27fbfba68940652492bc107075e7ffe23057f9425681", size = 16176053, upload-time = "2025-12-20T16:16:44.552Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5b/2a3753dc43916501b4183532e7ace862e13211042bceafa253afb5c71272/numpy-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:60e8c196cd82cbbd4f130b5290007e13e6de3eca79f0d4d38014769d96a7c475", size = 18277859, upload-time = "2025-12-20T16:16:47.174Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c5/a18bcdd07a941db3076ef489d036ab16d2bfc2eae0cf27e5a26e29189434/numpy-2.4.0-cp313-cp313-win32.whl", hash = "sha256:5f48cb3e88fbc294dc90e215d86fbaf1c852c63dbdb6c3a3e63f45c4b57f7344", size = 5953849, upload-time = "2025-12-20T16:16:49.554Z" }, + { url = "https://files.pythonhosted.org/packages/4f/f1/719010ff8061da6e8a26e1980cf090412d4f5f8060b31f0c45d77dd67a01/numpy-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:a899699294f28f7be8992853c0c60741f16ff199205e2e6cdca155762cbaa59d", size = 12302840, upload-time = "2025-12-20T16:16:51.227Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5a/b3d259083ed8b4d335270c76966cb6cf14a5d1b69e1a608994ac57a659e6/numpy-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:9198f447e1dc5647d07c9a6bbe2063cc0132728cc7175b39dbc796da5b54920d", size = 10308509, upload-time = "2025-12-20T16:16:53.313Z" }, + { url = "https://files.pythonhosted.org/packages/31/01/95edcffd1bb6c0633df4e808130545c4f07383ab629ac7e316fb44fff677/numpy-2.4.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74623f2ab5cc3f7c886add4f735d1031a1d2be4a4ae63c0546cfd74e7a31ddf6", size = 12491815, upload-time = "2025-12-20T16:16:55.496Z" }, + { url = "https://files.pythonhosted.org/packages/59/ea/5644b8baa92cc1c7163b4b4458c8679852733fa74ca49c942cfa82ded4e0/numpy-2.4.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:0804a8e4ab070d1d35496e65ffd3cf8114c136a2b81f61dfab0de4b218aacfd5", size = 5320321, upload-time = "2025-12-20T16:16:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/26/4e/e10938106d70bc21319bd6a86ae726da37edc802ce35a3a71ecdf1fdfe7f/numpy-2.4.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:02a2038eb27f9443a8b266a66911e926566b5a6ffd1a689b588f7f35b81e7dc3", size = 6641635, upload-time = "2025-12-20T16:16:59.379Z" }, + { url = "https://files.pythonhosted.org/packages/b3/8d/a8828e3eaf5c0b4ab116924df82f24ce3416fa38d0674d8f708ddc6c8aac/numpy-2.4.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1889b3a3f47a7b5bee16bc25a2145bd7cb91897f815ce3499db64c7458b6d91d", size = 14456053, upload-time = "2025-12-20T16:17:01.768Z" }, + { url = "https://files.pythonhosted.org/packages/68/a1/17d97609d87d4520aa5ae2dcfb32305654550ac6a35effb946d303e594ce/numpy-2.4.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85eef4cb5625c47ee6425c58a3502555e10f45ee973da878ac8248ad58c136f3", size = 16401702, upload-time = "2025-12-20T16:17:04.235Z" }, + { url = "https://files.pythonhosted.org/packages/18/32/0f13c1b2d22bea1118356b8b963195446f3af124ed7a5adfa8fdecb1b6ca/numpy-2.4.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6dc8b7e2f4eb184b37655195f421836cfae6f58197b67e3ffc501f1333d993fa", size = 16242493, upload-time = "2025-12-20T16:17:06.856Z" }, + { url = "https://files.pythonhosted.org/packages/ae/23/48f21e3d309fbc137c068a1475358cbd3a901b3987dcfc97a029ab3068e2/numpy-2.4.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:44aba2f0cafd287871a495fb3163408b0bd25bbce135c6f621534a07f4f7875c", size = 18324222, upload-time = "2025-12-20T16:17:09.392Z" }, + { url = "https://files.pythonhosted.org/packages/ac/52/41f3d71296a3dcaa4f456aaa3c6fc8e745b43d0552b6bde56571bb4b4a0f/numpy-2.4.0-cp313-cp313t-win32.whl", hash = "sha256:20c115517513831860c573996e395707aa9fb691eb179200125c250e895fcd93", size = 6076216, upload-time = "2025-12-20T16:17:11.437Z" }, + { url = "https://files.pythonhosted.org/packages/35/ff/46fbfe60ab0710d2a2b16995f708750307d30eccbb4c38371ea9e986866e/numpy-2.4.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b48e35f4ab6f6a7597c46e301126ceba4c44cd3280e3750f85db48b082624fa4", size = 12444263, upload-time = "2025-12-20T16:17:13.182Z" }, + { url = "https://files.pythonhosted.org/packages/a3/e3/9189ab319c01d2ed556c932ccf55064c5d75bb5850d1df7a482ce0badead/numpy-2.4.0-cp313-cp313t-win_arm64.whl", hash = "sha256:4d1cfce39e511069b11e67cd0bd78ceff31443b7c9e5c04db73c7a19f572967c", size = 10378265, upload-time = "2025-12-20T16:17:15.211Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ed/52eac27de39d5e5a6c9aadabe672bc06f55e24a3d9010cd1183948055d76/numpy-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c95eb6db2884917d86cde0b4d4cf31adf485c8ec36bf8696dd66fa70de96f36b", size = 16647476, upload-time = "2025-12-20T16:17:17.671Z" }, + { url = "https://files.pythonhosted.org/packages/77/c0/990ce1b7fcd4e09aeaa574e2a0a839589e4b08b2ca68070f1acb1fea6736/numpy-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:65167da969cd1ec3a1df31cb221ca3a19a8aaa25370ecb17d428415e93c1935e", size = 12374563, upload-time = "2025-12-20T16:17:20.216Z" }, + { url = "https://files.pythonhosted.org/packages/37/7c/8c5e389c6ae8f5fd2277a988600d79e9625db3fff011a2d87ac80b881a4c/numpy-2.4.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3de19cfecd1465d0dcf8a5b5ea8b3155b42ed0b639dba4b71e323d74f2a3be5e", size = 5203107, upload-time = "2025-12-20T16:17:22.47Z" }, + { url = "https://files.pythonhosted.org/packages/e6/94/ca5b3bd6a8a70a5eec9a0b8dd7f980c1eff4b8a54970a9a7fef248ef564f/numpy-2.4.0-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:6c05483c3136ac4c91b4e81903cb53a8707d316f488124d0398499a4f8e8ef51", size = 6538067, upload-time = "2025-12-20T16:17:24.001Z" }, + { url = "https://files.pythonhosted.org/packages/79/43/993eb7bb5be6761dde2b3a3a594d689cec83398e3f58f4758010f3b85727/numpy-2.4.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36667db4d6c1cea79c8930ab72fadfb4060feb4bfe724141cd4bd064d2e5f8ce", size = 14411926, upload-time = "2025-12-20T16:17:25.822Z" }, + { url = "https://files.pythonhosted.org/packages/03/75/d4c43b61de473912496317a854dac54f1efec3eeb158438da6884b70bb90/numpy-2.4.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9a818668b674047fd88c4cddada7ab8f1c298812783e8328e956b78dc4807f9f", size = 16354295, upload-time = "2025-12-20T16:17:28.308Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0a/b54615b47ee8736a6461a4bb6749128dd3435c5a759d5663f11f0e9af4ac/numpy-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1ee32359fb7543b7b7bd0b2f46294db27e29e7bbdf70541e81b190836cd83ded", size = 16190242, upload-time = "2025-12-20T16:17:30.993Z" }, + { url = "https://files.pythonhosted.org/packages/98/ce/ea207769aacad6246525ec6c6bbd66a2bf56c72443dc10e2f90feed29290/numpy-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e493962256a38f58283de033d8af176c5c91c084ea30f15834f7545451c42059", size = 18280875, upload-time = "2025-12-20T16:17:33.327Z" }, + { url = "https://files.pythonhosted.org/packages/17/ef/ec409437aa962ea372ed601c519a2b141701683ff028f894b7466f0ab42b/numpy-2.4.0-cp314-cp314-win32.whl", hash = "sha256:6bbaebf0d11567fa8926215ae731e1d58e6ec28a8a25235b8a47405d301332db", size = 6002530, upload-time = "2025-12-20T16:17:35.729Z" }, + { url = "https://files.pythonhosted.org/packages/5f/4a/5cb94c787a3ed1ac65e1271b968686521169a7b3ec0b6544bb3ca32960b0/numpy-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:3d857f55e7fdf7c38ab96c4558c95b97d1c685be6b05c249f5fdafcbd6f9899e", size = 12435890, upload-time = "2025-12-20T16:17:37.599Z" }, + { url = "https://files.pythonhosted.org/packages/48/a0/04b89db963af9de1104975e2544f30de89adbf75b9e75f7dd2599be12c79/numpy-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:bb50ce5fb202a26fd5404620e7ef820ad1ab3558b444cb0b55beb7ef66cd2d63", size = 10591892, upload-time = "2025-12-20T16:17:39.649Z" }, + { url = "https://files.pythonhosted.org/packages/53/e5/d74b5ccf6712c06c7a545025a6a71bfa03bdc7e0568b405b0d655232fd92/numpy-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:355354388cba60f2132df297e2d53053d4063f79077b67b481d21276d61fc4df", size = 12494312, upload-time = "2025-12-20T16:17:41.714Z" }, + { url = "https://files.pythonhosted.org/packages/c2/08/3ca9cc2ddf54dfee7ae9a6479c071092a228c68aef08252aa08dac2af002/numpy-2.4.0-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:1d8f9fde5f6dc1b6fc34df8162f3b3079365468703fee7f31d4e0cc8c63baed9", size = 5322862, upload-time = "2025-12-20T16:17:44.145Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/0bb63a68394c0c1e52670cfff2e309afa41edbe11b3327d9af29e4383f34/numpy-2.4.0-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:e0434aa22c821f44eeb4c650b81c7fbdd8c0122c6c4b5a576a76d5a35625ecd9", size = 6644986, upload-time = "2025-12-20T16:17:46.203Z" }, + { url = "https://files.pythonhosted.org/packages/06/8f/9264d9bdbcf8236af2823623fe2f3981d740fc3461e2787e231d97c38c28/numpy-2.4.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40483b2f2d3ba7aad426443767ff5632ec3156ef09742b96913787d13c336471", size = 14457958, upload-time = "2025-12-20T16:17:48.017Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d9/f9a69ae564bbc7236a35aa883319364ef5fd41f72aa320cc1cbe66148fe2/numpy-2.4.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9e6a7664ddd9746e20b7325351fe1a8408d0a2bf9c63b5e898290ddc8f09544", size = 16398394, upload-time = "2025-12-20T16:17:50.409Z" }, + { url = "https://files.pythonhosted.org/packages/34/c7/39241501408dde7f885d241a98caba5421061a2c6d2b2197ac5e3aa842d8/numpy-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ecb0019d44f4cdb50b676c5d0cb4b1eae8e15d1ed3d3e6639f986fc92b2ec52c", size = 16241044, upload-time = "2025-12-20T16:17:52.661Z" }, + { url = "https://files.pythonhosted.org/packages/7c/95/cae7effd90e065a95e59fe710eeee05d7328ed169776dfdd9f789e032125/numpy-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d0ffd9e2e4441c96a9c91ec1783285d80bf835b677853fc2770a89d50c1e48ac", size = 18321772, upload-time = "2025-12-20T16:17:54.947Z" }, + { url = "https://files.pythonhosted.org/packages/96/df/3c6c279accd2bfb968a76298e5b276310bd55d243df4fa8ac5816d79347d/numpy-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:77f0d13fa87036d7553bf81f0e1fe3ce68d14c9976c9851744e4d3e91127e95f", size = 6148320, upload-time = "2025-12-20T16:17:57.249Z" }, + { url = "https://files.pythonhosted.org/packages/92/8d/f23033cce252e7a75cae853d17f582e86534c46404dea1c8ee094a9d6d84/numpy-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b1f5b45829ac1848893f0ddf5cb326110604d6df96cdc255b0bf9edd154104d4", size = 12623460, upload-time = "2025-12-20T16:17:58.963Z" }, + { url = "https://files.pythonhosted.org/packages/a4/4f/1f8475907d1a7c4ef9020edf7f39ea2422ec896849245f00688e4b268a71/numpy-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:23a3e9d1a6f360267e8fbb38ba5db355a6a7e9be71d7fce7ab3125e88bb646c8", size = 10661799, upload-time = "2025-12-20T16:18:01.078Z" }, +] + +[[package]] +name = "nvidia-cublas-cu12" +version = "12.8.4.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.10.2.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.3.83" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, +] + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.13.1.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.9.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.3.90" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, + { name = "nvidia-cusparse-cu12" }, + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, +] + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.8.93" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, +] + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.27.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" }, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, +] + +[[package]] +name = "nvidia-nvshmem-cu12" +version = "3.3.20" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145, upload-time = "2025-08-04T20:25:19.995Z" }, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, +] + +[[package]] +name = "openpyxl" +version = "3.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "et-xmlfile" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/f9/88d94a75de065ea32619465d2f77b29a0469500e99012523b91cc4141cd1/openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050", size = 186464, upload-time = "2024-06-28T14:03:44.161Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2", size = 250910, upload-time = "2024-06-28T14:03:41.161Z" }, +] + +[[package]] +name = "orjson" +version = "3.11.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/04/b8/333fdb27840f3bf04022d21b654a35f58e15407183aeb16f3b41aa053446/orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5", size = 5972347, upload-time = "2025-12-06T15:55:39.458Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a4/8052a029029b096a78955eadd68ab594ce2197e24ec50e6b6d2ab3f4e33b/orjson-3.11.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:334e5b4bff9ad101237c2d799d9fd45737752929753bf4faf4b207335a416b7d", size = 245347, upload-time = "2025-12-06T15:54:22.061Z" }, + { url = "https://files.pythonhosted.org/packages/64/67/574a7732bd9d9d79ac620c8790b4cfe0717a3d5a6eb2b539e6e8995e24a0/orjson-3.11.5-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:ff770589960a86eae279f5d8aa536196ebda8273a2a07db2a54e82b93bc86626", size = 129435, upload-time = "2025-12-06T15:54:23.615Z" }, + { url = "https://files.pythonhosted.org/packages/52/8d/544e77d7a29d90cf4d9eecd0ae801c688e7f3d1adfa2ebae5e1e94d38ab9/orjson-3.11.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed24250e55efbcb0b35bed7caaec8cedf858ab2f9f2201f17b8938c618c8ca6f", size = 132074, upload-time = "2025-12-06T15:54:24.694Z" }, + { url = "https://files.pythonhosted.org/packages/6e/57/b9f5b5b6fbff9c26f77e785baf56ae8460ef74acdb3eae4931c25b8f5ba9/orjson-3.11.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a66d7769e98a08a12a139049aac2f0ca3adae989817f8c43337455fbc7669b85", size = 130520, upload-time = "2025-12-06T15:54:26.185Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6d/d34970bf9eb33f9ec7c979a262cad86076814859e54eb9a059a52f6dc13d/orjson-3.11.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86cfc555bfd5794d24c6a1903e558b50644e5e68e6471d66502ce5cb5fdef3f9", size = 136209, upload-time = "2025-12-06T15:54:27.264Z" }, + { url = "https://files.pythonhosted.org/packages/e7/39/bc373b63cc0e117a105ea12e57280f83ae52fdee426890d57412432d63b3/orjson-3.11.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a230065027bc2a025e944f9d4714976a81e7ecfa940923283bca7bbc1f10f626", size = 139837, upload-time = "2025-12-06T15:54:28.75Z" }, + { url = "https://files.pythonhosted.org/packages/cb/aa/7c4818c8d7d324da220f4f1af55c343956003aa4d1ce1857bdc1d396ba69/orjson-3.11.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b29d36b60e606df01959c4b982729c8845c69d1963f88686608be9ced96dbfaa", size = 137307, upload-time = "2025-12-06T15:54:29.856Z" }, + { url = "https://files.pythonhosted.org/packages/46/bf/0993b5a056759ba65145effe3a79dd5a939d4a070eaa5da2ee3180fbb13f/orjson-3.11.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74099c6b230d4261fdc3169d50efc09abf38ace1a42ea2f9994b1d79153d477", size = 139020, upload-time = "2025-12-06T15:54:31.024Z" }, + { url = "https://files.pythonhosted.org/packages/65/e8/83a6c95db3039e504eda60fc388f9faedbb4f6472f5aba7084e06552d9aa/orjson-3.11.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e697d06ad57dd0c7a737771d470eedc18e68dfdefcdd3b7de7f33dfda5b6212e", size = 141099, upload-time = "2025-12-06T15:54:32.196Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b4/24fdc024abfce31c2f6812973b0a693688037ece5dc64b7a60c1ce69e2f2/orjson-3.11.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e08ca8a6c851e95aaecc32bc44a5aa75d0ad26af8cdac7c77e4ed93acf3d5b69", size = 413540, upload-time = "2025-12-06T15:54:33.361Z" }, + { url = "https://files.pythonhosted.org/packages/d9/37/01c0ec95d55ed0c11e4cae3e10427e479bba40c77312b63e1f9665e0737d/orjson-3.11.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e8b5f96c05fce7d0218df3fdfeb962d6b8cfff7e3e20264306b46dd8b217c0f3", size = 151530, upload-time = "2025-12-06T15:54:34.6Z" }, + { url = "https://files.pythonhosted.org/packages/f9/d4/f9ebc57182705bb4bbe63f5bbe14af43722a2533135e1d2fb7affa0c355d/orjson-3.11.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ddbfdb5099b3e6ba6d6ea818f61997bb66de14b411357d24c4612cf1ebad08ca", size = 141863, upload-time = "2025-12-06T15:54:35.801Z" }, + { url = "https://files.pythonhosted.org/packages/0d/04/02102b8d19fdcb009d72d622bb5781e8f3fae1646bf3e18c53d1bc8115b5/orjson-3.11.5-cp312-cp312-win32.whl", hash = "sha256:9172578c4eb09dbfcf1657d43198de59b6cef4054de385365060ed50c458ac98", size = 135255, upload-time = "2025-12-06T15:54:37.209Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fb/f05646c43d5450492cb387de5549f6de90a71001682c17882d9f66476af5/orjson-3.11.5-cp312-cp312-win_amd64.whl", hash = "sha256:2b91126e7b470ff2e75746f6f6ee32b9ab67b7a93c8ba1d15d3a0caaf16ec875", size = 133252, upload-time = "2025-12-06T15:54:38.401Z" }, + { url = "https://files.pythonhosted.org/packages/dc/a6/7b8c0b26ba18c793533ac1cd145e131e46fcf43952aa94c109b5b913c1f0/orjson-3.11.5-cp312-cp312-win_arm64.whl", hash = "sha256:acbc5fac7e06777555b0722b8ad5f574739e99ffe99467ed63da98f97f9ca0fe", size = 126777, upload-time = "2025-12-06T15:54:39.515Z" }, + { url = "https://files.pythonhosted.org/packages/10/43/61a77040ce59f1569edf38f0b9faadc90c8cf7e9bec2e0df51d0132c6bb7/orjson-3.11.5-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3b01799262081a4c47c035dd77c1301d40f568f77cc7ec1bb7db5d63b0a01629", size = 245271, upload-time = "2025-12-06T15:54:40.878Z" }, + { url = "https://files.pythonhosted.org/packages/55/f9/0f79be617388227866d50edd2fd320cb8fb94dc1501184bb1620981a0aba/orjson-3.11.5-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:61de247948108484779f57a9f406e4c84d636fa5a59e411e6352484985e8a7c3", size = 129422, upload-time = "2025-12-06T15:54:42.403Z" }, + { url = "https://files.pythonhosted.org/packages/77/42/f1bf1549b432d4a78bfa95735b79b5dac75b65b5bb815bba86ad406ead0a/orjson-3.11.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:894aea2e63d4f24a7f04a1908307c738d0dce992e9249e744b8f4e8dd9197f39", size = 132060, upload-time = "2025-12-06T15:54:43.531Z" }, + { url = "https://files.pythonhosted.org/packages/25/49/825aa6b929f1a6ed244c78acd7b22c1481fd7e5fda047dc8bf4c1a807eb6/orjson-3.11.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ddc21521598dbe369d83d4d40338e23d4101dad21dae0e79fa20465dbace019f", size = 130391, upload-time = "2025-12-06T15:54:45.059Z" }, + { url = "https://files.pythonhosted.org/packages/42/ec/de55391858b49e16e1aa8f0bbbb7e5997b7345d8e984a2dec3746d13065b/orjson-3.11.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cce16ae2f5fb2c53c3eafdd1706cb7b6530a67cc1c17abe8ec747f5cd7c0c51", size = 135964, upload-time = "2025-12-06T15:54:46.576Z" }, + { url = "https://files.pythonhosted.org/packages/1c/40/820bc63121d2d28818556a2d0a09384a9f0262407cf9fa305e091a8048df/orjson-3.11.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e46c762d9f0e1cfb4ccc8515de7f349abbc95b59cb5a2bd68df5973fdef913f8", size = 139817, upload-time = "2025-12-06T15:54:48.084Z" }, + { url = "https://files.pythonhosted.org/packages/09/c7/3a445ca9a84a0d59d26365fd8898ff52bdfcdcb825bcc6519830371d2364/orjson-3.11.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7345c759276b798ccd6d77a87136029e71e66a8bbf2d2755cbdde1d82e78706", size = 137336, upload-time = "2025-12-06T15:54:49.426Z" }, + { url = "https://files.pythonhosted.org/packages/9a/b3/dc0d3771f2e5d1f13368f56b339c6782f955c6a20b50465a91acb79fe961/orjson-3.11.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75bc2e59e6a2ac1dd28901d07115abdebc4563b5b07dd612bf64260a201b1c7f", size = 138993, upload-time = "2025-12-06T15:54:50.939Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a2/65267e959de6abe23444659b6e19c888f242bf7725ff927e2292776f6b89/orjson-3.11.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:54aae9b654554c3b4edd61896b978568c6daa16af96fa4681c9b5babd469f863", size = 141070, upload-time = "2025-12-06T15:54:52.414Z" }, + { url = "https://files.pythonhosted.org/packages/63/c9/da44a321b288727a322c6ab17e1754195708786a04f4f9d2220a5076a649/orjson-3.11.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4bdd8d164a871c4ec773f9de0f6fe8769c2d6727879c37a9666ba4183b7f8228", size = 413505, upload-time = "2025-12-06T15:54:53.67Z" }, + { url = "https://files.pythonhosted.org/packages/7f/17/68dc14fa7000eefb3d4d6d7326a190c99bb65e319f02747ef3ebf2452f12/orjson-3.11.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a261fef929bcf98a60713bf5e95ad067cea16ae345d9a35034e73c3990e927d2", size = 151342, upload-time = "2025-12-06T15:54:55.113Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c5/ccee774b67225bed630a57478529fc026eda33d94fe4c0eac8fe58d4aa52/orjson-3.11.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c028a394c766693c5c9909dec76b24f37e6a1b91999e8d0c0d5feecbe93c3e05", size = 141823, upload-time = "2025-12-06T15:54:56.331Z" }, + { url = "https://files.pythonhosted.org/packages/67/80/5d00e4155d0cd7390ae2087130637671da713959bb558db9bac5e6f6b042/orjson-3.11.5-cp313-cp313-win32.whl", hash = "sha256:2cc79aaad1dfabe1bd2d50ee09814a1253164b3da4c00a78c458d82d04b3bdef", size = 135236, upload-time = "2025-12-06T15:54:57.507Z" }, + { url = "https://files.pythonhosted.org/packages/95/fe/792cc06a84808dbdc20ac6eab6811c53091b42f8e51ecebf14b540e9cfe4/orjson-3.11.5-cp313-cp313-win_amd64.whl", hash = "sha256:ff7877d376add4e16b274e35a3f58b7f37b362abf4aa31863dadacdd20e3a583", size = 133167, upload-time = "2025-12-06T15:54:58.71Z" }, + { url = "https://files.pythonhosted.org/packages/46/2c/d158bd8b50e3b1cfdcf406a7e463f6ffe3f0d167b99634717acdaf5e299f/orjson-3.11.5-cp313-cp313-win_arm64.whl", hash = "sha256:59ac72ea775c88b163ba8d21b0177628bd015c5dd060647bbab6e22da3aad287", size = 126712, upload-time = "2025-12-06T15:54:59.892Z" }, + { url = "https://files.pythonhosted.org/packages/c2/60/77d7b839e317ead7bb225d55bb50f7ea75f47afc489c81199befc5435b50/orjson-3.11.5-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e446a8ea0a4c366ceafc7d97067bfd55292969143b57e3c846d87fc701e797a0", size = 245252, upload-time = "2025-12-06T15:55:01.127Z" }, + { url = "https://files.pythonhosted.org/packages/f1/aa/d4639163b400f8044cef0fb9aa51b0337be0da3a27187a20d1166e742370/orjson-3.11.5-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:53deb5addae9c22bbe3739298f5f2196afa881ea75944e7720681c7080909a81", size = 129419, upload-time = "2025-12-06T15:55:02.723Z" }, + { url = "https://files.pythonhosted.org/packages/30/94/9eabf94f2e11c671111139edf5ec410d2f21e6feee717804f7e8872d883f/orjson-3.11.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd00d49d6063d2b8791da5d4f9d20539c5951f965e45ccf4e96d33505ce68f", size = 132050, upload-time = "2025-12-06T15:55:03.918Z" }, + { url = "https://files.pythonhosted.org/packages/3d/c8/ca10f5c5322f341ea9a9f1097e140be17a88f88d1cfdd29df522970d9744/orjson-3.11.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3fd15f9fc8c203aeceff4fda211157fad114dde66e92e24097b3647a08f4ee9e", size = 130370, upload-time = "2025-12-06T15:55:05.173Z" }, + { url = "https://files.pythonhosted.org/packages/25/d4/e96824476d361ee2edd5c6290ceb8d7edf88d81148a6ce172fc00278ca7f/orjson-3.11.5-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df95000fbe6777bf9820ae82ab7578e8662051bb5f83d71a28992f539d2cda7", size = 136012, upload-time = "2025-12-06T15:55:06.402Z" }, + { url = "https://files.pythonhosted.org/packages/85/8e/9bc3423308c425c588903f2d103cfcfe2539e07a25d6522900645a6f257f/orjson-3.11.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a8d676748fca47ade5bc3da7430ed7767afe51b2f8100e3cd65e151c0eaceb", size = 139809, upload-time = "2025-12-06T15:55:07.656Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3c/b404e94e0b02a232b957c54643ce68d0268dacb67ac33ffdee24008c8b27/orjson-3.11.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa0f513be38b40234c77975e68805506cad5d57b3dfd8fe3baa7f4f4051e15b4", size = 137332, upload-time = "2025-12-06T15:55:08.961Z" }, + { url = "https://files.pythonhosted.org/packages/51/30/cc2d69d5ce0ad9b84811cdf4a0cd5362ac27205a921da524ff42f26d65e0/orjson-3.11.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1863e75b92891f553b7922ce4ee10ed06db061e104f2b7815de80cdcb135ad", size = 138983, upload-time = "2025-12-06T15:55:10.595Z" }, + { url = "https://files.pythonhosted.org/packages/0e/87/de3223944a3e297d4707d2fe3b1ffb71437550e165eaf0ca8bbe43ccbcb1/orjson-3.11.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4be86b58e9ea262617b8ca6251a2f0d63cc132a6da4b5fcc8e0a4128782c829", size = 141069, upload-time = "2025-12-06T15:55:11.832Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/81d5087ae74be33bcae3ff2d80f5ccaa4a8fedc6d39bf65a427a95b8977f/orjson-3.11.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b923c1c13fa02084eb38c9c065afd860a5cff58026813319a06949c3af5732ac", size = 413491, upload-time = "2025-12-06T15:55:13.314Z" }, + { url = "https://files.pythonhosted.org/packages/d0/6f/f6058c21e2fc1efaf918986dbc2da5cd38044f1a2d4b7b91ad17c4acf786/orjson-3.11.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1b6bd351202b2cd987f35a13b5e16471cf4d952b42a73c391cc537974c43ef6d", size = 151375, upload-time = "2025-12-06T15:55:14.715Z" }, + { url = "https://files.pythonhosted.org/packages/54/92/c6921f17d45e110892899a7a563a925b2273d929959ce2ad89e2525b885b/orjson-3.11.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb150d529637d541e6af06bbe3d02f5498d628b7f98267ff87647584293ab439", size = 141850, upload-time = "2025-12-06T15:55:15.94Z" }, + { url = "https://files.pythonhosted.org/packages/88/86/cdecb0140a05e1a477b81f24739da93b25070ee01ce7f7242f44a6437594/orjson-3.11.5-cp314-cp314-win32.whl", hash = "sha256:9cc1e55c884921434a84a0c3dd2699eb9f92e7b441d7f53f3941079ec6ce7499", size = 135278, upload-time = "2025-12-06T15:55:17.202Z" }, + { url = "https://files.pythonhosted.org/packages/e4/97/b638d69b1e947d24f6109216997e38922d54dcdcdb1b11c18d7efd2d3c59/orjson-3.11.5-cp314-cp314-win_amd64.whl", hash = "sha256:a4f3cb2d874e03bc7767c8f88adaa1a9a05cecea3712649c3b58589ec7317310", size = 133170, upload-time = "2025-12-06T15:55:18.468Z" }, + { url = "https://files.pythonhosted.org/packages/8f/dd/f4fff4a6fe601b4f8f3ba3aa6da8ac33d17d124491a3b804c662a70e1636/orjson-3.11.5-cp314-cp314-win_arm64.whl", hash = "sha256:38b22f476c351f9a1c43e5b07d8b5a02eb24a6ab8e75f700f7d479d4568346a5", size = 126713, upload-time = "2025-12-06T15:55:19.738Z" }, +] + +[[package]] +name = "ormsgpack" +version = "1.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/96/34c40d621996c2f377a18decbd3c59f031dde73c3ba47d1e1e8f29a05aaa/ormsgpack-1.12.1.tar.gz", hash = "sha256:a3877fde1e4f27a39f92681a0aab6385af3a41d0c25375d33590ae20410ea2ac", size = 39476, upload-time = "2025-12-14T07:57:43.248Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/fe/ab9167ca037406b5703add24049cf3e18021a3b16133ea20615b1f160ea4/ormsgpack-1.12.1-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4d7fb0e1b6fbc701d75269f7405a4f79230a6ce0063fb1092e4f6577e312f86d", size = 376725, upload-time = "2025-12-14T07:57:07.894Z" }, + { url = "https://files.pythonhosted.org/packages/c7/ea/2820e65f506894c459b840d1091ae6e327fde3d5a3f3b002a11a1b9bdf7d/ormsgpack-1.12.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43a9353e2db5b024c91a47d864ef15eaa62d81824cfc7740fed4cef7db738694", size = 202466, upload-time = "2025-12-14T07:57:09.049Z" }, + { url = "https://files.pythonhosted.org/packages/45/8b/def01c13339c5bbec2ee1469ef53e7fadd66c8d775df974ee4def1572515/ormsgpack-1.12.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fc8fe866b7706fc25af0adf1f600bc06ece5b15ca44e34641327198b821e5c3c", size = 210748, upload-time = "2025-12-14T07:57:10.074Z" }, + { url = "https://files.pythonhosted.org/packages/5d/d2/bf350c92f7f067dd9484499705f2d8366d8d9008a670e3d1d0add1908f85/ormsgpack-1.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:813755b5f598a78242042e05dfd1ada4e769e94b98c9ab82554550f97ff4d641", size = 211510, upload-time = "2025-12-14T07:57:11.165Z" }, + { url = "https://files.pythonhosted.org/packages/74/92/9d689bcb95304a6da26c4d59439c350940c25d1b35f146d402ccc6344c51/ormsgpack-1.12.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8eea2a13536fae45d78f93f2cc846c9765c7160c85f19cfefecc20873c137cdd", size = 386237, upload-time = "2025-12-14T07:57:12.306Z" }, + { url = "https://files.pythonhosted.org/packages/17/fe/bd3107547f8b6129265dd957f40b9cd547d2445db2292aacb13335a7ea89/ormsgpack-1.12.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7a02ebda1a863cbc604740e76faca8eee1add322db2dcbe6cf32669fffdff65c", size = 479589, upload-time = "2025-12-14T07:57:13.475Z" }, + { url = "https://files.pythonhosted.org/packages/c1/7c/e8e5cc9edb967d44f6f85e9ebdad440b59af3fae00b137a4327dc5aed9bb/ormsgpack-1.12.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3c0bd63897c439931cdf29348e5e6e8c330d529830e848d10767615c0f3d1b82", size = 388077, upload-time = "2025-12-14T07:57:14.551Z" }, + { url = "https://files.pythonhosted.org/packages/35/6b/5031797e43b58506f28a8760b26dc23f2620fb4f2200c4c1b3045603e67e/ormsgpack-1.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:362f2e812f8d7035dc25a009171e09d7cc97cb30d3c9e75a16aeae00ca3c1dcf", size = 116190, upload-time = "2025-12-14T07:57:15.575Z" }, + { url = "https://files.pythonhosted.org/packages/1e/fd/9f43ea6425e383a6b2dbfafebb06fd60e8d68c700ef715adfbcdb499f75d/ormsgpack-1.12.1-cp312-cp312-win_arm64.whl", hash = "sha256:6190281e381db2ed0045052208f47a995ccf61eed48f1215ae3cce3fbccd59c5", size = 109990, upload-time = "2025-12-14T07:57:16.419Z" }, + { url = "https://files.pythonhosted.org/packages/11/42/f110dfe7cf23a52a82e23eb23d9a6a76ae495447d474686dfa758f3d71d6/ormsgpack-1.12.1-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:9663d6b3ecc917c063d61a99169ce196a80f3852e541ae404206836749459279", size = 376746, upload-time = "2025-12-14T07:57:17.699Z" }, + { url = "https://files.pythonhosted.org/packages/11/76/b386e508a8ae207daec240201a81adb26467bf99b163560724e86bd9ff33/ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32e85cfbaf01a94a92520e7fe7851cfcfe21a5698299c28ab86194895f9b9233", size = 202489, upload-time = "2025-12-14T07:57:18.807Z" }, + { url = "https://files.pythonhosted.org/packages/ea/0e/5db7a63f387149024572daa3d9512fe8fb14bf4efa0722d6d491bed280e7/ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dabfd2c24b59c7c69870a5ecee480dfae914a42a0c2e7c9d971cf531e2ba471a", size = 210757, upload-time = "2025-12-14T07:57:19.893Z" }, + { url = "https://files.pythonhosted.org/packages/64/79/3a9899e57cb57430bd766fc1b4c9ad410cb2ba6070bc8cf6301e7d385768/ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51bbf2b64afeded34ccd8e25402e4bca038757913931fa0d693078d75563f6f9", size = 211518, upload-time = "2025-12-14T07:57:20.972Z" }, + { url = "https://files.pythonhosted.org/packages/d7/cd/4f41710ae9fe50d7fcbe476793b3c487746d0e1cc194cc0fee42ff6d989b/ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9959a71dde1bd0ced84af17facc06a8afada495a34e9cb1bad8e9b20d4c59cef", size = 386251, upload-time = "2025-12-14T07:57:22.099Z" }, + { url = "https://files.pythonhosted.org/packages/bf/54/ba0c97d6231b1f01daafaa520c8cce1e1b7fceaae6fdc1c763925874a7de/ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:e9be0e3b62d758f21f5b20e0e06b3a240ec546c4a327bf771f5825462aa74714", size = 479607, upload-time = "2025-12-14T07:57:23.525Z" }, + { url = "https://files.pythonhosted.org/packages/18/75/19a9a97a462776d525baf41cfb7072734528775f0a3d5fbfab3aa7756b9b/ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a29d49ab7fdd77ea787818e60cb4ef491708105b9c4c9b0f919201625eb036b5", size = 388062, upload-time = "2025-12-14T07:57:24.616Z" }, + { url = "https://files.pythonhosted.org/packages/a8/6a/ec26e3f44e9632ecd2f43638b7b37b500eaea5d79cab984ad0b94be14f82/ormsgpack-1.12.1-cp313-cp313-win_amd64.whl", hash = "sha256:c418390b47a1d367e803f6c187f77e4d67c7ae07ba962e3a4a019001f4b0291a", size = 116195, upload-time = "2025-12-14T07:57:25.626Z" }, + { url = "https://files.pythonhosted.org/packages/7d/64/bfa5f4a34d0f15c6aba1b73e73f7441a66d635bd03249d334a4796b7a924/ormsgpack-1.12.1-cp313-cp313-win_arm64.whl", hash = "sha256:cfa22c91cffc10a7fbd43729baff2de7d9c28cef2509085a704168ae31f02568", size = 109986, upload-time = "2025-12-14T07:57:26.569Z" }, + { url = "https://files.pythonhosted.org/packages/87/0e/78e5697164e3223b9b216c13e99f1acbc1ee9833490d68842b13da8ba883/ormsgpack-1.12.1-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b93c91efb1a70751a1902a5b43b27bd8fd38e0ca0365cf2cde2716423c15c3a6", size = 376758, upload-time = "2025-12-14T07:57:27.641Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/3a3cbb64703263d7bbaed7effa3ce78cb9add360a60aa7c544d7df28b641/ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf0ea0389167b5fa8d2933dd3f33e887ec4ba68f89c25214d7eec4afd746d22", size = 202487, upload-time = "2025-12-14T07:57:29.051Z" }, + { url = "https://files.pythonhosted.org/packages/d7/2c/807ebe2b77995599bbb1dec8c3f450d5d7dddee14ce3e1e71dc60e2e2a74/ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4c29af837f35af3375070689e781161e7cf019eb2f7cd641734ae45cd001c0d", size = 210853, upload-time = "2025-12-14T07:57:30.508Z" }, + { url = "https://files.pythonhosted.org/packages/25/57/2cdfc354e3ad8e847628f511f4d238799d90e9e090941e50b9d5ba955ae2/ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:336fc65aa0fe65896a3dabaae31e332a0a98b4a00ad7b0afde21a7505fd23ff3", size = 211545, upload-time = "2025-12-14T07:57:31.585Z" }, + { url = "https://files.pythonhosted.org/packages/76/1d/c6fda560e4a8ff865b3aec8a86f7c95ab53f4532193a6ae4ab9db35f85aa/ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:940f60aabfefe71dd6b82cb33f4ff10b2e7f5fcfa5f103cdb0a23b6aae4c713c", size = 386333, upload-time = "2025-12-14T07:57:32.957Z" }, + { url = "https://files.pythonhosted.org/packages/fc/3e/715081b36fceb8b497c68b87d384e1cc6d9c9c130ce3b435634d3d785b86/ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:596ad9e1b6d4c95595c54aaf49b1392609ca68f562ce06f4f74a5bc4053bcda4", size = 479701, upload-time = "2025-12-14T07:57:34.686Z" }, + { url = "https://files.pythonhosted.org/packages/6d/cf/01ad04def42b3970fc1a302c07f4b46339edf62ef9650247097260471f40/ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:575210e8fcbc7b0375026ba040a5eef223e9f66a4453d9623fc23282ae09c3c8", size = 388148, upload-time = "2025-12-14T07:57:35.771Z" }, + { url = "https://files.pythonhosted.org/packages/15/91/1fff2fc2b5943c740028f339154e7103c8f2edf1a881d9fbba2ce11c3b1d/ormsgpack-1.12.1-cp314-cp314-win_amd64.whl", hash = "sha256:647daa3718572280893456be44c60aea6690b7f2edc54c55648ee66e8f06550f", size = 116201, upload-time = "2025-12-14T07:57:36.763Z" }, + { url = "https://files.pythonhosted.org/packages/ed/66/142b542aed3f96002c7d1c33507ca6e1e0d0a42b9253ab27ef7ed5793bd9/ormsgpack-1.12.1-cp314-cp314-win_arm64.whl", hash = "sha256:a8b3ab762a6deaf1b6490ab46dda0c51528cf8037e0246c40875c6fe9e37b699", size = 110029, upload-time = "2025-12-14T07:57:37.703Z" }, + { url = "https://files.pythonhosted.org/packages/38/b3/ef4494438c90359e1547eaed3c5ec46e2c431d59a3de2af4e70ebd594c49/ormsgpack-1.12.1-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:12087214e436c1f6c28491949571abea759a63111908c4f7266586d78144d7a8", size = 376777, upload-time = "2025-12-14T07:57:38.795Z" }, + { url = "https://files.pythonhosted.org/packages/05/a0/1149a7163f8b0dfbc64bf9099b6f16d102ad3b03bcc11afee198d751da2d/ormsgpack-1.12.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6d54c14cf86ef13f10ccade94d1e7de146aa9b17d371e18b16e95f329393b7", size = 202490, upload-time = "2025-12-14T07:57:40.168Z" }, + { url = "https://files.pythonhosted.org/packages/68/82/f2ec5e758d6a7106645cca9bb7137d98bce5d363789fa94075be6572057c/ormsgpack-1.12.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f3584d07882b7ea2a1a589f795a3af97fe4c2932b739408e6d1d9d286cad862", size = 211733, upload-time = "2025-12-14T07:57:42.253Z" }, +] + +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950, upload-time = "2024-11-08T09:47:47.202Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451, upload-time = "2024-11-08T09:47:44.722Z" }, +] + +[[package]] +name = "pandas" +version = "2.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" }, + { url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" }, + { url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" }, + { url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693, upload-time = "2025-09-29T23:20:14.098Z" }, + { url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002, upload-time = "2025-09-29T23:20:26.76Z" }, + { url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971, upload-time = "2025-09-29T23:20:41.344Z" }, + { url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722, upload-time = "2025-09-29T23:20:54.139Z" }, + { url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671, upload-time = "2025-09-29T23:21:05.024Z" }, + { url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807, upload-time = "2025-09-29T23:21:15.979Z" }, + { url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872, upload-time = "2025-09-29T23:21:27.165Z" }, + { url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371, upload-time = "2025-09-29T23:21:40.532Z" }, + { url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333, upload-time = "2025-09-29T23:21:55.77Z" }, + { url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120, upload-time = "2025-09-29T23:22:10.109Z" }, + { url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991, upload-time = "2025-09-29T23:25:04.889Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227, upload-time = "2025-09-29T23:22:24.343Z" }, + { url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056, upload-time = "2025-09-29T23:22:37.762Z" }, + { url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189, upload-time = "2025-09-29T23:22:51.688Z" }, + { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" }, + { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" }, + { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" }, + { url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635, upload-time = "2025-09-29T23:25:52.486Z" }, + { url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079, upload-time = "2025-09-29T23:26:33.204Z" }, + { url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049, upload-time = "2025-09-29T23:27:15.384Z" }, + { url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638, upload-time = "2025-09-29T23:27:51.625Z" }, + { url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834, upload-time = "2025-09-29T23:28:21.289Z" }, + { url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925, upload-time = "2025-09-29T23:28:58.261Z" }, + { url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071, upload-time = "2025-09-29T23:32:27.484Z" }, + { url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504, upload-time = "2025-09-29T23:29:31.47Z" }, + { url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702, upload-time = "2025-09-29T23:29:54.591Z" }, + { url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535, upload-time = "2025-09-29T23:30:21.003Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582, upload-time = "2025-09-29T23:30:43.391Z" }, + { url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963, upload-time = "2025-09-29T23:31:10.009Z" }, + { url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" }, +] + +[[package]] +name = "pandocfilters" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, +] + +[[package]] +name = "parso" +version = "0.8.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, +] + +[[package]] +name = "pathspec" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/b9/6eb731b52f132181a9144bbe77ff82117f6b2d2fbfba49aaab2c014c4760/pathspec-1.0.2.tar.gz", hash = "sha256:fa32b1eb775ed9ba8d599b22c5f906dc098113989da2c00bf8b210078ca7fb92", size = 130502, upload-time = "2026-01-08T04:33:27.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/6b/14fc9049d78435fd29e82846c777bd7ed9c470013dc8d0260fff3ff1c11e/pathspec-1.0.2-py3-none-any.whl", hash = "sha256:62f8558917908d237d399b9b338ef455a814801a4688bc41074b25feefd93472", size = 54844, upload-time = "2026-01-08T04:33:26.4Z" }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "pillow" +version = "12.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/02/d52c733a2452ef1ffcc123b68e6606d07276b0e358db70eabad7e40042b7/pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9", size = 46977283, upload-time = "2026-01-02T09:13:29.892Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/31/dc53fe21a2f2996e1b7d92bf671cdb157079385183ef7c1ae08b485db510/pillow-12.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a332ac4ccb84b6dde65dbace8431f3af08874bf9770719d32a635c4ef411b18b", size = 5262642, upload-time = "2026-01-02T09:11:10.138Z" }, + { url = "https://files.pythonhosted.org/packages/ab/c1/10e45ac9cc79419cedf5121b42dcca5a50ad2b601fa080f58c22fb27626e/pillow-12.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:907bfa8a9cb790748a9aa4513e37c88c59660da3bcfffbd24a7d9e6abf224551", size = 4657464, upload-time = "2026-01-02T09:11:12.319Z" }, + { url = "https://files.pythonhosted.org/packages/ad/26/7b82c0ab7ef40ebede7a97c72d473bda5950f609f8e0c77b04af574a0ddb/pillow-12.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efdc140e7b63b8f739d09a99033aa430accce485ff78e6d311973a67b6bf3208", size = 6234878, upload-time = "2026-01-02T09:11:14.096Z" }, + { url = "https://files.pythonhosted.org/packages/76/25/27abc9792615b5e886ca9411ba6637b675f1b77af3104710ac7353fe5605/pillow-12.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bef9768cab184e7ae6e559c032e95ba8d07b3023c289f79a2bd36e8bf85605a5", size = 8044868, upload-time = "2026-01-02T09:11:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ea/f200a4c36d836100e7bc738fc48cd963d3ba6372ebc8298a889e0cfc3359/pillow-12.1.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:742aea052cf5ab5034a53c3846165bc3ce88d7c38e954120db0ab867ca242661", size = 6349468, upload-time = "2026-01-02T09:11:17.631Z" }, + { url = "https://files.pythonhosted.org/packages/11/8f/48d0b77ab2200374c66d344459b8958c86693be99526450e7aee714e03e4/pillow-12.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6dfc2af5b082b635af6e08e0d1f9f1c4e04d17d4e2ca0ef96131e85eda6eb17", size = 7041518, upload-time = "2026-01-02T09:11:19.389Z" }, + { url = "https://files.pythonhosted.org/packages/1d/23/c281182eb986b5d31f0a76d2a2c8cd41722d6fb8ed07521e802f9bba52de/pillow-12.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:609e89d9f90b581c8d16358c9087df76024cf058fa693dd3e1e1620823f39670", size = 6462829, upload-time = "2026-01-02T09:11:21.28Z" }, + { url = "https://files.pythonhosted.org/packages/25/ef/7018273e0faac099d7b00982abdcc39142ae6f3bd9ceb06de09779c4a9d6/pillow-12.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43b4899cfd091a9693a1278c4982f3e50f7fb7cff5153b05174b4afc9593b616", size = 7166756, upload-time = "2026-01-02T09:11:23.559Z" }, + { url = "https://files.pythonhosted.org/packages/8f/c8/993d4b7ab2e341fe02ceef9576afcf5830cdec640be2ac5bee1820d693d4/pillow-12.1.0-cp312-cp312-win32.whl", hash = "sha256:aa0c9cc0b82b14766a99fbe6084409972266e82f459821cd26997a488a7261a7", size = 6328770, upload-time = "2026-01-02T09:11:25.661Z" }, + { url = "https://files.pythonhosted.org/packages/a7/87/90b358775a3f02765d87655237229ba64a997b87efa8ccaca7dd3e36e7a7/pillow-12.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:d70534cea9e7966169ad29a903b99fc507e932069a881d0965a1a84bb57f6c6d", size = 7033406, upload-time = "2026-01-02T09:11:27.474Z" }, + { url = "https://files.pythonhosted.org/packages/5d/cf/881b457eccacac9e5b2ddd97d5071fb6d668307c57cbf4e3b5278e06e536/pillow-12.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:65b80c1ee7e14a87d6a068dd3b0aea268ffcabfe0498d38661b00c5b4b22e74c", size = 2452612, upload-time = "2026-01-02T09:11:29.309Z" }, + { url = "https://files.pythonhosted.org/packages/dd/c7/2530a4aa28248623e9d7f27316b42e27c32ec410f695929696f2e0e4a778/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1", size = 4062543, upload-time = "2026-01-02T09:11:31.566Z" }, + { url = "https://files.pythonhosted.org/packages/8f/1f/40b8eae823dc1519b87d53c30ed9ef085506b05281d313031755c1705f73/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179", size = 4138373, upload-time = "2026-01-02T09:11:33.367Z" }, + { url = "https://files.pythonhosted.org/packages/d4/77/6fa60634cf06e52139fd0e89e5bbf055e8166c691c42fb162818b7fda31d/pillow-12.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0", size = 3601241, upload-time = "2026-01-02T09:11:35.011Z" }, + { url = "https://files.pythonhosted.org/packages/4f/bf/28ab865de622e14b747f0cd7877510848252d950e43002e224fb1c9ababf/pillow-12.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587", size = 5262410, upload-time = "2026-01-02T09:11:36.682Z" }, + { url = "https://files.pythonhosted.org/packages/1c/34/583420a1b55e715937a85bd48c5c0991598247a1fd2eb5423188e765ea02/pillow-12.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac", size = 4657312, upload-time = "2026-01-02T09:11:38.535Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fd/f5a0896839762885b3376ff04878f86ab2b097c2f9a9cdccf4eda8ba8dc0/pillow-12.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b", size = 6232605, upload-time = "2026-01-02T09:11:40.602Z" }, + { url = "https://files.pythonhosted.org/packages/98/aa/938a09d127ac1e70e6ed467bd03834350b33ef646b31edb7452d5de43792/pillow-12.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea", size = 8041617, upload-time = "2026-01-02T09:11:42.721Z" }, + { url = "https://files.pythonhosted.org/packages/17/e8/538b24cb426ac0186e03f80f78bc8dc7246c667f58b540bdd57c71c9f79d/pillow-12.1.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c", size = 6346509, upload-time = "2026-01-02T09:11:44.955Z" }, + { url = "https://files.pythonhosted.org/packages/01/9a/632e58ec89a32738cabfd9ec418f0e9898a2b4719afc581f07c04a05e3c9/pillow-12.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc", size = 7038117, upload-time = "2026-01-02T09:11:46.736Z" }, + { url = "https://files.pythonhosted.org/packages/c7/a2/d40308cf86eada842ca1f3ffa45d0ca0df7e4ab33c83f81e73f5eaed136d/pillow-12.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644", size = 6460151, upload-time = "2026-01-02T09:11:48.625Z" }, + { url = "https://files.pythonhosted.org/packages/f1/88/f5b058ad6453a085c5266660a1417bdad590199da1b32fb4efcff9d33b05/pillow-12.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c", size = 7164534, upload-time = "2026-01-02T09:11:50.445Z" }, + { url = "https://files.pythonhosted.org/packages/19/ce/c17334caea1db789163b5d855a5735e47995b0b5dc8745e9a3605d5f24c0/pillow-12.1.0-cp313-cp313-win32.whl", hash = "sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171", size = 6332551, upload-time = "2026-01-02T09:11:52.234Z" }, + { url = "https://files.pythonhosted.org/packages/e5/07/74a9d941fa45c90a0d9465098fe1ec85de3e2afbdc15cc4766622d516056/pillow-12.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a", size = 7040087, upload-time = "2026-01-02T09:11:54.822Z" }, + { url = "https://files.pythonhosted.org/packages/88/09/c99950c075a0e9053d8e880595926302575bc742b1b47fe1bbcc8d388d50/pillow-12.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45", size = 2452470, upload-time = "2026-01-02T09:11:56.522Z" }, + { url = "https://files.pythonhosted.org/packages/b5/ba/970b7d85ba01f348dee4d65412476321d40ee04dcb51cd3735b9dc94eb58/pillow-12.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d", size = 5264816, upload-time = "2026-01-02T09:11:58.227Z" }, + { url = "https://files.pythonhosted.org/packages/10/60/650f2fb55fdba7a510d836202aa52f0baac633e50ab1cf18415d332188fb/pillow-12.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0", size = 4660472, upload-time = "2026-01-02T09:12:00.798Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/5273a99478956a099d533c4f46cbaa19fd69d606624f4334b85e50987a08/pillow-12.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554", size = 6268974, upload-time = "2026-01-02T09:12:02.572Z" }, + { url = "https://files.pythonhosted.org/packages/b4/26/0bf714bc2e73d5267887d47931d53c4ceeceea6978148ed2ab2a4e6463c4/pillow-12.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e", size = 8073070, upload-time = "2026-01-02T09:12:04.75Z" }, + { url = "https://files.pythonhosted.org/packages/43/cf/1ea826200de111a9d65724c54f927f3111dc5ae297f294b370a670c17786/pillow-12.1.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82", size = 6380176, upload-time = "2026-01-02T09:12:06.626Z" }, + { url = "https://files.pythonhosted.org/packages/03/e0/7938dd2b2013373fd85d96e0f38d62b7a5a262af21ac274250c7ca7847c9/pillow-12.1.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4", size = 7067061, upload-time = "2026-01-02T09:12:08.624Z" }, + { url = "https://files.pythonhosted.org/packages/86/ad/a2aa97d37272a929a98437a8c0ac37b3cf012f4f8721e1bd5154699b2518/pillow-12.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0", size = 6491824, upload-time = "2026-01-02T09:12:10.488Z" }, + { url = "https://files.pythonhosted.org/packages/a4/44/80e46611b288d51b115826f136fb3465653c28f491068a72d3da49b54cd4/pillow-12.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b", size = 7190911, upload-time = "2026-01-02T09:12:12.772Z" }, + { url = "https://files.pythonhosted.org/packages/86/77/eacc62356b4cf81abe99ff9dbc7402750044aed02cfd6a503f7c6fc11f3e/pillow-12.1.0-cp313-cp313t-win32.whl", hash = "sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65", size = 6336445, upload-time = "2026-01-02T09:12:14.775Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3c/57d81d0b74d218706dafccb87a87ea44262c43eef98eb3b164fd000e0491/pillow-12.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0", size = 7045354, upload-time = "2026-01-02T09:12:16.599Z" }, + { url = "https://files.pythonhosted.org/packages/ac/82/8b9b97bba2e3576a340f93b044a3a3a09841170ab4c1eb0d5c93469fd32f/pillow-12.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8", size = 2454547, upload-time = "2026-01-02T09:12:18.704Z" }, + { url = "https://files.pythonhosted.org/packages/8c/87/bdf971d8bbcf80a348cc3bacfcb239f5882100fe80534b0ce67a784181d8/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:5cb7bc1966d031aec37ddb9dcf15c2da5b2e9f7cc3ca7c54473a20a927e1eb91", size = 4062533, upload-time = "2026-01-02T09:12:20.791Z" }, + { url = "https://files.pythonhosted.org/packages/ff/4f/5eb37a681c68d605eb7034c004875c81f86ec9ef51f5be4a63eadd58859a/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:97e9993d5ed946aba26baf9c1e8cf18adbab584b99f452ee72f7ee8acb882796", size = 4138546, upload-time = "2026-01-02T09:12:23.664Z" }, + { url = "https://files.pythonhosted.org/packages/11/6d/19a95acb2edbace40dcd582d077b991646b7083c41b98da4ed7555b59733/pillow-12.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:414b9a78e14ffeb98128863314e62c3f24b8a86081066625700b7985b3f529bd", size = 3601163, upload-time = "2026-01-02T09:12:26.338Z" }, + { url = "https://files.pythonhosted.org/packages/fc/36/2b8138e51cb42e4cc39c3297713455548be855a50558c3ac2beebdc251dd/pillow-12.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e6bdb408f7c9dd2a5ff2b14a3b0bb6d4deb29fb9961e6eb3ae2031ae9a5cec13", size = 5266086, upload-time = "2026-01-02T09:12:28.782Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/649056e4d22e1caa90816bf99cef0884aed607ed38075bd75f091a607a38/pillow-12.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3413c2ae377550f5487991d444428f1a8ae92784aac79caa8b1e3b89b175f77e", size = 4657344, upload-time = "2026-01-02T09:12:31.117Z" }, + { url = "https://files.pythonhosted.org/packages/6c/6b/c5742cea0f1ade0cd61485dc3d81f05261fc2276f537fbdc00802de56779/pillow-12.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e5dcbe95016e88437ecf33544ba5db21ef1b8dd6e1b434a2cb2a3d605299e643", size = 6232114, upload-time = "2026-01-02T09:12:32.936Z" }, + { url = "https://files.pythonhosted.org/packages/bf/8f/9f521268ce22d63991601aafd3d48d5ff7280a246a1ef62d626d67b44064/pillow-12.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d0a7735df32ccbcc98b98a1ac785cc4b19b580be1bdf0aeb5c03223220ea09d5", size = 8042708, upload-time = "2026-01-02T09:12:34.78Z" }, + { url = "https://files.pythonhosted.org/packages/1a/eb/257f38542893f021502a1bbe0c2e883c90b5cff26cc33b1584a841a06d30/pillow-12.1.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c27407a2d1b96774cbc4a7594129cc027339fd800cd081e44497722ea1179de", size = 6347762, upload-time = "2026-01-02T09:12:36.748Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5a/8ba375025701c09b309e8d5163c5a4ce0102fa86bbf8800eb0d7ac87bc51/pillow-12.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15c794d74303828eaa957ff8070846d0efe8c630901a1c753fdc63850e19ecd9", size = 7039265, upload-time = "2026-01-02T09:12:39.082Z" }, + { url = "https://files.pythonhosted.org/packages/cf/dc/cf5e4cdb3db533f539e88a7bbf9f190c64ab8a08a9bc7a4ccf55067872e4/pillow-12.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c990547452ee2800d8506c4150280757f88532f3de2a58e3022e9b179107862a", size = 6462341, upload-time = "2026-01-02T09:12:40.946Z" }, + { url = "https://files.pythonhosted.org/packages/d0/47/0291a25ac9550677e22eda48510cfc4fa4b2ef0396448b7fbdc0a6946309/pillow-12.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b63e13dd27da389ed9475b3d28510f0f954bca0041e8e551b2a4eb1eab56a39a", size = 7165395, upload-time = "2026-01-02T09:12:42.706Z" }, + { url = "https://files.pythonhosted.org/packages/4f/4c/e005a59393ec4d9416be06e6b45820403bb946a778e39ecec62f5b2b991e/pillow-12.1.0-cp314-cp314-win32.whl", hash = "sha256:1a949604f73eb07a8adab38c4fe50791f9919344398bdc8ac6b307f755fc7030", size = 6431413, upload-time = "2026-01-02T09:12:44.944Z" }, + { url = "https://files.pythonhosted.org/packages/1c/af/f23697f587ac5f9095d67e31b81c95c0249cd461a9798a061ed6709b09b5/pillow-12.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:4f9f6a650743f0ddee5593ac9e954ba1bdbc5e150bc066586d4f26127853ab94", size = 7176779, upload-time = "2026-01-02T09:12:46.727Z" }, + { url = "https://files.pythonhosted.org/packages/b3/36/6a51abf8599232f3e9afbd16d52829376a68909fe14efe29084445db4b73/pillow-12.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:808b99604f7873c800c4840f55ff389936ef1948e4e87645eaf3fccbc8477ac4", size = 2543105, upload-time = "2026-01-02T09:12:49.243Z" }, + { url = "https://files.pythonhosted.org/packages/82/54/2e1dd20c8749ff225080d6ba465a0cab4387f5db0d1c5fb1439e2d99923f/pillow-12.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc11908616c8a283cf7d664f77411a5ed2a02009b0097ff8abbba5e79128ccf2", size = 5268571, upload-time = "2026-01-02T09:12:51.11Z" }, + { url = "https://files.pythonhosted.org/packages/57/61/571163a5ef86ec0cf30d265ac2a70ae6fc9e28413d1dc94fa37fae6bda89/pillow-12.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:896866d2d436563fa2a43a9d72f417874f16b5545955c54a64941e87c1376c61", size = 4660426, upload-time = "2026-01-02T09:12:52.865Z" }, + { url = "https://files.pythonhosted.org/packages/5e/e1/53ee5163f794aef1bf84243f755ee6897a92c708505350dd1923f4afec48/pillow-12.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8e178e3e99d3c0ea8fc64b88447f7cac8ccf058af422a6cedc690d0eadd98c51", size = 6269908, upload-time = "2026-01-02T09:12:54.884Z" }, + { url = "https://files.pythonhosted.org/packages/bc/0b/b4b4106ff0ee1afa1dc599fde6ab230417f800279745124f6c50bcffed8e/pillow-12.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:079af2fb0c599c2ec144ba2c02766d1b55498e373b3ac64687e43849fbbef5bc", size = 8074733, upload-time = "2026-01-02T09:12:56.802Z" }, + { url = "https://files.pythonhosted.org/packages/19/9f/80b411cbac4a732439e629a26ad3ef11907a8c7fc5377b7602f04f6fe4e7/pillow-12.1.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdec5e43377761c5dbca620efb69a77f6855c5a379e32ac5b158f54c84212b14", size = 6381431, upload-time = "2026-01-02T09:12:58.823Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b7/d65c45db463b66ecb6abc17c6ba6917a911202a07662247e1355ce1789e7/pillow-12.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:565c986f4b45c020f5421a4cea13ef294dde9509a8577f29b2fc5edc7587fff8", size = 7068529, upload-time = "2026-01-02T09:13:00.885Z" }, + { url = "https://files.pythonhosted.org/packages/50/96/dfd4cd726b4a45ae6e3c669fc9e49deb2241312605d33aba50499e9d9bd1/pillow-12.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:43aca0a55ce1eefc0aefa6253661cb54571857b1a7b2964bd8a1e3ef4b729924", size = 6492981, upload-time = "2026-01-02T09:13:03.314Z" }, + { url = "https://files.pythonhosted.org/packages/4d/1c/b5dc52cf713ae46033359c5ca920444f18a6359ce1020dd3e9c553ea5bc6/pillow-12.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0deedf2ea233722476b3a81e8cdfbad786f7adbed5d848469fa59fe52396e4ef", size = 7191878, upload-time = "2026-01-02T09:13:05.276Z" }, + { url = "https://files.pythonhosted.org/packages/53/26/c4188248bd5edaf543864fe4834aebe9c9cb4968b6f573ce014cc42d0720/pillow-12.1.0-cp314-cp314t-win32.whl", hash = "sha256:b17fbdbe01c196e7e159aacb889e091f28e61020a8abeac07b68079b6e626988", size = 6438703, upload-time = "2026-01-02T09:13:07.491Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0e/69ed296de8ea05cb03ee139cee600f424ca166e632567b2d66727f08c7ed/pillow-12.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27b9baecb428899db6c0de572d6d305cfaf38ca1596b5c0542a5182e3e74e8c6", size = 7182927, upload-time = "2026-01-02T09:13:09.841Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f5/68334c015eed9b5cff77814258717dec591ded209ab5b6fb70e2ae873d1d/pillow-12.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f61333d817698bdcdd0f9d7793e365ac3d2a21c1f1eb02b32ad6aefb8d8ea831", size = 2545104, upload-time = "2026-01-02T09:13:12.068Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "prometheus-client" +version = "0.23.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/53/3edb5d68ecf6b38fcbcc1ad28391117d2a322d9a1a3eff04bfdb184d8c3b/prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce", size = 80481, upload-time = "2025-09-18T20:47:25.043Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/db/14bafcb4af2139e046d03fd00dea7873e48eafe18b7d2797e73d6681f210/prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99", size = 61145, upload-time = "2025-09-18T20:47:23.875Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, +] + +[[package]] +name = "propcache" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061, upload-time = "2025-10-08T19:46:46.075Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037, upload-time = "2025-10-08T19:46:47.23Z" }, + { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324, upload-time = "2025-10-08T19:46:48.384Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505, upload-time = "2025-10-08T19:46:50.055Z" }, + { url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242, upload-time = "2025-10-08T19:46:51.815Z" }, + { url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474, upload-time = "2025-10-08T19:46:53.208Z" }, + { url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575, upload-time = "2025-10-08T19:46:54.511Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736, upload-time = "2025-10-08T19:46:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019, upload-time = "2025-10-08T19:46:57.595Z" }, + { url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376, upload-time = "2025-10-08T19:46:59.067Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988, upload-time = "2025-10-08T19:47:00.544Z" }, + { url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615, upload-time = "2025-10-08T19:47:01.968Z" }, + { url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066, upload-time = "2025-10-08T19:47:03.503Z" }, + { url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655, upload-time = "2025-10-08T19:47:04.973Z" }, + { url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789, upload-time = "2025-10-08T19:47:06.077Z" }, + { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload-time = "2025-10-08T19:47:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload-time = "2025-10-08T19:47:08.851Z" }, + { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload-time = "2025-10-08T19:47:09.982Z" }, + { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload-time = "2025-10-08T19:47:11.319Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload-time = "2025-10-08T19:47:13.146Z" }, + { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload-time = "2025-10-08T19:47:14.913Z" }, + { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload-time = "2025-10-08T19:47:16.277Z" }, + { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload-time = "2025-10-08T19:47:17.962Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload-time = "2025-10-08T19:47:19.355Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload-time = "2025-10-08T19:47:21.338Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload-time = "2025-10-08T19:47:23.059Z" }, + { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload-time = "2025-10-08T19:47:24.445Z" }, + { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload-time = "2025-10-08T19:47:25.736Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload-time = "2025-10-08T19:47:26.847Z" }, + { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload-time = "2025-10-08T19:47:27.961Z" }, + { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload-time = "2025-10-08T19:47:29.445Z" }, + { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload-time = "2025-10-08T19:47:30.579Z" }, + { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload-time = "2025-10-08T19:47:31.79Z" }, + { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload-time = "2025-10-08T19:47:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload-time = "2025-10-08T19:47:34.906Z" }, + { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload-time = "2025-10-08T19:47:36.338Z" }, + { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload-time = "2025-10-08T19:47:37.692Z" }, + { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload-time = "2025-10-08T19:47:39.659Z" }, + { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload-time = "2025-10-08T19:47:41.084Z" }, + { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload-time = "2025-10-08T19:47:42.51Z" }, + { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload-time = "2025-10-08T19:47:43.927Z" }, + { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload-time = "2025-10-08T19:47:45.448Z" }, + { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" }, + { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" }, + { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" }, + { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" }, + { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" }, + { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" }, + { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" }, + { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" }, + { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" }, + { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" }, + { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" }, + { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" }, + { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" }, + { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" }, + { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" }, + { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" }, + { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" }, + { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" }, + { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" }, + { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" }, + { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" }, + { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" }, + { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" }, + { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" }, + { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, +] + +[[package]] +name = "psutil" +version = "7.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/73/cb/09e5184fb5fc0358d110fc3ca7f6b1d033800734d34cac10f4136cfac10e/psutil-7.2.1.tar.gz", hash = "sha256:f7583aec590485b43ca601dd9cea0dcd65bd7bb21d30ef4ddbf4ea6b5ed1bdd3", size = 490253, upload-time = "2025-12-29T08:26:00.169Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/8e/f0c242053a368c2aa89584ecd1b054a18683f13d6e5a318fc9ec36582c94/psutil-7.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ba9f33bb525b14c3ea563b2fd521a84d2fa214ec59e3e6a2858f78d0844dd60d", size = 129624, upload-time = "2025-12-29T08:26:04.255Z" }, + { url = "https://files.pythonhosted.org/packages/26/97/a58a4968f8990617decee234258a2b4fc7cd9e35668387646c1963e69f26/psutil-7.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:81442dac7abfc2f4f4385ea9e12ddf5a796721c0f6133260687fec5c3780fa49", size = 130132, upload-time = "2025-12-29T08:26:06.228Z" }, + { url = "https://files.pythonhosted.org/packages/db/6d/ed44901e830739af5f72a85fa7ec5ff1edea7f81bfbf4875e409007149bd/psutil-7.2.1-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ea46c0d060491051d39f0d2cff4f98d5c72b288289f57a21556cc7d504db37fc", size = 180612, upload-time = "2025-12-29T08:26:08.276Z" }, + { url = "https://files.pythonhosted.org/packages/c7/65/b628f8459bca4efbfae50d4bf3feaab803de9a160b9d5f3bd9295a33f0c2/psutil-7.2.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:35630d5af80d5d0d49cfc4d64c1c13838baf6717a13effb35869a5919b854cdf", size = 183201, upload-time = "2025-12-29T08:26:10.622Z" }, + { url = "https://files.pythonhosted.org/packages/fb/23/851cadc9764edcc18f0effe7d0bf69f727d4cf2442deb4a9f78d4e4f30f2/psutil-7.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:923f8653416604e356073e6e0bccbe7c09990acef442def2f5640dd0faa9689f", size = 139081, upload-time = "2025-12-29T08:26:12.483Z" }, + { url = "https://files.pythonhosted.org/packages/59/82/d63e8494ec5758029f31c6cb06d7d161175d8281e91d011a4a441c8a43b5/psutil-7.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cfbe6b40ca48019a51827f20d830887b3107a74a79b01ceb8cc8de4ccb17b672", size = 134767, upload-time = "2025-12-29T08:26:14.528Z" }, + { url = "https://files.pythonhosted.org/packages/05/c2/5fb764bd61e40e1fe756a44bd4c21827228394c17414ade348e28f83cd79/psutil-7.2.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:494c513ccc53225ae23eec7fe6e1482f1b8a44674241b54561f755a898650679", size = 129716, upload-time = "2025-12-29T08:26:16.017Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d2/935039c20e06f615d9ca6ca0ab756cf8408a19d298ffaa08666bc18dc805/psutil-7.2.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3fce5f92c22b00cdefd1645aa58ab4877a01679e901555067b1bd77039aa589f", size = 130133, upload-time = "2025-12-29T08:26:18.009Z" }, + { url = "https://files.pythonhosted.org/packages/77/69/19f1eb0e01d24c2b3eacbc2f78d3b5add8a89bf0bb69465bc8d563cc33de/psutil-7.2.1-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93f3f7b0bb07711b49626e7940d6fe52aa9940ad86e8f7e74842e73189712129", size = 181518, upload-time = "2025-12-29T08:26:20.241Z" }, + { url = "https://files.pythonhosted.org/packages/e1/6d/7e18b1b4fa13ad370787626c95887b027656ad4829c156bb6569d02f3262/psutil-7.2.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d34d2ca888208eea2b5c68186841336a7f5e0b990edec929be909353a202768a", size = 184348, upload-time = "2025-12-29T08:26:22.215Z" }, + { url = "https://files.pythonhosted.org/packages/98/60/1672114392dd879586d60dd97896325df47d9a130ac7401318005aab28ec/psutil-7.2.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2ceae842a78d1603753561132d5ad1b2f8a7979cb0c283f5b52fb4e6e14b1a79", size = 140400, upload-time = "2025-12-29T08:26:23.993Z" }, + { url = "https://files.pythonhosted.org/packages/fb/7b/d0e9d4513c46e46897b46bcfc410d51fc65735837ea57a25170f298326e6/psutil-7.2.1-cp314-cp314t-win_arm64.whl", hash = "sha256:08a2f175e48a898c8eb8eace45ce01777f4785bc744c90aa2cc7f2fa5462a266", size = 135430, upload-time = "2025-12-29T08:26:25.999Z" }, + { url = "https://files.pythonhosted.org/packages/c5/cf/5180eb8c8bdf6a503c6919f1da28328bd1e6b3b1b5b9d5b01ae64f019616/psutil-7.2.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2e953fcfaedcfbc952b44744f22d16575d3aa78eb4f51ae74165b4e96e55f42", size = 128137, upload-time = "2025-12-29T08:26:27.759Z" }, + { url = "https://files.pythonhosted.org/packages/c5/2c/78e4a789306a92ade5000da4f5de3255202c534acdadc3aac7b5458fadef/psutil-7.2.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:05cc68dbb8c174828624062e73078e7e35406f4ca2d0866c272c2410d8ef06d1", size = 128947, upload-time = "2025-12-29T08:26:29.548Z" }, + { url = "https://files.pythonhosted.org/packages/29/f8/40e01c350ad9a2b3cb4e6adbcc8a83b17ee50dd5792102b6142385937db5/psutil-7.2.1-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e38404ca2bb30ed7267a46c02f06ff842e92da3bb8c5bfdadbd35a5722314d8", size = 154694, upload-time = "2025-12-29T08:26:32.147Z" }, + { url = "https://files.pythonhosted.org/packages/06/e4/b751cdf839c011a9714a783f120e6a86b7494eb70044d7d81a25a5cd295f/psutil-7.2.1-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab2b98c9fc19f13f59628d94df5cc4cc4844bc572467d113a8b517d634e362c6", size = 156136, upload-time = "2025-12-29T08:26:34.079Z" }, + { url = "https://files.pythonhosted.org/packages/44/ad/bbf6595a8134ee1e94a4487af3f132cef7fce43aef4a93b49912a48c3af7/psutil-7.2.1-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f78baafb38436d5a128f837fab2d92c276dfb48af01a240b861ae02b2413ada8", size = 148108, upload-time = "2025-12-29T08:26:36.225Z" }, + { url = "https://files.pythonhosted.org/packages/1c/15/dd6fd869753ce82ff64dcbc18356093471a5a5adf4f77ed1f805d473d859/psutil-7.2.1-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:99a4cd17a5fdd1f3d014396502daa70b5ec21bf4ffe38393e152f8e449757d67", size = 147402, upload-time = "2025-12-29T08:26:39.21Z" }, + { url = "https://files.pythonhosted.org/packages/34/68/d9317542e3f2b180c4306e3f45d3c922d7e86d8ce39f941bb9e2e9d8599e/psutil-7.2.1-cp37-abi3-win_amd64.whl", hash = "sha256:b1b0671619343aa71c20ff9767eced0483e4fc9e1f489d50923738caf6a03c17", size = 136938, upload-time = "2025-12-29T08:26:41.036Z" }, + { url = "https://files.pythonhosted.org/packages/3e/73/2ce007f4198c80fcf2cb24c169884f833fe93fbc03d55d302627b094ee91/psutil-7.2.1-cp37-abi3-win_arm64.whl", hash = "sha256:0d67c1822c355aa6f7314d92018fb4268a76668a536f133599b91edd48759442", size = 133836, upload-time = "2025-12-29T08:26:43.086Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pydantic" +version = "2.12.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pymupdf" +version = "1.26.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/48/d6/09b28f027b510838559f7748807192149c419b30cb90e6d5f0cf916dc9dc/pymupdf-1.26.7.tar.gz", hash = "sha256:71add8bdc8eb1aaa207c69a13400693f06ad9b927bea976f5d5ab9df0bb489c3", size = 84327033, upload-time = "2025-12-11T21:48:50.694Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/35/cd74cea1787b2247702ef8522186bdef32e9cb30a099e6bb864627ef6045/pymupdf-1.26.7-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:07085718dfdae5ab83b05eb5eb397f863bcc538fe05135318a01ea353e7a1353", size = 23179369, upload-time = "2025-12-11T21:47:21.587Z" }, + { url = "https://files.pythonhosted.org/packages/72/74/448b6172927c829c6a3fba80078d7b0a016ebbe2c9ee528821f5ea21677a/pymupdf-1.26.7-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:31aa9c8377ea1eea02934b92f4dcf79fb2abba0bf41f8a46d64c3e31546a3c02", size = 22470101, upload-time = "2025-12-11T21:47:37.105Z" }, + { url = "https://files.pythonhosted.org/packages/65/e7/47af26f3ac76be7ac3dd4d6cc7ee105948a8355d774e5ca39857bf91c11c/pymupdf-1.26.7-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e419b609996434a14a80fa060adec72c434a1cca6a511ec54db9841bc5d51b3c", size = 23502486, upload-time = "2025-12-12T09:51:25.824Z" }, + { url = "https://files.pythonhosted.org/packages/2a/6b/3de1714d734ff949be1e90a22375d0598d3540b22ae73eb85c2d7d1f36a9/pymupdf-1.26.7-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:69dfc78f206a96e5b3ac22741263ebab945fdf51f0dbe7c5757c3511b23d9d72", size = 24115727, upload-time = "2025-12-11T21:47:51.274Z" }, + { url = "https://files.pythonhosted.org/packages/62/9b/f86224847949577a523be2207315ae0fd3155b5d909cd66c274d095349a3/pymupdf-1.26.7-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1d5106f46e1ca0d64d46bd51892372a4f82076bdc14a9678d33d630702abca36", size = 24324386, upload-time = "2025-12-12T14:58:45.483Z" }, + { url = "https://files.pythonhosted.org/packages/85/8e/a117d39092ca645fde8b903f4a941d9aa75b370a67b4f1f435f56393dc5a/pymupdf-1.26.7-cp310-abi3-win32.whl", hash = "sha256:7c9645b6f5452629c747690190350213d3e5bbdb6b2eca227d82702b327f6eee", size = 17203888, upload-time = "2025-12-12T13:59:57.613Z" }, + { url = "https://files.pythonhosted.org/packages/dd/c3/d0047678146c294469c33bae167c8ace337deafb736b0bf97b9bc481aa65/pymupdf-1.26.7-cp310-abi3-win_amd64.whl", hash = "sha256:425b1befe40d41b72eb0fe211711c7ae334db5eb60307e9dd09066ed060cceba", size = 18405952, upload-time = "2025-12-11T21:48:02.947Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "pytest-mock" +version = "3.15.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/14/eb014d26be205d38ad5ad20d9a80f7d201472e08167f0bb4361e251084a9/pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f", size = 34036, upload-time = "2025-09-16T16:37:27.081Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/cc/06253936f4a7fa2e0f48dfe6d851d9c56df896a9ab09ac019d70b760619c/pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", size = 10095, upload-time = "2025-09-16T16:37:25.734Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, +] + +[[package]] +name = "python-json-logger" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683, upload-time = "2025-10-06T04:15:18.984Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548, upload-time = "2025-10-06T04:15:17.553Z" }, +] + +[[package]] +name = "pytokens" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/8d/a762be14dae1c3bf280202ba3172020b2b0b4c537f94427435f19c413b72/pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a", size = 17644, upload-time = "2025-11-05T13:36:35.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195, upload-time = "2025-11-05T13:36:33.183Z" }, +] + +[[package]] +name = "pytz" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, +] + +[[package]] +name = "pywinpty" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/bb/a7cc2967c5c4eceb6cc49cfe39447d4bfc56e6c865e7c2249b6eb978935f/pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004", size = 30669, upload-time = "2025-10-03T21:16:29.205Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/4e/1098484e042c9485f56f16eb2b69b43b874bd526044ee401512234cf9e04/pywinpty-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:99fdd9b455f0ad6419aba6731a7a0d2f88ced83c3c94a80ff9533d95fa8d8a9e", size = 2050391, upload-time = "2025-10-03T21:19:01.642Z" }, + { url = "https://files.pythonhosted.org/packages/fc/19/b757fe28008236a4a713e813283721b8a40aa60cd7d3f83549f2e25a3155/pywinpty-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:18f78b81e4cfee6aabe7ea8688441d30247b73e52cd9657138015c5f4ee13a51", size = 2050057, upload-time = "2025-10-03T21:19:26.732Z" }, + { url = "https://files.pythonhosted.org/packages/cb/44/cbae12ecf6f4fa4129c36871fd09c6bef4f98d5f625ecefb5e2449765508/pywinpty-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:663383ecfab7fc382cc97ea5c4f7f0bb32c2f889259855df6ea34e5df42d305b", size = 2049874, upload-time = "2025-10-03T21:18:53.923Z" }, + { url = "https://files.pythonhosted.org/packages/ca/15/f12c6055e2d7a617d4d5820e8ac4ceaff849da4cb124640ef5116a230771/pywinpty-3.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:28297cecc37bee9f24d8889e47231972d6e9e84f7b668909de54f36ca785029a", size = 2050386, upload-time = "2025-10-03T21:18:50.477Z" }, + { url = "https://files.pythonhosted.org/packages/de/24/c6907c5bb06043df98ad6a0a0ff5db2e0affcecbc3b15c42404393a3f72a/pywinpty-3.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:34b55ae9a1b671fe3eae071d86618110538e8eaad18fcb1531c0830b91a82767", size = 2049834, upload-time = "2025-10-03T21:19:25.688Z" }, +] + +[[package]] +name = "pyxlsb" +version = "1.0.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/13/eebaeb7a40b062d1c6f7f91d09e73d30a69e33e4baa7cbe4b7658548b1cd/pyxlsb-1.0.10.tar.gz", hash = "sha256:8062d1ea8626d3f1980e8b1cfe91a4483747449242ecb61013bc2df85435f685", size = 22424, upload-time = "2022-10-14T19:17:47.308Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/92/345823838ae367c59b63e03aef9c331f485370f9df6d049256a61a28f06d/pyxlsb-1.0.10-py2.py3-none-any.whl", hash = "sha256:87c122a9a622e35ca5e741d2e541201d28af00fb46bec492cfa9586890b120b4", size = 23849, upload-time = "2022-10-14T19:17:46.079Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "pyzmq" +version = "27.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, + { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436, upload-time = "2025-09-08T23:08:20.801Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301, upload-time = "2025-09-08T23:08:22.47Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197, upload-time = "2025-09-08T23:08:24.286Z" }, + { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275, upload-time = "2025-09-08T23:08:26.063Z" }, + { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469, upload-time = "2025-09-08T23:08:27.623Z" }, + { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961, upload-time = "2025-09-08T23:08:29.672Z" }, + { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282, upload-time = "2025-09-08T23:08:31.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468, upload-time = "2025-09-08T23:08:33.543Z" }, + { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394, upload-time = "2025-09-08T23:08:35.51Z" }, + { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964, upload-time = "2025-09-08T23:08:37.178Z" }, + { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029, upload-time = "2025-09-08T23:08:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541, upload-time = "2025-09-08T23:08:42.668Z" }, + { url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197, upload-time = "2025-09-08T23:08:44.973Z" }, + { url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175, upload-time = "2025-09-08T23:08:46.601Z" }, + { url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427, upload-time = "2025-09-08T23:08:48.187Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929, upload-time = "2025-09-08T23:08:49.76Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193, upload-time = "2025-09-08T23:08:51.7Z" }, + { url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388, upload-time = "2025-09-08T23:08:53.393Z" }, + { url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316, upload-time = "2025-09-08T23:08:55.702Z" }, + { url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472, upload-time = "2025-09-08T23:08:58.18Z" }, + { url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401, upload-time = "2025-09-08T23:08:59.802Z" }, + { url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170, upload-time = "2025-09-08T23:09:01.418Z" }, +] + +[[package]] +name = "rank-bm25" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/0a/f9579384aa017d8b4c15613f86954b92a95a93d641cc849182467cf0bb3b/rank_bm25-0.2.2.tar.gz", hash = "sha256:096ccef76f8188563419aaf384a02f0ea459503fdf77901378d4fd9d87e5e51d", size = 8347, upload-time = "2022-02-16T12:10:52.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/21/f691fb2613100a62b3fa91e9988c991e9ca5b89ea31c0d3152a3210344f9/rank_bm25-0.2.2-py3-none-any.whl", hash = "sha256:7bd4a95571adadfc271746fa146a4bcfd89c0cf731e49c3d1ad863290adbe8ae", size = 8584, upload-time = "2022-02-16T12:10:50.626Z" }, +] + +[[package]] +name = "rapidfuzz" +version = "3.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900, upload-time = "2025-11-01T11:54:52.321Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/8e/3c215e860b458cfbedb3ed73bc72e98eb7e0ed72f6b48099604a7a3260c2/rapidfuzz-3.14.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:685c93ea961d135893b5984a5a9851637d23767feabe414ec974f43babbd8226", size = 1945306, upload-time = "2025-11-01T11:53:06.452Z" }, + { url = "https://files.pythonhosted.org/packages/36/d9/31b33512015c899f4a6e6af64df8dfe8acddf4c8b40a4b3e0e6e1bcd00e5/rapidfuzz-3.14.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fa7c8f26f009f8c673fbfb443792f0cf8cf50c4e18121ff1e285b5e08a94fbdb", size = 1390788, upload-time = "2025-11-01T11:53:08.721Z" }, + { url = "https://files.pythonhosted.org/packages/a9/67/2ee6f8de6e2081ccd560a571d9c9063184fe467f484a17fa90311a7f4a2e/rapidfuzz-3.14.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57f878330c8d361b2ce76cebb8e3e1dc827293b6abf404e67d53260d27b5d941", size = 1374580, upload-time = "2025-11-01T11:53:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/30/83/80d22997acd928eda7deadc19ccd15883904622396d6571e935993e0453a/rapidfuzz-3.14.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c5f545f454871e6af05753a0172849c82feaf0f521c5ca62ba09e1b382d6382", size = 3154947, upload-time = "2025-11-01T11:53:12.093Z" }, + { url = "https://files.pythonhosted.org/packages/5b/cf/9f49831085a16384695f9fb096b99662f589e30b89b4a589a1ebc1a19d34/rapidfuzz-3.14.3-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:07aa0b5d8863e3151e05026a28e0d924accf0a7a3b605da978f0359bb804df43", size = 1223872, upload-time = "2025-11-01T11:53:13.664Z" }, + { url = "https://files.pythonhosted.org/packages/c8/0f/41ee8034e744b871c2e071ef0d360686f5ccfe5659f4fd96c3ec406b3c8b/rapidfuzz-3.14.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73b07566bc7e010e7b5bd490fb04bb312e820970180df6b5655e9e6224c137db", size = 2392512, upload-time = "2025-11-01T11:53:15.109Z" }, + { url = "https://files.pythonhosted.org/packages/da/86/280038b6b0c2ccec54fb957c732ad6b41cc1fd03b288d76545b9cf98343f/rapidfuzz-3.14.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6de00eb84c71476af7d3110cf25d8fe7c792d7f5fa86764ef0b4ca97e78ca3ed", size = 2521398, upload-time = "2025-11-01T11:53:17.146Z" }, + { url = "https://files.pythonhosted.org/packages/fa/7b/05c26f939607dca0006505e3216248ae2de631e39ef94dd63dbbf0860021/rapidfuzz-3.14.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d7843a1abf0091773a530636fdd2a49a41bcae22f9910b86b4f903e76ddc82dc", size = 4259416, upload-time = "2025-11-01T11:53:19.34Z" }, + { url = "https://files.pythonhosted.org/packages/40/eb/9e3af4103d91788f81111af1b54a28de347cdbed8eaa6c91d5e98a889aab/rapidfuzz-3.14.3-cp312-cp312-win32.whl", hash = "sha256:dea97ac3ca18cd3ba8f3d04b5c1fe4aa60e58e8d9b7793d3bd595fdb04128d7a", size = 1709527, upload-time = "2025-11-01T11:53:20.949Z" }, + { url = "https://files.pythonhosted.org/packages/b8/63/d06ecce90e2cf1747e29aeab9f823d21e5877a4c51b79720b2d3be7848f8/rapidfuzz-3.14.3-cp312-cp312-win_amd64.whl", hash = "sha256:b5100fd6bcee4d27f28f4e0a1c6b5127bc8ba7c2a9959cad9eab0bf4a7ab3329", size = 1538989, upload-time = "2025-11-01T11:53:22.428Z" }, + { url = "https://files.pythonhosted.org/packages/fc/6d/beee32dcda64af8128aab3ace2ccb33d797ed58c434c6419eea015fec779/rapidfuzz-3.14.3-cp312-cp312-win_arm64.whl", hash = "sha256:4e49c9e992bc5fc873bd0fff7ef16a4405130ec42f2ce3d2b735ba5d3d4eb70f", size = 811161, upload-time = "2025-11-01T11:53:23.811Z" }, + { url = "https://files.pythonhosted.org/packages/e4/4f/0d94d09646853bd26978cb3a7541b6233c5760687777fa97da8de0d9a6ac/rapidfuzz-3.14.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbcb726064b12f356bf10fffdb6db4b6dce5390b23627c08652b3f6e49aa56ae", size = 1939646, upload-time = "2025-11-01T11:53:25.292Z" }, + { url = "https://files.pythonhosted.org/packages/b6/eb/f96aefc00f3bbdbab9c0657363ea8437a207d7545ac1c3789673e05d80bd/rapidfuzz-3.14.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1704fc70d214294e554a2421b473779bcdeef715881c5e927dc0f11e1692a0ff", size = 1385512, upload-time = "2025-11-01T11:53:27.594Z" }, + { url = "https://files.pythonhosted.org/packages/26/34/71c4f7749c12ee223dba90017a5947e8f03731a7cc9f489b662a8e9e643d/rapidfuzz-3.14.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc65e72790ddfd310c2c8912b45106e3800fefe160b0c2ef4d6b6fec4e826457", size = 1373571, upload-time = "2025-11-01T11:53:29.096Z" }, + { url = "https://files.pythonhosted.org/packages/32/00/ec8597a64f2be301ce1ee3290d067f49f6a7afb226b67d5f15b56d772ba5/rapidfuzz-3.14.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43e38c1305cffae8472572a0584d4ffc2f130865586a81038ca3965301f7c97c", size = 3156759, upload-time = "2025-11-01T11:53:30.777Z" }, + { url = "https://files.pythonhosted.org/packages/61/d5/b41eeb4930501cc899d5a9a7b5c9a33d85a670200d7e81658626dcc0ecc0/rapidfuzz-3.14.3-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:e195a77d06c03c98b3fc06b8a28576ba824392ce40de8c708f96ce04849a052e", size = 1222067, upload-time = "2025-11-01T11:53:32.334Z" }, + { url = "https://files.pythonhosted.org/packages/2a/7d/6d9abb4ffd1027c6ed837b425834f3bed8344472eb3a503ab55b3407c721/rapidfuzz-3.14.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1b7ef2f4b8583a744338a18f12c69693c194fb6777c0e9ada98cd4d9e8f09d10", size = 2394775, upload-time = "2025-11-01T11:53:34.24Z" }, + { url = "https://files.pythonhosted.org/packages/15/ce/4f3ab4c401c5a55364da1ffff8cc879fc97b4e5f4fa96033827da491a973/rapidfuzz-3.14.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a2135b138bcdcb4c3742d417f215ac2d8c2b87bde15b0feede231ae95f09ec41", size = 2526123, upload-time = "2025-11-01T11:53:35.779Z" }, + { url = "https://files.pythonhosted.org/packages/c1/4b/54f804975376a328f57293bd817c12c9036171d15cf7292032e3f5820b2d/rapidfuzz-3.14.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33a325ed0e8e1aa20c3e75f8ab057a7b248fdea7843c2a19ade0008906c14af0", size = 4262874, upload-time = "2025-11-01T11:53:37.866Z" }, + { url = "https://files.pythonhosted.org/packages/e9/b6/958db27d8a29a50ee6edd45d33debd3ce732e7209183a72f57544cd5fe22/rapidfuzz-3.14.3-cp313-cp313-win32.whl", hash = "sha256:8383b6d0d92f6cd008f3c9216535be215a064b2cc890398a678b56e6d280cb63", size = 1707972, upload-time = "2025-11-01T11:53:39.442Z" }, + { url = "https://files.pythonhosted.org/packages/07/75/fde1f334b0cec15b5946d9f84d73250fbfcc73c236b4bc1b25129d90876b/rapidfuzz-3.14.3-cp313-cp313-win_amd64.whl", hash = "sha256:e6b5e3036976f0fde888687d91be86d81f9ac5f7b02e218913c38285b756be6c", size = 1537011, upload-time = "2025-11-01T11:53:40.92Z" }, + { url = "https://files.pythonhosted.org/packages/2e/d7/d83fe001ce599dc7ead57ba1debf923dc961b6bdce522b741e6b8c82f55c/rapidfuzz-3.14.3-cp313-cp313-win_arm64.whl", hash = "sha256:7ba009977601d8b0828bfac9a110b195b3e4e79b350dcfa48c11269a9f1918a0", size = 810744, upload-time = "2025-11-01T11:53:42.723Z" }, + { url = "https://files.pythonhosted.org/packages/92/13/a486369e63ff3c1a58444d16b15c5feb943edd0e6c28a1d7d67cb8946b8f/rapidfuzz-3.14.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a0a28add871425c2fe94358c6300bbeb0bc2ed828ca003420ac6825408f5a424", size = 1967702, upload-time = "2025-11-01T11:53:44.554Z" }, + { url = "https://files.pythonhosted.org/packages/f1/82/efad25e260b7810f01d6b69122685e355bed78c94a12784bac4e0beb2afb/rapidfuzz-3.14.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:010e12e2411a4854b0434f920e72b717c43f8ec48d57e7affe5c42ecfa05dd0e", size = 1410702, upload-time = "2025-11-01T11:53:46.066Z" }, + { url = "https://files.pythonhosted.org/packages/ba/1a/34c977b860cde91082eae4a97ae503f43e0d84d4af301d857679b66f9869/rapidfuzz-3.14.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cfc3d57abd83c734d1714ec39c88a34dd69c85474918ebc21296f1e61eb5ca8", size = 1382337, upload-time = "2025-11-01T11:53:47.62Z" }, + { url = "https://files.pythonhosted.org/packages/88/74/f50ea0e24a5880a9159e8fd256b84d8f4634c2f6b4f98028bdd31891d907/rapidfuzz-3.14.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89acb8cbb52904f763e5ac238083b9fc193bed8d1f03c80568b20e4cef43a519", size = 3165563, upload-time = "2025-11-01T11:53:49.216Z" }, + { url = "https://files.pythonhosted.org/packages/e8/7a/e744359404d7737049c26099423fc54bcbf303de5d870d07d2fb1410f567/rapidfuzz-3.14.3-cp313-cp313t-manylinux_2_31_armv7l.whl", hash = "sha256:7d9af908c2f371bfb9c985bd134e295038e3031e666e4b2ade1e7cb7f5af2f1a", size = 1214727, upload-time = "2025-11-01T11:53:50.883Z" }, + { url = "https://files.pythonhosted.org/packages/d3/2e/87adfe14ce75768ec6c2b8acd0e05e85e84be4be5e3d283cdae360afc4fe/rapidfuzz-3.14.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1f1925619627f8798f8c3a391d81071336942e5fe8467bc3c567f982e7ce2897", size = 2403349, upload-time = "2025-11-01T11:53:52.322Z" }, + { url = "https://files.pythonhosted.org/packages/70/17/6c0b2b2bff9c8b12e12624c07aa22e922b0c72a490f180fa9183d1ef2c75/rapidfuzz-3.14.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:152555187360978119e98ce3e8263d70dd0c40c7541193fc302e9b7125cf8f58", size = 2507596, upload-time = "2025-11-01T11:53:53.835Z" }, + { url = "https://files.pythonhosted.org/packages/c3/d1/87852a7cbe4da7b962174c749a47433881a63a817d04f3e385ea9babcd9e/rapidfuzz-3.14.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:52619d25a09546b8db078981ca88939d72caa6b8701edd8b22e16482a38e799f", size = 4273595, upload-time = "2025-11-01T11:53:55.961Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ab/1d0354b7d1771a28fa7fe089bc23acec2bdd3756efa2419f463e3ed80e16/rapidfuzz-3.14.3-cp313-cp313t-win32.whl", hash = "sha256:489ce98a895c98cad284f0a47960c3e264c724cb4cfd47a1430fa091c0c25204", size = 1757773, upload-time = "2025-11-01T11:53:57.628Z" }, + { url = "https://files.pythonhosted.org/packages/0b/0c/71ef356adc29e2bdf74cd284317b34a16b80258fa0e7e242dd92cc1e6d10/rapidfuzz-3.14.3-cp313-cp313t-win_amd64.whl", hash = "sha256:656e52b054d5b5c2524169240e50cfa080b04b1c613c5f90a2465e84888d6f15", size = 1576797, upload-time = "2025-11-01T11:53:59.455Z" }, + { url = "https://files.pythonhosted.org/packages/fe/d2/0e64fc27bb08d4304aa3d11154eb5480bcf5d62d60140a7ee984dc07468a/rapidfuzz-3.14.3-cp313-cp313t-win_arm64.whl", hash = "sha256:c7e40c0a0af02ad6e57e89f62bef8604f55a04ecae90b0ceeda591bbf5923317", size = 829940, upload-time = "2025-11-01T11:54:01.1Z" }, + { url = "https://files.pythonhosted.org/packages/32/6f/1b88aaeade83abc5418788f9e6b01efefcd1a69d65ded37d89cd1662be41/rapidfuzz-3.14.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:442125473b247227d3f2de807a11da6c08ccf536572d1be943f8e262bae7e4ea", size = 1942086, upload-time = "2025-11-01T11:54:02.592Z" }, + { url = "https://files.pythonhosted.org/packages/a0/2c/b23861347436cb10f46c2bd425489ec462790faaa360a54a7ede5f78de88/rapidfuzz-3.14.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1ec0c8c0c3d4f97ced46b2e191e883f8c82dbbf6d5ebc1842366d7eff13cd5a6", size = 1386993, upload-time = "2025-11-01T11:54:04.12Z" }, + { url = "https://files.pythonhosted.org/packages/83/86/5d72e2c060aa1fbdc1f7362d938f6b237dff91f5b9fc5dd7cc297e112250/rapidfuzz-3.14.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2dc37bc20272f388b8c3a4eba4febc6e77e50a8f450c472def4751e7678f55e4", size = 1379126, upload-time = "2025-11-01T11:54:05.777Z" }, + { url = "https://files.pythonhosted.org/packages/c9/bc/ef2cee3e4d8b3fc22705ff519f0d487eecc756abdc7c25d53686689d6cf2/rapidfuzz-3.14.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dee362e7e79bae940a5e2b3f6d09c6554db6a4e301cc68343886c08be99844f1", size = 3159304, upload-time = "2025-11-01T11:54:07.351Z" }, + { url = "https://files.pythonhosted.org/packages/a0/36/dc5f2f62bbc7bc90be1f75eeaf49ed9502094bb19290dfb4747317b17f12/rapidfuzz-3.14.3-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:4b39921df948388a863f0e267edf2c36302983459b021ab928d4b801cbe6a421", size = 1218207, upload-time = "2025-11-01T11:54:09.641Z" }, + { url = "https://files.pythonhosted.org/packages/df/7e/8f4be75c1bc62f47edf2bbbe2370ee482fae655ebcc4718ac3827ead3904/rapidfuzz-3.14.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:beda6aa9bc44d1d81242e7b291b446be352d3451f8217fcb068fc2933927d53b", size = 2401245, upload-time = "2025-11-01T11:54:11.543Z" }, + { url = "https://files.pythonhosted.org/packages/05/38/f7c92759e1bb188dd05b80d11c630ba59b8d7856657baf454ff56059c2ab/rapidfuzz-3.14.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:6a014ba09657abfcfeed64b7d09407acb29af436d7fc075b23a298a7e4a6b41c", size = 2518308, upload-time = "2025-11-01T11:54:13.134Z" }, + { url = "https://files.pythonhosted.org/packages/c7/ac/85820f70fed5ecb5f1d9a55f1e1e2090ef62985ef41db289b5ac5ec56e28/rapidfuzz-3.14.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:32eeafa3abce138bb725550c0e228fc7eaeec7059aa8093d9cbbec2b58c2371a", size = 4265011, upload-time = "2025-11-01T11:54:15.087Z" }, + { url = "https://files.pythonhosted.org/packages/46/a9/616930721ea9835c918af7cde22bff17f9db3639b0c1a7f96684be7f5630/rapidfuzz-3.14.3-cp314-cp314-win32.whl", hash = "sha256:adb44d996fc610c7da8c5048775b21db60dd63b1548f078e95858c05c86876a3", size = 1742245, upload-time = "2025-11-01T11:54:17.19Z" }, + { url = "https://files.pythonhosted.org/packages/06/8a/f2fa5e9635b1ccafda4accf0e38246003f69982d7c81f2faa150014525a4/rapidfuzz-3.14.3-cp314-cp314-win_amd64.whl", hash = "sha256:f3d15d8527e2b293e38ce6e437631af0708df29eafd7c9fc48210854c94472f9", size = 1584856, upload-time = "2025-11-01T11:54:18.764Z" }, + { url = "https://files.pythonhosted.org/packages/ef/97/09e20663917678a6d60d8e0e29796db175b1165e2079830430342d5298be/rapidfuzz-3.14.3-cp314-cp314-win_arm64.whl", hash = "sha256:576e4b9012a67e0bf54fccb69a7b6c94d4e86a9540a62f1a5144977359133583", size = 833490, upload-time = "2025-11-01T11:54:20.753Z" }, + { url = "https://files.pythonhosted.org/packages/03/1b/6b6084576ba87bf21877c77218a0c97ba98cb285b0c02eaaee3acd7c4513/rapidfuzz-3.14.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:cec3c0da88562727dd5a5a364bd9efeb535400ff0bfb1443156dd139a1dd7b50", size = 1968658, upload-time = "2025-11-01T11:54:22.25Z" }, + { url = "https://files.pythonhosted.org/packages/38/c0/fb02a0db80d95704b0a6469cc394e8c38501abf7e1c0b2afe3261d1510c2/rapidfuzz-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d1fa009f8b1100e4880868137e7bf0501422898f7674f2adcd85d5a67f041296", size = 1410742, upload-time = "2025-11-01T11:54:23.863Z" }, + { url = "https://files.pythonhosted.org/packages/a4/72/3fbf12819fc6afc8ec75a45204013b40979d068971e535a7f3512b05e765/rapidfuzz-3.14.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b86daa7419b5e8b180690efd1fdbac43ff19230803282521c5b5a9c83977655", size = 1382810, upload-time = "2025-11-01T11:54:25.571Z" }, + { url = "https://files.pythonhosted.org/packages/0f/18/0f1991d59bb7eee28922a00f79d83eafa8c7bfb4e8edebf4af2a160e7196/rapidfuzz-3.14.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7bd1816db05d6c5ffb3a4df0a2b7b56fb8c81ef584d08e37058afa217da91b1", size = 3166349, upload-time = "2025-11-01T11:54:27.195Z" }, + { url = "https://files.pythonhosted.org/packages/0d/f0/baa958b1989c8f88c78bbb329e969440cf330b5a01a982669986495bb980/rapidfuzz-3.14.3-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:33da4bbaf44e9755b0ce192597f3bde7372fe2e381ab305f41b707a95ac57aa7", size = 1214994, upload-time = "2025-11-01T11:54:28.821Z" }, + { url = "https://files.pythonhosted.org/packages/e4/a0/cd12ec71f9b2519a3954febc5740291cceabc64c87bc6433afcb36259f3b/rapidfuzz-3.14.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3fecce764cf5a991ee2195a844196da840aba72029b2612f95ac68a8b74946bf", size = 2403919, upload-time = "2025-11-01T11:54:30.393Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ce/019bd2176c1644098eced4f0595cb4b3ef52e4941ac9a5854f209d0a6e16/rapidfuzz-3.14.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:ecd7453e02cf072258c3a6b8e930230d789d5d46cc849503729f9ce475d0e785", size = 2508346, upload-time = "2025-11-01T11:54:32.048Z" }, + { url = "https://files.pythonhosted.org/packages/23/f8/be16c68e2c9e6c4f23e8f4adbb7bccc9483200087ed28ff76c5312da9b14/rapidfuzz-3.14.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ea188aa00e9bcae8c8411f006a5f2f06c4607a02f24eab0d8dc58566aa911f35", size = 4274105, upload-time = "2025-11-01T11:54:33.701Z" }, + { url = "https://files.pythonhosted.org/packages/a1/d1/5ab148e03f7e6ec8cd220ccf7af74d3aaa4de26dd96df58936beb7cba820/rapidfuzz-3.14.3-cp314-cp314t-win32.whl", hash = "sha256:7ccbf68100c170e9a0581accbe9291850936711548c6688ce3bfb897b8c589ad", size = 1793465, upload-time = "2025-11-01T11:54:35.331Z" }, + { url = "https://files.pythonhosted.org/packages/cd/97/433b2d98e97abd9fff1c470a109b311669f44cdec8d0d5aa250aceaed1fb/rapidfuzz-3.14.3-cp314-cp314t-win_amd64.whl", hash = "sha256:9ec02e62ae765a318d6de38df609c57fc6dacc65c0ed1fd489036834fd8a620c", size = 1623491, upload-time = "2025-11-01T11:54:38.085Z" }, + { url = "https://files.pythonhosted.org/packages/e2/f6/e2176eb94f94892441bce3ddc514c179facb65db245e7ce3356965595b19/rapidfuzz-3.14.3-cp314-cp314t-win_arm64.whl", hash = "sha256:e805e52322ae29aa945baf7168b6c898120fbc16d2b8f940b658a5e9e3999253", size = 851487, upload-time = "2025-11-01T11:54:40.176Z" }, +] + +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, +] + +[[package]] +name = "regex" +version = "2025.11.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/a9/546676f25e573a4cf00fe8e119b78a37b6a8fe2dc95cda877b30889c9c45/regex-2025.11.3.tar.gz", hash = "sha256:1fedc720f9bb2494ce31a58a1631f9c82df6a09b49c19517ea5cc280b4541e01", size = 414669, upload-time = "2025-11-03T21:34:22.089Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/74/18f04cb53e58e3fb107439699bd8375cf5a835eec81084e0bddbd122e4c2/regex-2025.11.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bc8ab71e2e31b16e40868a40a69007bc305e1109bd4658eb6cad007e0bf67c41", size = 489312, upload-time = "2025-11-03T21:31:34.343Z" }, + { url = "https://files.pythonhosted.org/packages/78/3f/37fcdd0d2b1e78909108a876580485ea37c91e1acf66d3bb8e736348f441/regex-2025.11.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:22b29dda7e1f7062a52359fca6e58e548e28c6686f205e780b02ad8ef710de36", size = 291256, upload-time = "2025-11-03T21:31:35.675Z" }, + { url = "https://files.pythonhosted.org/packages/bf/26/0a575f58eb23b7ebd67a45fccbc02ac030b737b896b7e7a909ffe43ffd6a/regex-2025.11.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3a91e4a29938bc1a082cc28fdea44be420bf2bebe2665343029723892eb073e1", size = 288921, upload-time = "2025-11-03T21:31:37.07Z" }, + { url = "https://files.pythonhosted.org/packages/ea/98/6a8dff667d1af907150432cf5abc05a17ccd32c72a3615410d5365ac167a/regex-2025.11.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08b884f4226602ad40c5d55f52bf91a9df30f513864e0054bad40c0e9cf1afb7", size = 798568, upload-time = "2025-11-03T21:31:38.784Z" }, + { url = "https://files.pythonhosted.org/packages/64/15/92c1db4fa4e12733dd5a526c2dd2b6edcbfe13257e135fc0f6c57f34c173/regex-2025.11.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3e0b11b2b2433d1c39c7c7a30e3f3d0aeeea44c2a8d0bae28f6b95f639927a69", size = 864165, upload-time = "2025-11-03T21:31:40.559Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e7/3ad7da8cdee1ce66c7cd37ab5ab05c463a86ffeb52b1a25fe7bd9293b36c/regex-2025.11.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87eb52a81ef58c7ba4d45c3ca74e12aa4b4e77816f72ca25258a85b3ea96cb48", size = 912182, upload-time = "2025-11-03T21:31:42.002Z" }, + { url = "https://files.pythonhosted.org/packages/84/bd/9ce9f629fcb714ffc2c3faf62b6766ecb7a585e1e885eb699bcf130a5209/regex-2025.11.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a12ab1f5c29b4e93db518f5e3872116b7e9b1646c9f9f426f777b50d44a09e8c", size = 803501, upload-time = "2025-11-03T21:31:43.815Z" }, + { url = "https://files.pythonhosted.org/packages/7c/0f/8dc2e4349d8e877283e6edd6c12bdcebc20f03744e86f197ab6e4492bf08/regex-2025.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7521684c8c7c4f6e88e35ec89680ee1aa8358d3f09d27dfbdf62c446f5d4c695", size = 787842, upload-time = "2025-11-03T21:31:45.353Z" }, + { url = "https://files.pythonhosted.org/packages/f9/73/cff02702960bc185164d5619c0c62a2f598a6abff6695d391b096237d4ab/regex-2025.11.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7fe6e5440584e94cc4b3f5f4d98a25e29ca12dccf8873679a635638349831b98", size = 858519, upload-time = "2025-11-03T21:31:46.814Z" }, + { url = "https://files.pythonhosted.org/packages/61/83/0e8d1ae71e15bc1dc36231c90b46ee35f9d52fab2e226b0e039e7ea9c10a/regex-2025.11.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8e026094aa12b43f4fd74576714e987803a315c76edb6b098b9809db5de58f74", size = 850611, upload-time = "2025-11-03T21:31:48.289Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f5/70a5cdd781dcfaa12556f2955bf170cd603cb1c96a1827479f8faea2df97/regex-2025.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:435bbad13e57eb5606a68443af62bed3556de2f46deb9f7d4237bc2f1c9fb3a0", size = 789759, upload-time = "2025-11-03T21:31:49.759Z" }, + { url = "https://files.pythonhosted.org/packages/59/9b/7c29be7903c318488983e7d97abcf8ebd3830e4c956c4c540005fcfb0462/regex-2025.11.3-cp312-cp312-win32.whl", hash = "sha256:3839967cf4dc4b985e1570fd8d91078f0c519f30491c60f9ac42a8db039be204", size = 266194, upload-time = "2025-11-03T21:31:51.53Z" }, + { url = "https://files.pythonhosted.org/packages/1a/67/3b92df89f179d7c367be654ab5626ae311cb28f7d5c237b6bb976cd5fbbb/regex-2025.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:e721d1b46e25c481dc5ded6f4b3f66c897c58d2e8cfdf77bbced84339108b0b9", size = 277069, upload-time = "2025-11-03T21:31:53.151Z" }, + { url = "https://files.pythonhosted.org/packages/d7/55/85ba4c066fe5094d35b249c3ce8df0ba623cfd35afb22d6764f23a52a1c5/regex-2025.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:64350685ff08b1d3a6fff33f45a9ca183dc1d58bbfe4981604e70ec9801bbc26", size = 270330, upload-time = "2025-11-03T21:31:54.514Z" }, + { url = "https://files.pythonhosted.org/packages/e1/a7/dda24ebd49da46a197436ad96378f17df30ceb40e52e859fc42cac45b850/regex-2025.11.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c1e448051717a334891f2b9a620fe36776ebf3dd8ec46a0b877c8ae69575feb4", size = 489081, upload-time = "2025-11-03T21:31:55.9Z" }, + { url = "https://files.pythonhosted.org/packages/19/22/af2dc751aacf88089836aa088a1a11c4f21a04707eb1b0478e8e8fb32847/regex-2025.11.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b5aca4d5dfd7fbfbfbdaf44850fcc7709a01146a797536a8f84952e940cca76", size = 291123, upload-time = "2025-11-03T21:31:57.758Z" }, + { url = "https://files.pythonhosted.org/packages/a3/88/1a3ea5672f4b0a84802ee9891b86743438e7c04eb0b8f8c4e16a42375327/regex-2025.11.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:04d2765516395cf7dda331a244a3282c0f5ae96075f728629287dfa6f76ba70a", size = 288814, upload-time = "2025-11-03T21:32:01.12Z" }, + { url = "https://files.pythonhosted.org/packages/fb/8c/f5987895bf42b8ddeea1b315c9fedcfe07cadee28b9c98cf50d00adcb14d/regex-2025.11.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d9903ca42bfeec4cebedba8022a7c97ad2aab22e09573ce9976ba01b65e4361", size = 798592, upload-time = "2025-11-03T21:32:03.006Z" }, + { url = "https://files.pythonhosted.org/packages/99/2a/6591ebeede78203fa77ee46a1c36649e02df9eaa77a033d1ccdf2fcd5d4e/regex-2025.11.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:639431bdc89d6429f6721625e8129413980ccd62e9d3f496be618a41d205f160", size = 864122, upload-time = "2025-11-03T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/94/d6/be32a87cf28cf8ed064ff281cfbd49aefd90242a83e4b08b5a86b38e8eb4/regex-2025.11.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f117efad42068f9715677c8523ed2be1518116d1c49b1dd17987716695181efe", size = 912272, upload-time = "2025-11-03T21:32:06.148Z" }, + { url = "https://files.pythonhosted.org/packages/62/11/9bcef2d1445665b180ac7f230406ad80671f0fc2a6ffb93493b5dd8cd64c/regex-2025.11.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4aecb6f461316adf9f1f0f6a4a1a3d79e045f9b71ec76055a791affa3b285850", size = 803497, upload-time = "2025-11-03T21:32:08.162Z" }, + { url = "https://files.pythonhosted.org/packages/e5/a7/da0dc273d57f560399aa16d8a68ae7f9b57679476fc7ace46501d455fe84/regex-2025.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b3a5f320136873cc5561098dfab677eea139521cb9a9e8db98b7e64aef44cbc", size = 787892, upload-time = "2025-11-03T21:32:09.769Z" }, + { url = "https://files.pythonhosted.org/packages/da/4b/732a0c5a9736a0b8d6d720d4945a2f1e6f38f87f48f3173559f53e8d5d82/regex-2025.11.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:75fa6f0056e7efb1f42a1c34e58be24072cb9e61a601340cc1196ae92326a4f9", size = 858462, upload-time = "2025-11-03T21:32:11.769Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f5/a2a03df27dc4c2d0c769220f5110ba8c4084b0bfa9ab0f9b4fcfa3d2b0fc/regex-2025.11.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:dbe6095001465294f13f1adcd3311e50dd84e5a71525f20a10bd16689c61ce0b", size = 850528, upload-time = "2025-11-03T21:32:13.906Z" }, + { url = "https://files.pythonhosted.org/packages/d6/09/e1cd5bee3841c7f6eb37d95ca91cdee7100b8f88b81e41c2ef426910891a/regex-2025.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:454d9b4ae7881afbc25015b8627c16d88a597479b9dea82b8c6e7e2e07240dc7", size = 789866, upload-time = "2025-11-03T21:32:15.748Z" }, + { url = "https://files.pythonhosted.org/packages/eb/51/702f5ea74e2a9c13d855a6a85b7f80c30f9e72a95493260193c07f3f8d74/regex-2025.11.3-cp313-cp313-win32.whl", hash = "sha256:28ba4d69171fc6e9896337d4fc63a43660002b7da53fc15ac992abcf3410917c", size = 266189, upload-time = "2025-11-03T21:32:17.493Z" }, + { url = "https://files.pythonhosted.org/packages/8b/00/6e29bb314e271a743170e53649db0fdb8e8ff0b64b4f425f5602f4eb9014/regex-2025.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:bac4200befe50c670c405dc33af26dad5a3b6b255dd6c000d92fe4629f9ed6a5", size = 277054, upload-time = "2025-11-03T21:32:19.042Z" }, + { url = "https://files.pythonhosted.org/packages/25/f1/b156ff9f2ec9ac441710764dda95e4edaf5f36aca48246d1eea3f1fd96ec/regex-2025.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:2292cd5a90dab247f9abe892ac584cb24f0f54680c73fcb4a7493c66c2bf2467", size = 270325, upload-time = "2025-11-03T21:32:21.338Z" }, + { url = "https://files.pythonhosted.org/packages/20/28/fd0c63357caefe5680b8ea052131acbd7f456893b69cc2a90cc3e0dc90d4/regex-2025.11.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:1eb1ebf6822b756c723e09f5186473d93236c06c579d2cc0671a722d2ab14281", size = 491984, upload-time = "2025-11-03T21:32:23.466Z" }, + { url = "https://files.pythonhosted.org/packages/df/ec/7014c15626ab46b902b3bcc4b28a7bae46d8f281fc7ea9c95e22fcaaa917/regex-2025.11.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1e00ec2970aab10dc5db34af535f21fcf32b4a31d99e34963419636e2f85ae39", size = 292673, upload-time = "2025-11-03T21:32:25.034Z" }, + { url = "https://files.pythonhosted.org/packages/23/ab/3b952ff7239f20d05f1f99e9e20188513905f218c81d52fb5e78d2bf7634/regex-2025.11.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a4cb042b615245d5ff9b3794f56be4138b5adc35a4166014d31d1814744148c7", size = 291029, upload-time = "2025-11-03T21:32:26.528Z" }, + { url = "https://files.pythonhosted.org/packages/21/7e/3dc2749fc684f455f162dcafb8a187b559e2614f3826877d3844a131f37b/regex-2025.11.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44f264d4bf02f3176467d90b294d59bf1db9fe53c141ff772f27a8b456b2a9ed", size = 807437, upload-time = "2025-11-03T21:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/1b/0b/d529a85ab349c6a25d1ca783235b6e3eedf187247eab536797021f7126c6/regex-2025.11.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7be0277469bf3bd7a34a9c57c1b6a724532a0d235cd0dc4e7f4316f982c28b19", size = 873368, upload-time = "2025-11-03T21:32:30.4Z" }, + { url = "https://files.pythonhosted.org/packages/7d/18/2d868155f8c9e3e9d8f9e10c64e9a9f496bb8f7e037a88a8bed26b435af6/regex-2025.11.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0d31e08426ff4b5b650f68839f5af51a92a5b51abd8554a60c2fbc7c71f25d0b", size = 914921, upload-time = "2025-11-03T21:32:32.123Z" }, + { url = "https://files.pythonhosted.org/packages/2d/71/9d72ff0f354fa783fe2ba913c8734c3b433b86406117a8db4ea2bf1c7a2f/regex-2025.11.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e43586ce5bd28f9f285a6e729466841368c4a0353f6fd08d4ce4630843d3648a", size = 812708, upload-time = "2025-11-03T21:32:34.305Z" }, + { url = "https://files.pythonhosted.org/packages/e7/19/ce4bf7f5575c97f82b6e804ffb5c4e940c62609ab2a0d9538d47a7fdf7d4/regex-2025.11.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0f9397d561a4c16829d4e6ff75202c1c08b68a3bdbfe29dbfcdb31c9830907c6", size = 795472, upload-time = "2025-11-03T21:32:36.364Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/fd1063a176ffb7b2315f9a1b08d17b18118b28d9df163132615b835a26ee/regex-2025.11.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:dd16e78eb18ffdb25ee33a0682d17912e8cc8a770e885aeee95020046128f1ce", size = 868341, upload-time = "2025-11-03T21:32:38.042Z" }, + { url = "https://files.pythonhosted.org/packages/12/43/103fb2e9811205e7386366501bc866a164a0430c79dd59eac886a2822950/regex-2025.11.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:ffcca5b9efe948ba0661e9df0fa50d2bc4b097c70b9810212d6b62f05d83b2dd", size = 854666, upload-time = "2025-11-03T21:32:40.079Z" }, + { url = "https://files.pythonhosted.org/packages/7d/22/e392e53f3869b75804762c7c848bd2dd2abf2b70fb0e526f58724638bd35/regex-2025.11.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c56b4d162ca2b43318ac671c65bd4d563e841a694ac70e1a976ac38fcf4ca1d2", size = 799473, upload-time = "2025-11-03T21:32:42.148Z" }, + { url = "https://files.pythonhosted.org/packages/4f/f9/8bd6b656592f925b6845fcbb4d57603a3ac2fb2373344ffa1ed70aa6820a/regex-2025.11.3-cp313-cp313t-win32.whl", hash = "sha256:9ddc42e68114e161e51e272f667d640f97e84a2b9ef14b7477c53aac20c2d59a", size = 268792, upload-time = "2025-11-03T21:32:44.13Z" }, + { url = "https://files.pythonhosted.org/packages/e5/87/0e7d603467775ff65cd2aeabf1b5b50cc1c3708556a8b849a2fa4dd1542b/regex-2025.11.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7a7c7fdf755032ffdd72c77e3d8096bdcb0eb92e89e17571a196f03d88b11b3c", size = 280214, upload-time = "2025-11-03T21:32:45.853Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d0/2afc6f8e94e2b64bfb738a7c2b6387ac1699f09f032d363ed9447fd2bb57/regex-2025.11.3-cp313-cp313t-win_arm64.whl", hash = "sha256:df9eb838c44f570283712e7cff14c16329a9f0fb19ca492d21d4b7528ee6821e", size = 271469, upload-time = "2025-11-03T21:32:48.026Z" }, + { url = "https://files.pythonhosted.org/packages/31/e9/f6e13de7e0983837f7b6d238ad9458800a874bf37c264f7923e63409944c/regex-2025.11.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9697a52e57576c83139d7c6f213d64485d3df5bf84807c35fa409e6c970801c6", size = 489089, upload-time = "2025-11-03T21:32:50.027Z" }, + { url = "https://files.pythonhosted.org/packages/a3/5c/261f4a262f1fa65141c1b74b255988bd2fa020cc599e53b080667d591cfc/regex-2025.11.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e18bc3f73bd41243c9b38a6d9f2366cd0e0137a9aebe2d8ff76c5b67d4c0a3f4", size = 291059, upload-time = "2025-11-03T21:32:51.682Z" }, + { url = "https://files.pythonhosted.org/packages/8e/57/f14eeb7f072b0e9a5a090d1712741fd8f214ec193dba773cf5410108bb7d/regex-2025.11.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:61a08bcb0ec14ff4e0ed2044aad948d0659604f824cbd50b55e30b0ec6f09c73", size = 288900, upload-time = "2025-11-03T21:32:53.569Z" }, + { url = "https://files.pythonhosted.org/packages/3c/6b/1d650c45e99a9b327586739d926a1cd4e94666b1bd4af90428b36af66dc7/regex-2025.11.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9c30003b9347c24bcc210958c5d167b9e4f9be786cb380a7d32f14f9b84674f", size = 799010, upload-time = "2025-11-03T21:32:55.222Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/d66dcbc6b628ce4e3f7f0cbbb84603aa2fc0ffc878babc857726b8aab2e9/regex-2025.11.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4e1e592789704459900728d88d41a46fe3969b82ab62945560a31732ffc19a6d", size = 864893, upload-time = "2025-11-03T21:32:57.239Z" }, + { url = "https://files.pythonhosted.org/packages/bf/2d/f238229f1caba7ac87a6c4153d79947fb0261415827ae0f77c304260c7d3/regex-2025.11.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6538241f45eb5a25aa575dbba1069ad786f68a4f2773a29a2bd3dd1f9de787be", size = 911522, upload-time = "2025-11-03T21:32:59.274Z" }, + { url = "https://files.pythonhosted.org/packages/bd/3d/22a4eaba214a917c80e04f6025d26143690f0419511e0116508e24b11c9b/regex-2025.11.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce22519c989bb72a7e6b36a199384c53db7722fe669ba891da75907fe3587db", size = 803272, upload-time = "2025-11-03T21:33:01.393Z" }, + { url = "https://files.pythonhosted.org/packages/84/b1/03188f634a409353a84b5ef49754b97dbcc0c0f6fd6c8ede505a8960a0a4/regex-2025.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:66d559b21d3640203ab9075797a55165d79017520685fb407b9234d72ab63c62", size = 787958, upload-time = "2025-11-03T21:33:03.379Z" }, + { url = "https://files.pythonhosted.org/packages/99/6a/27d072f7fbf6fadd59c64d210305e1ff865cc3b78b526fd147db768c553b/regex-2025.11.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:669dcfb2e38f9e8c69507bace46f4889e3abbfd9b0c29719202883c0a603598f", size = 859289, upload-time = "2025-11-03T21:33:05.374Z" }, + { url = "https://files.pythonhosted.org/packages/9a/70/1b3878f648e0b6abe023172dacb02157e685564853cc363d9961bcccde4e/regex-2025.11.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:32f74f35ff0f25a5021373ac61442edcb150731fbaa28286bbc8bb1582c89d02", size = 850026, upload-time = "2025-11-03T21:33:07.131Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d5/68e25559b526b8baab8e66839304ede68ff6727237a47727d240006bd0ff/regex-2025.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e6c7a21dffba883234baefe91bc3388e629779582038f75d2a5be918e250f0ed", size = 789499, upload-time = "2025-11-03T21:33:09.141Z" }, + { url = "https://files.pythonhosted.org/packages/fc/df/43971264857140a350910d4e33df725e8c94dd9dee8d2e4729fa0d63d49e/regex-2025.11.3-cp314-cp314-win32.whl", hash = "sha256:795ea137b1d809eb6836b43748b12634291c0ed55ad50a7d72d21edf1cd565c4", size = 271604, upload-time = "2025-11-03T21:33:10.9Z" }, + { url = "https://files.pythonhosted.org/packages/01/6f/9711b57dc6894a55faf80a4c1b5aa4f8649805cb9c7aef46f7d27e2b9206/regex-2025.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:9f95fbaa0ee1610ec0fc6b26668e9917a582ba80c52cc6d9ada15e30aa9ab9ad", size = 280320, upload-time = "2025-11-03T21:33:12.572Z" }, + { url = "https://files.pythonhosted.org/packages/f1/7e/f6eaa207d4377481f5e1775cdeb5a443b5a59b392d0065f3417d31d80f87/regex-2025.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:dfec44d532be4c07088c3de2876130ff0fbeeacaa89a137decbbb5f665855a0f", size = 273372, upload-time = "2025-11-03T21:33:14.219Z" }, + { url = "https://files.pythonhosted.org/packages/c3/06/49b198550ee0f5e4184271cee87ba4dfd9692c91ec55289e6282f0f86ccf/regex-2025.11.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ba0d8a5d7f04f73ee7d01d974d47c5834f8a1b0224390e4fe7c12a3a92a78ecc", size = 491985, upload-time = "2025-11-03T21:33:16.555Z" }, + { url = "https://files.pythonhosted.org/packages/ce/bf/abdafade008f0b1c9da10d934034cb670432d6cf6cbe38bbb53a1cfd6cf8/regex-2025.11.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:442d86cf1cfe4faabf97db7d901ef58347efd004934da045c745e7b5bd57ac49", size = 292669, upload-time = "2025-11-03T21:33:18.32Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ef/0c357bb8edbd2ad8e273fcb9e1761bc37b8acbc6e1be050bebd6475f19c1/regex-2025.11.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fd0a5e563c756de210bb964789b5abe4f114dacae9104a47e1a649b910361536", size = 291030, upload-time = "2025-11-03T21:33:20.048Z" }, + { url = "https://files.pythonhosted.org/packages/79/06/edbb67257596649b8fb088d6aeacbcb248ac195714b18a65e018bf4c0b50/regex-2025.11.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf3490bcbb985a1ae97b2ce9ad1c0f06a852d5b19dde9b07bdf25bf224248c95", size = 807674, upload-time = "2025-11-03T21:33:21.797Z" }, + { url = "https://files.pythonhosted.org/packages/f4/d9/ad4deccfce0ea336296bd087f1a191543bb99ee1c53093dcd4c64d951d00/regex-2025.11.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3809988f0a8b8c9dcc0f92478d6501fac7200b9ec56aecf0ec21f4a2ec4b6009", size = 873451, upload-time = "2025-11-03T21:33:23.741Z" }, + { url = "https://files.pythonhosted.org/packages/13/75/a55a4724c56ef13e3e04acaab29df26582f6978c000ac9cd6810ad1f341f/regex-2025.11.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f4ff94e58e84aedb9c9fce66d4ef9f27a190285b451420f297c9a09f2b9abee9", size = 914980, upload-time = "2025-11-03T21:33:25.999Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/a1657ee15bd9116f70d4a530c736983eed997b361e20ecd8f5ca3759d5c5/regex-2025.11.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eb542fd347ce61e1321b0a6b945d5701528dca0cd9759c2e3bb8bd57e47964d", size = 812852, upload-time = "2025-11-03T21:33:27.852Z" }, + { url = "https://files.pythonhosted.org/packages/b8/6f/f7516dde5506a588a561d296b2d0044839de06035bb486b326065b4c101e/regex-2025.11.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2d5919075a1f2e413c00b056ea0c2f065b3f5fe83c3d07d325ab92dce51d6", size = 795566, upload-time = "2025-11-03T21:33:32.364Z" }, + { url = "https://files.pythonhosted.org/packages/d9/dd/3d10b9e170cc16fb34cb2cef91513cf3df65f440b3366030631b2984a264/regex-2025.11.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3f8bf11a4827cc7ce5a53d4ef6cddd5ad25595d3c1435ef08f76825851343154", size = 868463, upload-time = "2025-11-03T21:33:34.459Z" }, + { url = "https://files.pythonhosted.org/packages/f5/8e/935e6beff1695aa9085ff83195daccd72acc82c81793df480f34569330de/regex-2025.11.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:22c12d837298651e5550ac1d964e4ff57c3f56965fc1812c90c9fb2028eaf267", size = 854694, upload-time = "2025-11-03T21:33:36.793Z" }, + { url = "https://files.pythonhosted.org/packages/92/12/10650181a040978b2f5720a6a74d44f841371a3d984c2083fc1752e4acf6/regex-2025.11.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:62ba394a3dda9ad41c7c780f60f6e4a70988741415ae96f6d1bf6c239cf01379", size = 799691, upload-time = "2025-11-03T21:33:39.079Z" }, + { url = "https://files.pythonhosted.org/packages/67/90/8f37138181c9a7690e7e4cb388debbd389342db3c7381d636d2875940752/regex-2025.11.3-cp314-cp314t-win32.whl", hash = "sha256:4bf146dca15cdd53224a1bf46d628bd7590e4a07fbb69e720d561aea43a32b38", size = 274583, upload-time = "2025-11-03T21:33:41.302Z" }, + { url = "https://files.pythonhosted.org/packages/8f/cd/867f5ec442d56beb56f5f854f40abcfc75e11d10b11fdb1869dd39c63aaf/regex-2025.11.3-cp314-cp314t-win_amd64.whl", hash = "sha256:adad1a1bcf1c9e76346e091d22d23ac54ef28e1365117d99521631078dfec9de", size = 284286, upload-time = "2025-11-03T21:33:43.324Z" }, + { url = "https://files.pythonhosted.org/packages/20/31/32c0c4610cbc070362bf1d2e4ea86d1ea29014d400a6d6c2486fcfd57766/regex-2025.11.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c54f768482cef41e219720013cd05933b6f971d9562544d691c68699bf2b6801", size = 274741, upload-time = "2025-11-03T21:33:45.557Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, +] + +[[package]] +name = "rfc3339-validator" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, +] + +[[package]] +name = "rfc3986-validator" +version = "0.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, +] + +[[package]] +name = "rfc3987-syntax" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lark" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239, upload-time = "2025-07-18T01:05:05.015Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046, upload-time = "2025-07-18T01:05:03.843Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.30.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/e7/98a2f4ac921d82f33e03f3835f5bf3a4a40aa1bfdc57975e74a97b2b4bdd/rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad", size = 375086, upload-time = "2025-11-30T20:22:17.93Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05", size = 359053, upload-time = "2025-11-30T20:22:19.297Z" }, + { url = "https://files.pythonhosted.org/packages/65/1c/ae157e83a6357eceff62ba7e52113e3ec4834a84cfe07fa4b0757a7d105f/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28", size = 390763, upload-time = "2025-11-30T20:22:21.661Z" }, + { url = "https://files.pythonhosted.org/packages/d4/36/eb2eb8515e2ad24c0bd43c3ee9cd74c33f7ca6430755ccdb240fd3144c44/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd", size = 408951, upload-time = "2025-11-30T20:22:23.408Z" }, + { url = "https://files.pythonhosted.org/packages/d6/65/ad8dc1784a331fabbd740ef6f71ce2198c7ed0890dab595adb9ea2d775a1/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f", size = 514622, upload-time = "2025-11-30T20:22:25.16Z" }, + { url = "https://files.pythonhosted.org/packages/63/8e/0cfa7ae158e15e143fe03993b5bcd743a59f541f5952e1546b1ac1b5fd45/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1", size = 414492, upload-time = "2025-11-30T20:22:26.505Z" }, + { url = "https://files.pythonhosted.org/packages/60/1b/6f8f29f3f995c7ffdde46a626ddccd7c63aefc0efae881dc13b6e5d5bb16/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23", size = 394080, upload-time = "2025-11-30T20:22:27.934Z" }, + { url = "https://files.pythonhosted.org/packages/6d/d5/a266341051a7a3ca2f4b750a3aa4abc986378431fc2da508c5034d081b70/rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6", size = 408680, upload-time = "2025-11-30T20:22:29.341Z" }, + { url = "https://files.pythonhosted.org/packages/10/3b/71b725851df9ab7a7a4e33cf36d241933da66040d195a84781f49c50490c/rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51", size = 423589, upload-time = "2025-11-30T20:22:31.469Z" }, + { url = "https://files.pythonhosted.org/packages/00/2b/e59e58c544dc9bd8bd8384ecdb8ea91f6727f0e37a7131baeff8d6f51661/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5", size = 573289, upload-time = "2025-11-30T20:22:32.997Z" }, + { url = "https://files.pythonhosted.org/packages/da/3e/a18e6f5b460893172a7d6a680e86d3b6bc87a54c1f0b03446a3c8c7b588f/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e", size = 599737, upload-time = "2025-11-30T20:22:34.419Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e2/714694e4b87b85a18e2c243614974413c60aa107fd815b8cbc42b873d1d7/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394", size = 563120, upload-time = "2025-11-30T20:22:35.903Z" }, + { url = "https://files.pythonhosted.org/packages/6f/ab/d5d5e3bcedb0a77f4f613706b750e50a5a3ba1c15ccd3665ecc636c968fd/rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf", size = 223782, upload-time = "2025-11-30T20:22:37.271Z" }, + { url = "https://files.pythonhosted.org/packages/39/3b/f786af9957306fdc38a74cef405b7b93180f481fb48453a114bb6465744a/rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b", size = 240463, upload-time = "2025-11-30T20:22:39.021Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d2/b91dc748126c1559042cfe41990deb92c4ee3e2b415f6b5234969ffaf0cc/rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e", size = 230868, upload-time = "2025-11-30T20:22:40.493Z" }, + { url = "https://files.pythonhosted.org/packages/ed/dc/d61221eb88ff410de3c49143407f6f3147acf2538c86f2ab7ce65ae7d5f9/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2", size = 374887, upload-time = "2025-11-30T20:22:41.812Z" }, + { url = "https://files.pythonhosted.org/packages/fd/32/55fb50ae104061dbc564ef15cc43c013dc4a9f4527a1f4d99baddf56fe5f/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8", size = 358904, upload-time = "2025-11-30T20:22:43.479Z" }, + { url = "https://files.pythonhosted.org/packages/58/70/faed8186300e3b9bdd138d0273109784eea2396c68458ed580f885dfe7ad/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4", size = 389945, upload-time = "2025-11-30T20:22:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/bd/a8/073cac3ed2c6387df38f71296d002ab43496a96b92c823e76f46b8af0543/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136", size = 407783, upload-time = "2025-11-30T20:22:46.103Z" }, + { url = "https://files.pythonhosted.org/packages/77/57/5999eb8c58671f1c11eba084115e77a8899d6e694d2a18f69f0ba471ec8b/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7", size = 515021, upload-time = "2025-11-30T20:22:47.458Z" }, + { url = "https://files.pythonhosted.org/packages/e0/af/5ab4833eadc36c0a8ed2bc5c0de0493c04f6c06de223170bd0798ff98ced/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2", size = 414589, upload-time = "2025-11-30T20:22:48.872Z" }, + { url = "https://files.pythonhosted.org/packages/b7/de/f7192e12b21b9e9a68a6d0f249b4af3fdcdff8418be0767a627564afa1f1/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6", size = 394025, upload-time = "2025-11-30T20:22:50.196Z" }, + { url = "https://files.pythonhosted.org/packages/91/c4/fc70cd0249496493500e7cc2de87504f5aa6509de1e88623431fec76d4b6/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e", size = 408895, upload-time = "2025-11-30T20:22:51.87Z" }, + { url = "https://files.pythonhosted.org/packages/58/95/d9275b05ab96556fefff73a385813eb66032e4c99f411d0795372d9abcea/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d", size = 422799, upload-time = "2025-11-30T20:22:53.341Z" }, + { url = "https://files.pythonhosted.org/packages/06/c1/3088fc04b6624eb12a57eb814f0d4997a44b0d208d6cace713033ff1a6ba/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7", size = 572731, upload-time = "2025-11-30T20:22:54.778Z" }, + { url = "https://files.pythonhosted.org/packages/d8/42/c612a833183b39774e8ac8fecae81263a68b9583ee343db33ab571a7ce55/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31", size = 599027, upload-time = "2025-11-30T20:22:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/525a50f45b01d70005403ae0e25f43c0384369ad24ffe46e8d9068b50086/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95", size = 563020, upload-time = "2025-11-30T20:22:58.2Z" }, + { url = "https://files.pythonhosted.org/packages/0b/5d/47c4655e9bcd5ca907148535c10e7d489044243cc9941c16ed7cd53be91d/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d", size = 223139, upload-time = "2025-11-30T20:23:00.209Z" }, + { url = "https://files.pythonhosted.org/packages/f2/e1/485132437d20aa4d3e1d8b3fb5a5e65aa8139f1e097080c2a8443201742c/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15", size = 240224, upload-time = "2025-11-30T20:23:02.008Z" }, + { url = "https://files.pythonhosted.org/packages/24/95/ffd128ed1146a153d928617b0ef673960130be0009c77d8fbf0abe306713/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1", size = 230645, upload-time = "2025-11-30T20:23:03.43Z" }, + { url = "https://files.pythonhosted.org/packages/ff/1b/b10de890a0def2a319a2626334a7f0ae388215eb60914dbac8a3bae54435/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a", size = 364443, upload-time = "2025-11-30T20:23:04.878Z" }, + { url = "https://files.pythonhosted.org/packages/0d/bf/27e39f5971dc4f305a4fb9c672ca06f290f7c4e261c568f3dea16a410d47/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e", size = 353375, upload-time = "2025-11-30T20:23:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/40/58/442ada3bba6e8e6615fc00483135c14a7538d2ffac30e2d933ccf6852232/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000", size = 383850, upload-time = "2025-11-30T20:23:07.825Z" }, + { url = "https://files.pythonhosted.org/packages/14/14/f59b0127409a33c6ef6f5c1ebd5ad8e32d7861c9c7adfa9a624fc3889f6c/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db", size = 392812, upload-time = "2025-11-30T20:23:09.228Z" }, + { url = "https://files.pythonhosted.org/packages/b3/66/e0be3e162ac299b3a22527e8913767d869e6cc75c46bd844aa43fb81ab62/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2", size = 517841, upload-time = "2025-11-30T20:23:11.186Z" }, + { url = "https://files.pythonhosted.org/packages/3d/55/fa3b9cf31d0c963ecf1ba777f7cf4b2a2c976795ac430d24a1f43d25a6ba/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa", size = 408149, upload-time = "2025-11-30T20:23:12.864Z" }, + { url = "https://files.pythonhosted.org/packages/60/ca/780cf3b1a32b18c0f05c441958d3758f02544f1d613abf9488cd78876378/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083", size = 383843, upload-time = "2025-11-30T20:23:14.638Z" }, + { url = "https://files.pythonhosted.org/packages/82/86/d5f2e04f2aa6247c613da0c1dd87fcd08fa17107e858193566048a1e2f0a/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9", size = 396507, upload-time = "2025-11-30T20:23:16.105Z" }, + { url = "https://files.pythonhosted.org/packages/4b/9a/453255d2f769fe44e07ea9785c8347edaf867f7026872e76c1ad9f7bed92/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0", size = 414949, upload-time = "2025-11-30T20:23:17.539Z" }, + { url = "https://files.pythonhosted.org/packages/a3/31/622a86cdc0c45d6df0e9ccb6becdba5074735e7033c20e401a6d9d0e2ca0/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94", size = 565790, upload-time = "2025-11-30T20:23:19.029Z" }, + { url = "https://files.pythonhosted.org/packages/1c/5d/15bbf0fb4a3f58a3b1c67855ec1efcc4ceaef4e86644665fff03e1b66d8d/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08", size = 590217, upload-time = "2025-11-30T20:23:20.885Z" }, + { url = "https://files.pythonhosted.org/packages/6d/61/21b8c41f68e60c8cc3b2e25644f0e3681926020f11d06ab0b78e3c6bbff1/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27", size = 555806, upload-time = "2025-11-30T20:23:22.488Z" }, + { url = "https://files.pythonhosted.org/packages/f9/39/7e067bb06c31de48de3eb200f9fc7c58982a4d3db44b07e73963e10d3be9/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6", size = 211341, upload-time = "2025-11-30T20:23:24.449Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4d/222ef0b46443cf4cf46764d9c630f3fe4abaa7245be9417e56e9f52b8f65/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d", size = 225768, upload-time = "2025-11-30T20:23:25.908Z" }, + { url = "https://files.pythonhosted.org/packages/86/81/dad16382ebbd3d0e0328776d8fd7ca94220e4fa0798d1dc5e7da48cb3201/rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0", size = 362099, upload-time = "2025-11-30T20:23:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/2b/60/19f7884db5d5603edf3c6bce35408f45ad3e97e10007df0e17dd57af18f8/rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be", size = 353192, upload-time = "2025-11-30T20:23:29.151Z" }, + { url = "https://files.pythonhosted.org/packages/bf/c4/76eb0e1e72d1a9c4703c69607cec123c29028bff28ce41588792417098ac/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f", size = 384080, upload-time = "2025-11-30T20:23:30.785Z" }, + { url = "https://files.pythonhosted.org/packages/72/87/87ea665e92f3298d1b26d78814721dc39ed8d2c74b86e83348d6b48a6f31/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f", size = 394841, upload-time = "2025-11-30T20:23:32.209Z" }, + { url = "https://files.pythonhosted.org/packages/77/ad/7783a89ca0587c15dcbf139b4a8364a872a25f861bdb88ed99f9b0dec985/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87", size = 516670, upload-time = "2025-11-30T20:23:33.742Z" }, + { url = "https://files.pythonhosted.org/packages/5b/3c/2882bdac942bd2172f3da574eab16f309ae10a3925644e969536553cb4ee/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18", size = 408005, upload-time = "2025-11-30T20:23:35.253Z" }, + { url = "https://files.pythonhosted.org/packages/ce/81/9a91c0111ce1758c92516a3e44776920b579d9a7c09b2b06b642d4de3f0f/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad", size = 382112, upload-time = "2025-11-30T20:23:36.842Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8e/1da49d4a107027e5fbc64daeab96a0706361a2918da10cb41769244b805d/rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07", size = 399049, upload-time = "2025-11-30T20:23:38.343Z" }, + { url = "https://files.pythonhosted.org/packages/df/5a/7ee239b1aa48a127570ec03becbb29c9d5a9eb092febbd1699d567cae859/rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f", size = 415661, upload-time = "2025-11-30T20:23:40.263Z" }, + { url = "https://files.pythonhosted.org/packages/70/ea/caa143cf6b772f823bc7929a45da1fa83569ee49b11d18d0ada7f5ee6fd6/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65", size = 565606, upload-time = "2025-11-30T20:23:42.186Z" }, + { url = "https://files.pythonhosted.org/packages/64/91/ac20ba2d69303f961ad8cf55bf7dbdb4763f627291ba3d0d7d67333cced9/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f", size = 591126, upload-time = "2025-11-30T20:23:44.086Z" }, + { url = "https://files.pythonhosted.org/packages/21/20/7ff5f3c8b00c8a95f75985128c26ba44503fb35b8e0259d812766ea966c7/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53", size = 553371, upload-time = "2025-11-30T20:23:46.004Z" }, + { url = "https://files.pythonhosted.org/packages/72/c7/81dadd7b27c8ee391c132a6b192111ca58d866577ce2d9b0ca157552cce0/rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed", size = 215298, upload-time = "2025-11-30T20:23:47.696Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d2/1aaac33287e8cfb07aab2e6b8ac1deca62f6f65411344f1433c55e6f3eb8/rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950", size = 228604, upload-time = "2025-11-30T20:23:49.501Z" }, + { url = "https://files.pythonhosted.org/packages/e8/95/ab005315818cc519ad074cb7784dae60d939163108bd2b394e60dc7b5461/rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6", size = 222391, upload-time = "2025-11-30T20:23:50.96Z" }, + { url = "https://files.pythonhosted.org/packages/9e/68/154fe0194d83b973cdedcdcc88947a2752411165930182ae41d983dcefa6/rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb", size = 364868, upload-time = "2025-11-30T20:23:52.494Z" }, + { url = "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8", size = 353747, upload-time = "2025-11-30T20:23:54.036Z" }, + { url = "https://files.pythonhosted.org/packages/ab/00/ba2e50183dbd9abcce9497fa5149c62b4ff3e22d338a30d690f9af970561/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7", size = 383795, upload-time = "2025-11-30T20:23:55.556Z" }, + { url = "https://files.pythonhosted.org/packages/05/6f/86f0272b84926bcb0e4c972262f54223e8ecc556b3224d281e6598fc9268/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898", size = 393330, upload-time = "2025-11-30T20:23:57.033Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e9/0e02bb2e6dc63d212641da45df2b0bf29699d01715913e0d0f017ee29438/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e", size = 518194, upload-time = "2025-11-30T20:23:58.637Z" }, + { url = "https://files.pythonhosted.org/packages/ee/ca/be7bca14cf21513bdf9c0606aba17d1f389ea2b6987035eb4f62bd923f25/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419", size = 408340, upload-time = "2025-11-30T20:24:00.2Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c7/736e00ebf39ed81d75544c0da6ef7b0998f8201b369acf842f9a90dc8fce/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551", size = 383765, upload-time = "2025-11-30T20:24:01.759Z" }, + { url = "https://files.pythonhosted.org/packages/4a/3f/da50dfde9956aaf365c4adc9533b100008ed31aea635f2b8d7b627e25b49/rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8", size = 396834, upload-time = "2025-11-30T20:24:03.687Z" }, + { url = "https://files.pythonhosted.org/packages/4e/00/34bcc2565b6020eab2623349efbdec810676ad571995911f1abdae62a3a0/rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5", size = 415470, upload-time = "2025-11-30T20:24:05.232Z" }, + { url = "https://files.pythonhosted.org/packages/8c/28/882e72b5b3e6f718d5453bd4d0d9cf8df36fddeb4ddbbab17869d5868616/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404", size = 565630, upload-time = "2025-11-30T20:24:06.878Z" }, + { url = "https://files.pythonhosted.org/packages/3b/97/04a65539c17692de5b85c6e293520fd01317fd878ea1995f0367d4532fb1/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856", size = 591148, upload-time = "2025-11-30T20:24:08.445Z" }, + { url = "https://files.pythonhosted.org/packages/85/70/92482ccffb96f5441aab93e26c4d66489eb599efdcf96fad90c14bbfb976/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40", size = 556030, upload-time = "2025-11-30T20:24:10.956Z" }, + { url = "https://files.pythonhosted.org/packages/20/53/7c7e784abfa500a2b6b583b147ee4bb5a2b3747a9166bab52fec4b5b5e7d/rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0", size = 211570, upload-time = "2025-11-30T20:24:12.735Z" }, + { url = "https://files.pythonhosted.org/packages/d0/02/fa464cdfbe6b26e0600b62c528b72d8608f5cc49f96b8d6e38c95d60c676/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3", size = 226532, upload-time = "2025-11-30T20:24:14.634Z" }, +] + +[[package]] +name = "s3transfer" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" }, +] + +[[package]] +name = "safetensors" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878, upload-time = "2025-11-19T15:18:43.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781, upload-time = "2025-11-19T15:18:35.84Z" }, + { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058, upload-time = "2025-11-19T15:18:34.416Z" }, + { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748, upload-time = "2025-11-19T15:18:09.79Z" }, + { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881, upload-time = "2025-11-19T15:18:16.145Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463, upload-time = "2025-11-19T15:18:21.11Z" }, + { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855, upload-time = "2025-11-19T15:18:25.719Z" }, + { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152, upload-time = "2025-11-19T15:18:33.023Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856, upload-time = "2025-11-19T15:18:31.075Z" }, + { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060, upload-time = "2025-11-19T15:18:37.211Z" }, + { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715, upload-time = "2025-11-19T15:18:38.689Z" }, + { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377, upload-time = "2025-11-19T15:18:40.162Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" }, + { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380, upload-time = "2025-11-19T15:18:44.427Z" }, +] + +[[package]] +name = "scikit-learn" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "joblib" }, + { name = "numpy" }, + { name = "scipy" }, + { name = "threadpoolctl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0e/d4/40988bf3b8e34feec1d0e6a051446b1f66225f8529b9309becaeef62b6c4/scikit_learn-1.8.0.tar.gz", hash = "sha256:9bccbb3b40e3de10351f8f5068e105d0f4083b1a65fa07b6634fbc401a6287fd", size = 7335585, upload-time = "2025-12-10T07:08:53.618Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/74/e6a7cc4b820e95cc38cf36cd74d5aa2b42e8ffc2d21fe5a9a9c45c1c7630/scikit_learn-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5fb63362b5a7ddab88e52b6dbb47dac3fd7dafeee740dc6c8d8a446ddedade8e", size = 8548242, upload-time = "2025-12-10T07:07:51.568Z" }, + { url = "https://files.pythonhosted.org/packages/49/d8/9be608c6024d021041c7f0b3928d4749a706f4e2c3832bbede4fb4f58c95/scikit_learn-1.8.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:5025ce924beccb28298246e589c691fe1b8c1c96507e6d27d12c5fadd85bfd76", size = 8079075, upload-time = "2025-12-10T07:07:53.697Z" }, + { url = "https://files.pythonhosted.org/packages/dd/47/f187b4636ff80cc63f21cd40b7b2d177134acaa10f6bb73746130ee8c2e5/scikit_learn-1.8.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4496bb2cf7a43ce1a2d7524a79e40bc5da45cf598dbf9545b7e8316ccba47bb4", size = 8660492, upload-time = "2025-12-10T07:07:55.574Z" }, + { url = "https://files.pythonhosted.org/packages/97/74/b7a304feb2b49df9fafa9382d4d09061a96ee9a9449a7cbea7988dda0828/scikit_learn-1.8.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0bcfe4d0d14aec44921545fd2af2338c7471de9cb701f1da4c9d85906ab847a", size = 8931904, upload-time = "2025-12-10T07:07:57.666Z" }, + { url = "https://files.pythonhosted.org/packages/9f/c4/0ab22726a04ede56f689476b760f98f8f46607caecff993017ac1b64aa5d/scikit_learn-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:35c007dedb2ffe38fe3ee7d201ebac4a2deccd2408e8621d53067733e3c74809", size = 8019359, upload-time = "2025-12-10T07:07:59.838Z" }, + { url = "https://files.pythonhosted.org/packages/24/90/344a67811cfd561d7335c1b96ca21455e7e472d281c3c279c4d3f2300236/scikit_learn-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:8c497fff237d7b4e07e9ef1a640887fa4fb765647f86fbe00f969ff6280ce2bb", size = 7641898, upload-time = "2025-12-10T07:08:01.36Z" }, + { url = "https://files.pythonhosted.org/packages/03/aa/e22e0768512ce9255eba34775be2e85c2048da73da1193e841707f8f039c/scikit_learn-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0d6ae97234d5d7079dc0040990a6f7aeb97cb7fa7e8945f1999a429b23569e0a", size = 8513770, upload-time = "2025-12-10T07:08:03.251Z" }, + { url = "https://files.pythonhosted.org/packages/58/37/31b83b2594105f61a381fc74ca19e8780ee923be2d496fcd8d2e1147bd99/scikit_learn-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:edec98c5e7c128328124a029bceb09eda2d526997780fef8d65e9a69eead963e", size = 8044458, upload-time = "2025-12-10T07:08:05.336Z" }, + { url = "https://files.pythonhosted.org/packages/2d/5a/3f1caed8765f33eabb723596666da4ebbf43d11e96550fb18bdec42b467b/scikit_learn-1.8.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:74b66d8689d52ed04c271e1329f0c61635bcaf5b926db9b12d58914cdc01fe57", size = 8610341, upload-time = "2025-12-10T07:08:07.732Z" }, + { url = "https://files.pythonhosted.org/packages/38/cf/06896db3f71c75902a8e9943b444a56e727418f6b4b4a90c98c934f51ed4/scikit_learn-1.8.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8fdf95767f989b0cfedb85f7ed8ca215d4be728031f56ff5a519ee1e3276dc2e", size = 8900022, upload-time = "2025-12-10T07:08:09.862Z" }, + { url = "https://files.pythonhosted.org/packages/1c/f9/9b7563caf3ec8873e17a31401858efab6b39a882daf6c1bfa88879c0aa11/scikit_learn-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:2de443b9373b3b615aec1bb57f9baa6bb3a9bd093f1269ba95c17d870422b271", size = 7989409, upload-time = "2025-12-10T07:08:12.028Z" }, + { url = "https://files.pythonhosted.org/packages/49/bd/1f4001503650e72c4f6009ac0c4413cb17d2d601cef6f71c0453da2732fc/scikit_learn-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:eddde82a035681427cbedded4e6eff5e57fa59216c2e3e90b10b19ab1d0a65c3", size = 7619760, upload-time = "2025-12-10T07:08:13.688Z" }, + { url = "https://files.pythonhosted.org/packages/d2/7d/a630359fc9dcc95496588c8d8e3245cc8fd81980251079bc09c70d41d951/scikit_learn-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7cc267b6108f0a1499a734167282c00c4ebf61328566b55ef262d48e9849c735", size = 8826045, upload-time = "2025-12-10T07:08:15.215Z" }, + { url = "https://files.pythonhosted.org/packages/cc/56/a0c86f6930cfcd1c7054a2bc417e26960bb88d32444fe7f71d5c2cfae891/scikit_learn-1.8.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:fe1c011a640a9f0791146011dfd3c7d9669785f9fed2b2a5f9e207536cf5c2fd", size = 8420324, upload-time = "2025-12-10T07:08:17.561Z" }, + { url = "https://files.pythonhosted.org/packages/46/1e/05962ea1cebc1cf3876667ecb14c283ef755bf409993c5946ade3b77e303/scikit_learn-1.8.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72358cce49465d140cc4e7792015bb1f0296a9742d5622c67e31399b75468b9e", size = 8680651, upload-time = "2025-12-10T07:08:19.952Z" }, + { url = "https://files.pythonhosted.org/packages/fe/56/a85473cd75f200c9759e3a5f0bcab2d116c92a8a02ee08ccd73b870f8bb4/scikit_learn-1.8.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:80832434a6cc114f5219211eec13dcbc16c2bac0e31ef64c6d346cde3cf054cb", size = 8925045, upload-time = "2025-12-10T07:08:22.11Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b7/64d8cfa896c64435ae57f4917a548d7ac7a44762ff9802f75a79b77cb633/scikit_learn-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ee787491dbfe082d9c3013f01f5991658b0f38aa8177e4cd4bf434c58f551702", size = 8507994, upload-time = "2025-12-10T07:08:23.943Z" }, + { url = "https://files.pythonhosted.org/packages/5e/37/e192ea709551799379958b4c4771ec507347027bb7c942662c7fbeba31cb/scikit_learn-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf97c10a3f5a7543f9b88cbf488d33d175e9146115a451ae34568597ba33dcde", size = 7869518, upload-time = "2025-12-10T07:08:25.71Z" }, + { url = "https://files.pythonhosted.org/packages/24/05/1af2c186174cc92dcab2233f327336058c077d38f6fe2aceb08e6ab4d509/scikit_learn-1.8.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c22a2da7a198c28dd1a6e1136f19c830beab7fdca5b3e5c8bba8394f8a5c45b3", size = 8528667, upload-time = "2025-12-10T07:08:27.541Z" }, + { url = "https://files.pythonhosted.org/packages/a8/25/01c0af38fe969473fb292bba9dc2b8f9b451f3112ff242c647fee3d0dfe7/scikit_learn-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:6b595b07a03069a2b1740dc08c2299993850ea81cce4fe19b2421e0c970de6b7", size = 8066524, upload-time = "2025-12-10T07:08:29.822Z" }, + { url = "https://files.pythonhosted.org/packages/be/ce/a0623350aa0b68647333940ee46fe45086c6060ec604874e38e9ab7d8e6c/scikit_learn-1.8.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:29ffc74089f3d5e87dfca4c2c8450f88bdc61b0fc6ed5d267f3988f19a1309f6", size = 8657133, upload-time = "2025-12-10T07:08:31.865Z" }, + { url = "https://files.pythonhosted.org/packages/b8/cb/861b41341d6f1245e6ca80b1c1a8c4dfce43255b03df034429089ca2a2c5/scikit_learn-1.8.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb65db5d7531bccf3a4f6bec3462223bea71384e2cda41da0f10b7c292b9e7c4", size = 8923223, upload-time = "2025-12-10T07:08:34.166Z" }, + { url = "https://files.pythonhosted.org/packages/76/18/a8def8f91b18cd1ba6e05dbe02540168cb24d47e8dcf69e8d00b7da42a08/scikit_learn-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:56079a99c20d230e873ea40753102102734c5953366972a71d5cb39a32bc40c6", size = 8096518, upload-time = "2025-12-10T07:08:36.339Z" }, + { url = "https://files.pythonhosted.org/packages/d1/77/482076a678458307f0deb44e29891d6022617b2a64c840c725495bee343f/scikit_learn-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:3bad7565bc9cf37ce19a7c0d107742b320c1285df7aab1a6e2d28780df167242", size = 7754546, upload-time = "2025-12-10T07:08:38.128Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d1/ef294ca754826daa043b2a104e59960abfab4cf653891037d19dd5b6f3cf/scikit_learn-1.8.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:4511be56637e46c25721e83d1a9cea9614e7badc7040c4d573d75fbe257d6fd7", size = 8848305, upload-time = "2025-12-10T07:08:41.013Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e2/b1f8b05138ee813b8e1a4149f2f0d289547e60851fd1bb268886915adbda/scikit_learn-1.8.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:a69525355a641bf8ef136a7fa447672fb54fe8d60cab5538d9eb7c6438543fb9", size = 8432257, upload-time = "2025-12-10T07:08:42.873Z" }, + { url = "https://files.pythonhosted.org/packages/26/11/c32b2138a85dcb0c99f6afd13a70a951bfdff8a6ab42d8160522542fb647/scikit_learn-1.8.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2656924ec73e5939c76ac4c8b026fc203b83d8900362eb2599d8aee80e4880f", size = 8678673, upload-time = "2025-12-10T07:08:45.362Z" }, + { url = "https://files.pythonhosted.org/packages/c7/57/51f2384575bdec454f4fe4e7a919d696c9ebce914590abf3e52d47607ab8/scikit_learn-1.8.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15fc3b5d19cc2be65404786857f2e13c70c83dd4782676dd6814e3b89dc8f5b9", size = 8922467, upload-time = "2025-12-10T07:08:47.408Z" }, + { url = "https://files.pythonhosted.org/packages/35/4d/748c9e2872637a57981a04adc038dacaa16ba8ca887b23e34953f0b3f742/scikit_learn-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:00d6f1d66fbcf4eba6e356e1420d33cc06c70a45bb1363cd6f6a8e4ebbbdece2", size = 8774395, upload-time = "2025-12-10T07:08:49.337Z" }, + { url = "https://files.pythonhosted.org/packages/60/22/d7b2ebe4704a5e50790ba089d5c2ae308ab6bb852719e6c3bd4f04c3a363/scikit_learn-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f28dd15c6bb0b66ba09728cf09fd8736c304be29409bd8445a080c1280619e8c", size = 8002647, upload-time = "2025-12-10T07:08:51.601Z" }, +] + +[[package]] +name = "scipy" +version = "1.16.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/41/5bf55c3f386b1643812f3a5674edf74b26184378ef0f3e7c7a09a7e2ca7f/scipy-1.16.3-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:81fc5827606858cf71446a5e98715ba0e11f0dbc83d71c7409d05486592a45d6", size = 36659043, upload-time = "2025-10-28T17:32:40.285Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0f/65582071948cfc45d43e9870bf7ca5f0e0684e165d7c9ef4e50d783073eb/scipy-1.16.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:c97176013d404c7346bf57874eaac5187d969293bf40497140b0a2b2b7482e07", size = 28898986, upload-time = "2025-10-28T17:32:45.325Z" }, + { url = "https://files.pythonhosted.org/packages/96/5e/36bf3f0ac298187d1ceadde9051177d6a4fe4d507e8f59067dc9dd39e650/scipy-1.16.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2b71d93c8a9936046866acebc915e2af2e292b883ed6e2cbe5c34beb094b82d9", size = 20889814, upload-time = "2025-10-28T17:32:49.277Z" }, + { url = "https://files.pythonhosted.org/packages/80/35/178d9d0c35394d5d5211bbff7ac4f2986c5488b59506fef9e1de13ea28d3/scipy-1.16.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3d4a07a8e785d80289dfe66b7c27d8634a773020742ec7187b85ccc4b0e7b686", size = 23565795, upload-time = "2025-10-28T17:32:53.337Z" }, + { url = "https://files.pythonhosted.org/packages/fa/46/d1146ff536d034d02f83c8afc3c4bab2eddb634624d6529a8512f3afc9da/scipy-1.16.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0553371015692a898e1aa858fed67a3576c34edefa6b7ebdb4e9dde49ce5c203", size = 33349476, upload-time = "2025-10-28T17:32:58.353Z" }, + { url = "https://files.pythonhosted.org/packages/79/2e/415119c9ab3e62249e18c2b082c07aff907a273741b3f8160414b0e9193c/scipy-1.16.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:72d1717fd3b5e6ec747327ce9bda32d5463f472c9dce9f54499e81fbd50245a1", size = 35676692, upload-time = "2025-10-28T17:33:03.88Z" }, + { url = "https://files.pythonhosted.org/packages/27/82/df26e44da78bf8d2aeaf7566082260cfa15955a5a6e96e6a29935b64132f/scipy-1.16.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fb2472e72e24d1530debe6ae078db70fb1605350c88a3d14bc401d6306dbffe", size = 36019345, upload-time = "2025-10-28T17:33:09.773Z" }, + { url = "https://files.pythonhosted.org/packages/82/31/006cbb4b648ba379a95c87262c2855cd0d09453e500937f78b30f02fa1cd/scipy-1.16.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c5192722cffe15f9329a3948c4b1db789fbb1f05c97899187dcf009b283aea70", size = 38678975, upload-time = "2025-10-28T17:33:15.809Z" }, + { url = "https://files.pythonhosted.org/packages/c2/7f/acbd28c97e990b421af7d6d6cd416358c9c293fc958b8529e0bd5d2a2a19/scipy-1.16.3-cp312-cp312-win_amd64.whl", hash = "sha256:56edc65510d1331dae01ef9b658d428e33ed48b4f77b1d51caf479a0253f96dc", size = 38555926, upload-time = "2025-10-28T17:33:21.388Z" }, + { url = "https://files.pythonhosted.org/packages/ce/69/c5c7807fd007dad4f48e0a5f2153038dc96e8725d3345b9ee31b2b7bed46/scipy-1.16.3-cp312-cp312-win_arm64.whl", hash = "sha256:a8a26c78ef223d3e30920ef759e25625a0ecdd0d60e5a8818b7513c3e5384cf2", size = 25463014, upload-time = "2025-10-28T17:33:25.975Z" }, + { url = "https://files.pythonhosted.org/packages/72/f1/57e8327ab1508272029e27eeef34f2302ffc156b69e7e233e906c2a5c379/scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c", size = 36617856, upload-time = "2025-10-28T17:33:31.375Z" }, + { url = "https://files.pythonhosted.org/packages/44/13/7e63cfba8a7452eb756306aa2fd9b37a29a323b672b964b4fdeded9a3f21/scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d", size = 28874306, upload-time = "2025-10-28T17:33:36.516Z" }, + { url = "https://files.pythonhosted.org/packages/15/65/3a9400efd0228a176e6ec3454b1fa998fbbb5a8defa1672c3f65706987db/scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9", size = 20865371, upload-time = "2025-10-28T17:33:42.094Z" }, + { url = "https://files.pythonhosted.org/packages/33/d7/eda09adf009a9fb81827194d4dd02d2e4bc752cef16737cc4ef065234031/scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4", size = 23524877, upload-time = "2025-10-28T17:33:48.483Z" }, + { url = "https://files.pythonhosted.org/packages/7d/6b/3f911e1ebc364cb81320223a3422aab7d26c9c7973109a9cd0f27c64c6c0/scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959", size = 33342103, upload-time = "2025-10-28T17:33:56.495Z" }, + { url = "https://files.pythonhosted.org/packages/21/f6/4bfb5695d8941e5c570a04d9fcd0d36bce7511b7d78e6e75c8f9791f82d0/scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88", size = 35697297, upload-time = "2025-10-28T17:34:04.722Z" }, + { url = "https://files.pythonhosted.org/packages/04/e1/6496dadbc80d8d896ff72511ecfe2316b50313bfc3ebf07a3f580f08bd8c/scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234", size = 36021756, upload-time = "2025-10-28T17:34:13.482Z" }, + { url = "https://files.pythonhosted.org/packages/fe/bd/a8c7799e0136b987bda3e1b23d155bcb31aec68a4a472554df5f0937eef7/scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d", size = 38696566, upload-time = "2025-10-28T17:34:22.384Z" }, + { url = "https://files.pythonhosted.org/packages/cd/01/1204382461fcbfeb05b6161b594f4007e78b6eba9b375382f79153172b4d/scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304", size = 38529877, upload-time = "2025-10-28T17:35:51.076Z" }, + { url = "https://files.pythonhosted.org/packages/7f/14/9d9fbcaa1260a94f4bb5b64ba9213ceb5d03cd88841fe9fd1ffd47a45b73/scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2", size = 25455366, upload-time = "2025-10-28T17:35:59.014Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a3/9ec205bd49f42d45d77f1730dbad9ccf146244c1647605cf834b3a8c4f36/scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b", size = 37027931, upload-time = "2025-10-28T17:34:31.451Z" }, + { url = "https://files.pythonhosted.org/packages/25/06/ca9fd1f3a4589cbd825b1447e5db3a8ebb969c1eaf22c8579bd286f51b6d/scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079", size = 29400081, upload-time = "2025-10-28T17:34:39.087Z" }, + { url = "https://files.pythonhosted.org/packages/6a/56/933e68210d92657d93fb0e381683bc0e53a965048d7358ff5fbf9e6a1b17/scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a", size = 21391244, upload-time = "2025-10-28T17:34:45.234Z" }, + { url = "https://files.pythonhosted.org/packages/a8/7e/779845db03dc1418e215726329674b40576879b91814568757ff0014ad65/scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119", size = 23929753, upload-time = "2025-10-28T17:34:51.793Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4b/f756cf8161d5365dcdef9e5f460ab226c068211030a175d2fc7f3f41ca64/scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c", size = 33496912, upload-time = "2025-10-28T17:34:59.8Z" }, + { url = "https://files.pythonhosted.org/packages/09/b5/222b1e49a58668f23839ca1542a6322bb095ab8d6590d4f71723869a6c2c/scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e", size = 35802371, upload-time = "2025-10-28T17:35:08.173Z" }, + { url = "https://files.pythonhosted.org/packages/c1/8d/5964ef68bb31829bde27611f8c9deeac13764589fe74a75390242b64ca44/scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135", size = 36190477, upload-time = "2025-10-28T17:35:16.7Z" }, + { url = "https://files.pythonhosted.org/packages/ab/f2/b31d75cb9b5fa4dd39a0a931ee9b33e7f6f36f23be5ef560bf72e0f92f32/scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6", size = 38796678, upload-time = "2025-10-28T17:35:26.354Z" }, + { url = "https://files.pythonhosted.org/packages/b4/1e/b3723d8ff64ab548c38d87055483714fefe6ee20e0189b62352b5e015bb1/scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc", size = 38640178, upload-time = "2025-10-28T17:35:35.304Z" }, + { url = "https://files.pythonhosted.org/packages/8e/f3/d854ff38789aca9b0cc23008d607ced9de4f7ab14fa1ca4329f86b3758ca/scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a", size = 25803246, upload-time = "2025-10-28T17:35:42.155Z" }, + { url = "https://files.pythonhosted.org/packages/99/f6/99b10fd70f2d864c1e29a28bbcaa0c6340f9d8518396542d9ea3b4aaae15/scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6", size = 36606469, upload-time = "2025-10-28T17:36:08.741Z" }, + { url = "https://files.pythonhosted.org/packages/4d/74/043b54f2319f48ea940dd025779fa28ee360e6b95acb7cd188fad4391c6b/scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657", size = 28872043, upload-time = "2025-10-28T17:36:16.599Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e1/24b7e50cc1c4ee6ffbcb1f27fe9f4c8b40e7911675f6d2d20955f41c6348/scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26", size = 20862952, upload-time = "2025-10-28T17:36:22.966Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3a/3e8c01a4d742b730df368e063787c6808597ccb38636ed821d10b39ca51b/scipy-1.16.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7f68154688c515cdb541a31ef8eb66d8cd1050605be9dcd74199cbd22ac739bc", size = 23508512, upload-time = "2025-10-28T17:36:29.731Z" }, + { url = "https://files.pythonhosted.org/packages/1f/60/c45a12b98ad591536bfe5330cb3cfe1850d7570259303563b1721564d458/scipy-1.16.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3c820ddb80029fe9f43d61b81d8b488d3ef8ca010d15122b152db77dc94c22", size = 33413639, upload-time = "2025-10-28T17:36:37.982Z" }, + { url = "https://files.pythonhosted.org/packages/71/bc/35957d88645476307e4839712642896689df442f3e53b0fa016ecf8a3357/scipy-1.16.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3837938ae715fc0fe3c39c0202de3a8853aff22ca66781ddc2ade7554b7e2cc", size = 35704729, upload-time = "2025-10-28T17:36:46.547Z" }, + { url = "https://files.pythonhosted.org/packages/3b/15/89105e659041b1ca11c386e9995aefacd513a78493656e57789f9d9eab61/scipy-1.16.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aadd23f98f9cb069b3bd64ddc900c4d277778242e961751f77a8cb5c4b946fb0", size = 36086251, upload-time = "2025-10-28T17:36:55.161Z" }, + { url = "https://files.pythonhosted.org/packages/1a/87/c0ea673ac9c6cc50b3da2196d860273bc7389aa69b64efa8493bdd25b093/scipy-1.16.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b7c5f1bda1354d6a19bc6af73a649f8285ca63ac6b52e64e658a5a11d4d69800", size = 38716681, upload-time = "2025-10-28T17:37:04.1Z" }, + { url = "https://files.pythonhosted.org/packages/91/06/837893227b043fb9b0d13e4bd7586982d8136cb249ffb3492930dab905b8/scipy-1.16.3-cp314-cp314-win_amd64.whl", hash = "sha256:e5d42a9472e7579e473879a1990327830493a7047506d58d73fc429b84c1d49d", size = 39358423, upload-time = "2025-10-28T17:38:20.005Z" }, + { url = "https://files.pythonhosted.org/packages/95/03/28bce0355e4d34a7c034727505a02d19548549e190bedd13a721e35380b7/scipy-1.16.3-cp314-cp314-win_arm64.whl", hash = "sha256:6020470b9d00245926f2d5bb93b119ca0340f0d564eb6fbaad843eaebf9d690f", size = 26135027, upload-time = "2025-10-28T17:38:24.966Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6f/69f1e2b682efe9de8fe9f91040f0cd32f13cfccba690512ba4c582b0bc29/scipy-1.16.3-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:e1d27cbcb4602680a49d787d90664fa4974063ac9d4134813332a8c53dbe667c", size = 37028379, upload-time = "2025-10-28T17:37:14.061Z" }, + { url = "https://files.pythonhosted.org/packages/7c/2d/e826f31624a5ebbab1cd93d30fd74349914753076ed0593e1d56a98c4fb4/scipy-1.16.3-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9b9c9c07b6d56a35777a1b4cc8966118fb16cfd8daf6743867d17d36cfad2d40", size = 29400052, upload-time = "2025-10-28T17:37:21.709Z" }, + { url = "https://files.pythonhosted.org/packages/69/27/d24feb80155f41fd1f156bf144e7e049b4e2b9dd06261a242905e3bc7a03/scipy-1.16.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:3a4c460301fb2cffb7f88528f30b3127742cff583603aa7dc964a52c463b385d", size = 21391183, upload-time = "2025-10-28T17:37:29.559Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d3/1b229e433074c5738a24277eca520a2319aac7465eea7310ea6ae0e98ae2/scipy-1.16.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f667a4542cc8917af1db06366d3f78a5c8e83badd56409f94d1eac8d8d9133fa", size = 23930174, upload-time = "2025-10-28T17:37:36.306Z" }, + { url = "https://files.pythonhosted.org/packages/16/9d/d9e148b0ec680c0f042581a2be79a28a7ab66c0c4946697f9e7553ead337/scipy-1.16.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f379b54b77a597aa7ee5e697df0d66903e41b9c85a6dd7946159e356319158e8", size = 33497852, upload-time = "2025-10-28T17:37:42.228Z" }, + { url = "https://files.pythonhosted.org/packages/2f/22/4e5f7561e4f98b7bea63cf3fd7934bff1e3182e9f1626b089a679914d5c8/scipy-1.16.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4aff59800a3b7f786b70bfd6ab551001cb553244988d7d6b8299cb1ea653b353", size = 35798595, upload-time = "2025-10-28T17:37:48.102Z" }, + { url = "https://files.pythonhosted.org/packages/83/42/6644d714c179429fc7196857866f219fef25238319b650bb32dde7bf7a48/scipy-1.16.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:da7763f55885045036fabcebd80144b757d3db06ab0861415d1c3b7c69042146", size = 36186269, upload-time = "2025-10-28T17:37:53.72Z" }, + { url = "https://files.pythonhosted.org/packages/ac/70/64b4d7ca92f9cf2e6fc6aaa2eecf80bb9b6b985043a9583f32f8177ea122/scipy-1.16.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa6eea95283b2b8079b821dc11f50a17d0571c92b43e2b5b12764dc5f9b285d", size = 38802779, upload-time = "2025-10-28T17:37:59.393Z" }, + { url = "https://files.pythonhosted.org/packages/61/82/8d0e39f62764cce5ffd5284131e109f07cf8955aef9ab8ed4e3aa5e30539/scipy-1.16.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d9f48cafc7ce94cf9b15c6bffdc443a81a27bf7075cf2dcd5c8b40f85d10c4e7", size = 39471128, upload-time = "2025-10-28T17:38:05.259Z" }, + { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127, upload-time = "2025-10-28T17:38:11.34Z" }, +] + +[[package]] +name = "send2trash" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/62/6e/421803dec0c0dfbf5a27e66491ebe6643a461e4f90422f00ea4c68ae24aa/send2trash-2.0.0.tar.gz", hash = "sha256:1761421da3f9930bfe51ed7c45343948573383ad4c27e3acebc91be324e7770d", size = 17206, upload-time = "2025-12-31T04:12:48.664Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/5a/f2f2e5eda25579f754acd83399c522ee03d6acbe001dfe53c8a1ec928b44/send2trash-2.0.0-py3-none-any.whl", hash = "sha256:e70d5ce41dbb890882cc78bc25d137478330b39a391e756fadf82e34da4d85b8", size = 17642, upload-time = "2025-12-31T04:12:45.336Z" }, +] + +[[package]] +name = "sentence-transformers" +version = "5.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "torch" }, + { name = "tqdm" }, + { name = "transformers" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/a1/64e7b111e753307ffb7c5b6d039c52d4a91a47fa32a7f5bc377a49b22402/sentence_transformers-5.2.0.tar.gz", hash = "sha256:acaeb38717de689f3dab45d5e5a02ebe2f75960a4764ea35fea65f58a4d3019f", size = 381004, upload-time = "2025-12-11T14:12:31.038Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/d0/3b2897ef6a0c0c801e9fecca26bcc77081648e38e8c772885ebdd8d7d252/sentence_transformers-5.2.0-py3-none-any.whl", hash = "sha256:aa57180f053687d29b08206766ae7db549be5074f61849def7b17bf0b8025ca2", size = 493748, upload-time = "2025-12-11T14:12:29.516Z" }, +] + +[[package]] +name = "setuptools" +version = "80.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/89/23/adf3796d740536d63a6fbda113d07e60c734b6ed5d3058d1e47fc0495e47/soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350", size = 117856, upload-time = "2025-12-18T13:50:34.655Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/f3/b67d6ea49ca9154453b6d70b34ea22f3996b9fa55da105a79d8732227adc/soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434", size = 36710, upload-time = "2025-12-18T13:50:33.267Z" }, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.45" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/f9/5e4491e5ccf42f5d9cfc663741d261b3e6e1683ae7812114e7636409fcc6/sqlalchemy-2.0.45.tar.gz", hash = "sha256:1632a4bda8d2d25703fdad6363058d882541bdaaee0e5e3ddfa0cd3229efce88", size = 9869912, upload-time = "2025-12-09T21:05:16.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/c7/1900b56ce19bff1c26f39a4ce427faec7716c81ac792bfac8b6a9f3dca93/sqlalchemy-2.0.45-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3ee2aac15169fb0d45822983631466d60b762085bc4535cd39e66bea362df5f", size = 3333760, upload-time = "2025-12-09T22:11:02.66Z" }, + { url = "https://files.pythonhosted.org/packages/0a/93/3be94d96bb442d0d9a60e55a6bb6e0958dd3457751c6f8502e56ef95fed0/sqlalchemy-2.0.45-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba547ac0b361ab4f1608afbc8432db669bd0819b3e12e29fb5fa9529a8bba81d", size = 3348268, upload-time = "2025-12-09T22:13:49.054Z" }, + { url = "https://files.pythonhosted.org/packages/48/4b/f88ded696e61513595e4a9778f9d3f2bf7332cce4eb0c7cedaabddd6687b/sqlalchemy-2.0.45-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:215f0528b914e5c75ef2559f69dca86878a3beeb0c1be7279d77f18e8d180ed4", size = 3278144, upload-time = "2025-12-09T22:11:04.14Z" }, + { url = "https://files.pythonhosted.org/packages/ed/6a/310ecb5657221f3e1bd5288ed83aa554923fb5da48d760a9f7622afeb065/sqlalchemy-2.0.45-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:107029bf4f43d076d4011f1afb74f7c3e2ea029ec82eb23d8527d5e909e97aa6", size = 3313907, upload-time = "2025-12-09T22:13:50.598Z" }, + { url = "https://files.pythonhosted.org/packages/5c/39/69c0b4051079addd57c84a5bfb34920d87456dd4c90cf7ee0df6efafc8ff/sqlalchemy-2.0.45-cp312-cp312-win32.whl", hash = "sha256:0c9f6ada57b58420a2c0277ff853abe40b9e9449f8d7d231763c6bc30f5c4953", size = 2112182, upload-time = "2025-12-09T21:39:30.824Z" }, + { url = "https://files.pythonhosted.org/packages/f7/4e/510db49dd89fc3a6e994bee51848c94c48c4a00dc905e8d0133c251f41a7/sqlalchemy-2.0.45-cp312-cp312-win_amd64.whl", hash = "sha256:8defe5737c6d2179c7997242d6473587c3beb52e557f5ef0187277009f73e5e1", size = 2139200, upload-time = "2025-12-09T21:39:32.321Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c8/7cc5221b47a54edc72a0140a1efa56e0a2730eefa4058d7ed0b4c4357ff8/sqlalchemy-2.0.45-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe187fc31a54d7fd90352f34e8c008cf3ad5d064d08fedd3de2e8df83eb4a1cf", size = 3277082, upload-time = "2025-12-09T22:11:06.167Z" }, + { url = "https://files.pythonhosted.org/packages/0e/50/80a8d080ac7d3d321e5e5d420c9a522b0aa770ec7013ea91f9a8b7d36e4a/sqlalchemy-2.0.45-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:672c45cae53ba88e0dad74b9027dddd09ef6f441e927786b05bec75d949fbb2e", size = 3293131, upload-time = "2025-12-09T22:13:52.626Z" }, + { url = "https://files.pythonhosted.org/packages/da/4c/13dab31266fc9904f7609a5dc308a2432a066141d65b857760c3bef97e69/sqlalchemy-2.0.45-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:470daea2c1ce73910f08caf10575676a37159a6d16c4da33d0033546bddebc9b", size = 3225389, upload-time = "2025-12-09T22:11:08.093Z" }, + { url = "https://files.pythonhosted.org/packages/74/04/891b5c2e9f83589de202e7abaf24cd4e4fa59e1837d64d528829ad6cc107/sqlalchemy-2.0.45-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9c6378449e0940476577047150fd09e242529b761dc887c9808a9a937fe990c8", size = 3266054, upload-time = "2025-12-09T22:13:54.262Z" }, + { url = "https://files.pythonhosted.org/packages/f1/24/fc59e7f71b0948cdd4cff7a286210e86b0443ef1d18a23b0d83b87e4b1f7/sqlalchemy-2.0.45-cp313-cp313-win32.whl", hash = "sha256:4b6bec67ca45bc166c8729910bd2a87f1c0407ee955df110d78948f5b5827e8a", size = 2110299, upload-time = "2025-12-09T21:39:33.486Z" }, + { url = "https://files.pythonhosted.org/packages/c0/c5/d17113020b2d43073412aeca09b60d2009442420372123b8d49cc253f8b8/sqlalchemy-2.0.45-cp313-cp313-win_amd64.whl", hash = "sha256:afbf47dc4de31fa38fd491f3705cac5307d21d4bb828a4f020ee59af412744ee", size = 2136264, upload-time = "2025-12-09T21:39:36.801Z" }, + { url = "https://files.pythonhosted.org/packages/3d/8d/bb40a5d10e7a5f2195f235c0b2f2c79b0bf6e8f00c0c223130a4fbd2db09/sqlalchemy-2.0.45-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:83d7009f40ce619d483d26ac1b757dfe3167b39921379a8bd1b596cf02dab4a6", size = 3521998, upload-time = "2025-12-09T22:13:28.622Z" }, + { url = "https://files.pythonhosted.org/packages/75/a5/346128b0464886f036c039ea287b7332a410aa2d3fb0bb5d404cb8861635/sqlalchemy-2.0.45-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d8a2ca754e5415cde2b656c27900b19d50ba076aa05ce66e2207623d3fe41f5a", size = 3473434, upload-time = "2025-12-09T22:13:30.188Z" }, + { url = "https://files.pythonhosted.org/packages/cc/64/4e1913772646b060b025d3fc52ce91a58967fe58957df32b455de5a12b4f/sqlalchemy-2.0.45-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f46ec744e7f51275582e6a24326e10c49fbdd3fc99103e01376841213028774", size = 3272404, upload-time = "2025-12-09T22:11:09.662Z" }, + { url = "https://files.pythonhosted.org/packages/b3/27/caf606ee924282fe4747ee4fd454b335a72a6e018f97eab5ff7f28199e16/sqlalchemy-2.0.45-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:883c600c345123c033c2f6caca18def08f1f7f4c3ebeb591a63b6fceffc95cce", size = 3277057, upload-time = "2025-12-09T22:13:56.213Z" }, + { url = "https://files.pythonhosted.org/packages/85/d0/3d64218c9724e91f3d1574d12eb7ff8f19f937643815d8daf792046d88ab/sqlalchemy-2.0.45-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2c0b74aa79e2deade948fe8593654c8ef4228c44ba862bb7c9585c8e0db90f33", size = 3222279, upload-time = "2025-12-09T22:11:11.1Z" }, + { url = "https://files.pythonhosted.org/packages/24/10/dd7688a81c5bc7690c2a3764d55a238c524cd1a5a19487928844cb247695/sqlalchemy-2.0.45-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8a420169cef179d4c9064365f42d779f1e5895ad26ca0c8b4c0233920973db74", size = 3244508, upload-time = "2025-12-09T22:13:57.932Z" }, + { url = "https://files.pythonhosted.org/packages/aa/41/db75756ca49f777e029968d9c9fee338c7907c563267740c6d310a8e3f60/sqlalchemy-2.0.45-cp314-cp314-win32.whl", hash = "sha256:e50dcb81a5dfe4b7b4a4aa8f338116d127cb209559124f3694c70d6cd072b68f", size = 2113204, upload-time = "2025-12-09T21:39:38.365Z" }, + { url = "https://files.pythonhosted.org/packages/89/a2/0e1590e9adb292b1d576dbcf67ff7df8cf55e56e78d2c927686d01080f4b/sqlalchemy-2.0.45-cp314-cp314-win_amd64.whl", hash = "sha256:4748601c8ea959e37e03d13dcda4a44837afcd1b21338e637f7c935b8da06177", size = 2138785, upload-time = "2025-12-09T21:39:39.503Z" }, + { url = "https://files.pythonhosted.org/packages/42/39/f05f0ed54d451156bbed0e23eb0516bcad7cbb9f18b3bf219c786371b3f0/sqlalchemy-2.0.45-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd337d3526ec5298f67d6a30bbbe4ed7e5e68862f0bf6dd21d289f8d37b7d60b", size = 3522029, upload-time = "2025-12-09T22:13:32.09Z" }, + { url = "https://files.pythonhosted.org/packages/54/0f/d15398b98b65c2bce288d5ee3f7d0a81f77ab89d9456994d5c7cc8b2a9db/sqlalchemy-2.0.45-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9a62b446b7d86a3909abbcd1cd3cc550a832f99c2bc37c5b22e1925438b9367b", size = 3475142, upload-time = "2025-12-09T22:13:33.739Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e1/3ccb13c643399d22289c6a9786c1a91e3dcbb68bce4beb44926ac2c557bf/sqlalchemy-2.0.45-py3-none-any.whl", hash = "sha256:5225a288e4c8cc2308dbdd874edad6e7d0fd38eac1e9e5f23503425c8eee20d0", size = 1936672, upload-time = "2025-12-09T21:54:52.608Z" }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, +] + +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, +] + +[[package]] +name = "tenacity" +version = "9.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, +] + +[[package]] +name = "terminado" +version = "0.18.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess", marker = "os_name != 'nt'" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, +] + +[[package]] +name = "threadpoolctl" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, +] + +[[package]] +name = "tinycss2" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, +] + +[[package]] +name = "tokenizers" +version = "0.22.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, +] + +[[package]] +name = "torch" +version = "2.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "setuptools" }, + { name = "sympy" }, + { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/27/07c645c7673e73e53ded71705045d6cb5bae94c4b021b03aa8d03eee90ab/torch-2.9.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:da5f6f4d7f4940a173e5572791af238cb0b9e21b1aab592bd8b26da4c99f1cd6", size = 104126592, upload-time = "2025-11-12T15:20:41.62Z" }, + { url = "https://files.pythonhosted.org/packages/19/17/e377a460603132b00760511299fceba4102bd95db1a0ee788da21298ccff/torch-2.9.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:27331cd902fb4322252657f3902adf1c4f6acad9dcad81d8df3ae14c7c4f07c4", size = 899742281, upload-time = "2025-11-12T15:22:17.602Z" }, + { url = "https://files.pythonhosted.org/packages/b1/1a/64f5769025db846a82567fa5b7d21dba4558a7234ee631712ee4771c436c/torch-2.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:81a285002d7b8cfd3fdf1b98aa8df138d41f1a8334fd9ea37511517cedf43083", size = 110940568, upload-time = "2025-11-12T15:21:18.689Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ab/07739fd776618e5882661d04c43f5b5586323e2f6a2d7d84aac20d8f20bd/torch-2.9.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:c0d25d1d8e531b8343bea0ed811d5d528958f1dcbd37e7245bc686273177ad7e", size = 74479191, upload-time = "2025-11-12T15:21:25.816Z" }, + { url = "https://files.pythonhosted.org/packages/20/60/8fc5e828d050bddfab469b3fe78e5ab9a7e53dda9c3bdc6a43d17ce99e63/torch-2.9.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c29455d2b910b98738131990394da3e50eea8291dfeb4b12de71ecf1fdeb21cb", size = 104135743, upload-time = "2025-11-12T15:21:34.936Z" }, + { url = "https://files.pythonhosted.org/packages/f2/b7/6d3f80e6918213babddb2a37b46dbb14c15b14c5f473e347869a51f40e1f/torch-2.9.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:524de44cd13931208ba2c4bde9ec7741fd4ae6bfd06409a604fc32f6520c2bc9", size = 899749493, upload-time = "2025-11-12T15:24:36.356Z" }, + { url = "https://files.pythonhosted.org/packages/a6/47/c7843d69d6de8938c1cbb1eba426b1d48ddf375f101473d3e31a5fc52b74/torch-2.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:545844cc16b3f91e08ce3b40e9c2d77012dd33a48d505aed34b7740ed627a1b2", size = 110944162, upload-time = "2025-11-12T15:21:53.151Z" }, + { url = "https://files.pythonhosted.org/packages/28/0e/2a37247957e72c12151b33a01e4df651d9d155dd74d8cfcbfad15a79b44a/torch-2.9.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5be4bf7496f1e3ffb1dd44b672adb1ac3f081f204c5ca81eba6442f5f634df8e", size = 74830751, upload-time = "2025-11-12T15:21:43.792Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f7/7a18745edcd7b9ca2381aa03353647bca8aace91683c4975f19ac233809d/torch-2.9.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:30a3e170a84894f3652434b56d59a64a2c11366b0ed5776fab33c2439396bf9a", size = 104142929, upload-time = "2025-11-12T15:21:48.319Z" }, + { url = "https://files.pythonhosted.org/packages/f4/dd/f1c0d879f2863ef209e18823a988dc7a1bf40470750e3ebe927efdb9407f/torch-2.9.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:8301a7b431e51764629208d0edaa4f9e4c33e6df0f2f90b90e261d623df6a4e2", size = 899748978, upload-time = "2025-11-12T15:23:04.568Z" }, + { url = "https://files.pythonhosted.org/packages/1f/9f/6986b83a53b4d043e36f3f898b798ab51f7f20fdf1a9b01a2720f445043d/torch-2.9.1-cp313-cp313t-win_amd64.whl", hash = "sha256:2e1c42c0ae92bf803a4b2409fdfed85e30f9027a66887f5e7dcdbc014c7531db", size = 111176995, upload-time = "2025-11-12T15:22:01.618Z" }, + { url = "https://files.pythonhosted.org/packages/40/60/71c698b466dd01e65d0e9514b5405faae200c52a76901baf6906856f17e4/torch-2.9.1-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:2c14b3da5df416cf9cb5efab83aa3056f5b8cd8620b8fde81b4987ecab730587", size = 74480347, upload-time = "2025-11-12T15:21:57.648Z" }, + { url = "https://files.pythonhosted.org/packages/48/50/c4b5112546d0d13cc9eaa1c732b823d676a9f49ae8b6f97772f795874a03/torch-2.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1edee27a7c9897f4e0b7c14cfc2f3008c571921134522d5b9b5ec4ebbc69041a", size = 74433245, upload-time = "2025-11-12T15:22:39.027Z" }, + { url = "https://files.pythonhosted.org/packages/81/c9/2628f408f0518b3bae49c95f5af3728b6ab498c8624ab1e03a43dd53d650/torch-2.9.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:19d144d6b3e29921f1fc70503e9f2fc572cde6a5115c0c0de2f7ca8b1483e8b6", size = 104134804, upload-time = "2025-11-12T15:22:35.222Z" }, + { url = "https://files.pythonhosted.org/packages/28/fc/5bc91d6d831ae41bf6e9e6da6468f25330522e92347c9156eb3f1cb95956/torch-2.9.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:c432d04376f6d9767a9852ea0def7b47a7bbc8e7af3b16ac9cf9ce02b12851c9", size = 899747132, upload-time = "2025-11-12T15:23:36.068Z" }, + { url = "https://files.pythonhosted.org/packages/63/5d/e8d4e009e52b6b2cf1684bde2a6be157b96fb873732542fb2a9a99e85a83/torch-2.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:d187566a2cdc726fc80138c3cdb260970fab1c27e99f85452721f7759bbd554d", size = 110934845, upload-time = "2025-11-12T15:22:48.367Z" }, + { url = "https://files.pythonhosted.org/packages/bd/b2/2d15a52516b2ea3f414643b8de68fa4cb220d3877ac8b1028c83dc8ca1c4/torch-2.9.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cb10896a1f7fedaddbccc2017ce6ca9ecaaf990f0973bdfcf405439750118d2c", size = 74823558, upload-time = "2025-11-12T15:22:43.392Z" }, + { url = "https://files.pythonhosted.org/packages/86/5c/5b2e5d84f5b9850cd1e71af07524d8cbb74cba19379800f1f9f7c997fc70/torch-2.9.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:0a2bd769944991c74acf0c4ef23603b9c777fdf7637f115605a4b2d8023110c7", size = 104145788, upload-time = "2025-11-12T15:23:52.109Z" }, + { url = "https://files.pythonhosted.org/packages/a9/8c/3da60787bcf70add986c4ad485993026ac0ca74f2fc21410bc4eb1bb7695/torch-2.9.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:07c8a9660bc9414c39cac530ac83b1fb1b679d7155824144a40a54f4a47bfa73", size = 899735500, upload-time = "2025-11-12T15:24:08.788Z" }, + { url = "https://files.pythonhosted.org/packages/db/2b/f7818f6ec88758dfd21da46b6cd46af9d1b3433e53ddbb19ad1e0da17f9b/torch-2.9.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c88d3299ddeb2b35dcc31753305612db485ab6f1823e37fb29451c8b2732b87e", size = 111163659, upload-time = "2025-11-12T15:23:20.009Z" }, +] + +[[package]] +name = "tornado" +version = "6.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632, upload-time = "2025-12-15T19:21:03.836Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909, upload-time = "2025-12-15T19:20:48.382Z" }, + { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163, upload-time = "2025-12-15T19:20:49.791Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746, upload-time = "2025-12-15T19:20:51.491Z" }, + { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083, upload-time = "2025-12-15T19:20:52.778Z" }, + { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315, upload-time = "2025-12-15T19:20:53.996Z" }, + { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003, upload-time = "2025-12-15T19:20:56.101Z" }, + { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412, upload-time = "2025-12-15T19:20:57.398Z" }, + { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392, upload-time = "2025-12-15T19:20:58.692Z" }, + { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481, upload-time = "2025-12-15T19:21:00.008Z" }, + { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886, upload-time = "2025-12-15T19:21:01.287Z" }, + { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, +] + +[[package]] +name = "transformers" +version = "4.57.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "huggingface-hub" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "regex" }, + { name = "requests" }, + { name = "safetensors" }, + { name = "tokenizers" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dd/70/d42a739e8dfde3d92bb2fff5819cbf331fe9657323221e79415cd5eb65ee/transformers-4.57.3.tar.gz", hash = "sha256:df4945029aaddd7c09eec5cad851f30662f8bd1746721b34cc031d70c65afebc", size = 10139680, upload-time = "2025-11-25T15:51:30.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/6b/2f416568b3c4c91c96e5a365d164f8a4a4a88030aa8ab4644181fdadce97/transformers-4.57.3-py3-none-any.whl", hash = "sha256:c77d353a4851b1880191603d36acb313411d3577f6e2897814f333841f7003f4", size = 11993463, upload-time = "2025-11-25T15:51:26.493Z" }, +] + +[[package]] +name = "triton" +version = "3.5.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/50/9a8358d3ef58162c0a415d173cfb45b67de60176e1024f71fbc4d24c0b6d/triton-3.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d2c6b915a03888ab931a9fd3e55ba36785e1fe70cbea0b40c6ef93b20fc85232", size = 170470207, upload-time = "2025-11-11T17:41:00.253Z" }, + { url = "https://files.pythonhosted.org/packages/27/46/8c3bbb5b0a19313f50edcaa363b599e5a1a5ac9683ead82b9b80fe497c8d/triton-3.5.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3f4346b6ebbd4fad18773f5ba839114f4826037c9f2f34e0148894cd5dd3dba", size = 170470410, upload-time = "2025-11-11T17:41:06.319Z" }, + { url = "https://files.pythonhosted.org/packages/37/92/e97fcc6b2c27cdb87ce5ee063d77f8f26f19f06916aa680464c8104ef0f6/triton-3.5.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0b4d2c70127fca6a23e247f9348b8adde979d2e7a20391bfbabaac6aebc7e6a8", size = 170579924, upload-time = "2025-11-11T17:41:12.455Z" }, + { url = "https://files.pythonhosted.org/packages/a4/e6/c595c35e5c50c4bc56a7bac96493dad321e9e29b953b526bbbe20f9911d0/triton-3.5.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0637b1efb1db599a8e9dc960d53ab6e4637db7d4ab6630a0974705d77b14b60", size = 170480488, upload-time = "2025-11-11T17:41:18.222Z" }, + { url = "https://files.pythonhosted.org/packages/16/b5/b0d3d8b901b6a04ca38df5e24c27e53afb15b93624d7fd7d658c7cd9352a/triton-3.5.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bac7f7d959ad0f48c0e97d6643a1cc0fd5786fe61cb1f83b537c6b2d54776478", size = 170582192, upload-time = "2025-11-11T17:41:23.963Z" }, +] + +[[package]] +name = "types-requests" +version = "2.32.4.20260107" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0f/f3/a0663907082280664d745929205a89d41dffb29e89a50f753af7d57d0a96/types_requests-2.32.4.20260107.tar.gz", hash = "sha256:018a11ac158f801bfa84857ddec1650750e393df8a004a8a9ae2a9bec6fcb24f", size = 23165, upload-time = "2026-01-07T03:20:54.091Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/12/709ea261f2bf91ef0a26a9eed20f2623227a8ed85610c1e54c5805692ecb/types_requests-2.32.4.20260107-py3-none-any.whl", hash = "sha256:b703fe72f8ce5b31ef031264fe9395cac8f46a04661a79f7ed31a80fb308730d", size = 20676, upload-time = "2026-01-07T03:20:52.929Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspect" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, +] + +[[package]] +name = "uri-template" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, +] + +[[package]] +name = "uuid-utils" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/8a/17b11768dcb473d3a255c02ffdd94fbd1b345c906efea0a39124dcbaed52/uuid_utils-0.13.0.tar.gz", hash = "sha256:4c17df6427a9e23a4cd7fb9ee1efb53b8abb078660b9bdb2524ca8595022dfe1", size = 21921, upload-time = "2026-01-08T15:48:10.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/b8/d40848ca22781f206c60a1885fc737d2640392bd6b5792d455525accd89c/uuid_utils-0.13.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:83628283e977fb212e756bc055df8fdd2f9f589a2e539ba1abe755b8ce8df7a4", size = 602130, upload-time = "2026-01-08T15:47:34.877Z" }, + { url = "https://files.pythonhosted.org/packages/40/b9/00a944b8096632ea12638181f8e294abcde3e3b8b5e29b777f809896f6ae/uuid_utils-0.13.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c47638ed6334ab19d80f73664f153b04bbb04ab8ce4298d10da6a292d4d21c47", size = 304213, upload-time = "2026-01-08T15:47:36.807Z" }, + { url = "https://files.pythonhosted.org/packages/da/d7/07b36c33aef683b81c9afff3ec178d5eb39d325447a68c3c68a62e4abb32/uuid_utils-0.13.0-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:b276b538c57733ed406948584912da422a604313c71479654848b84b9e19c9b0", size = 340624, upload-time = "2026-01-08T15:47:38.821Z" }, + { url = "https://files.pythonhosted.org/packages/7d/55/fcff2fff02a27866cb1a6614c9df2b3ace721f0a0aab2b7b8f5a7d4e4221/uuid_utils-0.13.0-cp39-abi3-manylinux_2_24_armv7l.whl", hash = "sha256:bdaf2b77e34b199cf04cde28399495fd1ed951de214a4ece1f3919b2f945bb06", size = 346705, upload-time = "2026-01-08T15:47:40.397Z" }, + { url = "https://files.pythonhosted.org/packages/41/48/67438506c2bb8bee1b4b00d7c0b3ff866401b4790849bf591d654d4ea0bc/uuid_utils-0.13.0-cp39-abi3-manylinux_2_24_i686.whl", hash = "sha256:eb2f0baf81e82f9769a7684022dca8f3bf801ca1574a3e94df1876e9d6f9271e", size = 366023, upload-time = "2026-01-08T15:47:42.662Z" }, + { url = "https://files.pythonhosted.org/packages/8b/d7/2d91ce17f62fd764d593430de296b70843cc25229c772453f7261de9e6a8/uuid_utils-0.13.0-cp39-abi3-manylinux_2_24_ppc64le.whl", hash = "sha256:6be6c4d11275f5cc402a4fdba6c2b1ce45fd3d99bb78716cd1cc2cbf6802b2ce", size = 471149, upload-time = "2026-01-08T15:47:44.963Z" }, + { url = "https://files.pythonhosted.org/packages/2e/9a/aa0756186073ba84daf5704c150d41ede10eb3185d510e02532e2071550e/uuid_utils-0.13.0-cp39-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:77621cf6ceca7f42173a642a01c01c216f9eaec3b7b65d093d2d6a433ca0a83d", size = 342130, upload-time = "2026-01-08T15:47:46.331Z" }, + { url = "https://files.pythonhosted.org/packages/74/b4/3191789f4dc3bed59d79cec90559821756297a25d7dc34d1bf7781577a75/uuid_utils-0.13.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9a5a9eb06c2bb86dd876cd7b2fe927fc8543d14c90d971581db6ffda4a02526f", size = 524128, upload-time = "2026-01-08T15:47:47.628Z" }, + { url = "https://files.pythonhosted.org/packages/b2/30/29839210a8fff9fc219bfa7c8d8cd115324e92618cba0cda090d54d3d321/uuid_utils-0.13.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:775347c6110fb71360df17aac74132d8d47c1dbe71233ac98197fc872a791fd2", size = 615872, upload-time = "2026-01-08T15:47:50.61Z" }, + { url = "https://files.pythonhosted.org/packages/99/ed/15000c96a8bd8f5fd8efd622109bf52549ea0b366f8ce71c45580fa55878/uuid_utils-0.13.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf95f6370ad1a0910ee7b5ad5228fd19c4ae32fe3627389006adaf519408c41e", size = 581023, upload-time = "2026-01-08T15:47:52.776Z" }, + { url = "https://files.pythonhosted.org/packages/67/c8/3f809fa2dc2ca4bd331c792a3c7d3e45ae2b709d85847a12b8b27d1d5f19/uuid_utils-0.13.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5a88e23e0b2f4203fefe2ccbca5736ee06fcad10e61b5e7e39c8d7904bc13300", size = 546715, upload-time = "2026-01-08T15:47:54.415Z" }, + { url = "https://files.pythonhosted.org/packages/f5/80/4f7c7efd734d1494397c781bd3d421688e9c187ae836e3174625b1ddf8b0/uuid_utils-0.13.0-cp39-abi3-win32.whl", hash = "sha256:3e4f2cc54e6a99c0551158100ead528479ad2596847478cbad624977064ffce3", size = 177650, upload-time = "2026-01-08T15:47:55.679Z" }, + { url = "https://files.pythonhosted.org/packages/6c/94/d05ab68622e66ad787a241dfe5ccc649b3af09f30eae977b9ee8f7046aaa/uuid_utils-0.13.0-cp39-abi3-win_amd64.whl", hash = "sha256:046cb2756e1597b3de22d24851b769913e192135830486a0a70bf41327f0360c", size = 183211, upload-time = "2026-01-08T15:47:57.604Z" }, + { url = "https://files.pythonhosted.org/packages/69/37/674b3ce25cd715b831ea8ebbd828b74c40159f04c95d1bb963b2c876fe79/uuid_utils-0.13.0-cp39-abi3-win_arm64.whl", hash = "sha256:5447a680df6ef8a5a353976aaf4c97cc3a3a22b1ee13671c44227b921e3ae2a9", size = 183518, upload-time = "2026-01-08T15:47:59.148Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.2.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" }, +] + +[[package]] +name = "webcolors" +version = "25.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491, upload-time = "2025-10-31T07:51:03.977Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905, upload-time = "2025-10-31T07:51:01.778Z" }, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, +] + +[[package]] +name = "websocket-client" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, +] + +[[package]] +name = "widgetsnbextension" +version = "4.0.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402, upload-time = "2025-11-01T21:15:55.178Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503, upload-time = "2025-11-01T21:15:53.565Z" }, +] + +[[package]] +name = "word2number" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/29/a31940c848521f0725f0df6b25dca8917f13a2025b0e8fcbe5d0457e45e6/word2number-1.1.zip", hash = "sha256:70e27a5d387f67b04c71fbb7621c05930b19bfd26efd6851e6e0f9969dcde7d0", size = 9723, upload-time = "2017-06-02T15:45:14.488Z" } + +[[package]] +name = "xlsxwriter" +version = "3.2.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/2c/c06ef49dc36e7954e55b802a8b231770d286a9758b3d936bd1e04ce5ba88/xlsxwriter-3.2.9.tar.gz", hash = "sha256:254b1c37a368c444eac6e2f867405cc9e461b0ed97a3233b2ac1e574efb4140c", size = 215940, upload-time = "2025-09-16T00:16:21.63Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/0c/3662f4a66880196a590b202f0db82d919dd2f89e99a27fadef91c4a33d41/xlsxwriter-3.2.9-py3-none-any.whl", hash = "sha256:9a5db42bc5dff014806c58a20b9eae7322a134abb6fce3c92c181bfb275ec5b3", size = 175315, upload-time = "2025-09-16T00:16:20.108Z" }, +] + +[[package]] +name = "xxhash" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/07/d9412f3d7d462347e4511181dea65e47e0d0e16e26fbee2ea86a2aefb657/xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c", size = 32744, upload-time = "2025-10-02T14:34:34.622Z" }, + { url = "https://files.pythonhosted.org/packages/79/35/0429ee11d035fc33abe32dca1b2b69e8c18d236547b9a9b72c1929189b9a/xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204", size = 30816, upload-time = "2025-10-02T14:34:36.043Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f2/57eb99aa0f7d98624c0932c5b9a170e1806406cdbcdb510546634a1359e0/xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490", size = 194035, upload-time = "2025-10-02T14:34:37.354Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ed/6224ba353690d73af7a3f1c7cdb1fc1b002e38f783cb991ae338e1eb3d79/xxhash-3.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93f107c673bccf0d592cdba077dedaf52fe7f42dcd7676eba1f6d6f0c3efffd2", size = 212914, upload-time = "2025-10-02T14:34:38.6Z" }, + { url = "https://files.pythonhosted.org/packages/38/86/fb6b6130d8dd6b8942cc17ab4d90e223653a89aa32ad2776f8af7064ed13/xxhash-3.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aa5ee3444c25b69813663c9f8067dcfaa2e126dc55e8dddf40f4d1c25d7effa", size = 212163, upload-time = "2025-10-02T14:34:39.872Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dc/e84875682b0593e884ad73b2d40767b5790d417bde603cceb6878901d647/xxhash-3.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7f99123f0e1194fa59cc69ad46dbae2e07becec5df50a0509a808f90a0f03f0", size = 445411, upload-time = "2025-10-02T14:34:41.569Z" }, + { url = "https://files.pythonhosted.org/packages/11/4f/426f91b96701ec2f37bb2b8cec664eff4f658a11f3fa9d94f0a887ea6d2b/xxhash-3.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49e03e6fe2cac4a1bc64952dd250cf0dbc5ef4ebb7b8d96bce82e2de163c82a2", size = 193883, upload-time = "2025-10-02T14:34:43.249Z" }, + { url = "https://files.pythonhosted.org/packages/53/5a/ddbb83eee8e28b778eacfc5a85c969673e4023cdeedcfcef61f36731610b/xxhash-3.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bd17fede52a17a4f9a7bc4472a5867cb0b160deeb431795c0e4abe158bc784e9", size = 210392, upload-time = "2025-10-02T14:34:45.042Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c2/ff69efd07c8c074ccdf0a4f36fcdd3d27363665bcdf4ba399abebe643465/xxhash-3.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6fb5f5476bef678f69db04f2bd1efbed3030d2aba305b0fc1773645f187d6a4e", size = 197898, upload-time = "2025-10-02T14:34:46.302Z" }, + { url = "https://files.pythonhosted.org/packages/58/ca/faa05ac19b3b622c7c9317ac3e23954187516298a091eb02c976d0d3dd45/xxhash-3.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:843b52f6d88071f87eba1631b684fcb4b2068cd2180a0224122fe4ef011a9374", size = 210655, upload-time = "2025-10-02T14:34:47.571Z" }, + { url = "https://files.pythonhosted.org/packages/d4/7a/06aa7482345480cc0cb597f5c875b11a82c3953f534394f620b0be2f700c/xxhash-3.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7d14a6cfaf03b1b6f5f9790f76880601ccc7896aff7ab9cd8978a939c1eb7e0d", size = 414001, upload-time = "2025-10-02T14:34:49.273Z" }, + { url = "https://files.pythonhosted.org/packages/23/07/63ffb386cd47029aa2916b3d2f454e6cc5b9f5c5ada3790377d5430084e7/xxhash-3.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:418daf3db71e1413cfe211c2f9a528456936645c17f46b5204705581a45390ae", size = 191431, upload-time = "2025-10-02T14:34:50.798Z" }, + { url = "https://files.pythonhosted.org/packages/0f/93/14fde614cadb4ddf5e7cebf8918b7e8fac5ae7861c1875964f17e678205c/xxhash-3.6.0-cp312-cp312-win32.whl", hash = "sha256:50fc255f39428a27299c20e280d6193d8b63b8ef8028995323bf834a026b4fbb", size = 30617, upload-time = "2025-10-02T14:34:51.954Z" }, + { url = "https://files.pythonhosted.org/packages/13/5d/0d125536cbe7565a83d06e43783389ecae0c0f2ed037b48ede185de477c0/xxhash-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0f2ab8c715630565ab8991b536ecded9416d615538be8ecddce43ccf26cbc7c", size = 31534, upload-time = "2025-10-02T14:34:53.276Z" }, + { url = "https://files.pythonhosted.org/packages/54/85/6ec269b0952ec7e36ba019125982cf11d91256a778c7c3f98a4c5043d283/xxhash-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:eae5c13f3bc455a3bbb68bdc513912dc7356de7e2280363ea235f71f54064829", size = 27876, upload-time = "2025-10-02T14:34:54.371Z" }, + { url = "https://files.pythonhosted.org/packages/33/76/35d05267ac82f53ae9b0e554da7c5e281ee61f3cad44c743f0fcd354f211/xxhash-3.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:599e64ba7f67472481ceb6ee80fa3bd828fd61ba59fb11475572cc5ee52b89ec", size = 32738, upload-time = "2025-10-02T14:34:55.839Z" }, + { url = "https://files.pythonhosted.org/packages/31/a8/3fbce1cd96534a95e35d5120637bf29b0d7f5d8fa2f6374e31b4156dd419/xxhash-3.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d8b8aaa30fca4f16f0c84a5c8d7ddee0e25250ec2796c973775373257dde8f1", size = 30821, upload-time = "2025-10-02T14:34:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ea/d387530ca7ecfa183cb358027f1833297c6ac6098223fd14f9782cd0015c/xxhash-3.6.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d597acf8506d6e7101a4a44a5e428977a51c0fadbbfd3c39650cca9253f6e5a6", size = 194127, upload-time = "2025-10-02T14:34:59.21Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/71435dcb99874b09a43b8d7c54071e600a7481e42b3e3ce1eb5226a5711a/xxhash-3.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:858dc935963a33bc33490128edc1c12b0c14d9c7ebaa4e387a7869ecc4f3e263", size = 212975, upload-time = "2025-10-02T14:35:00.816Z" }, + { url = "https://files.pythonhosted.org/packages/84/7a/c2b3d071e4bb4a90b7057228a99b10d51744878f4a8a6dd643c8bd897620/xxhash-3.6.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba284920194615cb8edf73bf52236ce2e1664ccd4a38fdb543506413529cc546", size = 212241, upload-time = "2025-10-02T14:35:02.207Z" }, + { url = "https://files.pythonhosted.org/packages/81/5f/640b6eac0128e215f177df99eadcd0f1b7c42c274ab6a394a05059694c5a/xxhash-3.6.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b54219177f6c6674d5378bd862c6aedf64725f70dd29c472eaae154df1a2e89", size = 445471, upload-time = "2025-10-02T14:35:03.61Z" }, + { url = "https://files.pythonhosted.org/packages/5e/1e/3c3d3ef071b051cc3abbe3721ffb8365033a172613c04af2da89d5548a87/xxhash-3.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c36dd7dbad2f5238950c377fcbf6811b1cdb1c444fab447960030cea60504d", size = 193936, upload-time = "2025-10-02T14:35:05.013Z" }, + { url = "https://files.pythonhosted.org/packages/2c/bd/4a5f68381939219abfe1c22a9e3a5854a4f6f6f3c4983a87d255f21f2e5d/xxhash-3.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f22927652cba98c44639ffdc7aaf35828dccf679b10b31c4ad72a5b530a18eb7", size = 210440, upload-time = "2025-10-02T14:35:06.239Z" }, + { url = "https://files.pythonhosted.org/packages/eb/37/b80fe3d5cfb9faff01a02121a0f4d565eb7237e9e5fc66e73017e74dcd36/xxhash-3.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b45fad44d9c5c119e9c6fbf2e1c656a46dc68e280275007bbfd3d572b21426db", size = 197990, upload-time = "2025-10-02T14:35:07.735Z" }, + { url = "https://files.pythonhosted.org/packages/d7/fd/2c0a00c97b9e18f72e1f240ad4e8f8a90fd9d408289ba9c7c495ed7dc05c/xxhash-3.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6f2580ffab1a8b68ef2b901cde7e55fa8da5e4be0977c68f78fc80f3c143de42", size = 210689, upload-time = "2025-10-02T14:35:09.438Z" }, + { url = "https://files.pythonhosted.org/packages/93/86/5dd8076a926b9a95db3206aba20d89a7fc14dd5aac16e5c4de4b56033140/xxhash-3.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40c391dd3cd041ebc3ffe6f2c862f402e306eb571422e0aa918d8070ba31da11", size = 414068, upload-time = "2025-10-02T14:35:11.162Z" }, + { url = "https://files.pythonhosted.org/packages/af/3c/0bb129170ee8f3650f08e993baee550a09593462a5cddd8e44d0011102b1/xxhash-3.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f205badabde7aafd1a31e8ca2a3e5a763107a71c397c4481d6a804eb5063d8bd", size = 191495, upload-time = "2025-10-02T14:35:12.971Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3a/6797e0114c21d1725e2577508e24006fd7ff1d8c0c502d3b52e45c1771d8/xxhash-3.6.0-cp313-cp313-win32.whl", hash = "sha256:2577b276e060b73b73a53042ea5bd5203d3e6347ce0d09f98500f418a9fcf799", size = 30620, upload-time = "2025-10-02T14:35:14.129Z" }, + { url = "https://files.pythonhosted.org/packages/86/15/9bc32671e9a38b413a76d24722a2bf8784a132c043063a8f5152d390b0f9/xxhash-3.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:757320d45d2fbcce8f30c42a6b2f47862967aea7bf458b9625b4bbe7ee390392", size = 31542, upload-time = "2025-10-02T14:35:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/39/c5/cc01e4f6188656e56112d6a8e0dfe298a16934b8c47a247236549a3f7695/xxhash-3.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:457b8f85dec5825eed7b69c11ae86834a018b8e3df5e77783c999663da2f96d6", size = 27880, upload-time = "2025-10-02T14:35:16.315Z" }, + { url = "https://files.pythonhosted.org/packages/f3/30/25e5321c8732759e930c555176d37e24ab84365482d257c3b16362235212/xxhash-3.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a42e633d75cdad6d625434e3468126c73f13f7584545a9cf34e883aa1710e702", size = 32956, upload-time = "2025-10-02T14:35:17.413Z" }, + { url = "https://files.pythonhosted.org/packages/9f/3c/0573299560d7d9f8ab1838f1efc021a280b5ae5ae2e849034ef3dee18810/xxhash-3.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:568a6d743219e717b07b4e03b0a828ce593833e498c3b64752e0f5df6bfe84db", size = 31072, upload-time = "2025-10-02T14:35:18.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1c/52d83a06e417cd9d4137722693424885cc9878249beb3a7c829e74bf7ce9/xxhash-3.6.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bec91b562d8012dae276af8025a55811b875baace6af510412a5e58e3121bc54", size = 196409, upload-time = "2025-10-02T14:35:20.31Z" }, + { url = "https://files.pythonhosted.org/packages/e3/8e/c6d158d12a79bbd0b878f8355432075fc82759e356ab5a111463422a239b/xxhash-3.6.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78e7f2f4c521c30ad5e786fdd6bae89d47a32672a80195467b5de0480aa97b1f", size = 215736, upload-time = "2025-10-02T14:35:21.616Z" }, + { url = "https://files.pythonhosted.org/packages/bc/68/c4c80614716345d55071a396cf03d06e34b5f4917a467faf43083c995155/xxhash-3.6.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3ed0df1b11a79856df5ffcab572cbd6b9627034c1c748c5566fa79df9048a7c5", size = 214833, upload-time = "2025-10-02T14:35:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e9/ae27c8ffec8b953efa84c7c4a6c6802c263d587b9fc0d6e7cea64e08c3af/xxhash-3.6.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e4edbfc7d420925b0dd5e792478ed393d6e75ff8fc219a6546fb446b6a417b1", size = 448348, upload-time = "2025-10-02T14:35:25.111Z" }, + { url = "https://files.pythonhosted.org/packages/d7/6b/33e21afb1b5b3f46b74b6bd1913639066af218d704cc0941404ca717fc57/xxhash-3.6.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fba27a198363a7ef87f8c0f6b171ec36b674fe9053742c58dd7e3201c1ab30ee", size = 196070, upload-time = "2025-10-02T14:35:26.586Z" }, + { url = "https://files.pythonhosted.org/packages/96/b6/fcabd337bc5fa624e7203aa0fa7d0c49eed22f72e93229431752bddc83d9/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:794fe9145fe60191c6532fa95063765529770edcdd67b3d537793e8004cabbfd", size = 212907, upload-time = "2025-10-02T14:35:28.087Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d3/9ee6160e644d660fcf176c5825e61411c7f62648728f69c79ba237250143/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6105ef7e62b5ac73a837778efc331a591d8442f8ef5c7e102376506cb4ae2729", size = 200839, upload-time = "2025-10-02T14:35:29.857Z" }, + { url = "https://files.pythonhosted.org/packages/0d/98/e8de5baa5109394baf5118f5e72ab21a86387c4f89b0e77ef3e2f6b0327b/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f01375c0e55395b814a679b3eea205db7919ac2af213f4a6682e01220e5fe292", size = 213304, upload-time = "2025-10-02T14:35:31.222Z" }, + { url = "https://files.pythonhosted.org/packages/7b/1d/71056535dec5c3177eeb53e38e3d367dd1d16e024e63b1cee208d572a033/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d706dca2d24d834a4661619dcacf51a75c16d65985718d6a7d73c1eeeb903ddf", size = 416930, upload-time = "2025-10-02T14:35:32.517Z" }, + { url = "https://files.pythonhosted.org/packages/dc/6c/5cbde9de2cd967c322e651c65c543700b19e7ae3e0aae8ece3469bf9683d/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f059d9faeacd49c0215d66f4056e1326c80503f51a1532ca336a385edadd033", size = 193787, upload-time = "2025-10-02T14:35:33.827Z" }, + { url = "https://files.pythonhosted.org/packages/19/fa/0172e350361d61febcea941b0cc541d6e6c8d65d153e85f850a7b256ff8a/xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec", size = 30916, upload-time = "2025-10-02T14:35:35.107Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e6/e8cf858a2b19d6d45820f072eff1bea413910592ff17157cabc5f1227a16/xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8", size = 31799, upload-time = "2025-10-02T14:35:36.165Z" }, + { url = "https://files.pythonhosted.org/packages/56/15/064b197e855bfb7b343210e82490ae672f8bc7cdf3ddb02e92f64304ee8a/xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746", size = 28044, upload-time = "2025-10-02T14:35:37.195Z" }, + { url = "https://files.pythonhosted.org/packages/7e/5e/0138bc4484ea9b897864d59fce9be9086030825bc778b76cb5a33a906d37/xxhash-3.6.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a40a3d35b204b7cc7643cbcf8c9976d818cb47befcfac8bbefec8038ac363f3e", size = 32754, upload-time = "2025-10-02T14:35:38.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/d7/5dac2eb2ec75fd771957a13e5dda560efb2176d5203f39502a5fc571f899/xxhash-3.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a54844be970d3fc22630b32d515e79a90d0a3ddb2644d8d7402e3c4c8da61405", size = 30846, upload-time = "2025-10-02T14:35:39.6Z" }, + { url = "https://files.pythonhosted.org/packages/fe/71/8bc5be2bb00deb5682e92e8da955ebe5fa982da13a69da5a40a4c8db12fb/xxhash-3.6.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:016e9190af8f0a4e3741343777710e3d5717427f175adfdc3e72508f59e2a7f3", size = 194343, upload-time = "2025-10-02T14:35:40.69Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/52badfb2aecec2c377ddf1ae75f55db3ba2d321c5e164f14461c90837ef3/xxhash-3.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f6f72232f849eb9d0141e2ebe2677ece15adfd0fa599bc058aad83c714bb2c6", size = 213074, upload-time = "2025-10-02T14:35:42.29Z" }, + { url = "https://files.pythonhosted.org/packages/a2/2b/ae46b4e9b92e537fa30d03dbc19cdae57ed407e9c26d163895e968e3de85/xxhash-3.6.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63275a8aba7865e44b1813d2177e0f5ea7eadad3dd063a21f7cf9afdc7054063", size = 212388, upload-time = "2025-10-02T14:35:43.929Z" }, + { url = "https://files.pythonhosted.org/packages/f5/80/49f88d3afc724b4ac7fbd664c8452d6db51b49915be48c6982659e0e7942/xxhash-3.6.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cd01fa2aa00d8b017c97eb46b9a794fbdca53fc14f845f5a328c71254b0abb7", size = 445614, upload-time = "2025-10-02T14:35:45.216Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ba/603ce3961e339413543d8cd44f21f2c80e2a7c5cfe692a7b1f2cccf58f3c/xxhash-3.6.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0226aa89035b62b6a86d3c68df4d7c1f47a342b8683da2b60cedcddb46c4d95b", size = 194024, upload-time = "2025-10-02T14:35:46.959Z" }, + { url = "https://files.pythonhosted.org/packages/78/d1/8e225ff7113bf81545cfdcd79eef124a7b7064a0bba53605ff39590b95c2/xxhash-3.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c6e193e9f56e4ca4923c61238cdaced324f0feac782544eb4c6d55ad5cc99ddd", size = 210541, upload-time = "2025-10-02T14:35:48.301Z" }, + { url = "https://files.pythonhosted.org/packages/6f/58/0f89d149f0bad89def1a8dd38feb50ccdeb643d9797ec84707091d4cb494/xxhash-3.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9176dcaddf4ca963d4deb93866d739a343c01c969231dbe21680e13a5d1a5bf0", size = 198305, upload-time = "2025-10-02T14:35:49.584Z" }, + { url = "https://files.pythonhosted.org/packages/11/38/5eab81580703c4df93feb5f32ff8fa7fe1e2c51c1f183ee4e48d4bb9d3d7/xxhash-3.6.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c1ce4009c97a752e682b897aa99aef84191077a9433eb237774689f14f8ec152", size = 210848, upload-time = "2025-10-02T14:35:50.877Z" }, + { url = "https://files.pythonhosted.org/packages/5e/6b/953dc4b05c3ce678abca756416e4c130d2382f877a9c30a20d08ee6a77c0/xxhash-3.6.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:8cb2f4f679b01513b7adbb9b1b2f0f9cdc31b70007eaf9d59d0878809f385b11", size = 414142, upload-time = "2025-10-02T14:35:52.15Z" }, + { url = "https://files.pythonhosted.org/packages/08/a9/238ec0d4e81a10eb5026d4a6972677cbc898ba6c8b9dbaec12ae001b1b35/xxhash-3.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:653a91d7c2ab54a92c19ccf43508b6a555440b9be1bc8be553376778be7f20b5", size = 191547, upload-time = "2025-10-02T14:35:53.547Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ee/3cf8589e06c2164ac77c3bf0aa127012801128f1feebf2a079272da5737c/xxhash-3.6.0-cp314-cp314-win32.whl", hash = "sha256:a756fe893389483ee8c394d06b5ab765d96e68fbbfe6fde7aa17e11f5720559f", size = 31214, upload-time = "2025-10-02T14:35:54.746Z" }, + { url = "https://files.pythonhosted.org/packages/02/5d/a19552fbc6ad4cb54ff953c3908bbc095f4a921bc569433d791f755186f1/xxhash-3.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:39be8e4e142550ef69629c9cd71b88c90e9a5db703fecbcf265546d9536ca4ad", size = 32290, upload-time = "2025-10-02T14:35:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/b1/11/dafa0643bc30442c887b55baf8e73353a344ee89c1901b5a5c54a6c17d39/xxhash-3.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:25915e6000338999236f1eb68a02a32c3275ac338628a7eaa5a269c401995679", size = 28795, upload-time = "2025-10-02T14:35:57.162Z" }, + { url = "https://files.pythonhosted.org/packages/2c/db/0e99732ed7f64182aef4a6fb145e1a295558deec2a746265dcdec12d191e/xxhash-3.6.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c5294f596a9017ca5a3e3f8884c00b91ab2ad2933cf288f4923c3fd4346cf3d4", size = 32955, upload-time = "2025-10-02T14:35:58.267Z" }, + { url = "https://files.pythonhosted.org/packages/55/f4/2a7c3c68e564a099becfa44bb3d398810cc0ff6749b0d3cb8ccb93f23c14/xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1cf9dcc4ab9cff01dfbba78544297a3a01dafd60f3bde4e2bfd016cf7e4ddc67", size = 31072, upload-time = "2025-10-02T14:35:59.382Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d9/72a29cddc7250e8a5819dad5d466facb5dc4c802ce120645630149127e73/xxhash-3.6.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01262da8798422d0685f7cef03b2bd3f4f46511b02830861df548d7def4402ad", size = 196579, upload-time = "2025-10-02T14:36:00.838Z" }, + { url = "https://files.pythonhosted.org/packages/63/93/b21590e1e381040e2ca305a884d89e1c345b347404f7780f07f2cdd47ef4/xxhash-3.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51a73fb7cb3a3ead9f7a8b583ffd9b8038e277cdb8cb87cf890e88b3456afa0b", size = 215854, upload-time = "2025-10-02T14:36:02.207Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b8/edab8a7d4fa14e924b29be877d54155dcbd8b80be85ea00d2be3413a9ed4/xxhash-3.6.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b9c6df83594f7df8f7f708ce5ebeacfc69f72c9fbaaababf6cf4758eaada0c9b", size = 214965, upload-time = "2025-10-02T14:36:03.507Z" }, + { url = "https://files.pythonhosted.org/packages/27/67/dfa980ac7f0d509d54ea0d5a486d2bb4b80c3f1bb22b66e6a05d3efaf6c0/xxhash-3.6.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:627f0af069b0ea56f312fd5189001c24578868643203bca1abbc2c52d3a6f3ca", size = 448484, upload-time = "2025-10-02T14:36:04.828Z" }, + { url = "https://files.pythonhosted.org/packages/8c/63/8ffc2cc97e811c0ca5d00ab36604b3ea6f4254f20b7bc658ca825ce6c954/xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa912c62f842dfd013c5f21a642c9c10cd9f4c4e943e0af83618b4a404d9091a", size = 196162, upload-time = "2025-10-02T14:36:06.182Z" }, + { url = "https://files.pythonhosted.org/packages/4b/77/07f0e7a3edd11a6097e990f6e5b815b6592459cb16dae990d967693e6ea9/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b465afd7909db30168ab62afe40b2fcf79eedc0b89a6c0ab3123515dc0df8b99", size = 213007, upload-time = "2025-10-02T14:36:07.733Z" }, + { url = "https://files.pythonhosted.org/packages/ae/d8/bc5fa0d152837117eb0bef6f83f956c509332ce133c91c63ce07ee7c4873/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a881851cf38b0a70e7c4d3ce81fc7afd86fbc2a024f4cfb2a97cf49ce04b75d3", size = 200956, upload-time = "2025-10-02T14:36:09.106Z" }, + { url = "https://files.pythonhosted.org/packages/26/a5/d749334130de9411783873e9b98ecc46688dad5db64ca6e04b02acc8b473/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9b3222c686a919a0f3253cfc12bb118b8b103506612253b5baeaac10d8027cf6", size = 213401, upload-time = "2025-10-02T14:36:10.585Z" }, + { url = "https://files.pythonhosted.org/packages/89/72/abed959c956a4bfc72b58c0384bb7940663c678127538634d896b1195c10/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:c5aa639bc113e9286137cec8fadc20e9cd732b2cc385c0b7fa673b84fc1f2a93", size = 417083, upload-time = "2025-10-02T14:36:12.276Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b3/62fd2b586283b7d7d665fb98e266decadf31f058f1cf6c478741f68af0cb/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5c1343d49ac102799905e115aee590183c3921d475356cb24b4de29a4bc56518", size = 193913, upload-time = "2025-10-02T14:36:14.025Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/c19c42c5b3f5a4aad748a6d5b4f23df3bed7ee5445accc65a0fb3ff03953/xxhash-3.6.0-cp314-cp314t-win32.whl", hash = "sha256:5851f033c3030dd95c086b4a36a2683c2ff4a799b23af60977188b057e467119", size = 31586, upload-time = "2025-10-02T14:36:15.603Z" }, + { url = "https://files.pythonhosted.org/packages/03/d6/4cc450345be9924fd5dc8c590ceda1db5b43a0a889587b0ae81a95511360/xxhash-3.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0444e7967dac37569052d2409b00a8860c2135cff05502df4da80267d384849f", size = 32526, upload-time = "2025-10-02T14:36:16.708Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c9/7243eb3f9eaabd1a88a5a5acadf06df2d83b100c62684b7425c6a11bcaa8/xxhash-3.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bb79b1e63f6fd84ec778a4b1916dfe0a7c3fdb986c06addd5db3a0d413819d95", size = 28898, upload-time = "2025-10-02T14:36:17.843Z" }, +] + +[[package]] +name = "yarl" +version = "1.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/ff/46736024fee3429b80a165a732e38e5d5a238721e634ab41b040d49f8738/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", size = 142000, upload-time = "2025-10-06T14:09:44.631Z" }, + { url = "https://files.pythonhosted.org/packages/5a/9a/b312ed670df903145598914770eb12de1bac44599549b3360acc96878df8/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", size = 94338, upload-time = "2025-10-06T14:09:46.372Z" }, + { url = "https://files.pythonhosted.org/packages/ba/f5/0601483296f09c3c65e303d60c070a5c19fcdbc72daa061e96170785bc7d/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", size = 94909, upload-time = "2025-10-06T14:09:48.648Z" }, + { url = "https://files.pythonhosted.org/packages/60/41/9a1fe0b73dbcefce72e46cf149b0e0a67612d60bfc90fb59c2b2efdfbd86/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", size = 372940, upload-time = "2025-10-06T14:09:50.089Z" }, + { url = "https://files.pythonhosted.org/packages/17/7a/795cb6dfee561961c30b800f0ed616b923a2ec6258b5def2a00bf8231334/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", size = 345825, upload-time = "2025-10-06T14:09:52.142Z" }, + { url = "https://files.pythonhosted.org/packages/d7/93/a58f4d596d2be2ae7bab1a5846c4d270b894958845753b2c606d666744d3/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", size = 386705, upload-time = "2025-10-06T14:09:54.128Z" }, + { url = "https://files.pythonhosted.org/packages/61/92/682279d0e099d0e14d7fd2e176bd04f48de1484f56546a3e1313cd6c8e7c/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", size = 396518, upload-time = "2025-10-06T14:09:55.762Z" }, + { url = "https://files.pythonhosted.org/packages/db/0f/0d52c98b8a885aeda831224b78f3be7ec2e1aa4a62091f9f9188c3c65b56/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", size = 377267, upload-time = "2025-10-06T14:09:57.958Z" }, + { url = "https://files.pythonhosted.org/packages/22/42/d2685e35908cbeaa6532c1fc73e89e7f2efb5d8a7df3959ea8e37177c5a3/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", size = 365797, upload-time = "2025-10-06T14:09:59.527Z" }, + { url = "https://files.pythonhosted.org/packages/a2/83/cf8c7bcc6355631762f7d8bdab920ad09b82efa6b722999dfb05afa6cfac/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", size = 365535, upload-time = "2025-10-06T14:10:01.139Z" }, + { url = "https://files.pythonhosted.org/packages/25/e1/5302ff9b28f0c59cac913b91fe3f16c59a033887e57ce9ca5d41a3a94737/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", size = 382324, upload-time = "2025-10-06T14:10:02.756Z" }, + { url = "https://files.pythonhosted.org/packages/bf/cd/4617eb60f032f19ae3a688dc990d8f0d89ee0ea378b61cac81ede3e52fae/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", size = 383803, upload-time = "2025-10-06T14:10:04.552Z" }, + { url = "https://files.pythonhosted.org/packages/59/65/afc6e62bb506a319ea67b694551dab4a7e6fb7bf604e9bd9f3e11d575fec/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", size = 374220, upload-time = "2025-10-06T14:10:06.489Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3d/68bf18d50dc674b942daec86a9ba922d3113d8399b0e52b9897530442da2/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", size = 81589, upload-time = "2025-10-06T14:10:09.254Z" }, + { url = "https://files.pythonhosted.org/packages/c8/9a/6ad1a9b37c2f72874f93e691b2e7ecb6137fb2b899983125db4204e47575/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", size = 87213, upload-time = "2025-10-06T14:10:11.369Z" }, + { url = "https://files.pythonhosted.org/packages/44/c5/c21b562d1680a77634d748e30c653c3ca918beb35555cff24986fff54598/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", size = 81330, upload-time = "2025-10-06T14:10:13.112Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f3/d67de7260456ee105dc1d162d43a019ecad6b91e2f51809d6cddaa56690e/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", size = 139980, upload-time = "2025-10-06T14:10:14.601Z" }, + { url = "https://files.pythonhosted.org/packages/01/88/04d98af0b47e0ef42597b9b28863b9060bb515524da0a65d5f4db160b2d5/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", size = 93424, upload-time = "2025-10-06T14:10:16.115Z" }, + { url = "https://files.pythonhosted.org/packages/18/91/3274b215fd8442a03975ce6bee5fe6aa57a8326b29b9d3d56234a1dca244/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", size = 93821, upload-time = "2025-10-06T14:10:17.993Z" }, + { url = "https://files.pythonhosted.org/packages/61/3a/caf4e25036db0f2da4ca22a353dfeb3c9d3c95d2761ebe9b14df8fc16eb0/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", size = 373243, upload-time = "2025-10-06T14:10:19.44Z" }, + { url = "https://files.pythonhosted.org/packages/6e/9e/51a77ac7516e8e7803b06e01f74e78649c24ee1021eca3d6a739cb6ea49c/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", size = 342361, upload-time = "2025-10-06T14:10:21.124Z" }, + { url = "https://files.pythonhosted.org/packages/d4/f8/33b92454789dde8407f156c00303e9a891f1f51a0330b0fad7c909f87692/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", size = 387036, upload-time = "2025-10-06T14:10:22.902Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9a/c5db84ea024f76838220280f732970aa4ee154015d7f5c1bfb60a267af6f/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", size = 397671, upload-time = "2025-10-06T14:10:24.523Z" }, + { url = "https://files.pythonhosted.org/packages/11/c9/cd8538dc2e7727095e0c1d867bad1e40c98f37763e6d995c1939f5fdc7b1/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", size = 377059, upload-time = "2025-10-06T14:10:26.406Z" }, + { url = "https://files.pythonhosted.org/packages/a1/b9/ab437b261702ced75122ed78a876a6dec0a1b0f5e17a4ac7a9a2482d8abe/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", size = 365356, upload-time = "2025-10-06T14:10:28.461Z" }, + { url = "https://files.pythonhosted.org/packages/b2/9d/8e1ae6d1d008a9567877b08f0ce4077a29974c04c062dabdb923ed98e6fe/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", size = 361331, upload-time = "2025-10-06T14:10:30.541Z" }, + { url = "https://files.pythonhosted.org/packages/ca/5a/09b7be3905962f145b73beb468cdd53db8aa171cf18c80400a54c5b82846/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", size = 382590, upload-time = "2025-10-06T14:10:33.352Z" }, + { url = "https://files.pythonhosted.org/packages/aa/7f/59ec509abf90eda5048b0bc3e2d7b5099dffdb3e6b127019895ab9d5ef44/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", size = 385316, upload-time = "2025-10-06T14:10:35.034Z" }, + { url = "https://files.pythonhosted.org/packages/e5/84/891158426bc8036bfdfd862fabd0e0fa25df4176ec793e447f4b85cf1be4/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", size = 374431, upload-time = "2025-10-06T14:10:37.76Z" }, + { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555, upload-time = "2025-10-06T14:10:39.649Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965, upload-time = "2025-10-06T14:10:41.313Z" }, + { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205, upload-time = "2025-10-06T14:10:43.167Z" }, + { url = "https://files.pythonhosted.org/packages/88/fc/6908f062a2f77b5f9f6d69cecb1747260831ff206adcbc5b510aff88df91/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", size = 146209, upload-time = "2025-10-06T14:10:44.643Z" }, + { url = "https://files.pythonhosted.org/packages/65/47/76594ae8eab26210b4867be6f49129861ad33da1f1ebdf7051e98492bf62/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", size = 95966, upload-time = "2025-10-06T14:10:46.554Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ce/05e9828a49271ba6b5b038b15b3934e996980dd78abdfeb52a04cfb9467e/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", size = 97312, upload-time = "2025-10-06T14:10:48.007Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c5/7dffad5e4f2265b29c9d7ec869c369e4223166e4f9206fc2243ee9eea727/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", size = 361967, upload-time = "2025-10-06T14:10:49.997Z" }, + { url = "https://files.pythonhosted.org/packages/50/b2/375b933c93a54bff7fc041e1a6ad2c0f6f733ffb0c6e642ce56ee3b39970/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", size = 323949, upload-time = "2025-10-06T14:10:52.004Z" }, + { url = "https://files.pythonhosted.org/packages/66/50/bfc2a29a1d78644c5a7220ce2f304f38248dc94124a326794e677634b6cf/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", size = 361818, upload-time = "2025-10-06T14:10:54.078Z" }, + { url = "https://files.pythonhosted.org/packages/46/96/f3941a46af7d5d0f0498f86d71275696800ddcdd20426298e572b19b91ff/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", size = 372626, upload-time = "2025-10-06T14:10:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/c1/42/8b27c83bb875cd89448e42cd627e0fb971fa1675c9ec546393d18826cb50/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", size = 341129, upload-time = "2025-10-06T14:10:57.985Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/99ca3122201b382a3cf7cc937b95235b0ac944f7e9f2d5331d50821ed352/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", size = 346776, upload-time = "2025-10-06T14:10:59.633Z" }, + { url = "https://files.pythonhosted.org/packages/85/b4/47328bf996acd01a4c16ef9dcd2f59c969f495073616586f78cd5f2efb99/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", size = 334879, upload-time = "2025-10-06T14:11:01.454Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ad/b77d7b3f14a4283bffb8e92c6026496f6de49751c2f97d4352242bba3990/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", size = 350996, upload-time = "2025-10-06T14:11:03.452Z" }, + { url = "https://files.pythonhosted.org/packages/81/c8/06e1d69295792ba54d556f06686cbd6a7ce39c22307100e3fb4a2c0b0a1d/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", size = 356047, upload-time = "2025-10-06T14:11:05.115Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b8/4c0e9e9f597074b208d18cef227d83aac36184bfbc6eab204ea55783dbc5/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", size = 342947, upload-time = "2025-10-06T14:11:08.137Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943, upload-time = "2025-10-06T14:11:10.284Z" }, + { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" }, + { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" }, + { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" }, + { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" }, + { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" }, + { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" }, + { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" }, + { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" }, + { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" }, + { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" }, + { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" }, + { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" }, + { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" }, + { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" }, + { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" }, + { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" }, + { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" }, + { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" }, + { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" }, + { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" }, + { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" }, + { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" }, + { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" }, + { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" }, + { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, + { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, +] + +[[package]] +name = "zstandard" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738, upload-time = "2025-09-14T22:16:56.237Z" }, + { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436, upload-time = "2025-09-14T22:16:57.774Z" }, + { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019, upload-time = "2025-09-14T22:16:59.302Z" }, + { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012, upload-time = "2025-09-14T22:17:01.156Z" }, + { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148, upload-time = "2025-09-14T22:17:03.091Z" }, + { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652, upload-time = "2025-09-14T22:17:04.979Z" }, + { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993, upload-time = "2025-09-14T22:17:06.781Z" }, + { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806, upload-time = "2025-09-14T22:17:08.415Z" }, + { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659, upload-time = "2025-09-14T22:17:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933, upload-time = "2025-09-14T22:17:11.857Z" }, + { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008, upload-time = "2025-09-14T22:17:13.627Z" }, + { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517, upload-time = "2025-09-14T22:17:16.103Z" }, + { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292, upload-time = "2025-09-14T22:17:17.827Z" }, + { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237, upload-time = "2025-09-14T22:17:19.954Z" }, + { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, + { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, + { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" }, + { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" }, + { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" }, + { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" }, + { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" }, + { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" }, + { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" }, + { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" }, + { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" }, + { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" }, + { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" }, + { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" }, + { url = "https://files.pythonhosted.org/packages/3d/5c/f8923b595b55fe49e30612987ad8bf053aef555c14f05bb659dd5dbe3e8a/zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3", size = 795887, upload-time = "2025-09-14T22:17:54.198Z" }, + { url = "https://files.pythonhosted.org/packages/8d/09/d0a2a14fc3439c5f874042dca72a79c70a532090b7ba0003be73fee37ae2/zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f", size = 640658, upload-time = "2025-09-14T22:17:55.423Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7c/8b6b71b1ddd517f68ffb55e10834388d4f793c49c6b83effaaa05785b0b4/zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c", size = 5379849, upload-time = "2025-09-14T22:17:57.372Z" }, + { url = "https://files.pythonhosted.org/packages/a4/86/a48e56320d0a17189ab7a42645387334fba2200e904ee47fc5a26c1fd8ca/zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439", size = 5058095, upload-time = "2025-09-14T22:17:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ad/eb659984ee2c0a779f9d06dbfe45e2dc39d99ff40a319895df2d3d9a48e5/zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043", size = 5551751, upload-time = "2025-09-14T22:18:01.618Z" }, + { url = "https://files.pythonhosted.org/packages/61/b3/b637faea43677eb7bd42ab204dfb7053bd5c4582bfe6b1baefa80ac0c47b/zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859", size = 6364818, upload-time = "2025-09-14T22:18:03.769Z" }, + { url = "https://files.pythonhosted.org/packages/31/dc/cc50210e11e465c975462439a492516a73300ab8caa8f5e0902544fd748b/zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0", size = 5560402, upload-time = "2025-09-14T22:18:05.954Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ae/56523ae9c142f0c08efd5e868a6da613ae76614eca1305259c3bf6a0ed43/zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7", size = 4955108, upload-time = "2025-09-14T22:18:07.68Z" }, + { url = "https://files.pythonhosted.org/packages/98/cf/c899f2d6df0840d5e384cf4c4121458c72802e8bda19691f3b16619f51e9/zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2", size = 5269248, upload-time = "2025-09-14T22:18:09.753Z" }, + { url = "https://files.pythonhosted.org/packages/1b/c0/59e912a531d91e1c192d3085fc0f6fb2852753c301a812d856d857ea03c6/zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344", size = 5430330, upload-time = "2025-09-14T22:18:11.966Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/7e31db1240de2df22a58e2ea9a93fc6e38cc29353e660c0272b6735d6669/zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c", size = 5811123, upload-time = "2025-09-14T22:18:13.907Z" }, + { url = "https://files.pythonhosted.org/packages/f6/49/fac46df5ad353d50535e118d6983069df68ca5908d4d65b8c466150a4ff1/zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088", size = 5359591, upload-time = "2025-09-14T22:18:16.465Z" }, + { url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" }, + { url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" }, +]