From edcbf3bc0cceb907aa2bdffa82383605e94dac5e Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Sun, 8 Aug 2021 16:22:27 -0400 Subject: [PATCH 01/17] new DAG operator imports for Airflow 2.0+ --- scripts/dag_imports.json | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/scripts/dag_imports.json b/scripts/dag_imports.json index 9af103771..302ced257 100644 --- a/scripts/dag_imports.json +++ b/scripts/dag_imports.json @@ -1,5 +1,5 @@ { - "1.10.15": { + "1": { "BashOperator": { "import": "from airflow.operators import bash_operator", "class": "bash_operator.BashOperator" @@ -28,5 +28,31 @@ "import": "from airflow.contrib.operators import gcs_delete_operator", "class": "gcs_delete_operator.GoogleCloudStorageDeleteOperator" } + }, + "2": { + "BashOperator": { + "import": "from airflow.operators import bash", + "class": "bash.BashOperator" + }, + "GoogleCloudStorageToBigQueryOperator": { + "import": "from airflow.providers.google.cloud.transfers import gcs_to_bigquery", + "class": "gcs_to_bigquery.GCSToBigQueryOperator" + }, + "GoogleCloudStorageToGoogleCloudStorageOperator": { + "import": "from airflow.providers.google.cloud.transfers import gcs_to_gcs", + "class": "gcs_to_gcs.GCSToGCSOperator" + }, + "GoogleCloudStorageDeleteOperator": { + "import": "from airflow.providers.google.cloud.operators import gcs", + "class": "gcs.GCSDeleteObjectsOperator" + }, + "BigQueryInsertJobOperator": { + "import": "from airflow.providers.google.cloud.operators import bigquery", + "class": "bigquery.BigQueryInsertJobOperator" + }, + "KubernetesPodOperator": { + "import": "from airflow.providers.cncf.kubernetes.operators import kubernetes_pod", + "class": "kubernetes_pod.KubernetesPodOperator" + } } } From 8482173a37451dcdd01ccacf12e3b0df524268b6 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Sun, 8 Aug 2021 16:27:55 -0400 Subject: [PATCH 02/17] support Airflow 2 operators when generating DAGs --- scripts/generate_dag.py | 67 ++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 44 deletions(-) diff --git a/scripts/generate_dag.py b/scripts/generate_dag.py index 0aeb40039..596900aea 100644 --- a/scripts/generate_dag.py +++ b/scripts/generate_dag.py @@ -50,7 +50,7 @@ "default_args": AIRFLOW_TEMPLATES_PATH / "default_args.py.jinja2", } -AIRFLOW_VERSION = "1.10.15" +DEFAULT_AIRFLOW_VERSION = 1 AIRFLOW_IMPORTS = json.load(open(CURRENT_PATH / "dag_imports.json")) @@ -80,24 +80,18 @@ def generate_pipeline_dag(dataset_id: str, pipeline_id: str, env: str): validate_dag_id_existence_and_format(config) dag_contents = generate_dag(config, dataset_id) - target_path = pipeline_dir / f"{pipeline_id}_dag.py" - create_file_in_dot_and_project_dirs( - dataset_id, - pipeline_id, - dag_contents, - target_path.name, - PROJECT_ROOT / f".{env}", - ) - write_to_file(dag_contents, target_path) + dag_path = pipeline_dir / f"{pipeline_id}_dag.py" + dag_path.touch() + write_to_file(dag_contents, dag_path) + format_python_code(dag_path) - copy_custom_callables_to_dot_dir( + copy_files_to_dot_dir( dataset_id, pipeline_id, PROJECT_ROOT / f".{env}", ) print_airflow_variables(dataset_id, dag_contents, env) - format_python_code(target_path) def generate_dag(config: dict, dataset_id: str) -> str: @@ -111,16 +105,18 @@ def generate_dag(config: dict, dataset_id: str) -> str: def generate_package_imports(config: dict) -> str: + _airflow_version = airflow_version(config) contents = {"from airflow import DAG"} for task in config["dag"]["tasks"]: - contents.add(AIRFLOW_IMPORTS[AIRFLOW_VERSION][task["operator"]]["import"]) + contents.add(AIRFLOW_IMPORTS[_airflow_version][task["operator"]]["import"]) return "\n".join(contents) def generate_tasks(config: dict) -> list: + _airflow_version = airflow_version(config) contents = [] for task in config["dag"]["tasks"]: - contents.append(generate_task_contents(task)) + contents.append(generate_task_contents(task, _airflow_version)) return contents @@ -138,11 +134,11 @@ def generate_dag_context(config: dict, dataset_id: str) -> str: ) -def generate_task_contents(task: dict) -> str: +def generate_task_contents(task: dict, airflow_version: str) -> str: validate_task(task) return jinja2.Template(TEMPLATE_PATHS["task"].read_text()).render( **task, - namespaced_operator=AIRFLOW_IMPORTS[AIRFLOW_VERSION][task["operator"]]["class"], + namespaced_operator=AIRFLOW_IMPORTS[airflow_version][task["operator"]]["class"], ) @@ -156,6 +152,10 @@ def dag_init(config: dict) -> dict: return config["dag"].get("initialize") or config["dag"].get("init") +def airflow_version(config: dict) -> str: + return str(config["dag"].get("airflow_version", DEFAULT_AIRFLOW_VERSION)) + + def namespaced_dag_id(dag_id: str, dataset_id: str) -> str: return f"{dataset_id}.{dag_id}" @@ -219,34 +219,13 @@ def print_airflow_variables(dataset_id: str, dag_contents: str, env: str): print() -def create_file_in_dot_and_project_dirs( - dataset_id: str, - pipeline_id: str, - contents: str, - filename: str, - env_dir: pathlib.Path, -): - print("\nCreated\n") - for prefix in ( - env_dir / "datasets" / dataset_id / pipeline_id, - DATASETS_PATH / dataset_id / pipeline_id, - ): - prefix.mkdir(parents=True, exist_ok=True) - target_path = prefix / filename - write_to_file(contents + "\n", target_path) - print(f" - {target_path.relative_to(PROJECT_ROOT)}") - - -def copy_custom_callables_to_dot_dir( - dataset_id: str, pipeline_id: str, env_dir: pathlib.Path -): - callables_dir = DATASETS_PATH / dataset_id / pipeline_id / "custom" - if callables_dir.exists(): - target_dir = env_dir / "datasets" / dataset_id / pipeline_id - target_dir.mkdir(parents=True, exist_ok=True) - subprocess.check_call( - ["cp", "-rf", str(callables_dir), str(target_dir)], cwd=PROJECT_ROOT - ) +def copy_files_to_dot_dir(dataset_id: str, pipeline_id: str, env_dir: pathlib.Path): + source_dir = PROJECT_ROOT / "datasets" / dataset_id / pipeline_id + target_dir = env_dir / "datasets" / dataset_id + target_dir.mkdir(parents=True, exist_ok=True) + subprocess.check_call( + ["cp", "-rf", str(source_dir), str(target_dir)], cwd=PROJECT_ROOT + ) def build_images(dataset_id: str, env: str): From 3ec84495b8fd57c4daaa9998e1b1924c6f1c16cb Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Sun, 8 Aug 2021 16:29:33 -0400 Subject: [PATCH 03/17] version compatibility checks for DAGs and Airflow environments --- scripts/deploy_dag.py | 76 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/scripts/deploy_dag.py b/scripts/deploy_dag.py index 94e5be055..cf1e6bdf4 100644 --- a/scripts/deploy_dag.py +++ b/scripts/deploy_dag.py @@ -14,14 +14,24 @@ import argparse +import json import pathlib import subprocess import typing import warnings +from ruamel import yaml + +yaml = yaml.YAML(typ="safe") + CURRENT_PATH = pathlib.Path(__file__).resolve().parent PROJECT_ROOT = CURRENT_PATH.parent DATASETS_PATH = PROJECT_ROOT / "datasets" +DEFAULT_AIRFLOW_VERSION = 1 + + +class IncompatibilityError(Exception): + pass def main( @@ -44,11 +54,18 @@ def main( print("========== AIRFLOW DAGS ==========") if pipeline: - pipelines = [env_path / "datasets" / pipeline] + pipelines = [env_path / "datasets" / dataset_id / pipeline] else: pipelines = list_subdirs(env_path / "datasets" / dataset_id) + # if local: + # runtime_airflow_version = local_airflow_version() + # else: + # runtime_airflow_version = composer_airflow_version(composer_env, composer_region) + for pipeline_path in pipelines: + # check_airflow_version_compatibility(pipeline_path, runtime_airflow_version) + copy_custom_callables_to_airflow_dags_folder( local, env_path, @@ -127,6 +144,7 @@ def run_cloud_composer_vars_import( subprocess.check_call( [ "gcloud", + "beta", "composer", "environments", "run", @@ -135,7 +153,7 @@ def run_cloud_composer_vars_import( str(composer_region), "variables", "--", - "--import", + "import", str(airflow_path), ], cwd=cwd, @@ -266,6 +284,60 @@ def list_subdirs(path: pathlib.Path) -> typing.List[pathlib.Path]: return subdirs +def local_airflow_version() -> str: + airflow_version = subprocess.run( + ["airflow", "version"], stdout=subprocess.PIPE + ).stdout.decode("utf-8") + return 2 if airflow_version.startswith("2") else 1 + + +def composer_airflow_version(composer_env: str, composer_region: str) -> str: + composer_env = json.loads( + subprocess.run( + [ + "gcloud", + "composer", + "environments", + "describe", + composer_env, + "--location", + composer_region, + "--format", + "json", + ], + stdout=subprocess.PIPE, + ).stdout.decode("utf-8") + ) + + # Example image version: composer-1.17.0-preview.8-airflow-2.1.1 + image_version = composer_env["config"]["softwareConfig"]["imageVersion"] + + airflow_version = image_version.split("-airflow-")[-1] + return 2 if airflow_version.startswith("2") else 1 + + +def get_dag_airflow_version(config: dict) -> int: + return config["dag"].get("airflow_version", DEFAULT_AIRFLOW_VERSION) + + +def check_airflow_version_compatibility( + pipeline_path: pathlib.Path, runtime_airflow_version: int +) -> None: + """If a DAG uses Airflow 2 operators but the runtime version uses Airflow 1, + raise a compatibility error. On the other hand, DAGs using Airflow 1.x operators + can still run in an Airflow 2 runtime environment via backport providers. + """ + dag_airflow_version = get_dag_airflow_version( + yaml.load((pipeline_path / "pipeline.yaml").read_text()) + ) + + if dag_airflow_version > runtime_airflow_version: + raise IncompatibilityError( + f"The DAG {pipeline_path.name} uses Airflow 2, but" + " you are deploying to an Airflow 1.x environment." + ) + + if __name__ == "__main__": parser = argparse.ArgumentParser( description="Deploy DAGs and variables to an Airflow environment" From 32b7ebc98cdc7d109dab7e7d82ee608eac1d729a Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Sun, 8 Aug 2021 16:33:43 -0400 Subject: [PATCH 04/17] tests to copy pipeline.yaml to dot folder (for airflow version spec) --- tests/scripts/test_deploy_dag.py | 8 ++++++++ tests/scripts/test_generate_dag.py | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/tests/scripts/test_deploy_dag.py b/tests/scripts/test_deploy_dag.py index 25d189259..0a8924564 100644 --- a/tests/scripts/test_deploy_dag.py +++ b/tests/scripts/test_deploy_dag.py @@ -90,6 +90,13 @@ def copy_config_files_and_set_tmp_folder_names_as_ids( ) ) generate_dag.write_to_file(pipeline_yaml_str, pipeline_path / "pipeline.yaml") + (ENV_DATASETS_PATH / dataset_path.name / pipeline_path.name).mkdir( + parents=True, exist_ok=True + ) + shutil.copyfile( + pipeline_path / "pipeline.yaml", + ENV_DATASETS_PATH / dataset_path.name / pipeline_path.name / "pipeline.yaml", + ) def create_airflow_folders(airflow_home: pathlib.Path): @@ -204,6 +211,7 @@ def test_script_can_deploy_without_variables_files( mocker.patch("scripts.deploy_dag.run_gsutil_cmd") mocker.patch("scripts.deploy_dag.run_cloud_composer_vars_import") + mocker.patch("scripts.deploy_dag.composer_airflow_version", return_value=1) deploy_dag.main( local=False, diff --git a/tests/scripts/test_generate_dag.py b/tests/scripts/test_generate_dag.py index f0f0b3b0f..5d94e6d32 100644 --- a/tests/scripts/test_generate_dag.py +++ b/tests/scripts/test_generate_dag.py @@ -110,6 +110,20 @@ def test_main_generates_dag_files( assert (path_prefix / f"{pipeline_path.name}_dag.py").exists() +def test_main_copies_pipeline_yaml_file( + dataset_path: pathlib.Path, pipeline_path: pathlib.Path, env: str +): + copy_config_files_and_set_tmp_folder_names_as_ids(dataset_path, pipeline_path) + + generate_dag.main(dataset_path.name, pipeline_path.name, env) + + for path_prefix in ( + pipeline_path, + ENV_DATASETS_PATH / dataset_path.name / pipeline_path.name, + ): + assert (path_prefix / "pipeline.yaml").exists() + + def test_main_copies_custom_dir_if_it_exists( dataset_path: pathlib.Path, pipeline_path: pathlib.Path, env: str ): From f780f902247902a8d38e8bf49963dd36aa58f0c4 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Sun, 8 Aug 2021 16:34:15 -0400 Subject: [PATCH 05/17] tests for version compatibility checks --- tests/scripts/test_deploy_dag.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/scripts/test_deploy_dag.py b/tests/scripts/test_deploy_dag.py index 0a8924564..3a855541e 100644 --- a/tests/scripts/test_deploy_dag.py +++ b/tests/scripts/test_deploy_dag.py @@ -225,6 +225,37 @@ def test_script_can_deploy_without_variables_files( ) +def test_script_errors_out_when_deploying_airflow2_dag_to_airflow1_env( + dataset_path: pathlib.Path, + pipeline_path: pathlib.Path, + airflow_home: pathlib.Path, + env: str, + mocker, +): + setup_dag_and_variables( + dataset_path, + pipeline_path, + airflow_home, + env, + f"{dataset_path.name}_variables.json", + ) + + mocker.patch("scripts.deploy_dag.get_dag_airflow_version", return_value=2) + mocker.patch("scripts.deploy_dag.composer_airflow_version", return_value=1) + + with pytest.raises(Exception): + deploy_dag.main( + local=False, + env_path=ENV_PATH, + dataset_id=dataset_path.name, + pipeline=pipeline_path.name, + airflow_home=airflow_home, + composer_env="test-env", + composer_bucket="test-bucket", + composer_region="test-region", + ) + + def test_script_with_pipeline_arg_deploys_only_that_pipeline( dataset_path: pathlib.Path, pipeline_path: pathlib.Path, From e4338f0176bc714c9b40804f7690dd59ce6f3c97 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Mon, 9 Aug 2021 16:07:29 -0400 Subject: [PATCH 06/17] revised pipeline YAML template for Airflow 1 compat --- samples/pipeline.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/samples/pipeline.yaml b/samples/pipeline.yaml index ea4cf77dc..a63b98d84 100644 --- a/samples/pipeline.yaml +++ b/samples/pipeline.yaml @@ -12,6 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. + +# ===== NOTE ===== +# This YAML config template is used to write DAGs that use Airflow 1.10 operators. +# You can keep using this template when deploying to an environment that uses Airflow 2, +# they will keep working due to backport compatibility. +# +# For tracking progress on the YAML config templates that use Airflow 2 operators, see +# https://github.com/GoogleCloudPlatform/public-datasets-pipelines/issues/137. + --- resources: # A list of GCP resources that are unique and specific to your pipeline. @@ -58,6 +67,9 @@ resources: deletion_protection: true dag: + # Specify the Airflow version of the operators used by the DAG. Defaults to Airflow 1 when unspecified. + airflow_version: 1 + # The DAG acronym stands for directed acyclic graph. This block represents # your data pipeline along with every property and configuration it needs to # onboard your data. From 9249214f6241cbadb3afef9006079b8981054134 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Mon, 9 Aug 2021 16:42:29 -0400 Subject: [PATCH 07/17] feat!: Upgrade dependencies to Airflow 2.1.1 (#135) * revised dependendices for Airflow 2.1.1 * use proper variables file as required by Airflow 2 * changed README to use Airflow 2 requirement * uncommented deploy_dag_versioning check * feat: Upgrade `usa_names` pipeline to usse Airflow 2 operators and environment (#136) --- Pipfile | 8 +- Pipfile.lock | 1407 ++++++++++------- README.md | 4 +- .../usa_names/usa_1910_current/pipeline.yaml | 1 + .../usa_1910_current/usa_1910_current_dag.py | 8 +- requirements-dev.txt | 214 +-- scripts/deploy_dag.py | 12 +- scripts/generate_dag.py | 6 +- 8 files changed, 1027 insertions(+), 633 deletions(-) diff --git a/Pipfile b/Pipfile index 915458379..e69398802 100644 --- a/Pipfile +++ b/Pipfile @@ -7,7 +7,9 @@ name = "pypi" beautifulsoup4 = "==4.9.3" [dev-packages] -apache-airflow = {version = "==1.10.15", extras = ["google"]} +apache-airflow = "==2.1.1" +apache-airflow-providers-google = "*" +apache-airflow-providers-cncf-kubernetes = "*" black = "==20.8b1" flake8 = "==3.9.2" isort = "*" @@ -16,8 +18,8 @@ pandas-gbq = "==0.14.1" pytest-mock = "*" pytest = "*" "ruamel.yaml" = "==0.17.10" -Jinja2 = "*" -SQLAlchemy = "==1.3.15" +Jinja2 = "==2.11.3" +SQLAlchemy = "==1.3.18" [requires] python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index 4d2f1fe9e..41ee53ec1 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5adbe6a3ed45425119e46c954d2b3673b59d16719ad2d41f267e2bd29fa94c31" + "sha256": "f459633c615c656f05ddee0c6a5096e3799171fb9482f7ce2966ab4e97ffcf85" }, "pipfile-spec": 6, "requires": { @@ -43,26 +43,72 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==1.6.5" }, + "anyio": { + "hashes": [ + "sha256:929a6852074397afe1d989002aa96d457e3e1e5441357c60d03e7eea0e65e1b0", + "sha256:ae57a67583e5ff8b4af47666ff5651c3732d45fd26c929253748e796af860374" + ], + "markers": "python_full_version >= '3.6.2'", + "version": "==3.3.0" + }, "apache-airflow": { - "extras": [ - "google" + "hashes": [ + "sha256:1eab49f278b154b5c3748e7db9e390fb0c39fd22f08fe8b3dfbf207bcd03b3c0", + "sha256:99188c212c46a54ee1fde8c67314459c0f9dac15dc43d8a06de0c795c97fb321" ], + "index": "pypi", + "version": "==2.1.1" + }, + "apache-airflow-providers-cncf-kubernetes": { "hashes": [ - "sha256:25ac3988e1f2ca20c14b397fdb21ac6b160d868ff319c474af944b4b2b46db63", - "sha256:7df77ab7b05a768fe5b49483b990f023abcdd8f031a469003f733f308d5a67ab" + "sha256:4efecd18a9f0daa1e37f09c2d952f114b10f0507cafb8dd23630dca0092bf8aa", + "sha256:81ca71025a68f18ebba79de8f005798a10bc1ed75d60ef60fefe44704ec0fa89" ], "index": "pypi", - "version": "==1.10.15" + "version": "==2.0.1" + }, + "apache-airflow-providers-ftp": { + "hashes": [ + "sha256:09bb3fc41e8839267ff5f0c2a84370299161d6092ff20cdaa970e3b7e171f3f5", + "sha256:39b2cb20b2eea77961da1ab57c7a2d03942708e0064c9ffb1ec877658f30adbe" + ], + "markers": "python_version ~= '3.6'", + "version": "==2.0.0" + }, + "apache-airflow-providers-google": { + "hashes": [ + "sha256:d3a96ad53b191d1e0f68153aaf8963f88e5dd9b50fed85a5b97bab4b3ee8b48b", + "sha256:db7ed139a2e7750918c7cdf798292dd1e4c40b7e244d3d797edd95f4290e611f" + ], + "index": "pypi", + "version": "==5.0.0" + }, + "apache-airflow-providers-imap": { + "hashes": [ + "sha256:21d3c986c5f4dd1ba0376fe61ff01be2fd73f5131b6cc42c33a120196c6175ae", + "sha256:6f777185ce1df9ef7c690fd676d3e4a5250d3226638a5fbc3abca44cce68a866" + ], + "markers": "python_version ~= '3.6'", + "version": "==2.0.0" + }, + "apache-airflow-providers-sqlite": { + "hashes": [ + "sha256:26fb9d20e3833a01aa7d6d134b417431d7c1889fd25036bd2fda13ea7f2d8579", + "sha256:817c8a5e3d8768124cd75301a84866733d7496805040ba426854073dd9311224" + ], + "markers": "python_version ~= '3.6'", + "version": "==2.0.0" }, "apispec": { "extras": [ "yaml" ], "hashes": [ - "sha256:13088129b657789671d18e5022f4f9e6ec9ec38742d301285232f11d1d35976c", - "sha256:de3c6cb97b50e16a0123ddd449002f10a48fafdd789fcfe7771d60d36b700ea1" + "sha256:a1df9ec6b2cd0edf45039ef025abd7f0660808fa2edf737d3ba1cf5ef1a4625b", + "sha256:d23ebd5b71e541e031b02a19db10b5e6d5ef8452c552833e3e1afc836b40b1ad" ], - "version": "==1.3.3" + "markers": "python_full_version >= '3.5.0'", + "version": "==3.3.2" }, "appdirs": { "hashes": [ @@ -94,6 +140,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.9.1" }, + "backports.entry-points-selectable": { + "hashes": [ + "sha256:988468260ec1c196dab6ae1149260e2f5472c9110334e5d51adcb77867361f6a", + "sha256:a6d9a871cde5e15b4c4a53e3d43ba890cc6861ec1332c9c2428c92f977192acc" + ], + "markers": "python_version >= '2.7'", + "version": "==1.1.0" + }, "black": { "hashes": [ "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea" @@ -101,12 +155,11 @@ "index": "pypi", "version": "==20.8b1" }, - "cached-property": { + "blinker": { "hashes": [ - "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130", - "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0" + "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6" ], - "version": "==1.5.2" + "version": "==1.4" }, "cachetools": { "hashes": [ @@ -118,11 +171,11 @@ }, "cattrs": { "hashes": [ - "sha256:95265b8aaa45e6de75b5f52ae081e021a2a7a688babdb711e4174e6b18920d08", - "sha256:d69bd4a3239e189f0740c3c41178dd0f00e4eac3bcb806937e49942fa83adfee" + "sha256:277d12740b45e46318b41c3b2e4a3bc067a7b9971cf61f0e96497598ad83f282", + "sha256:a6233d0ce33d48ac71ef818f8e0b9309a89496b359994c4dfe9ad211c1f6d0a3" ], - "markers": "python_version >= '3.7'", - "version": "==1.7.1" + "markers": "python_version > '3.6'", + "version": "==1.5.0" }, "certifi": { "hashes": [ @@ -133,65 +186,61 @@ }, "cffi": { "hashes": [ - "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813", - "sha256:04c468b622ed31d408fea2346bec5bbffba2cc44226302a0de1ade9f5ea3d373", - "sha256:06d7cd1abac2ffd92e65c0609661866709b4b2d82dd15f611e602b9b188b0b69", - "sha256:06db6321b7a68b2bd6df96d08a5adadc1fa0e8f419226e25b2a5fbf6ccc7350f", - "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06", - "sha256:0f861a89e0043afec2a51fd177a567005847973be86f709bbb044d7f42fc4e05", - "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea", - "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee", - "sha256:1bf1ac1984eaa7675ca8d5745a8cb87ef7abecb5592178406e55858d411eadc0", - "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396", - "sha256:24a570cd11895b60829e941f2613a4f79df1a27344cbbb82164ef2e0116f09c7", - "sha256:24ec4ff2c5c0c8f9c6b87d5bb53555bf267e1e6f70e52e5a9740d32861d36b6f", - "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73", - "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315", - "sha256:293e7ea41280cb28c6fcaaa0b1aa1f533b8ce060b9e701d78511e1e6c4a1de76", - "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1", - "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49", - "sha256:3c3f39fa737542161d8b0d680df2ec249334cd70a8f420f71c9304bd83c3cbed", - "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892", - "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482", - "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058", - "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5", - "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53", - "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045", - "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3", - "sha256:681d07b0d1e3c462dd15585ef5e33cb021321588bebd910124ef4f4fb71aef55", - "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5", - "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e", - "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c", - "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369", - "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827", - "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053", - "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa", - "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4", - "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322", - "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132", - "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62", - "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa", - "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0", - "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396", - "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e", - "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991", - "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6", - "sha256:cc5a8e069b9ebfa22e26d0e6b97d6f9781302fe7f4f2b8776c3e1daea35f1adc", - "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1", - "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406", - "sha256:df5052c5d867c1ea0b311fb7c3cd28b19df469c056f7fdcfe88c7473aa63e333", - "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d", - "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c" - ], - "version": "==1.14.5" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + "sha256:06c54a68935738d206570b20da5ef2b6b6d92b38ef3ec45c5422c0ebaf338d4d", + "sha256:0c0591bee64e438883b0c92a7bed78f6290d40bf02e54c5bf0978eaf36061771", + "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872", + "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c", + "sha256:26bb2549b72708c833f5abe62b756176022a7b9a7f689b571e74c8478ead51dc", + "sha256:33791e8a2dc2953f28b8d8d300dde42dd929ac28f974c4b4c6272cb2955cb762", + "sha256:3c8d896becff2fa653dc4438b54a5a25a971d1f4110b32bd3068db3722c80202", + "sha256:4373612d59c404baeb7cbd788a18b2b2a8331abcc84c3ba40051fcd18b17a4d5", + "sha256:487d63e1454627c8e47dd230025780e91869cfba4c753a74fda196a1f6ad6548", + "sha256:48916e459c54c4a70e52745639f1db524542140433599e13911b2f329834276a", + "sha256:4922cd707b25e623b902c86188aca466d3620892db76c0bdd7b99a3d5e61d35f", + "sha256:55af55e32ae468e9946f741a5d51f9896da6b9bf0bbdd326843fec05c730eb20", + "sha256:57e555a9feb4a8460415f1aac331a2dc833b1115284f7ded7278b54afc5bd218", + "sha256:5d4b68e216fc65e9fe4f524c177b54964af043dde734807586cf5435af84045c", + "sha256:64fda793737bc4037521d4899be780534b9aea552eb673b9833b01f945904c2e", + "sha256:6d6169cb3c6c2ad50db5b868db6491a790300ade1ed5d1da29289d73bbe40b56", + "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224", + "sha256:80b06212075346b5546b0417b9f2bf467fea3bfe7352f781ffc05a8ab24ba14a", + "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2", + "sha256:8eb687582ed7cd8c4bdbff3df6c0da443eb89c3c72e6e5dcdd9c81729712791a", + "sha256:99f27fefe34c37ba9875f224a8f36e31d744d8083e00f520f133cab79ad5e819", + "sha256:9f3e33c28cd39d1b655ed1ba7247133b6f7fc16fa16887b120c0c670e35ce346", + "sha256:a8661b2ce9694ca01c529bfa204dbb144b275a31685a075ce123f12331be790b", + "sha256:a9da7010cec5a12193d1af9872a00888f396aba3dc79186604a09ea3ee7c029e", + "sha256:aedb15f0a5a5949ecb129a82b72b19df97bbbca024081ed2ef88bd5c0a610534", + "sha256:b315d709717a99f4b27b59b021e6207c64620790ca3e0bde636a6c7f14618abb", + "sha256:ba6f2b3f452e150945d58f4badd92310449876c4c954836cfb1803bdd7b422f0", + "sha256:c33d18eb6e6bc36f09d793c0dc58b0211fccc6ae5149b808da4a62660678b156", + "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd", + "sha256:c9e005e9bd57bc987764c32a1bee4364c44fdc11a3cc20a40b93b444984f2b87", + "sha256:d2ad4d668a5c0645d281dcd17aff2be3212bc109b33814bbb15c4939f44181cc", + "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195", + "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33", + "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f", + "sha256:e9dc245e3ac69c92ee4c167fbdd7428ec1956d4e754223124991ef29eb57a09d", + "sha256:eb687a11f0a7a1839719edd80f41e459cc5366857ecbed383ff376c4e3cc6afd", + "sha256:eb9e2a346c5238a30a746893f23a9535e700f8192a68c07c0258e7ece6ff3728", + "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7", + "sha256:f0010c6f9d1a4011e429109fda55a225921e3206e7f62a0c22a35344bfd13cca", + "sha256:f0c5d1acbfca6ebdd6b1e3eded8d261affb6ddcf2186205518f1428b8569bb99", + "sha256:f10afb1004f102c7868ebfe91c28f4a712227fe4cb24974350ace1f90e1febbf", + "sha256:f174135f5609428cc6e1b9090f9268f5c8935fddb1b25ccb8255a2d50de6789e", + "sha256:f3ebe6e73c319340830a9b2825d32eb6d8475c1dac020b4f0aa774ee3b898d1c", + "sha256:f627688813d0a4140153ff532537fbe4afea5a3dffce1f9deb7f91f848a832b5", + "sha256:fd4305f86f53dfd8cd3522269ed7fc34856a8ee3709a5e28b2836b2db9d4cd69" + ], + "version": "==1.14.6" + }, + "charset-normalizer": { + "hashes": [ + "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b", + "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==3.0.4" + "markers": "python_version >= '3'", + "version": "==2.0.4" }, "click": { "hashes": [ @@ -201,6 +250,13 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==7.1.2" }, + "clickclick": { + "hashes": [ + "sha256:4efb13e62353e34c5eef7ed6582c4920b418d7dedc86d819e22ee089ba01802c", + "sha256:c8f33e6d9ec83f68416dd2136a7950125bd256ec39ccc9a85c6e280a16be2bb5" + ], + "version": "==20.10.2" + }, "colorama": { "hashes": [ "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b", @@ -211,27 +267,25 @@ }, "colorlog": { "hashes": [ - "sha256:3cf31b25cbc8f86ec01fef582ef3b840950dea414084ed19ab922c8b493f9b42", - "sha256:450f52ea2a2b6ebb308f034ea9a9b15cea51e65650593dca1da3eb792e4e4981" + "sha256:3dd15cb27e8119a24c1a7b5c93f9f3b455855e0f73993b1c25921b2f646f1dcd", + "sha256:59b53160c60902c405cdec28d38356e09d40686659048893e026ecbd589516b1" ], - "version": "==4.0.2" + "version": "==4.8.0" }, - "configparser": { + "commonmark": { "hashes": [ - "sha256:18873eb33d111429143eef0ad334f76abdf9736d5da1219de513d74b0a559674", - "sha256:561d6a2303a3e9afaafbaa9f459b2a16e5d49f5390954cd4e6ce1a4bfbd8f726", - "sha256:adaba55d292e94fac7a1080de30ea776139ea48b65db869659e87357f10c55d2" + "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60", + "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9" ], - "markers": "python_version >= '2.6'", - "version": "==3.5.3" + "version": "==0.9.1" }, "croniter": { "hashes": [ - "sha256:12ced475dfc107bf7c6c1440af031f34be14cd97bbbfaf0f62221a9c11e86404", - "sha256:8f573a889ca9379e08c336193435c57c02698c2dd22659cdbe04fee57426d79b" + "sha256:0f97b361fe343301a8f66f852e7d84e4fb7f21379948f71e1bbfe10f5d015fbd", + "sha256:a70dfc9d52de9fc1a886128b9148c89dd9e76b67d55f46516ca94d2d73d58219" ], "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.3.37" + "version": "==1.0.15" }, "cryptography": { "hashes": [ @@ -248,7 +302,7 @@ "sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d", "sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9" ], - "markers": "python_version >= '3'", + "markers": "python_version >= '3.6'", "version": "==3.4.7" }, "defusedxml": { @@ -267,6 +321,13 @@ "markers": "python_version >= '2.7' and python_version != '3.0'", "version": "==0.3.4" }, + "distlib": { + "hashes": [ + "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736", + "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c" + ], + "version": "==0.3.2" + }, "dnspython": { "hashes": [ "sha256:95d12f6ef0317118d2a1a6fc49aac65ffec7eb8087474158f42f26a639135216", @@ -277,11 +338,11 @@ }, "docutils": { "hashes": [ - "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125", - "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61" + "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af", + "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.17.1" + "version": "==0.16" }, "email-validator": { "hashes": [ @@ -291,6 +352,13 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==1.1.3" }, + "filelock": { + "hashes": [ + "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", + "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836" + ], + "version": "==3.0.12" + }, "flake8": { "hashes": [ "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b", @@ -307,19 +375,13 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==1.1.4" }, - "flask-admin": { - "hashes": [ - "sha256:ed7b256471dba0f3af74f1a315733c3b36244592f2002c3bbdc65fd7c2aa807a" - ], - "version": "==1.5.4" - }, "flask-appbuilder": { "hashes": [ - "sha256:14de4244838f010424efe47d63260123189f472527a20f3b3a8ef9acb6fd9a0d", - "sha256:4d6f974ff5aa226f11894a447c43fb9c31425bb740e7841a3277a9cbeb9d22b1" + "sha256:5d46338b0d6cf5bb1b6c5ed9c3ed09487a6b37e04727b2bbe3f9e63fe877d084", + "sha256:d13015bd2b709562072ac47797103152a6a5e40f87b49a1ba6110840d5b241cb" ], - "markers": "python_version >= '3.6'", - "version": "==2.3.4" + "markers": "python_version ~= '3.6'", + "version": "==3.3.2" }, "flask-babel": { "hashes": [ @@ -330,16 +392,17 @@ }, "flask-caching": { "hashes": [ - "sha256:21236d2b4567deb9fc95e474a604602097189e834629c24f4d62937abc963636", - "sha256:5af1759e5ae3424abec918537f0201a1476ae9442452bcb5c8787468a9de0f5a" + "sha256:bcda8acbc7508e31e50f63e9b1ab83185b446f6b6318bd9dd1d45626fba2e903", + "sha256:cf19b722fcebc2ba03e4ae7c55b532ed53f0cbf683ce36fafe5e881789a01c00" ], - "version": "==1.3.3" + "markers": "python_full_version >= '3.5.0'", + "version": "==1.10.1" }, "flask-jwt-extended": { "hashes": [ "sha256:bbf4467f41c56cf1fd8a5870d2556f419c572aad2b4085757581c3f9b4d7767a" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4.0'", "version": "==3.25.1" }, "flask-login": { @@ -362,13 +425,6 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.5.1" }, - "flask-swagger": { - "hashes": [ - "sha256:3caddb1311388eafc86f82f8e64ba386a5df6b84e5f16dfae19ca08173eba216", - "sha256:b4085f5bc36df4c20b6548cd1413adc9cf35719b0f0695367cd542065145294d" - ], - "version": "==0.2.14" - }, "flask-wtf": { "hashes": [ "sha256:57b3faf6fe5d6168bda0c36b0df1d05770f8e205e18332d0376ddb954d17aef2", @@ -376,19 +432,12 @@ ], "version": "==0.14.3" }, - "funcsigs": { - "hashes": [ - "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca", - "sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50" - ], - "version": "==1.0.2" - }, - "future": { + "google-ads": { "hashes": [ - "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d" + "sha256:172b25ffabd2f4926f4b300dff74f64692230609f8ca21a9e8780295ab23500b" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.18.2" + "markers": "python_version >= '3.7'", + "version": "==13.0.0" }, "google-api-core": { "extras": [ @@ -396,26 +445,27 @@ "grpcgcp" ], "hashes": [ - "sha256:0724d354d394b3d763bc10dfee05807813c5210f0bd9b8e2ddf6b6925603411c", - "sha256:92cd9e9f366e84bfcf2524e34d2dc244906c645e731962617ba620da1620a1e0" + "sha256:108cf94336aed7e614eafc53933ef02adf63b9f0fd87e8f8212acaa09eaca456", + "sha256:1d63e2b28057d79d64795c9a70abcecb5b7e96da732d011abf09606a39b48701" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.30.0" + "version": "==1.31.1" }, "google-api-python-client": { "hashes": [ "sha256:3c4c4ca46b5c21196bec7ee93453443e477d82cbfa79234d1ce0645f81170eaf", "sha256:f3b9684442eec2cfe9f9bb48e796ef919456b82142c7528c5fd527e5224f08bb" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.12.8" }, "google-auth": { "hashes": [ - "sha256:b3a67fa9ba5b768861dacf374c2135eb09fa14a0e40c851c3b8ea7abe6fc8fef", - "sha256:e34e5f5de5610b202f9b40ebd9f8b27571d5c5537db9afed3a72b2db5a345039" + "sha256:bd6aa5916970a823e76ffb3d5c3ad3f0bedafca0a7fa53bc15149ab21cb71e05", + "sha256:f1094088bae046fb06f3d1a3d7df14717e8d959e9105b79c57725bd4e17597a2" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.32.0" + "markers": "python_version >= '3.6'", + "version": "==1.34.0" }, "google-auth-httplib2": { "hashes": [ @@ -426,11 +476,35 @@ }, "google-auth-oauthlib": { "hashes": [ - "sha256:09832c6e75032f93818edf1affe4746121d640c625a5bef9b5c96af676e98eee", - "sha256:0e92aacacfb94978de3b7972cf4b0f204c3cd206f74ddd0dc0b31e91164e6317" + "sha256:4ab58e6c3dc6ccf112f921fcced40e5426fba266768986ea502228488276eaba", + "sha256:b5a1ce7c617d247ccb2dfbba9d4bfc734b41096803d854a2c52592ae80150a67" ], "markers": "python_version >= '3.6'", - "version": "==0.4.4" + "version": "==0.4.5" + }, + "google-cloud-appengine-logging": { + "hashes": [ + "sha256:0f5cea4f2b45e12a34e15285b967d903dcf9ded6bb06959fdcd23e3eeec1f2e9", + "sha256:d44fb77d7706b086d387b9d79c139c553d54b58ddc8ee967bbf32a53e7bbee56" + ], + "markers": "python_version >= '3.6'", + "version": "==0.1.4" + }, + "google-cloud-audit-log": { + "hashes": [ + "sha256:5bf5a53c641b13828154ab21fb209669be69d71cd462f5d6456bf87722fc0eeb", + "sha256:a17064203b985ffa9219937d339cab3583548f07d38e96d67a498aba69c1387d" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.1.0" + }, + "google-cloud-automl": { + "hashes": [ + "sha256:2acaa975849f86bc2eca75911908a60502dbf417fc13dd3e2794e7098986dacf", + "sha256:737ce5a427a35c1fd13bc467c855290e49de7e9a0c6565d681a4bb002a6a740c" + ], + "markers": "python_version >= '3.6'", + "version": "==2.4.2" }, "google-cloud-bigquery": { "extras": [ @@ -438,24 +512,33 @@ "pandas" ], "hashes": [ - "sha256:bbe41300cc931a00649d4e7c59b86e6c1e9fab94e1ba958e1a27c5b330172490", - "sha256:ff728f9a4a64d6b4ec5beb7fd2f6ed550b49bfe2b8bb3755c00821716e0d1f91" + "sha256:38ec0bf0f120f5aacb1620c197367904e35f824e7aa40a08c4d65aa70516e550", + "sha256:b0d2304bf4e85b2823da3f5ce648b0ab68a5ea909e213c4bed9ee05ea49d00a0" ], "markers": "python_version < '3.10' and python_version >= '3.6'", - "version": "==2.20.0" + "version": "==2.23.2" + }, + "google-cloud-bigquery-datatransfer": { + "hashes": [ + "sha256:a0292db7cc0060a7b0cfa19ae26206572d085a89d74ea42f68ee4c4f83241cc6", + "sha256:a83578f3c60356b95500aa1a8167989877890a0f08a04412d89f1364e96c96fa" + ], + "markers": "python_version >= '3.6'", + "version": "==3.3.1" }, "google-cloud-bigquery-storage": { "hashes": [ - "sha256:784513bec243e4bcab0ca5a4218701b599b94f5ec1cfe345f64db487c5ff270e", - "sha256:be7d2f88c617876c4b05b766cb32bd0730ee575745767db7c79df270d09ac80b" + "sha256:63f03c88e8ca9dc07e947731f8f6e0bfa5451e32ee226fb6a4141cf23655b168", + "sha256:aa88ceec9f016b07fdfb1a9aa2630f7fb88d3424c99b4bdfe6cc45a15aa26b5a" ], - "version": "==2.4.0" + "version": "==2.6.2" }, "google-cloud-bigtable": { "hashes": [ "sha256:90bd53a19c33c34101b8567c82a6dc0386af4118d70e1ad69b49375358a21aa6", "sha256:e372b72c573309cb4f2b9998baac5d881ba023bae500841683e8d0849641f955" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.7.0" }, "google-cloud-container": { @@ -463,35 +546,110 @@ "sha256:3dda5050084101c2e74248ada8f0fdf470376ec9333a3b2d1024eaee3a84205e", "sha256:c8fe8fecb003dfb5fd67b8e6b55b25be4fe794e296d107492cab429f0b999d5a" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.0.1" }, "google-cloud-core": { "hashes": [ - "sha256:2ab0cf260c11d0cc334573301970419abb6a1f3909c6cd136e4be996616372fe", - "sha256:9bd528810423aeaa428a9a178e7320883bbb690a8b0bb38297b794dc319c415a" + "sha256:5b77935f3d9573e27007749a3b522f08d764c5b5930ff1527b2ab2743e9f0c15", + "sha256:b1030aadcbb2aeb4ee51475426351af83c1072456b918fb8fdb80666c4bb63b5" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.7.0" + "markers": "python_version >= '3.6'", + "version": "==1.7.2" + }, + "google-cloud-datacatalog": { + "hashes": [ + "sha256:2faca51e974c46203c09fd4cb2c03fd6e82cd572cc06a2bbc3b401aa419cb09f", + "sha256:c70d7ad720ba7d23d316b7468b6fc0c52e4a1824b7f1b946b8855f6964953562" + ], + "version": "==3.4.0" + }, + "google-cloud-dataproc": { + "hashes": [ + "sha256:be13518d81e32833aeb03fc7572125e6d526a26eaad0823147efd4efaeebd6b1", + "sha256:c11188baeb76989e91261f1f454013d090e69d4ade4185e181582c7d1c6fcb1a" + ], + "markers": "python_version >= '3.6'", + "version": "==2.5.0" }, "google-cloud-dlp": { "hashes": [ "sha256:2ccf04209f96b4759d8ed76da2c916a456386836caacd47ce01b6344f5b8f212", "sha256:e0c57337c3fbe2bf22cc4d4deaf3d58a21603718301ee9ee4806b49f59a52e5a" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.0.0" }, + "google-cloud-kms": { + "hashes": [ + "sha256:28903798ec34d20625c976b830746d73a5883be8a838737d9fb800dc980590ec", + "sha256:2ec7b138c29374f5158cb9bc12a5a47eba294a9f63a123451cec3abb28997e25" + ], + "markers": "python_version >= '3.6'", + "version": "==2.4.3" + }, "google-cloud-language": { "hashes": [ "sha256:2772badf8fe8ac57cd7e7840a60764603b3e19e6dbd843460a5ae8915798b32f", "sha256:76e349fcc223c66b9aa138e05853f4bf550f0d06e37641c2c206dc2661b83f30" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.3.0" }, + "google-cloud-logging": { + "hashes": [ + "sha256:499eed5f13cab805c8780b0d14a0d931a9ff1d65efccdd9e68772d40e7dad4c5", + "sha256:abf404c2823d4fdff5e86cd869d77e6fda8d40096cbab897bc78a11f59096a3c" + ], + "markers": "python_version >= '3.6'", + "version": "==2.6.0" + }, + "google-cloud-memcache": { + "hashes": [ + "sha256:0ded02972ec60a8b707fb36867383c7e85f01c27e209896281fe5ae5df77c123", + "sha256:950e20d1935ee1e5a03630d2c6b8a9343b8952b62418b11924343195db3b4a74" + ], + "markers": "python_version >= '3.6'", + "version": "==1.0.0" + }, + "google-cloud-monitoring": { + "hashes": [ + "sha256:3d08d302a4b38c204f1f9f2764701ce8e6b5d8d48356fb761346477b04c565f6", + "sha256:c80ed69ae2ce94de85bbb0b2b90678094599a76e96ed558523dd40d2f2ae71e4" + ], + "markers": "python_version >= '3.6'", + "version": "==2.4.2" + }, + "google-cloud-os-login": { + "hashes": [ + "sha256:3926c9f60fb488f4470fdecf642b18de5d0fee568a4122028b652a38fa60ce6c", + "sha256:7200118409a67c69034c1eda284b48320cdd6d9e5fe1d74cebac84f09f283e13" + ], + "markers": "python_version >= '3.6'", + "version": "==2.3.1" + }, + "google-cloud-pubsub": { + "hashes": [ + "sha256:1788ad25a765ea83499d8f4410d4c8ba026597cb82db46d2f7217f1c2525ad65", + "sha256:7b49095623de343f2ad91a066e1bd59fe196ab8e088c6f11351fb54ca7b1303e" + ], + "markers": "python_version >= '3.6'", + "version": "==2.7.0" + }, + "google-cloud-redis": { + "hashes": [ + "sha256:23adcfb99284c5fd33a21838ac0f681aff6331b21bc9d1feda47925bc9aa7e15", + "sha256:9718f19012bfeeea7eb76745da1673dd05de5cbc28f4bd19efc987e9a0b821c7" + ], + "markers": "python_version >= '3.6'", + "version": "==2.2.2" + }, "google-cloud-secret-manager": { "hashes": [ "sha256:1975298142e48a29feb31f6e2a2fbc9aed6a1095a22d038ed877d9ce14eea3b2", "sha256:60dc4485bc7ff777ee64fb8d4707127e4afdf27bf575d4f60929fa1bd78e7941" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.0.0" }, "google-cloud-spanner": { @@ -499,6 +657,7 @@ "sha256:50c375d8224415b7b7cc19a720c745cd8fb49144db50b252d06c42121374312d", "sha256:ff6869e50eb284854fec864fcaa26139c04ded7ed522ae488fff3b08ffc5dc30" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.19.1" }, "google-cloud-speech": { @@ -506,20 +665,31 @@ "sha256:2e5adbc0e88f296b1bc8667f1dcf26ca4ea2db6596f07cb0a39e7b1b8ef14656", "sha256:3aa7bd9148c1dd02ab343ad5048d859cb4d17e950c7d506727743a780f748409" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.3.2" }, "google-cloud-storage": { "hashes": [ - "sha256:89a5f5290e61990a5ae138d8ba8895bc3fe1e00fbc2e3b6beb7fb8378ca7a2f1", - "sha256:e9ba9e0486b385fa0b9f16a0c3bfa4cbb7001a2285adb65374de4415588cdb2d" + "sha256:a81ecc0f382b8e4437cc7f152f74d77ef917c8280a5d1040f5dcfbd0502c7906", + "sha256:cd4c9039eb0017fdc75c3f96b0b5ea57759ceefe3a0401d514bcf0111cd7a508" ], - "version": "==1.39.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==1.41.1" + }, + "google-cloud-tasks": { + "hashes": [ + "sha256:75c1ee7869bfa725d75e57f2c3487934f4dc7766373d8854bac6a0572dd54032", + "sha256:e1038a1bb168adfdf1e65d5741b6d7e00f2ea48c5ef9e0a2c213e2972dba76ee" + ], + "markers": "python_version >= '3.6'", + "version": "==2.5.1" }, "google-cloud-texttospeech": { "hashes": [ "sha256:c5c66c148f6f47a213c8d53827c1dbf08cdf41f8047868433da0009e406e201e", "sha256:e1ff11093a52b5d980bc1ad085027d41d81eac9d0047b13c3caf169924746111" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.0.1" }, "google-cloud-translate": { @@ -527,6 +697,7 @@ "sha256:302af77bc18fc56fe4a83aad835cf54609d4e188dd6bd7b35ffcb3f303459705", "sha256:55b6563121883acce5d80afbf61a59e50d52c429e6ebbfe81a1c8f2734b75e8c" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.7.0" }, "google-cloud-videointelligence": { @@ -534,6 +705,7 @@ "sha256:98a5d043d4824ad0529f8c2a3108bc4e1ed530e76314ea2c0e39f3d81cdf378e", "sha256:bbde4a5bb479f60466dabad67d5debb30448bb2451b67bba3bfd9b67281a230a" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.1" }, "google-cloud-vision": { @@ -541,8 +713,17 @@ "sha256:18e78b190c81d200ae4f6a46d4af57422d68b3b05b0540d5cd1806e3874142bf", "sha256:e61091a52f334a20e597b74e2fb42c9f27dda25323544cd157d6110fde26c9a6" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.0.0" }, + "google-cloud-workflows": { + "hashes": [ + "sha256:2ae093e73f1d29a55180c717e872577c83e35b76db2e2a86f598812362e5ee24", + "sha256:998b5b203e530205a27b3b7a033762d7f7a7b2a017cb6ee0d589e0b27a1a2e43" + ], + "markers": "python_version >= '3.6'", + "version": "==1.2.1" + }, "google-crc32c": { "hashes": [ "sha256:0ae3cf54e0d4d83c8af1afe96fc0970fbf32f1b29275f3bfd44ce25c4b622a2b", @@ -580,11 +761,11 @@ }, "google-resumable-media": { "hashes": [ - "sha256:106db689574283a7d9d154d5a97ab384153c55a1195cecb8c01cad9e6e827628", - "sha256:1a1eb743d13f782d1405437c266b2c815ef13c2b141ba40835c74a3317539d01" + "sha256:092f39153cd67a4e409924edf08129f43cc72e630a1eb22abec93e80155df4ba", + "sha256:ce38555d250bd70b0c2598bf61e99003cb8c569b0176ec0e3f38b86f9ffff581" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.3.1" + "markers": "python_version >= '3.6'", + "version": "==1.3.3" }, "googleapis-common-protos": { "extras": [ @@ -599,11 +780,11 @@ }, "graphviz": { "hashes": [ - "sha256:3cad5517c961090dfc679df6402a57de62d97703e2880a1a46147bb0dc1639eb", - "sha256:d2d25af1c199cad567ce4806f0449cb74eb30cf451fd7597251e1da099ac6e57" + "sha256:5dadec94046d82adaae6019311a30e0487536d9d5a60d85451f0ba32f9fc6559", + "sha256:ef6e2c5deb9cdcc0c7eece1d89625fd07b0f2208ea2bcb483520907ddf8b4e12" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==0.16" + "markers": "python_version >= '3.6'", + "version": "==0.17" }, "grpc-google-iam-v1": { "hashes": [ @@ -613,59 +794,59 @@ }, "grpcio": { "hashes": [ - "sha256:0e193feaf4ebc72f6af57d7b8a08c0b8e43ebbd76f81c6f1e55d013557602dfd", - "sha256:118479436bda25b369e2dc1cd0921790fbfaea1ec663e4ee7095c4c325694495", - "sha256:1f79d8a24261e3c12ec3a6c25945ff799ae09874fd24815bc17c2dc37715ef6c", - "sha256:26af85ae0a7ff8e8f8f550255bf85551df86a89883c11721c0756b71bc1019be", - "sha256:278e131bfbc57bab112359b98930b0fdbf81aa0ba2cdfc6555c7a5119d7e2117", - "sha256:2a179b2565fa85a134933acc7845f9d4c12e742c802b4f50bf2fd208bf8b741e", - "sha256:3a25e1a46f51c80d06b66223f61938b9ffda37f2824ca65749c49b758137fac2", - "sha256:3db0680fee9e55022677abda186e73e3c019c59ed83e1550519250dc97cf6793", - "sha256:3e85bba6f0e0c454a90b8fea16b59db9c6d19ddf9cc95052b2d4ca77b22d46d6", - "sha256:3eb960c2f9e031f0643b53bab67733a9544d82f42d0714338183d14993d2a23c", - "sha256:419af4f577a3d5d9f386aeacf4c4992f90016f84cbceb11ecd832101b1f7f9c9", - "sha256:44efa41ac36f6bcbf4f64d6479b3031cceea28cf6892a77f15bd1c22611bff9d", - "sha256:4bc60f8372c3ab06f41279163c5d558bf95195bb3f68e35ed19f95d4fbd53d71", - "sha256:4c19578b35715e110c324b27c18ab54a56fccc4c41b8f651b1d1da5a64e0d605", - "sha256:532ab738351aad2cdad80f4355123652e08b207281f3923ce51fb2b58692dd4c", - "sha256:549beb5646137b78534a312a3b80b2b8b1ea01058b38a711d42d6b54b20b6c2b", - "sha256:59f5fb4ba219a11fdc1c23e17c93ca3090480a8cde4370c980908546ffc091e6", - "sha256:5efa68fc3fe0c439e2858215f2224bfb7242c35079538d58063f68a0d5d5ec33", - "sha256:5ff4802d9b3704e680454289587e1cc146bb0d953cf3c9296e2d96441a6a8e88", - "sha256:6a225440015db88ec4625a2a41c21582a50cce7ffbe38dcbbb416c7180352516", - "sha256:6d898441ada374f76e0b5354d7e240e1c0e905a1ebcb1e95d9ffd99c88f63700", - "sha256:6e137d014cf4162e5a796777012452516d92547717c1b4914fb71ce4e41817b5", - "sha256:6edf68d4305e08f6f8c45bfaa9dc04d527ab5a1562aaf0c452fa921fbe90eb23", - "sha256:72e8358c751da9ab4f8653a3b67b2a3bb7e330ee57cb26439c6af358d6eac032", - "sha256:77054f24d46498d9696c809da7810b67bccf6153f9848ea48331708841926d82", - "sha256:7adfbd4e22647f880c9ed86b2be7f6d7a7dbbb8adc09395808cc7a4d021bc328", - "sha256:87b4b1977b52d5e0873a5e396340d2443640ba760f4fa23e93a38997ecfbcd5b", - "sha256:889518ce7c2a0609a3cffb7b667669a39b3410e869ff38e087bf7eeadad62e5d", - "sha256:89af675d38bf490384dae85151768b8434e997cece98e5d1eb6fcb3c16d6af12", - "sha256:8ab27a6626c2038e13c1b250c5cd22da578f182364134620ec298b4ccfc85722", - "sha256:8ccde1df51eeaddf5515edc41bde2ea43a834a288914eae9ce4287399be108f5", - "sha256:947bdba3ebcd93a7cef537d6405bc5667d1caf818fa8bbd2e2cc952ec8f97e09", - "sha256:96d78d9edf3070770cefd1822bc220d8cccad049b818a70a3c630052e9f15490", - "sha256:a433d3740a9ef7bc34a18e2b12bf72b25e618facdfd09871167b30fd8e955fed", - "sha256:a77d1f47e5e82504c531bc9dd22c093ff093b6706ec8bcdad228464ef3a5dd54", - "sha256:b1624123710fa701988a8a43994de78416e5010ac1508f64ed41e2577358604a", - "sha256:b16e1967709392a0ec4b10b4374a72eb062c47c168a189606c9a7ea7b36593a8", - "sha256:b5ea9902fc2990af993b74862282b49ae0b8de8a64ca3b4a8dda26a3163c3bb4", - "sha256:c323265a4f18f586e8de84fda12b48eb3bd48395294aa2b8c05307ac1680299d", - "sha256:c83481501533824fe341c17d297bbec1ec584ec46b352f98ce12bf16740615c4", - "sha256:cd7ddb5b6ffcbd3691990df20f260a888c8bd770d57480a97da1b756fb1be5c0", - "sha256:cddd61bff66e42ef334f8cb9e719951e479b5ad2cb75c00338aac8de28e17484", - "sha256:cf6c3bfa403e055380fe90844beb4fe8e9448edab5d2bf40d37d208dbb2f768c", - "sha256:d4179d96b0ce27602756185c1a00d088c9c1feb0cc17a36f8a66eec6ddddbc0c", - "sha256:d49f250c3ffbe83ba2d03e3500e03505576a985f7c5f77172a9531058347aa68", - "sha256:dcfcb147c18272a22a592251a49830b3c7abc82385ffff34916c2534175d885e", - "sha256:ddd33c90b0c95eca737c9f6db7e969a48d23aed72cecb23f3b8aac009ca2cfb4", - "sha256:e4a8a371ad02bf31576bcd99093cea3849e19ca1e9eb63fc0b2c0f1db1132f7d", - "sha256:e891b0936aab73550d673dd3bbf89fa9577b3db1a61baecea480afd36fdb1852", - "sha256:e90cda2ccd4bdb89a3cd5dc11771c3b8394817d5caaa1ae36042bc96a428c10e", - "sha256:ff9ebc416e815161d89d2fd22d1a91acf3b810ef800dae38c402d19d203590bf" - ], - "version": "==1.38.1" + "sha256:02e8a8b41db8e13df53078355b439363e4ac46d0ac9a8a461a39e42829e2bcf8", + "sha256:050901a5baa6c4ca445e1781ef4c32d864f965ccec70c46cd5ad92d15e282c6a", + "sha256:1ab44dde4e1b225d3fc873535ca6e642444433131dd2891a601b75fb46c87c11", + "sha256:2068a2b896ac67103c4a5453d5435fafcbb1a2f41eaf25148d08780096935cee", + "sha256:20f57c5d09a36e0d0c8fe16ee1905f4307edb1d04f6034b56320f7fbc1a1071a", + "sha256:25731b2c20a4ed51bea7e3952d5e83d408a5df32d03c7553457b2e6eb8bcb16c", + "sha256:27e2c6213fc04e71a862bacccb51f3c8e722255933f01736ace183e92d860ee6", + "sha256:2a4308875b9b986000513c6b04c2e7424f436a127f15547036c42d3cf8289374", + "sha256:2a958ad794292e12d8738a06754ebaf71662e635a89098916c18715b27ca2b5b", + "sha256:2bc7eebb405aac2d7eecfaa881fd73b489f99c01470d7193b4431a6ce199b9c3", + "sha256:366b6b35b3719c5570588e21d866460c5666ae74e3509c2a5a73ca79997abdaf", + "sha256:3c14e2087f809973d5ee8ca64f772a089ead0167286f3f21fdda8b6029b50abb", + "sha256:3c57fa7fec932767bc553bfb956759f45026890255bd232b2f797c3bc4dfeba2", + "sha256:3cccf470fcaab65a1b0a826ff34bd7c0861eb82ed957a83c6647a983459e4ecd", + "sha256:4039645b8b5d19064766f3a6fa535f1db52a61c4d4de97a6a8945331a354d527", + "sha256:4163e022f365406be2da78db890035463371effea172300ce5af8a768142baf3", + "sha256:4258b778ce09ffa3b7c9a26971c216a34369e786771afbf4f98afe223f27d248", + "sha256:43c57987e526d1b893b85099424387b22de6e3eee4ea7188443de8d657d11cc0", + "sha256:43e0f5c49f985c94332794aa6c4f15f3a1ced336f0c6a6c8946c67b5ab111ae9", + "sha256:46cfb0f2b757673bfd36ab4b0e3d61988cc1a0d47e0597e91462dcbef7528f35", + "sha256:46d510a7af777d2f38ef4c1d25491add37cad24143012f3eebe72dc5c6d0fc4c", + "sha256:476fa94ba8efb09213baabd757f6f93e839794d8ae0eaa371347d6899e8f57a0", + "sha256:4b3fcc1878a1a5b71e1ecdfe82c74f7cd9eadaa43e25be0d67676dcec0c9d39f", + "sha256:5091b4a5ee8454a8f0c8ac45946ca25d6142c3be4b1fba141f1d62a6e0b5c696", + "sha256:5127f4ba1f52fda28037ae465cf4b0e5fabe89d5ac1d64d15b073b46b7db5e16", + "sha256:52100d800390d58492ed1093de6faccd957de6fc29b1a0e5948c84f275d9228f", + "sha256:544e1c1a133b43893e03e828c8325be5b82e20d3b0ef0ee3942d32553052a1b5", + "sha256:5628e7cc69079159f9465388ff21fde1e1a780139f76dd99d319119d45156f45", + "sha256:57974361a459d6fe04c9ae0af1845974606612249f467bbd2062d963cb90f407", + "sha256:691f5b3a75f072dfb7b093f46303f493b885b7a42f25a831868ffaa22ee85f9d", + "sha256:6ba6ad60009da2258cf15a72c51b7e0c2f58c8da517e97550881e488839e56c6", + "sha256:6d51be522b573cec14798d4742efaa69d234bedabce122fec2d5489abb3724d4", + "sha256:7b95b3329446408e2fe6db9b310d263303fa1a94649d08ec1e1cc12506743d26", + "sha256:88dbef504b491b96e3238a6d5360b04508c34c62286080060c85fddd3caf7137", + "sha256:8ed1e52ad507a54d20e6aaedf4b3edcab18cc12031eafe6de898f97513d8997b", + "sha256:a1fb9936b86b5efdea417fe159934bcad82a6f8c6ab7d1beec4bf3a78324d975", + "sha256:a2733994b05ee5382da1d0378f6312b72c5cb202930c7fa20c794a24e96a1a34", + "sha256:a6211150765cc2343e69879dfb856718b0f7477a4618b5f9a8f6c3ee84c047c0", + "sha256:a659f7c634cacfcf14657687a9fa3265b0a1844b1c19d140f3b66aebfba1a66b", + "sha256:b0ff14dd872030e6b2fce8a6811642bd30d93833f794d3782c7e9eb2f01234cc", + "sha256:b236eb4b50d83754184b248b8b1041bb1546287fff7618c4b7001b9f257bb903", + "sha256:c44958a24559f875d902d5c1acb0ae43faa5a84f6120d1d0d800acb52f96516e", + "sha256:c8fe430add656b92419f6cd0680b64fbe6347c831d89a7788324f5037dfb3359", + "sha256:cd2e39a199bcbefb3f4b9fa6677c72b0e67332915550fed3bd7c28b454bf917d", + "sha256:cffdccc94e63710dd6ead01849443390632c8e0fec52dc26e4fddf9f28ac9280", + "sha256:d5a105f5a595b89a0e394e5b147430b115333d07c55efb0c0eddc96055f0d951", + "sha256:dc3a24022a90c1754e54315009da6f949b48862c1d06daa54f9a28f89a5efacb", + "sha256:de83a045005703e7b9e67b61c38bb72cd49f68d9d2780d2c675353a3a3f2816f", + "sha256:e98aca5cfe05ca29950b3d99006b9ddb54fde6451cd12cb2db1443ae3b9fa076", + "sha256:ed845ba6253c4032d5a01b7fb9db8fe80299e9a437e695a698751b0b191174be", + "sha256:f2621c82fbbff1496993aa5fbf60e235583c7f970506e818671ad52000b6f310" + ], + "version": "==1.39.0" }, "grpcio-gcp": { "hashes": [ @@ -679,9 +860,25 @@ "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8" ], - "markers": "python_version >= '3.5'", + "markers": "python_full_version >= '3.5.0'", "version": "==20.1.0" }, + "h11": { + "hashes": [ + "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6", + "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042" + ], + "markers": "python_version >= '3.6'", + "version": "==0.12.0" + }, + "httpcore": { + "hashes": [ + "sha256:b0d16f0012ec88d8cc848f5a55f8a03158405f4bca02ee49bc4ca2c1fda49f3e", + "sha256:db4c0dcb8323494d01b8c6d812d80091a31e520033e7b0120883d6f52da649ff" + ], + "markers": "python_version >= '3.6'", + "version": "==0.13.6" + }, "httplib2": { "hashes": [ "sha256:0b12617eeca7433d4c396a100eaecfa4b08ee99aa881e6df6e257a7aad5d533d", @@ -689,21 +886,28 @@ ], "version": "==0.19.1" }, + "httpx": { + "hashes": [ + "sha256:979afafecb7d22a1d10340bafb403cf2cb75aff214426ff206521fc79d26408c", + "sha256:9f99c15d33642d38bce8405df088c1c4cfd940284b4290cacbfb02e64f4877c6" + ], + "markers": "python_version >= '3.6'", + "version": "==0.18.2" + }, "idna": { "hashes": [ - "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", - "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a", + "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.10" + "version": "==3.2" }, "importlib-metadata": { "hashes": [ - "sha256:b8de9eff2b35fb037368f28a7df1df4e6436f578fa74423505b6c6a778d5b5dd", - "sha256:c2d6341ff566f609e89a2acb2db190e5e1d23d5409d6cc8d2fe34d72443876d4" + "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83", + "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070" ], "markers": "python_version < '3.9'", - "version": "==2.1.1" + "version": "==1.7.0" }, "importlib-resources": { "hashes": [ @@ -713,6 +917,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==1.5.0" }, + "inflection": { + "hashes": [ + "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417", + "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2" + ], + "markers": "python_full_version >= '3.5.0'", + "version": "==0.5.1" + }, "iniconfig": { "hashes": [ "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", @@ -722,18 +934,25 @@ }, "iso8601": { "hashes": [ - "sha256:8aafd56fa0290496c5edbb13c311f78fa3a241f0853540da09d9363eae3ebd79", - "sha256:e7e1122f064d626e17d47cd5106bed2c620cb38fe464999e0ddae2b6d2de6004" + "sha256:36532f77cc800594e8f16641edae7f1baf7932f05d8e508545b95fc53c6dc85b", + "sha256:906714829fedbc89955d52806c903f2332e3948ed94e31e85037f9e0226b8376" + ], + "version": "==0.1.16" + }, + "isodate": { + "hashes": [ + "sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8", + "sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81" ], - "version": "==0.1.14" + "version": "==0.6.0" }, "isort": { "hashes": [ - "sha256:83510593e07e433b77bd5bff0f6f607dbafa06d1a89022616f02d8b699cfcd56", - "sha256:8e2c107091cfec7286bc0f68a547d0ba4c094d460b732075b6fba674f1035c0c" + "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899", + "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2" ], "index": "pypi", - "version": "==5.9.1" + "version": "==5.9.3" }, "itsdangerous": { "hashes": [ @@ -766,38 +985,39 @@ }, "kubernetes": { "hashes": [ - "sha256:225a95a0aadbd5b645ab389d941a7980db8cdad2a776fde64d1b43fc3299bde9", - "sha256:c69b318696ba797dcf63eb928a8d4370c52319f4140023c502d7dfdf2080eb79" + "sha256:1a2472f8b01bc6aa87e3a34781f859bded5a5c8ff791a53d889a8bd6cc550430", + "sha256:4af81201520977139a143f96123fb789fa351879df37f122916b9b6ed050bbaf" ], "index": "pypi", - "version": "==17.17.0" + "version": "==11.0.0" }, "lazy-object-proxy": { "hashes": [ - "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d", - "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449", - "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08", - "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a", - "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50", - "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd", - "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239", - "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb", - "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea", - "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e", - "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156", - "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142", - "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442", - "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62", - "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db", - "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531", - "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383", - "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a", - "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357", - "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4", - "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0" + "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653", + "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61", + "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2", + "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837", + "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3", + "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43", + "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726", + "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3", + "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587", + "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8", + "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a", + "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd", + "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f", + "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad", + "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4", + "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b", + "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf", + "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981", + "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741", + "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e", + "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93", + "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.4.3" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==1.6.0" }, "libcst": { "hashes": [ @@ -824,57 +1044,77 @@ }, "markdown": { "hashes": [ - "sha256:9ba587db9daee7ec761cfc656272be6aabe2ed300fece21208e4aab2e457bc8f", - "sha256:a856869c7ff079ad84a3e19cd87a64998350c2b94e9e08e44270faef33400f81" + "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49", + "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c" ], - "version": "==2.6.11" + "markers": "python_version >= '3.6'", + "version": "==3.3.4" }, "markupsafe": { "hashes": [ - "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298", - "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64", - "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b", - "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567", - "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff", - "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74", - "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35", - "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26", - "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7", - "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75", - "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f", - "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135", - "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8", - "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", - "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914", - "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18", - "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8", - "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2", - "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d", - "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b", - "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f", - "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb", - "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833", - "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415", - "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902", - "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9", - "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d", - "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066", - "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f", - "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5", - "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94", - "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509", - "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", - "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" + "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", + "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", + "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", + "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", + "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42", + "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f", + "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39", + "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", + "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", + "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014", + "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f", + "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", + "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", + "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", + "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", + "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b", + "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", + "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15", + "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", + "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85", + "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1", + "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", + "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", + "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", + "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850", + "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0", + "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", + "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", + "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb", + "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", + "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", + "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", + "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1", + "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2", + "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", + "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", + "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", + "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7", + "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", + "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8", + "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", + "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193", + "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", + "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b", + "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", + "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2", + "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5", + "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c", + "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032", + "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7", + "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be", + "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621" ], - "markers": "python_version >= '3.6'", - "version": "==2.0.1" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.1.1" }, "marshmallow": { "hashes": [ - "sha256:7cb1881a0fa84be4b5c1e301168236932c345f6910725f99905d636bfe93e9e9", - "sha256:e9390c0c80437d7a02d84e3d1635dc20f37a8bcb149ca443d93791bdc683f28d" + "sha256:c67929438fd73a2be92128caa0325b1b5ed8b626d91a094d2f7f2771bf1f1c0e", + "sha256:dd4724335d3c2b870b641ffe4a2f8728a1380cd2e7e2312756715ffeaa82b842" ], - "version": "==2.21.0" + "markers": "python_full_version >= '3.5.0'", + "version": "==3.13.0" }, "marshmallow-enum": { "hashes": [ @@ -883,6 +1123,14 @@ ], "version": "==1.5.1" }, + "marshmallow-oneofschema": { + "hashes": [ + "sha256:62cd2099b29188c92493c2940ee79d1bf2f2619a71721664e5a98ec2faa58237", + "sha256:bd29410a9f2f7457a2b428286e2a80ef76b8ddc3701527dc1f935a88914b02f2" + ], + "markers": "python_version >= '3.6'", + "version": "==3.0.1" + }, "marshmallow-sqlalchemy": { "hashes": [ "sha256:03a555b610bb307689b821b64e2416593ec21a85925c8c436c2cd08ebc6bb85e", @@ -905,47 +1153,47 @@ ], "version": "==0.4.3" }, - "natsort": { + "nox": { "hashes": [ - "sha256:00c603a42365830c4722a2eb7663a25919551217ec09a243d3399fa8dd4ac403", - "sha256:d0f4fc06ca163fa4a5ef638d9bf111c67f65eedcc7920f98dec08e489045b67e" + "sha256:58a662070767ed4786beb46ce3a789fca6f1e689ed3ac15c73c4d0094e4f9dc4", + "sha256:f179d6990f7a0a9cebad01b9ecea34556518b8d3340dfcafdc1d85f2c1a37ea0" ], - "markers": "python_version >= '3.4'", - "version": "==7.1.1" + "markers": "python_version >= '3.6'", + "version": "==2020.12.31" }, "numpy": { "hashes": [ - "sha256:1a784e8ff7ea2a32e393cc53eb0003eca1597c7ca628227e34ce34eb11645a0e", - "sha256:2ba579dde0563f47021dcd652253103d6fd66165b18011dce1a0609215b2791e", - "sha256:3537b967b350ad17633b35c2f4b1a1bbd258c018910b518c30b48c8e41272717", - "sha256:3c40e6b860220ed862e8097b8f81c9af6d7405b723f4a7af24a267b46f90e461", - "sha256:598fe100b2948465cf3ed64b1a326424b5e4be2670552066e17dfaa67246011d", - "sha256:620732f42259eb2c4642761bd324462a01cdd13dd111740ce3d344992dd8492f", - "sha256:709884863def34d72b183d074d8ba5cfe042bc3ff8898f1ffad0209161caaa99", - "sha256:75579acbadbf74e3afd1153da6177f846212ea2a0cc77de53523ae02c9256513", - "sha256:7c55407f739f0bfcec67d0df49103f9333edc870061358ac8a8c9e37ea02fcd2", - "sha256:a1f2fb2da242568af0271455b89aee0f71e4e032086ee2b4c5098945d0e11cf6", - "sha256:a290989cd671cd0605e9c91a70e6df660f73ae87484218e8285c6522d29f6e38", - "sha256:ac4fd578322842dbda8d968e3962e9f22e862b6ec6e3378e7415625915e2da4d", - "sha256:ad09f55cc95ed8d80d8ab2052f78cc21cb231764de73e229140d81ff49d8145e", - "sha256:b9205711e5440954f861ceeea8f1b415d7dd15214add2e878b4d1cf2bcb1a914", - "sha256:bba474a87496d96e61461f7306fba2ebba127bed7836212c360f144d1e72ac54", - "sha256:bebab3eaf0641bba26039fb0b2c5bf9b99407924b53b1ea86e03c32c64ef5aef", - "sha256:cc367c86eb87e5b7c9592935620f22d13b090c609f1b27e49600cd033b529f54", - "sha256:ccc6c650f8700ce1e3a77668bb7c43e45c20ac06ae00d22bdf6760b38958c883", - "sha256:cf680682ad0a3bef56dae200dbcbac2d57294a73e5b0f9864955e7dd7c2c2491", - "sha256:d2910d0a075caed95de1a605df00ee03b599de5419d0b95d55342e9a33ad1fb3", - "sha256:d5caa946a9f55511e76446e170bdad1d12d6b54e17a2afe7b189112ed4412bb8", - "sha256:d89b0dc7f005090e32bb4f9bf796e1dcca6b52243caf1803fdd2b748d8561f63", - "sha256:d95d16204cd51ff1a1c8d5f9958ce90ae190be81d348b514f9be39f878b8044a", - "sha256:e4d5a86a5257843a18fb1220c5f1c199532bc5d24e849ed4b0289fb59fbd4d8f", - "sha256:e58ddb53a7b4959932f5582ac455ff90dcb05fac3f8dcc8079498d43afbbde6c", - "sha256:e80fe25cba41c124d04c662f33f6364909b985f2eb5998aaa5ae4b9587242cce", - "sha256:eda2829af498946c59d8585a9fd74da3f810866e05f8df03a86f70079c7531dd", - "sha256:fd0a359c1c17f00cb37de2969984a74320970e0ceef4808c32e00773b06649d9" + "sha256:01721eefe70544d548425a07c80be8377096a54118070b8a62476866d5208e33", + "sha256:0318c465786c1f63ac05d7c4dbcecd4d2d7e13f0959b01b534ea1e92202235c5", + "sha256:05a0f648eb28bae4bcb204e6fd14603de2908de982e761a2fc78efe0f19e96e1", + "sha256:1412aa0aec3e00bc23fbb8664d76552b4efde98fb71f60737c83efbac24112f1", + "sha256:25b40b98ebdd272bc3020935427a4530b7d60dfbe1ab9381a39147834e985eac", + "sha256:2d4d1de6e6fb3d28781c73fbde702ac97f03d79e4ffd6598b880b2d95d62ead4", + "sha256:38e8648f9449a549a7dfe8d8755a5979b45b3538520d1e735637ef28e8c2dc50", + "sha256:4a3d5fb89bfe21be2ef47c0614b9c9c707b7362386c9a3ff1feae63e0267ccb6", + "sha256:635e6bd31c9fb3d475c8f44a089569070d10a9ef18ed13738b03049280281267", + "sha256:73101b2a1fef16602696d133db402a7e7586654682244344b8329cdcbbb82172", + "sha256:791492091744b0fe390a6ce85cc1bf5149968ac7d5f0477288f78c89b385d9af", + "sha256:7a708a79c9a9d26904d1cca8d383bf869edf6f8e7650d85dbc77b041e8c5a0f8", + "sha256:88c0b89ad1cc24a5efbb99ff9ab5db0f9a86e9cc50240177a571fbe9c2860ac2", + "sha256:8a326af80e86d0e9ce92bcc1e65c8ff88297de4fa14ee936cb2293d414c9ec63", + "sha256:8a92c5aea763d14ba9d6475803fc7904bda7decc2a0a68153f587ad82941fec1", + "sha256:91c6f5fc58df1e0a3cc0c3a717bb3308ff850abdaa6d2d802573ee2b11f674a8", + "sha256:95b995d0c413f5d0428b3f880e8fe1660ff9396dcd1f9eedbc311f37b5652e16", + "sha256:9749a40a5b22333467f02fe11edc98f022133ee1bfa8ab99bda5e5437b831214", + "sha256:978010b68e17150db8765355d1ccdd450f9fc916824e8c4e35ee620590e234cd", + "sha256:9a513bd9c1551894ee3d31369f9b07460ef223694098cf27d399513415855b68", + "sha256:a75b4498b1e93d8b700282dc8e655b8bd559c0904b3910b144646dbbbc03e062", + "sha256:c6a2324085dd52f96498419ba95b5777e40b6bcbc20088fddb9e8cbb58885e8e", + "sha256:d7a4aeac3b94af92a9373d6e77b37691b86411f9745190d2c351f410ab3a791f", + "sha256:d9e7912a56108aba9b31df688a4c4f5cb0d9d3787386b87d504762b6754fbb1b", + "sha256:dff4af63638afcc57a3dfb9e4b26d434a7a602d225b42d746ea7fe2edf1342fd", + "sha256:e46ceaff65609b5399163de5893d8f2a82d3c77d5e56d976c8b5fb01faa6b671", + "sha256:f01f28075a92eede918b965e86e8f0ba7b7797a95aa8d35e1cc8821f5fc3ad6a", + "sha256:fd7d7409fa643a91d0a05c7554dd68aa9c9bb16e186f6ccfe40d6e003156e33a" ], "markers": "python_version >= '3.7'", - "version": "==1.21.0" + "version": "==1.21.1" }, "oauthlib": { "hashes": [ @@ -955,36 +1203,55 @@ "markers": "python_version >= '3.6'", "version": "==3.1.1" }, + "openapi-schema-validator": { + "hashes": [ + "sha256:215b516d0942f4e8e2446cf3f7d4ff2ed71d102ebddcc30526d8a3f706ab1df6", + "sha256:a4b2712020284cee880b4c55faa513fbc2f8f07f365deda6098f8ab943c9f0df", + "sha256:b65d6c2242620bfe76d4c749b61cd9657e4528895a8f4fb6f916085b508ebd24" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.1.5" + }, + "openapi-spec-validator": { + "hashes": [ + "sha256:0a7da925bad4576f4518f77302c0b1990adb2fbcbe7d63fb4ed0de894cad8bdd", + "sha256:3d70e6592754799f7e77a45b98c6a91706bdd309a425169d17d8e92173e198a2", + "sha256:ba28b06e63274f2bc6de995a07fb572c657e534425b5baf68d9f7911efe6929f" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.3.1" + }, "packaging": { "hashes": [ - "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5", - "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a" + "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7", + "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.9" + "markers": "python_version >= '3.6'", + "version": "==21.0" }, "pandas": { "hashes": [ - "sha256:0c34b89215f984a9e4956446e0a29330d720085efa08ea72022387ee37d8b373", - "sha256:0dbd125b0e44e5068163cbc9080a00db1756a5e36309329ae14fd259747f2300", - "sha256:1102d719038e134e648e7920672188a00375f3908f0383fd3b202fbb9d2c3a95", - "sha256:14abb8ea73fce8aebbb1fb44bec809163f1c55241bcc1db91c2c780e97265033", - "sha256:25fc8ef6c6beb51c9224284a1ad89dfb591832f23ceff78845f182de35c52356", - "sha256:38e7486410de23069392bdf1dc7297ae75d2d67531750753f3149c871cd1c6e3", - "sha256:4bfbf62b00460f78a8bc4407112965c5ab44324f34551e8e1f4cac271a07706c", - "sha256:78de96c1174bcfdbe8dece9c38c2d7994e407fd8bb62146bb46c61294bcc06ef", - "sha256:7b09293c7119ab22ab3f7f086f813ac2acbfa3bcaaaeb650f4cddfb5b9fa9be4", - "sha256:821d92466fcd2826656374a9b6fe4f2ec2ba5e370cce71d5a990577929d948df", - "sha256:9244fb0904512b074d8c6362fb13aac1da6c4db94372760ddb2565c620240264", - "sha256:94ca6ea3f46f44a979a38a4d5a70a88cee734f7248d7aeeed202e6b3ba485af1", - "sha256:a67227e17236442c6bc31c02cb713b5277b26eee204eac14b5aecba52492e3a3", - "sha256:c862cd72353921c102166784fc4db749f1c3b691dd017fc36d9df2c67a9afe4e", - "sha256:d9e6edddeac9a8e473391d2d2067bb3c9dc7ad79fd137af26a39ee425c2b4c78", - "sha256:e36515163829e0e95a6af10820f178dd8768102482c01872bff8ae592e508e58", - "sha256:f20e4b8a7909f5a0c0a9e745091e3ea18b45af9f73496a4d498688badbdac7ea", - "sha256:fc9215dd1dd836ff26b896654e66b2dfcf4bbb18aa4c1089a79bab527b665a90" + "sha256:0c976e023ed580e60a82ccebdca8e1cc24d8b1fbb28175eb6521025c127dab66", + "sha256:114c6789d15862508900a25cb4cb51820bfdd8595ea306bab3b53cd19f990b65", + "sha256:1ee8418d0f936ff2216513aa03e199657eceb67690995d427a4a7ecd2e68f442", + "sha256:22f3fcc129fb482ef44e7df2a594f0bd514ac45aabe50da1a10709de1b0f9d84", + "sha256:23c7452771501254d2ae23e9e9dac88417de7e6eff3ce64ee494bb94dc88c300", + "sha256:341935a594db24f3ff07d1b34d1d231786aa9adfa84b76eab10bf42907c8aed3", + "sha256:45656cd59ae9745a1a21271a62001df58342b59c66d50754390066db500a8362", + "sha256:527c43311894aff131dea99cf418cd723bfd4f0bcf3c3da460f3b57e52a64da5", + "sha256:5c09a2538f0fddf3895070579082089ff4ae52b6cb176d8ec7a4dacf7e3676c1", + "sha256:5d9acfca191140a518779d1095036d842d5e5bc8e8ad8b5eaad1aff90fe1870d", + "sha256:5ee927c70794e875a59796fab8047098aa59787b1be680717c141cd7873818ae", + "sha256:7150039e78a81eddd9f5a05363a11cadf90a4968aac6f086fd83e66cf1c8d1d6", + "sha256:905fc3e0fcd86b0a9f1f97abee7d36894698d2592b22b859f08ea5a8fe3d3aab", + "sha256:9d06661c6eb741ae633ee1c57e8c432bb4203024e263fe1a077fa3fda7817fdb", + "sha256:9e1fe6722cbe27eb5891c1977bca62d456c19935352eea64d33956db46139364", + "sha256:be12d77f7e03c40a2466ed00ccd1a5f20a574d3c622fe1516037faa31aa448aa", + "sha256:c28760932283d2c9f6fa5e53d2f77a514163b9e67fd0ee0879081be612567195", + "sha256:e323028ab192fcfe1e8999c012a0fa96d066453bb354c7e7a4a267b25e73d3c8", + "sha256:fdb3b33dde260b1766ea4d3c6b8fbf6799cee18d50a2a8bc534cf3550b7c819a" ], - "version": "==1.2.5" + "version": "==1.3.1" }, "pandas-gbq": { "hashes": [ @@ -996,24 +1263,45 @@ }, "pathspec": { "hashes": [ - "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd", - "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d" + "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a", + "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1" ], - "version": "==0.8.1" + "version": "==0.9.0" }, "pendulum": { "hashes": [ - "sha256:253983de6d64a01909c2524e4ab27febd0d3987d001ea6ab93a7b945fdc0e6c6", - "sha256:3d8b280a903fb25bdba258203bbcd0533c5c04a65878f6e0700931dedd2bae72", - "sha256:4c945ed6a3b0afab8c2f1b1e3e26bb23ad0a9be6f201604111a8217cea78e7ab", - "sha256:501670f3b1d581395ec4094aff7c13dca6b699d1810cf15c446433b9e736eb4a", - "sha256:601e52cb0425e94b1784b6613a9085e0066ae1fa1915d18771884b67e93cac5c", - "sha256:76ee830b4b57a3f8244a228505bf9c55285cc92f1a200c8578b0ca54f8185861", - "sha256:b9a7ef02ad6255292f35218c595f8be35e0ca3c7ac19e633ff2de96480f26ab3", - "sha256:f30fb1149e4f67b3aaa9eae874dca7bbf49788ac121d702486f5b9fe549e7920" + "sha256:0731f0c661a3cb779d398803655494893c9f581f6488048b3fb629c2342b5394", + "sha256:1245cd0075a3c6d889f581f6325dd8404aca5884dea7223a5566c38aab94642b", + "sha256:29c40a6f2942376185728c9a0347d7c0f07905638c83007e1d262781f1e6953a", + "sha256:2d1619a721df661e506eff8db8614016f0720ac171fe80dda1333ee44e684087", + "sha256:318f72f62e8e23cd6660dbafe1e346950281a9aed144b5c596b2ddabc1d19739", + "sha256:33fb61601083f3eb1d15edeb45274f73c63b3c44a8524703dc143f4212bf3269", + "sha256:3481fad1dc3f6f6738bd575a951d3c15d4b4ce7c82dce37cf8ac1483fde6e8b0", + "sha256:4c9c689747f39d0d02a9f94fcee737b34a5773803a64a5fdb046ee9cac7442c5", + "sha256:7c5ec650cb4bec4c63a89a0242cc8c3cebcec92fcfe937c417ba18277d8560be", + "sha256:94b1fc947bfe38579b28e1cccb36f7e28a15e841f30384b5ad6c5e31055c85d7", + "sha256:9702069c694306297ed362ce7e3c1ef8404ac8ede39f9b28b7c1a7ad8c3959e3", + "sha256:b06a0ca1bfe41c990bbf0c029f0b6501a7f2ec4e38bfec730712015e8860f207", + "sha256:b6c352f4bd32dff1ea7066bd31ad0f71f8d8100b9ff709fb343f3b86cee43efe", + "sha256:c501749fdd3d6f9e726086bf0cd4437281ed47e7bca132ddb522f86a1645d360", + "sha256:c807a578a532eeb226150d5006f156632df2cc8c5693d778324b43ff8c515dd0", + "sha256:db0a40d8bcd27b4fb46676e8eb3c732c67a5a5e6bfab8927028224fbced0b40b", + "sha256:de42ea3e2943171a9e95141f2eecf972480636e8e484ccffaf1e833929e9e052", + "sha256:e95d329384717c7bf627bf27e204bc3b15c8238fa8d9d9781d93712776c14002", + "sha256:f5e236e7730cab1644e1b87aca3d2ff3e375a608542e90fe25685dae46310116", + "sha256:f888f2d2909a414680a29ae74d0592758f2b9fcdee3549887779cd4055e975db", + "sha256:fb53ffa0085002ddd43b6ca61a7b34f2d4d7c3ed66f931fe599e1a531b42af9b" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.4.4" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==2.1.2" + }, + "platformdirs": { + "hashes": [ + "sha256:4666d822218db6a262bdfdc9c39d21f23b4cfdb08af331a81e92751daf6c866c", + "sha256:632daad3ab546bd8e6af0537d09805cec458dce201bccfe23012df73332e181e" + ], + "markers": "python_version >= '3.6'", + "version": "==2.2.0" }, "pluggy": { "hashes": [ @@ -1032,11 +1320,11 @@ }, "proto-plus": { "hashes": [ - "sha256:600e2793ec1a0bf2b9e5ba18cd9eccbc1bc690a03c73b571bbe59789fbaaeecc", - "sha256:cfc45474c7eda0fe3c4b9eca2542124f2a0ff5543242bec61e8d08bce0f5bd48" + "sha256:ce6695ce804383ad6f392c4bb1874c323896290a1f656560de36416ba832d91e", + "sha256:df7c71c08dc06403bdb0fba58cf9bf5f217198f6488c26b768f81e03a738c059" ], "markers": "python_version >= '3.6'", - "version": "==1.18.1" + "version": "==1.19.0" }, "protobuf": { "hashes": [ @@ -1048,19 +1336,23 @@ "sha256:2ae692bb6d1992afb6b74348e7bb648a75bb0d3565a3f5eea5bec8f62bd06d87", "sha256:2bfb815216a9cd9faec52b16fd2bfa68437a44b67c56bee59bc3926522ecb04e", "sha256:4ffbd23640bb7403574f7aff8368e2aeb2ec9a5c6306580be48ac59a6bac8bde", + "sha256:59e5cf6b737c3a376932fbfb869043415f7c16a0cf176ab30a5bbc419cd709c1", "sha256:6902a1e4b7a319ec611a7345ff81b6b004b36b0d2196ce7a748b3493da3d226d", "sha256:6ce4d8bf0321e7b2d4395e253f8002a1a5ffbcfd7bcc0a6ba46712c07d47d0b4", "sha256:6d847c59963c03fd7a0cd7c488cadfa10cda4fff34d8bc8cba92935a91b7a037", "sha256:72804ea5eaa9c22a090d2803813e280fb273b62d5ae497aaf3553d141c4fdd7b", "sha256:7a4c97961e9e5b03a56f9a6c82742ed55375c4a25f2692b625d4087d02ed31b9", + "sha256:85d6303e4adade2827e43c2b54114d9a6ea547b671cb63fafd5011dc47d0e13d", "sha256:8727ee027157516e2c311f218ebf2260a18088ffb2d29473e82add217d196b1c", "sha256:99938f2a2d7ca6563c0ade0c5ca8982264c484fdecf418bd68e880a7ab5730b1", "sha256:9b7a5c1022e0fa0dbde7fd03682d07d14624ad870ae52054849d8960f04bc764", "sha256:a22b3a0dbac6544dacbafd4c5f6a29e389a50e3b193e2c70dae6bbf7930f651d", + "sha256:a38bac25f51c93e4be4092c88b2568b9f407c27217d3dd23c7a57fa522a17554", "sha256:a981222367fb4210a10a929ad5983ae93bd5a050a0824fc35d6371c07b78caf6", "sha256:ab6bb0e270c6c58e7ff4345b3a803cc59dbee19ddf77a4719c5b635f1d547aa8", "sha256:c56c050a947186ba51de4f94ab441d7f04fcd44c56df6e922369cc2e1a92d683", "sha256:e76d9686e088fece2450dbc7ee905f9be904e427341d289acbe9ad00b78ebd47", + "sha256:ebcb546f10069b56dc2e3da35e003a02076aaa377caf8530fe9789570984a8d2", "sha256:f0e59430ee953184a703a324b8ec52f571c6c4259d496a19d1cabcdc19dabc62", "sha256:ffea251f5cd3c0b9b43c7a7a912777e0bc86263436a87c2555242a348817221b" ], @@ -1110,33 +1402,36 @@ }, "pyarrow": { "hashes": [ - "sha256:04be0f7cb9090bd029b5b53bed628548fef569e5d0b5c6cd7f6d0106dbbc782d", - "sha256:0fde9c7a3d5d37f3fe5d18c4ed015e8f585b68b26d72a10d7012cad61afe43ff", - "sha256:11517f0b4f4acbab0c37c674b4d1aad3c3dfea0f6b1bb322e921555258101ab3", - "sha256:150db335143edd00d3ec669c7c8167d401c4aa0a290749351c80bbf146892b2e", - "sha256:24040a20208e9b16ba7b284624ebfe67e40f5c40b5dc8d874da322ac0053f9d3", - "sha256:33c457728a1ce825b80aa8c8ed573709f1efe72003d45fa6fdbb444de9cc0b74", - "sha256:423cd6a14810f4e40cb76e13d4240040fc1594d69fe1c4f2c70be00ad512ade5", - "sha256:5387db80c6a7b5598884bf4df3fc546b3373771ad614548b782e840b71704877", - "sha256:5a76ec44af838862b23fb5cfc48765bc7978f7b58a181c96ad92856280de548b", - "sha256:5f2660f59dfcfd34adac7c08dc7f615920de703f191066ed6277628975f06878", - "sha256:6b7bd8f5aa327cc32a1b9b02a76502851575f5edb110f93c59a45c70211a5618", - "sha256:72cf3477538bd8504f14d6299a387cc335444f7a188f548096dfea9533551f02", - "sha256:76b75a9cfc572e890a1e000fd532bdd2084ec3f1ee94ee51802a477913a21072", - "sha256:a81adbfbe2f6528d4593b5a8962b2751838517401d14e9d4cab6787478802693", - "sha256:a968375c66e505f72b421f5864a37f51aad5da61b6396fa283f956e9f2b2b923", - "sha256:afd4f7c0a225a326d2c0039cdc8631b5e8be30f78f6b7a3e5ce741cf5dd81c72", - "sha256:b05bdd513f045d43228247ef4d9269c88139788e2d566f4cb3e855e282ad0330", - "sha256:c2733c9bcd00074ce5497dd0a7b8a10c91d3395ddce322d7021c7fdc4ea6f610", - "sha256:d0f080b2d9720bec42624cb0df66f60ae66b84a2ccd1fe2c291322df915ac9db", - "sha256:dcd20ee0240a88772eeb5691102c276f5cdec79527fb3a0679af7f93f93cb4bd", - "sha256:e1351576877764fb4d5690e4721ce902e987c85f4ab081c70a34e1d24646586e", - "sha256:e44dfd7e61c9eb6dda59bc49ad69e77945f6d049185a517c130417e3ca0494d8", - "sha256:ee3d87615876550fee9a523307dd4b00f0f44cf47a94a32a07793da307df31a0", - "sha256:fa7b165cfa97158c1e6d15c68428317b4f4ae786d1dc2dbab43f1328c1eb43aa", - "sha256:fe976695318560a97c6d31bba828eeca28c44c6f6401005e54ba476a28ac0a10" - ], - "version": "==4.0.1" + "sha256:1832709281efefa4f199c639e9f429678286329860188e53beeda71750775923", + "sha256:1d9485741e497ccc516cb0a0c8f56e22be55aea815be185c3f9a681323b0e614", + "sha256:24e64ea33eed07441cc0e80c949e3a1b48211a1add8953268391d250f4d39922", + "sha256:2d26186ca9748a1fb89ae6c1fa04fb343a4279b53f118734ea8096f15d66c820", + "sha256:357605665fbefb573d40939b13a684c2490b6ed1ab4a5de8dd246db4ab02e5a4", + "sha256:4341ac0f552dc04c450751e049976940c7f4f8f2dae03685cc465ebe0a61e231", + "sha256:456a4488ae810a0569d1adf87dbc522bcc9a0e4a8d1809b934ca28c163d8edce", + "sha256:4d8adda1892ef4553c4804af7f67cce484f4d6371564e2d8374b8e2bc85293e2", + "sha256:53e550dec60d1ab86cba3afa1719dc179a8bc9632a0e50d9fe91499cf0a7f2bc", + "sha256:5c0d1b68e67bb334a5af0cecdf9b6a702aaa4cc259c5cbb71b25bbed40fcedaf", + "sha256:601b0aabd6fb066429e706282934d4d8d38f53bdb8d82da9576be49f07eedf5c", + "sha256:64f30aa6b28b666a925d11c239344741850eb97c29d3aa0f7187918cf82494f7", + "sha256:6e1f0e4374061116f40e541408a8a170c170d0a070b788717e18165ebfdd2a54", + "sha256:6e937ce4a40ea0cc7896faff96adecadd4485beb53fbf510b46858e29b2e75ae", + "sha256:7560332e5846f0e7830b377c14c93624e24a17f91c98f0b25dafb0ca1ea6ba02", + "sha256:7c4edd2bacee3eea6c8c28bddb02347f9d41a55ec9692c71c6de6e47c62a7f0d", + "sha256:99c8b0f7e2ce2541dd4c0c0101d9944bb8e592ae3295fe7a2f290ab99222666d", + "sha256:9e04d3621b9f2f23898eed0d044203f66c156d880f02c5534a7f9947ebb1a4af", + "sha256:b1453c2411b5062ba6bf6832dbc4df211ad625f678c623a2ee177aee158f199b", + "sha256:b3115df938b8d7a7372911a3cb3904196194bcea8bb48911b4b3eafee3ab8d90", + "sha256:b6387d2058d95fa48ccfedea810a768187affb62f4a3ef6595fa30bf9d1a65cf", + "sha256:bbe2e439bec2618c74a3bb259700c8a7353dc2ea0c5a62686b6cf04a50ab1e0d", + "sha256:c3fc856f107ca2fb3c9391d7ea33bbb33f3a1c2b4a0e2b41f7525c626214cc03", + "sha256:c5493d2414d0d690a738aac8dd6d38518d1f9b870e52e24f89d8d7eb3afd4161", + "sha256:e9ec80f4a77057498cf4c5965389e42e7f6a618b6859e6dd615e57505c9167a6", + "sha256:ed135a99975380c27077f9d0e210aea8618ed9fadcec0e71f8a3190939557afe", + "sha256:f4db312e9ba80e730cefcae0a05b63ea5befc7634c28df56682b628ad8e1c25c", + "sha256:ff21711f6ff3b0bc90abc8ca8169e676faeb2401ddc1a0bc1c7dc181708a3406" + ], + "version": "==5.0.0" }, "pyasn1": { "hashes": [ @@ -1210,7 +1505,7 @@ "sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f", "sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e" ], - "markers": "python_version >= '3.5'", + "markers": "python_full_version >= '3.5.0'", "version": "==2.9.0" }, "pyjwt": { @@ -1225,6 +1520,7 @@ "sha256:4c231c759543ba02560fcd2480c48dcec4dae34c9da7d3747c508227e0624b51", "sha256:818ae18e06922c066f777a33f1fca45786d85edfe71cd043de6379337a7f274b" ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==20.0.1" }, "pyparsing": { @@ -1232,15 +1528,35 @@ "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.4.7" }, "pyrsistent": { "hashes": [ - "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e" + "sha256:097b96f129dd36a8c9e33594e7ebb151b1515eb52cceb08474c10a5479e799f2", + "sha256:2aaf19dc8ce517a8653746d98e962ef480ff34b6bc563fc067be6401ffb457c7", + "sha256:404e1f1d254d314d55adb8d87f4f465c8693d6f902f67eb6ef5b4526dc58e6ea", + "sha256:48578680353f41dca1ca3dc48629fb77dfc745128b56fc01096b2530c13fd426", + "sha256:4916c10896721e472ee12c95cdc2891ce5890898d2f9907b1b4ae0f53588b710", + "sha256:527be2bfa8dc80f6f8ddd65242ba476a6c4fb4e3aedbf281dfbac1b1ed4165b1", + "sha256:58a70d93fb79dc585b21f9d72487b929a6fe58da0754fa4cb9f279bb92369396", + "sha256:5e4395bbf841693eaebaa5bb5c8f5cdbb1d139e07c975c682ec4e4f8126e03d2", + "sha256:6b5eed00e597b5b5773b4ca30bd48a5774ef1e96f2a45d105db5b4ebb4bca680", + "sha256:73ff61b1411e3fb0ba144b8f08d6749749775fe89688093e1efef9839d2dcc35", + "sha256:772e94c2c6864f2cd2ffbe58bb3bdefbe2a32afa0acb1a77e472aac831f83427", + "sha256:773c781216f8c2900b42a7b638d5b517bb134ae1acbebe4d1e8f1f41ea60eb4b", + "sha256:a0c772d791c38bbc77be659af29bb14c38ced151433592e326361610250c605b", + "sha256:b29b869cf58412ca5738d23691e96d8aff535e17390128a1a52717c9a109da4f", + "sha256:c1a9ff320fa699337e05edcaae79ef8c2880b52720bc031b219e5b5008ebbdef", + "sha256:cd3caef37a415fd0dae6148a1b6957a8c5f275a62cca02e18474608cb263640c", + "sha256:d5ec194c9c573aafaceebf05fc400656722793dac57f254cd4741f3c27ae57b4", + "sha256:da6e5e818d18459fa46fac0a4a4e543507fe1110e808101277c5a2b5bab0cd2d", + "sha256:e79d94ca58fcafef6395f6352383fa1a76922268fa02caa2272fff501c2fdc78", + "sha256:f3ef98d7b76da5eb19c37fda834d50262ff9167c65658d1d8f974d2e4d90676b", + "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72" ], - "markers": "python_version >= '3.5'", - "version": "==0.17.3" + "markers": "python_version >= '3.6'", + "version": "==0.18.0" }, "pytest": { "hashes": [ @@ -1267,11 +1583,11 @@ }, "python-dateutil": { "hashes": [ - "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", - "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" + "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", + "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.1" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==2.8.2" }, "python-editor": { "hashes": [ @@ -1349,63 +1665,53 @@ "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6", "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==5.4.1" }, "regex": { "hashes": [ - "sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5", - "sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79", - "sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31", - "sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500", - "sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11", - "sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14", - "sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3", - "sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439", - "sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c", - "sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82", - "sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711", - "sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093", - "sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a", - "sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb", - "sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8", - "sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17", - "sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000", - "sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d", - "sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480", - "sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc", - "sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0", - "sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9", - "sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765", - "sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e", - "sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a", - "sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07", - "sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f", - "sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac", - "sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7", - "sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed", - "sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968", - "sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7", - "sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2", - "sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4", - "sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87", - "sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8", - "sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10", - "sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29", - "sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605", - "sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6", - "sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042" - ], - "version": "==2021.4.4" + "sha256:026beb631097a4a3def7299aa5825e05e057de3c6d72b139c37813bfa351274b", + "sha256:14caacd1853e40103f59571f169704367e79fb78fac3d6d09ac84d9197cadd16", + "sha256:16d9eaa8c7e91537516c20da37db975f09ac2e7772a0694b245076c6d68f85da", + "sha256:18fdc51458abc0a974822333bd3a932d4e06ba2a3243e9a1da305668bd62ec6d", + "sha256:28e8af338240b6f39713a34e337c3813047896ace09d51593d6907c66c0708ba", + "sha256:3835de96524a7b6869a6c710b26c90e94558c31006e96ca3cf6af6751b27dca1", + "sha256:3905c86cc4ab6d71635d6419a6f8d972cab7c634539bba6053c47354fd04452c", + "sha256:3c09d88a07483231119f5017904db8f60ad67906efac3f1baa31b9b7f7cca281", + "sha256:4551728b767f35f86b8e5ec19a363df87450c7376d7419c3cac5b9ceb4bce576", + "sha256:459bbe342c5b2dec5c5223e7c363f291558bc27982ef39ffd6569e8c082bdc83", + "sha256:4f421e3cdd3a273bace013751c345f4ebeef08f05e8c10757533ada360b51a39", + "sha256:577737ec3d4c195c4aef01b757905779a9e9aee608fa1cf0aec16b5576c893d3", + "sha256:57fece29f7cc55d882fe282d9de52f2f522bb85290555b49394102f3621751ee", + "sha256:7976d410e42be9ae7458c1816a416218364e06e162b82e42f7060737e711d9ce", + "sha256:85f568892422a0e96235eb8ea6c5a41c8ccbf55576a2260c0160800dbd7c4f20", + "sha256:8764a78c5464ac6bde91a8c87dd718c27c1cabb7ed2b4beaf36d3e8e390567f9", + "sha256:8935937dad2c9b369c3d932b0edbc52a62647c2afb2fafc0c280f14a8bf56a6a", + "sha256:8fe58d9f6e3d1abf690174fd75800fda9bdc23d2a287e77758dc0e8567e38ce6", + "sha256:937b20955806381e08e54bd9d71f83276d1f883264808521b70b33d98e4dec5d", + "sha256:9569da9e78f0947b249370cb8fadf1015a193c359e7e442ac9ecc585d937f08d", + "sha256:a3b73390511edd2db2d34ff09aa0b2c08be974c71b4c0505b4a048d5dc128c2b", + "sha256:a4eddbe2a715b2dd3849afbdeacf1cc283160b24e09baf64fa5675f51940419d", + "sha256:a5c6dbe09aff091adfa8c7cfc1a0e83fdb8021ddb2c183512775a14f1435fe16", + "sha256:b63e3571b24a7959017573b6455e05b675050bbbea69408f35f3cb984ec54363", + "sha256:bb350eb1060591d8e89d6bac4713d41006cd4d479f5e11db334a48ff8999512f", + "sha256:bf6d987edd4a44dd2fa2723fca2790f9442ae4de2c8438e53fcb1befdf5d823a", + "sha256:bfa6a679410b394600eafd16336b2ce8de43e9b13f7fb9247d84ef5ad2b45e91", + "sha256:c856ec9b42e5af4fe2d8e75970fcc3a2c15925cbcc6e7a9bcb44583b10b95e80", + "sha256:cea56288eeda8b7511d507bbe7790d89ae7049daa5f51ae31a35ae3c05408531", + "sha256:ea212df6e5d3f60341aef46401d32fcfded85593af1d82b8b4a7a68cd67fdd6b", + "sha256:f35567470ee6dbfb946f069ed5f5615b40edcbb5f1e6e1d3d2b114468d505fc6", + "sha256:fbc20975eee093efa2071de80df7f972b7b35e560b213aafabcec7c0bd00bd8c", + "sha256:ff4a8ad9638b7ca52313d8732f37ecd5fd3c8e3aff10a8ccb93176fd5b3812f6" + ], + "version": "==2021.8.3" }, "requests": { "hashes": [ - "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee", - "sha256:5d2d0ffbb515f39417009a46c14256291061ac01ba8f875b90cad137de83beb4", - "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6" + "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", + "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" ], - "markers": "python_version >= '3'", - "version": "==2.23.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==2.26.0" }, "requests-oauthlib": { "hashes": [ @@ -1415,6 +1721,24 @@ ], "version": "==1.3.0" }, + "rfc3986": { + "extras": [ + "idna2008" + ], + "hashes": [ + "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835", + "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97" + ], + "version": "==1.5.0" + }, + "rich": { + "hashes": [ + "sha256:13ac80676e12cf528dc4228dc682c8402f82577c2aa67191e294350fa2c3c4e9", + "sha256:517b4e0efd064dd1fe821ca93dd3095d73380ceac1f0a07173d507d9b18f1396" + ], + "markers": "python_version >= '3.6' and python_version < '4.0'", + "version": "==10.7.0" + }, "rsa": { "hashes": [ "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2", @@ -1433,40 +1757,30 @@ }, "ruamel.yaml.clib": { "hashes": [ - "sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b", - "sha256:1236df55e0f73cd138c0eca074ee086136c3f16a97c2ac719032c050f7e0622f", - "sha256:1f8c0a4577c0e6c99d208de5c4d3fd8aceed9574bb154d7a2b21c16bb924154c", - "sha256:2602e91bd5c1b874d6f93d3086f9830f3e907c543c7672cf293a97c3fabdcd91", - "sha256:28116f204103cb3a108dfd37668f20abe6e3cafd0d3fd40dba126c732457b3cc", - "sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7", - "sha256:2fd336a5c6415c82e2deb40d08c222087febe0aebe520f4d21910629018ab0f3", - "sha256:30dca9bbcbb1cc858717438218d11eafb78666759e5094dd767468c0d577a7e7", - "sha256:44c7b0498c39f27795224438f1a6be6c5352f82cb887bc33d962c3a3acc00df6", - "sha256:464e66a04e740d754170be5e740657a3b3b6d2bcc567f0c3437879a6e6087ff6", - "sha256:46d6d20815064e8bb023ea8628cfb7402c0f0e83de2c2227a88097e239a7dffd", - "sha256:4df5019e7783d14b79217ad9c56edf1ba7485d614ad5a385d1b3c768635c81c0", - "sha256:4e52c96ca66de04be42ea2278012a2342d89f5e82b4512fb6fb7134e377e2e62", - "sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99", - "sha256:52ae5739e4b5d6317b52f5b040b1b6639e8af68a5b8fd606a8b08658fbd0cab5", - "sha256:53b9dd1abd70e257a6e32f934ebc482dac5edb8c93e23deb663eac724c30b026", - "sha256:6c0a5dc52fc74eb87c67374a4e554d4761fd42a4d01390b7e868b30d21f4b8bb", - "sha256:73b3d43e04cc4b228fa6fa5d796409ece6fcb53a6c270eb2048109cbcbc3b9c2", - "sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1", - "sha256:75f0ee6839532e52a3a53f80ce64925ed4aed697dd3fa890c4c918f3304bd4f4", - "sha256:839dd72545ef7ba78fd2aa1a5dd07b33696adf3e68fae7f31327161c1093001b", - "sha256:8be05be57dc5c7b4a0b24edcaa2f7275866d9c907725226cdde46da09367d923", - "sha256:8e8fd0a22c9d92af3a34f91e8a2594eeb35cba90ab643c5e0e643567dc8be43e", - "sha256:a873e4d4954f865dcb60bdc4914af7eaae48fb56b60ed6daa1d6251c72f5337c", - "sha256:ab845f1f51f7eb750a78937be9f79baea4a42c7960f5a94dde34e69f3cce1988", - "sha256:b1e981fe1aff1fd11627f531524826a4dcc1f26c726235a52fcb62ded27d150f", - "sha256:b4b0d31f2052b3f9f9b5327024dc629a253a83d8649d4734ca7f35b60ec3e9e5", - "sha256:c6ac7e45367b1317e56f1461719c853fd6825226f45b835df7436bb04031fd8a", - "sha256:daf21aa33ee9b351f66deed30a3d450ab55c14242cfdfcd377798e2c0d25c9f1", - "sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2", - "sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f" - ], - "markers": "python_version < '3.10' and platform_python_implementation == 'CPython'", - "version": "==0.2.2" + "sha256:0847201b767447fc33b9c235780d3aa90357d20dd6108b92be544427bea197dd", + "sha256:1866cf2c284a03b9524a5cc00daca56d80057c5ce3cdc86a52020f4c720856f0", + "sha256:31ea73e564a7b5fbbe8188ab8b334393e06d997914a4e184975348f204790277", + "sha256:3fb9575a5acd13031c57a62cc7823e5d2ff8bc3835ba4d94b921b4e6ee664104", + "sha256:4ff604ce439abb20794f05613c374759ce10e3595d1867764dd1ae675b85acbd", + "sha256:72a2b8b2ff0a627496aad76f37a652bcef400fd861721744201ef1b45199ab78", + "sha256:78988ed190206672da0f5d50c61afef8f67daa718d614377dcd5e3ed85ab4a99", + "sha256:7b2927e92feb51d830f531de4ccb11b320255ee95e791022555971c466af4527", + "sha256:7f7ecb53ae6848f959db6ae93bdff1740e651809780822270eab111500842a84", + "sha256:825d5fccef6da42f3c8eccd4281af399f21c02b32d98e113dbc631ea6a6ecbc7", + "sha256:846fc8336443106fe23f9b6d6b8c14a53d38cef9a375149d61f99d78782ea468", + "sha256:89221ec6d6026f8ae859c09b9718799fea22c0e8da8b766b0b2c9a9ba2db326b", + "sha256:9efef4aab5353387b07f6b22ace0867032b900d8e91674b5d8ea9150db5cae94", + "sha256:a32f8d81ea0c6173ab1b3da956869114cae53ba1e9f72374032e33ba3118c233", + "sha256:a49e0161897901d1ac9c4a79984b8410f450565bbad64dbfcbf76152743a0cdb", + "sha256:ada3f400d9923a190ea8b59c8f60680c4ef8a4b0dfae134d2f2ff68429adfab5", + "sha256:bf75d28fa071645c529b5474a550a44686821decebdd00e21127ef1fd566eabe", + "sha256:cfdb9389d888c5b74af297e51ce357b800dd844898af9d4a547ffc143fa56751", + "sha256:d67f273097c368265a7b81e152e07fb90ed395df6e552b9fa858c6d2c9f42502", + "sha256:dc6a613d6c74eef5a14a214d433d06291526145431c3b964f5e16529b1842bed", + "sha256:de9c6b8a1ba52919ae919f3ae96abb72b994dd0350226e28f3686cb4f142165c" + ], + "markers": "platform_python_implementation == 'CPython' and python_version < '3.10'", + "version": "==0.2.6" }, "setproctitle": { "hashes": [ @@ -1500,31 +1814,73 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" }, + "sniffio": { + "hashes": [ + "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663", + "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de" + ], + "markers": "python_full_version >= '3.5.0'", + "version": "==1.2.0" + }, "sqlalchemy": { "hashes": [ - "sha256:c4cca4aed606297afbe90d4306b49ad3a4cd36feb3f87e4bfd655c57fd9ef445" + "sha256:0942a3a0df3f6131580eddd26d99071b48cfe5aaf3eab2783076fbc5a1c1882e", + "sha256:0ec575db1b54909750332c2e335c2bb11257883914a03bc5a3306a4488ecc772", + "sha256:109581ccc8915001e8037b73c29590e78ce74be49ca0a3630a23831f9e3ed6c7", + "sha256:16593fd748944726540cd20f7e83afec816c2ac96b082e26ae226e8f7e9688cf", + "sha256:427273b08efc16a85aa2b39892817e78e3ed074fcb89b2a51c4979bae7e7ba98", + "sha256:50c4ee32f0e1581828843267d8de35c3298e86ceecd5e9017dc45788be70a864", + "sha256:512a85c3c8c3995cc91af3e90f38f460da5d3cade8dc3a229c8e0879037547c9", + "sha256:57aa843b783179ab72e863512e14bdcba186641daf69e4e3a5761d705dcc35b1", + "sha256:621f58cd921cd71ba6215c42954ffaa8a918eecd8c535d97befa1a8acad986dd", + "sha256:6ac2558631a81b85e7fb7a44e5035347938b0a73f5fdc27a8566777d0792a6a4", + "sha256:716754d0b5490bdcf68e1e4925edc02ac07209883314ad01a137642ddb2056f1", + "sha256:736d41cfebedecc6f159fc4ac0769dc89528a989471dc1d378ba07d29a60ba1c", + "sha256:8619b86cb68b185a778635be5b3e6018623c0761dde4df2f112896424aa27bd8", + "sha256:87fad64529cde4f1914a5b9c383628e1a8f9e3930304c09cf22c2ae118a1280e", + "sha256:89494df7f93b1836cae210c42864b292f9b31eeabca4810193761990dc689cce", + "sha256:8cac7bb373a5f1423e28de3fd5fc8063b9c8ffe8957dc1b1a59cb90453db6da1", + "sha256:8fd452dc3d49b3cc54483e033de6c006c304432e6f84b74d7b2c68afa2569ae5", + "sha256:adad60eea2c4c2a1875eb6305a0b6e61a83163f8e233586a4d6a55221ef984fe", + "sha256:c26f95e7609b821b5f08a72dab929baa0d685406b953efd7c89423a511d5c413", + "sha256:cbe1324ef52ff26ccde2cb84b8593c8bf930069dfc06c1e616f1bfd4e47f48a3", + "sha256:d05c4adae06bd0c7f696ae3ec8d993ed8ffcc4e11a76b1b35a5af8a099bd2284", + "sha256:d98bc827a1293ae767c8f2f18be3bb5151fd37ddcd7da2a5f9581baeeb7a3fa1", + "sha256:da2fb75f64792c1fc64c82313a00c728a7c301efe6a60b7a9fe35b16b4368ce7", + "sha256:e4624d7edb2576cd72bb83636cd71c8ce544d8e272f308bd80885056972ca299", + "sha256:e89e0d9e106f8a9180a4ca92a6adde60c58b1b0299e1b43bd5e0312f535fbf33", + "sha256:f11c2437fb5f812d020932119ba02d9e2bc29a6eca01a055233a8b449e3e1e7d", + "sha256:f57be5673e12763dd400fea568608700a63ce1c6bd5bdbc3cc3a2c5fdb045274", + "sha256:fc728ece3d5c772c196fd338a99798e7efac7a04f9cb6416299a3638ee9a94cd" ], "index": "pypi", - "version": "==1.3.15" + "version": "==1.3.18" }, "sqlalchemy-jsonfield": { "hashes": [ - "sha256:1abf295f7215c8f1c0b0d30d659f4372870fc83755874ef21cad7e2f2d6419ba", - "sha256:1cb760abf186a97beb5acdfd47dc2f98829070f679a838869162cd7c0b447e0d" + "sha256:766d0b25bdebf53f67ccfaf9975987f921965987b37bae3a95ba6e7855afe98b", + "sha256:db129c0e79f6b3c61ca88b340363e2cc2023a187a40b9992dfee33bc75c3a02c" ], - "markers": "python_version >= '3.5'", - "version": "==0.9.0" + "markers": "python_full_version >= '3.5.0'", + "version": "==1.0.0" }, "sqlalchemy-utils": { "hashes": [ - "sha256:716d9d9592258db9651a511d03e6b2553242c2a440855ee3f7d5812bbb55d9eb", - "sha256:afd204ed051f53302cd8789cc29c9b15bf458f8baef14a9052bf2823f855d2cb" + "sha256:a6aaee154f798be4e479af0ceffaa5034d35fcf6f40707c0947d21bde64e05e5", + "sha256:b1bf67d904fed16b16ef1dc07f03e5e93a6b23899f920f6b41c09be45fbb85f2" ], "markers": "python_version ~= '3.4'", - "version": "==0.37.7" + "version": "==0.37.8" + }, + "swagger-ui-bundle": { + "hashes": [ + "sha256:f5255f786cde67a2638111f4a7d04355836743198a83c4ecbe815d9fc384b0c8", + "sha256:f5691167f2e9f73ecbe8229a89454ae5ea958f90bb0d4583ed7adaae598c4122" + ], + "version": "==0.0.8" }, "tabulate": { "hashes": [ @@ -1535,10 +1891,16 @@ }, "tenacity": { "hashes": [ - "sha256:0dff43d3faa411ebb8506b6adc174ef725df18322eef8437aabf4f63e478ec11", - "sha256:dcd7646fe731b21b73870ead85a965a4202abeaf56e0588e6a8b38375110098f" + "sha256:29ae90e7faf488a8628432154bb34ace1cca58244c6ea399fd33f066ac71339a", + "sha256:5a5d3dcd46381abe8b4f82b5736b8726fd3160c6c7161f53f8af7f1eb9b82173" ], - "version": "==4.12.0" + "version": "==6.2.0" + }, + "termcolor": { + "hashes": [ + "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b" + ], + "version": "==1.1.0" }, "text-unidecode": { "hashes": [ @@ -1547,18 +1909,12 @@ ], "version": "==1.3" }, - "thrift": { - "hashes": [ - "sha256:9af1c86bf73433afc6010ed376a6c6aca2b54099cc0d61895f640870a9ae7d89" - ], - "version": "==0.13.0" - }, "toml": { "hashes": [ "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'", "version": "==0.10.2" }, "typed-ast": { @@ -1612,12 +1968,6 @@ ], "version": "==0.7.1" }, - "tzlocal": { - "hashes": [ - "sha256:4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e" - ], - "version": "==1.5.1" - }, "unicodecsv": { "hashes": [ "sha256:018c08037d48649a0412063ff4eda26eaa81eff1546dbffa51fa5293276ff7fc" @@ -1634,27 +1984,35 @@ }, "urllib3": { "hashes": [ - "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2", - "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e" + "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4", + "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.25.11" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4.0'", + "version": "==1.26.6" + }, + "virtualenv": { + "hashes": [ + "sha256:97066a978431ec096d163e72771df5357c5c898ffdd587048f45e0aecc228094", + "sha256:fdfdaaf0979ac03ae7f76d5224a05b58165f3c804f8aa633f3dd6f22fbd435d5" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==20.7.0" }, "websocket-client": { "hashes": [ - "sha256:b68e4959d704768fa20e35c9d508c8dc2bbc041fd8d267c0d7345cffe2824568", - "sha256:e5c333bfa9fa739538b652b6f8c8fc2559f1d364243c8a689d7c0e1d41c2e611" + "sha256:4cf754af7e3b3ba76589d49f9e09fd9a6c0aae9b799a89124d656009c01a261d", + "sha256:8d07f155f8ed14ae3ced97bd7582b08f280bb1bfd27945f023ba2aceff05ab52" ], "markers": "python_version >= '3.6'", - "version": "==1.1.0" + "version": "==1.1.1" }, "werkzeug": { "hashes": [ - "sha256:1e0dedc2acb1f46827daa2e399c1485c8fa17c0d8e70b6b875b4e7f54bf408d2", - "sha256:b353856d37dec59d6511359f97f6a4b2468442e454bd1c98298ddce53cac1f04" + "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43", + "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.16.1" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.0.1" }, "wtforms": { "hashes": [ @@ -1665,18 +2023,11 @@ }, "zipp": { "hashes": [ - "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76", - "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098" + "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3", + "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4" ], "markers": "python_version >= '3.6'", - "version": "==3.4.1" - }, - "zope.deprecation": { - "hashes": [ - "sha256:0d453338f04bacf91bbfba545d8bcdf529aa829e67b705eac8c1a7fdce66e2df", - "sha256:f1480b74995958b24ce37b0ef04d3663d2683e5d6debc96726eff18acf4ea113" - ], - "version": "==4.4.0" + "version": "==3.5.0" } } } diff --git a/README.md b/README.md index 1ead1b08b..32862b2b6 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ Cloud-native, data pipeline architecture for onboarding public datasets to [Data # Requirements - Python `>=3.6.10,<3.9`. We currently use `3.8`. For more info, see the [Cloud Composer version list](https://cloud.google.com/composer/docs/concepts/versioning/composer-versions). -- Familiarity with [Apache Airflow](https://airflow.apache.org/docs/apache-airflow/1.10.15/concepts.html) (>=v1.10.15) +- Familiarity with [Apache Airflow](https://airflow.apache.org/docs/apache-airflow/stable/concepts/index.html) (>=v2.1) - [pipenv](https://pipenv-fork.readthedocs.io/en/latest/install.html#installing-pipenv) for creating similar Python environments via `Pipfile.lock` - [gcloud](https://cloud.google.com/sdk/gcloud) command-line tool with Google Cloud Platform credentials configured. Instructions can be found [here](https://cloud.google.com/sdk/docs/initializing). - [Terraform](https://learn.hashicorp.com/tutorials/terraform/install-cli) `>=v0.15.1` -- [Google Cloud Composer](https://cloud.google.com/composer/docs/concepts/overview) environment running [Apache Airflow](https://airflow.apache.org/docs/apache-airflow/1.10.15/concepts.html) `>=v1.10.15,<2.0`. To create a new Cloud Composer environment, see [this guide](https://cloud.google.com/composer/docs/how-to/managing/creating). +- [Google Cloud Composer](https://cloud.google.com/composer/docs/concepts/overview) environment running [Apache Airflow](https://airflow.apache.org/docs/apache-airflow/stable/concepts.html) `>=2.0`. To create a new Cloud Composer environment, see [this guide](https://cloud.google.com/composer/docs/how-to/managing/creating). # Environment Setup diff --git a/datasets/usa_names/usa_1910_current/pipeline.yaml b/datasets/usa_names/usa_1910_current/pipeline.yaml index 8e8133cf8..53153ffca 100644 --- a/datasets/usa_names/usa_1910_current/pipeline.yaml +++ b/datasets/usa_names/usa_1910_current/pipeline.yaml @@ -22,6 +22,7 @@ resources: source: http://www.ssa.gov/OACT/babynames/limits.html dag: + airflow_version: 2 initialize: dag_id: "usa_1910_current" default_args: diff --git a/datasets/usa_names/usa_1910_current/usa_1910_current_dag.py b/datasets/usa_names/usa_1910_current/usa_1910_current_dag.py index 35ddb42b1..eb00496a7 100644 --- a/datasets/usa_names/usa_1910_current/usa_1910_current_dag.py +++ b/datasets/usa_names/usa_1910_current/usa_1910_current_dag.py @@ -14,8 +14,8 @@ from airflow import DAG -from airflow.contrib.operators import gcs_to_bq -from airflow.operators import bash_operator +from airflow.operators import bash +from airflow.providers.google.cloud.transfers import gcs_to_bigquery default_args = { "owner": "Google", @@ -34,7 +34,7 @@ ) as dag: # Task to copy `namesbystate.zip` from Social Security Administration to GCS - download_and_process_source_zip_file = bash_operator.BashOperator( + download_and_process_source_zip_file = bash.BashOperator( task_id="download_and_process_source_zip_file", bash_command="mkdir -p $data_dir/{{ ds }}\ncurl -o $data_dir/{{ ds }}/namesbystate.zip -L $zip_source_url\nunzip $data_dir/{{ ds }}/namesbystate.zip -d $data_dir/{{ ds }}\ncat $data_dir/{{ ds }}/*.TXT \u003e\u003e $data_dir/{{ ds }}/data.csv\n", env={ @@ -44,7 +44,7 @@ ) # Task to load the data from Airflow data folder to BigQuery - load_csv_file_to_bq_table = gcs_to_bq.GoogleCloudStorageToBigQueryOperator( + load_csv_file_to_bq_table = gcs_to_bigquery.GCSToBigQueryOperator( task_id="load_csv_file_to_bq_table", bucket="{{ var.json.shared.composer_bucket }}", source_objects=["data/usa_names/usa_1910_current/{{ ds }}/data.csv"], diff --git a/requirements-dev.txt b/requirements-dev.txt index 522a83448..00d8cd15d 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -6,156 +6,192 @@ # -i https://pypi.org/simple -alembic==1.6.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' -apache-airflow[google]==1.10.14 -apispec[yaml]==1.3.3 +alembic==1.6.5; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' +anyio==3.3.0; python_full_version >= '3.6.2' +apache-airflow-providers-cncf-kubernetes==2.0.1 +apache-airflow-providers-ftp==2.0.0; python_version ~= '3.6' +apache-airflow-providers-google==5.0.0 +apache-airflow-providers-imap==2.0.0; python_version ~= '3.6' +apache-airflow-providers-sqlite==2.0.0; python_version ~= '3.6' +apache-airflow==2.1.1 +apispec[yaml]==3.3.2; python_full_version >= '3.5.0' appdirs==1.4.4 argcomplete==1.12.3 attrs==20.3.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' babel==2.9.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +backports.entry-points-selectable==1.1.0; python_version >= '2.7' black==20.8b1 -cached-property==1.5.2 +blinker==1.4 cachetools==4.2.2; python_version ~= '3.5' -cattrs==1.6.0; python_version >= '3.7' -certifi==2020.12.5 -cffi==1.14.5 -chardet==3.0.4; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +cattrs==1.5.0; python_version > '3.6' +certifi==2021.5.30 +cffi==1.14.6 +charset-normalizer==2.0.4; python_version >= '3' click==7.1.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +clickclick==20.10.2 colorama==0.4.4; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -colorlog==4.0.2 -configparser==3.5.3; python_version >= '2.6' -croniter==0.3.37; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' -cryptography==3.4.7; python_version >= '3.0' +colorlog==4.8.0 +commonmark==0.9.1 +croniter==1.0.15; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' +cryptography==3.4.7; python_version >= '3.6' defusedxml==0.7.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -dill==0.3.3; python_version >= '2.6' and python_version != '3.0' +dill==0.3.4; python_version >= '2.7' and python_version != '3.0' +distlib==0.3.2 dnspython==2.1.0; python_version >= '3.6' -docutils==0.17.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -email-validator==1.1.2 -flake8==3.8.4 -flask-admin==1.5.4 -flask-appbuilder==2.3.4; python_version >= '3.6' +docutils==0.16; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +email-validator==1.1.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +filelock==3.0.12 +flake8==3.9.2 +flask-appbuilder==3.3.2; python_version ~= '3.6' flask-babel==1.0.0 -flask-caching==1.3.3 -flask-jwt-extended==3.25.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' +flask-caching==1.10.1; python_full_version >= '3.5.0' +flask-jwt-extended==3.25.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4.0' flask-login==0.4.1 flask-openid==1.2.5 flask-sqlalchemy==2.5.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -flask-swagger==0.2.14 flask-wtf==0.14.3 flask==1.1.4; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -funcsigs==1.0.2 -future==0.18.2; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' -google-api-core[grpc,grpcgcp]==1.26.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' -google-api-python-client==1.12.8 +google-ads==13.0.0; python_version >= '3.7' +google-api-core[grpc,grpcgcp]==1.31.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' +google-api-python-client==1.12.8; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' google-auth-httplib2==0.1.0 -google-auth-oauthlib==0.4.4; python_version >= '3.6' -google-auth==1.30.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' -google-cloud-bigquery-storage==2.4.0 -google-cloud-bigquery[bqstorage,pandas]==2.16.1; python_version < '3.10' and python_version >= '3.6' -google-cloud-bigtable==1.7.0 -google-cloud-container==1.0.1 -google-cloud-core==1.6.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' -google-cloud-dlp==1.0.0 -google-cloud-language==1.3.0 -google-cloud-secret-manager==1.0.0 -google-cloud-spanner==1.19.1 -google-cloud-speech==1.3.2 -google-cloud-storage==1.38.0 -google-cloud-texttospeech==1.0.1 -google-cloud-translate==1.7.0 -google-cloud-videointelligence==1.16.1 -google-cloud-vision==1.0.0 +google-auth-oauthlib==0.4.5; python_version >= '3.6' +google-auth==1.34.0; python_version >= '3.6' +google-cloud-appengine-logging==0.1.4; python_version >= '3.6' +google-cloud-audit-log==0.1.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +google-cloud-automl==2.4.2; python_version >= '3.6' +google-cloud-bigquery-datatransfer==3.3.1; python_version >= '3.6' +google-cloud-bigquery-storage==2.6.2 +google-cloud-bigquery[bqstorage,pandas]==2.23.2; python_version < '3.10' and python_version >= '3.6' +google-cloud-bigtable==1.7.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +google-cloud-container==1.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +google-cloud-core==1.7.2; python_version >= '3.6' +google-cloud-datacatalog==3.4.0 +google-cloud-dataproc==2.5.0; python_version >= '3.6' +google-cloud-dlp==1.0.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +google-cloud-kms==2.4.3; python_version >= '3.6' +google-cloud-language==1.3.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +google-cloud-logging==2.6.0; python_version >= '3.6' +google-cloud-memcache==1.0.0; python_version >= '3.6' +google-cloud-monitoring==2.4.2; python_version >= '3.6' +google-cloud-os-login==2.3.1; python_version >= '3.6' +google-cloud-pubsub==2.7.0; python_version >= '3.6' +google-cloud-redis==2.2.2; python_version >= '3.6' +google-cloud-secret-manager==1.0.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +google-cloud-spanner==1.19.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +google-cloud-speech==1.3.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +google-cloud-storage==1.41.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' +google-cloud-tasks==2.5.1; python_version >= '3.6' +google-cloud-texttospeech==1.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +google-cloud-translate==1.7.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +google-cloud-videointelligence==1.16.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +google-cloud-vision==1.0.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +google-cloud-workflows==1.2.1; python_version >= '3.6' google-crc32c==1.1.2; python_version >= '3.5' -google-resumable-media==1.2.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' +google-resumable-media==1.3.3; python_version >= '3.6' googleapis-common-protos[grpc]==1.53.0; python_version >= '3.6' -graphviz==0.16; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' +graphviz==0.17; python_version >= '3.6' grpc-google-iam-v1==0.12.3 grpcio-gcp==0.2.2 -grpcio==1.37.1 -gunicorn==20.1.0; python_version >= '3.5' +grpcio==1.39.0 +gunicorn==20.1.0; python_full_version >= '3.5.0' +h11==0.12.0; python_version >= '3.6' +httpcore==0.13.6; python_version >= '3.6' httplib2==0.19.1 -idna==2.10; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +httpx==0.18.2; python_version >= '3.6' +idna==3.2 +importlib-metadata==1.7.0; python_version < '3.9' importlib-resources==1.5.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +inflection==0.5.1; python_full_version >= '3.5.0' iniconfig==1.1.1 -iso8601==0.1.14 -isort==5.8.0 +iso8601==0.1.16 +isodate==0.6.0 +isort==5.9.3 itsdangerous==1.1.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' jinja2==2.11.3 json-merge-patch==0.2 jsonschema==3.2.0 -kubernetes==17.17.0 -lazy-object-proxy==1.4.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +kubernetes==11.0.0 +lazy-object-proxy==1.6.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' libcst==0.3.19; python_version >= '3.6' lockfile==0.12.2 mako==1.1.4; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -markdown==2.6.11 -markupsafe==2.0.0; python_version >= '3.6' +markdown==3.3.4; python_version >= '3.6' +markupsafe==1.1.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' marshmallow-enum==1.5.1 +marshmallow-oneofschema==3.0.1; python_version >= '3.6' marshmallow-sqlalchemy==0.23.1; python_version >= '3.6' -marshmallow==2.21.0 +marshmallow==3.13.0; python_full_version >= '3.5.0' mccabe==0.6.1 mypy-extensions==0.4.3 -natsort==7.1.1; python_version >= '3.4' -numpy==1.20.3; python_version >= '3.7' -oauthlib==3.1.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -packaging==20.9; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +nox==2020.12.31; python_version >= '3.6' +numpy==1.21.1; python_version >= '3.7' +oauthlib==3.1.1; python_version >= '3.6' +openapi-schema-validator==0.1.5; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +openapi-spec-validator==0.3.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +packaging==21.0; python_version >= '3.6' pandas-gbq==0.14.1 -pandas==1.2.4 -pathspec==0.8.1 -pendulum==1.4.4; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +pandas==1.3.1 +pathspec==0.9.0 +pendulum==2.1.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +platformdirs==2.2.0; python_version >= '3.6' pluggy==0.13.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' prison==0.1.3 -proto-plus==1.18.1; python_version >= '3.6' -protobuf==3.17.0 +proto-plus==1.19.0; python_version >= '3.6' +protobuf==3.17.3 psutil==5.8.0; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' py==1.10.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -pyarrow==4.0.0 +pyarrow==5.0.0 pyasn1-modules==0.2.8 pyasn1==0.4.8 -pycodestyle==2.6.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +pycodestyle==2.7.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' pycparser==2.20; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' pydata-google-auth==1.2.0 -pyflakes==2.2.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -pygments==2.9.0; python_version >= '3.5' +pyflakes==2.3.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +pygments==2.9.0; python_full_version >= '3.5.0' pyjwt==1.7.1 -pyopenssl==20.0.1 -pyparsing==2.4.7; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' -pyrsistent==0.17.3; python_version >= '3.5' +pyopenssl==20.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +pyparsing==2.4.7; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2' +pyrsistent==0.18.0; python_version >= '3.6' pytest-mock==3.6.1 pytest==6.2.4 python-daemon==2.3.0 -python-dateutil==2.8.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +python-dateutil==2.8.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2' python-editor==1.0.4 python-nvd3==0.15.0 python-slugify==4.0.1 python3-openid==3.2.0 pytz==2021.1 pytzdata==2020.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -pyyaml==5.4.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' -regex==2021.4.4 +pyyaml==5.4.1 +regex==2021.8.3 requests-oauthlib==1.3.0 -requests==2.23.0; python_version >= '3.0' +requests==2.26.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' +rfc3986[idna2008]==1.5.0 +rich==10.7.0; python_version >= '3.6' and python_version < '4.0' rsa==4.7.2; python_version >= '3.6' -ruamel.yaml.clib==0.2.2; python_version < '3.9' and platform_python_implementation == 'CPython' -ruamel.yaml==0.16.12 +ruamel.yaml.clib==0.2.6; platform_python_implementation == 'CPython' and python_version < '3.10' +ruamel.yaml==0.17.10 setproctitle==1.2.2; python_version >= '3.6' -six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -sqlalchemy-jsonfield==0.9.0; python_version >= '3.5' -sqlalchemy-utils==0.37.3; python_version ~= '3.4' -sqlalchemy==1.3.15 +six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2' +sniffio==1.2.0; python_full_version >= '3.5.0' +sqlalchemy-jsonfield==1.0.0; python_full_version >= '3.5.0' +sqlalchemy-utils==0.37.8; python_version ~= '3.4' +sqlalchemy==1.3.18 +swagger-ui-bundle==0.0.8 tabulate==0.8.9 -tenacity==4.12.0 +tenacity==6.2.0 +termcolor==1.1.0 text-unidecode==1.3 -thrift==0.13.0 -toml==0.10.2; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' +toml==0.10.2; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2' typed-ast==1.4.3 typing-extensions==3.10.0.0 -typing-inspect==0.6.0 -tzlocal==1.5.1 +typing-inspect==0.7.1 unicodecsv==0.14.1 uritemplate==3.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -urllib3==1.25.11; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' -websocket-client==0.59.0; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' -werkzeug==0.16.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +urllib3==1.26.6; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4.0' +virtualenv==20.7.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' +websocket-client==1.1.1; python_version >= '3.6' +werkzeug==1.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' wtforms==2.3.3 -zope.deprecation==4.4.0 +zipp==3.5.0; python_version >= '3.6' diff --git a/scripts/deploy_dag.py b/scripts/deploy_dag.py index cf1e6bdf4..01528fb0b 100644 --- a/scripts/deploy_dag.py +++ b/scripts/deploy_dag.py @@ -58,13 +58,15 @@ def main( else: pipelines = list_subdirs(env_path / "datasets" / dataset_id) - # if local: - # runtime_airflow_version = local_airflow_version() - # else: - # runtime_airflow_version = composer_airflow_version(composer_env, composer_region) + if local: + runtime_airflow_version = local_airflow_version() + else: + runtime_airflow_version = composer_airflow_version( + composer_env, composer_region + ) for pipeline_path in pipelines: - # check_airflow_version_compatibility(pipeline_path, runtime_airflow_version) + check_airflow_version_compatibility(pipeline_path, runtime_airflow_version) copy_custom_callables_to_airflow_dags_folder( local, diff --git a/scripts/generate_dag.py b/scripts/generate_dag.py index 596900aea..50a8f404a 100644 --- a/scripts/generate_dag.py +++ b/scripts/generate_dag.py @@ -143,9 +143,11 @@ def generate_task_contents(task: dict, airflow_version: str) -> str: def generate_shared_variables_file(env: str) -> None: - pathlib.Path( + shared_variables_file = pathlib.Path( PROJECT_ROOT / f".{env}" / "datasets" / "shared_variables.json" - ).touch() + ) + shared_variables_file.touch() + shared_variables_file.write_text("{}", encoding="utf-8") def dag_init(config: dict) -> dict: From 11bbb620dd5b4ab261a45d532707cefee9f7d146 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Mon, 9 Aug 2021 17:26:57 -0400 Subject: [PATCH 08/17] default to Airflow 2 --- datasets/bls/cpsaat18/pipeline.yaml | 1 + .../city_level_cases_and_deaths/pipeline.yaml | 1 + .../covid_racial_data_tracker/pipeline.yaml | 1 + .../pipeline.yaml | 1 + .../pipeline.yaml | 1 + .../pipeline.yaml | 1 + .../pipeline.yaml | 1 + .../pipeline.yaml | 1 + .../state_screenshots/pipeline.yaml | 1 + .../state_testing_and_outcomes/pipeline.yaml | 1 + .../vaccination_access_to_bq/pipeline.yaml | 1 + .../pipeline.yaml | 1 + .../diversity_annual_report/pipeline.yaml | 1 + .../google_trends/top_terms/pipeline.yaml | 1 + .../2020_sales_train/pipeline.yaml | 1 + .../2021_sales_predict/pipeline.yaml | 1 + datasets/ml_datasets/penguins/pipeline.yaml | 1 + .../mouse_brain_map/pipeline.yaml | 1 + samples/pipeline.yaml | 2 +- scripts/generate_dag.py | 2 +- tests/scripts/test_generate_dag.py | 58 +++++++++++++++++++ 21 files changed, 78 insertions(+), 2 deletions(-) diff --git a/datasets/bls/cpsaat18/pipeline.yaml b/datasets/bls/cpsaat18/pipeline.yaml index 918756048..69645d018 100644 --- a/datasets/bls/cpsaat18/pipeline.yaml +++ b/datasets/bls/cpsaat18/pipeline.yaml @@ -19,6 +19,7 @@ resources: description: "Current population survey 18: Employed persons by detailed industry, sex, race, and Hispanic or Latino ethnicity" dag: + airflow_version: 1 initialize: dag_id: cpsaat18 default_args: diff --git a/datasets/covid19_tracking/city_level_cases_and_deaths/pipeline.yaml b/datasets/covid19_tracking/city_level_cases_and_deaths/pipeline.yaml index 026719175..f0572bd94 100644 --- a/datasets/covid19_tracking/city_level_cases_and_deaths/pipeline.yaml +++ b/datasets/covid19_tracking/city_level_cases_and_deaths/pipeline.yaml @@ -18,6 +18,7 @@ resources: table_id: city_level_cases_and_deaths dag: + airflow_version: 1 initialize: dag_id: "city_level_cases_and_deaths" default_args: diff --git a/datasets/covid19_tracking/covid_racial_data_tracker/pipeline.yaml b/datasets/covid19_tracking/covid_racial_data_tracker/pipeline.yaml index 199159662..4b1a06ce6 100644 --- a/datasets/covid19_tracking/covid_racial_data_tracker/pipeline.yaml +++ b/datasets/covid19_tracking/covid_racial_data_tracker/pipeline.yaml @@ -19,6 +19,7 @@ resources: dag: initialize: + airflow_version: 1 dag_id: "covid_racial_data_tracker" default_args: owner: "Google" diff --git a/datasets/covid19_tracking/national_testing_and_outcomes/pipeline.yaml b/datasets/covid19_tracking/national_testing_and_outcomes/pipeline.yaml index e0db961d3..b76787fc8 100644 --- a/datasets/covid19_tracking/national_testing_and_outcomes/pipeline.yaml +++ b/datasets/covid19_tracking/national_testing_and_outcomes/pipeline.yaml @@ -18,6 +18,7 @@ resources: table_id: national_testing_and_outcomes dag: + airflow_version: 1 initialize: dag_id: "national_testing_and_outcomes" default_args: diff --git a/datasets/covid19_tracking/state_facility_level_long_term_care/pipeline.yaml b/datasets/covid19_tracking/state_facility_level_long_term_care/pipeline.yaml index 753591fc4..9753a329a 100644 --- a/datasets/covid19_tracking/state_facility_level_long_term_care/pipeline.yaml +++ b/datasets/covid19_tracking/state_facility_level_long_term_care/pipeline.yaml @@ -18,6 +18,7 @@ resources: table_id: state_facility_level_long_term_care dag: + airflow_version: 1 initialize: dag_id: "state_facility_level_long_term_care" default_args: diff --git a/datasets/covid19_tracking/state_level_aggregate_long_term_care/pipeline.yaml b/datasets/covid19_tracking/state_level_aggregate_long_term_care/pipeline.yaml index faabda735..4c2661800 100644 --- a/datasets/covid19_tracking/state_level_aggregate_long_term_care/pipeline.yaml +++ b/datasets/covid19_tracking/state_level_aggregate_long_term_care/pipeline.yaml @@ -18,6 +18,7 @@ resources: table_id: state_level_aggregate_long_term_care dag: + airflow_version: 1 initialize: dag_id: "state_level_aggregate_long_term_care" default_args: diff --git a/datasets/covid19_tracking/state_level_cumulative_long_term_care/pipeline.yaml b/datasets/covid19_tracking/state_level_cumulative_long_term_care/pipeline.yaml index fbc08c498..ef896b7b4 100644 --- a/datasets/covid19_tracking/state_level_cumulative_long_term_care/pipeline.yaml +++ b/datasets/covid19_tracking/state_level_cumulative_long_term_care/pipeline.yaml @@ -18,6 +18,7 @@ resources: table_id: state_level_cumulative_long_term_care dag: + airflow_version: 1 initialize: dag_id: "state_level_cumulative_long_term_care" default_args: diff --git a/datasets/covid19_tracking/state_level_current_outbreak_long_term_care/pipeline.yaml b/datasets/covid19_tracking/state_level_current_outbreak_long_term_care/pipeline.yaml index 4e8380d52..c0ef7294c 100644 --- a/datasets/covid19_tracking/state_level_current_outbreak_long_term_care/pipeline.yaml +++ b/datasets/covid19_tracking/state_level_current_outbreak_long_term_care/pipeline.yaml @@ -18,6 +18,7 @@ resources: table_id: state_level_current_outbreak_long_term_care dag: + airflow_version: 1 initialize: dag_id: "state_level_current_outbreak_long_term_care" default_args: diff --git a/datasets/covid19_tracking/state_screenshots/pipeline.yaml b/datasets/covid19_tracking/state_screenshots/pipeline.yaml index aa6bac472..038119e5c 100644 --- a/datasets/covid19_tracking/state_screenshots/pipeline.yaml +++ b/datasets/covid19_tracking/state_screenshots/pipeline.yaml @@ -18,6 +18,7 @@ resources: table_id: state_screenshots dag: + airflow_version: 1 initialize: dag_id: "state_screenshots" default_args: diff --git a/datasets/covid19_tracking/state_testing_and_outcomes/pipeline.yaml b/datasets/covid19_tracking/state_testing_and_outcomes/pipeline.yaml index 2a69397dc..b925ba3f4 100644 --- a/datasets/covid19_tracking/state_testing_and_outcomes/pipeline.yaml +++ b/datasets/covid19_tracking/state_testing_and_outcomes/pipeline.yaml @@ -18,6 +18,7 @@ resources: table_id: state_testing_and_outcomes dag: + airflow_version: 1 initialize: dag_id: "state_testing_and_outcomes" default_args: diff --git a/datasets/covid19_vaccination_access/vaccination_access_to_bq/pipeline.yaml b/datasets/covid19_vaccination_access/vaccination_access_to_bq/pipeline.yaml index da61830a2..1ed5de751 100644 --- a/datasets/covid19_vaccination_access/vaccination_access_to_bq/pipeline.yaml +++ b/datasets/covid19_vaccination_access/vaccination_access_to_bq/pipeline.yaml @@ -28,6 +28,7 @@ resources: description: "This table represents the boundaries of areas surrounding vaccination facilities from which people can reach the facility by walking within predetermined time periods." dag: + airflow_version: 1 initialize: dag_id: vaccination_access_to_bq default_args: diff --git a/datasets/covid19_vaccination_search_insights/covid19_vaccination_search_insights/pipeline.yaml b/datasets/covid19_vaccination_search_insights/covid19_vaccination_search_insights/pipeline.yaml index 98e1feb57..d2e8b4fcf 100644 --- a/datasets/covid19_vaccination_search_insights/covid19_vaccination_search_insights/pipeline.yaml +++ b/datasets/covid19_vaccination_search_insights/covid19_vaccination_search_insights/pipeline.yaml @@ -122,6 +122,7 @@ resources: ] dag: + airflow_version: 1 initialize: dag_id: covid19_vaccination_search_insights default_args: diff --git a/datasets/google_dei/diversity_annual_report/pipeline.yaml b/datasets/google_dei/diversity_annual_report/pipeline.yaml index f6a8eeda8..9b4f87c3b 100644 --- a/datasets/google_dei/diversity_annual_report/pipeline.yaml +++ b/datasets/google_dei/diversity_annual_report/pipeline.yaml @@ -65,6 +65,7 @@ resources: deletion_protection: False dag: + airflow_version: 1 initialize: dag_id: diversity_annual_report default_args: diff --git a/datasets/google_trends/top_terms/pipeline.yaml b/datasets/google_trends/top_terms/pipeline.yaml index 7ad017f18..980cf9784 100644 --- a/datasets/google_trends/top_terms/pipeline.yaml +++ b/datasets/google_trends/top_terms/pipeline.yaml @@ -93,6 +93,7 @@ resources: ] dag: + airflow_version: 1 initialize: dag_id: top_terms default_args: diff --git a/datasets/iowa_liquor_sales_forecasting/2020_sales_train/pipeline.yaml b/datasets/iowa_liquor_sales_forecasting/2020_sales_train/pipeline.yaml index 5beca9843..f656a675c 100644 --- a/datasets/iowa_liquor_sales_forecasting/2020_sales_train/pipeline.yaml +++ b/datasets/iowa_liquor_sales_forecasting/2020_sales_train/pipeline.yaml @@ -36,6 +36,7 @@ dag: # The DAG acronym stands for directed acyclic graph. This block represents # your data pipeline along with every property and configuration it needs to # onboard your data. + airflow_version: 1 initialize: dag_id: 2020_sales_train default_args: diff --git a/datasets/iowa_liquor_sales_forecasting/2021_sales_predict/pipeline.yaml b/datasets/iowa_liquor_sales_forecasting/2021_sales_predict/pipeline.yaml index 7460b3771..5a87adf3b 100644 --- a/datasets/iowa_liquor_sales_forecasting/2021_sales_predict/pipeline.yaml +++ b/datasets/iowa_liquor_sales_forecasting/2021_sales_predict/pipeline.yaml @@ -36,6 +36,7 @@ dag: # The DAG acronym stands for directed acyclic graph. This block represents # your data pipeline along with every property and configuration it needs to # onboard your data. + airflow_version: 1 initialize: dag_id: 2021_sales_predict default_args: diff --git a/datasets/ml_datasets/penguins/pipeline.yaml b/datasets/ml_datasets/penguins/pipeline.yaml index 9bb8afe82..9bac05a60 100644 --- a/datasets/ml_datasets/penguins/pipeline.yaml +++ b/datasets/ml_datasets/penguins/pipeline.yaml @@ -36,6 +36,7 @@ dag: # The DAG acronym stands for directed acyclic graph. This block represents # your data pipeline along with every property and configuration it needs to # onboard your data. + airflow_version: 1 initialize: dag_id: penguins default_args: diff --git a/datasets/vizgen_merfish/mouse_brain_map/pipeline.yaml b/datasets/vizgen_merfish/mouse_brain_map/pipeline.yaml index f5d0c1143..80999eefc 100644 --- a/datasets/vizgen_merfish/mouse_brain_map/pipeline.yaml +++ b/datasets/vizgen_merfish/mouse_brain_map/pipeline.yaml @@ -19,6 +19,7 @@ dag: # The DAG acronym stands for directed acyclic graph. This block represents # your data pipeline along with every property and configuration it needs to # onboard your data. + airflow_version: 1 initialize: dag_id: mouse_brain_map default_args: diff --git a/samples/pipeline.yaml b/samples/pipeline.yaml index a63b98d84..37b943d9a 100644 --- a/samples/pipeline.yaml +++ b/samples/pipeline.yaml @@ -67,7 +67,7 @@ resources: deletion_protection: true dag: - # Specify the Airflow version of the operators used by the DAG. Defaults to Airflow 1 when unspecified. + # Specify the Airflow version of the operators used by the DAG. Defaults to Airflow 2 when unspecified. airflow_version: 1 # The DAG acronym stands for directed acyclic graph. This block represents diff --git a/scripts/generate_dag.py b/scripts/generate_dag.py index 50a8f404a..93a61e437 100644 --- a/scripts/generate_dag.py +++ b/scripts/generate_dag.py @@ -50,7 +50,7 @@ "default_args": AIRFLOW_TEMPLATES_PATH / "default_args.py.jinja2", } -DEFAULT_AIRFLOW_VERSION = 1 +DEFAULT_AIRFLOW_VERSION = 2 AIRFLOW_IMPORTS = json.load(open(CURRENT_PATH / "dag_imports.json")) diff --git a/tests/scripts/test_generate_dag.py b/tests/scripts/test_generate_dag.py index 5d94e6d32..842aa69d5 100644 --- a/tests/scripts/test_generate_dag.py +++ b/tests/scripts/test_generate_dag.py @@ -154,6 +154,64 @@ def test_main_creates_shared_variables_file( assert not (ENV_DATASETS_PATH / "shared_variables.json").is_dir() +def test_main_uses_airflow1_operators_when_airflow_version_is_set_to_1( + dataset_path: pathlib.Path, pipeline_path: pathlib.Path, env: str +): + copy_config_files_and_set_tmp_folder_names_as_ids(dataset_path, pipeline_path) + + # Verify that the template uses Airflow 1 + config = yaml.load(open(pipeline_path / "pipeline.yaml")) + assert config["dag"]["airflow_version"] == 1 + + generate_dag.main(dataset_path.name, pipeline_path.name, env) + + for path_prefix in ( + pipeline_path, + ENV_DATASETS_PATH / dataset_path.name / pipeline_path.name, + ): + assert (path_prefix / f"{pipeline_path.name}_dag.py").exists() + assert ( + "airflow.contrib.operators" + in (path_prefix / f"{pipeline_path.name}_dag.py").read_text() + ) + assert ( + "airflow.providers.google" + not in (path_prefix / f"{pipeline_path.name}_dag.py").read_text() + ) + + +# Requires a pipeline.yaml config that uses Airflow2 operators. Soon to follow. +# See https://github.com/GoogleCloudPlatform/public-datasets-pipelines/issues/137 +@pytest.mark.skip() +def test_main_defaults_to_using_airflow2_when_airflow_version_is_unspecified( + dataset_path: pathlib.Path, pipeline_path: pathlib.Path, env: str +): + copy_config_files_and_set_tmp_folder_names_as_ids(dataset_path, pipeline_path) + + config = yaml.load(open(pipeline_path / "pipeline.yaml")) + + # Delete the `airflow_version` field in the pipeline YAML config + del config["dag"]["airflow_version"] + with open(pipeline_path / "pipeline.yaml", "w") as file: + yaml.dump(config, file) + + generate_dag.main(dataset_path.name, pipeline_path.name, env) + + for path_prefix in ( + pipeline_path, + ENV_DATASETS_PATH / dataset_path.name / pipeline_path.name, + ): + assert (path_prefix / f"{pipeline_path.name}_dag.py").exists() + assert ( + "providers.google" + in (path_prefix / f"{pipeline_path.name}_dag.py").read_text() + ) + assert ( + "airflow.contrib.operators" + not in (path_prefix / f"{pipeline_path.name}_dag.py").read_text() + ) + + def test_main_only_depends_on_pipeline_yaml( dataset_path: pathlib.Path, pipeline_path: pathlib.Path, env: str ): From 3621dd1da777ed425a74e528f92a1680421f3f91 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Tue, 10 Aug 2021 15:47:18 -0400 Subject: [PATCH 09/17] README revisions for old and new YAML references --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 32862b2b6..9c4b27087 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,9 @@ Use only underscores and alpha-numeric characters for the names. If you created a new dataset directory above, you need to create a `datasets/DATASET/dataset.yaml` config file. See this [section](https://github.com/GoogleCloudPlatform/public-datasets-pipelines/blob/main/README.md#yaml-config-reference) for the `dataset.yaml` reference. -Create a `datasets/DATASET/PIPELINE/pipeline.yaml` config file for your pipeline. See [here](https://github.com/GoogleCloudPlatform/public-datasets-pipelines/blob/main/samples/pipeline.yaml) for the `pipeline.yaml` reference. +Create a `datasets/DATASET/PIPELINE/pipeline.yaml` config file for your pipeline. See [here](https://github.com/GoogleCloudPlatform/public-datasets-pipelines/blob/main/samples/) for the `pipeline.yaml` references. + +For a YAML config template using Airflow 1.10 operators, see [`samples/pipeline.airflow1.yaml`](https://github.com/GoogleCloudPlatform/public-datasets-pipelines/blob/main/samples/pipeline.airflow1.yaml). If you'd like to get started faster, you can inspect config files that already exist in the repository and infer the patterns from there: @@ -219,10 +221,14 @@ $ pipenv run python -m pytest -v # YAML Config Reference -Every dataset and pipeline folder must contain a `dataset.yaml` and a `pipeline.yaml` configuration file, respectively: +Every dataset and pipeline folder must contain a `dataset.yaml` and a `pipeline.yaml` configuration file, respectively. + +The `samples` folder contains references for the YAML config files, complete with descriptions for config blocks and Airflow operators and parameters. When creating a new dataset or pipeline, you can copy them to your specific dataset/pipeline paths to be used as templates. -- For dataset configuration syntax, see [`samples/dataset.yaml`](https://github.com/GoogleCloudPlatform/public-datasets-pipelines/blob/main/samples/dataset.yaml) as a reference. -- For pipeline configuration syntax, see [`samples/pipeline.yaml`](https://github.com/GoogleCloudPlatform/public-datasets-pipelines/blob/main/samples/pipeline.yaml) as a reference. +- For dataset configuration syntax, see the [`samples/dataset.yaml`](https://github.com/GoogleCloudPlatform/public-datasets-pipelines/blob/main/samples/dataset.yaml) reference. +- For pipeline configuration syntax: + - For the default Airflow 2 operators, see the [`samples/pipeline.yaml`](https://github.com/GoogleCloudPlatform/public-datasets-pipelines/blob/main/samples/pipeline.yaml) reference. + - If you'd like to use Airflow 1.10 operators, see the [`samples/pipeline.airflow1.yaml`](https://github.com/GoogleCloudPlatform/public-datasets-pipelines/blob/main/samples/pipeline.yaml) as a reference. # Best Practices From 6f68a2ab8a390714cdca55c720d845b7c2863136 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Tue, 10 Aug 2021 16:40:34 -0400 Subject: [PATCH 10/17] sample pipeline YAML template for Airflow 2 operators --- samples/pipeline.airflow1.yaml | 337 +++++++++++++++++++++++++++++++++ samples/pipeline.yaml | 166 +++++++++++----- scripts/dag_imports.json | 18 +- 3 files changed, 477 insertions(+), 44 deletions(-) create mode 100644 samples/pipeline.airflow1.yaml diff --git a/samples/pipeline.airflow1.yaml b/samples/pipeline.airflow1.yaml new file mode 100644 index 000000000..37b943d9a --- /dev/null +++ b/samples/pipeline.airflow1.yaml @@ -0,0 +1,337 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# ===== NOTE ===== +# This YAML config template is used to write DAGs that use Airflow 1.10 operators. +# You can keep using this template when deploying to an environment that uses Airflow 2, +# they will keep working due to backport compatibility. +# +# For tracking progress on the YAML config templates that use Airflow 2 operators, see +# https://github.com/GoogleCloudPlatform/public-datasets-pipelines/issues/137. + +--- +resources: + # A list of GCP resources that are unique and specific to your pipeline. + # + # The currently supported resources are shown below. Use only the resources + # needed by your pipeline, and delete the rest of the examples. + # + # We will keep adding to the list below to support more Google Cloud resources + # over time. If a resource you need isn't supported, please file an issue on + # the repository. + + - type: bigquery_table + # A Google BigQuery table to store your data. Requires a `bigquery_dataset` + # to be specified in the config (i.e. `dataset.yaml) for the dataset that + # this pipeline belongs in. + # + # Required Properties: + # table_id + table_id: PIPELINE_FOLDER_NAME + + # Optional Properties: + # Description of the table + description: "This is a table description." + + # Time-based partitioning configuration. There is no need for this property + # if you have a relatively small dataset to host on a BigQuery table. + time_partitioning: + + # The supported types are DAY, HOUR, MONTH, and YEAR, which will generate one partition per day, hour, month, and year, respectively. + type: "DAY" + + # If set to true, queries over this table require a partition filter that can be used for partition elimination to be specified. + require_partition_filter: false + + # Specifies column names to use for data clustering. Up to four top-level columns are allowed, and should be specified in descending priority order. + clustering: + - "column_1" + - "column_2" + - "column_3" + + # The table cannot be deleted without first disabling this property. + # Unless this field is set to false in Terraform state, a `terraform destroy` + # or `terraform apply` that would delete the table will fail. + deletion_protection: true + +dag: + # Specify the Airflow version of the operators used by the DAG. Defaults to Airflow 2 when unspecified. + airflow_version: 1 + + # The DAG acronym stands for directed acyclic graph. This block represents + # your data pipeline along with every property and configuration it needs to + # onboard your data. + initialize: + dag_id: PIPELINE_FOLDER_NAME + default_args: + owner: "Google" + + # When set to True, keeps a task from getting triggered if the previous schedule for the task hasn’t succeeded + depends_on_past: False + start_date: '2021-03-01' + max_active_runs: 1 + schedule_interval: "@once" # run once a week at Sunday 12am + catchup: False + default_view: graph + + tasks: + # This is where you specify the tasks (a.k.a. processes) that your data + # pipeline will run to onboard the data. + # + # As the examples below will show, every task must be represented by an + # Airflow operator. The list of suported operators are listed in + # + # scripts/dag_imports.json + # + # If an operator you need isn't supported, please file an issue on the + # repository. + # + # Use the YAML list syntax in this block to specify every task for your + # pipeline. + + - operator: "BashOperator" + # Initializes an Airflow BashOperator for the DAG. This operator can be + # used to + # - Download from HTTP sources + # - Run custom Python scripts + # - Run processes using specific packages that support CLI commands + + # Task description + description: "Run a custom Python script" + + args: + # Arguments supported by this operator: + # https://airflow.apache.org/docs/apache-airflow/1.10.15/howto/operator/bash.html + + task_id: "sample_bash_task" + bash_command: | + mkdir -p $airflow_home/data/$dataset/$pipeline/run_date={{ ds }} + CUSTOM_ENV_VAR=$custom_env_var python $airflow_home/dags/$dataset/$pipeline/custom/some_script.py + env: + airflow_home: "{{ var.json.shared.airflow_home }}" + dataset: DATASET_FOLDER_NAME + pipeline: PIPELINE_FOLDER_NAME + custom_env_var: "some value that your custom script needs" + + - operator: "GoogleCloudStorageToBigQueryOperator" + # Initializes GCS to BQ task for the DAG. This operator is used to load a + # CSV file from GCS into a BigQuery table. + + # Task description + description: "Task to load CSV data to a BigQuery table" + + args: + # Arguments supported by this operator: + # http://airflow.apache.org/docs/apache-airflow/1.10.15/howto/operator/gcp/gcs.html#googlecloudstoragetobigqueryoperator + + task_id: "sample_gcs_to_bq_task" + + # The GCS bucket where the CSV file is located in. + bucket: "{{ var.json.shared.composer_bucket }}" + + # The GCS object path for the CSV file + source_objects: ["data/DATASET_FOLDER_NAME/PIPELINE_FOLDER_NAME/run_date={{ ds }}/data.csv"] + source_format: "CSV" + destination_project_dataset_table: "DATASET_FOLDER_NAME.PIPELINE_FOLDER_NAME" + + # Use this if your CSV file contains a header row + skip_leading_rows: 1 + + # How to write data to the table: overwrite, append, or write if empty + # See https://cloud.google.com/bigquery/docs/reference/auditlogs/rest/Shared.Types/WriteDisposition + write_disposition: "WRITE_TRUNCATE" + + # The BigQuery table schema based on the CSV file. For more info, see + # https://cloud.google.com/bigquery/docs/schemas. + # Always use snake_case and lowercase for column names, and be explicit, + # i.e. specify modes for all columns. + schema_fields: + - name: "name" + type: "STRING" + mode: "REQUIRED" + - name: "string_col" + type: "STRING" + mode: "NULLABLE" + - name: "date" + type: "DATE" + mode: "REQUIRED" + - name: "num_col" + type: "INTEGER" + mode: "NULLABLE" + + - operator: "GoogleCloudStorageToGoogleCloudStorageOperator" + # Initializes a GCS-to-GCS task for the DAG. This operator is used to copy + # GCS objects from one location to another. + + # Task description + description: "Task to run a GoogleCloudStorageToGoogleCloudStorageOperator" + + args: + # Arguments supported by this operator: + # https://airflow.apache.org/docs/apache-airflow/1.10.15/_api/airflow/contrib/operators/gcs_to_gcs/index.html#airflow.contrib.operators.gcs_to_gcs.GoogleCloudStorageToGoogleCloudStorageOperator + + task_id: "sample_gcs_to_gcs_task" + + # The GCS bucket to copy the object/s from + source_bucket: "{{ var.json.shared.composer_bucket }}" + + # Use a trailing "/*" if you want to copy all objects under that path. + source_object: "data/DATASET_FOLDER_NAME/PIPELINE_FOLDER_NAME/run_date={{ ds }}/*" + + # The GCS bucket to copy the object/s to + destination_bucket: "{{ var.json.DATASET_FOLDER_NAME.destination_bucket }}" + + # The GCS prefix to copy the object/s to + destination_object: "datasets/DATASET_FOLDER_NAME/PIPELINE_FOLDER_NAME/run_date={{ ds }}/" + + # Use this argument if you don't want to keep the source object/s. + move_object: True + + - operator: "BigQueryOperator" + # Initializes a BigQuery operator that executes SQL queries in a specific + # BigQuery table. + + # Task description + description: "Task to run a BigQueryOperator" + + args: + # Arguments supported by this operator: + # https://airflow.apache.org/docs/apache-airflow/1.10.15/_api/airflow/contrib/operators/bigquery_operator/index.html#airflow.contrib.operators.bigquery_operator.BigQueryOperator + + task_id: "sample_bq_sql_task" + + # The SQL query to execute, along with query parameters. For more info, + # see https://cloud.google.com/bigquery/docs/parameterized-queries. + sql: "SELECT * FROM DATASET_FOLDER_NAME.PIPELINE_FOLDER_NAME LIMIT @max_rows" + query_params: + - name: "max_rows" + parameterType: + type: "INTEGER" + parameterValue: + value: 100 + + # The BigQuery destination table + destination_dataset_table: "destination_dataset.destination_table" + + # How to write to the destination: overwrite, append, or write if empty + # See https://cloud.google.com/bigquery/docs/reference/auditlogs/rest/Shared.Types/WriteDisposition + write_disposition: "WRITE_TRUNCATE" + + - operator: "GoogleCloudStorageDeleteOperator" + # Initializes a GCS operator that deletes all specified objects + + # Task description + description: "Task to run a GoogleCloudStorageDeleteOperator" + + args: + # Arguments supported by this operator: + # https://airflow.apache.org/docs/apache-airflow/1.10.15/_api/airflow/contrib/operators/gcs_delete_operator/index.html#airflow.contrib.operators.gcs_delete_operator.GoogleCloudStorageDeleteOperator + task_id: "sample_gcs_delete_task" + + # The GCS bucket where the objects to delete are located. + bucket_name: "sample_bucket" + + # List of objects to delete. These should be the names of objects in the bucket, not including gs://bucket/. + objects: ["path/to/some_object"] + + # Alternatively, you can specify a prefix of objects to delete. + # All objects matching this prefix in the bucket will be deleted. + prefix: "prefix/to/delete" + + - operator: "KubernetesPodOperator" + # Executes a task in a Kubernetes pod that uses the Cloud Composer environment's own CPU and memory resources. + # + # Note: Do NOT use this for very heavy workloads. This can potentially starve resources from Cloud Composer + # and affect data pipeline orchestration overall. Instead, use a different GKE cluster using Kubernetes + # Engine operators: https://github.com/apache/airflow/blob/master/airflow/providers/google/cloud/operators/kubernetes_engine.py + + # Task description + description: "Task to run a KubernetesPodOperator" + + args: + # Arguments supported by this operator: + # https://airflow.readthedocs.io/en/1.10.15/_api/airflow/contrib/operators/kubernetes_pod_operator/index.html#airflow.contrib.operators.kubernetes_pod_operator.KubernetesPodOperator + + task_id: "sample_kube_pod_operator" + + # The name of the pod in which the task will run. This will be used (plus a random suffix) to generate a pod id + name: "sample-kube-operator" + + # The namespace to run within Kubernetes. Always set its value to "default" because we follow the guideline that KubernetesPodOperator will only be used for very light workloads, i.e. use the Cloud Composer environment's resources without starving other pipelines. + namespace: "default" + + # The Google Container Registry image URL. To prepare a Docker image to be used by this operator: + # + # 1. Create an `_images` folder under your dataset folder if it doesn't exist. + # + # 2. Inside the `_images` folder, create another folder and name it after what the image is expected to do, e.g. process_shapefiles, get_cdf_metadata. + # + # 3. In that subfolder, create a Dockerfile (https://docs.docker.com/engine/reference/builder/) and any scripts you need to process the data. Use the `COPY` command (https://docs.docker.com/engine/reference/builder/#copy) in your `Dockerfile` to include your scripts in the image. + # + # The resulting file tree for a dataset that uses two container images may look like + # + # datasets + # └── DATASET + # ├── _images + # │ ├── container_a + # │ │ ├── Dockerfile + # │ │ ├── requirements.txt + # │ │ └── script.py + # │ └── container_b + # │ ├── Dockerfile + # │ ├── requirements.txt + # │ └── script.py + # ├── _terraform/ + # ├── PIPELINE_A + # ├── PIPELINE_B + # ├── ... + # └── dataset.yaml + # + # Docker images will be built and pushed to GCR by default whenever the `scripts/generate_dag.py` is run. To skip building and pushing images, use the optional `--skip-builds` flag. + image: "{{ var.json.DATASET_FOLDER_NAME.container_registry.IMAGE_REPOSITORY }}" + + # Always pull the latest image. We recommend to keep this as "Always". + image_pull_policy: "Always" + + # Set the environment variables you need initialized in the container. Use these as input variables for the script your container is expected to perform. + env_vars: + TEST_ENV_VAR: "test-value" + ANOTHER_ENV_VAR: 12345 + + # Set resource limits for the pod here. For resource units in Kubernetes, see https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-units-in-kubernetes + resources: + limit_memory: "250M" + limit_cpu: "1" + + - operator: "BigQueryToBigQueryOperator" + description: "Task to run a BQ to BQ operator" + + args: + task_id: "sample_bq_to_bq_task" + source_project_dataset_tables: ["{{ var.json.DATASET_FOLDER_NAME.PIPELINE_NAME.source_project_dataset_table }}"] + destination_project_dataset_table: "{{ var.json.DATASET_FOLDER_NAME.PIPELINE_NAME.destination_project_dataset_table }}" + impersonation_chain: "{{ var.json.DATASET_FOLDER_NAME.service_account }}" + write_disposition: "WRITE_TRUNCATE" + + graph_paths: + # This is where you specify the relationships (i.e. directed paths/edges) + # among the tasks specified above. Use the bitshift operator to define the + # relationships and the `task_id` value above to represent tasks. + # + # For more info, see + # https://airflow.apache.org/docs/apache-airflow/stable/tutorial.html#setting-up-dependencies + - "sample_bash_task >> [sample_gcs_to_bq_task, sample_gcs_to_gcs_task]" + - "sample_gcs_to_bq_task >> [sample_bq_sql_task, sample_bq_to_bq_task]" + - "sample_bq_sql_task >> sample_gcs_delete_task" diff --git a/samples/pipeline.yaml b/samples/pipeline.yaml index 37b943d9a..0ecc3c67d 100644 --- a/samples/pipeline.yaml +++ b/samples/pipeline.yaml @@ -13,14 +13,6 @@ # limitations under the License. -# ===== NOTE ===== -# This YAML config template is used to write DAGs that use Airflow 1.10 operators. -# You can keep using this template when deploying to an environment that uses Airflow 2, -# they will keep working due to backport compatibility. -# -# For tracking progress on the YAML config templates that use Airflow 2 operators, see -# https://github.com/GoogleCloudPlatform/public-datasets-pipelines/issues/137. - --- resources: # A list of GCP resources that are unique and specific to your pipeline. @@ -68,7 +60,7 @@ resources: dag: # Specify the Airflow version of the operators used by the DAG. Defaults to Airflow 2 when unspecified. - airflow_version: 1 + airflow_version: 2 # The DAG acronym stands for directed acyclic graph. This block represents # your data pipeline along with every property and configuration it needs to @@ -82,7 +74,7 @@ dag: depends_on_past: False start_date: '2021-03-01' max_active_runs: 1 - schedule_interval: "@once" # run once a week at Sunday 12am + schedule_interval: "@once" catchup: False default_view: graph @@ -113,7 +105,7 @@ dag: args: # Arguments supported by this operator: - # https://airflow.apache.org/docs/apache-airflow/1.10.15/howto/operator/bash.html + # https://airflow.apache.org/docs/apache-airflow/stable/howto/operator/bash.html task_id: "sample_bash_task" bash_command: | @@ -127,15 +119,14 @@ dag: - operator: "GoogleCloudStorageToBigQueryOperator" # Initializes GCS to BQ task for the DAG. This operator is used to load a - # CSV file from GCS into a BigQuery table. + # JSON, CSV, Avro, ORC, or Parquet data from GCS into a BigQuery table. # Task description description: "Task to load CSV data to a BigQuery table" + # Arguments supported by this operator: + # http://airflow.apache.org/docs/apache-airflow/stable/howto/operator/gcp/gcs.html#googlecloudstoragetobigqueryoperator args: - # Arguments supported by this operator: - # http://airflow.apache.org/docs/apache-airflow/1.10.15/howto/operator/gcp/gcs.html#googlecloudstoragetobigqueryoperator - task_id: "sample_gcs_to_bq_task" # The GCS bucket where the CSV file is located in. @@ -171,16 +162,16 @@ dag: type: "INTEGER" mode: "NULLABLE" + # Initializes a GCS-to-GCS task for the DAG. This operator is used to copy or move + # GCS objects from one location to another. - operator: "GoogleCloudStorageToGoogleCloudStorageOperator" - # Initializes a GCS-to-GCS task for the DAG. This operator is used to copy - # GCS objects from one location to another. # Task description description: "Task to run a GoogleCloudStorageToGoogleCloudStorageOperator" args: # Arguments supported by this operator: - # https://airflow.apache.org/docs/apache-airflow/1.10.15/_api/airflow/contrib/operators/gcs_to_gcs/index.html#airflow.contrib.operators.gcs_to_gcs.GoogleCloudStorageToGoogleCloudStorageOperator + # https://airflow.apache.org/docs/apache-airflow-providers-google/stable/_api/airflow/providers/google/cloud/transfers/gcs_to_gcs/index.html task_id: "sample_gcs_to_gcs_task" @@ -190,6 +181,11 @@ dag: # Use a trailing "/*" if you want to copy all objects under that path. source_object: "data/DATASET_FOLDER_NAME/PIPELINE_FOLDER_NAME/run_date={{ ds }}/*" + # Optionally, you can supply a list of objects to specifically copy + source_objects: + - "path/to/object" + - "path/to/another/object" + # The GCS bucket to copy the object/s to destination_bucket: "{{ var.json.DATASET_FOLDER_NAME.destination_bucket }}" @@ -199,16 +195,28 @@ dag: # Use this argument if you don't want to keep the source object/s. move_object: True - - operator: "BigQueryOperator" - # Initializes a BigQuery operator that executes SQL queries in a specific - # BigQuery table. + # Whether you want to replace existing destination files or not. + replace: False + + # [Optional] This is used to restrict the result to only the matching names in a given folder + # If source_objects = ['foo/bah/'] and delimiter = '.avro', then only the .avro + # files will be copied to the destination folder. + delimiter: ".csv" + + # [Optional] When specified, the objects will be copied or moved, only if they were modified + # after last_modified_time. If tzinfo has not been set, UTC will be assumed. + last_modified_time: "2021-08-10 11:58:27" + + - operator: "BigQueryExecuteQueryOperator" + # Initializes a BigQuery operator that executes SQL queries in a specific BigQuery table, + # and can optionally store the results of a query to another table # Task description - description: "Task to run a BigQueryOperator" + description: "Task to run a execute a BigQuery SQL query in a specific BigQuery database" args: # Arguments supported by this operator: - # https://airflow.apache.org/docs/apache-airflow/1.10.15/_api/airflow/contrib/operators/bigquery_operator/index.html#airflow.contrib.operators.bigquery_operator.BigQueryOperator + # https://airflow.apache.org/docs/apache-airflow-providers-google/stable/_api/airflow/providers/google/cloud/operators/bigquery/index.html#airflow.providers.google.cloud.operators.bigquery.BigQueryExecuteQueryOperator task_id: "sample_bq_sql_task" @@ -222,23 +230,44 @@ dag: parameterValue: value: 100 - # The BigQuery destination table + # If specified, will store the results of the query to a BigQuery destination table destination_dataset_table: "destination_dataset.destination_table" + # Specifies whether the job is allowed to create new tables. + create_disposition: "CREATE_IF_NEEDED" + # How to write to the destination: overwrite, append, or write if empty # See https://cloud.google.com/bigquery/docs/reference/auditlogs/rest/Shared.Types/WriteDisposition write_disposition: "WRITE_TRUNCATE" + # [Optional] Configure optional time partitioning fields i.e. partition by field, type and expiration + # as per API specifications. + time_partitioning: + # The supported types are DAY, HOUR, MONTH, and YEAR, which will generate one partition per day, hour, + # month, and year, respectively. + type: "DAY" + + # [Optional] BigQuery supports clustering for both partitioned and non-partitioned tables. The order + # of columns given determines the sort order. + cluster_fields: + - "column_1" + - "column_2" + - "column_3" + + # [Optional for US and EU] The geographic location of the job + location: "asia-northeast1" + + # Deletes objects from a Google Cloud Storage bucket, either from an explicit list of object names + # or all objects matching a prefix. - operator: "GoogleCloudStorageDeleteOperator" - # Initializes a GCS operator that deletes all specified objects # Task description - description: "Task to run a GoogleCloudStorageDeleteOperator" + description: "Task to delete objects from a GCS bucket" + # Arguments supported by this operator: + # https://airflow.apache.org/docs/apache-airflow-providers-google/stable/_api/airflow/providers/google/cloud/operators/gcs/index.html#airflow.providers.google.cloud.operators.gcs.GCSDeleteObjectsOperator args: - # Arguments supported by this operator: - # https://airflow.apache.org/docs/apache-airflow/1.10.15/_api/airflow/contrib/operators/gcs_delete_operator/index.html#airflow.contrib.operators.gcs_delete_operator.GoogleCloudStorageDeleteOperator - task_id: "sample_gcs_delete_task" + task_id: "gcs_delete_task" # The GCS bucket where the objects to delete are located. bucket_name: "sample_bucket" @@ -250,12 +279,11 @@ dag: # All objects matching this prefix in the bucket will be deleted. prefix: "prefix/to/delete" + # Executes a task in a Kubernetes pod that uses the Cloud Composer environment's own CPU and memory resources. + # Note: Do NOT use this for very heavy workloads. This can potentially starve resources from Cloud Composer + # and affect data pipeline orchestration overall. Instead, use a different GKE cluster using Kubernetes + # Engine operators: https://github.com/apache/airflow/blob/master/airflow/providers/google/cloud/operators/kubernetes_engine.py - operator: "KubernetesPodOperator" - # Executes a task in a Kubernetes pod that uses the Cloud Composer environment's own CPU and memory resources. - # - # Note: Do NOT use this for very heavy workloads. This can potentially starve resources from Cloud Composer - # and affect data pipeline orchestration overall. Instead, use a different GKE cluster using Kubernetes - # Engine operators: https://github.com/apache/airflow/blob/master/airflow/providers/google/cloud/operators/kubernetes_engine.py # Task description description: "Task to run a KubernetesPodOperator" @@ -315,15 +343,67 @@ dag: limit_memory: "250M" limit_cpu: "1" - - operator: "BigQueryToBigQueryOperator" - description: "Task to run a BQ to BQ operator" + # Documentation: + # http://airflow.apache.org/docs/apache-airflow-providers-google/stable/_api/airflow/providers/google/cloud/operators/kubernetes_engine/index.html#airflow.providers.google.cloud.operators.kubernetes_engine.GKEStartPodOperator + - operator: "GKEStartPodOperator" args: - task_id: "sample_bq_to_bq_task" - source_project_dataset_tables: ["{{ var.json.DATASET_FOLDER_NAME.PIPELINE_NAME.source_project_dataset_table }}"] - destination_project_dataset_table: "{{ var.json.DATASET_FOLDER_NAME.PIPELINE_NAME.destination_project_dataset_table }}" - impersonation_chain: "{{ var.json.DATASET_FOLDER_NAME.service_account }}" - write_disposition: "WRITE_TRUNCATE" + task_id: "gke_start_pod_task" + project_id: "{{ var.json.shared.gcp_project_id }}" + location: "{{ var.json.shared.gcp_location }}" + + # The name of the Google Kubernetes Engine cluster the pod should be spawned in + cluster_name: "GKE_CLUSTER_NAME" + + # The namespace to run within Kubernetes + namespace: "default" + + # The name of the pod in which the task will run. This will be used (plus a random suffix) to generate a pod id + name: "sample-gke-pod" + + # The GCR image URL. It's recommended to redact its value and set it using Airflow variables + image: "{{ var.json.DATASET_FOLDER_NAME.container_registry.IMAGE_REPOSITORY }}" + + # [Optional] Entrypoint command for the container + cmds: + - "mkdir -p /airflow/xcom/ &&" + - "echo '[1,2,3,4]' > /airflow/xcom/return.json" + + # [Optional] Enable the usage of XCom on the operator. XCom allows you to store values used downstream + # in your DAG. To do this, create a `return.json` file under /airflow/xcom in your pod script. To use + # XCom variables in other operators, use the macro {{ task_instance.xcom_pull('POD_TASK_ID')[0] }} + do_xcom_push: True + + # Deletes a GKE cluster, including the Kubernetes endpoint and all worker nodes. + - operator: "GKEDeleteClusterOperator" + + args: + task_id: "gke_delete_cluster_task" + project_id: "{{ var.json.shared.gcp_project_id }}" + location: "{{ var.json.shared.gcp_location }}" + + # The GKE cluster name + name: "sample-gke-cluster" + + # Optional service account to impersonate using short-term credentials + impersonation_chain: "{{ var.json.DATASET_FOLDER_NAME.PIPELINE_FOLDER_NAME.service_account }}" + + # Create a GKE cluster of specified dimensions. The operator will wait until the cluster is created. + - operator: "GKECreateClusterOperator" + + args: + task_id: "gke_create_cluster_task" + project_id: "{{ var.json.shared.gcp_project_id }}" + location: "{{ var.json.shared.gcp_location }}" + + # The cluster definition to create, + # see https://googleapis.dev/python/container/latest/container_v1/types.html#google.cloud.container_v1.types.Cluster + body: + name: "sample-gke-cluster" + initial_node_count: 1 + + # Optional service account to impersonate using short-term credentials + impersonation_chain: "{{ var.json.DATASET_FOLDER_NAME.PIPELINE_FOLDER_NAME.service_account }}" graph_paths: # This is where you specify the relationships (i.e. directed paths/edges) @@ -333,5 +413,5 @@ dag: # For more info, see # https://airflow.apache.org/docs/apache-airflow/stable/tutorial.html#setting-up-dependencies - "sample_bash_task >> [sample_gcs_to_bq_task, sample_gcs_to_gcs_task]" - - "sample_gcs_to_bq_task >> [sample_bq_sql_task, sample_bq_to_bq_task]" - - "sample_bq_sql_task >> sample_gcs_delete_task" + - "sample_gcs_to_bq_task >> [sample_bq_sql_task, gcs_delete_task]" + - "gke_create_cluster_task >> gke_start_pod_task >> gke_delete_cluster_task" diff --git a/scripts/dag_imports.json b/scripts/dag_imports.json index 302ced257..c0f88ee0d 100644 --- a/scripts/dag_imports.json +++ b/scripts/dag_imports.json @@ -46,6 +46,10 @@ "import": "from airflow.providers.google.cloud.operators import gcs", "class": "gcs.GCSDeleteObjectsOperator" }, + "BigQueryExecuteQueryOperator": { + "import": "from airflow.providers.google.cloud.operators import bigquery", + "class": "bigquery.BigQueryExecuteQueryOperator" + }, "BigQueryInsertJobOperator": { "import": "from airflow.providers.google.cloud.operators import bigquery", "class": "bigquery.BigQueryInsertJobOperator" @@ -53,6 +57,18 @@ "KubernetesPodOperator": { "import": "from airflow.providers.cncf.kubernetes.operators import kubernetes_pod", "class": "kubernetes_pod.KubernetesPodOperator" + }, + "GKEStartPodOperator": { + "import": "from airflow.providers.google.cloud.operators import kubernetes_engine", + "class": "kubernetes_engine.GKEStartPodOperator" + }, + "GKECreateClusterOperator": { + "import": "from airflow.providers.google.cloud.operators import kubernetes_engine", + "class": "kubernetes_engine.GKECreateClusterOperator" + }, + "GKEDeleteClusterOperator": { + "import": "from airflow.providers.google.cloud.operators import kubernetes_engine", + "class": "kubernetes_engine.GKEDeleteClusterOperator" } - } + } } From 271843026d340e0020fb76604b4ff1fa8725531f Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Tue, 10 Aug 2021 16:41:18 -0400 Subject: [PATCH 11/17] add license header to unit-tests --- .github/workflows/unit-tests.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index 9e5c2492d..40fd58f4a 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -1,3 +1,17 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + name: Run unit tests on: [pull_request] jobs: From 5f7a5ab07daefb0befe1dbf6d3152c33b3e5e828 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Tue, 10 Aug 2021 16:44:07 -0400 Subject: [PATCH 12/17] require airflow_version to be explicitly stated --- samples/pipeline.airflow1.yaml | 2 +- samples/pipeline.yaml | 2 +- scripts/generate_dag.py | 30 ++++++++++++++++-------------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/samples/pipeline.airflow1.yaml b/samples/pipeline.airflow1.yaml index 37b943d9a..30261d145 100644 --- a/samples/pipeline.airflow1.yaml +++ b/samples/pipeline.airflow1.yaml @@ -67,7 +67,7 @@ resources: deletion_protection: true dag: - # Specify the Airflow version of the operators used by the DAG. Defaults to Airflow 2 when unspecified. + # [Required] Specify the Airflow version of the operators used by the DAG. airflow_version: 1 # The DAG acronym stands for directed acyclic graph. This block represents diff --git a/samples/pipeline.yaml b/samples/pipeline.yaml index 0ecc3c67d..cac42c1b6 100644 --- a/samples/pipeline.yaml +++ b/samples/pipeline.yaml @@ -59,7 +59,7 @@ resources: deletion_protection: true dag: - # Specify the Airflow version of the operators used by the DAG. Defaults to Airflow 2 when unspecified. + # [Required] Specify the Airflow version of the operators used by the DAG. airflow_version: 2 # The DAG acronym stands for directed acyclic graph. This block represents diff --git a/scripts/generate_dag.py b/scripts/generate_dag.py index 93a61e437..7c313dde8 100644 --- a/scripts/generate_dag.py +++ b/scripts/generate_dag.py @@ -27,16 +27,6 @@ yaml = yaml.YAML(typ="safe") -OPERATORS = { - "BashOperator", - "GoogleCloudStorageToBigQueryOperator", - "GoogleCloudStorageToGoogleCloudStorageOperator", - "GoogleCloudStorageDeleteOperator", - "BigQueryOperator", - "BigQueryToBigQueryOperator", - "KubernetesPodOperator", -} - CURRENT_PATH = pathlib.Path(__file__).resolve().parent PROJECT_ROOT = CURRENT_PATH.parent DATASETS_PATH = PROJECT_ROOT / "datasets" @@ -52,6 +42,7 @@ DEFAULT_AIRFLOW_VERSION = 2 AIRFLOW_IMPORTS = json.load(open(CURRENT_PATH / "dag_imports.json")) +AIRFLOW_VERSIONS = list(AIRFLOW_IMPORTS.keys()) def main( @@ -77,6 +68,7 @@ def generate_pipeline_dag(dataset_id: str, pipeline_id: str, env: str): pipeline_dir = DATASETS_PATH / dataset_id / pipeline_id config = yaml.load((pipeline_dir / "pipeline.yaml").read_text()) + validate_airflow_version_existence_and_value(config) validate_dag_id_existence_and_format(config) dag_contents = generate_dag(config, dataset_id) @@ -135,7 +127,7 @@ def generate_dag_context(config: dict, dataset_id: str) -> str: def generate_task_contents(task: dict, airflow_version: str) -> str: - validate_task(task) + validate_task(task, airflow_version) return jinja2.Template(TEMPLATE_PATHS["task"].read_text()).render( **task, namespaced_operator=AIRFLOW_IMPORTS[airflow_version][task["operator"]]["class"], @@ -162,6 +154,14 @@ def namespaced_dag_id(dag_id: str, dataset_id: str) -> str: return f"{dataset_id}.{dag_id}" +def validate_airflow_version_existence_and_value(config: dict): + if "airflow_version" not in config["dag"]: + raise KeyError("Missing required parameter:`dag.airflow_version`") + + if str(config["dag"]["airflow_version"]) not in AIRFLOW_VERSIONS: + raise ValueError("`dag.airflow_version` must be a valid Airflow major version") + + def validate_dag_id_existence_and_format(config: dict): init = dag_init(config) if not init.get("dag_id"): @@ -174,12 +174,14 @@ def validate_dag_id_existence_and_format(config: dict): ) -def validate_task(task: dict): +def validate_task(task: dict, airflow_version: str): if not task.get("operator"): raise KeyError(f"`operator` key must exist in {task}") - if not task["operator"] in OPERATORS: - raise ValueError(f"`task.operator` must be one of {list(OPERATORS)}") + if not task["operator"] in AIRFLOW_IMPORTS[airflow_version]: + raise ValueError( + f"`task.operator` must be one of {list(AIRFLOW_IMPORTS[airflow_version].keys())}" + ) if not task["args"].get("task_id"): raise KeyError(f"`args.task_id` key must exist in {task}") From f09065453a718fe1280ba5c8734b88cbd12baafa Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Tue, 10 Aug 2021 16:45:07 -0400 Subject: [PATCH 13/17] set default Cloud Composer version to Airflow 2 --- tests/scripts/test_deploy_dag.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/scripts/test_deploy_dag.py b/tests/scripts/test_deploy_dag.py index 3a855541e..c33341b21 100644 --- a/tests/scripts/test_deploy_dag.py +++ b/tests/scripts/test_deploy_dag.py @@ -211,7 +211,7 @@ def test_script_can_deploy_without_variables_files( mocker.patch("scripts.deploy_dag.run_gsutil_cmd") mocker.patch("scripts.deploy_dag.run_cloud_composer_vars_import") - mocker.patch("scripts.deploy_dag.composer_airflow_version", return_value=1) + mocker.patch("scripts.deploy_dag.composer_airflow_version", return_value=2) deploy_dag.main( local=False, From c37c2c8b7f44eee2ee027ea83b292eb89f4201d0 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Tue, 10 Aug 2021 16:45:54 -0400 Subject: [PATCH 14/17] tests to verify correct Airflow operators based on version specified --- tests/scripts/test_generate_dag.py | 117 ++++++++++++++++------------- 1 file changed, 65 insertions(+), 52 deletions(-) diff --git a/tests/scripts/test_generate_dag.py b/tests/scripts/test_generate_dag.py index 842aa69d5..9612f68bf 100644 --- a/tests/scripts/test_generate_dag.py +++ b/tests/scripts/test_generate_dag.py @@ -13,6 +13,7 @@ # limitations under the License. +import json import pathlib import random import shutil @@ -36,6 +37,9 @@ ENV_PATH = generate_dag.PROJECT_ROOT / ".test" ENV_DATASETS_PATH = ENV_PATH / "datasets" +AIRFLOW_IMPORTS = json.load(open(PROJECT_ROOT / "scripts" / "dag_imports.json")) +AIRFLOW_VERSIONS = list(AIRFLOW_IMPORTS.keys()) + @pytest.fixture def dataset_path() -> typing.Iterator[pathlib.Path]: @@ -154,47 +158,44 @@ def test_main_creates_shared_variables_file( assert not (ENV_DATASETS_PATH / "shared_variables.json").is_dir() -def test_main_uses_airflow1_operators_when_airflow_version_is_set_to_1( +def test_main_raises_an_error_when_airflow_version_is_not_specified( dataset_path: pathlib.Path, pipeline_path: pathlib.Path, env: str ): copy_config_files_and_set_tmp_folder_names_as_ids(dataset_path, pipeline_path) - - # Verify that the template uses Airflow 1 config = yaml.load(open(pipeline_path / "pipeline.yaml")) - assert config["dag"]["airflow_version"] == 1 - generate_dag.main(dataset_path.name, pipeline_path.name, env) + # Don't specify the `airflow_version` + del config["dag"]["airflow_version"] + with open(pipeline_path / "pipeline.yaml", "w") as file: + yaml.dump(config, file) - for path_prefix in ( - pipeline_path, - ENV_DATASETS_PATH / dataset_path.name / pipeline_path.name, - ): - assert (path_prefix / f"{pipeline_path.name}_dag.py").exists() - assert ( - "airflow.contrib.operators" - in (path_prefix / f"{pipeline_path.name}_dag.py").read_text() - ) - assert ( - "airflow.providers.google" - not in (path_prefix / f"{pipeline_path.name}_dag.py").read_text() - ) + with pytest.raises(KeyError): + generate_dag.main(dataset_path.name, pipeline_path.name, env) -# Requires a pipeline.yaml config that uses Airflow2 operators. Soon to follow. -# See https://github.com/GoogleCloudPlatform/public-datasets-pipelines/issues/137 -@pytest.mark.skip() -def test_main_defaults_to_using_airflow2_when_airflow_version_is_unspecified( +def test_main_raises_an_error_when_airflow_version_is_incorrect( dataset_path: pathlib.Path, pipeline_path: pathlib.Path, env: str ): copy_config_files_and_set_tmp_folder_names_as_ids(dataset_path, pipeline_path) - config = yaml.load(open(pipeline_path / "pipeline.yaml")) - # Delete the `airflow_version` field in the pipeline YAML config - del config["dag"]["airflow_version"] + # Set an incorrect `airflow_version` + config["dag"]["airflow_version"] = "789" with open(pipeline_path / "pipeline.yaml", "w") as file: yaml.dump(config, file) + with pytest.raises(ValueError): + generate_dag.main(dataset_path.name, pipeline_path.name, env) + + +def test_main_uses_airflow_operators_based_on_airflow_version_specified_in_the_config( + dataset_path: pathlib.Path, pipeline_path: pathlib.Path, env: str +): + copy_config_files_and_set_tmp_folder_names_as_ids(dataset_path, pipeline_path) + + config = yaml.load(open(pipeline_path / "pipeline.yaml")) + airflow_version = config["dag"]["airflow_version"] + generate_dag.main(dataset_path.name, pipeline_path.name, env) for path_prefix in ( @@ -202,14 +203,25 @@ def test_main_defaults_to_using_airflow2_when_airflow_version_is_unspecified( ENV_DATASETS_PATH / dataset_path.name / pipeline_path.name, ): assert (path_prefix / f"{pipeline_path.name}_dag.py").exists() - assert ( - "providers.google" - in (path_prefix / f"{pipeline_path.name}_dag.py").read_text() - ) - assert ( - "airflow.contrib.operators" - not in (path_prefix / f"{pipeline_path.name}_dag.py").read_text() - ) + + if airflow_version == "1": + assert ( + "airflow.contrib.operators" + in (path_prefix / f"{pipeline_path.name}_dag.py").read_text() + ) + assert ( + "airflow.providers.google" + not in (path_prefix / f"{pipeline_path.name}_dag.py").read_text() + ) + elif airflow_version == "2": + assert ( + "airflow.contrib.operators" + not in (path_prefix / f"{pipeline_path.name}_dag.py").read_text() + ) + assert ( + "airflow.providers.google" + in (path_prefix / f"{pipeline_path.name}_dag.py").read_text() + ) def test_main_only_depends_on_pipeline_yaml( @@ -243,25 +255,26 @@ def test_main_errors_out_on_nonexisting_pipeline_yaml( def test_checks_for_task_operator_and_id(): - valid_task = { - "operator": "GoogleCloudStorageToBigQueryOperator", - "args": {"task_id": "load_gcs_to_bq"}, - } - generate_dag.validate_task(valid_task) - - non_existing_operator = { - "operator": "NonExisting", - "args": {"task_id": "load_gcs_to_bq"}, - } - with pytest.raises(ValueError): - generate_dag.validate_task(non_existing_operator) - - non_existing_task_id = { - "operator": "GoogleCloudStorageToBigQueryOperator", - "args": {"some_arg": "some_val"}, - } - with pytest.raises(KeyError): - generate_dag.validate_task(non_existing_task_id) + for airflow_version in AIRFLOW_VERSIONS: + valid_task = { + "operator": "GoogleCloudStorageToBigQueryOperator", + "args": {"task_id": "load_gcs_to_bq"}, + } + generate_dag.validate_task(valid_task, airflow_version) + + non_existing_operator = { + "operator": "NonExisting", + "args": {"task_id": "load_gcs_to_bq"}, + } + with pytest.raises(ValueError): + generate_dag.validate_task(non_existing_operator, airflow_version) + + non_existing_task_id = { + "operator": "GoogleCloudStorageToBigQueryOperator", + "args": {"some_arg": "some_val"}, + } + with pytest.raises(KeyError): + generate_dag.validate_task(non_existing_task_id, airflow_version) def test_generated_dag_file_loads_properly_in_python( From ad52f1113d4ef9d970f2f90ad4d993945e2d2614 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Tue, 10 Aug 2021 16:46:20 -0400 Subject: [PATCH 15/17] additional GitHub check for unit testing Airflow 1 pipelines --- .github/workflows/unit-tests-airflow1.yaml | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/unit-tests-airflow1.yaml diff --git a/.github/workflows/unit-tests-airflow1.yaml b/.github/workflows/unit-tests-airflow1.yaml new file mode 100644 index 000000000..8db3f5220 --- /dev/null +++ b/.github/workflows/unit-tests-airflow1.yaml @@ -0,0 +1,41 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Run unit tests for Airflow 1.10 operators +on: [pull_request] +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.8] + steps: + - uses: actions/checkout@v2 + - uses: hashicorp/setup-terraform@v1 + with: + terraform_version: 0.15.1 + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install pipenv + run: pip install pipenv + - name: Install dependencies + run: pipenv install --ignore-pipfile --dev + - name: Initialize Airflow + run: pipenv run airflow db init + - name: Setup Airflow 1.10 pipeline YAML config + run: cp samples/pipeline.airflow1.yaml samples/pipeline.yaml + - name: Run tests + run: pipenv run python -m pytest -v From cc2a4af9f7e031ce33ab1f7cddd823bcabde9d18 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Tue, 10 Aug 2021 16:53:23 -0400 Subject: [PATCH 16/17] set default Airflow version to 2 --- scripts/deploy_dag.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/deploy_dag.py b/scripts/deploy_dag.py index 01528fb0b..cb48cbd14 100644 --- a/scripts/deploy_dag.py +++ b/scripts/deploy_dag.py @@ -27,7 +27,7 @@ CURRENT_PATH = pathlib.Path(__file__).resolve().parent PROJECT_ROOT = CURRENT_PATH.parent DATASETS_PATH = PROJECT_ROOT / "datasets" -DEFAULT_AIRFLOW_VERSION = 1 +DEFAULT_AIRFLOW_VERSION = 2 class IncompatibilityError(Exception): From 7c2706e8611870bd4528cac8e50fb86dd9f47fa5 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Tue, 10 Aug 2021 18:22:10 -0400 Subject: [PATCH 17/17] retrigger checks --- scripts/deploy_dag.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/deploy_dag.py b/scripts/deploy_dag.py index cb48cbd14..db8a523c8 100644 --- a/scripts/deploy_dag.py +++ b/scripts/deploy_dag.py @@ -175,7 +175,7 @@ def import_variables_to_airflow_env( airflow variables import .{ENV}/datasets/{DATASET_ID}/variables.json [remote] - gcloud composer environments run COMPOSER_ENV --location COMPOSER_REGION variables -- --import /home/airflow/gcs/data/variables/{DATASET_ID}_variables.json + gcloud composer environments run COMPOSER_ENV --location COMPOSER_REGION variables -- import /home/airflow/gcs/data/variables/{DATASET_ID}_variables.json """ for cwd, filename in ( (env_path / "datasets", "shared_variables.json"),