diff --git a/airflow/Dockerfile b/airflow/Dockerfile index ac10035114..2dcb1a1e11 100644 --- a/airflow/Dockerfile +++ b/airflow/Dockerfile @@ -1,4 +1,4 @@ -FROM apache/airflow:2.5.3-python3.8 +FROM apache/airflow:2.10.2-python3.11 # install gcloud as root, then switch back to airflow USER root @@ -17,4 +17,4 @@ USER airflow COPY requirements.txt /tmp/requirements.txt -RUN pip install --no-cache-dir --user -r /tmp/requirements.txt +RUN pip install --no-cache-dir -r /tmp/requirements.txt diff --git a/airflow/Dockerfile.composer b/airflow/Dockerfile.composer index 1aa9e198af..4b1c541c18 100644 --- a/airflow/Dockerfile.composer +++ b/airflow/Dockerfile.composer @@ -1,4 +1,4 @@ -FROM apache/airflow:2.4.3-python3.8 +FROM apache/airflow:2.10.2-python3.11 # install gcloud as root, then switch back to airflow USER root @@ -15,8 +15,8 @@ RUN gcloud components install gke-gcloud-auth-plugin USER airflow -COPY requirements-composer-2.6.5-airflow-2.5.3.txt /tmp/requirements-composer-2.6.5-airflow-2.5.3.txt -RUN pip install --no-cache-dir --user -r /tmp/requirements-composer-2.6.5-airflow-2.5.3.txt +COPY requirements-composer-2.11.1-airflow-2.10.2.txt /tmp/requirements-composer-2.11.1-airflow-2.10.2.txt +RUN pip install --no-cache-dir --user -r /tmp/requirements-composer-2.11.1-airflow-2.10.2.txt COPY requirements.txt /tmp/requirements.txt RUN pip install --no-cache-dir --user -r /tmp/requirements.txt diff --git a/airflow/dags/airtable_loader_v2/generate_gtfs_download_configs.py b/airflow/dags/airtable_loader_v2/generate_gtfs_download_configs.py index 071f7286e6..ca3cdc9f47 100644 --- a/airflow/dags/airtable_loader_v2/generate_gtfs_download_configs.py +++ b/airflow/dags/airtable_loader_v2/generate_gtfs_download_configs.py @@ -19,7 +19,7 @@ GTFSDownloadConfigExtract, get_fs, ) -from pydantic import ValidationError +from pydantic.v1 import ValidationError def gtfs_datasets_to_extract_configs( diff --git a/airflow/dags/download_gtfs_schedule_v2/download_schedule_feeds.py b/airflow/dags/download_gtfs_schedule_v2/download_schedule_feeds.py index 38aad85c8e..dde36ccc17 100644 --- a/airflow/dags/download_gtfs_schedule_v2/download_schedule_feeds.py +++ b/airflow/dags/download_gtfs_schedule_v2/download_schedule_feeds.py @@ -24,7 +24,7 @@ get_fs, get_latest, ) -from pydantic import validator +from pydantic.v1 import validator from requests.exceptions import HTTPError GTFS_FEED_LIST_ERROR_THRESHOLD = 0.95 diff --git a/airflow/dags/sync_ntd_data_xlsx/scrape_ntd_xlsx_urls.py b/airflow/dags/sync_ntd_data_xlsx/scrape_ntd_xlsx_urls.py index e4ea42d26b..1b4150c338 100644 --- a/airflow/dags/sync_ntd_data_xlsx/scrape_ntd_xlsx_urls.py +++ b/airflow/dags/sync_ntd_data_xlsx/scrape_ntd_xlsx_urls.py @@ -6,7 +6,7 @@ import requests from bs4 import BeautifulSoup -from pydantic import HttpUrl, ValidationError, parse_obj_as +from pydantic.v1 import HttpUrl, ValidationError, parse_obj_as from airflow.exceptions import AirflowException diff --git a/airflow/plugins/operators/airtable_to_gcs.py b/airflow/plugins/operators/airtable_to_gcs.py index ee4616a2e6..30342a24f3 100644 --- a/airflow/plugins/operators/airtable_to_gcs.py +++ b/airflow/plugins/operators/airtable_to_gcs.py @@ -7,7 +7,7 @@ from calitp_data_infra.auth import get_secret_by_name from calitp_data_infra.storage import get_fs, make_name_bq_safe from pyairtable import Api -from pydantic import BaseModel +from pydantic.v1 import BaseModel from airflow.models import BaseOperator diff --git a/airflow/plugins/operators/blackcat_to_gcs.py b/airflow/plugins/operators/blackcat_to_gcs.py index 75fafa5e12..062b2472e4 100644 --- a/airflow/plugins/operators/blackcat_to_gcs.py +++ b/airflow/plugins/operators/blackcat_to_gcs.py @@ -7,7 +7,7 @@ import pendulum import requests from calitp_data_infra.storage import get_fs, make_name_bq_safe -from pydantic import BaseModel +from pydantic.v1 import BaseModel from airflow.models import BaseOperator diff --git a/airflow/plugins/operators/littlepay_raw_sync.py b/airflow/plugins/operators/littlepay_raw_sync.py index b5bd1c0984..26ad57e8af 100644 --- a/airflow/plugins/operators/littlepay_raw_sync.py +++ b/airflow/plugins/operators/littlepay_raw_sync.py @@ -16,9 +16,9 @@ get_fs, get_latest_file, ) -from pydantic.class_validators import validator -from pydantic.error_wrappers import ValidationError -from pydantic.main import BaseModel +from pydantic.v1.class_validators import validator +from pydantic.v1.error_wrappers import ValidationError +from pydantic.v1.main import BaseModel from tqdm import tqdm from tqdm.contrib.logging import logging_redirect_tqdm diff --git a/airflow/plugins/operators/scrape_ntd_api.py b/airflow/plugins/operators/scrape_ntd_api.py index 75f5ac1cfe..ac3fb193dd 100644 --- a/airflow/plugins/operators/scrape_ntd_api.py +++ b/airflow/plugins/operators/scrape_ntd_api.py @@ -11,7 +11,7 @@ get_fs, make_name_bq_safe, ) -from pydantic import HttpUrl, parse_obj_as +from pydantic.v1 import HttpUrl, parse_obj_as from airflow.exceptions import AirflowException from airflow.models import BaseOperator # type: ignore diff --git a/airflow/plugins/operators/scrape_ntd_xlsx.py b/airflow/plugins/operators/scrape_ntd_xlsx.py index 5e82ae6b5e..0e34914c92 100644 --- a/airflow/plugins/operators/scrape_ntd_xlsx.py +++ b/airflow/plugins/operators/scrape_ntd_xlsx.py @@ -12,7 +12,7 @@ get_fs, make_name_bq_safe, ) -from pydantic import HttpUrl, parse_obj_as +from pydantic.v1 import HttpUrl, parse_obj_as from airflow.exceptions import AirflowException from airflow.models import BaseOperator # type: ignore diff --git a/airflow/plugins/operators/scrape_state_geoportal.py b/airflow/plugins/operators/scrape_state_geoportal.py index 7ebbc389fe..67bd595738 100644 --- a/airflow/plugins/operators/scrape_state_geoportal.py +++ b/airflow/plugins/operators/scrape_state_geoportal.py @@ -7,7 +7,7 @@ import pendulum import requests from calitp_data_infra.storage import PartitionedGCSArtifact, get_fs # type: ignore -from pydantic import HttpUrl, parse_obj_as +from pydantic.v1 import HttpUrl, parse_obj_as from airflow.exceptions import AirflowException from airflow.models import BaseOperator # type: ignore diff --git a/airflow/plugins/utils.py b/airflow/plugins/utils.py index 4c723533b4..504c1d854e 100644 --- a/airflow/plugins/utils.py +++ b/airflow/plugins/utils.py @@ -11,7 +11,7 @@ PartitionedGCSArtifact, fetch_all_in_partition, ) -from pydantic import validator +from pydantic.v1 import validator SCHEDULE_UNZIPPED_BUCKET = os.environ["CALITP_BUCKET__GTFS_SCHEDULE_UNZIPPED"] SCHEDULE_UNZIPPED_BUCKET_HOURLY = os.environ[ diff --git a/airflow/requirements-composer-2.11.1-airflow-2.10.2.txt b/airflow/requirements-composer-2.11.1-airflow-2.10.2.txt new file mode 100644 index 0000000000..30b1967698 --- /dev/null +++ b/airflow/requirements-composer-2.11.1-airflow-2.10.2.txt @@ -0,0 +1,373 @@ +#composer-2.11.1-airflow-2.10.2 +absl-py==2.1.0 +agate==1.9.1 +aiodebug==2.3.0 +aiofiles==23.2.1 +aiohappyeyeballs==2.4.4 +aiohttp==3.11.11 +aiomysql==0.2.0 +aiosignal==1.3.2 +aiosqlite==0.20.0 +alembic==1.14.0 +amqp==5.3.1 +annotated-types==0.7.0 +anyio==4.8.0 +# apache-airflow==2.10.2+composer +apache-airflow-providers-apache-beam==6.0.0 +apache-airflow-providers-celery==3.8.5 +apache-airflow-providers-cncf-kubernetes==10.1.0 +apache-airflow-providers-common-compat==1.3.0 +apache-airflow-providers-common-io==1.5.0 +apache-airflow-providers-common-sql==1.21.0 +apache-airflow-providers-dbt-cloud==4.0.0 +apache-airflow-providers-fab==1.3.0 +apache-airflow-providers-ftp==3.12.0 +apache-airflow-providers-google==10.26.0 +apache-airflow-providers-hashicorp==4.0.0 +apache-airflow-providers-http==5.0.0 +apache-airflow-providers-imap==3.8.0 +# apache-airflow-providers-mysql==6.0.0 +apache-airflow-providers-openlineage==2.0.0 +apache-airflow-providers-postgres==5.14.0 +apache-airflow-providers-sendgrid==4.0.0 +apache-airflow-providers-smtp==1.9.0 +apache-airflow-providers-sqlite==4.0.0 +apache-airflow-providers-ssh==4.0.0 +apache-airflow-providers-standard==0.0.3 +apache-beam==2.61.0 +apispec==6.8.1 +appdirs==1.4.4 +argcomplete==3.5.3 +asgiref==3.8.1 +astunparse==1.6.3 +attrs==24.3.0 +babel==2.16.0 +backoff==2.2.1 +backports.tarfile==1.2.0 +bcrypt==4.2.1 +billiard==4.2.1 +blinker==1.9.0 +CacheControl==0.14.2 +cachelib==0.9.0 +cachetools==5.5.0 +cattrs==24.1.2 +celery==5.4.0 +certifi==2024.12.14 +cffi==1.17.1 +chardet==5.2.0 +charset-normalizer==3.4.1 +click==8.1.8 +click-didyoumean==0.3.1 +click-plugins==1.1.1 +click-repl==0.3.0 +clickclick==20.10.2 +cloudpickle==2.2.1 +colorama==0.4.6 +colorlog==6.9.0 +ConfigUpdater==3.2 +connexion==2.14.2 +crcmod==1.7 +cron-descriptor==1.4.5 +croniter==6.0.0 +cryptography==43.0.3 +daff==1.3.46 +db-dtypes==1.3.1 +dbt-adapters==1.7.0 +dbt-bigquery==1.9.1 +dbt-common==1.10.0 +dbt-core==1.8.8 +dbt-extractor==0.5.1 +dbt-semantic-interfaces==0.5.1 +decorator==5.1.1 +deepdiff==7.0.1 +Deprecated==1.2.15 +diff_cover==9.2.1 +dill==0.3.1.1 +distlib==0.3.9 +dnspython==2.7.0 +docopt==0.6.2 +docstring_parser==0.16 +durationpy==0.9 +email_validator==2.2.0 +fastavro==1.10.0 +fasteners==0.19 +filelock==3.15.4 +firebase-admin==6.6.0 +Flask==2.2.5 +Flask-AppBuilder==4.5.0 +Flask-Babel==2.0.0 +Flask-Bcrypt==1.0.1 +Flask-Caching==2.3.0 +Flask-JWT-Extended==4.7.1 +Flask-Limiter==3.10.0 +Flask-Login==0.6.3 +Flask-Session==0.5.0 +Flask-SQLAlchemy==2.5.1 +Flask-WTF==1.2.2 +flatbuffers==24.12.23 +flower==2.0.1 +frozenlist==1.5.0 +fsspec==2024.12.0 +gast==0.6.0 +gcloud-aio-auth==5.3.2 +gcloud-aio-bigquery==7.1.0 +gcloud-aio-storage==9.3.0 +gcsfs==2024.12.0 +google-ads==25.1.0 +google-analytics-admin==0.23.3 +google-api-core==2.24.0 +google-api-python-client==2.158.0 +google-apitools==0.5.32 +google-auth==2.37.0 +google-auth-httplib2==0.2.0 +google-auth-oauthlib==1.2.1 +google-cloud-access-context-manager==0.2.1 +google-cloud-aiplatform==1.76.0 +google-cloud-appengine-logging==1.5.0 +google-cloud-asset==3.28.0 +google-cloud-audit-log==0.3.0 +google-cloud-automl==2.15.0 +google-cloud-batch==0.17.33 +google-cloud-bigquery==3.27.0 +google-cloud-bigquery-datatransfer==3.18.0 +google-cloud-bigtable==2.28.0 +google-cloud-build==3.28.0 +google-cloud-common==1.4.0 +google-cloud-compute==1.23.0 +google-cloud-container==2.55.0 +google-cloud-core==2.4.1 +google-cloud-datacatalog==3.24.1 +google-cloud-datacatalog-lineage==0.3.11 +# google-cloud-datacatalog-lineage-producer-client==0.2.2 +google-cloud-dataflow-client==0.8.15 +google-cloud-dataform==0.5.14 +google-cloud-dataplex==2.6.0 +google-cloud-dataproc==5.16.0 +google-cloud-dataproc-metastore==1.17.0 +google-cloud-datastore==2.20.2 +google-cloud-dlp==3.26.0 +google-cloud-documentai==3.1.0 +google-cloud-filestore==1.11.0 +google-cloud-firestore==2.19.0 +google-cloud-kms==3.2.1 +google-cloud-language==2.16.0 +google-cloud-logging==3.11.3 +google-cloud-memcache==1.11.0 +google-cloud-monitoring==2.25.0 +google-cloud-orchestration-airflow==1.16.0 +google-cloud-org-policy==1.12.0 +google-cloud-os-config==1.19.0 +google-cloud-os-login==2.16.0 +google-cloud-pubsub==2.27.2 +google-cloud-pubsublite==0.6.1 +google-cloud-redis==2.17.0 +google-cloud-resource-manager==1.14.0 +google-cloud-run==0.10.14 +google-cloud-secret-manager==2.22.0 +google-cloud-spanner==3.51.0 +google-cloud-speech==2.30.0 +google-cloud-storage==2.19.0 +google-cloud-storage-transfer==1.15.0 +google-cloud-tasks==2.18.0 +google-cloud-texttospeech==2.23.0 +google-cloud-translate==3.19.0 +google-cloud-videointelligence==2.15.0 +google-cloud-vision==3.9.0 +google-cloud-workflows==1.16.0 +google-crc32c==1.6.0 +google-pasta==0.2.0 +google-re2==1.1.20240702 +google-resumable-media==2.7.2 +googleapis-common-protos==1.66.0 +greenlet==3.1.1 +grpc-google-iam-v1==0.14.0 +grpc-interceptor==0.15.4 +grpcio==1.65.5 +grpcio-gcp==0.2.2 +grpcio-status==1.62.3 +gunicorn==23.0.0 +h11==0.14.0 +h5py==3.12.1 +hdfs==2.7.3 +httpcore==1.0.7 +httplib2==0.22.0 +httpx==0.28.1 +humanize==4.11.0 +hvac==2.3.0 +idna==3.10 +immutabledict==4.2.1 +importlib-metadata==6.11.0 +inflection==0.5.1 +iniconfig==2.0.0 +isodate==0.6.1 +itsdangerous==2.2.0 +jaraco.classes==3.4.0 +jaraco.context==6.0.1 +jaraco.functools==4.1.0 +jeepney==0.8.0 +Jinja2==3.1.5 +jmespath==1.0.1 +json-merge-patch==0.2 +jsonpickle==3.4.2 +jsonschema==4.23.0 +jsonschema-specifications==2024.10.1 +keras==3.8.0 +keyring==25.5.0 +keyrings.google-artifactregistry-auth==1.1.2 +kombu==5.4.2 +kubernetes==31.0.0 +kubernetes_asyncio==30.3.1 +lazy-object-proxy==1.10.0 +leather==0.4.0 +libclang==18.1.1 +limits==4.0.0 +linkify-it-py==2.0.3 +lockfile==0.12.2 +Logbook==1.5.3 +looker-sdk==24.20.0 +Mako==1.3.8 +Markdown==3.7 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +marshmallow==3.25.1 +marshmallow-oneofschema==3.1.1 +marshmallow-sqlalchemy==0.28.2 +mashumaro==3.15 +mdit-py-plugins==0.4.2 +mdurl==0.1.2 +methodtools==0.4.7 +minimal-snowplow-tracker==0.0.2 +ml-dtypes==0.4.1 +more-itertools==10.5.0 +msgpack==1.1.0 +multidict==6.1.0 +# mysql-connector-python==9.1.0 +# mysqlclient==2.2.7 -- requires MYSQLCLIENT_CFLAGS and MYSQLCLIENT_LDFLAGS env variables; since we don't use MySQL, just disabling. +namex==0.0.8 +networkx==3.4.2 +numpy==1.26.4 +oauth2client==4.1.3 +oauthlib==3.2.2 +objsize==0.7.0 +openlineage-integration-common==1.26.0 +openlineage-python==1.26.0 +openlineage_sql==1.26.0 +opentelemetry-api==1.27.0 +opentelemetry-exporter-otlp==1.27.0 +opentelemetry-exporter-otlp-proto-common==1.27.0 +opentelemetry-exporter-otlp-proto-grpc==1.27.0 +opentelemetry-exporter-otlp-proto-http==1.27.0 +opentelemetry-proto==1.27.0 +opentelemetry-sdk==1.27.0 +opentelemetry-semantic-conventions==0.48b0 +opt_einsum==3.4.0 +optree==0.13.1 +ordered-set==4.1.0 +orjson==3.10.14 +overrides==6.5.0 +packaging==24.2 +pandas==2.1.4 +pandas-gbq==0.26.1 +paramiko==3.5.0 +parsedatetime==2.6 +pathspec==0.12.1 +pendulum==3.0.0 +pip==23.2.1 +pipdeptree==2.23.1 +platformdirs==4.3.6 +pluggy==1.5.0 +prison==0.2.1 +prometheus_client==0.21.1 +prompt_toolkit==3.0.48 +propcache==0.2.1 +proto-plus==1.25.0 +protobuf==4.25.5 +psutil==6.1.1 +psycopg2-binary==2.9.10 +pyarrow==16.1.0 +pyarrow-hotfix==0.6 +pyasn1==0.6.1 +pyasn1_modules==0.4.0 +pycparser==2.22 +pydantic==2.10.5 +pydantic_core==2.27.2 +pydata-google-auth==1.9.0 +pydot==1.4.2 +Pygments==2.19.1 +PyJWT==2.10.1 +pymongo==4.10.1 +# PyMySQL==1.1.1 +PyNaCl==1.5.0 +pyOpenSSL==25.0.0 +pyparsing==3.2.1 +pytest==8.3.4 +python-daemon==3.1.2 +python-dateutil==2.9.0.post0 +python-http-client==3.3.7 +python-nvd3==0.16.0 +python-slugify==8.0.4 +pytimeparse==1.1.8 +pytz==2024.2 +PyYAML==6.0.2 +redis==5.2.1 +referencing==0.35.1 +regex==2024.11.6 +requests==2.32.3 +requests-oauthlib==2.0.0 +requests-toolbelt==1.0.0 +rfc3339-validator==0.1.4 +rich==13.9.4 +rich-argparse==1.6.0 +rpds-py==0.22.3 +rsa==4.9 +SecretStorage==3.3.3 +sendgrid==6.11.0 +setproctitle==1.3.4 +setuptools==75.8.0 +shapely==2.0.6 +six==1.17.0 +sniffio==1.3.1 +sortedcontainers==2.4.0 +SQLAlchemy==1.4.54 +sqlalchemy-bigquery==1.12.0 +SQLAlchemy-JSONField==1.0.2 +sqlalchemy-spanner==1.8.0 +SQLAlchemy-Utils==0.41.2 +sqlfluff==2.3.3 +sqllineage==1.4.8 +sqlparse==0.5.3 +sshtunnel==0.4.0 +starkbank-ecdsa==2.2.0 +statsd==4.0.1 +tabulate==0.9.0 +tblib==3.0.0 +tenacity==9.0.0 +tensorboard==2.18.0 +tensorboard-data-server==0.7.2 +tensorflow==2.18.0 +tensorflow-io-gcs-filesystem==0.37.1 +termcolor==2.5.0 +text-unidecode==1.3 +time-machine==2.16.0 +tornado==6.4.2 +tqdm==4.67.1 +typing_extensions==4.12.2 +tzdata==2024.2 +uc-micro-py==1.0.3 +unicodecsv==0.14.1 +universal_pathlib==0.2.6 +uritemplate==4.1.1 +urllib3==2.2.3 +vine==5.1.0 +virtualenv==20.28.1 +wcwidth==0.2.13 +websocket-client==1.8.0 +websockets==14.1 +Werkzeug==2.2.3 +wheel==0.45.1 +wirerope==0.4.8 +wrapt==1.17.1 +WTForms==3.1.2 +yarl==1.18.3 +zipp==3.21.0 +zstandard==0.23.0 diff --git a/airflow/requirements.txt b/airflow/requirements.txt index 834732006d..3a7fbfeb43 100644 --- a/airflow/requirements.txt +++ b/airflow/requirements.txt @@ -1,10 +1,10 @@ calitp-data-infra==2025.1.30 gusty==0.6.0 pyairtable==2.2.1 -pydantic==1.9 +pydantic>=1.9 # 2.10.5 for latest composer typer==0.4.1 sentry-sdk==1.17.0 -platformdirs<3,>=2.5 -boto3==1.26.87 +platformdirs>=2.5 # 4.3.6 for latest composer +boto3>=1.26.87 # 1.36.15 for latest composer openpyxl==3.1.5 beautifulsoup4==4.12.3 diff --git a/packages/calitp-data-infra/calitp_data_infra/storage.py b/packages/calitp-data-infra/calitp_data_infra/storage.py index 4fe57d66cf..706d936f88 100644 --- a/packages/calitp-data-infra/calitp_data_infra/storage.py +++ b/packages/calitp-data-infra/calitp_data_infra/storage.py @@ -28,7 +28,7 @@ import humanize import pendulum from google.cloud import storage # type: ignore -from pydantic import ( +from pydantic.v1 import ( BaseModel, ConstrainedStr, Extra, @@ -37,8 +37,8 @@ ValidationError, validator, ) -from pydantic.class_validators import root_validator -from pydantic.tools import parse_obj_as +from pydantic.v1.class_validators import root_validator +from pydantic.v1.tools import parse_obj_as from requests import Request, Session from typing_extensions import Annotated, Literal diff --git a/packages/calitp-data-infra/pyproject.toml b/packages/calitp-data-infra/pyproject.toml index ba5c39f8b0..a09b286cd3 100644 --- a/packages/calitp-data-infra/pyproject.toml +++ b/packages/calitp-data-infra/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "calitp-data-infra" -version = "2025.1.30" +version = "2025.2.4" description = "Shared code for developing data pipelines that process Cal-ITP data." package-mode = true authors = ["Andrew Vaccaro"] @@ -8,14 +8,14 @@ authors = ["Andrew Vaccaro"] [tool.poetry.dependencies] python = ">=3.8,<3.12" # Some of these are pinned oddly to play nicely with Composer -pydantic = "~1.9" +pydantic = ">1.9" tqdm = "^4.64.1" -pendulum = "^2.1.2" +pendulum = ">2.1.2" humanize = "^4.6.0" backoff = "^2.2.1" google-api-core = ">=1.31.4" typing-extensions = ">=3.10.0.2" -google-cloud-secret-manager = "2.16.4" +google-cloud-secret-manager = ">2.16.4" gcsfs = "!=2022.7.1" [tool.poetry.group.dev.dependencies] diff --git a/packages/calitp-data-infra/tests/test_storage.py b/packages/calitp-data-infra/tests/test_storage.py index e3955eed4c..89253d2cb8 100644 --- a/packages/calitp-data-infra/tests/test_storage.py +++ b/packages/calitp-data-infra/tests/test_storage.py @@ -1,7 +1,7 @@ import pendulum import pytest from calitp_data_infra.storage import GTFSDownloadConfig -from pydantic import ValidationError +from pydantic.v1 import ValidationError def test_gtfs_download_config() -> None: