diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml
index 18151f74547..2a6cff517c4 100644
--- a/.github/auto_assign.yml
+++ b/.github/auto_assign.yml
@@ -9,7 +9,6 @@ assignees:
- woop
- tsotnet
- achals
- - adchia
- felixwang9817
# A number of assignees to add to the pull request
diff --git a/.github/fork_workflows/fork_pr_integration_tests_aws.yml b/.github/fork_workflows/fork_pr_integration_tests_aws.yml
index e4362af7d3e..7261833ae6b 100644
--- a/.github/fork_workflows/fork_pr_integration_tests_aws.yml
+++ b/.github/fork_workflows/fork_pr_integration_tests_aws.yml
@@ -83,7 +83,7 @@ jobs:
--health-timeout 5s
--health-retries 5
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# pull_request_target runs the workflow in the context of the base repo
# as such actions/checkout needs to be explicit configured to retrieve
@@ -91,7 +91,7 @@ jobs:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
submodules: recursive
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
id: setup-python
with:
python-version: ${{ matrix.python-version }}
@@ -109,9 +109,6 @@ jobs:
aws-region: us-west-2
- name: Use AWS CLI
run: aws sts get-caller-identity
- - name: Upgrade pip version
- run: |
- pip install --upgrade "pip>=21.3.1,<22.1"
- name: Get pip cache dir
id: pip-cache
run: |
@@ -126,6 +123,9 @@ jobs:
key: ${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-${{ hashFiles(format('**/py{0}-ci-requirements.txt', env.PYTHON)) }}
restore-keys: |
${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-
+ - name: Upgrade pip version
+ run: |
+ pip install --upgrade "pip>=21.3.1,<22.3"
- name: Install pip-tools
run: pip install pip-tools
- name: Install apache-arrow on ubuntu
diff --git a/.github/fork_workflows/fork_pr_integration_tests_gcp.yml b/.github/fork_workflows/fork_pr_integration_tests_gcp.yml
index d77c1052e7c..1a05c068b50 100644
--- a/.github/fork_workflows/fork_pr_integration_tests_gcp.yml
+++ b/.github/fork_workflows/fork_pr_integration_tests_gcp.yml
@@ -25,7 +25,7 @@ jobs:
--health-timeout 5s
--health-retries 5
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# pull_request_target runs the workflow in the context of the base repo
# as such actions/checkout needs to be explicit configured to retrieve
@@ -33,7 +33,7 @@ jobs:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
submodules: recursive
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
id: setup-python
with:
python-version: ${{ matrix.python-version }}
@@ -53,9 +53,6 @@ jobs:
project_id: ${{ secrets.GCP_PROJECT_ID }}
- name: Use gcloud CLI
run: gcloud info
- - name: Upgrade pip version
- run: |
- pip install --upgrade "pip>=21.3.1,<22.1"
- name: Get pip cache dir
id: pip-cache
run: |
@@ -70,6 +67,9 @@ jobs:
key: ${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-${{ hashFiles(format('**/py{0}-ci-requirements.txt', env.PYTHON)) }}
restore-keys: |
${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-
+ - name: Upgrade pip version
+ run: |
+ pip install --upgrade "pip>=21.3.1,<23.2"
- name: Install pip-tools
run: pip install pip-tools
- name: Install apache-arrow on ubuntu
diff --git a/.github/fork_workflows/fork_pr_integration_tests_snowflake.yml b/.github/fork_workflows/fork_pr_integration_tests_snowflake.yml
index 56b4c268b70..9327f5c7294 100644
--- a/.github/fork_workflows/fork_pr_integration_tests_snowflake.yml
+++ b/.github/fork_workflows/fork_pr_integration_tests_snowflake.yml
@@ -25,7 +25,7 @@ jobs:
--health-timeout 5s
--health-retries 5
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# pull_request_target runs the workflow in the context of the base repo
# as such actions/checkout needs to be explicit configured to retrieve
@@ -33,7 +33,7 @@ jobs:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
submodules: recursive
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
id: setup-python
with:
python-version: ${{ matrix.python-version }}
@@ -43,10 +43,6 @@ jobs:
uses: actions/setup-go@v2
with:
go-version: 1.18.0
-
- - name: Upgrade pip version
- run: |
- pip install --upgrade "pip>=21.3.1,<22.1"
- name: Get pip cache dir
id: pip-cache
run: |
@@ -61,6 +57,9 @@ jobs:
key: ${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-${{ hashFiles(format('**/py{0}-ci-requirements.txt', env.PYTHON)) }}
restore-keys: |
${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-
+ - name: Upgrade pip version
+ run: |
+ pip install --upgrade "pip>=21.3.1,<23.2"
- name: Install pip-tools
run: pip install pip-tools
- name: Install apache-arrow on ubuntu
diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml
index 9bed2a4282b..6e6539cf9e4 100644
--- a/.github/workflows/build_wheels.yml
+++ b/.github/workflows/build_wheels.yml
@@ -18,7 +18,7 @@ jobs:
highest_semver_tag: ${{ steps.get_highest_semver.outputs.highest_semver_tag }}
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
persist-credentials: false
- name: Get release version
@@ -55,14 +55,14 @@ jobs:
name: Build wheels
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
with:
python-version: "3.8"
architecture: x64
- name: Setup Node
- uses: actions/setup-node@v2
+ uses: actions/setup-node@v3
with:
node-version: '17.x'
registry-url: 'https://registry.npmjs.org'
@@ -72,24 +72,24 @@ jobs:
run: |
python -m pip install build
python -m build --wheel --outdir wheelhouse/
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
with:
name: wheels
path: ./wheelhouse/*.whl
build-source-distribution:
name: Build source distribution
- runs-on: macos-10.15
+ runs-on: macos-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup Python
id: setup-python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
with:
python-version: "3.10"
architecture: x64
- name: Setup Node
- uses: actions/setup-node@v2
+ uses: actions/setup-node@v3
with:
node-version: '17.x'
registry-url: 'https://registry.npmjs.org'
@@ -105,7 +105,7 @@ jobs:
- name: Build
run: |
python3 setup.py sdist
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
with:
name: wheels
path: dist/*
@@ -120,7 +120,7 @@ jobs:
env:
REGISTRY: feastdev
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
@@ -136,7 +136,7 @@ jobs:
needs: [build-python-wheel, build-source-distribution, get-version]
strategy:
matrix:
- os: [ubuntu-latest, macos-10.15 ]
+ os: [ubuntu-latest, macos-latest ]
python-version: [ "3.8", "3.9", "3.10"]
from-source: [ True, False ]
env:
@@ -156,7 +156,7 @@ jobs:
steps:
- name: Setup Python
id: setup-python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
architecture: x64
@@ -165,7 +165,7 @@ jobs:
name: wheels
path: dist
- name: Install OS X dependencies
- if: matrix.os == 'macos-10.15'
+ if: matrix.os == 'macos-latest'
run: brew install coreutils
- name: Install wheel
if: ${{ !matrix.from-source }}
@@ -192,11 +192,12 @@ jobs:
echo "$VERSION_OUTPUT from installed wheel is not in the correct format or doesn't have the right version $VERSION."
exit 1
fi
- - name: Smoke test
- run: |
- feast init test_repo
- cd test_repo/feature_repo
- feast apply
- echo "$TEST_SCRIPT" > run-and-wait.sh
- bash run-and-wait.sh feast serve
- bash run-and-wait.sh feast ui
+ # This is temporarily disabled.
+ # - name: Smoke test
+ # run: |
+ # feast init test_repo
+ # cd test_repo/feature_repo
+ # feast apply
+ # echo "$TEST_SCRIPT" > run-and-wait.sh
+ # bash run-and-wait.sh feast serve
+ # bash run-and-wait.sh feast ui
diff --git a/.github/workflows/java_master_only.yml b/.github/workflows/java_master_only.yml
index f4c280d682d..d82f69dd3cb 100644
--- a/.github/workflows/java_master_only.yml
+++ b/.github/workflows/java_master_only.yml
@@ -18,11 +18,11 @@ jobs:
MAVEN_CACHE: gs://feast-templocation-kf-feast/.m2.2020-08-19.tar
REGISTRY: gcr.io/kf-feast
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
submodules: 'true'
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
id: setup-python
with:
python-version: "3.8"
@@ -53,7 +53,7 @@ jobs:
if: github.repository == 'feast-dev/feast'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
submodules: 'true'
- name: Lint java
@@ -63,7 +63,7 @@ jobs:
if: github.repository == 'feast-dev/feast'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
submodules: 'true'
- name: Set up JDK 11
@@ -86,7 +86,7 @@ jobs:
${{ runner.os }}-ut-maven-
- name: Test java
run: make test-java-with-coverage
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
with:
name: java-coverage-report
path: ${{ github.workspace }}/docs/coverage/java/target/site/jacoco-aggregate/
@@ -97,7 +97,7 @@ jobs:
env:
PYTHON: 3.8
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
submodules: 'true'
- name: Set up JDK 11
@@ -107,14 +107,11 @@ jobs:
java-package: jdk
architecture: x64
- name: Setup Python (to call feast apply)
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
id: setup-python
with:
python-version: 3.8
architecture: x64
- - name: Upgrade pip version
- run: |
- pip install --upgrade pip
- name: Get pip cache dir
id: pip-cache
run: |
@@ -129,9 +126,11 @@ jobs:
key: ${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-${{ hashFiles(format('**/py{0}-ci-requirements.txt', env.PYTHON)) }}
restore-keys: |
${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-
+ - name: Upgrade pip version
+ run: |
+ pip install --upgrade "pip>=21.3.1,<23.2"
- name: Install pip-tools
run: pip install pip-tools
-
- name: Install Python dependencies
run: make install-python-ci-dependencies
- uses: actions/cache@v2
diff --git a/.github/workflows/java_pr.yml b/.github/workflows/java_pr.yml
index ad8700c0722..83c52e7dbfd 100644
--- a/.github/workflows/java_pr.yml
+++ b/.github/workflows/java_pr.yml
@@ -12,7 +12,7 @@ jobs:
if: github.repository == 'feast-dev/feast'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# pull_request_target runs the workflow in the context of the base repo
# as such actions/checkout needs to be explicit configured to retrieve
@@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
needs: lint-java
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# pull_request_target runs the workflow in the context of the base repo
# as such actions/checkout needs to be explicit configured to retrieve
@@ -54,7 +54,7 @@ jobs:
${{ runner.os }}-ut-maven-
- name: Test java
run: make test-java-with-coverage
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
with:
name: java-coverage-report
path: ${{ github.workspace }}/docs/coverage/java/target/site/jacoco-aggregate/
@@ -69,11 +69,11 @@ jobs:
MAVEN_CACHE: gs://feast-templocation-kf-feast/.m2.2020-08-19.tar
REGISTRY: gcr.io/kf-feast
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
submodules: 'true'
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
id: setup-python
with:
python-version: "3.8"
@@ -101,7 +101,7 @@ jobs:
env:
PYTHON: 3.8
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# pull_request_target runs the workflow in the context of the base repo
# as such actions/checkout needs to be explicit configured to retrieve
@@ -114,7 +114,7 @@ jobs:
java-version: '11'
java-package: jdk
architecture: x64
- - uses: actions/setup-python@v2
+ - uses: actions/setup-python@v3
with:
python-version: '3.8'
architecture: 'x64'
@@ -143,14 +143,11 @@ jobs:
- name: Use AWS CLI
run: aws sts get-caller-identity
- name: Setup Python (to call feast apply)
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
id: setup-python
with:
python-version: 3.8
architecture: x64
- - name: Upgrade pip version
- run: |
- pip install --upgrade pip
- name: Get pip cache dir
id: pip-cache
run: |
@@ -165,6 +162,9 @@ jobs:
key: ${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-${{ hashFiles(format('**/py{0}-ci-requirements.txt', env.PYTHON)) }}
restore-keys: |
${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-
+ - name: Upgrade pip version
+ run: |
+ pip install --upgrade "pip>=21.3.1,<23.2"
- name: Install pip-tools
run: pip install pip-tools
- name: Install Python dependencies
@@ -172,7 +172,7 @@ jobs:
- name: Run integration tests
run: make test-java-integration
- name: Save report
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
if: failure()
with:
name: it-report
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
index 31657d3dfcb..a4a42a11edb 100644
--- a/.github/workflows/linter.yml
+++ b/.github/workflows/linter.yml
@@ -8,16 +8,13 @@ jobs:
env:
PYTHON: 3.8
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup Python
id: setup-python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
with:
python-version: "3.8"
architecture: x64
- - name: Upgrade pip version
- run: |
- pip install --upgrade pip
- name: Get pip cache dir
id: pip-cache
run: |
@@ -32,6 +29,9 @@ jobs:
key: ${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-${{ hashFiles(format('**/py{0}-ci-requirements.txt', env.PYTHON)) }}
restore-keys: |
${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-
+ - name: Upgrade pip version
+ run: |
+ pip install --upgrade "pip>=21.3.1,<23.2"
- name: Install pip-tools
run: pip install pip-tools
- name: Install dependencies
diff --git a/.github/workflows/master_only.yml b/.github/workflows/master_only.yml
index 49d6fa4f856..580ea3171b3 100644
--- a/.github/workflows/master_only.yml
+++ b/.github/workflows/master_only.yml
@@ -10,7 +10,7 @@ jobs:
if: github.repository == 'feast-dev/feast'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
@@ -81,10 +81,10 @@ jobs:
--health-timeout 5s
--health-retries 5
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup Python
id: setup-python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
architecture: x64
@@ -106,9 +106,6 @@ jobs:
aws-region: us-west-2
- name: Use AWS CLI
run: aws sts get-caller-identity
- - name: Upgrade pip version
- run: |
- pip install --upgrade pip
- name: Get pip cache dir
id: pip-cache
run: |
@@ -123,6 +120,9 @@ jobs:
key: ${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-${{ hashFiles(format('**/py{0}-ci-requirements.txt', env.PYTHON)) }}
restore-keys: |
${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-
+ - name: Upgrade pip version
+ run: |
+ pip install --upgrade "pip>=21.3.1,<23.2"
- name: Install pip-tools
run: pip install pip-tools
- name: Install dependencies
@@ -166,7 +166,7 @@ jobs:
MAVEN_CACHE: gs://feast-templocation-kf-feast/.m2.2020-08-19.tar
REGISTRY: gcr.io/kf-feast
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
diff --git a/.github/workflows/nightly-ci.yml b/.github/workflows/nightly-ci.yml
index 7a22435fda9..0e1df81262d 100644
--- a/.github/workflows/nightly-ci.yml
+++ b/.github/workflows/nightly-ci.yml
@@ -17,7 +17,7 @@ jobs:
outputs:
WAS_EDITED: ${{ steps.check_date.outputs.WAS_EDITED }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
ref: master
- id: check_date
@@ -27,13 +27,13 @@ jobs:
cleanup_dynamo_tables:
if: github.repository == 'feast-dev/feast'
runs-on: ubuntu-latest
- name: Cleanup dynamo tables which can fail to cleanup
+ name: Cleanup Bigtable / Dynamo tables which can fail to cleanup
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
ref: master
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
id: setup-python
with:
python-version: "3.8"
@@ -47,9 +47,20 @@ jobs:
- name: Install Python dependencies
run: |
pip install boto3
+ pip install google-cloud-bigtable
pip install tqdm
- - name: Run DynamoDB cleanup script
- run: python infra/scripts/cleanup_dynamo_ci.py
+ - name: Authenticate to Google Cloud
+ uses: 'google-github-actions/auth@v1'
+ with:
+ credentials_json: '${{ secrets.GCP_SA_KEY }}'
+ - name: Set up gcloud SDK
+ uses: google-github-actions/setup-gcloud@v1
+ with:
+ project_id: ${{ secrets.GCP_PROJECT_ID }}
+ - name: Use gcloud CLI
+ run: gcloud info
+ - name: Run DynamoDB / Bigtable cleanup script
+ run: python infra/scripts/cleanup_ci.py
build-docker-image:
if: github.repository == 'feast-dev/feast'
needs: [check_date]
@@ -129,12 +140,12 @@ jobs:
--health-timeout 5s
--health-retries 5
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
ref: master
submodules: recursive
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
id: setup-python
with:
python-version: ${{ matrix.python-version }}
@@ -162,9 +173,6 @@ jobs:
aws-region: us-west-2
- name: Use AWS CLI
run: aws sts get-caller-identity
- - name: Upgrade pip version
- run: |
- pip install --upgrade pip
- name: Get pip cache dir
id: pip-cache
run: |
@@ -179,6 +187,9 @@ jobs:
key: ${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-${{ hashFiles(format('**/py{0}-ci-requirements.txt', env.PYTHON)) }}
restore-keys: |
${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-
+ - name: Upgrade pip version
+ run: |
+ pip install --upgrade "pip>=21.3.1,<23.2"
- name: Install pip-tools
run: pip install pip-tools
- name: Install apache-arrow on ubuntu
diff --git a/.github/workflows/pr_integration_tests.yml b/.github/workflows/pr_integration_tests.yml
index 1fd49f08aff..26c85b0126e 100644
--- a/.github/workflows/pr_integration_tests.yml
+++ b/.github/workflows/pr_integration_tests.yml
@@ -86,7 +86,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- python-version: [ "3.8" ]
+ python-version: [ "3.8", "3.10" ]
os: [ ubuntu-latest ]
env:
OS: ${{ matrix.os }}
@@ -102,7 +102,7 @@ jobs:
--health-timeout 5s
--health-retries 5
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# pull_request_target runs the workflow in the context of the base repo
# as such actions/checkout needs to be explicit configured to retrieve
@@ -110,7 +110,7 @@ jobs:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
submodules: recursive
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
id: setup-python
with:
python-version: ${{ matrix.python-version }}
@@ -133,9 +133,6 @@ jobs:
aws-region: us-west-2
- name: Use AWS CLI
run: aws sts get-caller-identity
- - name: Upgrade pip version
- run: |
- pip install --upgrade pip
- name: Get pip cache dir
id: pip-cache
run: |
@@ -150,6 +147,9 @@ jobs:
key: ${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-${{ hashFiles(format('**/py{0}-ci-requirements.txt', env.PYTHON)) }}
restore-keys: |
${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-
+ - name: Upgrade pip version
+ run: |
+ pip install --upgrade "pip>=21.3.1,<23.2"
- name: Install pip-tools
run: pip install pip-tools
- name: Install dependencies
diff --git a/.github/workflows/pr_local_integration_tests.yml b/.github/workflows/pr_local_integration_tests.yml
index 41df3aefff2..aeb4100dc85 100644
--- a/.github/workflows/pr_local_integration_tests.yml
+++ b/.github/workflows/pr_local_integration_tests.yml
@@ -19,13 +19,13 @@ jobs:
strategy:
fail-fast: false
matrix:
- python-version: [ "3.8" ]
+ python-version: [ "3.8", "3.10" ]
os: [ ubuntu-latest ]
env:
OS: ${{ matrix.os }}
PYTHON: ${{ matrix.python-version }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# pull_request_target runs the workflow in the context of the base repo
# as such actions/checkout needs to be explicit configured to retrieve
@@ -33,14 +33,11 @@ jobs:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
submodules: recursive
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
id: setup-python
with:
python-version: ${{ matrix.python-version }}
architecture: x64
- - name: Upgrade pip version
- run: |
- pip install --upgrade pip
- name: Get pip cache dir
id: pip-cache
run: |
@@ -55,6 +52,9 @@ jobs:
key: ${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-${{ hashFiles(format('**/py{0}-ci-requirements.txt', env.PYTHON)) }}
restore-keys: |
${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-
+ - name: Upgrade pip version
+ run: |
+ pip install --upgrade "pip>=21.3.1,<23.2"
- name: Install pip-tools
run: pip install pip-tools
- name: Install dependencies
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 11f08bf2e52..135d1d3a8df 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -14,7 +14,7 @@ jobs:
version_without_prefix: ${{ steps.get_release_version_without_prefix.outputs.version_without_prefix }}
highest_semver_tag: ${{ steps.get_highest_semver.outputs.highest_semver_tag }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Get release version
id: get_release_version
run: echo ::set-output name=release_version::${GITHUB_REF#refs/*/}
@@ -54,7 +54,7 @@ jobs:
MAVEN_CACHE: gs://feast-templocation-kf-feast/.m2.2020-08-19.tar
REGISTRY: feastdev
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
@@ -105,7 +105,7 @@ jobs:
HELM_VERSION: v3.8.0
VERSION_WITHOUT_PREFIX: ${{ needs.get-version.outputs.version_without_prefix }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Authenticate to Google Cloud
uses: 'google-github-actions/auth@v1'
with:
@@ -149,7 +149,7 @@ jobs:
runs-on: ubuntu-latest
needs: get-version
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
submodules: 'true'
- name: Set up JDK 11
@@ -158,7 +158,7 @@ jobs:
java-version: '11'
java-package: jdk
architecture: x64
- - uses: actions/setup-python@v2
+ - uses: actions/setup-python@v3
with:
python-version: '3.7'
architecture: 'x64'
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index da16c5f8f1c..b0d3e3cb390 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -30,14 +30,13 @@ jobs:
next_version: ${{ steps.get_versions.outputs.next_version }}
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
persist-credentials: false
- name: Setup Node.js
- uses: actions/setup-node@v2
+ uses: actions/setup-node@v3
with:
- node-version: '18.x'
- registry-url: 'https://registry.npmjs.org'
+ node-version: "lts/*"
- name: Release (Dry Run)
id: get_versions
run: |
@@ -59,11 +58,11 @@ jobs:
CURRENT_VERSION: ${{ needs.get_dry_release_versions.outputs.current_version }}
NEXT_VERSION: ${{ needs.get_dry_release_versions.outputs.next_version }}
steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-node@v2
+ - uses: actions/checkout@v3
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
with:
- node-version: '18.x'
- registry-url: 'https://registry.npmjs.org'
+ node-version: "lts/*"
- name: Bump file versions
run: python ./infra/scripts/release/bump_file_versions.py ${CURRENT_VERSION} ${NEXT_VERSION}
- name: Install yarn dependencies
@@ -100,11 +99,11 @@ jobs:
CURRENT_VERSION: ${{ needs.get_dry_release_versions.outputs.current_version }}
NEXT_VERSION: ${{ needs.get_dry_release_versions.outputs.next_version }}
steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-node@v2
+ - uses: actions/checkout@v3
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
with:
- node-version: '18.x'
- registry-url: 'https://registry.npmjs.org'
+ node-version: "lts/*"
- name: Bump file versions (temporarily for Web UI publish)
run: python ./infra/scripts/release/bump_file_versions.py ${CURRENT_VERSION} ${NEXT_VERSION}
- name: Install yarn dependencies
@@ -133,14 +132,13 @@ jobs:
GIT_COMMITTER_EMAIL: feast-ci-bot@willem.co
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
persist-credentials: false
- name: Setup Node.js
- uses: actions/setup-node@v2
+ uses: actions/setup-node@v3
with:
- node-version: '18.x'
- registry-url: 'https://registry.npmjs.org'
+ node-version: "lts/*"
- name: Set up Homebrew
id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master
diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml
index 285ebbb87e9..31e6d08c743 100644
--- a/.github/workflows/unit_tests.yml
+++ b/.github/workflows/unit_tests.yml
@@ -12,16 +12,14 @@ jobs:
exclude:
- os: macOS-latest
python-version: "3.9"
- - os: macOS-latest
- python-version: "3.10"
env:
OS: ${{ matrix.os }}
PYTHON: ${{ matrix.python-version }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup Python
id: setup-python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
architecture: x64
@@ -36,9 +34,6 @@ jobs:
run: |
brew install zlib
ln -sv $(brew --prefix zlib)/lib/libz.dylib $(brew --prefix)/lib/libzlib.dylib
- - name: Upgrade pip version
- run: |
- pip install --upgrade pip
- name: Get pip cache dir
id: pip-cache
run: |
@@ -53,6 +48,9 @@ jobs:
key: ${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-${{ hashFiles(format('**/py{0}-ci-requirements.txt', env.PYTHON)) }}
restore-keys: |
${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-pip-
+ - name: Upgrade pip version
+ run: |
+ pip install --upgrade "pip>=21.3.1,<23.2"
- name: Install pip-tools
run: pip install pip-tools
- name: Install dependencies
@@ -66,8 +64,8 @@ jobs:
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-node@v2
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
with:
node-version: '17.x'
registry-url: 'https://registry.npmjs.org'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ad30d312ee4..26b8baa963e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,98 @@
# Changelog
+# [0.35.0](https://github.com/feast-dev/feast/compare/v0.34.0...v0.35.0) (2024-01-13)
+
+
+### Bug Fixes
+
+* Add async refresh to prevent synchronous refresh in main thread ([#3812](https://github.com/feast-dev/feast/issues/3812)) ([9583ed6](https://github.com/feast-dev/feast/commit/9583ed6b4ae8d3b97934bf0c80ecb236ed1e2895))
+* Adopt connection pooling for HBase ([#3793](https://github.com/feast-dev/feast/issues/3793)) ([b3852bf](https://github.com/feast-dev/feast/commit/b3852bfb8b27bf07736935f465da3067fcbac0ae))
+* Bytewax engine create configmap from object ([#3821](https://github.com/feast-dev/feast/issues/3821)) ([25e9775](https://github.com/feast-dev/feast/commit/25e97756adedfd1227d591ae74bdf60655f9067e))
+* Fix warnings from deprecated paths and update default log level ([#3757](https://github.com/feast-dev/feast/issues/3757)) ([68a8737](https://github.com/feast-dev/feast/commit/68a87379c42567f338d86cb2be90520cc6d4bfb6))
+* improve parsing bytewax job status ([5983f40](https://github.com/feast-dev/feast/commit/5983f40f8f5df5dbbcd2640f83ef82c19cdb4d19))
+* make bytewax settings unexposed ([ae1bb8b](https://github.com/feast-dev/feast/commit/ae1bb8bdd1b9e293809519971935c93c2214d791))
+* Make generated temp table name escaped ([#3797](https://github.com/feast-dev/feast/issues/3797)) ([175d796](https://github.com/feast-dev/feast/commit/175d7969b1f75ab797aff9c92a70d845297444ad))
+* Pin numpy version to avoid spammy deprecation messages ([774ed33](https://github.com/feast-dev/feast/commit/774ed33a067bf9bf087520325b72f4f4d194106a))
+* Redundant feature materialization and premature incremental materialization timestamp updates ([#3789](https://github.com/feast-dev/feast/issues/3789)) ([417b16b](https://github.com/feast-dev/feast/commit/417b16b57af7b38fbd0708b9a0c5d5035ed021fd)), closes [#6](https://github.com/feast-dev/feast/issues/6) [#7](https://github.com/feast-dev/feast/issues/7)
+* Resolve hbase hotspot issue when materializing ([#3790](https://github.com/feast-dev/feast/issues/3790)) ([7376db8](https://github.com/feast-dev/feast/commit/7376db8dbd1d3168a1262fbbc0ce3899be8d0c34))
+* Set keepalives_idle None by default ([#3756](https://github.com/feast-dev/feast/issues/3756)) ([8717e9b](https://github.com/feast-dev/feast/commit/8717e9bf0fd253454982b9c9e9527c4d41906e9c))
+* Set upper bound for bigquery client due to its breaking changes ([2151c39](https://github.com/feast-dev/feast/commit/2151c39d1a8d8eba114306411dd4bd91ac0ce3f6))
+* UI project cannot handle fallback routes ([#3766](https://github.com/feast-dev/feast/issues/3766)) ([96ece0f](https://github.com/feast-dev/feast/commit/96ece0fe94a07cc6f1dabf5d6c9b061b48b06d67))
+* update dependencies versions due to conflicts ([5dc0b24](https://github.com/feast-dev/feast/commit/5dc0b241ec68aa10fd783569bf0ae12c5752f20f))
+* Update jackson and remove unnecessary logging ([#3809](https://github.com/feast-dev/feast/issues/3809)) ([018d0ea](https://github.com/feast-dev/feast/commit/018d0eab69dde63266f2c56813045ea5c5523f76))
+* upgrade the pyarrow to latest v14.0.1 for CVE-2023-47248. ([052182b](https://github.com/feast-dev/feast/commit/052182bcca046e35456674fc7d524825882f4b35))
+
+
+### Features
+
+* Add get online feature rpc to gprc server ([#3815](https://github.com/feast-dev/feast/issues/3815)) ([01db8cc](https://github.com/feast-dev/feast/commit/01db8cce6f82d4c6e496041351fb6b56eb2645b0))
+* Add materialize and materialize-incremental rest endpoints ([#3761](https://github.com/feast-dev/feast/issues/3761)) ([fa600fe](https://github.com/feast-dev/feast/commit/fa600fe3c4b1d5fdd383a9367511ac5616ee7a32)), closes [#3760](https://github.com/feast-dev/feast/issues/3760)
+* add redis sentinel support ([3387a15](https://github.com/feast-dev/feast/commit/3387a15d2b7e8dea430a271570be5a19b32bd3fe))
+* add redis sentinel support ([4337c89](https://github.com/feast-dev/feast/commit/4337c89083a3cfca21ee1beef473fda13b0e9014))
+* add redis sentinel support format lint ([aad8718](https://github.com/feast-dev/feast/commit/aad8718d24d893b3ff8c5864c5b8d210cfcdb22f))
+* Add support for `table_create_disposition` in bigquery job for offline store ([#3762](https://github.com/feast-dev/feast/issues/3762)) ([6a728fe](https://github.com/feast-dev/feast/commit/6a728fe66db0286ea10301d1fe693d6dcba4e4f4))
+* Add support for in_cluster config and additional labels for bytewax materialization ([#3754](https://github.com/feast-dev/feast/issues/3754)) ([2192e65](https://github.com/feast-dev/feast/commit/2192e6527fa10f1580e4dd8f350e05e45af981b7))
+* Apply cache to load proto registry for performance ([#3702](https://github.com/feast-dev/feast/issues/3702)) ([709c709](https://github.com/feast-dev/feast/commit/709c7098dc28a35dd488f5079d3787cf1f74ec03))
+* Make bytewax job write as mini-batches ([#3777](https://github.com/feast-dev/feast/issues/3777)) ([9b0e5ce](https://github.com/feast-dev/feast/commit/9b0e5ce2d1b617fcdcf0699c8b0cf8549a5e5ac5))
+* Optimize bytewax pod resource with zero-copy ([9cf9d96](https://github.com/feast-dev/feast/commit/9cf9d965a5566a87bb7419f2e8509666076f035f))
+* Support GCS filesystem for bytewax engine ([#3774](https://github.com/feast-dev/feast/issues/3774)) ([fb6b807](https://github.com/feast-dev/feast/commit/fb6b807f8b32776d388757ca431d290c03170c66))
+
+# [0.34.0](https://github.com/feast-dev/feast/compare/v0.33.0...v0.34.0) (2023-09-07)
+
+
+### Bug Fixes
+
+* Add NUMERIC to bq_to_feast type map ([#3719](https://github.com/feast-dev/feast/issues/3719)) ([6474b4b](https://github.com/feast-dev/feast/commit/6474b4b0169dc9b3df8e8daecded2b1fad5ead58))
+* Fix python unit tests ([#3734](https://github.com/feast-dev/feast/issues/3734)) ([e81684d](https://github.com/feast-dev/feast/commit/e81684d4f7916c986fa8e6cf06c2918951469799))
+* Handle unknown postgres source types gracefully ([#3634](https://github.com/feast-dev/feast/issues/3634)) ([d7041f4](https://github.com/feast-dev/feast/commit/d7041f4cce813d349e9016da55d65a65c1ec2355))
+* Pin protobuf version to avoid seg fault on some machines ([028cc20](https://github.com/feast-dev/feast/commit/028cc20a28118bd31deca8965782d5ad25f74300))
+* Remove unwanted excessive splitting of gcs path, so expected gcs parquet paths are returned from BigQueryRetrievalJob.to_remote_storage() ([#3730](https://github.com/feast-dev/feast/issues/3730)) ([f2c5988](https://github.com/feast-dev/feast/commit/f2c59885e31f3f238dbd9c13cd1ba168e3233a9d))
+* Run store.plan() only when need it. ([#3708](https://github.com/feast-dev/feast/issues/3708)) ([7bc7c47](https://github.com/feast-dev/feast/commit/7bc7c47b4507310850474290131c03fb6d480834))
+* Saved datasets no longer break CLI registry-dump command ([#3717](https://github.com/feast-dev/feast/issues/3717)) ([f28ccc2](https://github.com/feast-dev/feast/commit/f28ccc2b8f42bcca943d498ad583337d4cd70383))
+* Update py3.8 ci requirements for cython 3.0 release ([#3735](https://github.com/feast-dev/feast/issues/3735)) ([1695c13](https://github.com/feast-dev/feast/commit/1695c13fa8f48fdc2b5e627837043c5eea0914a9))
+
+
+### Features
+
+* Enhance customization of Trino connections when using Trino-based Offline Stores ([#3699](https://github.com/feast-dev/feast/issues/3699)) ([ed7535e](https://github.com/feast-dev/feast/commit/ed7535e23d490249ca7d224fb88e53b98d496ec0))
+* Implement gRPC server to ingest streaming features ([#3687](https://github.com/feast-dev/feast/issues/3687)) ([a3fcd1f](https://github.com/feast-dev/feast/commit/a3fcd1f369bdf07174b5ecf2a49ca9864cf145d4))
+
+# [0.33.0](https://github.com/feast-dev/feast/compare/v0.32.0...v0.33.0) (2023-08-14)
+
+
+### Bug Fixes
+
+* Add aws-sts dependency in java sdk so that S3 client acquires IRSA role ([#3696](https://github.com/feast-dev/feast/issues/3696)) ([c75a01f](https://github.com/feast-dev/feast/commit/c75a01fce2d52cd18479ace748b8eb2e6c81c988))
+* Redshift push ignores schema ([#3671](https://github.com/feast-dev/feast/issues/3671)) ([76270f6](https://github.com/feast-dev/feast/commit/76270f66b3d98b0119b70927c06908f9834b6120))
+
+
+### Features
+
+* Add possibility to save dataset as table, when spark config has remote warehouse info ([#3645](https://github.com/feast-dev/feast/issues/3645)) ([22c109b](https://github.com/feast-dev/feast/commit/22c109bc088d093a7c81c59e11490a9a21f82309))
+
+# [0.32.0](https://github.com/feast-dev/feast/compare/v0.31.0...v0.32.0) (2023-07-17)
+
+
+### Bug Fixes
+
+* Added generic Feature store Creation for CLI ([#3618](https://github.com/feast-dev/feast/issues/3618)) ([bf740d2](https://github.com/feast-dev/feast/commit/bf740d2d0ef3b62cf27f25083b5b4d49955b56fb))
+* Broken non-root path with projects-list.json ([#3665](https://github.com/feast-dev/feast/issues/3665)) ([4861af0](https://github.com/feast-dev/feast/commit/4861af0f3206f965ad2f7a4eddf2ebec2df149f8))
+* Clean up snowflake to_spark_df() ([#3607](https://github.com/feast-dev/feast/issues/3607)) ([e8e643e](https://github.com/feast-dev/feast/commit/e8e643e3555127daf37fa4961fdadb0508a041db))
+* Entityless fv breaks with `KeyError: __dummy` applying feature_store.plan() on python ([#3640](https://github.com/feast-dev/feast/issues/3640)) ([ef4ef32](https://github.com/feast-dev/feast/commit/ef4ef32f7466b5d874d537abe8def4731b15dc85))
+* Fix scan datasize to 0 for inference schema ([#3628](https://github.com/feast-dev/feast/issues/3628)) ([c3dd74e](https://github.com/feast-dev/feast/commit/c3dd74e238b5b9e784e3dbe102941c66a63f6686))
+* Fix timestamp consistency in push api ([#3614](https://github.com/feast-dev/feast/issues/3614)) ([9b227d7](https://github.com/feast-dev/feast/commit/9b227d7d44f30d28d1faadc8015f25dc4a6f56b5))
+* For SQL registry, increase max data_source_name length to 255 ([#3630](https://github.com/feast-dev/feast/issues/3630)) ([478caec](https://github.com/feast-dev/feast/commit/478caecc8d61b6070ec03bc13688a83b8c5f5936))
+* Implements connection pool for postgres online store ([#3633](https://github.com/feast-dev/feast/issues/3633)) ([059509a](https://github.com/feast-dev/feast/commit/059509a492d180effb1786713738665e293838e7))
+* Manage redis pipe's context ([#3655](https://github.com/feast-dev/feast/issues/3655)) ([48e0971](https://github.com/feast-dev/feast/commit/48e097130e68241e751bd4be5af7427fffad47cf))
+* Missing Catalog argument in athena connector ([#3661](https://github.com/feast-dev/feast/issues/3661)) ([f6d3caf](https://github.com/feast-dev/feast/commit/f6d3caf8affc74aef7ac489d3e6816d45b30d820))
+* Optimize bytes processed when retrieving entity df schema to 0 ([#3680](https://github.com/feast-dev/feast/issues/3680)) ([1c01035](https://github.com/feast-dev/feast/commit/1c010357affd48616d39f1ad01b872fac946269d))
+
+
+### Features
+
+* Add gunicorn for serve with multiprocess ([#3636](https://github.com/feast-dev/feast/issues/3636)) ([4de7faf](https://github.com/feast-dev/feast/commit/4de7faf7b262d30a9f6795911d8fa97df775fa8d))
+* Use string as a substitute for unregistered types during schema inference ([#3646](https://github.com/feast-dev/feast/issues/3646)) ([c474ccd](https://github.com/feast-dev/feast/commit/c474ccdd23ca8161de5e2958f0a12826c020dc44))
+
# [0.31.0](https://github.com/feast-dev/feast/compare/v0.30.0...v0.31.0) (2023-04-21)
diff --git a/CODEOWNERS b/CODEOWNERS
index 259c13ea3f0..bb154a71481 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -2,16 +2,21 @@
# for more info about CODEOWNERS file
# Core Interfaces
-/sdk/python/feast/infra/offline_stores/offline_store.py @feast-dev/maintainers @chhabrakadabra @mavysavydav @sfc-gh-madkins
+/sdk/python/feast/infra/offline_stores/offline_store.py @feast-dev/maintainers @sfc-gh-madkins
/sdk/python/feast/infra/online_stores/online_store.py @feast-dev/maintainers @DvirDukhan
/sdk/python/feast/infra/materialization_engine/batch_materialization_engine.py @feast-dev/maintainers @whoahbot @sfc-gh-madkins
# ==== Offline Stores ====
# Core utils
-/sdk/python/feast/infra/offline_stores/offline_utils.py @feast-dev/maintainers @chhabrakadabra @mavysavydav @sfc-gh-madkins
+/sdk/python/feast/infra/offline_stores/offline_utils.py @feast-dev/maintainers @sfc-gh-madkins
+
+# Offline interfaces
+/sdk/python/feast/infra/offline_stores/offline_store.py @feast-dev/maintainers
# BigQuery
-/sdk/python/feast/infra/offline_stores/offline_store.py @feast-dev/maintainers @chhabrakadabra @mavysavydav
+/sdk/python/feast/infra/offline_stores/bigquery.py @sudohainguyen
+/sdk/python/feast/infra/offline_stores/bigquery_source.py @sudohainguyen
+/sdk/python/tests/integration/feature_repos/universal/data_sources/bigquery.py @sudohainguyen
# Snowflake
/sdk/python/feast/infra/offline_stores/snowflake* @sfc-gh-madkins
@@ -27,6 +32,10 @@
# ==== Online Stores ====
+# HBase
+/sdk/python/feast/infra/online_stores/hbase.py @sudohainguyen
+/sdk/python/feast/infra/online_stores/contrib/hbase_online_store @sudohainguyen
+
# Redis
/sdk/python/feast/infra/online_stores/redis.py @DvirDukhan
/java/feast/serving/connectors/redis/ @DvirDukhan
@@ -47,8 +56,3 @@
# AWS Lambda
/sdk/python/feast/infra/materialization/contrib/aws_lambda/ @achals
-
-# ==== Web UI ====
-/ui/ @adchia
-/sdk/python/feast/ui/ @adchia
-/sdk/python/feast/ui_server.py @adchia
diff --git a/Makefile b/Makefile
index a104bf9ca5a..e8ddd397027 100644
--- a/Makefile
+++ b/Makefile
@@ -186,6 +186,28 @@ test-python-universal-athena:
not test_snowflake" \
sdk/python/tests
+test-python-universal-duckdb:
+ PYTHONPATH='.' \
+ FULL_REPO_CONFIGS_MODULE=sdk.python.feast.infra.offline_stores.contrib.duckdb_repo_configuration \
+ PYTEST_PLUGINS=feast.infra.offline_stores.contrib.duckdb_offline_store.tests \
+ FEAST_USAGE=False IS_TEST=True \
+ python -m pytest -n 8 --integration \
+ -k "not test_historical_features_persisting and \
+ not test_historical_retrieval_fails_on_validation and \
+ not test_historical_retrieval_with_validation and \
+ not test_feature_logging and \
+ not test_logged_features_validation and \
+ not test_lambda_materialization_consistency and \
+ not test_offline_write and \
+ not test_push_features_to_offline_store.py and \
+ not test_nullable_online_store and \
+ not gcs_registry and \
+ not s3_registry and \
+ not test_snowflake and \
+ not bigquery and \
+ not test_spark_materialization_consistency" \
+ sdk/python/tests
+
test-python-universal-postgres-offline:
PYTHONPATH='.' \
FULL_REPO_CONFIGS_MODULE=sdk.python.feast.infra.offline_stores.contrib.postgres_repo_configuration \
@@ -310,7 +332,7 @@ format-python:
cd ${ROOT_DIR}/sdk/python; python -m black --target-version py38 feast tests
lint-python:
- cd ${ROOT_DIR}/sdk/python; python -m mypy
+ cd ${ROOT_DIR}/sdk/python; python -m mypy feast
cd ${ROOT_DIR}/sdk/python; python -m isort feast/ tests/ --check-only
cd ${ROOT_DIR}/sdk/python; python -m flake8 feast/ tests/
cd ${ROOT_DIR}/sdk/python; python -m black --check feast tests
@@ -353,7 +375,7 @@ kill-trino-locally:
cd ${ROOT_DIR}; docker stop trino
install-protoc-dependencies:
- pip install --ignore-installed protobuf grpcio-tools==1.47.0 mypy-protobuf==3.1.0
+ pip install --ignore-installed protobuf==4.23.4 "grpcio-tools>=1.56.2,<2" mypy-protobuf==3.1.0
install-feast-ci-locally:
pip install -e ".[ci]"
diff --git a/README.md b/README.md
index 1152aa060e4..6a851d0d417 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ Feast allows ML platform teams to:
* **Avoid data leakage** by generating point-in-time correct feature sets so data scientists can focus on feature engineering rather than debugging error-prone dataset joining logic. This ensure that future feature values do not leak to models during training.
* **Decouple ML from data infrastructure** by providing a single data access layer that abstracts feature storage from feature retrieval, ensuring models remain portable as you move from training models to serving models, from batch models to realtime models, and from one data infra system to another.
-Please see our [documentation](https://docs.feast.dev/) for more information about the project, or sign up for an [email newsletter](https://feast.dev/).
+Please see our [documentation](https://docs.feast.dev/) for more information about the project.
## 📐 Architecture

@@ -145,7 +145,6 @@ pprint(feature_vector)
The list below contains the functionality that contributors are planning to develop for Feast.
* We welcome contribution to all items in the roadmap!
-* Have questions about the roadmap? Go to the Slack channel to ask on #feast-development.
* **Data Sources**
* [x] [Snowflake source](https://docs.feast.dev/reference/data-sources/snowflake)
@@ -175,6 +174,7 @@ The list below contains the functionality that contributors are planning to deve
* [x] [Datastore](https://docs.feast.dev/reference/online-stores/datastore)
* [x] [Bigtable](https://docs.feast.dev/reference/online-stores/bigtable)
* [x] [SQLite](https://docs.feast.dev/reference/online-stores/sqlite)
+ * [x] [Dragonfly](https://docs.feast.dev/reference/online-stores/dragonfly)
* [x] [Azure Cache for Redis (community plugin)](https://github.com/Azure/feast-azure)
* [x] [Postgres (contrib plugin)](https://docs.feast.dev/reference/online-stores/postgres)
* [x] [Cassandra / AstraDB (contrib plugin)](https://docs.feast.dev/reference/online-stores/cassandra)
@@ -213,7 +213,6 @@ Please refer to the official documentation at [Documentation](https://docs.feast
* [Tutorials](https://docs.feast.dev/tutorials/tutorials-overview)
* [Running Feast with Snowflake/GCP/AWS](https://docs.feast.dev/how-to-guides/feast-snowflake-gcp-aws)
* [Change Log](https://github.com/feast-dev/feast/blob/master/CHANGELOG.md)
- * [Slack (#Feast)](https://slack.feast.dev/)
## 👋 Contributing
Feast is a community project and is still under active development. Please have a look at our contributing and development guides if you want to contribute to the project:
diff --git a/community/governance.excalidraw b/community/governance.excalidraw
deleted file mode 100644
index f4c8dad9a4f..00000000000
--- a/community/governance.excalidraw
+++ /dev/null
@@ -1,913 +0,0 @@
-{
- "type": "excalidraw",
- "version": 2,
- "source": "https://excalidraw.com",
- "elements": [
- {
- "type": "rectangle",
- "version": 620,
- "versionNonce": 853777363,
- "isDeleted": false,
- "id": "pr0yIJcUDXb4nFgowH9_r",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "dashed",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 409.5,
- "y": 620.5,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "width": 194,
- "height": 83,
- "seed": 1695250557,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "boundElements": [
- {
- "id": "YfmPferxgVKoP70zGfYDK",
- "type": "text"
- },
- {
- "id": "YfmPferxgVKoP70zGfYDK",
- "type": "text"
- },
- {
- "type": "text",
- "id": "YfmPferxgVKoP70zGfYDK"
- },
- {
- "id": "IsihlXUGDSklv2RsxX6wO",
- "type": "arrow"
- },
- {
- "id": "G5s2AUFJ730fyPsIbA8xP",
- "type": "arrow"
- },
- {
- "id": "j9ZVC3ZgHTsAGe3hJQecp",
- "type": "arrow"
- }
- ],
- "updated": 1662582134601,
- "link": null,
- "locked": false
- },
- {
- "type": "text",
- "version": 623,
- "versionNonce": 328400605,
- "isDeleted": false,
- "id": "YfmPferxgVKoP70zGfYDK",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 414.5,
- "y": 649.5,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "width": 184,
- "height": 25,
- "seed": 1575229907,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "boundElements": [],
- "updated": 1662582134601,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 1,
- "text": "CODEOWNERS",
- "baseline": 18,
- "textAlign": "center",
- "verticalAlign": "middle",
- "containerId": "pr0yIJcUDXb4nFgowH9_r",
- "originalText": "CODEOWNERS"
- },
- {
- "type": "rectangle",
- "version": 756,
- "versionNonce": 1648798067,
- "isDeleted": false,
- "id": "XDy4VWWtJ9sd6hzPJDdFe",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 409.5,
- "y": 779.5,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "width": 194,
- "height": 83,
- "seed": 1925179667,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "boundElements": [
- {
- "id": "gUz4p_oPytb5-ejbYb81N",
- "type": "text"
- },
- {
- "id": "gUz4p_oPytb5-ejbYb81N",
- "type": "text"
- },
- {
- "id": "gUz4p_oPytb5-ejbYb81N",
- "type": "text"
- },
- {
- "type": "text",
- "id": "gUz4p_oPytb5-ejbYb81N"
- },
- {
- "id": "G5s2AUFJ730fyPsIbA8xP",
- "type": "arrow"
- }
- ],
- "updated": 1662582134601,
- "link": null,
- "locked": false
- },
- {
- "type": "text",
- "version": 781,
- "versionNonce": 1240013629,
- "isDeleted": false,
- "id": "gUz4p_oPytb5-ejbYb81N",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 414.5,
- "y": 808.5,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "width": 184,
- "height": 25,
- "seed": 140322205,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "boundElements": [],
- "updated": 1662582134601,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 1,
- "text": "Contributors",
- "baseline": 18,
- "textAlign": "center",
- "verticalAlign": "middle",
- "containerId": "XDy4VWWtJ9sd6hzPJDdFe",
- "originalText": "Contributors"
- },
- {
- "type": "text",
- "version": 463,
- "versionNonce": 2109720179,
- "isDeleted": false,
- "id": "AYJKq2RGJrSIpbfiJOf_4",
- "fillStyle": "hachure",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 526,
- "y": 517.5,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "width": 274,
- "height": 75,
- "seed": 1616513981,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "boundElements": [],
- "updated": 1662582134602,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 1,
- "text": "1. organize contributors\n2. influence roadmap\n3. own direction of an area",
- "baseline": 68,
- "textAlign": "left",
- "verticalAlign": "top",
- "containerId": null,
- "originalText": "1. organize contributors\n2. influence roadmap\n3. own direction of an area"
- },
- {
- "type": "rectangle",
- "version": 776,
- "versionNonce": 519656573,
- "isDeleted": false,
- "id": "z5LT5d710gSTA9DjwiL3O",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 70,
- "angle": 0,
- "x": 1013.7117834394903,
- "y": 187.5000000000001,
- "strokeColor": "#000000",
- "backgroundColor": "#4c6ef5",
- "width": 132,
- "height": 682,
- "seed": 1424710877,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "boundElements": [
- {
- "id": "RscqyQXicYOkFsE_zvran",
- "type": "text"
- },
- {
- "id": "J7IG4T5j15pB3b_K0Cpd9",
- "type": "arrow"
- },
- {
- "id": "XEohLLmfFl0L9Wi2ew5AU",
- "type": "arrow"
- },
- {
- "id": "o3Pp-94PORhEiEauRcZW_",
- "type": "arrow"
- },
- {
- "type": "text",
- "id": "RscqyQXicYOkFsE_zvran"
- },
- {
- "id": "j9ZVC3ZgHTsAGe3hJQecp",
- "type": "arrow"
- },
- {
- "id": "Klq-VJGZiolZnGuaNJ8k9",
- "type": "arrow"
- }
- ],
- "updated": 1662582138112,
- "link": null,
- "locked": false
- },
- {
- "type": "text",
- "version": 896,
- "versionNonce": 1733426643,
- "isDeleted": false,
- "id": "RscqyQXicYOkFsE_zvran",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 1018.7117834394903,
- "y": 476.0000000000001,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "width": 122,
- "height": 105,
- "seed": 1202400115,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "boundElements": [],
- "updated": 1662582138113,
- "link": null,
- "locked": false,
- "fontSize": 28,
- "fontFamily": 1,
- "text": "Feast \nGitHub \nproject",
- "baseline": 95,
- "textAlign": "center",
- "verticalAlign": "middle",
- "containerId": "z5LT5d710gSTA9DjwiL3O",
- "originalText": "Feast GitHub project"
- },
- {
- "id": "IsihlXUGDSklv2RsxX6wO",
- "type": "arrow",
- "x": 506.997671158975,
- "y": 619,
- "width": 0,
- "height": 132,
- "angle": 0,
- "strokeColor": "#000000",
- "backgroundColor": "#868e96",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "seed": 345290749,
- "version": 680,
- "versionNonce": 787007421,
- "isDeleted": false,
- "boundElements": null,
- "updated": 1662582134602,
- "link": null,
- "locked": false,
- "points": [
- [
- 0,
- 0
- ],
- [
- 0,
- -132
- ]
- ],
- "lastCommittedPoint": null,
- "startBinding": {
- "elementId": "pr0yIJcUDXb4nFgowH9_r",
- "focus": 0.005130630504896713,
- "gap": 1.5
- },
- "endBinding": {
- "elementId": "TBYpmrW2OsKEqbpZfEeJg",
- "focus": 0.461338833375829,
- "gap": 1
- },
- "startArrowhead": null,
- "endArrowhead": "arrow"
- },
- {
- "id": "G5s2AUFJ730fyPsIbA8xP",
- "type": "arrow",
- "x": 506.9985864097345,
- "y": 776,
- "width": 0.9914493467237548,
- "height": 71,
- "angle": 0,
- "strokeColor": "#000000",
- "backgroundColor": "#868e96",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "seed": 241364467,
- "version": 241,
- "versionNonce": 649485971,
- "isDeleted": false,
- "boundElements": null,
- "updated": 1662582134602,
- "link": null,
- "locked": false,
- "points": [
- [
- 0,
- 0
- ],
- [
- -0.9914493467237548,
- -71
- ]
- ],
- "lastCommittedPoint": null,
- "startBinding": {
- "elementId": "XDy4VWWtJ9sd6hzPJDdFe",
- "focus": 0.011569796958606356,
- "gap": 3.5
- },
- "endBinding": {
- "elementId": "pr0yIJcUDXb4nFgowH9_r",
- "focus": 0.011204382815075232,
- "gap": 1.5
- },
- "startArrowhead": null,
- "endArrowhead": "arrow"
- },
- {
- "id": "TBYpmrW2OsKEqbpZfEeJg",
- "type": "rectangle",
- "x": 409.5,
- "y": 188,
- "width": 361.99999999999994,
- "height": 298,
- "angle": 0,
- "strokeColor": "#000000",
- "backgroundColor": "#868e96",
- "fillStyle": "solid",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 30,
- "groupIds": [
- "mcHoJ-dlfU3T8l_C93UPa"
- ],
- "strokeSharpness": "sharp",
- "seed": 1515491581,
- "version": 231,
- "versionNonce": 593345661,
- "isDeleted": false,
- "boundElements": [
- {
- "id": "IsihlXUGDSklv2RsxX6wO",
- "type": "arrow"
- },
- {
- "id": "Klq-VJGZiolZnGuaNJ8k9",
- "type": "arrow"
- }
- ],
- "updated": 1662582134602,
- "link": null,
- "locked": false
- },
- {
- "id": "YEEHpa4RXaR8G9YW55v25",
- "type": "rectangle",
- "x": 428.5,
- "y": 398,
- "width": 163.61445783132532,
- "height": 70.00000000000001,
- "angle": 0,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "groupIds": [
- "mcHoJ-dlfU3T8l_C93UPa"
- ],
- "strokeSharpness": "sharp",
- "seed": 932648787,
- "version": 319,
- "versionNonce": 398988755,
- "isDeleted": false,
- "boundElements": [
- {
- "type": "text",
- "id": "8iyUZwSph5yMVrXehf6vg"
- },
- {
- "id": "o3Pp-94PORhEiEauRcZW_",
- "type": "arrow"
- },
- {
- "id": "IsihlXUGDSklv2RsxX6wO",
- "type": "arrow"
- }
- ],
- "updated": 1662582134602,
- "link": null,
- "locked": false
- },
- {
- "id": "8iyUZwSph5yMVrXehf6vg",
- "type": "text",
- "x": 433.5,
- "y": 422.5,
- "width": 153.61445783132532,
- "height": 21,
- "angle": 0,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "groupIds": [
- "mcHoJ-dlfU3T8l_C93UPa"
- ],
- "strokeSharpness": "sharp",
- "seed": 1803538003,
- "version": 365,
- "versionNonce": 952837341,
- "isDeleted": false,
- "boundElements": null,
- "updated": 1662582134602,
- "link": null,
- "locked": false,
- "text": "Area maintainers",
- "fontSize": 16.697223677317968,
- "fontFamily": 1,
- "textAlign": "center",
- "verticalAlign": "middle",
- "baseline": 15,
- "containerId": "YEEHpa4RXaR8G9YW55v25",
- "originalText": "Area maintainers"
- },
- {
- "type": "rectangle",
- "version": 355,
- "versionNonce": 1753998195,
- "isDeleted": false,
- "id": "Wh-PpzmGy1bWJko0akD-a",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 429.8072289156627,
- "y": 257.1185567010309,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "width": 161,
- "height": 68.88144329896907,
- "seed": 1844448573,
- "groupIds": [
- "mcHoJ-dlfU3T8l_C93UPa"
- ],
- "strokeSharpness": "sharp",
- "boundElements": [
- {
- "id": "OJCS1hAx71BD6u1jesJzR",
- "type": "text"
- },
- {
- "type": "text",
- "id": "OJCS1hAx71BD6u1jesJzR"
- },
- {
- "id": "o3Pp-94PORhEiEauRcZW_",
- "type": "arrow"
- }
- ],
- "updated": 1662582134602,
- "link": null,
- "locked": false
- },
- {
- "type": "text",
- "version": 409,
- "versionNonce": 556564797,
- "isDeleted": false,
- "id": "OJCS1hAx71BD6u1jesJzR",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 434.8072289156627,
- "y": 271.55927835051546,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "width": 151,
- "height": 40,
- "seed": 852504851,
- "groupIds": [
- "mcHoJ-dlfU3T8l_C93UPa"
- ],
- "strokeSharpness": "sharp",
- "boundElements": [],
- "updated": 1662582134602,
- "link": null,
- "locked": false,
- "fontSize": 16.413043478260864,
- "fontFamily": 1,
- "text": "Project \nmaintainers",
- "baseline": 34,
- "textAlign": "center",
- "verticalAlign": "middle",
- "containerId": "Wh-PpzmGy1bWJko0akD-a",
- "originalText": "Project maintainers"
- },
- {
- "id": "o3Pp-94PORhEiEauRcZW_",
- "type": "arrow",
- "x": 510.1952932956257,
- "y": 396.60017389144207,
- "width": 0.34508644012566947,
- "height": 69.20034778288408,
- "angle": 0,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "fillStyle": "hachure",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "groupIds": [
- "mcHoJ-dlfU3T8l_C93UPa"
- ],
- "strokeSharpness": "sharp",
- "seed": 1889236627,
- "version": 572,
- "versionNonce": 918879507,
- "isDeleted": false,
- "boundElements": null,
- "updated": 1662582134602,
- "link": null,
- "locked": false,
- "points": [
- [
- 0,
- 0
- ],
- [
- 0.34508644012566947,
- -69.20034778288408
- ]
- ],
- "lastCommittedPoint": null,
- "startBinding": {
- "elementId": "YEEHpa4RXaR8G9YW55v25",
- "focus": -0.0035794947090358044,
- "gap": 1.3998261085579315
- },
- "endBinding": {
- "elementId": "Wh-PpzmGy1bWJko0akD-a",
- "focus": -0.0051056226396315905,
- "gap": 1.3998261085579884
- },
- "startArrowhead": null,
- "endArrowhead": "arrow"
- },
- {
- "id": "4CHi-UfB3oI1PAfcFm2o_",
- "type": "text",
- "x": 528.5,
- "y": 354.5,
- "width": 218,
- "height": 20,
- "angle": 0,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "fillStyle": "hachure",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "groupIds": [
- "mcHoJ-dlfU3T8l_C93UPa"
- ],
- "strokeSharpness": "sharp",
- "seed": 2054408115,
- "version": 238,
- "versionNonce": 1105416605,
- "isDeleted": false,
- "boundElements": null,
- "updated": 1662582134602,
- "link": null,
- "locked": false,
- "text": "break ties by majority vote",
- "fontSize": 16,
- "fontFamily": 1,
- "textAlign": "left",
- "verticalAlign": "top",
- "baseline": 14,
- "containerId": null,
- "originalText": "break ties by majority vote"
- },
- {
- "id": "gHvMhIQl4S1SxPE8kzHLx",
- "type": "text",
- "x": 431.8072289156627,
- "y": 201.5,
- "width": 157,
- "height": 35,
- "angle": 0,
- "strokeColor": "#000000",
- "backgroundColor": "#868e96",
- "fillStyle": "solid",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "groupIds": [
- "mcHoJ-dlfU3T8l_C93UPa"
- ],
- "strokeSharpness": "sharp",
- "seed": 1597289651,
- "version": 154,
- "versionNonce": 1038738099,
- "isDeleted": false,
- "boundElements": null,
- "updated": 1662582134602,
- "link": null,
- "locked": false,
- "text": "Maintainers",
- "fontSize": 28,
- "fontFamily": 1,
- "textAlign": "left",
- "verticalAlign": "top",
- "baseline": 25,
- "containerId": null,
- "originalText": "Maintainers"
- },
- {
- "type": "text",
- "version": 545,
- "versionNonce": 1478563325,
- "isDeleted": false,
- "id": "_qJ5MtLgnvmF1-EDKX6qg",
- "fillStyle": "hachure",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 533,
- "y": 732.5,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "width": 106,
- "height": 25,
- "seed": 1870614973,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "boundElements": [],
- "updated": 1662582134602,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 1,
- "text": "review PRs",
- "baseline": 18,
- "textAlign": "left",
- "verticalAlign": "top",
- "containerId": null,
- "originalText": "review PRs"
- },
- {
- "id": "j9ZVC3ZgHTsAGe3hJQecp",
- "type": "arrow",
- "x": 610.590909090909,
- "y": 673.6931323855418,
- "width": 394.7818338530517,
- "height": 1.1368683772161603e-13,
- "angle": 0,
- "strokeColor": "#000000",
- "backgroundColor": "#868e96",
- "fillStyle": "solid",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "seed": 1115132605,
- "version": 594,
- "versionNonce": 1612334739,
- "isDeleted": false,
- "boundElements": null,
- "updated": 1662582138112,
- "link": null,
- "locked": false,
- "points": [
- [
- 0,
- 0
- ],
- [
- 394.7818338530517,
- 1.1368683772161603e-13
- ]
- ],
- "lastCommittedPoint": null,
- "startBinding": {
- "elementId": "pr0yIJcUDXb4nFgowH9_r",
- "gap": 7.0909090909090455,
- "focus": 0.2817622261576348
- },
- "endBinding": {
- "elementId": "z5LT5d710gSTA9DjwiL3O",
- "gap": 9.339040495529549,
- "focus": -0.4257863119810608
- },
- "startArrowhead": null,
- "endArrowhead": "arrow"
- },
- {
- "id": "Klq-VJGZiolZnGuaNJ8k9",
- "type": "arrow",
- "x": 775.7385321100917,
- "y": 334,
- "width": 233.2672383568049,
- "height": 0,
- "angle": 0,
- "strokeColor": "#000000",
- "backgroundColor": "#868e96",
- "fillStyle": "solid",
- "strokeWidth": 1,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "seed": 632787667,
- "version": 198,
- "versionNonce": 1893334067,
- "isDeleted": false,
- "boundElements": null,
- "updated": 1662582138112,
- "link": null,
- "locked": false,
- "points": [
- [
- 0,
- 0
- ],
- [
- 233.2672383568049,
- 0
- ]
- ],
- "lastCommittedPoint": null,
- "startBinding": {
- "elementId": "TBYpmrW2OsKEqbpZfEeJg",
- "gap": 4.238532110091741,
- "focus": -0.020134228187919462
- },
- "endBinding": {
- "elementId": "z5LT5d710gSTA9DjwiL3O",
- "gap": 5.7060129725937765,
- "focus": 0.5703812316715546
- },
- "startArrowhead": null,
- "endArrowhead": "arrow"
- },
- {
- "type": "text",
- "version": 651,
- "versionNonce": 1375877757,
- "isDeleted": false,
- "id": "diazwl57WWW_7gfm7wMea",
- "fillStyle": "hachure",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 678,
- "y": 637.5,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "width": 262,
- "height": 25,
- "seed": 2077675699,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "boundElements": [],
- "updated": 1662582152851,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 1,
- "text": "merge PRs if no objections",
- "baseline": 18,
- "textAlign": "left",
- "verticalAlign": "top",
- "containerId": null,
- "originalText": "merge PRs if no objections"
- },
- {
- "type": "text",
- "version": 658,
- "versionNonce": 1558756051,
- "isDeleted": false,
- "id": "_T1wMHFNqfA6a8Ku2OLDl",
- "fillStyle": "hachure",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 840,
- "y": 296.5,
- "strokeColor": "#000000",
- "backgroundColor": "transparent",
- "width": 102,
- "height": 25,
- "seed": 1987233139,
- "groupIds": [],
- "strokeSharpness": "sharp",
- "boundElements": [],
- "updated": 1662582148465,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 1,
- "text": "merge PRs",
- "baseline": 18,
- "textAlign": "left",
- "verticalAlign": "top",
- "containerId": null,
- "originalText": "merge PRs"
- }
- ],
- "appState": {
- "gridSize": null,
- "viewBackgroundColor": "#ffffff"
- },
- "files": {}
-}
\ No newline at end of file
diff --git a/community/governance.md b/community/governance.md
index 89cf800bc88..087b3599dbf 100644
--- a/community/governance.md
+++ b/community/governance.md
@@ -42,11 +42,7 @@ A formal governance structure helps us to
On a high level, the key moving parts of the community are:
- **GitHub activity** (issues + pull requests)
-- **Slack community** ([slack.feast.dev](slack.feast.dev))
- - `#feast-development` is where design discussions happen amongst contributors
- - Other Slack channels exist for users to ask and answer questions.
- **RFCs** ([drive folder](https://drive.google.com/drive/u/0/folders/1msUsgmDbVBaysmhBlg9lklYLLTMk4bC3)) for detailed discussions
-- **Community calls** (biweekly) to discuss best practices, contributions, and announce changes
- **Maintainer syncs** (monthly) for [maintainers](maintainers.md) to discuss project direction and health
With this structure, users and contributors largely self-organize and contribute changes as per [lazy consensus](#lazy-consensus). If there is active opposition and unresolvable conflict, then maintainers step in to break ties or make decisions.
@@ -61,10 +57,6 @@ Anyone interested in the project can join the community to:
- contribute to the project design
- participate in the decision-making process.
-The general decision making workflow is as follows:
-
-
-
> **Note**: There may not always a corresponding CODEOWNER for the affected code, in which case the responsibility falls on other maintainers or contributors with write access to review + merge the PR
# Roles And Responsibilities
@@ -96,7 +88,7 @@ In addition to their actions as users, contributors may also find themselves doi
* Writing, editing, translating or reviewing the documentation
* Organizing events or evangelizing the project
-Contributors engage with the project through the issue tracker and slack community, or by writing or editing documentation. They submit changes to the project itself via Pull Requests (PRs), which will be considered for inclusion in the project by existing maintainers (see next section).
+Contributors engage with the project through the issue tracker or by writing or editing documentation. They submit changes to the project itself via Pull Requests (PRs), which will be considered for inclusion in the project by existing maintainers (see next section).
Contributors should follow the following guides when creating PRs:
- [Contribution Process](https://docs.feast.dev/project/contributing)
@@ -116,27 +108,14 @@ Maintainers are community members who have shown that they are committed to Feas
> **Note**: maintainers, like other contributors, must make changes to Feast via pull requests (with code review). This applies to all changes to documentation, code, configuration, governance, etc.
-### Types of maintainers
-
-There are two kinds of maintainers
-
-1. **Project maintainers** control overall project organization and resolving disputes. They also
- - Attend a regular maintainers sync
- - Participate in strategic planning, approve changes to the governance model, and manage the copyrights within the project outputs.
- - (optional) Attend community calls
- - (optional) Planning project roadmaps and articulating vision
- - (optional) Guide design decisions to reinforce key project values (e.g. simplicity)
-2. **Area maintainers** own a specific technical area (which may span code modules), often specifically targeting a user journey or tech stack. They
- - are generally point people in GitHub or Slack on discussions in that area (e.g. tagged in `#feast-development`)
- - (optional) help drive roadmap decisions
-
-> **Note:** project maintainers may also be area maintainers, but this does not give their ideas increased weight over other area maintainers.
-
-Decisions that need tie breakers may require intervention via project maintainers majority consensus.
+Maintainers control overall project organization and resolving disputes. They also
+- Attend a regular maintainers sync
+- Participate in strategic planning, approve changes to the governance model, and manage the copyrights within the project outputs.
+- (optional) Planning project roadmaps and articulating vision
+- (optional) Guide design decisions to reinforce key project values (e.g. simplicity)
### Optional maintainer responsibilities
Other optional activites a maintainer (project or area maintainer) may participate in:
- * Monitor email aliases and our Slack (#feast-general, #feast-development, #feast-beginners).
* Perform code reviews for other maintainers and the community. The areas of specialization listed in [OWNERS.md](OWNERS.md) can be used to help with routing an issue/question to the right person.
* Triage GitHub issues, applying [labels]([https://github.com/feast-dev/feast/labels](https://github.com/feast-dev/feast/labels)) to each new item. Labels are extremely useful for future issue follow ups. Adding labels is somewhat subjective, so please use your best judgment.
* Triage build issues, filing issues for known flaky builds or bugs, fixing or finding someone to fix any master build breakages.
diff --git a/community/governance.png b/community/governance.png
deleted file mode 100644
index c2b00930e3a..00000000000
Binary files a/community/governance.png and /dev/null differ
diff --git a/community/maintainers.md b/community/maintainers.md
index cdf78b150cd..0b3d4ab6480 100644
--- a/community/maintainers.md
+++ b/community/maintainers.md
@@ -7,36 +7,30 @@ See [Governance](governance.md) for what each maintainer type is
In alphabetical order
| Name | GitHub Username | Email | Organization |
-| -------------- | ---------------- | --------------------------- | ------------------ |
-| Abhin Chhabra | `chhabrakadabra` | chhabra.abhin@gmail.com | Shopify |
+| -------------- | ---------------- |-----------------------------| ------------------ |
| Achal Shah | `achals` | achals@gmail.com | Tecton |
-| Danny Chiao | `adchia` | d.chiao@gmail.com | Tecton |
-| David Liu | `mavysavydav` | davidyliuliu@gmail.com | Twitter |
-| Felix Wang | `felixwang9817` | wangfelix98@gmail.com | Tecton |
-| Kevin Zhang | `kevjumba` | kevin.zhang.13499@gmail.com | Tecton |
-| Matt Delacour | `MattDelac` | mdelacour@hey.com | (formerly) Shopify |
-| Miles Adkins | `sfc-gh-madkins` | miles.adkins@snowflake.com | Snowflake |
-| Willem Pienaar | `woop` | will.pienaar@gmail.com | Tecton |
+| Edson Tirelli | `etirelli` | ed.tirelli@gmail.com | Red Hat |
+| Francisco Javier Arceo | `franciscojavierarceo` | arceofrancisco@gmail.com | Affirm |
+| Hao Xu | `HaoXuAI` | sduxuhao@gmail.com | JPMorgan |
+| Jeremy Ary | `jeremyary` | jeremy.ary@gmail.com | Red Hat |
+| Shuchu Han | `shuchu` | shuchu.han@gmail.com | Independent |
+| Willem Pienaar | `woop` | will.pienaar@gmail.com | Cleric |
| Zhiling Chen | `zhilingc` | chnzhlng@gmail.com | GetGround |
-## Area maintainers
-
-Generally, with contribution questions here, default to `#feast-development` in the [slack.feast.dev](slack.feast.dev) Slack channel, but these may be folks for you to tag in messages
-
-| Area | Description | Name |
-| -------------------- | -------------------------------------------------------------------------- | --------------------------------------------- |
-| Data ingestion | ingesting batch + stream data into the online store (materialization) | Achal Shah,
Felix Wang,
Kevin Zhang |
-| Developer experience | tooling, testing, documentation, tutorials | Achal Shah |
-| Feature serving | optimization, caching, deployment patterns, batch retrieval, range queries | Dvir Dukhan |
-| Ops | general deployment concerns, CI/CD, versioning | Keith Adler,
Danny Chiao,
Felix Wang |
-| Web UI | i.e. `feast ui` output | Danny Chiao,
David Liu |
-
## Emeritus Maintainers
-| Name | GitHub Username | Email | Organization |
-| ------------------- | --------------- | --------------------------- | ------------ |
-| Oleg Avdeev | oavdeev | oleg.v.avdeev@gmail.com | Tecton |
-| Oleksii Moskalenko | pyalex | moskalenko.alexey@gmail.com | Tecton |
-| Jay Parthasarthy | jparthasarthy | jparthasarthy@gmail.com | Tecton |
-| Pradithya Aria Pura | pradithya | pradithya.aria@gmail.com | Gojek |
-| Tsotne Tabidze | tsotnet | tsotnet@gmail.com | Tecton |
\ No newline at end of file
+| Name | GitHub Username | Email | Organization |
+|---------------------|-----------------|-----------------------------|-------------------|
+| Oleg Avdeev | oavdeev | oleg.v.avdeev@gmail.com | Tecton |
+| Oleksii Moskalenko | pyalex | moskalenko.alexey@gmail.com | Tecton |
+| Jay Parthasarthy | jparthasarthy | jparthasarthy@gmail.com | Tecton |
+| Danny Chiao | adchia | danny@tecton.ai | Tecton |
+| Pradithya Aria Pura | pradithya | pradithya.aria@gmail.com | Gojek |
+| Tsotne Tabidze | tsotnet | tsotnet@gmail.com | Tecton |
+| Abhin Chhabra | chhabrakadabra | chhabra.abhin@gmail.com | Shopify |
+| Danny Chiao | adchia | danny@tecton.ai | Tecton |
+| David Liu | mavysavydav | davidyliuliu@gmail.com | Twitter |
+| Matt Delacour | MattDelac | mdelacour@hey.com | Shopify |
+| Miles Adkins | sfc-gh-madkins | miles.adkins@snowflake.com | Snowflake |
+| Felix Wang | `felixwang9817` | wangfelix98@gmail.com | Tecton |
+| Kevin Zhang | `kevjumba` | kevin.zhang.13499@gmail.com | Tecton |
diff --git a/docs/README.md b/docs/README.md
index a305c4aecde..66c7548440b 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -57,7 +57,7 @@ Many companies have used Feast to power real-world ML use cases such as:
## How can I get started?
{% hint style="info" %}
-The best way to learn Feast is to use it. Join our [Slack channel](http://slack.feast.dev) and head over to our [Quickstart](getting-started/quickstart.md) and try it out!
+The best way to learn Feast is to use it. Head over to our [Quickstart](getting-started/quickstart.md) and try it out!
{% endhint %}
Explore the following resources to get started with Feast:
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
index 9b22d1e2865..8affea898ef 100644
--- a/docs/SUMMARY.md
+++ b/docs/SUMMARY.md
@@ -90,6 +90,7 @@
* [SQLite](reference/online-stores/sqlite.md)
* [Snowflake](reference/online-stores/snowflake.md)
* [Redis](reference/online-stores/redis.md)
+ * [Dragonfly](reference/online-stores/dragonfly.md)
* [Datastore](reference/online-stores/datastore.md)
* [DynamoDB](reference/online-stores/dynamodb.md)
* [Bigtable](reference/online-stores/bigtable.md)
@@ -98,6 +99,7 @@
* [MySQL (contrib)](reference/online-stores/mysql.md)
* [Rockset (contrib)](reference/online-stores/rockset.md)
* [Hazelcast (contrib)](reference/online-stores/hazelcast.md)
+ * [ScyllaDB (contrib)](reference/online-stores/scylladb.md)
* [Providers](reference/providers/README.md)
* [Local](reference/providers/local.md)
* [Google Cloud Platform](reference/providers/google-cloud-platform.md)
diff --git a/docs/community.md b/docs/community.md
index 098b6b3f90b..21cca702bf1 100644
--- a/docs/community.md
+++ b/docs/community.md
@@ -4,13 +4,6 @@
* [GitHub Repository](https://github.com/feast-dev/feast/): Find the complete Feast codebase on GitHub.
* [Community Governance Doc](https://github.com/feast-dev/feast/blob/master/community): See the governance model of Feast, including who the maintainers are and how decisions are made.
-* [Slack](https://slack.feast.dev): Feel free to ask questions or say hello! This is the main place where maintainers and contributors brainstorm and where users ask questions or discuss best practices.
- * Feast users should join `#feast-general` or `#feast-beginners` to ask questions
- * Feast developers / contributors should join `#feast-development`
-* [Mailing list](https://groups.google.com/d/forum/feast-dev): We have both a user and developer mailing list.
- * Feast users should join [feast-discuss@googlegroups.com](mailto:feast-discuss@googlegroups.com) group by clicking [here](https://groups.google.com/g/feast-discuss).
- * Feast developers / contributors should join [feast-dev@googlegroups.com](mailto:feast-dev@googlegroups.com) group by clicking [here](https://groups.google.com/d/forum/feast-dev).
-* [Community Calendar](https://calendar.google.com/calendar/u/0?cid=ZTFsZHVhdGM3MDU3YTJucTBwMzNqNW5rajBAZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbQ): Includes community calls and design meetings.
* [Google Folder](https://drive.google.com/drive/u/0/folders/1jgMHOPDT2DvBlJeO9LCM79DP4lm4eOrR): This folder is used as a central repository for all Feast resources. For example:
* Design proposals in the form of Request for Comments (RFC).
* User surveys and meeting minutes.
@@ -19,36 +12,4 @@
## How can I get help?
-* **Slack:** Need to speak to a human? Come ask a question in our Slack channel (link above).
* **GitHub Issues:** Found a bug or need a feature? [Create an issue on GitHub](https://github.com/feast-dev/feast/issues/new).
-* **StackOverflow:** Need to ask a question on how to use Feast? We also monitor and respond to [StackOverflow](https://stackoverflow.com/questions/tagged/feast).
-
-## Community Calls
-
-### General community call (biweekly)
-We have a user and contributor community call every two weeks (US & EU friendly).
-
-{% hint style="info" %}
-Please join the above Feast user groups in order to see calendar invites to the community calls
-{% endhint %}
-
-#### Frequency (every 2 weeks)
-
-* Tuesday 10:00 am to 10:30 am PST
-
-#### Links
-
-* Zoom: [https://zoom.us/j/6325193230](https://zoom.us/j/6325193230)
-* Meeting notes (incl recordings): [https://bit.ly/feast-notes](https://bit.ly/feast-notes)
-
-### Developers call (biweekly)
-We also have a `#feast-development` community call every two weeks, where we discuss contributions + brainstorm best practices.
-
-#### Frequency (every 2 weeks)
-
-* Tuesday 8:00 am to 8:30 am PST
-
-#### Links
-
-* Meeting notes (incl recordings): [Feast Development Biweekly](https://docs.google.com/document/d/1zUbIWFWjaBEVlToOdupnmKQwgAtFYx41sPoEEEdd2io/edit#)
-* Zoom: [https://zoom.us/j/93657748160?pwd=K3ZpdzhqejgrcXNhc3BlSjFMdzUxdz09](https://zoom.us/j/93657748160?pwd=K3ZpdzhqejgrcXNhc3BlSjFMdzUxdz09)
diff --git a/docs/getting-started/faq.md b/docs/getting-started/faq.md
index a511ddb0dc2..9b7eb834bf2 100644
--- a/docs/getting-started/faq.md
+++ b/docs/getting-started/faq.md
@@ -3,7 +3,7 @@
{% hint style="info" %}
**Don't see your question?**
-We encourage you to ask questions on [Slack](https://slack.feast.dev) or [GitHub](https://github.com/feast-dev/feast). Even better, once you get an answer, add the answer to this FAQ via a [pull request](../project/development-guide.md)!
+We encourage you to ask questions on [GitHub](https://github.com/feast-dev/feast). Even better, once you get an answer, add the answer to this FAQ via a [pull request](../project/development-guide.md)!
{% endhint %}
## Getting started
diff --git a/docs/getting-started/quickstart.md b/docs/getting-started/quickstart.md
index b30bdb585c7..d10e8a174ab 100644
--- a/docs/getting-started/quickstart.md
+++ b/docs/getting-started/quickstart.md
@@ -555,9 +555,7 @@ show up in the upcoming concepts + architecture + tutorial pages as well.
## Next steps
-* Join the [email newsletter](https://feast.dev/) to get new updates on Feast / feature stores.
* Read the [Concepts](concepts/) page to understand the Feast data model.
* Read the [Architecture](architecture-and-components/) page.
* Check out our [Tutorials](../tutorials/tutorials-overview/) section for more examples on how to use Feast.
* Follow our [Running Feast with Snowflake/GCP/AWS](../how-to-guides/feast-snowflake-gcp-aws/) guide for a more in-depth tutorial on using Feast.
-* Join other Feast users and contributors in [Slack](https://slack.feast.dev) and become part of the community!
diff --git a/docs/project/contributing.md b/docs/project/contributing.md
index 9a3e3e1a3ea..cded378951d 100644
--- a/docs/project/contributing.md
+++ b/docs/project/contributing.md
@@ -2,21 +2,15 @@
## Getting started
After familiarizing yourself with the documentation, the simplest way to get started is to:
-1. Join the `#feast-development` [Slack channel](https://tectonfeast.slack.com/archives/C01NTDB88QK), where contributors discuss ideas and PRs
-2. Join our Google Groups in order to get access to RFC folders + get invites to community calls. See [community](../community.md) for more details.
-3. Setup your developer environment by following [development guide](development-guide.md).
-4. Either create a [GitHub issue](https://github.com/feast-dev/feast/issues) or make a draft PR (following [development guide](development-guide.md)) to get the ball rolling!
+1. Setup your developer environment by following [development guide](development-guide.md).
+2. Either create a [GitHub issue](https://github.com/feast-dev/feast/issues) or make a draft PR (following [development guide](development-guide.md)) to get the ball rolling!
## Decision making process
*See [governance](../../community/governance.md) for more details here*
We follow a process of [lazy consensus](http://community.apache.org/committers/lazyConsensus.html). If you believe you know what the project needs then just start development. As long as there is no active opposition and the PR has been approved by maintainers or CODEOWNERS, contributions will be merged.
-We use our `#feast-development` [Slack channel](https://tectonfeast.slack.com/archives/C01NTDB88QK), [GitHub issues](https://github.com/feast-dev/feast/issues), and [GitHub pull requests](https://github.com/feast-dev/feast/pulls) to communicate development ideas.
-
-The general decision making workflow is as follows:
-
-
+We use our [GitHub issues](https://github.com/feast-dev/feast/issues), and [GitHub pull requests](https://github.com/feast-dev/feast/pulls) to communicate development ideas.
> **Note**: There may not always a corresponding CODEOWNER for the affected code, in which case the responsibility falls on other maintainers or contributors with write access to review + merge the PR
@@ -30,7 +24,7 @@ See also [Making a pull request](development-guide.md#making-a-pull-request) for
## Resources
-- [Community](../community.md) for other ways to get involved with the community (e.g. joining community calls)
+- [Community](../community.md) for other ways to get involved with the community
- [Development guide](development-guide.md) for tips on how to contribute
- [Feast GitHub issues](https://github.com/feast-dev/feast/issues) to see what others are working on
- [Feast RFCs](https://drive.google.com/drive/u/0/folders/1msUsgmDbVBaysmhBlg9lklYLLTMk4bC3) for a folder of previously written RFCs
\ No newline at end of file
diff --git a/docs/project/development-guide.md b/docs/project/development-guide.md
index 69a1ab298a4..43dae1d678d 100644
--- a/docs/project/development-guide.md
+++ b/docs/project/development-guide.md
@@ -51,13 +51,6 @@ The compatibility policy for Feast can be found [here](compatibility.md), and sh
## Community
See [Contribution process](./contributing.md) and [Community](../community.md) for details on how to get more involved in the community.
-A quick few highlights:
-- [RFCs](https://drive.google.com/drive/u/0/folders/0AAe8j7ZK3sxSUk9PVA)
-- [Community Slack](https://slack.feast.dev/)
-- [Feast Dev Mailing List](https://groups.google.com/g/feast-dev)
-- [Community Calendar](https://calendar.google.com/calendar/u/0?cid=ZTFsZHVhdGM3MDU3YTJucTBwMzNqNW5rajBAZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbQ)
- - Includes biweekly community calls at 10AM PST
-
## Making a pull request
We use the convention that the assignee of a PR is the person with the next action.
@@ -161,6 +154,16 @@ pip install -e ".[dev]"
This will allow the installed feast version to automatically reflect changes to your local development version of Feast without needing to reinstall everytime you make code changes.
+10. Compile the protubufs
+```sh
+make compile-protos-python
+```
+
+11. Spin up Docker Image
+```sh
+docker build -t docker-whale -f ./sdk/python/feast/infra/feature_servers/multicloud/Dockerfile .
+```
+
### Code Style & Linting
Feast Python SDK / CLI codebase:
- Conforms to [Black code style](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html)
diff --git a/docs/project/release-process.md b/docs/project/release-process.md
index 0aa7d3fb5ba..d3ff34bbc38 100644
--- a/docs/project/release-process.md
+++ b/docs/project/release-process.md
@@ -16,14 +16,14 @@ If you were cutting Feast 0.22.3, for example, you might do:
After this step, you will have all the changes you need in the branch.
-### 2. Pre-release verification
+### 2. Pre-release verification (currently broken)
A lot of things can go wrong. One of the most common is getting the wheels to build correctly (and not accidentally
building dev wheels from improper tagging or local code changes during the release process).
Another possible failure is that the Docker images might not build correctly.
We verify the building the wheels and Docker images in **your fork** of Feast, not the main feast-dev/feast repo.
-#### For minor releases (e.g. v0.22.0)
+#### 2a. Verifying minor releases (e.g. v0.22.0)
1. Merge upstream master changes into your **fork**. Make sure you are running the workflow off of your fork!
2. Create a tag manually for the release on your fork. For example, if you are doing a release for version 0.22.0, create a tag by doing the following.
- Checkout master branch and run `git tag v0.22.0`.
@@ -37,17 +37,7 @@ We verify the building the wheels and Docker images in **your fork** of Feast, n
5. Run the workflow off of the tag you just created(`v0.22.0` in this case, **not** the master branch) and verify that
the workflow worked (i.e ensure that all jobs are green).
-#### For patch releases (e.g. v0.22.3)
-You should already have checked out the existing minor release branch from step 1 (e.g. `v0.22-branch`).
-1. Push the minor release branch to your fork (`git push -u origin `).
-2. Add a patch release tag (e.g `v0.22.1`) by running `git tag `.
- > This is important. If you don't have a tag, then the wheels you build will be **dev wheels**, which we can't
- > push. The release process will automatically produce a tag for you via Semantic Release.
-3. Push tags to your **origin branch** (not the upstream feast-dev/feast branch) with `git push origin `.
-4. Kick off `build_wheels` workflow in your fork in the same way as is detailed in the last section, running the
- workflow from this tag you just pushed up.
-
-### 3. Release for Python and Java SDK
+### 2. Release for Python and Java SDK
1. Generate a [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) or retrieve your saved personal access token.
* The personal access token should have all of the permissions under the `repo` checkbox.
2. Access the `Actions` tab on the main `feast-dev/feast` repo and find the `release` action.
@@ -81,7 +71,7 @@ so it helps to have a high level overview. See https://github.com/feast-dev/feas
#### 4c: Update documentation
-In the Feast Gitbook (ask [Danny Chiao](https://tectonfeast.slack.com/team/U029405HFEU) in Slack for access):
+In the Feast Gitbook:
1. Create a new space within the Feast collection
2. Go to the overflow menu on the top -> Synchronize with Git
1. Specify GitHub as the provider
diff --git a/docs/reference/data-sources/overview.md b/docs/reference/data-sources/overview.md
index 112d4168d30..302c19b049c 100644
--- a/docs/reference/data-sources/overview.md
+++ b/docs/reference/data-sources/overview.md
@@ -19,13 +19,13 @@ Details for each specific data source can be found [here](README.md).
Below is a matrix indicating which data sources support which types.
| | File | BigQuery | Snowflake | Redshift | Postgres | Spark | Trino |
-| :-------------------------------- | :-- | :-- | :-- | :-- | :-- | :-- | :-- |
-| `bytes` | yes | yes | yes | yes | yes | yes | yes |
-| `string` | yes | yes | yes | yes | yes | yes | yes |
-| `int32` | yes | yes | yes | yes | yes | yes | yes |
-| `int64` | yes | yes | yes | yes | yes | yes | yes |
-| `float32` | yes | yes | yes | yes | yes | yes | yes |
-| `float64` | yes | yes | yes | yes | yes | yes | yes |
-| `bool` | yes | yes | yes | yes | yes | yes | yes |
-| `timestamp` | yes | yes | yes | yes | yes | yes | yes |
-| array types | yes | yes | no | no | yes | yes | no |
\ No newline at end of file
+| :-------------------------------- | :-- | :-- |:----------| :-- | :-- | :-- | :-- |
+| `bytes` | yes | yes | yes | yes | yes | yes | yes |
+| `string` | yes | yes | yes | yes | yes | yes | yes |
+| `int32` | yes | yes | yes | yes | yes | yes | yes |
+| `int64` | yes | yes | yes | yes | yes | yes | yes |
+| `float32` | yes | yes | yes | yes | yes | yes | yes |
+| `float64` | yes | yes | yes | yes | yes | yes | yes |
+| `bool` | yes | yes | yes | yes | yes | yes | yes |
+| `timestamp` | yes | yes | yes | yes | yes | yes | yes |
+| array types | yes | yes | yes | no | yes | yes | no |
\ No newline at end of file
diff --git a/docs/reference/data-sources/snowflake.md b/docs/reference/data-sources/snowflake.md
index 82bf5cb4d49..98a56e09f87 100644
--- a/docs/reference/data-sources/snowflake.md
+++ b/docs/reference/data-sources/snowflake.md
@@ -46,5 +46,5 @@ The full set of configuration options is available [here](https://rtd.feast.dev/
## Supported Types
-Snowflake data sources support all eight primitive types, but currently do not support array types.
+Snowflake data sources support all eight primitive types. Array types are also supported but not with type inference.
For a comparison against other batch data sources, please see [here](overview.md#functionality-matrix).
diff --git a/docs/reference/feast-cli-commands.md b/docs/reference/feast-cli-commands.md
index 38e85843d41..7bdea19e610 100644
--- a/docs/reference/feast-cli-commands.md
+++ b/docs/reference/feast-cli-commands.md
@@ -11,8 +11,6 @@ Usage: feast [OPTIONS] COMMAND [ARGS]...
For more information, see our public docs at https://docs.feast.dev/
- For any questions, you can reach us at https://slack.feast.dev/
-
Options:
-c, --chdir TEXT Switch to a different feature repository directory before
executing the given subcommand.
diff --git a/docs/reference/offline-stores/trino.md b/docs/reference/offline-stores/trino.md
index 446db620e32..fd437a7aa67 100644
--- a/docs/reference/offline-stores/trino.md
+++ b/docs/reference/offline-stores/trino.md
@@ -27,6 +27,47 @@ offline_store:
catalog: memory
connector:
type: memory
+ user: trino
+ source: feast-trino-offline-store
+ http-scheme: https
+ ssl-verify: false
+ x-trino-extra-credential-header: foo=bar, baz=qux
+
+ # enables authentication in Trino connections, pick the one you need
+ # if you don't need authentication, you can safely remove the whole auth block
+ auth:
+ # Basic Auth
+ type: basic
+ config:
+ username: foo
+ password: $FOO
+
+ # Certificate
+ type: certificate
+ config:
+ cert-file: /path/to/cert/file
+ key-file: /path/to/key/file
+
+ # JWT
+ type: jwt
+ config:
+ token: $JWT_TOKEN
+
+ # OAuth2 (no config required)
+ type: oauth2
+
+ # Kerberos
+ type: kerberos
+ config:
+ config-file: /path/to/kerberos/config/file
+ service-name: foo
+ mutual-authentication: true
+ force-preemptive: true
+ hostname-override: custom-hostname
+ sanitize-mutual-error-response: true
+ principal: principal-name
+ delegate: true
+ ca_bundle: /path/to/ca/bundle/file
online_store:
path: data/online_store.db
```
diff --git a/docs/reference/online-stores/README.md b/docs/reference/online-stores/README.md
index 2fdfd50f7c1..d90bfcf1632 100644
--- a/docs/reference/online-stores/README.md
+++ b/docs/reference/online-stores/README.md
@@ -18,6 +18,10 @@ Please see [Online Store](../../getting-started/architecture-and-components/onli
[redis.md](redis.md)
{% endcontent-ref %}
+{% content-ref url="dragonfly.md" %}
+[dragonfly.md](dragonfly.md)
+{% endcontent-ref %}
+
{% content-ref url="datastore.md" %}
[datastore.md](datastore.md)
{% endcontent-ref %}
@@ -50,4 +54,6 @@ Please see [Online Store](../../getting-started/architecture-and-components/onli
[hazelcast.md](hazelcast.md)
{% endcontent-ref %}
-
+{% content-ref url="scylladb.md" %}
+[scylladb.md](scylladb.md)
+{% endcontent-ref %}
diff --git a/docs/reference/online-stores/dragonfly.md b/docs/reference/online-stores/dragonfly.md
new file mode 100644
index 00000000000..bcd814ecc45
--- /dev/null
+++ b/docs/reference/online-stores/dragonfly.md
@@ -0,0 +1,90 @@
+# Dragonfly online store
+
+## Description
+
+[Dragonfly](https://github.com/dragonflydb/dragonfly) is a modern in-memory datastore that implements novel algorithms and data structures on top of a multi-threaded, share-nothing architecture. Thanks to its API compatibility, Dragonfly can act as a drop-in replacement for Redis. Due to Dragonfly's hardware efficiency, you can run a single node instance on a small 8GB instance or scale vertically to large 768GB machines with 64 cores. This greatly reduces infrastructure costs as well as architectural complexity.
+
+Similar to Redis, Dragonfly can be used as an online feature store for Feast.
+
+## Using Dragonfly as a drop-in Feast online store instead of Redis
+
+Make sure you have Python and `pip` installed.
+
+Install the Feast SDK and CLI
+
+`pip install feast`
+
+In order to use Dragonfly as the online store, you'll need to install the redis extra:
+
+`pip install 'feast[redis]'`
+
+### 1. Create a feature repository
+
+Bootstrap a new feature repository:
+
+```
+feast init feast_dragonfly
+cd feast_dragonfly/feature_repo
+```
+
+Update `feature_repo/feature_store.yaml` with the below contents:
+
+```
+project: feast_dragonfly
+registry: data/registry.db
+provider: local
+online_store:
+type: redis
+connection_string: "localhost:6379"
+```
+
+### 2. Start Dragonfly
+
+There are several options available to get Dragonfly up and running quickly. We will be using Docker for this tutorial.
+
+`docker run --network=host --ulimit memlock=-1 docker.dragonflydb.io/dragonflydb/dragonfly`
+
+### 3. Register feature definitions and deploy your feature store
+
+`feast apply`
+
+The `apply` command scans python files in the current directory (`example_repo.py` in this case) for feature view/entity definitions, registers the objects, and deploys infrastructure.
+You should see the following output:
+
+```
+....
+Created entity driver
+Created feature view driver_hourly_stats_fresh
+Created feature view driver_hourly_stats
+Created on demand feature view transformed_conv_rate
+Created on demand feature view transformed_conv_rate_fresh
+Created feature service driver_activity_v1
+Created feature service driver_activity_v3
+Created feature service driver_activity_v2
+```
+
+## Functionality Matrix
+
+The set of functionality supported by online stores is described in detail [here](overview.md#functionality).
+Below is a matrix indicating which functionality is supported by the Redis online store.
+
+| | Redis |
+| :-------------------------------------------------------- | :---- |
+| write feature values to the online store | yes |
+| read feature values from the online store | yes |
+| update infrastructure (e.g. tables) in the online store | yes |
+| teardown infrastructure (e.g. tables) in the online store | yes |
+| generate a plan of infrastructure changes | no |
+| support for on-demand transforms | yes |
+| readable by Python SDK | yes |
+| readable by Java | yes |
+| readable by Go | yes |
+| support for entityless feature views | yes |
+| support for concurrent writing to the same key | yes |
+| support for ttl (time to live) at retrieval | yes |
+| support for deleting expired data | yes |
+| collocated by feature view | no |
+| collocated by feature service | no |
+| collocated by entity key | yes |
+
+To compare this set of functionality against other online stores, please see the full [functionality matrix](overview.md#functionality-matrix).
diff --git a/docs/reference/online-stores/redis.md b/docs/reference/online-stores/redis.md
index c08cef2a3e1..ae7f8b4c5ca 100644
--- a/docs/reference/online-stores/redis.md
+++ b/docs/reference/online-stores/redis.md
@@ -45,6 +45,21 @@ online_store:
```
{% endcode %}
+Connecting to a Redis Sentinel with SSL enabled and password authentication:
+
+{% code title="feature_store.yaml" %}
+```yaml
+project: my_feature_repo
+registry: data/registry.db
+provider: local
+online_store:
+ type: redis
+ redis_type: redis_sentinel
+ sentinel_master: mymaster
+ connection_string: "redis1:26379,ssl=true,password=my_password"
+```
+{% endcode %}
+
Additionally, the redis online store also supports automatically deleting data via a TTL mechanism.
The TTL is applied at the entity level, so feature values from any associated feature views for an entity are removed together.
This TTL can be set in the `feature_store.yaml`, using the `key_ttl_seconds` field in the online store. For example:
diff --git a/docs/reference/online-stores/scylladb.md b/docs/reference/online-stores/scylladb.md
new file mode 100644
index 00000000000..e28e810e214
--- /dev/null
+++ b/docs/reference/online-stores/scylladb.md
@@ -0,0 +1,94 @@
+# ScyllaDB Cloud online store
+
+## Description
+
+ScyllaDB is a low-latency and high-performance Cassandra-compatible (uses CQL) database. You can use the existing Cassandra connector to use ScyllaDB as an online store in Feast.
+
+The [ScyllaDB](https://www.scylladb.com/) online store provides support for materializing feature values into a ScyllaDB or [ScyllaDB Cloud](https://www.scylladb.com/product/scylla-cloud/) cluster for serving online features real-time.
+
+## Getting started
+
+Install Feast with Cassandra support:
+```bash
+pip install "feast[cassandra]"
+```
+
+Create a new Feast project:
+```bash
+feast init REPO_NAME -t cassandra
+```
+
+### Example (ScyllaDB)
+
+{% code title="feature_store.yaml" %}
+```yaml
+project: scylla_feature_repo
+registry: data/registry.db
+provider: local
+online_store:
+ type: cassandra
+ hosts:
+ - 172.17.0.2
+ keyspace: feast
+ username: scylla
+ password: password
+```
+{% endcode %}
+
+### Example (ScyllaDB Cloud)
+
+{% code title="feature_store.yaml" %}
+```yaml
+project: scylla_feature_repo
+registry: data/registry.db
+provider: local
+online_store:
+ type: cassandra
+ hosts:
+ - node-0.aws_us_east_1.xxxxxxxx.clusters.scylla.cloud
+ - node-1.aws_us_east_1.xxxxxxxx.clusters.scylla.cloud
+ - node-2.aws_us_east_1.xxxxxxxx.clusters.scylla.cloud
+ keyspace: feast
+ username: scylla
+ password: password
+```
+{% endcode %}
+
+
+The full set of configuration options is available in [CassandraOnlineStoreConfig](https://rtd.feast.dev/en/master/#feast.infra.online_stores.contrib.cassandra_online_store.cassandra_online_store.CassandraOnlineStoreConfig).
+For a full explanation of configuration options please look at file
+`sdk/python/feast/infra/online_stores/contrib/cassandra_online_store/README.md`.
+
+Storage specifications can be found at `docs/specs/online_store_format.md`.
+
+## Functionality Matrix
+
+The set of functionality supported by online stores is described in detail [here](overview.md#functionality).
+Below is a matrix indicating which functionality is supported by the Cassandra plugin.
+
+| | Cassandra |
+| :-------------------------------------------------------- | :-------- |
+| write feature values to the online store | yes |
+| read feature values from the online store | yes |
+| update infrastructure (e.g. tables) in the online store | yes |
+| teardown infrastructure (e.g. tables) in the online store | yes |
+| generate a plan of infrastructure changes | yes |
+| support for on-demand transforms | yes |
+| readable by Python SDK | yes |
+| readable by Java | no |
+| readable by Go | no |
+| support for entityless feature views | yes |
+| support for concurrent writing to the same key | no |
+| support for ttl (time to live) at retrieval | no |
+| support for deleting expired data | no |
+| collocated by feature view | yes |
+| collocated by feature service | no |
+| collocated by entity key | no |
+
+To compare this set of functionality against other online stores, please see the full [functionality matrix](overview.md#functionality-matrix).
+
+## Resources
+
+* [Sample application with ScyllaDB](https://feature-store.scylladb.com/stable/)
+* [ScyllaDB website](https://www.scylladb.com/)
+* [ScyllaDB Cloud documentation](https://cloud.docs.scylladb.com/stable/)
diff --git a/docs/roadmap.md b/docs/roadmap.md
index e75e58849bf..a04ede7c993 100644
--- a/docs/roadmap.md
+++ b/docs/roadmap.md
@@ -3,7 +3,6 @@
The list below contains the functionality that contributors are planning to develop for Feast.
* We welcome contribution to all items in the roadmap!
-* Have questions about the roadmap? Go to the Slack channel to ask on #feast-development.
* **Data Sources**
* [x] [Snowflake source](https://docs.feast.dev/reference/data-sources/snowflake)
@@ -33,6 +32,7 @@ The list below contains the functionality that contributors are planning to deve
* [x] [Datastore](https://docs.feast.dev/reference/online-stores/datastore)
* [x] [Bigtable](https://docs.feast.dev/reference/online-stores/bigtable)
* [x] [SQLite](https://docs.feast.dev/reference/online-stores/sqlite)
+ * [x] [Dragonfly](https://docs.feast.dev/reference/online-stores/dragonfly)
* [x] [Azure Cache for Redis (community plugin)](https://github.com/Azure/feast-azure)
* [x] [Postgres (contrib plugin)](https://docs.feast.dev/reference/online-stores/postgres)
* [x] [Cassandra / AstraDB (contrib plugin)](https://docs.feast.dev/reference/online-stores/cassandra)
diff --git a/examples/quickstart/quickstart.ipynb b/examples/quickstart/quickstart.ipynb
index 6e07d3e23bc..f84457ac02d 100644
--- a/examples/quickstart/quickstart.ipynb
+++ b/examples/quickstart/quickstart.ipynb
@@ -1066,7 +1066,6 @@
"- Read the [Concepts](https://docs.feast.dev/getting-started/concepts/) page to understand the Feast data model and architecture.\n",
"- Check out our [Tutorials](https://docs.feast.dev/tutorials/tutorials-overview) section for more examples on how to use Feast.\n",
"- Follow our [Running Feast with Snowflake/GCP/AWS](https://docs.feast.dev/how-to-guides/feast-snowflake-gcp-aws) guide for a more in-depth tutorial on using Feast.\n",
- "- Join other Feast users and contributors in [Slack](https://slack.feast.dev/) and become part of the community!"
]
}
],
diff --git a/go.mod b/go.mod
index a051a13f6fe..6def9339859 100644
--- a/go.mod
+++ b/go.mod
@@ -7,29 +7,26 @@ replace github.com/go-python/gopy v0.4.4 => github.com/feast-dev/gopy v0.4.1-0.2
require (
github.com/apache/arrow/go/v8 v8.0.0
github.com/ghodss/yaml v1.0.0
- github.com/go-python/gopy v0.4.4
github.com/go-redis/redis/v8 v8.11.4
- github.com/golang/protobuf v1.5.2
+ github.com/golang/protobuf v1.5.3
github.com/google/uuid v1.3.0
github.com/mattn/go-sqlite3 v1.14.12
github.com/pkg/errors v0.9.1
github.com/spaolacci/murmur3 v1.1.0
github.com/stretchr/testify v1.7.0
- google.golang.org/grpc v1.47.0
- google.golang.org/protobuf v1.28.0
+ google.golang.org/grpc v1.56.3
+ google.golang.org/protobuf v1.30.0
)
require (
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/apache/thrift v0.15.0 // indirect
- github.com/cespare/xxhash/v2 v2.1.2 // indirect
+ github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/goccy/go-json v0.9.6 // indirect
github.com/golang/snappy v0.0.4 // indirect
- github.com/gonuts/commander v0.1.0 // indirect
- github.com/gonuts/flag v0.1.0 // indirect
github.com/google/flatbuffers v2.0.6+incompatible // indirect
github.com/klauspost/asmfmt v1.3.2 // indirect
github.com/klauspost/compress v1.15.1 // indirect
@@ -40,13 +37,13 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
golang.org/x/exp v0.0.0-20220407100705-7b9b53b0aca4 // indirect
- golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
- golang.org/x/net v0.7.0 // indirect
- golang.org/x/sys v0.5.0 // indirect
- golang.org/x/text v0.7.0 // indirect
- golang.org/x/tools v0.1.12 // indirect
+ golang.org/x/mod v0.8.0 // indirect
+ golang.org/x/net v0.17.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
+ golang.org/x/text v0.13.0 // indirect
+ golang.org/x/tools v0.6.0 // indirect
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
- google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac // indirect
+ google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
diff --git a/go.sum b/go.sum
index cbcfc75ac44..9a33f2c9ee6 100644
--- a/go.sum
+++ b/go.sum
@@ -1,8 +1,601 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
+cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
+cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
+cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
+cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
+cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
+cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
+cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
+cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
+cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
+cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
+cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
+cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
+cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
+cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U=
+cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
+cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
+cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
+cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
+cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM=
+cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I=
+cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY=
+cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4=
+cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw=
+cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E=
+cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o=
+cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE=
+cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM=
+cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ=
+cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
+cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=
+cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg=
+cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ=
+cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k=
+cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw=
+cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
+cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=
+cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M=
+cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE=
+cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE=
+cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk=
+cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc=
+cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8=
+cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc=
+cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04=
+cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8=
+cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY=
+cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM=
+cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc=
+cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU=
+cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI=
+cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8=
+cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno=
+cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak=
+cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84=
+cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A=
+cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E=
+cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4=
+cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0=
+cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY=
+cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k=
+cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ=
+cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk=
+cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0=
+cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc=
+cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI=
+cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ=
+cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI=
+cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08=
+cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o=
+cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s=
+cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0=
+cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ=
+cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY=
+cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo=
+cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg=
+cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw=
+cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY=
+cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw=
+cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI=
+cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo=
+cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0=
+cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E=
+cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=
+cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8=
+cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8=
+cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM=
+cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU=
+cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc=
+cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI=
+cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss=
+cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE=
+cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE=
+cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g=
+cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4=
+cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8=
+cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM=
+cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA=
+cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw=
+cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc=
+cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E=
+cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac=
+cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q=
+cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU=
+cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=
+cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=
+cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI=
+cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y=
+cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss=
+cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc=
+cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM=
+cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI=
+cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0=
+cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk=
+cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q=
+cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg=
+cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590=
+cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8=
+cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk=
+cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk=
+cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE=
+cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU=
+cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U=
+cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA=
+cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M=
+cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg=
+cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s=
+cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM=
+cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk=
+cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA=
+cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY=
+cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI=
+cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4=
+cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI=
+cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y=
+cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs=
+cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
+cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
+cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
+cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
+cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
+cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
+cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=
+cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
+cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
+cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE=
+cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo=
+cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA=
+cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs=
+cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU=
+cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE=
+cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=
+cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
+cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
+cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
+cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY=
+cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck=
+cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w=
+cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg=
+cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo=
+cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4=
+cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM=
+cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA=
+cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=
+cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4=
+cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI=
+cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s=
+cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0=
+cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs=
+cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc=
+cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE=
+cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM=
+cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M=
+cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0=
+cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8=
+cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM=
+cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ=
+cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE=
+cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo=
+cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE=
+cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0=
+cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA=
+cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE=
+cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38=
+cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w=
+cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8=
+cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I=
+cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ=
+cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM=
+cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA=
+cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A=
+cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ=
+cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs=
+cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s=
+cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI=
+cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4=
+cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo=
+cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA=
+cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM=
+cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c=
+cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo=
+cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ=
+cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g=
+cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4=
+cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs=
+cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww=
+cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c=
+cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s=
+cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI=
+cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ=
+cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4=
+cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0=
+cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8=
+cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek=
+cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0=
+cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM=
+cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4=
+cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE=
+cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM=
+cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q=
+cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4=
+cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU=
+cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU=
+cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k=
+cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4=
+cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM=
+cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs=
+cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y=
+cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg=
+cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE=
+cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk=
+cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w=
+cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc=
+cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY=
+cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU=
+cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI=
+cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8=
+cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M=
+cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc=
+cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw=
+cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw=
+cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY=
+cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w=
+cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI=
+cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs=
+cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg=
+cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE=
+cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk=
+cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg=
+cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY=
+cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08=
+cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw=
+cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA=
+cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c=
+cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM=
+cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA=
+cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w=
+cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM=
+cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0=
+cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60=
+cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo=
+cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg=
+cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o=
+cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A=
+cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw=
+cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0=
+cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0=
+cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E=
+cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw=
+cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA=
+cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI=
+cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y=
+cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc=
+cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM=
+cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o=
+cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo=
+cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c=
+cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
+cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=
+cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc=
+cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg=
+cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE=
+cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY=
+cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY=
+cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=
+cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc=
+cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A=
+cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk=
+cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo=
+cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74=
+cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM=
+cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY=
+cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4=
+cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs=
+cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g=
+cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o=
+cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE=
+cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA=
+cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg=
+cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0=
+cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg=
+cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w=
+cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24=
+cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI=
+cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=
+cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=
+cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE=
+cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8=
+cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY=
+cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8=
+cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08=
+cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo=
+cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw=
+cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M=
+cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE=
+cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc=
+cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo=
+cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE=
+cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM=
+cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA=
+cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI=
+cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw=
+cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY=
+cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4=
+cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w=
+cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I=
+cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE=
+cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM=
+cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA=
+cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY=
+cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM=
+cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY=
+cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s=
+cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8=
+cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI=
+cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo=
+cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk=
+cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4=
+cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w=
+cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw=
+cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=
+cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=
+cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM=
+cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8=
+cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E=
+cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM=
+cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8=
+cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4=
+cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY=
+cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ=
+cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU=
+cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k=
+cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU=
+cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY=
+cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34=
+cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA=
+cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0=
+cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE=
+cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ=
+cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4=
+cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs=
+cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI=
+cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA=
+cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk=
+cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ=
+cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE=
+cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc=
+cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc=
+cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs=
+cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg=
+cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo=
+cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw=
+cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw=
+cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E=
+cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU=
+cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70=
+cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo=
+cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs=
+cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0=
+cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA=
+cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk=
+cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg=
+cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE=
+cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw=
+cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc=
+cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0=
+cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI=
+cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg=
+cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI=
+cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0=
+cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8=
+cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4=
+cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg=
+cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k=
+cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM=
+cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4=
+cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o=
+cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk=
+cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo=
+cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE=
+cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U=
+cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA=
+cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c=
+cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg=
+cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4=
+cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac=
+cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg=
+cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c=
+cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs=
+cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70=
+cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ=
+cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y=
+cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A=
+cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA=
+cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM=
+cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ=
+cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA=
+cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0=
+cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots=
+cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo=
+cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI=
+cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU=
+cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg=
+cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA=
+cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4=
+cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY=
+cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc=
+cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y=
+cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14=
+cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do=
+cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo=
+cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM=
+cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg=
+cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s=
+cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI=
+cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk=
+cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44=
+cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc=
+cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc=
+cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA=
+cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4=
+cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4=
+cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU=
+cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4=
+cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0=
+cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU=
+cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q=
+cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA=
+cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8=
+cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0=
+cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU=
+cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc=
+cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk=
+cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk=
+cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0=
+cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag=
+cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU=
+cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s=
+cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA=
+cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc=
+cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk=
+cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs=
+cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg=
+cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4=
+cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U=
+cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY=
+cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s=
+cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco=
+cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo=
+cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc=
+cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4=
+cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E=
+cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU=
+cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec=
+cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA=
+cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4=
+cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw=
+cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A=
+cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos=
+cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk=
+cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M=
+cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM=
+cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ=
+cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0=
+cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco=
+cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0=
+cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
+cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
+cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
+cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
+cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y=
+cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4=
+cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w=
+cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I=
+cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4=
+cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw=
+cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
+cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=
+cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM=
+cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA=
+cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c=
+cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8=
+cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4=
+cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc=
+cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ=
+cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg=
+cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM=
+cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28=
+cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y=
+cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA=
+cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk=
+cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs=
+cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg=
+cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0=
+cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos=
+cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos=
+cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk=
+cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw=
+cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg=
+cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk=
+cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ=
+cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ=
+cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU=
+cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4=
+cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M=
+cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU=
+cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU=
+cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0=
+cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo=
+cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo=
+cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY=
+cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E=
+cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY=
+cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0=
+cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE=
+cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g=
+cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc=
+cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY=
+cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208=
+cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8=
+cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY=
+cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w=
+cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8=
+cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes=
+cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE=
+cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
+cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc=
+cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A=
+cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg=
+cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo=
+cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ=
+cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng=
+cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
+cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
+cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M=
+cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA=
+cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
+git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU=
@@ -13,7 +606,10 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
+github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
+github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
+github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -21,12 +617,16 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=
+github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI=
github.com/apache/arrow/go/v8 v8.0.0 h1:mG1dDlq8aQO4a/PB00T9H19Ga2imvqoFPHI5cykpibs=
github.com/apache/arrow/go/v8 v8.0.0/go.mod h1:63co72EKYQT9WKr8Y1Yconk4dysC0t79wNDauYO1ZGg=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.15.0 h1:aGvdaR0v1t9XLgjtBYwxcBvBOTMqClzwE26CHOgjW1Y=
github.com/apache/thrift v0.15.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
+github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY=
+github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
@@ -39,24 +639,36 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
+github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -65,6 +677,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -73,6 +686,7 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
@@ -81,14 +695,19 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
+github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34=
+github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
+github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
+github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/feast-dev/gopy v0.4.1-0.20220714211711-252048177d85 h1:BKmfqWiDbxvviB6vemPbbNjF+ywRsBMCdk1QvrcGgkc=
-github.com/feast-dev/gopy v0.4.1-0.20220714211711-252048177d85/go.mod h1:tlA/KcD7rM8B+NQJR4SASwiinfKY0aiMFanHszR8BZA=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
@@ -101,17 +720,22 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks=
github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=
+github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=
github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
+github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
+github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
@@ -119,20 +743,35 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/goccy/go-json v0.9.6 h1:5/4CtRQdtsX0sal8fdVhTaiMN01Ri8BExZZ8iRmHQ6E=
github.com/goccy/go-json v0.9.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
+github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
+github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@@ -142,35 +781,81 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/gonuts/commander v0.1.0 h1:EcDTiVw9oAVORFjQOEOuHQqcl6OXMyTgELocTq6zJ0I=
-github.com/gonuts/commander v0.1.0/go.mod h1:qkb5mSlcWodYgo7vs8ulLnXhfinhZsZcm6+H/z1JjgY=
-github.com/gonuts/flag v0.1.0 h1:fqMv/MZ+oNGu0i9gp0/IQ/ZaPIDoAZBOBaJoV7viCWM=
-github.com/gonuts/flag v0.1.0/go.mod h1:ZTmTGtrSPejTo/SRNhCqwLTmiAgyBdCkLYhHrAoBdz4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/flatbuffers v2.0.5+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/flatbuffers v2.0.6+incompatible h1:XHFReMv7nFFusa+CEokzWbzaYocKXI6C7hdU5Kgh9Lw=
github.com/google/flatbuffers v2.0.6+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
+github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM=
+github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
+github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
+github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
+github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
+github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
+github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
+github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
+github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
+github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
+github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
+github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
+github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
+github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
+github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
+github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
+github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
+github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
@@ -180,6 +865,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -202,6 +889,9 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
+github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@@ -209,10 +899,13 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/asmfmt v1.3.1/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
@@ -221,26 +914,40 @@ github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
+github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
+github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
+github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
+github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
+github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw=
+github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
@@ -297,17 +1004,23 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
+github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.12/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
+github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
+github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
+github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
@@ -320,6 +1033,8 @@ github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
@@ -328,13 +1043,17 @@ github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
+github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@@ -349,6 +1068,9 @@ github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJ
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
+github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
+github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
@@ -357,17 +1079,30 @@ github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5J
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
@@ -379,13 +1114,22 @@ go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
+go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -402,20 +1146,35 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20211216164055-b2b84827b756/go.mod h1:b9TAUYHmRtqA6klRHApnXMnj+OyLce4yF5cZCUbk2ps=
golang.org/x/exp v0.0.0-20220407100705-7b9b53b0aca4 h1:K3x+yU+fbot38x5bQbU2QqUAVyYLEktdNH2GxZLnM3U=
golang.org/x/exp v0.0.0-20220407100705-7b9b53b0aca4/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
+golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw=
+golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -425,24 +1184,45 @@ golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+o
golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
+golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
+golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
+golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
+golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -455,34 +1235,110 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
+golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
+golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
+golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
+golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
+golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
+golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
+golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
+golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
+golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
+golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
+golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
+golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -496,45 +1352,123 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
+golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
+golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
+golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -546,66 +1480,336 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
+golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
+golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
-golang.org/x/tools v0.1.11-0.20220413170336-afc6aad76eb1/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
-golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
+golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
+golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
+golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
gonum.org/v1/gonum v0.9.3 h1:DnoIG+QAMaF5NvxnGe/oKsgKcAc6PcUyl8q0VetfQ8s=
gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0=
+gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E=
+gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY=
+gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
+google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
+google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
+google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
+google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
+google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
+google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
+google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
+google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
+google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
+google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
+google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
+google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
+google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
+google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
+google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
+google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
+google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
+google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
+google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
+google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
+google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
+google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
+google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
+google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g=
+google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
+google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
+google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=
+google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
+google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
+google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
+google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08=
+google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70=
+google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo=
+google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0=
+google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
+google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
+google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
+google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI=
+google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
+google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
+google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
+google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
+google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
+google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
+google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
+google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
+google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
+google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
+google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac h1:qSNTkEN+L2mvWcLgJOR+8bdHX9rN/IdU3A1Ghpfb1Rg=
+google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
+google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
+google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
+google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
+google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
+google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
+google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
+google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
+google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
+google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE=
+google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
+google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
+google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
+google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
+google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
+google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
+google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
+google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
+google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
+google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
+google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
+google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw=
+google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
+google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
+google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U=
+google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
+google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
+google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
+google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
+google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo=
+google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
+google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
+google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
+google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
+google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
+google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
+google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE=
+google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA=
+google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=
+google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=
+google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA=
+google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
+google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
+google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
+google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
+google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
+google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
+google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
+google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
+google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
-google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
+google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
+google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
+google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
+google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
+google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc=
+google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -614,12 +1818,16 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
+google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -643,11 +1851,54 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
+lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
+lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
+modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
+modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
+modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
+modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
+modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
+modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
+modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
+modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws=
+modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo=
+modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
+modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
+modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
+modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
+modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=
+modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
+modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
+modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0=
+modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s=
+modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
+modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
+modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
+modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
+modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
+modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
+modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
+modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
+modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
+modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
+modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
+modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw=
+modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
+modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/infra/charts/feast-feature-server/Chart.yaml b/infra/charts/feast-feature-server/Chart.yaml
index 65dea258e09..6111639b684 100644
--- a/infra/charts/feast-feature-server/Chart.yaml
+++ b/infra/charts/feast-feature-server/Chart.yaml
@@ -2,7 +2,7 @@ apiVersion: v2
name: feast-feature-server
description: Feast Feature Server in Go or Python
type: application
-version: 0.31.0
+version: 0.35.0
keywords:
- machine learning
- big data
diff --git a/infra/charts/feast-feature-server/README.md b/infra/charts/feast-feature-server/README.md
index e3515b10f8f..2467b60e1e8 100644
--- a/infra/charts/feast-feature-server/README.md
+++ b/infra/charts/feast-feature-server/README.md
@@ -1,6 +1,6 @@
# Feast Python / Go Feature Server Helm Charts
-Current chart version is `0.31.0`
+Current chart version is `0.35.0`
## Installation
@@ -30,7 +30,7 @@ See [here](https://github.com/feast-dev/feast/tree/master/examples/python-helm-d
| fullnameOverride | string | `""` | |
| image.pullPolicy | string | `"IfNotPresent"` | |
| image.repository | string | `"feastdev/feature-server"` | Docker image for Feature Server repository |
-| image.tag | string | `"0.31.0"` | The Docker image tag (can be overwritten if custom feature server deps are needed for on demand transforms) |
+| image.tag | string | `"0.35.0"` | The Docker image tag (can be overwritten if custom feature server deps are needed for on demand transforms) |
| imagePullSecrets | list | `[]` | |
| livenessProbe.initialDelaySeconds | int | `30` | |
| livenessProbe.periodSeconds | int | `30` | |
diff --git a/infra/charts/feast-feature-server/values.yaml b/infra/charts/feast-feature-server/values.yaml
index 8a66052861c..2383d6fa9fd 100644
--- a/infra/charts/feast-feature-server/values.yaml
+++ b/infra/charts/feast-feature-server/values.yaml
@@ -9,7 +9,7 @@ image:
repository: feastdev/feature-server
pullPolicy: IfNotPresent
# image.tag -- The Docker image tag (can be overwritten if custom feature server deps are needed for on demand transforms)
- tag: 0.31.0
+ tag: 0.35.0
imagePullSecrets: []
nameOverride: ""
diff --git a/infra/charts/feast/Chart.yaml b/infra/charts/feast/Chart.yaml
index 0daded67ed6..c53b73848c4 100644
--- a/infra/charts/feast/Chart.yaml
+++ b/infra/charts/feast/Chart.yaml
@@ -1,7 +1,7 @@
apiVersion: v1
description: Feature store for machine learning
name: feast
-version: 0.31.0
+version: 0.35.0
keywords:
- machine learning
- big data
diff --git a/infra/charts/feast/README.md b/infra/charts/feast/README.md
index 17ba86b1d1a..d8d4a3d376d 100644
--- a/infra/charts/feast/README.md
+++ b/infra/charts/feast/README.md
@@ -8,7 +8,7 @@ This repo contains Helm charts for Feast Java components that are being installe
## Chart: Feast
-Feature store for machine learning Current chart version is `0.31.0`
+Feature store for machine learning Current chart version is `0.35.0`
## Installation
@@ -65,8 +65,8 @@ See [here](https://github.com/feast-dev/feast/tree/master/examples/java-demo) fo
| Repository | Name | Version |
|------------|------|---------|
| https://charts.helm.sh/stable | redis | 10.5.6 |
-| https://feast-helm-charts.storage.googleapis.com | feature-server(feature-server) | 0.31.0 |
-| https://feast-helm-charts.storage.googleapis.com | transformation-service(transformation-service) | 0.31.0 |
+| https://feast-helm-charts.storage.googleapis.com | feature-server(feature-server) | 0.35.0 |
+| https://feast-helm-charts.storage.googleapis.com | transformation-service(transformation-service) | 0.35.0 |
## Values
diff --git a/infra/charts/feast/charts/feature-server/Chart.yaml b/infra/charts/feast/charts/feature-server/Chart.yaml
index 78b83bb4f23..122c80f9fd7 100644
--- a/infra/charts/feast/charts/feature-server/Chart.yaml
+++ b/infra/charts/feast/charts/feature-server/Chart.yaml
@@ -1,8 +1,8 @@
apiVersion: v1
description: "Feast Feature Server: Online feature serving service for Feast"
name: feature-server
-version: 0.31.0
-appVersion: v0.31.0
+version: 0.35.0
+appVersion: v0.35.0
keywords:
- machine learning
- big data
diff --git a/infra/charts/feast/charts/feature-server/README.md b/infra/charts/feast/charts/feature-server/README.md
index 237ed7b67ac..514fcc57278 100644
--- a/infra/charts/feast/charts/feature-server/README.md
+++ b/infra/charts/feast/charts/feature-server/README.md
@@ -1,6 +1,6 @@
# feature-server
- 
+ 
Feast Feature Server: Online feature serving service for Feast
@@ -17,7 +17,7 @@ Feast Feature Server: Online feature serving service for Feast
| envOverrides | object | `{}` | Extra environment variables to set |
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
| image.repository | string | `"feastdev/feature-server-java"` | Docker image for Feature Server repository |
-| image.tag | string | `"0.31.0"` | Image tag |
+| image.tag | string | `"0.35.0"` | Image tag |
| ingress.grpc.annotations | object | `{}` | Extra annotations for the ingress |
| ingress.grpc.auth.enabled | bool | `false` | Flag to enable auth |
| ingress.grpc.class | string | `"nginx"` | Which ingress controller to use |
@@ -64,4 +64,4 @@ Feast Feature Server: Online feature serving service for Feast
| transformationService.port | int | `6566` | |
----------------------------------------------
-Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0)
+Autogenerated from chart metadata using [helm-docs v1.12.0](https://github.com/norwoodj/helm-docs/releases/v1.12.0)
diff --git a/infra/charts/feast/charts/feature-server/values.yaml b/infra/charts/feast/charts/feature-server/values.yaml
index 054729f4784..a14cc2d28f3 100644
--- a/infra/charts/feast/charts/feature-server/values.yaml
+++ b/infra/charts/feast/charts/feature-server/values.yaml
@@ -5,7 +5,7 @@ image:
# image.repository -- Docker image for Feature Server repository
repository: feastdev/feature-server-java
# image.tag -- Image tag
- tag: 0.31.0
+ tag: 0.35.0
# image.pullPolicy -- Image pull policy
pullPolicy: IfNotPresent
diff --git a/infra/charts/feast/charts/transformation-service/Chart.yaml b/infra/charts/feast/charts/transformation-service/Chart.yaml
index ecb02682f13..852045f52b5 100644
--- a/infra/charts/feast/charts/transformation-service/Chart.yaml
+++ b/infra/charts/feast/charts/transformation-service/Chart.yaml
@@ -1,8 +1,8 @@
apiVersion: v1
description: "Transformation service: to compute on-demand features"
name: transformation-service
-version: 0.31.0
-appVersion: v0.31.0
+version: 0.35.0
+appVersion: v0.35.0
keywords:
- machine learning
- big data
diff --git a/infra/charts/feast/charts/transformation-service/README.md b/infra/charts/feast/charts/transformation-service/README.md
index 64ebff9e9d4..758620d56a5 100644
--- a/infra/charts/feast/charts/transformation-service/README.md
+++ b/infra/charts/feast/charts/transformation-service/README.md
@@ -1,6 +1,6 @@
# transformation-service
- 
+ 
Transformation service: to compute on-demand features
@@ -13,7 +13,7 @@ Transformation service: to compute on-demand features
| envOverrides | object | `{}` | Extra environment variables to set |
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
| image.repository | string | `"feastdev/feature-transformation-server"` | Docker image for Transformation Server repository |
-| image.tag | string | `"0.31.0"` | Image tag |
+| image.tag | string | `"0.35.0"` | Image tag |
| nodeSelector | object | `{}` | Node labels for pod assignment |
| podLabels | object | `{}` | Labels to be added to Feast Serving pods |
| replicaCount | int | `1` | Number of pods that will be created |
@@ -25,4 +25,4 @@ Transformation service: to compute on-demand features
| service.type | string | `"ClusterIP"` | Kubernetes service type |
----------------------------------------------
-Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0)
+Autogenerated from chart metadata using [helm-docs v1.12.0](https://github.com/norwoodj/helm-docs/releases/v1.12.0)
diff --git a/infra/charts/feast/charts/transformation-service/values.yaml b/infra/charts/feast/charts/transformation-service/values.yaml
index ecd9221eebb..e45ef47288d 100644
--- a/infra/charts/feast/charts/transformation-service/values.yaml
+++ b/infra/charts/feast/charts/transformation-service/values.yaml
@@ -5,7 +5,7 @@ image:
# image.repository -- Docker image for Transformation Server repository
repository: feastdev/feature-transformation-server
# image.tag -- Image tag
- tag: 0.31.0
+ tag: 0.35.0
# image.pullPolicy -- Image pull policy
pullPolicy: IfNotPresent
diff --git a/infra/charts/feast/requirements.yaml b/infra/charts/feast/requirements.yaml
index 4d611f6fc8f..ec098f2f7b9 100644
--- a/infra/charts/feast/requirements.yaml
+++ b/infra/charts/feast/requirements.yaml
@@ -1,12 +1,12 @@
dependencies:
- name: feature-server
alias: feature-server
- version: 0.31.0
+ version: 0.35.0
condition: feature-server.enabled
repository: https://feast-helm-charts.storage.googleapis.com
- name: transformation-service
alias: transformation-service
- version: 0.31.0
+ version: 0.35.0
condition: transformation-service.enabled
repository: https://feast-helm-charts.storage.googleapis.com
- name: redis
diff --git a/infra/scripts/cleanup_ci.py b/infra/scripts/cleanup_ci.py
new file mode 100644
index 00000000000..262adf1e3eb
--- /dev/null
+++ b/infra/scripts/cleanup_ci.py
@@ -0,0 +1,50 @@
+from time import sleep
+import boto3
+from tqdm import tqdm
+from google.cloud import bigtable
+from google.cloud.bigtable import enums
+
+
+def cleanup_dynamo_ci():
+ db = boto3.resource("dynamodb")
+
+ num_to_delete = 0
+ all_tables = db.tables.all()
+ for table in all_tables:
+ if "integration_test" in table.name:
+ num_to_delete += 1
+ with tqdm(total=num_to_delete) as progress:
+ for table in all_tables:
+ if "integration_test" in table.name:
+ table.delete()
+ progress.update()
+ print(f"Deleted {num_to_delete} CI DynamoDB tables")
+
+
+def cleanup_bigtable_ci():
+ client = bigtable.Client(project="kf-feast", admin=True)
+ instance = client.instance("feast-integration-tests")
+ if instance.exists():
+ print(f"Deleted Bigtable CI instance")
+ instance.delete()
+
+ location_id = "us-central1-f"
+ serve_nodes = 1
+ storage_type = enums.StorageType.SSD
+ cluster = instance.cluster(
+ "feast-integration-tests-c1",
+ location_id=location_id,
+ serve_nodes=serve_nodes,
+ default_storage_type=storage_type,
+ )
+ instance.create(clusters=[cluster])
+ print(f"Created new Bigtable CI tables")
+
+
+def main() -> None:
+ cleanup_dynamo_ci()
+ cleanup_bigtable_ci()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/infra/scripts/cleanup_dynamo_ci.py b/infra/scripts/cleanup_dynamo_ci.py
deleted file mode 100644
index 2dda36cc5a5..00000000000
--- a/infra/scripts/cleanup_dynamo_ci.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import boto3
-from tqdm import tqdm
-
-
-def main() -> None:
- db = boto3.resource("dynamodb")
-
- num_to_delete = 0
- all_tables = db.tables.all()
- for table in all_tables:
- if "integration_test" in table.name:
- num_to_delete += 1
- with tqdm(total=num_to_delete) as progress:
- for table in all_tables:
- if "integration_test" in table.name:
- table.delete()
- progress.update()
- print(f"Deleted {num_to_delete} CI DynamoDB tables")
-
-
-if __name__ == "__main__":
- main()
diff --git a/infra/templates/README.md.jinja2 b/infra/templates/README.md.jinja2
index 47779d4eb7f..1cce08ecfac 100644
--- a/infra/templates/README.md.jinja2
+++ b/infra/templates/README.md.jinja2
@@ -25,7 +25,7 @@ Feast allows ML platform teams to:
* **Avoid data leakage** by generating point-in-time correct feature sets so data scientists can focus on feature engineering rather than debugging error-prone dataset joining logic. This ensure that future feature values do not leak to models during training.
* **Decouple ML from data infrastructure** by providing a single data access layer that abstracts feature storage from feature retrieval, ensuring models remain portable as you move from training models to serving models, from batch models to realtime models, and from one data infra system to another.
-Please see our [documentation](https://docs.feast.dev/) for more information about the project, or sign up for an [email newsletter](https://feast.dev/).
+Please see our [documentation](https://docs.feast.dev/) for more information about the project.
## 📐 Architecture

@@ -149,7 +149,6 @@ Please refer to the official documentation at [Documentation](https://docs.feast
* [Tutorials](https://docs.feast.dev/tutorials/tutorials-overview)
* [Running Feast with Snowflake/GCP/AWS](https://docs.feast.dev/how-to-guides/feast-snowflake-gcp-aws)
* [Change Log](https://github.com/feast-dev/feast/blob/master/CHANGELOG.md)
- * [Slack (#Feast)](https://slack.feast.dev/)
## 👋 Contributing
Feast is a community project and is still under active development. Please have a look at our contributing and development guides if you want to contribute to the project:
diff --git a/java/pom.xml b/java/pom.xml
index edcd383e5b3..59c67337842 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -35,7 +35,7 @@
- 0.31.0
+ 0.35.0
https://github.com/feast-dev/feast
UTF-8
@@ -61,7 +61,7 @@
1.5.24
3.14.7
3.10
- 2.12.6
+ 2.14.0
2.3.1
1.3.2
2.0.1.Final
diff --git a/java/serving/pom.xml b/java/serving/pom.xml
index 8f0cf407e96..19e54e1362b 100644
--- a/java/serving/pom.xml
+++ b/java/serving/pom.xml
@@ -243,6 +243,12 @@
1.12.261
+
+ com.amazonaws
+ aws-java-sdk-sts
+ 1.12.476
+
+
com.adobe.testing
s3mock-testcontainers
@@ -268,7 +274,7 @@
org.apache.avro
avro
- 1.10.2
+ 1.11.3
diff --git a/java/serving/src/main/java/feast/serving/service/config/ServingServiceV2Module.java b/java/serving/src/main/java/feast/serving/service/config/ServingServiceV2Module.java
index 564159ceed3..8beb91e4859 100644
--- a/java/serving/src/main/java/feast/serving/service/config/ServingServiceV2Module.java
+++ b/java/serving/src/main/java/feast/serving/service/config/ServingServiceV2Module.java
@@ -54,7 +54,6 @@ public ServingServiceV2 registryBasedServingServiceV2(
break;
case REDIS:
RedisClientAdapter redisClient = RedisClient.create(store.getRedisConfig());
- log.info("Created EntityKeySerializerV2");
retriever =
new RedisOnlineRetriever(
applicationProperties.getFeast().getProject(),
@@ -69,8 +68,6 @@ public ServingServiceV2 registryBasedServingServiceV2(
store.getType()));
}
- log.info("Working Directory = " + System.getProperty("user.dir"));
-
final OnlineTransformationService onlineTransformationService =
new OnlineTransformationService(
applicationProperties.getFeast().getTransformationServiceEndpoint(),
diff --git a/java/serving/src/test/resources/docker-compose/feast10/requirements.txt b/java/serving/src/test/resources/docker-compose/feast10/requirements.txt
index 94e4771de2a..6ba2c53d817 100644
--- a/java/serving/src/test/resources/docker-compose/feast10/requirements.txt
+++ b/java/serving/src/test/resources/docker-compose/feast10/requirements.txt
@@ -1,5 +1,5 @@
# for source generation
-pyarrow==6.0.0
+pyarrow==14.0.1
# temp fixes
proto-plus
diff --git a/protos/feast/registry/RegistryServer.proto b/protos/feast/registry/RegistryServer.proto
new file mode 100644
index 00000000000..3e7773e89a4
--- /dev/null
+++ b/protos/feast/registry/RegistryServer.proto
@@ -0,0 +1,230 @@
+syntax = "proto3";
+
+package feast.registry;
+
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/empty.proto";
+import "feast/core/Registry.proto";
+import "feast/core/Entity.proto";
+import "feast/core/DataSource.proto";
+import "feast/core/FeatureView.proto";
+import "feast/core/RequestFeatureView.proto";
+import "feast/core/StreamFeatureView.proto";
+import "feast/core/OnDemandFeatureView.proto";
+import "feast/core/FeatureService.proto";
+import "feast/core/SavedDataset.proto";
+import "feast/core/ValidationProfile.proto";
+import "feast/core/InfraObject.proto";
+
+service RegistryServer{
+ // Entity RPCs
+ rpc GetEntity (GetEntityRequest) returns (feast.core.Entity) {}
+ rpc ListEntities (ListEntitiesRequest) returns (ListEntitiesResponse) {}
+
+ // DataSource RPCs
+ rpc GetDataSource (GetDataSourceRequest) returns (feast.core.DataSource) {}
+ rpc ListDataSources (ListDataSourcesRequest) returns (ListDataSourcesResponse) {}
+
+ // FeatureView RPCs
+ rpc GetFeatureView (GetFeatureViewRequest) returns (feast.core.FeatureView) {}
+ rpc ListFeatureViews (ListFeatureViewsRequest) returns (ListFeatureViewsResponse) {}
+
+ // RequestFeatureView RPCs
+ rpc GetRequestFeatureView (GetRequestFeatureViewRequest) returns (feast.core.RequestFeatureView) {}
+ rpc ListRequestFeatureViews (ListRequestFeatureViewsRequest) returns (ListRequestFeatureViewsResponse) {}
+
+ // StreamFeatureView RPCs
+ rpc GetStreamFeatureView (GetStreamFeatureViewRequest) returns (feast.core.StreamFeatureView) {}
+ rpc ListStreamFeatureViews (ListStreamFeatureViewsRequest) returns (ListStreamFeatureViewsResponse) {}
+
+ // OnDemandFeatureView RPCs
+ rpc GetOnDemandFeatureView (GetOnDemandFeatureViewRequest) returns (feast.core.OnDemandFeatureView) {}
+ rpc ListOnDemandFeatureViews (ListOnDemandFeatureViewsRequest) returns (ListOnDemandFeatureViewsResponse) {}
+
+ // FeatureService RPCs
+ rpc GetFeatureService (GetFeatureServiceRequest) returns (feast.core.FeatureService) {}
+ rpc ListFeatureServices (ListFeatureServicesRequest) returns (ListFeatureServicesResponse) {}
+
+ // SavedDataset RPCs
+ rpc GetSavedDataset (GetSavedDatasetRequest) returns (feast.core.SavedDataset) {}
+ rpc ListSavedDatasets (ListSavedDatasetsRequest) returns (ListSavedDatasetsResponse) {}
+
+ // ValidationReference RPCs
+ rpc GetValidationReference (GetValidationReferenceRequest) returns (feast.core.ValidationReference) {}
+ rpc ListValidationReferences (ListValidationReferencesRequest) returns (ListValidationReferencesResponse) {}
+
+ rpc ListProjectMetadata (ListProjectMetadataRequest) returns (ListProjectMetadataResponse) {}
+ rpc GetInfra (GetInfraRequest) returns (feast.core.Infra) {}
+ rpc Refresh (RefreshRequest) returns (google.protobuf.Empty) {}
+ rpc Proto (google.protobuf.Empty) returns (feast.core.Registry) {}
+
+}
+
+message RefreshRequest {
+ string project = 1;
+}
+
+message GetInfraRequest {
+ string project = 1;
+ bool allow_cache = 2;
+}
+
+message ListProjectMetadataRequest {
+ string project = 1;
+ bool allow_cache = 2;
+}
+
+message ListProjectMetadataResponse {
+ repeated feast.core.ProjectMetadata project_metadata = 1;
+}
+
+message GetEntityRequest {
+ string name = 1;
+ string project = 2;
+ bool allow_cache = 3;
+}
+
+message ListEntitiesRequest {
+ string project = 1;
+ bool allow_cache = 2;
+}
+
+message ListEntitiesResponse {
+ repeated feast.core.Entity entities = 1;
+}
+
+// DataSources
+
+message GetDataSourceRequest {
+ string name = 1;
+ string project = 2;
+ bool allow_cache = 3;
+}
+
+message ListDataSourcesRequest {
+ string project = 1;
+ bool allow_cache = 2;
+}
+
+message ListDataSourcesResponse {
+ repeated feast.core.DataSource data_sources = 1;
+}
+
+// FeatureViews
+
+message GetFeatureViewRequest {
+ string name = 1;
+ string project = 2;
+ bool allow_cache = 3;
+}
+
+message ListFeatureViewsRequest {
+ string project = 1;
+ bool allow_cache = 2;
+}
+
+message ListFeatureViewsResponse {
+ repeated feast.core.FeatureView feature_views = 1;
+}
+
+// RequestFeatureView
+
+message GetRequestFeatureViewRequest {
+ string name = 1;
+ string project = 2;
+ bool allow_cache = 3;
+}
+
+message ListRequestFeatureViewsRequest {
+ string project = 1;
+ bool allow_cache = 2;
+}
+
+message ListRequestFeatureViewsResponse {
+ repeated feast.core.RequestFeatureView request_feature_views = 1;
+}
+
+// StreamFeatureView
+
+message GetStreamFeatureViewRequest {
+ string name = 1;
+ string project = 2;
+ bool allow_cache = 3;
+}
+
+message ListStreamFeatureViewsRequest {
+ string project = 1;
+ bool allow_cache = 2;
+}
+
+message ListStreamFeatureViewsResponse {
+ repeated feast.core.StreamFeatureView stream_feature_views = 1;
+}
+
+// OnDemandFeatureView
+
+message GetOnDemandFeatureViewRequest {
+ string name = 1;
+ string project = 2;
+ bool allow_cache = 3;
+}
+
+message ListOnDemandFeatureViewsRequest {
+ string project = 1;
+ bool allow_cache = 2;
+}
+
+message ListOnDemandFeatureViewsResponse {
+ repeated feast.core.OnDemandFeatureView on_demand_feature_views = 1;
+}
+
+// FeatureServices
+
+message GetFeatureServiceRequest {
+ string name = 1;
+ string project = 2;
+ bool allow_cache = 3;
+}
+
+message ListFeatureServicesRequest {
+ string project = 1;
+ bool allow_cache = 2;
+}
+
+message ListFeatureServicesResponse {
+ repeated feast.core.FeatureService feature_services = 1;
+}
+
+// SavedDataset
+
+message GetSavedDatasetRequest {
+ string name = 1;
+ string project = 2;
+ bool allow_cache = 3;
+}
+
+message ListSavedDatasetsRequest {
+ string project = 1;
+ bool allow_cache = 2;
+}
+
+message ListSavedDatasetsResponse {
+ repeated feast.core.SavedDataset saved_datasets = 1;
+}
+
+// ValidationReference
+
+message GetValidationReferenceRequest {
+ string name = 1;
+ string project = 2;
+ bool allow_cache = 3;
+}
+
+message ListValidationReferencesRequest {
+ string project = 1;
+ bool allow_cache = 2;
+}
+
+message ListValidationReferencesResponse {
+ repeated feast.core.ValidationReference validation_references = 1;
+}
diff --git a/protos/feast/serving/GrpcServer.proto b/protos/feast/serving/GrpcServer.proto
new file mode 100644
index 00000000000..34edb4ebe9c
--- /dev/null
+++ b/protos/feast/serving/GrpcServer.proto
@@ -0,0 +1,30 @@
+syntax = "proto3";
+
+import "feast/serving/ServingService.proto";
+
+message PushRequest {
+ map features = 1;
+ string stream_feature_view = 2;
+ bool allow_registry_cache = 3;
+ string to = 4;
+}
+
+message PushResponse {
+ bool status = 1;
+}
+
+message WriteToOnlineStoreRequest {
+ map features = 1;
+ string feature_view_name = 2;
+ bool allow_registry_cache = 3;
+}
+
+message WriteToOnlineStoreResponse {
+ bool status = 1;
+}
+
+service GrpcFeatureServer {
+ rpc Push (PushRequest) returns (PushResponse) {};
+ rpc WriteToOnlineStore (WriteToOnlineStoreRequest) returns (WriteToOnlineStoreResponse);
+ rpc GetOnlineFeatures (feast.serving.GetOnlineFeaturesRequest) returns (feast.serving.GetOnlineFeaturesResponse);
+}
\ No newline at end of file
diff --git a/protos/feast/serving/ServingService.proto b/protos/feast/serving/ServingService.proto
index 0eef3cd883c..154d850099f 100644
--- a/protos/feast/serving/ServingService.proto
+++ b/protos/feast/serving/ServingService.proto
@@ -105,6 +105,8 @@ message GetOnlineFeaturesResponse {
repeated FieldStatus statuses = 2;
repeated google.protobuf.Timestamp event_timestamps = 3;
}
+
+ bool status = 3;
}
message GetOnlineFeaturesResponseMetadata {
diff --git a/sdk/python/feast/cli.py b/sdk/python/feast/cli.py
index 229cb992321..7ce8aaef2bc 100644
--- a/sdk/python/feast/cli.py
+++ b/sdk/python/feast/cli.py
@@ -18,16 +18,20 @@
from typing import List, Optional
import click
-import pkg_resources
import yaml
from colorama import Fore, Style
from dateutil import parser
+from importlib_metadata import version as importlib_version
from pygments import formatters, highlight, lexers
from feast import utils
-from feast.constants import DEFAULT_FEATURE_TRANSFORMATION_SERVER_PORT
+from feast.constants import (
+ DEFAULT_FEATURE_TRANSFORMATION_SERVER_PORT,
+ DEFAULT_REGISTRY_SERVER_PORT,
+)
from feast.errors import FeastObjectNotFoundException, FeastProviderLoginError
from feast.feature_view import FeatureView
+from feast.infra.contrib.grpc_server import get_grpc_server
from feast.on_demand_feature_view import OnDemandFeatureView
from feast.repo_config import load_repo_config
from feast.repo_operations import (
@@ -67,11 +71,12 @@ def format_options(self, ctx: click.Context, formatter: click.HelpFormatter):
)
@click.option(
"--log-level",
- default="info",
+ default="warning",
help="The logging level. One of DEBUG, INFO, WARNING, ERROR, and CRITICAL (case-insensitive).",
)
@click.option(
"--feature-store-yaml",
+ "-f",
help="Override the directory where the CLI should look for the feature_store.yaml file.",
)
@click.pass_context
@@ -85,8 +90,6 @@ def cli(
Feast CLI
For more information, see our public docs at https://docs.feast.dev/
-
- For any questions, you can reach us at https://slack.feast.dev/
"""
ctx.ensure_object(dict)
ctx.obj["CHDIR"] = Path.cwd() if chdir is None else Path(chdir).absolute()
@@ -121,7 +124,7 @@ def version():
"""
Display Feast SDK version
"""
- print(f'Feast SDK Version: "{pkg_resources.get_distribution("feast")}"')
+ print(f'Feast SDK Version: "{importlib_version("feast")}"')
@cli.command()
@@ -664,6 +667,14 @@ def init_command(project_directory, minimal: bool, template: str):
show_default=True,
help="Timeout for keep alive",
)
+@click.option(
+ "--registry_ttl_sec",
+ "-r",
+ help="Number of seconds after which the registry is refreshed",
+ type=click.INT,
+ default=5,
+ show_default=True,
+)
@click.pass_context
def serve_command(
ctx: click.Context,
@@ -674,6 +685,7 @@ def serve_command(
no_feature_log: bool,
workers: int,
keep_alive_timeout: int,
+ registry_ttl_sec: int = 5,
):
"""Start a feature server locally on a given port."""
store = create_feature_store(ctx)
@@ -686,9 +698,49 @@ def serve_command(
no_feature_log=no_feature_log,
workers=workers,
keep_alive_timeout=keep_alive_timeout,
+ registry_ttl_sec=registry_ttl_sec,
)
+@cli.command("listen")
+@click.option(
+ "--address",
+ "-a",
+ type=click.STRING,
+ default="localhost:50051",
+ show_default=True,
+ help="Address of the gRPC server",
+)
+@click.option(
+ "--max_workers",
+ "-w",
+ type=click.INT,
+ default=10,
+ show_default=False,
+ help="The maximum number of threads that can be used to execute the gRPC calls",
+)
+@click.option(
+ "--registry_ttl_sec",
+ "-r",
+ help="Number of seconds after which the registry is refreshed",
+ type=click.INT,
+ default=5,
+ show_default=True,
+)
+@click.pass_context
+def listen_command(
+ ctx: click.Context,
+ address: str,
+ max_workers: int,
+ registry_ttl_sec: int,
+):
+ """Start a gRPC feature server to ingest streaming features on given address"""
+ store = create_feature_store(ctx)
+ server = get_grpc_server(address, store, max_workers, registry_ttl_sec)
+ server.start()
+ server.wait_for_termination()
+
+
@cli.command("serve_transformations")
@click.option(
"--port",
@@ -705,6 +757,22 @@ def serve_transformations_command(ctx: click.Context, port: int):
store.serve_transformations(port)
+@cli.command("serve_registry")
+@click.option(
+ "--port",
+ "-p",
+ type=click.INT,
+ default=DEFAULT_REGISTRY_SERVER_PORT,
+ help="Specify a port for the server",
+)
+@click.pass_context
+def serve_registry_command(ctx: click.Context, port: int):
+ """Start a registry server locally on a given port."""
+ store = create_feature_store(ctx)
+
+ store.serve_registry(port)
+
+
@cli.command("validate")
@click.option(
"--feature-service",
diff --git a/sdk/python/feast/constants.py b/sdk/python/feast/constants.py
index 574d79f4167..c022ecba557 100644
--- a/sdk/python/feast/constants.py
+++ b/sdk/python/feast/constants.py
@@ -44,5 +44,8 @@
# Default FTS port
DEFAULT_FEATURE_TRANSFORMATION_SERVER_PORT = 6569
+# Default registry server port
+DEFAULT_REGISTRY_SERVER_PORT = 6570
+
# Environment variable for feature server docker image tag
DOCKER_IMAGE_TAG_ENV_NAME: str = "FEAST_SERVER_DOCKER_IMAGE_TAG"
diff --git a/sdk/python/feast/data_source.py b/sdk/python/feast/data_source.py
index b7ce19aad9b..3421fd5d309 100644
--- a/sdk/python/feast/data_source.py
+++ b/sdk/python/feast/data_source.py
@@ -11,7 +11,6 @@
# 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.
-
import enum
import warnings
from abc import ABC, abstractmethod
@@ -485,12 +484,12 @@ def to_proto(self) -> DataSourceProto:
return data_source_proto
def validate(self, config: RepoConfig):
- pass
+ raise NotImplementedError
def get_table_column_names_and_types(
self, config: RepoConfig
) -> Iterable[Tuple[str, str]]:
- pass
+ raise NotImplementedError
@staticmethod
def source_datatype_to_feast_value_type() -> Callable[[str], ValueType]:
@@ -534,12 +533,12 @@ def __init__(
self.schema = schema
def validate(self, config: RepoConfig):
- pass
+ raise NotImplementedError
def get_table_column_names_and_types(
self, config: RepoConfig
) -> Iterable[Tuple[str, str]]:
- pass
+ raise NotImplementedError
def __eq__(self, other):
if not isinstance(other, RequestSource):
@@ -610,12 +609,12 @@ def source_datatype_to_feast_value_type() -> Callable[[str], ValueType]:
@typechecked
class KinesisSource(DataSource):
def validate(self, config: RepoConfig):
- pass
+ raise NotImplementedError
def get_table_column_names_and_types(
self, config: RepoConfig
) -> Iterable[Tuple[str, str]]:
- pass
+ raise NotImplementedError
@staticmethod
def from_proto(data_source: DataSourceProto):
@@ -639,7 +638,7 @@ def from_proto(data_source: DataSourceProto):
@staticmethod
def source_datatype_to_feast_value_type() -> Callable[[str], ValueType]:
- pass
+ raise NotImplementedError
def get_table_query_string(self) -> str:
raise NotImplementedError
@@ -772,12 +771,12 @@ def __hash__(self):
return super().__hash__()
def validate(self, config: RepoConfig):
- pass
+ raise NotImplementedError
def get_table_column_names_and_types(
self, config: RepoConfig
) -> Iterable[Tuple[str, str]]:
- pass
+ raise NotImplementedError
@staticmethod
def from_proto(data_source: DataSourceProto):
diff --git a/sdk/python/feast/feature_server.py b/sdk/python/feast/feature_server.py
index 3abca1d6e8e..618aefb2f28 100644
--- a/sdk/python/feast/feature_server.py
+++ b/sdk/python/feast/feature_server.py
@@ -1,9 +1,12 @@
import json
+import threading
import traceback
import warnings
+from typing import List, Optional
import gunicorn.app.base
import pandas as pd
+from dateutil import parser
from fastapi import FastAPI, HTTPException, Request, Response, status
from fastapi.logger import logger
from fastapi.params import Depends
@@ -11,7 +14,7 @@
from pydantic import BaseModel
import feast
-from feast import proto_json
+from feast import proto_json, utils
from feast.data_source import PushMode
from feast.errors import PushSourceNotFoundException
from feast.protos.feast.serving.ServingService_pb2 import GetOnlineFeaturesRequest
@@ -31,14 +34,48 @@ class PushFeaturesRequest(BaseModel):
to: str = "online"
-def get_app(store: "feast.FeatureStore"):
+class MaterializeRequest(BaseModel):
+ start_ts: str
+ end_ts: str
+ feature_views: Optional[List[str]] = None
+
+
+class MaterializeIncrementalRequest(BaseModel):
+ end_ts: str
+ feature_views: Optional[List[str]] = None
+
+
+def get_app(store: "feast.FeatureStore", registry_ttl_sec: int = 5):
proto_json.patch()
app = FastAPI()
+ # Asynchronously refresh registry, notifying shutdown and canceling the active timer if the app is shutting down
+ registry_proto = None
+ shutting_down = False
+ active_timer: Optional[threading.Timer] = None
async def get_body(request: Request):
return await request.body()
+ def async_refresh():
+ store.refresh_registry()
+ nonlocal registry_proto
+ registry_proto = store.registry.proto()
+ if shutting_down:
+ return
+ nonlocal active_timer
+ active_timer = threading.Timer(registry_ttl_sec, async_refresh)
+ active_timer.start()
+
+ @app.on_event("shutdown")
+ def shutdown_event():
+ nonlocal shutting_down
+ shutting_down = True
+ if active_timer:
+ active_timer.cancel()
+
+ async_refresh()
+
@app.post("/get-online-features")
def get_online_features(body=Depends(get_body)):
try:
@@ -134,12 +171,43 @@ def write_to_online_store(body=Depends(get_body)):
def health():
return Response(status_code=status.HTTP_200_OK)
+ @app.post("/materialize")
+ def materialize(body=Depends(get_body)):
+ try:
+ request = MaterializeRequest(**json.loads(body))
+ store.materialize(
+ utils.make_tzaware(parser.parse(request.start_ts)),
+ utils.make_tzaware(parser.parse(request.end_ts)),
+ request.feature_views,
+ )
+ except Exception as e:
+ # Print the original exception on the server side
+ logger.exception(traceback.format_exc())
+ # Raise HTTPException to return the error message to the client
+ raise HTTPException(status_code=500, detail=str(e))
+
+ @app.post("/materialize-incremental")
+ def materialize_incremental(body=Depends(get_body)):
+ try:
+ request = MaterializeIncrementalRequest(**json.loads(body))
+ store.materialize_incremental(
+ utils.make_tzaware(parser.parse(request.end_ts)), request.feature_views
+ )
+ except Exception as e:
+ # Print the original exception on the server side
+ logger.exception(traceback.format_exc())
+ # Raise HTTPException to return the error message to the client
+ raise HTTPException(status_code=500, detail=str(e))
+
return app
class FeastServeApplication(gunicorn.app.base.BaseApplication):
def __init__(self, store: "feast.FeatureStore", **options):
- self._app = get_app(store=store)
+ self._app = get_app(
+ store=store,
+ registry_ttl_sec=options.get("registry_ttl_sec", 5),
+ )
self._options = options
super().__init__()
@@ -161,6 +229,7 @@ def start_server(
no_access_log: bool,
workers: int,
keep_alive_timeout: int,
+ registry_ttl_sec: int = 5,
):
FeastServeApplication(
store=store,
@@ -168,4 +237,5 @@ def start_server(
accesslog=None if no_access_log else "-",
workers=workers,
keepalive=keep_alive_timeout,
+ registry_ttl_sec=registry_ttl_sec,
).run()
diff --git a/sdk/python/feast/feature_service.py b/sdk/python/feast/feature_service.py
index c3037a55da2..7ec923205a3 100644
--- a/sdk/python/feast/feature_service.py
+++ b/sdk/python/feast/feature_service.py
@@ -56,7 +56,7 @@ def __init__(
*,
name: str,
features: List[Union[FeatureView, OnDemandFeatureView]],
- tags: Dict[str, str] = None,
+ tags: Optional[Dict[str, str]] = None,
description: str = "",
owner: str = "",
logging_config: Optional[LoggingConfig] = None,
diff --git a/sdk/python/feast/feature_store.py b/sdk/python/feast/feature_store.py
index 70f7d3dcb70..4a53672b2e2 100644
--- a/sdk/python/feast/feature_store.py
+++ b/sdk/python/feast/feature_store.py
@@ -287,7 +287,11 @@ def _list_feature_views(
for fv in self._registry.list_feature_views(
self.project, allow_cache=allow_cache
):
- if hide_dummy_entity and fv.entities[0] == DUMMY_ENTITY_NAME:
+ if (
+ hide_dummy_entity
+ and fv.entities
+ and fv.entities[0] == DUMMY_ENTITY_NAME
+ ):
fv.entities = []
fv.entity_columns = []
feature_views.append(fv)
@@ -2224,6 +2228,7 @@ def serve(
no_feature_log: bool,
workers: int,
keep_alive_timeout: int,
+ registry_ttl_sec: int,
) -> None:
"""Start the feature consumption server locally on a given port."""
type_ = type_.lower()
@@ -2239,6 +2244,7 @@ def serve(
no_access_log=no_access_log,
workers=workers,
keep_alive_timeout=keep_alive_timeout,
+ registry_ttl_sec=registry_ttl_sec,
)
@log_exceptions_and_usage
@@ -2272,6 +2278,13 @@ def serve_ui(
root_path=root_path,
)
+ @log_exceptions_and_usage
+ def serve_registry(self, port: int) -> None:
+ """Start registry server locally on a given port."""
+ from feast import registry_server
+
+ registry_server.start_server(self, port)
+
@log_exceptions_and_usage
def serve_transformations(self, port: int) -> None:
"""Start the feature transformation server locally on a given port."""
diff --git a/sdk/python/feast/feature_view.py b/sdk/python/feast/feature_view.py
index e26759ba92e..f87ae7ab132 100644
--- a/sdk/python/feast/feature_view.py
+++ b/sdk/python/feast/feature_view.py
@@ -17,6 +17,7 @@
from typing import Dict, List, Optional, Tuple, Type
from google.protobuf.duration_pb2 import Duration
+from google.protobuf.message import Message
from typeguard import typechecked
from feast import utils
@@ -100,7 +101,7 @@ def __init__(
name: str,
source: DataSource,
schema: Optional[List[Field]] = None,
- entities: List[Entity] = None,
+ entities: Optional[List[Entity]] = None,
ttl: Optional[timedelta] = timedelta(days=0),
online: bool = True,
description: str = "",
@@ -274,7 +275,7 @@ def ensure_valid(self):
raise ValueError("Feature view has no entities.")
@property
- def proto_class(self) -> Type[FeatureViewProto]:
+ def proto_class(self) -> Type[Message]:
return FeatureViewProto
def with_join_key_map(self, join_key_map: Dict[str, str]):
diff --git a/sdk/python/feast/importer.py b/sdk/python/feast/importer.py
index bbd592101a6..938d29fe313 100644
--- a/sdk/python/feast/importer.py
+++ b/sdk/python/feast/importer.py
@@ -7,7 +7,7 @@
)
-def import_class(module_name: str, class_name: str, class_type: str = None):
+def import_class(module_name: str, class_name: str, class_type: str = ""):
"""
Dynamically loads and returns a class from a module.
diff --git a/sdk/python/feast/inference.py b/sdk/python/feast/inference.py
index d416763bd39..28a170172c8 100644
--- a/sdk/python/feast/inference.py
+++ b/sdk/python/feast/inference.py
@@ -1,5 +1,5 @@
import re
-from typing import List, Set, Union
+from typing import List, Optional, Set, Union
from feast.data_source import DataSource, PushSource, RequestSource
from feast.entity import Entity
@@ -119,7 +119,10 @@ def update_feature_views_with_inferred_features_and_entities(
for fv in fvs:
join_keys = set(
- [entity_name_to_join_key_map[entity_name] for entity_name in fv.entities]
+ [
+ entity_name_to_join_key_map.get(entity_name)
+ for entity_name in fv.entities
+ ]
)
# Fields whose names match a join key are considered to be entity columns; all
@@ -137,7 +140,10 @@ def update_feature_views_with_inferred_features_and_entities(
# Respect the `value_type` attribute of the entity, if it is specified.
for entity_name in fv.entities:
- entity = entity_name_to_entity_map[entity_name]
+ entity = entity_name_to_entity_map.get(entity_name)
+ # pass when entity does not exist. Entityless feature view case
+ if entity is None:
+ continue
if (
entity.join_key
not in [entity_column.name for entity_column in fv.entity_columns]
@@ -181,7 +187,7 @@ def update_feature_views_with_inferred_features_and_entities(
def _infer_features_and_entities(
fv: FeatureView,
- join_keys: Set[str],
+ join_keys: Set[Optional[str]],
run_inference_for_features,
config,
) -> None:
diff --git a/sdk/python/feast/infra/contrib/grpc_server.py b/sdk/python/feast/infra/contrib/grpc_server.py
new file mode 100644
index 00000000000..27ac45e77cc
--- /dev/null
+++ b/sdk/python/feast/infra/contrib/grpc_server.py
@@ -0,0 +1,148 @@
+import logging
+import threading
+from concurrent import futures
+from typing import Optional
+
+import grpc
+import pandas as pd
+from grpc_health.v1 import health, health_pb2_grpc
+
+from feast.data_source import PushMode
+from feast.errors import FeatureServiceNotFoundException, PushSourceNotFoundException
+from feast.feature_store import FeatureStore
+from feast.protos.feast.serving.GrpcServer_pb2 import (
+ PushResponse,
+ WriteToOnlineStoreResponse,
+)
+from feast.protos.feast.serving.GrpcServer_pb2_grpc import (
+ GrpcFeatureServerServicer,
+ add_GrpcFeatureServerServicer_to_server,
+)
+from feast.protos.feast.serving.ServingService_pb2 import (
+ GetOnlineFeaturesRequest,
+ GetOnlineFeaturesResponse,
+)
+
+logger = logging.getLogger(__name__)
+
+
+def parse(features):
+ df = {}
+ for i in features.keys():
+ df[i] = [features.get(i)]
+ return pd.DataFrame.from_dict(df)
+
+
+class GrpcFeatureServer(GrpcFeatureServerServicer):
+ fs: FeatureStore
+
+ _shuting_down: bool = False
+ _active_timer: Optional[threading.Timer] = None
+
+ def __init__(self, fs: FeatureStore, registry_ttl_sec: int = 5):
+ self.fs = fs
+ self.registry_ttl_sec = registry_ttl_sec
+ super().__init__()
+
+ self._async_refresh()
+
+ def Push(self, request, context):
+ try:
+ df = parse(request.features)
+ if request.to == "offline":
+ to = PushMode.OFFLINE
+ elif request.to == "online":
+ to = PushMode.ONLINE
+ elif request.to == "online_and_offline":
+ to = PushMode.ONLINE_AND_OFFLINE
+ else:
+ raise ValueError(
+ f"{request.to} is not a supported push format. Please specify one of these ['online', 'offline', "
+ f"'online_and_offline']."
+ )
+ self.fs.push(
+ push_source_name=request.push_source_name,
+ df=df,
+ allow_registry_cache=request.allow_registry_cache,
+ to=to,
+ )
+ except PushSourceNotFoundException as e:
+ logger.exception(str(e))
+ context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
+ context.set_details(str(e))
+ return PushResponse(status=False)
+ except Exception as e:
+ logger.exception(str(e))
+ context.set_code(grpc.StatusCode.INTERNAL)
+ context.set_details(str(e))
+ return PushResponse(status=False)
+ return PushResponse(status=True)
+
+ def WriteToOnlineStore(self, request, context):
+ logger.warning(
+ "write_to_online_store is deprecated. Please consider using Push instead"
+ )
+ try:
+ df = parse(request.features)
+ self.fs.write_to_online_store(
+ feature_view_name=request.feature_view_name,
+ df=df,
+ allow_registry_cache=request.allow_registry_cache,
+ )
+ except Exception as e:
+ logger.exception(str(e))
+ context.set_code(grpc.StatusCode.INTERNAL)
+ context.set_details(str(e))
+ return PushResponse(status=False)
+ return WriteToOnlineStoreResponse(status=True)
+
+ def GetOnlineFeatures(self, request: GetOnlineFeaturesRequest, context):
+ if request.HasField("feature_service"):
+ logger.info(f"Requesting feature service: {request.feature_service}")
+ try:
+ features = self.fs.get_feature_service(
+ request.feature_service, allow_cache=True
+ )
+ except FeatureServiceNotFoundException as e:
+ logger.error(f"Feature service {request.feature_service} not found")
+ context.set_code(grpc.StatusCode.INTERNAL)
+ context.set_details(str(e))
+ return GetOnlineFeaturesResponse()
+ else:
+ features = list(request.features.val)
+
+ result = self.fs._get_online_features(
+ features,
+ request.entities,
+ request.full_feature_names,
+ ).proto
+
+ return result
+
+ def _async_refresh(self):
+ self.fs.refresh_registry()
+ if self._shuting_down:
+ return
+ self._active_timer = threading.Timer(self.registry_ttl_sec, self._async_refresh)
+ self._active_timer.start()
+
+
+def get_grpc_server(
+ address: str,
+ fs: FeatureStore,
+ max_workers: int,
+ registry_ttl_sec: int,
+):
+ logger.info(f"Initializing gRPC server on {address}")
+ server = grpc.server(futures.ThreadPoolExecutor(max_workers=max_workers))
+ add_GrpcFeatureServerServicer_to_server(
+ GrpcFeatureServer(fs, registry_ttl_sec=registry_ttl_sec),
+ server,
+ )
+ health_servicer = health.HealthServicer(
+ experimental_non_blocking=True,
+ experimental_thread_pool=futures.ThreadPoolExecutor(max_workers=max_workers),
+ )
+ health_pb2_grpc.add_HealthServicer_to_server(health_servicer, server)
+ server.add_insecure_port(address)
+ return server
diff --git a/sdk/python/feast/infra/contrib/spark_kafka_processor.py b/sdk/python/feast/infra/contrib/spark_kafka_processor.py
index ea55d89988a..fc4a34f17bd 100644
--- a/sdk/python/feast/infra/contrib/spark_kafka_processor.py
+++ b/sdk/python/feast/infra/contrib/spark_kafka_processor.py
@@ -1,10 +1,11 @@
from types import MethodType
-from typing import List, Optional
+from typing import List, Optional, no_type_check
import pandas as pd
from pyspark.sql import DataFrame, SparkSession
from pyspark.sql.avro.functions import from_avro
from pyspark.sql.functions import col, from_json
+from pyspark.sql.streaming import StreamingQuery
from feast.data_format import AvroFormat, JsonFormat
from feast.data_source import KafkaSource, PushMode
@@ -63,12 +64,20 @@ def __init__(
self.join_keys = [fs.get_entity(entity).join_key for entity in sfv.entities]
super().__init__(fs=fs, sfv=sfv, data_source=sfv.stream_source)
- def ingest_stream_feature_view(self, to: PushMode = PushMode.ONLINE) -> None:
+ # Type hinting for data_source type.
+ # data_source type has been checked to be an instance of KafkaSource.
+ self.data_source: KafkaSource = self.data_source # type: ignore
+
+ def ingest_stream_feature_view(
+ self, to: PushMode = PushMode.ONLINE
+ ) -> StreamingQuery:
ingested_stream_df = self._ingest_stream_data()
transformed_df = self._construct_transformation_plan(ingested_stream_df)
online_store_query = self._write_stream_data(transformed_df, to)
return online_store_query
+ # In the line 64 of __init__(), the "data_source" is assigned a stream_source (and has to be KafkaSource as in line 40).
+ @no_type_check
def _ingest_stream_data(self) -> StreamTable:
"""Only supports json and avro formats currently."""
if self.format == "json":
@@ -122,7 +131,7 @@ def _ingest_stream_data(self) -> StreamTable:
def _construct_transformation_plan(self, df: StreamTable) -> StreamTable:
return self.sfv.udf.__call__(df) if self.sfv.udf else df
- def _write_stream_data(self, df: StreamTable, to: PushMode):
+ def _write_stream_data(self, df: StreamTable, to: PushMode) -> StreamingQuery:
# Validation occurs at the fs.write_to_online_store() phase against the stream feature view schema.
def batch_write(row: DataFrame, batch_id: int):
rows: pd.DataFrame = row.toPandas()
diff --git a/sdk/python/feast/infra/contrib/stream_processor.py b/sdk/python/feast/infra/contrib/stream_processor.py
index 24817c82eaa..3f1fe085109 100644
--- a/sdk/python/feast/infra/contrib/stream_processor.py
+++ b/sdk/python/feast/infra/contrib/stream_processor.py
@@ -1,8 +1,9 @@
-from abc import ABC
+from abc import ABC, abstractmethod
from types import MethodType
-from typing import TYPE_CHECKING, Optional
+from typing import TYPE_CHECKING, Any, Optional
from pyspark.sql import DataFrame
+from typing_extensions import TypeAlias
from feast.data_source import DataSource, PushMode
from feast.importer import import_class
@@ -17,7 +18,7 @@
}
# TODO: support more types other than just Spark.
-StreamTable = DataFrame
+StreamTable: TypeAlias = DataFrame
class ProcessorConfig(FeastConfigBaseModel):
@@ -49,33 +50,39 @@ def __init__(
self.sfv = sfv
self.data_source = data_source
- def ingest_stream_feature_view(self, to: PushMode = PushMode.ONLINE) -> None:
+ @abstractmethod
+ def ingest_stream_feature_view(
+ self, to: PushMode = PushMode.ONLINE
+ ) -> Optional[Any]:
"""
Ingests data from the stream source attached to the stream feature view; transforms the data
and then persists it to the online store and/or offline store, depending on the 'to' parameter.
"""
- pass
+ raise NotImplementedError
+ @abstractmethod
def _ingest_stream_data(self) -> StreamTable:
"""
Ingests data into a StreamTable.
"""
- pass
+ raise NotImplementedError
+ @abstractmethod
def _construct_transformation_plan(self, table: StreamTable) -> StreamTable:
"""
Applies transformations on top of StreamTable object. Since stream engines use lazy
evaluation, the StreamTable will not be materialized until it is actually evaluated.
For example: df.collect() in spark or tbl.execute() in Flink.
"""
- pass
+ raise NotImplementedError
- def _write_stream_data(self, table: StreamTable, to: PushMode) -> None:
+ @abstractmethod
+ def _write_stream_data(self, table: StreamTable, to: PushMode) -> Optional[Any]:
"""
Launches a job to persist stream data to the online store and/or offline store, depending
on the 'to' parameter, and returns a handle for the job.
"""
- pass
+ raise NotImplementedError
def get_stream_processor_object(
diff --git a/sdk/python/feast/infra/feature_servers/aws_lambda/config.py b/sdk/python/feast/infra/feature_servers/aws_lambda/config.py
index 31dd879af6d..946831a18fb 100644
--- a/sdk/python/feast/infra/feature_servers/aws_lambda/config.py
+++ b/sdk/python/feast/infra/feature_servers/aws_lambda/config.py
@@ -1,5 +1,6 @@
+from typing import Literal
+
from pydantic import StrictBool, StrictStr
-from pydantic.typing import Literal
from feast.infra.feature_servers.base_config import BaseFeatureServerConfig
diff --git a/sdk/python/feast/infra/feature_servers/base_config.py b/sdk/python/feast/infra/feature_servers/base_config.py
index 756dd79b438..1a348032e17 100644
--- a/sdk/python/feast/infra/feature_servers/base_config.py
+++ b/sdk/python/feast/infra/feature_servers/base_config.py
@@ -30,5 +30,5 @@ class BaseFeatureServerConfig(FeastConfigBaseModel):
enabled: StrictBool = False
"""Whether the feature server should be launched."""
- feature_logging: Optional[FeatureLoggingConfig]
+ feature_logging: Optional[FeatureLoggingConfig] = None
""" Feature logging configuration """
diff --git a/sdk/python/feast/infra/feature_servers/gcp_cloudrun/config.py b/sdk/python/feast/infra/feature_servers/gcp_cloudrun/config.py
index 8d0c269cf5d..ddcbde7924a 100644
--- a/sdk/python/feast/infra/feature_servers/gcp_cloudrun/config.py
+++ b/sdk/python/feast/infra/feature_servers/gcp_cloudrun/config.py
@@ -1,5 +1,6 @@
+from typing import Literal
+
from pydantic import StrictBool
-from pydantic.typing import Literal
from feast.infra.feature_servers.base_config import BaseFeatureServerConfig
diff --git a/sdk/python/feast/infra/feature_servers/local_process/config.py b/sdk/python/feast/infra/feature_servers/local_process/config.py
index bb2e7bdf738..3d97912e4bd 100644
--- a/sdk/python/feast/infra/feature_servers/local_process/config.py
+++ b/sdk/python/feast/infra/feature_servers/local_process/config.py
@@ -1,4 +1,4 @@
-from pydantic.typing import Literal
+from typing import Literal
from feast.infra.feature_servers.base_config import BaseFeatureServerConfig
diff --git a/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile b/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile
index c95c515fb4b..4527c5b1566 100644
--- a/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile
+++ b/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile
@@ -1,15 +1,17 @@
FROM python:3.8
+# Input the feast version to install
+# This requires feast package to be available in pypi before building this image
+ARG VERSION
+
RUN apt update && \
apt install -y \
jq \
python3-dev \
- default-libmysqlclient-dev \
build-essential
RUN pip install pip --upgrade
-RUN pip install "feast[aws,gcp,snowflake,redis,go,mysql,postgres]"
-
+RUN pip install "feast[aws,gcp,snowflake,redis,go,mysql,postgres]==${VERSION}"
RUN apt update
RUN apt install -y -V ca-certificates lsb-release wget
diff --git a/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile.dev b/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile.dev
index ecbc199a5b9..015e3c7ee82 100644
--- a/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile.dev
+++ b/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile.dev
@@ -1,20 +1,23 @@
FROM python:3.8
+# Input the feast version to install
+# This requires feast package to be available in pypi before building this image
+ARG VERSION
+
RUN apt update && \
apt install -y \
jq \
python3-dev \
- default-libmysqlclient-dev \
build-essential
RUN pip install pip --upgrade
COPY . .
-RUN pip install "feast[aws,gcp,snowflake,redis,go,mysql,postgres]"
+RUN pip install "feast[aws,gcp,snowflake,redis,go,mysql,postgres]==${VERSION}"
RUN apt update
RUN apt install -y -V ca-certificates lsb-release wget
RUN wget https://apache.jfrog.io/artifactory/arrow/$(lsb_release --id --short | tr 'A-Z' 'a-z')/apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb
RUN apt install -y -V ./apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb
RUN apt update
-RUN apt -y install libarrow-dev
\ No newline at end of file
+RUN apt -y install libarrow-dev
diff --git a/sdk/python/feast/infra/materialization/contrib/bytewax/Dockerfile b/sdk/python/feast/infra/materialization/contrib/bytewax/Dockerfile
index 963924f38d8..a7d0af9b416 100644
--- a/sdk/python/feast/infra/materialization/contrib/bytewax/Dockerfile
+++ b/sdk/python/feast/infra/materialization/contrib/bytewax/Dockerfile
@@ -25,5 +25,5 @@ COPY README.md README.md
# git dir to infer the version of feast we're installing.
# https://github.com/pypa/setuptools_scm#usage-from-docker
# I think it also assumes that this dockerfile is being built from the root of the directory.
-RUN --mount=source=.git,target=.git,type=bind pip3 install --no-cache-dir -e '.[aws,gcp,bytewax]'
+RUN --mount=source=.git,target=.git,type=bind pip3 install --no-cache-dir '.[aws,gcp,bytewax,snowflake,postgres]'
diff --git a/sdk/python/feast/infra/materialization/contrib/bytewax/bytewax_materialization_dataflow.py b/sdk/python/feast/infra/materialization/contrib/bytewax/bytewax_materialization_dataflow.py
index bf5229303ab..6fc53b67f2f 100644
--- a/sdk/python/feast/infra/materialization/contrib/bytewax/bytewax_materialization_dataflow.py
+++ b/sdk/python/feast/infra/materialization/contrib/bytewax/bytewax_materialization_dataflow.py
@@ -1,17 +1,20 @@
+import logging
+import os
from typing import List
import pyarrow as pa
import pyarrow.parquet as pq
-import s3fs
from bytewax.dataflow import Dataflow # type: ignore
from bytewax.execution import cluster_main
-from bytewax.inputs import ManualInputConfig, distribute
+from bytewax.inputs import ManualInputConfig
from bytewax.outputs import ManualOutputConfig
-from tqdm import tqdm
from feast import FeatureStore, FeatureView, RepoConfig
from feast.utils import _convert_arrow_to_proto, _run_pyarrow_field_mapping
+logger = logging.getLogger(__name__)
+DEFAULT_BATCH_SIZE = 1000
+
class BytewaxMaterializationDataflow:
def __init__(
@@ -19,57 +22,56 @@ def __init__(
config: RepoConfig,
feature_view: FeatureView,
paths: List[str],
+ worker_index: int,
):
self.config = config
self.feature_store = FeatureStore(config=config)
self.feature_view = feature_view
+ self.worker_index = worker_index
self.paths = paths
+ self.mini_batch_size = int(
+ os.getenv("BYTEWAX_MINI_BATCH_SIZE", DEFAULT_BATCH_SIZE)
+ )
self._run_dataflow()
def process_path(self, path):
- fs = s3fs.S3FileSystem()
- dataset = pq.ParquetDataset(path, filesystem=fs, use_legacy_dataset=False)
+ logger.info(f"Processing path {path}")
+ dataset = pq.ParquetDataset(path, use_legacy_dataset=False)
batches = []
for fragment in dataset.fragments:
- for batch in fragment.to_table().to_batches():
+ for batch in fragment.to_table().to_batches(
+ max_chunksize=self.mini_batch_size
+ ):
batches.append(batch)
return batches
def input_builder(self, worker_index, worker_count, _state):
- worker_paths = distribute(self.paths, worker_index, worker_count)
- for path in worker_paths:
- yield None, path
-
- return
+ return [(None, self.paths[self.worker_index])]
def output_builder(self, worker_index, worker_count):
- def output_fn(batch):
- table = pa.Table.from_batches([batch])
+ def output_fn(mini_batch):
+ table: pa.Table = pa.Table.from_batches([mini_batch])
if self.feature_view.batch_source.field_mapping is not None:
table = _run_pyarrow_field_mapping(
table, self.feature_view.batch_source.field_mapping
)
-
join_key_to_value_type = {
entity.name: entity.dtype.to_value_type()
for entity in self.feature_view.entity_columns
}
-
rows_to_write = _convert_arrow_to_proto(
table, self.feature_view, join_key_to_value_type
)
- provider = self.feature_store._get_provider()
- with tqdm(total=len(rows_to_write)) as progress:
- provider.online_write_batch(
- config=self.config,
- table=self.feature_view,
- data=rows_to_write,
- progress=progress.update,
- )
+ self.feature_store._get_provider().online_write_batch(
+ config=self.config,
+ table=self.feature_view,
+ data=rows_to_write,
+ progress=None,
+ )
return output_fn
diff --git a/sdk/python/feast/infra/materialization/contrib/bytewax/bytewax_materialization_engine.py b/sdk/python/feast/infra/materialization/contrib/bytewax/bytewax_materialization_engine.py
index b222128bbbe..060a47ce585 100644
--- a/sdk/python/feast/infra/materialization/contrib/bytewax/bytewax_materialization_engine.py
+++ b/sdk/python/feast/infra/materialization/contrib/bytewax/bytewax_materialization_engine.py
@@ -1,11 +1,14 @@
+import logging
import uuid
from datetime import datetime
+from time import sleep
from typing import Callable, List, Literal, Sequence, Union
import yaml
from kubernetes import client
from kubernetes import config as k8s_config
from kubernetes import utils
+from kubernetes.client.exceptions import ApiException
from kubernetes.utils import FailToCreateError
from pydantic import StrictStr
from tqdm import tqdm
@@ -16,6 +19,7 @@
from feast.infra.materialization.batch_materialization_engine import (
BatchMaterializationEngine,
MaterializationJob,
+ MaterializationJobStatus,
MaterializationTask,
)
from feast.infra.offline_stores.offline_store import OfflineStore
@@ -23,10 +27,12 @@
from feast.infra.registry.base_registry import BaseRegistry
from feast.repo_config import FeastConfigBaseModel
from feast.stream_feature_view import StreamFeatureView
-from feast.utils import _get_column_names, get_default_yaml_file_path
+from feast.utils import _get_column_names
from .bytewax_materialization_job import BytewaxMaterializationJob
+logger = logging.getLogger(__name__)
+
class BytewaxMaterializationEngineConfig(FeastConfigBaseModel):
"""Batch Materialization Engine config for Bytewax"""
@@ -61,6 +67,30 @@ class BytewaxMaterializationEngineConfig(FeastConfigBaseModel):
include_security_context_capabilities: bool = True
""" (optional) Include security context capabilities in the init and job container spec """
+ labels: dict = {}
+ """ (optional) additional labels to append to kubernetes objects """
+
+ max_parallelism: int = 10
+ """ (optional) Maximum number of pods allowed to run in parallel"""
+
+ synchronous: bool = False
+ """ (optional) If true, wait for materialization for one feature to complete before moving to the next """
+
+ retry_limit: int = 2
+ """ (optional) Maximum number of times to retry a materialization worker pod"""
+
+ mini_batch_size: int = 1000
+ """ (optional) Number of rows to process per write operation (default 1000)"""
+
+ active_deadline_seconds: int = 86400
+ """ (optional) Maximum amount of time a materialization job is allowed to run"""
+
+ job_batch_size: int = 100
+ """ (optional) Maximum number of pods to process per job. Only applies to synchronous materialization"""
+
+ print_pod_logs_on_failure: bool = True
+ """(optional) Print pod logs on job failure. Only applies to synchronous materialization"""
+
class BytewaxMaterializationEngine(BatchMaterializationEngine):
def __init__(
@@ -81,8 +111,7 @@ def __init__(
self.offline_store = offline_store
self.online_store = online_store
- # TODO: Configure k8s here
- k8s_config.load_kube_config()
+ k8s_config.load_config()
self.k8s_client = client.api_client.ApiClient()
self.v1 = client.CoreV1Api(self.k8s_client)
@@ -164,8 +193,98 @@ def _materialize_one(
)
paths = offline_job.to_remote_storage()
+ if self.batch_engine_config.synchronous:
+ offset = 0
+ total_pods = len(paths)
+ batch_size = self.batch_engine_config.job_batch_size
+ if batch_size < 1:
+ raise ValueError("job_batch_size must be a value greater than 0")
+ if batch_size < self.batch_engine_config.max_parallelism:
+ logger.warning(
+ "job_batch_size is less than max_parallelism. Setting job_batch_size = max_parallelism"
+ )
+ batch_size = self.batch_engine_config.max_parallelism
+
+ while True:
+ next_offset = min(offset + batch_size, total_pods)
+ job = self._await_path_materialization(
+ paths[offset:next_offset],
+ feature_view,
+ offset,
+ next_offset,
+ total_pods,
+ )
+ offset += batch_size
+ if (
+ offset >= total_pods
+ or job.status() == MaterializationJobStatus.ERROR
+ ):
+ break
+ else:
+ job_id = str(uuid.uuid4())
+ job = self._create_kubernetes_job(job_id, paths, feature_view)
+
+ return job
+
+ def _await_path_materialization(
+ self, paths, feature_view, batch_start, batch_end, total_pods
+ ):
job_id = str(uuid.uuid4())
- return self._create_kubernetes_job(job_id, paths, feature_view)
+ job = self._create_kubernetes_job(job_id, paths, feature_view)
+
+ try:
+ while job.status() in (
+ MaterializationJobStatus.WAITING,
+ MaterializationJobStatus.RUNNING,
+ ):
+ logger.info(
+ f"{feature_view.name} materialization for pods {batch_start}-{batch_end} "
+ f"(of {total_pods}) running..."
+ )
+ sleep(30)
+ logger.info(
+ f"{feature_view.name} materialization for pods {batch_start}-{batch_end} "
+ f"(of {total_pods}) complete with status {job.status()}"
+ )
+ except BaseException as e:
+ logger.info(f"Deleting job {job.job_id()}")
+ try:
+ self.batch_v1.delete_namespaced_job(job.job_id(), self.namespace)
+ except ApiException as ae:
+ logger.warning(f"Could not delete job due to API Error: {ae.body}")
+ raise e
+ finally:
+ logger.info(f"Deleting configmap {self._configmap_name(job_id)}")
+ try:
+ self.v1.delete_namespaced_config_map(
+ self._configmap_name(job_id), self.namespace
+ )
+ except ApiException as ae:
+ logger.warning(
+ f"Could not delete configmap due to API Error: {ae.body}"
+ )
+
+ if (
+ job.status() == MaterializationJobStatus.ERROR
+ and self.batch_engine_config.print_pod_logs_on_failure
+ ):
+ self._print_pod_logs(job.job_id(), feature_view, batch_start)
+
+ return job
+
+ def _print_pod_logs(self, job_id, feature_view, offset=0):
+ pods_list = self.v1.list_namespaced_pod(
+ namespace=self.namespace,
+ label_selector=f"job-name={job_id}",
+ ).items
+ for i, pod in enumerate(pods_list):
+ logger.info(f"Logging output for {feature_view.name} pod {offset+i}")
+ try:
+ logger.info(
+ self.v1.read_namespaced_pod_log(pod.metadata.name, self.namespace)
+ )
+ except ApiException as e:
+ logger.warning(f"Could not retrieve pod logs due to: {e.body}")
def _create_kubernetes_job(self, job_id, paths, feature_view):
try:
@@ -179,6 +298,9 @@ def _create_kubernetes_job(self, job_id, paths, feature_view):
len(paths), # Create a pod for each parquet file
self.batch_engine_config.env,
)
+ logger.info(
+ f"Created job `dataflow-{job_id}` on namespace `{self.namespace}`"
+ )
except FailToCreateError as failures:
return BytewaxMaterializationJob(job_id, self.namespace, error=failures)
@@ -187,23 +309,19 @@ def _create_kubernetes_job(self, job_id, paths, feature_view):
def _create_configuration_map(self, job_id, paths, feature_view, namespace):
"""Create a Kubernetes configmap for this job"""
- repo_path = self.repo_config.repo_path
- assert repo_path
- feature_store_path = get_default_yaml_file_path(repo_path)
- feature_store_configuration = feature_store_path.read_text()
+ feature_store_configuration = yaml.dump(self.repo_config.dict())
materialization_config = yaml.dump(
{"paths": paths, "feature_view": feature_view.name}
)
+ labels = {"feast-bytewax-materializer": "configmap"}
configmap_manifest = {
"kind": "ConfigMap",
"apiVersion": "v1",
"metadata": {
- "name": f"feast-{job_id}",
- "labels": {
- "feast-bytewax-materializer": "configmap",
- },
+ "name": self._configmap_name(job_id),
+ "labels": {**labels, **self.batch_engine_config.labels},
},
"data": {
"feature_store.yaml": feature_store_configuration,
@@ -215,7 +333,10 @@ def _create_configuration_map(self, job_id, paths, feature_view, namespace):
body=configmap_manifest,
)
- def _create_job_definition(self, job_id, namespace, pods, env):
+ def _configmap_name(self, job_id):
+ return f"feast-{job_id}"
+
+ def _create_job_definition(self, job_id, namespace, pods, env, index_offset=0):
"""Create a kubernetes job definition."""
job_env = [
{"name": "RUST_BACKTRACE", "value": "full"},
@@ -239,7 +360,7 @@ def _create_job_definition(self, job_id, namespace, pods, env):
},
{
"name": "BYTEWAX_REPLICAS",
- "value": f"{pods}",
+ "value": "1",
},
{
"name": "BYTEWAX_KEEP_CONTAINER_ALIVE",
@@ -249,6 +370,10 @@ def _create_job_definition(self, job_id, namespace, pods, env):
"name": "BYTEWAX_STATEFULSET_NAME",
"value": f"dataflow-{job_id}",
},
+ {
+ "name": "BYTEWAX_MINI_BATCH_SIZE",
+ "value": str(self.batch_engine_config.mini_batch_size),
+ },
]
# Add any Feast configured environment variables
job_env.extend(env)
@@ -260,27 +385,27 @@ def _create_job_definition(self, job_id, namespace, pods, env):
"drop": ["ALL"],
}
+ job_labels = {"feast-bytewax-materializer": "job"}
+ pod_labels = {"feast-bytewax-materializer": "pod"}
job_definition = {
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": f"dataflow-{job_id}",
"namespace": namespace,
- "labels": {
- "feast-bytewax-materializer": "job",
- },
+ "labels": {**job_labels, **self.batch_engine_config.labels},
},
"spec": {
"ttlSecondsAfterFinished": 3600,
+ "backoffLimit": self.batch_engine_config.retry_limit,
"completions": pods,
- "parallelism": pods,
+ "parallelism": min(pods, self.batch_engine_config.max_parallelism),
+ "activeDeadlineSeconds": self.batch_engine_config.active_deadline_seconds,
"completionMode": "Indexed",
"template": {
"metadata": {
"annotations": self.batch_engine_config.annotations,
- "labels": {
- "feast-bytewax-materializer": "pod",
- },
+ "labels": {**pod_labels, **self.batch_engine_config.labels},
},
"spec": {
"restartPolicy": "Never",
@@ -296,7 +421,7 @@ def _create_job_definition(self, job_id, namespace, pods, env):
}
],
"image": "busybox",
- "imagePullPolicy": "Always",
+ "imagePullPolicy": "IfNotPresent",
"name": "init-hostfile",
"resources": {},
"securityContext": {
@@ -314,7 +439,7 @@ def _create_job_definition(self, job_id, namespace, pods, env):
},
{
"mountPath": "/var/feast/",
- "name": f"feast-{job_id}",
+ "name": self._configmap_name(job_id),
},
],
}
@@ -345,7 +470,7 @@ def _create_job_definition(self, job_id, namespace, pods, env):
{"mountPath": "/etc/bytewax", "name": "hostfile"},
{
"mountPath": "/var/feast/",
- "name": f"feast-{job_id}",
+ "name": self._configmap_name(job_id),
},
],
}
@@ -355,13 +480,13 @@ def _create_job_definition(self, job_id, namespace, pods, env):
{
"configMap": {
"defaultMode": 420,
- "name": f"feast-{job_id}",
+ "name": self._configmap_name(job_id),
},
"name": "python-files",
},
{
- "configMap": {"name": f"feast-{job_id}"},
- "name": f"feast-{job_id}",
+ "configMap": {"name": self._configmap_name(job_id)},
+ "name": self._configmap_name(job_id),
},
],
},
diff --git a/sdk/python/feast/infra/materialization/contrib/bytewax/bytewax_materialization_job.py b/sdk/python/feast/infra/materialization/contrib/bytewax/bytewax_materialization_job.py
index 77d2149eb5a..da969d5a880 100644
--- a/sdk/python/feast/infra/materialization/contrib/bytewax/bytewax_materialization_job.py
+++ b/sdk/python/feast/infra/materialization/contrib/bytewax/bytewax_materialization_job.py
@@ -35,12 +35,24 @@ def status(self):
if job_status.active is not None:
if job_status.completion_time is None:
return MaterializationJobStatus.RUNNING
- elif job_status.failed is not None:
- return MaterializationJobStatus.ERROR
- elif job_status.active is None and job_status.succeeded is not None:
- if job_status.conditions[0].type == "Complete":
+ else:
+ if (
+ job_status.completion_time is not None
+ and job_status.conditions[0].type == "Complete"
+ ):
return MaterializationJobStatus.SUCCEEDED
+ if (
+ job_status.conditions is not None
+ and job_status.conditions[0].type == "Failed"
+ ):
+ self._error = Exception(
+ f"Job {self.job_id()} failed with reason: "
+ f"{job_status.conditions[0].message}"
+ )
+ return MaterializationJobStatus.ERROR
+ return MaterializationJobStatus.WAITING
+
def should_be_retried(self):
return False
diff --git a/sdk/python/feast/infra/materialization/contrib/bytewax/dataflow.py b/sdk/python/feast/infra/materialization/contrib/bytewax/dataflow.py
index e3d95e2a75c..bbc32cc1651 100644
--- a/sdk/python/feast/infra/materialization/contrib/bytewax/dataflow.py
+++ b/sdk/python/feast/infra/materialization/contrib/bytewax/dataflow.py
@@ -1,3 +1,6 @@
+import logging
+import os
+
import yaml
from feast import FeatureStore, RepoConfig
@@ -6,11 +9,13 @@
)
if __name__ == "__main__":
+ logging.basicConfig(level=logging.INFO)
+
with open("/var/feast/feature_store.yaml") as f:
- feast_config = yaml.safe_load(f)
+ feast_config = yaml.load(f, Loader=yaml.Loader)
with open("/var/feast/bytewax_materialization_config.yaml") as b:
- bytewax_config = yaml.safe_load(b)
+ bytewax_config = yaml.load(b, Loader=yaml.Loader)
config = RepoConfig(**feast_config)
store = FeatureStore(config=config)
@@ -19,4 +24,5 @@
config,
store.get_feature_view(bytewax_config["feature_view"]),
bytewax_config["paths"],
+ int(os.environ["JOB_COMPLETION_INDEX"]),
)
diff --git a/sdk/python/feast/infra/materialization/contrib/spark/spark_materialization_engine.py b/sdk/python/feast/infra/materialization/contrib/spark/spark_materialization_engine.py
index ed4388aeb31..798d3a8e6f5 100644
--- a/sdk/python/feast/infra/materialization/contrib/spark/spark_materialization_engine.py
+++ b/sdk/python/feast/infra/materialization/contrib/spark/spark_materialization_engine.py
@@ -3,6 +3,7 @@
from typing import Callable, List, Literal, Optional, Sequence, Union, cast
import dill
+import pandas
import pandas as pd
import pyarrow
from tqdm import tqdm
@@ -178,9 +179,9 @@ def _materialize_one(
self.repo_config.batch_engine.partitions
)
- spark_df.foreachPartition(
- lambda x: _process_by_partition(x, spark_serialized_artifacts)
- )
+ spark_df.mapInPandas(
+ lambda x: _map_by_partition(x, spark_serialized_artifacts), "status int"
+ ).count() # dummy action to force evaluation
return SparkMaterializationJob(
job_id=job_id, status=MaterializationJobStatus.SUCCEEDED
@@ -225,38 +226,40 @@ def unserialize(self):
return feature_view, online_store, repo_config
-def _process_by_partition(rows, spark_serialized_artifacts: _SparkSerializedArtifacts):
- """Load pandas df to online store"""
-
- # convert to pyarrow table
- dicts = []
- for row in rows:
- dicts.append(row.asDict())
+def _map_by_partition(iterator, spark_serialized_artifacts: _SparkSerializedArtifacts):
+ for pdf in iterator:
+ if pdf.shape[0] == 0:
+ print("Skipping")
+ return
- df = pd.DataFrame.from_records(dicts)
- if df.shape[0] == 0:
- print("Skipping")
- return
+ table = pyarrow.Table.from_pandas(pdf)
- table = pyarrow.Table.from_pandas(df)
+ (
+ feature_view,
+ online_store,
+ repo_config,
+ ) = spark_serialized_artifacts.unserialize()
+
+ if feature_view.batch_source.field_mapping is not None:
+ table = _run_pyarrow_field_mapping(
+ table, feature_view.batch_source.field_mapping
+ )
- # unserialize artifacts
- feature_view, online_store, repo_config = spark_serialized_artifacts.unserialize()
+ join_key_to_value_type = {
+ entity.name: entity.dtype.to_value_type()
+ for entity in feature_view.entity_columns
+ }
- if feature_view.batch_source.field_mapping is not None:
- table = _run_pyarrow_field_mapping(
- table, feature_view.batch_source.field_mapping
+ rows_to_write = _convert_arrow_to_proto(
+ table, feature_view, join_key_to_value_type
+ )
+ online_store.online_write_batch(
+ repo_config,
+ feature_view,
+ rows_to_write,
+ lambda x: None,
)
- join_key_to_value_type = {
- entity.name: entity.dtype.to_value_type()
- for entity in feature_view.entity_columns
- }
-
- rows_to_write = _convert_arrow_to_proto(table, feature_view, join_key_to_value_type)
- online_store.online_write_batch(
- repo_config,
- feature_view,
- rows_to_write,
- lambda x: None,
- )
+ yield pd.DataFrame(
+ [pd.Series(range(1, 2))]
+ ) # dummy result because mapInPandas needs to return something
diff --git a/sdk/python/feast/infra/materialization/snowflake_engine.py b/sdk/python/feast/infra/materialization/snowflake_engine.py
index 36c42cd390c..62b23dfadef 100644
--- a/sdk/python/feast/infra/materialization/snowflake_engine.py
+++ b/sdk/python/feast/infra/materialization/snowflake_engine.py
@@ -7,7 +7,7 @@
import click
import pandas as pd
from colorama import Fore, Style
-from pydantic import Field, StrictStr
+from pydantic import ConfigDict, Field, StrictStr
from pytz import utc
from tqdm import tqdm
@@ -72,9 +72,7 @@ class SnowflakeMaterializationEngineConfig(FeastConfigBaseModel):
schema_: Optional[str] = Field("PUBLIC", alias="schema")
""" Snowflake schema name """
-
- class Config:
- allow_population_by_field_name = True
+ model_config = ConfigDict(populate_by_name=True)
@dataclass
diff --git a/sdk/python/feast/infra/offline_stores/bigquery.py b/sdk/python/feast/infra/offline_stores/bigquery.py
index 47335c411fd..68420c06642 100644
--- a/sdk/python/feast/infra/offline_stores/bigquery.py
+++ b/sdk/python/feast/infra/offline_stores/bigquery.py
@@ -10,6 +10,7 @@
Dict,
Iterator,
List,
+ Literal,
Optional,
Tuple,
Union,
@@ -19,8 +20,7 @@
import pandas as pd
import pyarrow
import pyarrow.parquet
-from pydantic import StrictStr, validator
-from pydantic.typing import Literal
+from pydantic import StrictStr, field_validator
from tenacity import Retrying, retry_if_exception_type, stop_after_delay, wait_fixed
from feast import flags_helper
@@ -95,7 +95,15 @@ class BigQueryOfflineStoreConfig(FeastConfigBaseModel):
gcs_staging_location: Optional[str] = None
""" (optional) GCS location used for offloading BigQuery results as parquet files."""
- @validator("billing_project_id")
+ table_create_disposition: Literal[
+ "CREATE_NEVER", "CREATE_IF_NEEDED"
+ ] = "CREATE_IF_NEEDED"
+ """ (optional) Specifies whether the job is allowed to create new tables. The default value is CREATE_IF_NEEDED.
+ Custom constraint for table_create_disposition. To understand more, see:
+ https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#JobConfigurationLoad.FIELDS.create_disposition
+ """
+
+ @field_validator("billing_project_id")
def project_id_exists(cls, v, values, **kwargs):
if v and not values["project_id"]:
raise ValueError(
@@ -324,6 +332,7 @@ def write_logged_features(
job_config = bigquery.LoadJobConfig(
source_format=bigquery.SourceFormat.PARQUET,
schema=arrow_schema_to_bq_schema(source.get_schema(registry)),
+ create_disposition=config.offline_store.table_create_disposition,
time_partitioning=bigquery.TimePartitioning(
type_=bigquery.TimePartitioningType.DAY,
field=source.get_log_timestamp_column(),
@@ -342,7 +351,14 @@ def write_logged_features(
return
with tempfile.TemporaryFile() as parquet_temp_file:
- pyarrow.parquet.write_table(table=data, where=parquet_temp_file)
+ # In Pyarrow v13.0, the parquet version was upgraded to v2.6 from v2.4.
+ # Set the coerce_timestamps to "us"(microseconds) for backward compatibility.
+ pyarrow.parquet.write_table(
+ table=data,
+ where=parquet_temp_file,
+ coerce_timestamps="us",
+ allow_truncated_timestamps=True,
+ )
parquet_temp_file.seek(0)
@@ -384,11 +400,19 @@ def offline_write_batch(
job_config = bigquery.LoadJobConfig(
source_format=bigquery.SourceFormat.PARQUET,
schema=arrow_schema_to_bq_schema(pa_schema),
+ create_disposition=config.offline_store.table_create_disposition,
write_disposition="WRITE_APPEND", # Default but included for clarity
)
with tempfile.TemporaryFile() as parquet_temp_file:
- pyarrow.parquet.write_table(table=table, where=parquet_temp_file)
+ # In Pyarrow v13.0, the parquet version was upgraded to v2.6 from v2.4.
+ # Set the coerce_timestamps to "us"(microseconds) for backward compatibility.
+ pyarrow.parquet.write_table(
+ table=table,
+ where=parquet_temp_file,
+ coerce_timestamps="us",
+ allow_truncated_timestamps=True,
+ )
parquet_temp_file.seek(0)
@@ -503,7 +527,7 @@ def to_bigquery(
temp_dest_table = f"{tmp_dest['projectId']}.{tmp_dest['datasetId']}.{tmp_dest['tableId']}"
# persist temp table
- sql = f"CREATE TABLE `{dest}` AS SELECT * FROM {temp_dest_table}"
+ sql = f"CREATE TABLE `{dest}` AS SELECT * FROM `{temp_dest_table}`"
self._execute_query(sql, timeout=timeout)
print(f"Done writing to '{dest}'.")
@@ -577,7 +601,6 @@ def to_remote_storage(self) -> List[str]:
else:
storage_client = StorageClient(project=self.client.project)
bucket, prefix = self._gcs_path[len("gs://") :].split("/", 1)
- prefix = prefix.rsplit("/", 1)[0]
if prefix.startswith("/"):
prefix = prefix[1:]
@@ -693,7 +716,7 @@ def _get_entity_schema(
) -> Dict[str, np.dtype]:
if isinstance(entity_df, str):
entity_df_sample = (
- client.query(f"SELECT * FROM ({entity_df}) LIMIT 1").result().to_dataframe()
+ client.query(f"SELECT * FROM ({entity_df}) LIMIT 0").result().to_dataframe()
)
entity_schema = dict(zip(entity_df_sample.columns, entity_df_sample.dtypes))
diff --git a/sdk/python/feast/infra/offline_stores/contrib/athena_offline_store/athena.py b/sdk/python/feast/infra/offline_stores/contrib/athena_offline_store/athena.py
index 85a61106aaf..ae510171db9 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/athena_offline_store/athena.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/athena_offline_store/athena.py
@@ -8,6 +8,7 @@
Dict,
Iterator,
List,
+ Literal,
Optional,
Tuple,
Union,
@@ -18,7 +19,6 @@
import pyarrow
import pyarrow as pa
from pydantic import StrictStr
-from pydantic.typing import Literal
from pytz import utc
from feast import OnDemandFeatureView
diff --git a/sdk/python/feast/infra/offline_stores/contrib/athena_offline_store/athena_source.py b/sdk/python/feast/infra/offline_stores/contrib/athena_offline_store/athena_source.py
index 8e9e3893f3a..0aca42cd682 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/athena_offline_store/athena_source.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/athena_offline_store/athena_source.py
@@ -297,9 +297,9 @@ class SavedDatasetAthenaStorage(SavedDatasetStorage):
def __init__(
self,
table_ref: str,
- query: str = None,
- database: str = None,
- data_source: str = None,
+ query: Optional[str] = None,
+ database: Optional[str] = None,
+ data_source: Optional[str] = None,
):
self.athena_options = AthenaOptions(
table=table_ref, query=query, database=database, data_source=data_source
diff --git a/sdk/python/feast/infra/offline_stores/contrib/athena_offline_store/tests/data_source.py b/sdk/python/feast/infra/offline_stores/contrib/athena_offline_store/tests/data_source.py
index 384ab69e81f..6b2238830b6 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/athena_offline_store/tests/data_source.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/athena_offline_store/tests/data_source.py
@@ -48,10 +48,10 @@ def create_data_source(
self,
df: pd.DataFrame,
destination_name: str,
- suffix: Optional[str] = None,
- timestamp_field="ts",
+ event_timestamp_column="ts",
created_timestamp_column="created_ts",
- field_mapping: Dict[str, str] = None,
+ field_mapping: Optional[Dict[str, str]] = None,
+ timestamp_field: Optional[str] = "ts",
) -> DataSource:
table_name = destination_name
diff --git a/sdk/python/feast/infra/offline_stores/contrib/duckdb_offline_store/__init__.py b/sdk/python/feast/infra/offline_stores/contrib/duckdb_offline_store/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/sdk/python/feast/infra/offline_stores/contrib/duckdb_offline_store/duckdb.py b/sdk/python/feast/infra/offline_stores/contrib/duckdb_offline_store/duckdb.py
new file mode 100644
index 00000000000..282d8ebb9b1
--- /dev/null
+++ b/sdk/python/feast/infra/offline_stores/contrib/duckdb_offline_store/duckdb.py
@@ -0,0 +1,44 @@
+from typing import List, Union
+
+import ibis
+import pandas as pd
+from pydantic import StrictStr
+
+from feast.feature_view import FeatureView
+from feast.infra.offline_stores.contrib.ibis_offline_store.ibis import IbisOfflineStore
+from feast.infra.offline_stores.offline_store import RetrievalJob
+from feast.infra.registry.base_registry import BaseRegistry
+from feast.repo_config import FeastConfigBaseModel, RepoConfig
+
+
+class DuckDBOfflineStoreConfig(FeastConfigBaseModel):
+ type: StrictStr = "duckdb"
+ # """ Offline store type selector"""
+
+
+class DuckDBOfflineStore(IbisOfflineStore):
+ @staticmethod
+ def setup_ibis_backend():
+ ibis.set_backend("duckdb")
+
+ @staticmethod
+ def get_historical_features(
+ config: RepoConfig,
+ feature_views: List[FeatureView],
+ feature_refs: List[str],
+ entity_df: Union[pd.DataFrame, str],
+ registry: BaseRegistry,
+ project: str,
+ full_feature_names: bool = False,
+ ) -> RetrievalJob:
+ DuckDBOfflineStore.setup_ibis_backend()
+
+ return IbisOfflineStore.get_historical_features(
+ config=config,
+ feature_views=feature_views,
+ feature_refs=feature_refs,
+ entity_df=entity_df,
+ registry=registry,
+ project=project,
+ full_feature_names=full_feature_names,
+ )
diff --git a/sdk/python/feast/infra/offline_stores/contrib/duckdb_offline_store/tests/__init__.py b/sdk/python/feast/infra/offline_stores/contrib/duckdb_offline_store/tests/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/sdk/python/feast/infra/offline_stores/contrib/duckdb_offline_store/tests/data_source.py b/sdk/python/feast/infra/offline_stores/contrib/duckdb_offline_store/tests/data_source.py
new file mode 100644
index 00000000000..63b0a515b5b
--- /dev/null
+++ b/sdk/python/feast/infra/offline_stores/contrib/duckdb_offline_store/tests/data_source.py
@@ -0,0 +1,12 @@
+from feast.infra.offline_stores.contrib.duckdb_offline_store.duckdb import (
+ DuckDBOfflineStoreConfig,
+)
+from tests.integration.feature_repos.universal.data_sources.file import ( # noqa: E402
+ FileDataSourceCreator,
+)
+
+
+class DuckDBDataSourceCreator(FileDataSourceCreator):
+ def create_offline_store_config(self):
+ self.duckdb_offline_store_config = DuckDBOfflineStoreConfig()
+ return self.duckdb_offline_store_config
diff --git a/sdk/python/feast/infra/offline_stores/contrib/duckdb_repo_configuration.py b/sdk/python/feast/infra/offline_stores/contrib/duckdb_repo_configuration.py
new file mode 100644
index 00000000000..07cc0176d4f
--- /dev/null
+++ b/sdk/python/feast/infra/offline_stores/contrib/duckdb_repo_configuration.py
@@ -0,0 +1,13 @@
+from tests.integration.feature_repos.repo_configuration import REDIS_CONFIG
+from tests.integration.feature_repos.universal.data_sources.file import (
+ FileDataSourceCreator,
+)
+from tests.integration.feature_repos.universal.online_store.redis import (
+ RedisOnlineStoreCreator,
+)
+
+AVAILABLE_OFFLINE_STORES = [
+ ("local", FileDataSourceCreator),
+]
+
+AVAILABLE_ONLINE_STORES = {"redis": (REDIS_CONFIG, RedisOnlineStoreCreator)}
diff --git a/sdk/python/feast/infra/offline_stores/contrib/ibis_offline_store/__init__.py b/sdk/python/feast/infra/offline_stores/contrib/ibis_offline_store/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/sdk/python/feast/infra/offline_stores/contrib/ibis_offline_store/ibis.py b/sdk/python/feast/infra/offline_stores/contrib/ibis_offline_store/ibis.py
new file mode 100644
index 00000000000..03c0cd436d1
--- /dev/null
+++ b/sdk/python/feast/infra/offline_stores/contrib/ibis_offline_store/ibis.py
@@ -0,0 +1,289 @@
+from datetime import datetime
+from pathlib import Path
+from typing import Any, Callable, Dict, List, Optional, Tuple, Union
+
+import ibis
+import ibis.selectors as s
+import numpy as np
+import pandas as pd
+import pyarrow
+from ibis.expr.types import Table
+
+from feast.data_source import DataSource
+from feast.feature_logging import LoggingConfig, LoggingSource
+from feast.feature_view import FeatureView
+from feast.infra.offline_stores import offline_utils
+from feast.infra.offline_stores.offline_store import (
+ OfflineStore,
+ RetrievalJob,
+ RetrievalMetadata,
+)
+from feast.infra.registry.base_registry import BaseRegistry
+from feast.on_demand_feature_view import OnDemandFeatureView
+from feast.repo_config import RepoConfig
+from feast.saved_dataset import SavedDatasetStorage
+
+
+def _get_entity_schema(entity_df: pd.DataFrame) -> Dict[str, np.dtype]:
+ return dict(zip(entity_df.columns, entity_df.dtypes))
+
+
+class IbisOfflineStore(OfflineStore):
+ @staticmethod
+ def pull_latest_from_table_or_query(
+ config: RepoConfig,
+ data_source: DataSource,
+ join_key_columns: List[str],
+ feature_name_columns: List[str],
+ timestamp_field: str,
+ created_timestamp_column: Optional[str],
+ start_date: datetime,
+ end_date: datetime,
+ ) -> RetrievalJob:
+ raise NotImplementedError()
+
+ def _get_entity_df_event_timestamp_range(
+ entity_df: pd.DataFrame, entity_df_event_timestamp_col: str
+ ) -> Tuple[datetime, datetime]:
+ entity_df_event_timestamp = entity_df.loc[
+ :, entity_df_event_timestamp_col
+ ].infer_objects()
+ if pd.api.types.is_string_dtype(entity_df_event_timestamp):
+ entity_df_event_timestamp = pd.to_datetime(
+ entity_df_event_timestamp, utc=True
+ )
+ entity_df_event_timestamp_range = (
+ entity_df_event_timestamp.min().to_pydatetime(),
+ entity_df_event_timestamp.max().to_pydatetime(),
+ )
+
+ return entity_df_event_timestamp_range
+
+ @staticmethod
+ def _get_historical_features_one(
+ feature_view: FeatureView,
+ entity_table: Table,
+ feature_refs: List[str],
+ full_feature_names: bool,
+ timestamp_range: Tuple,
+ acc_table: Table,
+ event_timestamp_col: str,
+ ) -> Table:
+ fv_table: Table = ibis.read_parquet(feature_view.batch_source.name)
+ fv_table = fv_table.relabel(feature_view.batch_source.field_mapping)
+ timestamp_field = feature_view.batch_source.timestamp_field
+
+ full_name_prefix = feature_view.projection.name_alias or feature_view.name
+
+ feature_refs = [
+ fr.split(":")[1]
+ for fr in feature_refs
+ if fr.startswith(f"{full_name_prefix}:")
+ ]
+
+ timestamp_range_end = ibis.literal(
+ timestamp_range[1].strftime("%Y-%m-%d %H:%M:%S.%f")
+ ).cast("timestamp")
+ fv_table = fv_table.filter(
+ (
+ fv_table[timestamp_field] <= timestamp_range_end
+ ) # TODO ((fv_table[timestamp_field] > timestamp_range[0] - fv.ttl) if fv.ttl and fv.ttl > timedelta(0,0,0,0,0,0,0) else ibis.literal(True))
+ )
+
+ # join_key_map = feature_view.projection.join_key_map or {e.name: e.name for e in feature_view.entity_columns}
+ # predicates = [fv_table[k] == entity_table[v] for k, v in join_key_map.items()]
+
+ if feature_view.projection.join_key_map:
+ predicates = [
+ fv_table[k] == entity_table[v]
+ for k, v in feature_view.projection.join_key_map.items()
+ ]
+ else:
+ predicates = [
+ fv_table[e.name] == entity_table[e.name]
+ for e in feature_view.entity_columns
+ ]
+
+ predicates.append(
+ fv_table[timestamp_field] <= entity_table[event_timestamp_col]
+ )
+
+ fv_table = fv_table.inner_join(
+ entity_table, predicates, lname="", rname="{name}_y"
+ )
+
+ fv_table = (
+ fv_table.group_by(by="entity_row_id")
+ .order_by(ibis.desc(fv_table[timestamp_field]))
+ .mutate(rn=ibis.row_number())
+ )
+
+ fv_table = fv_table.filter(fv_table["rn"] == ibis.literal(0))
+
+ select_cols = ["entity_row_id"]
+ select_cols.extend(feature_refs)
+ fv_table = fv_table.select(select_cols)
+
+ if full_feature_names:
+ fv_table = fv_table.relabel(
+ {feature: f"{full_name_prefix}__{feature}" for feature in feature_refs}
+ )
+
+ acc_table = acc_table.left_join(
+ fv_table,
+ predicates=[fv_table.entity_row_id == acc_table.entity_row_id],
+ lname="",
+ rname="{name}_yyyy",
+ )
+
+ acc_table = acc_table.drop(s.endswith("_yyyy"))
+
+ return acc_table
+
+ @staticmethod
+ def _to_utc(entity_df: pd.DataFrame, event_timestamp_col):
+ entity_df_event_timestamp = entity_df.loc[
+ :, event_timestamp_col
+ ].infer_objects()
+ if pd.api.types.is_string_dtype(entity_df_event_timestamp):
+ entity_df_event_timestamp = pd.to_datetime(
+ entity_df_event_timestamp, utc=True
+ )
+
+ entity_df[event_timestamp_col] = entity_df_event_timestamp
+ return entity_df
+
+ @staticmethod
+ def _generate_row_id(
+ entity_table: Table, feature_views: List[FeatureView], event_timestamp_col
+ ) -> Table:
+ all_entities = [event_timestamp_col]
+ for fv in feature_views:
+ if fv.projection.join_key_map:
+ all_entities.extend(fv.projection.join_key_map.values())
+ else:
+ all_entities.extend([e.name for e in fv.entity_columns])
+
+ r = ibis.literal("")
+
+ for e in set(all_entities):
+ r = r.concat(entity_table[e].cast("string"))
+
+ entity_table = entity_table.mutate(entity_row_id=r)
+
+ return entity_table
+
+ @staticmethod
+ def get_historical_features(
+ config: RepoConfig,
+ feature_views: List[FeatureView],
+ feature_refs: List[str],
+ entity_df: Union[pd.DataFrame, str],
+ registry: BaseRegistry,
+ project: str,
+ full_feature_names: bool = False,
+ ) -> RetrievalJob:
+ entity_schema = _get_entity_schema(
+ entity_df=entity_df,
+ )
+ event_timestamp_col = offline_utils.infer_event_timestamp_from_entity_df(
+ entity_schema=entity_schema,
+ )
+
+ timestamp_range = IbisOfflineStore._get_entity_df_event_timestamp_range(
+ entity_df, event_timestamp_col
+ )
+ entity_df = IbisOfflineStore._to_utc(entity_df, event_timestamp_col)
+
+ entity_table = ibis.memtable(entity_df)
+ entity_table = IbisOfflineStore._generate_row_id(
+ entity_table, feature_views, event_timestamp_col
+ )
+
+ res: Table = entity_table
+
+ for fv in feature_views:
+ res = IbisOfflineStore._get_historical_features_one(
+ fv,
+ entity_table,
+ feature_refs,
+ full_feature_names,
+ timestamp_range,
+ res,
+ event_timestamp_col,
+ )
+
+ res = res.drop("entity_row_id")
+
+ return IbisRetrievalJob(
+ res,
+ OnDemandFeatureView.get_requested_odfvs(feature_refs, project, registry),
+ full_feature_names,
+ )
+
+ @staticmethod
+ def pull_all_from_table_or_query(
+ config: RepoConfig,
+ data_source: DataSource,
+ join_key_columns: List[str],
+ feature_name_columns: List[str],
+ timestamp_field: str,
+ start_date: datetime,
+ end_date: datetime,
+ ) -> RetrievalJob:
+ raise NotImplementedError()
+
+ @staticmethod
+ def write_logged_features(
+ config: RepoConfig,
+ data: Union[pyarrow.Table, Path],
+ source: LoggingSource,
+ logging_config: LoggingConfig,
+ registry: BaseRegistry,
+ ):
+ raise NotImplementedError()
+
+ @staticmethod
+ def offline_write_batch(
+ config: RepoConfig,
+ feature_view: FeatureView,
+ table: pyarrow.Table,
+ progress: Optional[Callable[[int], Any]],
+ ):
+ raise NotImplementedError()
+
+
+class IbisRetrievalJob(RetrievalJob):
+ def __init__(self, table, on_demand_feature_views, full_feature_names) -> None:
+ super().__init__()
+ self.table = table
+ self._on_demand_feature_views: List[
+ OnDemandFeatureView
+ ] = on_demand_feature_views
+ self._full_feature_names = full_feature_names
+
+ def _to_df_internal(self, timeout: Optional[int] = None) -> pd.DataFrame:
+ return self.table.execute()
+
+ def _to_arrow_internal(self, timeout: Optional[int] = None) -> pyarrow.Table:
+ return self.table.to_pyarrow()
+
+ @property
+ def full_feature_names(self) -> bool:
+ return self._full_feature_names
+
+ @property
+ def on_demand_feature_views(self) -> List[OnDemandFeatureView]:
+ return self._on_demand_feature_views
+
+ def persist(
+ self,
+ storage: SavedDatasetStorage,
+ allow_overwrite: bool = False,
+ timeout: Optional[int] = None,
+ ):
+ pass
+
+ @property
+ def metadata(self) -> Optional[RetrievalMetadata]:
+ pass
diff --git a/sdk/python/feast/infra/offline_stores/contrib/mssql_offline_store/mssql.py b/sdk/python/feast/infra/offline_stores/contrib/mssql_offline_store/mssql.py
index 849d5cc797f..67bae292c37 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/mssql_offline_store/mssql.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/mssql_offline_store/mssql.py
@@ -3,7 +3,7 @@
import warnings
from datetime import datetime
from pathlib import Path
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
+from typing import Any, Callable, Dict, List, Literal, Optional, Set, Tuple, Union
import numpy as np
import pandas
@@ -11,7 +11,6 @@
import pyarrow as pa
import sqlalchemy
from pydantic.types import StrictStr
-from pydantic.typing import Literal
from sqlalchemy import create_engine
from sqlalchemy.engine import Engine
from sqlalchemy.orm import sessionmaker
@@ -32,7 +31,7 @@
from feast.infra.provider import RetrievalJob
from feast.infra.registry.base_registry import BaseRegistry
from feast.on_demand_feature_view import OnDemandFeatureView
-from feast.repo_config import FeastBaseModel, RepoConfig
+from feast.repo_config import FeastConfigBaseModel, RepoConfig
from feast.saved_dataset import SavedDatasetStorage
from feast.type_map import pa_to_mssql_type
from feast.usage import log_exceptions_and_usage
@@ -43,7 +42,7 @@
EntitySchema = Dict[str, np.dtype]
-class MsSqlServerOfflineStoreConfig(FeastBaseModel):
+class MsSqlServerOfflineStoreConfig(FeastConfigBaseModel):
"""Offline store config for SQL Server"""
type: Literal["mssql"] = "mssql"
diff --git a/sdk/python/feast/infra/offline_stores/contrib/mssql_offline_store/tests/data_source.py b/sdk/python/feast/infra/offline_stores/contrib/mssql_offline_store/tests/data_source.py
index 9b751d98efe..71ce56bdefd 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/mssql_offline_store/tests/data_source.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/mssql_offline_store/tests/data_source.py
@@ -1,4 +1,4 @@
-from typing import Dict, List
+from typing import Dict, List, Optional
import pandas as pd
import pytest
@@ -64,10 +64,10 @@ def create_data_source(
self,
df: pd.DataFrame,
destination_name: str,
- timestamp_field="ts",
+ event_timestamp_column="ts",
created_timestamp_column="created_ts",
- field_mapping: Dict[str, str] = None,
- **kwargs,
+ field_mapping: Optional[Dict[str, str]] = None,
+ timestamp_field: Optional[str] = "ts",
) -> DataSource:
# Make sure the field mapping is correct and convert the datetime datasources.
if timestamp_field in df:
@@ -99,10 +99,10 @@ def create_data_source(
)
def create_saved_dataset_destination(self) -> SavedDatasetStorage:
- pass
+ raise NotImplementedError
def get_prefixed_table_name(self, destination_name: str) -> str:
return f"{self.project_name}_{destination_name}"
def teardown(self):
- pass
+ raise NotImplementedError
diff --git a/sdk/python/feast/infra/offline_stores/contrib/postgres_offline_store/postgres.py b/sdk/python/feast/infra/offline_stores/contrib/postgres_offline_store/postgres.py
index c2e95a8648e..9b300d7bf46 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/postgres_offline_store/postgres.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/postgres_offline_store/postgres.py
@@ -9,6 +9,7 @@
Iterator,
KeysView,
List,
+ Literal,
Optional,
Tuple,
Union,
@@ -19,7 +20,6 @@
import pyarrow as pa
from jinja2 import BaseLoader, Environment
from psycopg2 import sql
-from pydantic.typing import Literal
from pytz import utc
from feast.data_source import DataSource
diff --git a/sdk/python/feast/infra/offline_stores/contrib/postgres_offline_store/tests/data_source.py b/sdk/python/feast/infra/offline_stores/contrib/postgres_offline_store/tests/data_source.py
index f4479501323..f50cdc4c41f 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/postgres_offline_store/tests/data_source.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/postgres_offline_store/tests/data_source.py
@@ -1,5 +1,5 @@
import logging
-from typing import Dict, Optional
+from typing import Dict, Literal, Optional
import pandas as pd
import pytest
@@ -12,6 +12,7 @@
PostgreSQLSource,
)
from feast.infra.utils.postgres.connection_utils import df_to_postgres_table
+from feast.infra.utils.postgres.postgres_config import PostgreSQLConfig
from tests.integration.feature_repos.universal.data_source_creator import (
DataSourceCreator,
)
@@ -26,6 +27,10 @@
POSTGRES_DB = "test"
+class PostgreSQLOnlineStoreConfig(PostgreSQLConfig):
+ type: Literal["postgres"] = "postgres"
+
+
@pytest.fixture(scope="session")
def postgres_container():
container = (
@@ -82,10 +87,10 @@ def create_data_source(
self,
df: pd.DataFrame,
destination_name: str,
- suffix: Optional[str] = None,
- timestamp_field="ts",
+ event_timestamp_column="ts",
created_timestamp_column="created_ts",
- field_mapping: Dict[str, str] = None,
+ field_mapping: Optional[Dict[str, str]] = None,
+ timestamp_field: Optional[str] = "ts",
) -> DataSource:
destination_name = self.get_prefixed_table_name(destination_name)
@@ -106,17 +111,17 @@ def create_offline_store_config(self) -> PostgreSQLOfflineStoreConfig:
def get_prefixed_table_name(self, suffix: str) -> str:
return f"{self.project_name}_{suffix}"
- def create_online_store(self) -> Dict[str, str]:
+ def create_online_store(self) -> PostgreSQLOnlineStoreConfig:
assert self.container
- return {
- "type": "postgres",
- "host": "localhost",
- "port": self.container.get_exposed_port(5432),
- "database": POSTGRES_DB,
- "db_schema": "feature_store",
- "user": POSTGRES_USER,
- "password": POSTGRES_PASSWORD,
- }
+ return PostgreSQLOnlineStoreConfig(
+ type="postgres",
+ host="localhost",
+ port=self.container.get_exposed_port(5432),
+ database=POSTGRES_DB,
+ db_schema="feature_store",
+ user=POSTGRES_USER,
+ password=POSTGRES_PASSWORD,
+ )
def create_saved_dataset_destination(self):
# FIXME: ...
diff --git a/sdk/python/feast/infra/offline_stores/contrib/spark_offline_store/spark.py b/sdk/python/feast/infra/offline_stores/contrib/spark_offline_store/spark.py
index 7574ac4865c..c9591b7c3f0 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/spark_offline_store/spark.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/spark_offline_store/spark.py
@@ -352,13 +352,36 @@ def persist(
):
"""
Run the retrieval and persist the results in the same offline store used for read.
- Please note the persisting is done only within the scope of the spark session.
+ Please note the persisting is done only within the scope of the spark session for local warehouse directory.
"""
assert isinstance(storage, SavedDatasetSparkStorage)
table_name = storage.spark_options.table
if not table_name:
raise ValueError("Cannot persist, table_name is not defined")
- self.to_spark_df().createOrReplaceTempView(table_name)
+ if self._has_remote_warehouse_in_config():
+ file_format = storage.spark_options.file_format
+ if not file_format:
+ self.to_spark_df().write.saveAsTable(table_name)
+ else:
+ self.to_spark_df().write.format(file_format).saveAsTable(table_name)
+ else:
+ self.to_spark_df().createOrReplaceTempView(table_name)
+
+ def _has_remote_warehouse_in_config(self) -> bool:
+ """
+ Check if Spark Session config has info about hive metastore uri
+ or warehouse directory is not a local path
+ """
+ self.spark_session.sparkContext.getConf().getAll()
+ try:
+ self.spark_session.conf.get("hive.metastore.uris")
+ return True
+ except Exception:
+ warehouse_dir = self.spark_session.conf.get("spark.sql.warehouse.dir")
+ if warehouse_dir and warehouse_dir.startswith("file:"):
+ return False
+ else:
+ return True
def supports_remote_storage_export(self) -> bool:
return self._config.offline_store.staging_location is not None
diff --git a/sdk/python/feast/infra/offline_stores/contrib/spark_offline_store/tests/data_source.py b/sdk/python/feast/infra/offline_stores/contrib/spark_offline_store/tests/data_source.py
index 71c07b20c27..b9785218857 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/spark_offline_store/tests/data_source.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/spark_offline_store/tests/data_source.py
@@ -2,13 +2,14 @@
import shutil
import tempfile
import uuid
-from typing import Dict, List
+from typing import Dict, List, Optional
import pandas as pd
from pyspark import SparkConf
from pyspark.sql import SparkSession
from feast.data_source import DataSource
+from feast.feature_logging import LoggingDestination
from feast.infra.offline_stores.contrib.spark_offline_store.spark import (
SparkOfflineStoreConfig,
)
@@ -68,10 +69,10 @@ def create_data_source(
self,
df: pd.DataFrame,
destination_name: str,
- timestamp_field="ts",
+ event_timestamp_column="ts",
created_timestamp_column="created_ts",
- field_mapping: Dict[str, str] = None,
- **kwargs,
+ field_mapping: Optional[Dict[str, str]] = None,
+ timestamp_field: Optional[str] = "ts",
) -> DataSource:
if timestamp_field in df:
df[timestamp_field] = pd.to_datetime(df[timestamp_field], utc=True)
@@ -119,3 +120,7 @@ def create_saved_dataset_destination(self) -> SavedDatasetSparkStorage:
def get_prefixed_table_name(self, suffix: str) -> str:
return f"{self.project_name}_{suffix}"
+
+ def create_logged_features_destination(self) -> LoggingDestination:
+ # No implementation of LoggingDestination for Spark offline store.
+ return None # type: ignore
diff --git a/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/test_config/manual_tests.py b/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/test_config/manual_tests.py
index 7d31aa90fb4..a31d368ea11 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/test_config/manual_tests.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/test_config/manual_tests.py
@@ -8,6 +8,6 @@
FULL_REPO_CONFIGS = [
IntegrationTestRepoConfig(
provider="local",
- offline_store_creator=TrinoSourceCreator,
+ offline_store_creator=TrinoSourceCreator, # type: ignore
),
]
diff --git a/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/tests/data_source.py b/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/tests/data_source.py
index 67efa6a27f8..fcc0c8d0fa7 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/tests/data_source.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/tests/data_source.py
@@ -67,6 +67,11 @@ def __init__(
catalog="memory",
host="localhost",
port=self.exposed_port,
+ source="trino-python-client",
+ http_scheme="http",
+ verify=False,
+ extra_credential=None,
+ auth=None,
)
def teardown(self):
@@ -76,10 +81,10 @@ def create_data_source(
self,
df: pd.DataFrame,
destination_name: str,
- suffix: Optional[str] = None,
- timestamp_field="ts",
+ event_timestamp_column="ts",
created_timestamp_column="created_ts",
field_mapping: Optional[Dict[str, str]] = None,
+ timestamp_field: Optional[str] = "ts",
) -> DataSource:
destination_name = self.get_prefixed_table_name(destination_name)
self.client.execute_query(
@@ -123,4 +128,6 @@ def create_offline_store_config(self) -> FeastConfigBaseModel:
catalog="memory",
dataset=self.project_name,
connector={"type": "memory"},
+ user="test",
+ auth=None,
)
diff --git a/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/trino.py b/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/trino.py
index e0f73404ebe..cdc94350244 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/trino.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/trino.py
@@ -1,12 +1,18 @@
import uuid
from datetime import date, datetime
-from typing import Any, Dict, List, Optional, Tuple, Union
+from typing import Any, Dict, List, Literal, Optional, Tuple, Union
import numpy as np
import pandas as pd
import pyarrow
-from pydantic import StrictStr
-from trino.auth import Authentication
+from pydantic import Field, FilePath, SecretStr, StrictBool, StrictStr, model_validator
+from trino.auth import (
+ BasicAuthentication,
+ CertificateAuthentication,
+ JWTAuthentication,
+ KerberosAuthentication,
+ OAuth2Authentication,
+)
from feast.data_source import DataSource
from feast.errors import InvalidEntityType
@@ -32,6 +38,87 @@
from feast.usage import log_exceptions_and_usage
+class BasicAuthModel(FeastConfigBaseModel):
+ username: StrictStr
+ password: StrictStr
+
+
+class KerberosAuthModel(FeastConfigBaseModel):
+ config: Optional[FilePath] = Field(default=None, alias="config-file")
+ service_name: Optional[StrictStr] = Field(default=None, alias="service-name")
+ mutual_authentication: StrictBool = Field(
+ default=False, alias="mutual-authentication"
+ )
+ force_preemptive: StrictBool = Field(default=False, alias="force-preemptive")
+ hostname_override: Optional[StrictStr] = Field(
+ default=None, alias="hostname-override"
+ )
+ sanitize_mutual_error_response: StrictBool = Field(
+ default=True, alias="sanitize-mutual-error-response"
+ )
+ principal: Optional[StrictStr]
+ delegate: StrictBool = False
+ ca_bundle: Optional[FilePath] = Field(default=None, alias="ca-bundle-file")
+
+
+class JWTAuthModel(FeastConfigBaseModel):
+ token: SecretStr
+
+
+class CertificateAuthModel(FeastConfigBaseModel):
+ cert: FilePath = Field(default=None, alias="cert-file")
+ key: FilePath = Field(default=None, alias="key-file")
+
+
+CLASSES_BY_AUTH_TYPE = {
+ "kerberos": {
+ "auth_model": KerberosAuthModel,
+ "trino_auth": KerberosAuthentication,
+ },
+ "basic": {
+ "auth_model": BasicAuthModel,
+ "trino_auth": BasicAuthentication,
+ },
+ "jwt": {
+ "auth_model": JWTAuthModel,
+ "trino_auth": JWTAuthentication,
+ },
+ "oauth2": {
+ "auth_model": None,
+ "trino_auth": OAuth2Authentication,
+ },
+ "certificate": {
+ "auth_model": CertificateAuthModel,
+ "trino_auth": CertificateAuthentication,
+ },
+}
+
+
+class AuthConfig(FeastConfigBaseModel):
+ type: Literal["kerberos", "basic", "jwt", "oauth2", "certificate"]
+ config: Optional[Dict[StrictStr, Any]]
+
+ @model_validator(mode="after")
+ def config_only_nullable_for_oauth2(self):
+ auth_type = self.type
+ auth_config = self.config
+ if auth_type != "oauth2" and auth_config is None:
+ raise ValueError(f"config cannot be null for auth type '{auth_type}'")
+
+ return self
+
+ def to_trino_auth(self):
+ auth_type = self.type
+ trino_auth_cls = CLASSES_BY_AUTH_TYPE[auth_type]["trino_auth"]
+
+ if auth_type == "oauth2":
+ return trino_auth_cls()
+
+ model_cls = CLASSES_BY_AUTH_TYPE[auth_type]["auth_model"]
+ model = model_cls(**self.config)
+ return trino_auth_cls(**model.dict())
+
+
class TrinoOfflineStoreConfig(FeastConfigBaseModel):
"""Online store config for Trino"""
@@ -47,6 +134,23 @@ class TrinoOfflineStoreConfig(FeastConfigBaseModel):
catalog: StrictStr
""" Catalog of the Trino cluster """
+ user: StrictStr
+ """ User of the Trino cluster """
+
+ source: Optional[StrictStr] = "trino-python-client"
+ """ ID of the feast's Trino Python client, useful for debugging """
+
+ http_scheme: Literal["http", "https"] = Field(default="http", alias="http-scheme")
+ """ HTTP scheme that should be used while establishing a connection to the Trino cluster """
+
+ verify: StrictBool = Field(default=True, alias="ssl-verify")
+ """ Whether the SSL certificate emited by the Trino cluster should be verified or not """
+
+ extra_credential: Optional[StrictStr] = Field(
+ default=None, alias="x-trino-extra-credential-header"
+ )
+ """ Specifies the HTTP header X-Trino-Extra-Credential, e.g. user1=pwd1, user2=pwd2 """
+
connector: Dict[str, str]
"""
Trino connector to use as well as potential extra parameters.
@@ -59,6 +163,16 @@ class TrinoOfflineStoreConfig(FeastConfigBaseModel):
dataset: StrictStr = "feast"
""" (optional) Trino Dataset name for temporary tables """
+ auth: Optional[AuthConfig]
+ """
+ (optional) Authentication mechanism to use when connecting to Trino. Supported options are:
+ - kerberos
+ - basic
+ - jwt
+ - oauth2
+ - certificate
+ """
+
class TrinoRetrievalJob(RetrievalJob):
def __init__(
@@ -162,9 +276,6 @@ def pull_latest_from_table_or_query(
created_timestamp_column: Optional[str],
start_date: datetime,
end_date: datetime,
- user: Optional[str] = None,
- auth: Optional[Authentication] = None,
- http_scheme: Optional[str] = None,
) -> TrinoRetrievalJob:
assert isinstance(config.offline_store, TrinoOfflineStoreConfig)
assert isinstance(data_source, TrinoSource)
@@ -181,9 +292,7 @@ def pull_latest_from_table_or_query(
timestamps.append(created_timestamp_column)
timestamp_desc_string = " DESC, ".join(timestamps) + " DESC"
field_string = ", ".join(join_key_columns + feature_name_columns + timestamps)
- client = _get_trino_client(
- config=config, user=user, auth=auth, http_scheme=http_scheme
- )
+ client = _get_trino_client(config=config)
query = f"""
SELECT
@@ -216,17 +325,12 @@ def get_historical_features(
registry: Registry,
project: str,
full_feature_names: bool = False,
- user: Optional[str] = None,
- auth: Optional[Authentication] = None,
- http_scheme: Optional[str] = None,
) -> TrinoRetrievalJob:
assert isinstance(config.offline_store, TrinoOfflineStoreConfig)
for fv in feature_views:
assert isinstance(fv.batch_source, TrinoSource)
- client = _get_trino_client(
- config=config, user=user, auth=auth, http_scheme=http_scheme
- )
+ client = _get_trino_client(config=config)
table_reference = _get_table_reference_for_new_entity(
catalog=config.offline_store.catalog,
@@ -307,17 +411,12 @@ def pull_all_from_table_or_query(
timestamp_field: str,
start_date: datetime,
end_date: datetime,
- user: Optional[str] = None,
- auth: Optional[Authentication] = None,
- http_scheme: Optional[str] = None,
) -> RetrievalJob:
assert isinstance(config.offline_store, TrinoOfflineStoreConfig)
assert isinstance(data_source, TrinoSource)
from_expression = data_source.get_table_query_string()
- client = _get_trino_client(
- config=config, user=user, auth=auth, http_scheme=http_scheme
- )
+ client = _get_trino_client(config=config)
field_string = ", ".join(
join_key_columns + feature_name_columns + [timestamp_field]
)
@@ -378,21 +477,22 @@ def _upload_entity_df_and_get_entity_schema(
# TODO: Ensure that the table expires after some time
-def _get_trino_client(
- config: RepoConfig,
- user: Optional[str],
- auth: Optional[Any],
- http_scheme: Optional[str],
-) -> Trino:
- client = Trino(
- user=user,
- catalog=config.offline_store.catalog,
+def _get_trino_client(config: RepoConfig) -> Trino:
+ auth = None
+ if config.offline_store.auth is not None:
+ auth = config.offline_store.auth.to_trino_auth()
+
+ return Trino(
host=config.offline_store.host,
port=config.offline_store.port,
+ user=config.offline_store.user,
+ catalog=config.offline_store.catalog,
+ source=config.offline_store.source,
+ http_scheme=config.offline_store.http_scheme,
+ verify=config.offline_store.verify,
+ extra_credential=config.offline_store.extra_credential,
auth=auth,
- http_scheme=http_scheme,
)
- return client
def _get_entity_df_event_timestamp_range(
diff --git a/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/trino_queries.py b/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/trino_queries.py
index 97c61f78a60..50472407bc6 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/trino_queries.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/trino_queries.py
@@ -1,7 +1,6 @@
from __future__ import annotations
import datetime
-import os
import signal
from dataclasses import dataclass
from enum import Enum
@@ -30,34 +29,27 @@ class QueryStatus(Enum):
class Trino:
def __init__(
self,
- host: Optional[str] = None,
- port: Optional[int] = None,
- user: Optional[str] = None,
- catalog: Optional[str] = None,
- auth: Optional[Any] = None,
- http_scheme: Optional[str] = None,
- source: Optional[str] = None,
- extra_credential: Optional[str] = None,
+ host: str,
+ port: int,
+ user: str,
+ catalog: str,
+ source: Optional[str],
+ http_scheme: str,
+ verify: bool,
+ extra_credential: Optional[str],
+ auth: Optional[trino.Authentication],
):
- self.host = host or os.getenv("TRINO_HOST")
- self.port = port or os.getenv("TRINO_PORT")
- self.user = user or os.getenv("TRINO_USER")
- self.catalog = catalog or os.getenv("TRINO_CATALOG")
- self.auth = auth or os.getenv("TRINO_AUTH")
- self.http_scheme = http_scheme or os.getenv("TRINO_HTTP_SCHEME")
- self.source = source or os.getenv("TRINO_SOURCE")
- self.extra_credential = extra_credential or os.getenv("TRINO_EXTRA_CREDENTIAL")
+ self.host = host
+ self.port = port
+ self.user = user
+ self.catalog = catalog
+ self.source = source
+ self.http_scheme = http_scheme
+ self.verify = verify
+ self.extra_credential = extra_credential
+ self.auth = auth
self._cursor: Optional[Cursor] = None
- if self.host is None:
- raise ValueError("TRINO_HOST must be set if not passed in")
- if self.port is None:
- raise ValueError("TRINO_PORT must be set if not passed in")
- if self.user is None:
- raise ValueError("TRINO_USER must be set if not passed in")
- if self.catalog is None:
- raise ValueError("TRINO_CATALOG must be set if not passed in")
-
def _get_cursor(self) -> Cursor:
if self._cursor is None:
headers = (
@@ -70,9 +62,10 @@ def _get_cursor(self) -> Cursor:
port=self.port,
user=self.user,
catalog=self.catalog,
- auth=self.auth,
- http_scheme=self.http_scheme,
source=self.source,
+ http_scheme=self.http_scheme,
+ verify=self.verify,
+ auth=self.auth,
http_headers=headers,
).cursor()
diff --git a/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/trino_source.py b/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/trino_source.py
index f09b79069ca..e618e8664ee 100644
--- a/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/trino_source.py
+++ b/sdk/python/feast/infra/offline_stores/contrib/trino_offline_store/trino_source.py
@@ -227,10 +227,20 @@ def source_datatype_to_feast_value_type() -> Callable[[str], ValueType]:
def get_table_column_names_and_types(
self, config: RepoConfig
) -> Iterable[Tuple[str, str]]:
+ auth = None
+ if config.offline_store.auth is not None:
+ auth = config.offline_store.auth.to_trino_auth()
+
client = Trino(
catalog=config.offline_store.catalog,
host=config.offline_store.host,
port=config.offline_store.port,
+ user=config.offline_store.user,
+ source=config.offline_store.source,
+ http_scheme=config.offline_store.http_scheme,
+ verify=config.offline_store.verify,
+ extra_credential=config.offline_store.extra_credential,
+ auth=auth,
)
if self.table:
table_schema = client.execute_query(
diff --git a/sdk/python/feast/infra/offline_stores/file.py b/sdk/python/feast/infra/offline_stores/file.py
index 5e4107545f0..0e5064ba785 100644
--- a/sdk/python/feast/infra/offline_stores/file.py
+++ b/sdk/python/feast/infra/offline_stores/file.py
@@ -2,7 +2,7 @@
import uuid
from datetime import datetime
from pathlib import Path
-from typing import Any, Callable, List, Optional, Tuple, Union
+from typing import Any, Callable, List, Literal, Optional, Tuple, Union
import dask.dataframe as dd
import pandas as pd
@@ -10,7 +10,6 @@
import pyarrow.dataset
import pyarrow.parquet
import pytz
-from pydantic.typing import Literal
from feast.data_source import DataSource
from feast.errors import (
diff --git a/sdk/python/feast/infra/offline_stores/file_source.py b/sdk/python/feast/infra/offline_stores/file_source.py
index d8522fb4456..887b4100796 100644
--- a/sdk/python/feast/infra/offline_stores/file_source.py
+++ b/sdk/python/feast/infra/offline_stores/file_source.py
@@ -158,7 +158,7 @@ def get_table_column_names_and_types(
# Adding support for different file format path
# based on S3 filesystem
if filesystem is None:
- schema = ParquetDataset(path).schema
+ schema = ParquetDataset(path, use_legacy_dataset=False).schema
if hasattr(schema, "names") and hasattr(schema, "types"):
# Newer versions of pyarrow doesn't have this method,
# but this field is good enough.
@@ -183,7 +183,7 @@ def create_filesystem_and_path(
return None, path
def get_table_query_string(self) -> str:
- pass
+ raise NotImplementedError
class FileOptions:
diff --git a/sdk/python/feast/infra/offline_stores/offline_store.py b/sdk/python/feast/infra/offline_stores/offline_store.py
index 6141e3c435b..30135feccb3 100644
--- a/sdk/python/feast/infra/offline_stores/offline_store.py
+++ b/sdk/python/feast/infra/offline_stores/offline_store.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import warnings
-from abc import ABC, abstractmethod
+from abc import ABC
from datetime import datetime
from pathlib import Path
from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union
@@ -150,9 +150,8 @@ def to_sql(self) -> str:
"""
Return RetrievalJob generated SQL statement if applicable.
"""
- pass
+ raise NotImplementedError
- @abstractmethod
def _to_df_internal(self, timeout: Optional[int] = None) -> pd.DataFrame:
"""
Synchronously executes the underlying query and returns the result as a pandas dataframe.
@@ -162,9 +161,8 @@ def _to_df_internal(self, timeout: Optional[int] = None) -> pd.DataFrame:
Does not handle on demand transformations or dataset validation. For either of those,
`to_df` should be used.
"""
- pass
+ raise NotImplementedError
- @abstractmethod
def _to_arrow_internal(self, timeout: Optional[int] = None) -> pyarrow.Table:
"""
Synchronously executes the underlying query and returns the result as an arrow table.
@@ -174,21 +172,18 @@ def _to_arrow_internal(self, timeout: Optional[int] = None) -> pyarrow.Table:
Does not handle on demand transformations or dataset validation. For either of those,
`to_arrow` should be used.
"""
- pass
+ raise NotImplementedError
@property
- @abstractmethod
def full_feature_names(self) -> bool:
"""Returns True if full feature names should be applied to the results of the query."""
- pass
+ raise NotImplementedError
@property
- @abstractmethod
def on_demand_feature_views(self) -> List[OnDemandFeatureView]:
"""Returns a list containing all the on demand feature views to be handled."""
- pass
+ raise NotImplementedError
- @abstractmethod
def persist(
self,
storage: SavedDatasetStorage,
@@ -204,13 +199,12 @@ def persist(
allow_overwrite: If True, a pre-existing location (e.g. table or file) can be overwritten.
Currently not all individual offline store implementations make use of this parameter.
"""
- pass
+ raise NotImplementedError
@property
- @abstractmethod
def metadata(self) -> Optional[RetrievalMetadata]:
"""Returns metadata about the retrieval job."""
- pass
+ raise NotImplementedError
def supports_remote_storage_export(self) -> bool:
"""Returns True if the RetrievalJob supports `to_remote_storage`."""
@@ -226,7 +220,7 @@ def to_remote_storage(self) -> List[str]:
Returns:
A list of parquet file paths in remote storage.
"""
- raise NotImplementedError()
+ raise NotImplementedError
class OfflineStore(ABC):
@@ -239,7 +233,6 @@ class OfflineStore(ABC):
"""
@staticmethod
- @abstractmethod
def pull_latest_from_table_or_query(
config: RepoConfig,
data_source: DataSource,
@@ -270,10 +263,9 @@ def pull_latest_from_table_or_query(
Returns:
A RetrievalJob that can be executed to get the entity rows.
"""
- pass
+ raise NotImplementedError
@staticmethod
- @abstractmethod
def get_historical_features(
config: RepoConfig,
feature_views: List[FeatureView],
@@ -302,10 +294,9 @@ def get_historical_features(
Returns:
A RetrievalJob that can be executed to get the features.
"""
- pass
+ raise NotImplementedError
@staticmethod
- @abstractmethod
def pull_all_from_table_or_query(
config: RepoConfig,
data_source: DataSource,
@@ -334,7 +325,7 @@ def pull_all_from_table_or_query(
Returns:
A RetrievalJob that can be executed to get the entity rows.
"""
- pass
+ raise NotImplementedError
@staticmethod
def write_logged_features(
@@ -358,7 +349,7 @@ def write_logged_features(
logging_config: A LoggingConfig object that determines where the logs will be written.
registry: The registry for the current feature store.
"""
- raise NotImplementedError()
+ raise NotImplementedError
@staticmethod
def offline_write_batch(
@@ -377,4 +368,4 @@ def offline_write_batch(
progress: Function to be called once a portion of the data has been written, used
to show progress.
"""
- raise NotImplementedError()
+ raise NotImplementedError
diff --git a/sdk/python/feast/infra/offline_stores/redshift.py b/sdk/python/feast/infra/offline_stores/redshift.py
index aba2bda353c..2565a569ad1 100644
--- a/sdk/python/feast/infra/offline_stores/redshift.py
+++ b/sdk/python/feast/infra/offline_stores/redshift.py
@@ -9,6 +9,7 @@
Dict,
Iterator,
List,
+ Literal,
Optional,
Tuple,
Union,
@@ -19,8 +20,7 @@
import pyarrow
import pyarrow as pa
from dateutil import parser
-from pydantic import StrictStr, root_validator
-from pydantic.typing import Literal
+from pydantic import StrictStr, model_validator
from pytz import utc
from feast import OnDemandFeatureView, RedshiftSource
@@ -51,13 +51,13 @@ class RedshiftOfflineStoreConfig(FeastConfigBaseModel):
type: Literal["redshift"] = "redshift"
""" Offline store type selector"""
- cluster_id: Optional[StrictStr]
+ cluster_id: Optional[StrictStr] = None
""" Redshift cluster identifier, for provisioned clusters """
- user: Optional[StrictStr]
+ user: Optional[StrictStr] = None
""" Redshift user name, only required for provisioned clusters """
- workgroup: Optional[StrictStr]
+ workgroup: Optional[StrictStr] = None
""" Redshift workgroup identifier, for serverless """
region: StrictStr
@@ -72,16 +72,16 @@ class RedshiftOfflineStoreConfig(FeastConfigBaseModel):
iam_role: StrictStr
""" IAM Role for Redshift, granting it access to S3 """
- @root_validator
- def require_cluster_and_user_or_workgroup(cls, values):
+ @model_validator(mode="after")
+ def require_cluster_and_user_or_workgroup(self):
"""
Provisioned Redshift clusters: Require cluster_id and user, ignore workgroup
Serverless Redshift: Require workgroup, ignore cluster_id and user
"""
cluster_id, user, workgroup = (
- values.get("cluster_id"),
- values.get("user"),
- values.get("workgroup"),
+ self.cluster_id,
+ self.user,
+ self.workgroup,
)
if not (cluster_id and user) and not workgroup:
raise ValueError(
@@ -90,7 +90,7 @@ def require_cluster_and_user_or_workgroup(cls, values):
elif cluster_id and workgroup:
raise ValueError("cannot specify both cluster_id and workgroup")
- return values
+ return self
class RedshiftOfflineStore(OfflineStore):
@@ -369,7 +369,7 @@ def offline_write_batch(
s3_resource=s3_resource,
s3_path=f"{config.offline_store.s3_staging_location}/push/{uuid.uuid4()}.parquet",
iam_role=config.offline_store.iam_role,
- table_name=redshift_options.table,
+ table_name=redshift_options.fully_qualified_table_name,
schema=pa_schema,
fail_if_exists=False,
)
diff --git a/sdk/python/feast/infra/offline_stores/redshift_source.py b/sdk/python/feast/infra/offline_stores/redshift_source.py
index 1f80dede076..52ab50ba000 100644
--- a/sdk/python/feast/infra/offline_stores/redshift_source.py
+++ b/sdk/python/feast/infra/offline_stores/redshift_source.py
@@ -294,6 +294,42 @@ def from_proto(cls, redshift_options_proto: DataSourceProto.RedshiftOptions):
return redshift_options
+ @property
+ def fully_qualified_table_name(self) -> str:
+ """
+ The fully qualified table name of this Redshift table.
+
+ Returns:
+ A string in the format of ..
+ May be empty or None if the table is not set
+ """
+
+ if not self.table:
+ return ""
+
+ # self.table may already contain the database and schema
+ parts = self.table.split(".")
+ if len(parts) == 3:
+ database, schema, table = parts
+ elif len(parts) == 2:
+ database = self.database
+ schema, table = parts
+ elif len(parts) == 1:
+ database = self.database
+ schema = self.schema
+ table = parts[0]
+ else:
+ raise ValueError(
+ f"Invalid table name: {self.table} - can't determine database and schema"
+ )
+
+ if database and schema:
+ return f"{database}.{schema}.{table}"
+ elif schema:
+ return f"{schema}.{table}"
+ else:
+ return table
+
def to_proto(self) -> DataSourceProto.RedshiftOptions:
"""
Converts an RedshiftOptionsProto object to its protobuf representation.
@@ -323,7 +359,6 @@ def __init__(self, table_ref: str):
@staticmethod
def from_proto(storage_proto: SavedDatasetStorageProto) -> SavedDatasetStorage:
-
return SavedDatasetRedshiftStorage(
table_ref=RedshiftOptions.from_proto(storage_proto.redshift_storage).table
)
diff --git a/sdk/python/feast/infra/offline_stores/snowflake.py b/sdk/python/feast/infra/offline_stores/snowflake.py
index 38568ce79b2..14752fd8572 100644
--- a/sdk/python/feast/infra/offline_stores/snowflake.py
+++ b/sdk/python/feast/infra/offline_stores/snowflake.py
@@ -1,4 +1,5 @@
import contextlib
+import json
import os
import uuid
import warnings
@@ -13,6 +14,7 @@
Dict,
Iterator,
List,
+ Literal,
Optional,
Tuple,
Union,
@@ -22,8 +24,7 @@
import numpy as np
import pandas as pd
import pyarrow
-from pydantic import Field, StrictStr
-from pydantic.typing import Literal
+from pydantic import ConfigDict, Field, StrictStr
from pytz import utc
from feast import OnDemandFeatureView
@@ -51,6 +52,17 @@
)
from feast.repo_config import FeastConfigBaseModel, RepoConfig
from feast.saved_dataset import SavedDatasetStorage
+from feast.types import (
+ Array,
+ Bool,
+ Bytes,
+ Float32,
+ Float64,
+ Int32,
+ Int64,
+ String,
+ UnixTimestamp,
+)
from feast.usage import log_exceptions_and_usage
try:
@@ -107,9 +119,7 @@ class SnowflakeOfflineStoreConfig(FeastConfigBaseModel):
convert_timestamp_columns: Optional[bool] = None
""" Convert timestamp columns on export to a Parquet-supported format """
-
- class Config:
- allow_population_by_field_name = True
+ model_config = ConfigDict(populate_by_name=True)
class SnowflakeOfflineStore(OfflineStore):
@@ -320,6 +330,7 @@ def query_generator() -> Iterator[str]:
on_demand_feature_views=OnDemandFeatureView.get_requested_odfvs(
feature_refs, project, registry
),
+ feature_views=feature_views,
metadata=RetrievalMetadata(
features=feature_refs,
keys=list(entity_schema.keys() - {entity_df_event_timestamp_col}),
@@ -398,9 +409,12 @@ def __init__(
config: RepoConfig,
full_feature_names: bool,
on_demand_feature_views: Optional[List[OnDemandFeatureView]] = None,
+ feature_views: Optional[List[FeatureView]] = None,
metadata: Optional[RetrievalMetadata] = None,
):
+ if feature_views is None:
+ feature_views = []
if not isinstance(query, str):
self._query_generator = query
else:
@@ -416,6 +430,7 @@ def query_generator() -> Iterator[str]:
self.config = config
self._full_feature_names = full_feature_names
self._on_demand_feature_views = on_demand_feature_views or []
+ self._feature_views = feature_views
self._metadata = metadata
self.export_path: Optional[str]
if self.config.offline_store.blob_export_location:
@@ -436,12 +451,28 @@ def _to_df_internal(self, timeout: Optional[int] = None) -> pd.DataFrame:
self.snowflake_conn, self.to_sql()
).fetch_pandas_all()
+ for feature_view in self._feature_views:
+ for feature in feature_view.features:
+ if feature.dtype in [
+ Array(String),
+ Array(Bytes),
+ Array(Int32),
+ Array(Int64),
+ Array(UnixTimestamp),
+ Array(Float64),
+ Array(Float32),
+ Array(Bool),
+ ]:
+ df[feature.name] = [
+ json.loads(x) if x else None for x in df[feature.name]
+ ]
+
return df
def _to_arrow_internal(self, timeout: Optional[int] = None) -> pyarrow.Table:
pa_table = execute_snowflake_statement(
self.snowflake_conn, self.to_sql()
- ).fetch_arrow_all()
+ ).fetch_arrow_all(force_return_table=False)
if pa_table:
return pa_table
@@ -584,12 +615,17 @@ def to_remote_storage(self) -> List[str]:
HEADER = TRUE
"""
cursor = execute_snowflake_statement(self.snowflake_conn, query)
+ # s3gov schema is used by Snowflake in AWS govcloud regions
+ # remove gov portion from schema and pass it to online store upload
+ native_export_path = self.export_path.replace("s3gov://", "s3://")
+ return self._get_file_names_from_copy_into(cursor, native_export_path)
+ def _get_file_names_from_copy_into(self, cursor, native_export_path) -> List[str]:
file_name_column_index = [
idx for idx, rm in enumerate(cursor.description) if rm.name == "FILE_NAME"
][0]
return [
- f"{self.export_path}/{row[file_name_column_index]}"
+ f"{native_export_path}/{row[file_name_column_index]}"
for row in cursor.fetchall()
]
diff --git a/sdk/python/feast/infra/offline_stores/snowflake_source.py b/sdk/python/feast/infra/offline_stores/snowflake_source.py
index 95bd46f1ec1..9a2c6e09bc4 100644
--- a/sdk/python/feast/infra/offline_stores/snowflake_source.py
+++ b/sdk/python/feast/infra/offline_stores/snowflake_source.py
@@ -1,5 +1,5 @@
import warnings
-from typing import Callable, Dict, Iterable, Optional, Tuple
+from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, no_type_check
from typeguard import typechecked
@@ -202,6 +202,7 @@ def get_table_query_string(self) -> str:
def source_datatype_to_feast_value_type() -> Callable[[str], ValueType]:
return type_map.snowflake_type_to_feast_value_type
+ @no_type_check
def get_table_column_names_and_types(
self, config: RepoConfig
) -> Iterable[Tuple[str, str]]:
@@ -223,7 +224,7 @@ def get_table_column_names_and_types(
query = f"SELECT * FROM {self.get_table_query_string()} LIMIT 5"
cursor = execute_snowflake_statement(conn, query)
- metadata = [
+ metadata: List[Dict[str, Any]] = [
{
"column_name": column.name,
"type_code": column.type_code,
@@ -279,12 +280,12 @@ def get_table_column_names_and_types(
else:
row["snowflake_type"] = "NUMBERwSCALE"
- elif row["type_code"] in [5, 9, 10, 12]:
+ elif row["type_code"] in [5, 9, 12]:
error = snowflake_unsupported_map[row["type_code"]]
raise NotImplementedError(
f"The following Snowflake Data Type is not supported: {error}"
)
- elif row["type_code"] in [1, 2, 3, 4, 6, 7, 8, 11, 13]:
+ elif row["type_code"] in [1, 2, 3, 4, 6, 7, 8, 10, 11, 13]:
row["snowflake_type"] = snowflake_type_code_map[row["type_code"]]
else:
raise NotImplementedError(
@@ -292,7 +293,8 @@ def get_table_column_names_and_types(
)
return [
- (column["column_name"], column["snowflake_type"]) for column in metadata
+ (str(column["column_name"]), str(column["snowflake_type"]))
+ for column in metadata
]
@@ -305,6 +307,7 @@ def get_table_column_names_and_types(
6: "TIMESTAMP_LTZ",
7: "TIMESTAMP_TZ",
8: "TIMESTAMP_NTZ",
+ 10: "ARRAY",
11: "BINARY",
13: "BOOLEAN",
}
@@ -312,7 +315,6 @@ def get_table_column_names_and_types(
snowflake_unsupported_map = {
5: "VARIANT -- Try converting to VARCHAR",
9: "OBJECT -- Try converting to VARCHAR",
- 10: "ARRAY -- Try converting to VARCHAR",
12: "TIME -- Try converting to VARCHAR",
}
diff --git a/sdk/python/feast/infra/online_stores/bigtable.py b/sdk/python/feast/infra/online_stores/bigtable.py
index 30561d0840f..3a83d23cedb 100644
--- a/sdk/python/feast/infra/online_stores/bigtable.py
+++ b/sdk/python/feast/infra/online_stores/bigtable.py
@@ -2,13 +2,12 @@
import logging
from concurrent import futures
from datetime import datetime
-from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple
+from typing import Any, Callable, Dict, List, Literal, Optional, Sequence, Set, Tuple
import google
from google.cloud import bigtable
from google.cloud.bigtable import row_filters
from pydantic import StrictStr
-from pydantic.typing import Literal
from feast import Entity, FeatureView, utils
from feast.feature_view import DUMMY_ENTITY_NAME
diff --git a/sdk/python/feast/infra/online_stores/contrib/cassandra_online_store/cassandra_online_store.py b/sdk/python/feast/infra/online_stores/contrib/cassandra_online_store/cassandra_online_store.py
index 34a8cab036d..c672e18db03 100644
--- a/sdk/python/feast/infra/online_stores/contrib/cassandra_online_store/cassandra_online_store.py
+++ b/sdk/python/feast/infra/online_stores/contrib/cassandra_online_store/cassandra_online_store.py
@@ -20,7 +20,17 @@
import logging
from datetime import datetime
-from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple
+from typing import (
+ Any,
+ Callable,
+ Dict,
+ Iterable,
+ List,
+ Literal,
+ Optional,
+ Sequence,
+ Tuple,
+)
from cassandra.auth import PlainTextAuthProvider
from cassandra.cluster import (
@@ -34,7 +44,6 @@
from cassandra.policies import DCAwareRoundRobinPolicy, TokenAwarePolicy
from cassandra.query import PreparedStatement
from pydantic import StrictFloat, StrictInt, StrictStr
-from pydantic.typing import Literal
from feast import Entity, FeatureView, RepoConfig
from feast.infra.key_encoding_utils import serialize_entity_key
diff --git a/sdk/python/feast/infra/online_stores/contrib/hbase_online_store/hbase.py b/sdk/python/feast/infra/online_stores/contrib/hbase_online_store/hbase.py
index aff0c6c42c5..4b2d8ae39c2 100644
--- a/sdk/python/feast/infra/online_stores/contrib/hbase_online_store/hbase.py
+++ b/sdk/python/feast/infra/online_stores/contrib/hbase_online_store/hbase.py
@@ -1,16 +1,17 @@
import calendar
import struct
from datetime import datetime
-from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
+from typing import Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple
-from happybase import Connection
-from pydantic.typing import Literal
+from happybase import ConnectionPool
+from happybase.connection import DEFAULT_PROTOCOL, DEFAULT_TRANSPORT
+from pydantic import StrictStr
from feast import Entity
from feast.feature_view import FeatureView
-from feast.infra.key_encoding_utils import serialize_entity_key
+from feast.infra.online_stores.helpers import compute_entity_id
from feast.infra.online_stores.online_store import OnlineStore
-from feast.infra.utils.hbase_utils import HbaseConstants, HbaseUtils
+from feast.infra.utils.hbase_utils import HBaseConnector, HbaseConstants
from feast.protos.feast.types.EntityKey_pb2 import EntityKey as EntityKeyProto
from feast.protos.feast.types.Value_pb2 import Value as ValueProto
from feast.repo_config import FeastConfigBaseModel, RepoConfig
@@ -23,35 +24,20 @@ class HbaseOnlineStoreConfig(FeastConfigBaseModel):
type: Literal["hbase"] = "hbase"
"""Online store type selector"""
- host: str
+ host: StrictStr
"""Hostname of Hbase Thrift server"""
- port: str
+ port: StrictStr
"""Port in which Hbase Thrift server is running"""
+ connection_pool_size: int = 4
+ """Number of connections to Hbase Thrift server to keep in the connection pool"""
-class HbaseConnection:
- """
- Hbase connecttion to connect to hbase.
-
- Attributes:
- store_config: Online store config for Hbase store.
- """
-
- def __init__(self, store_config: HbaseOnlineStoreConfig):
- self._store_config = store_config
- self._real_conn = Connection(
- host=store_config.host, port=int(store_config.port)
- )
+ protocol: StrictStr = DEFAULT_PROTOCOL
+ """Protocol used to communicate with Hbase Thrift server"""
- @property
- def real_conn(self) -> Connection:
- """Stores the real happybase Connection to connect to hbase."""
- return self._real_conn
-
- def close(self) -> None:
- """Close the happybase connection."""
- self.real_conn.close()
+ transport: StrictStr = DEFAULT_TRANSPORT
+ """Transport used to communicate with Hbase Thrift server"""
class HbaseOnlineStore(OnlineStore):
@@ -62,7 +48,7 @@ class HbaseOnlineStore(OnlineStore):
_conn: Happybase Connection to connect to hbase thrift server.
"""
- _conn: Connection = None
+ _conn: ConnectionPool = None
def _get_conn(self, config: RepoConfig):
"""
@@ -76,7 +62,13 @@ def _get_conn(self, config: RepoConfig):
assert isinstance(store_config, HbaseOnlineStoreConfig)
if not self._conn:
- self._conn = Connection(host=store_config.host, port=int(store_config.port))
+ self._conn = ConnectionPool(
+ host=store_config.host,
+ port=int(store_config.port),
+ size=int(store_config.connection_pool_size),
+ protocol=store_config.protocol,
+ transport=store_config.transport,
+ )
return self._conn
@log_exceptions_and_usage(online_store="hbase")
@@ -102,16 +94,17 @@ def online_write_batch(
the online store. Can be used to display progress.
"""
- hbase = HbaseUtils(self._get_conn(config))
+ hbase = HBaseConnector(self._get_conn(config))
project = config.project
- table_name = _table_id(project, table)
+ table_name = self._table_id(project, table)
b = hbase.batch(table_name)
for entity_key, values, timestamp, created_ts in data:
- row_key = serialize_entity_key(
+ row_key = self._hbase_row_key(
entity_key,
- entity_key_serialization_version=config.entity_key_serialization_version,
- ).hex()
+ feature_view_name=table.name,
+ config=config,
+ )
values_dict = {}
for feature_name, val in values.items():
values_dict[
@@ -133,6 +126,9 @@ def online_write_batch(
b.put(row_key, values_dict)
b.send()
+ if progress:
+ progress(len(data))
+
@log_exceptions_and_usage(online_store="hbase")
def online_read(
self,
@@ -150,17 +146,18 @@ def online_read(
entity_keys: a list of entity keys that should be read from the FeatureStore.
requested_features: a list of requested feature names.
"""
- hbase = HbaseUtils(self._get_conn(config))
+ hbase = HBaseConnector(self._get_conn(config))
project = config.project
- table_name = _table_id(project, table)
+ table_name = self._table_id(project, table)
result: List[Tuple[Optional[datetime], Optional[Dict[str, ValueProto]]]] = []
row_keys = [
- serialize_entity_key(
+ self._hbase_row_key(
entity_key,
- entity_key_serialization_version=config.entity_key_serialization_version,
- ).hex()
+ feature_view_name=table.name,
+ config=config,
+ )
for entity_key in entity_keys
]
rows = hbase.rows(table_name, row_keys=row_keys)
@@ -201,17 +198,17 @@ def update(
tables_to_delete: Tables to delete from the Hbase Online Store.
tables_to_keep: Tables to keep in the Hbase Online Store.
"""
- hbase = HbaseUtils(self._get_conn(config))
+ hbase = HBaseConnector(self._get_conn(config))
project = config.project
# We don't create any special state for the entites in this implementation.
for table in tables_to_keep:
- table_name = _table_id(project, table)
+ table_name = self._table_id(project, table)
if not hbase.check_if_table_exist(table_name):
hbase.create_table_with_default_cf(table_name)
for table in tables_to_delete:
- table_name = _table_id(project, table)
+ table_name = self._table_id(project, table)
hbase.delete_table(table_name)
def teardown(
@@ -227,20 +224,47 @@ def teardown(
config: The RepoConfig for the current FeatureStore.
tables: Tables to delete from the feature repo.
"""
- hbase = HbaseUtils(self._get_conn(config))
+ hbase = HBaseConnector(self._get_conn(config))
project = config.project
for table in tables:
- table_name = _table_id(project, table)
+ table_name = self._table_id(project, table)
hbase.delete_table(table_name)
+ def _hbase_row_key(
+ self,
+ entity_key: EntityKeyProto,
+ feature_view_name: str,
+ config: RepoConfig,
+ ) -> bytes:
+ """
+ Computes the HBase row key for a given entity key and feature view name.
-def _table_id(project: str, table: FeatureView) -> str:
- """
- Returns table name given the project_name and the feature_view.
+ Args:
+ entity_key (EntityKeyProto): The entity key to compute the row key for.
+ feature_view_name (str): The name of the feature view to compute the row key for.
+ config (RepoConfig): The configuration for the Feast repository.
- Args:
- project: Name of the feast project.
- table: Feast FeatureView.
- """
- return f"{project}_{table.name}"
+ Returns:
+ bytes: The HBase row key for the given entity key and feature view name.
+ """
+ entity_id = compute_entity_id(
+ entity_key,
+ entity_key_serialization_version=config.entity_key_serialization_version,
+ )
+ # Even though `entity_id` uniquely identifies an entity, we use the same table
+ # for multiple feature_views with the same set of entities.
+ # To uniquely identify the row for a feature_view, we suffix the name of the feature_view itself.
+ # This also ensures that features for entities from various feature_views are
+ # colocated.
+ return f"{entity_id}#{feature_view_name}".encode()
+
+ def _table_id(self, project: str, table: FeatureView) -> str:
+ """
+ Returns table name given the project_name and the feature_view.
+
+ Args:
+ project: Name of the feast project.
+ table: Feast FeatureView.
+ """
+ return f"{project}:{table.name}"
diff --git a/sdk/python/feast/infra/online_stores/contrib/mysql_online_store/mysql.py b/sdk/python/feast/infra/online_stores/contrib/mysql_online_store/mysql.py
index fa7dd2c2a49..cf07d5fef12 100644
--- a/sdk/python/feast/infra/online_stores/contrib/mysql_online_store/mysql.py
+++ b/sdk/python/feast/infra/online_stores/contrib/mysql_online_store/mysql.py
@@ -1,7 +1,7 @@
from __future__ import absolute_import
from datetime import datetime
-from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
+from typing import Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple
import pymysql
import pytz
@@ -23,7 +23,7 @@ class MySQLOnlineStoreConfig(FeastConfigBaseModel):
NOTE: The class *must* end with the `OnlineStoreConfig` suffix.
"""
- type = "mysql"
+ type: Literal["mysql"] = "mysql"
host: Optional[StrictStr] = None
user: Optional[StrictStr] = None
@@ -178,8 +178,11 @@ def update(
# We don't create any special state for the entities in this implementation.
for table in tables_to_keep:
+
+ table_name = _table_id(project, table)
+ index_name = f"{table_name}_ek"
cur.execute(
- f"""CREATE TABLE IF NOT EXISTS {_table_id(project, table)} (entity_key VARCHAR(512),
+ f"""CREATE TABLE IF NOT EXISTS {table_name} (entity_key VARCHAR(512),
feature_name VARCHAR(256),
value BLOB,
event_ts timestamp NULL DEFAULT NULL,
@@ -187,9 +190,16 @@ def update(
PRIMARY KEY(entity_key, feature_name))"""
)
- cur.execute(
- f"ALTER TABLE {_table_id(project, table)} ADD INDEX {_table_id(project, table)}_ek (entity_key);"
+ index_exists = cur.execute(
+ f"""
+ SELECT 1 FROM information_schema.statistics
+ WHERE table_schema = DATABASE() AND table_name = '{table_name}' AND index_name = '{index_name}'
+ """
)
+ if not index_exists:
+ cur.execute(
+ f"ALTER TABLE {table_name} ADD INDEX {index_name} (entity_key);"
+ )
for table in tables_to_delete:
_drop_table_and_index(cur, project, table)
diff --git a/sdk/python/feast/infra/online_stores/contrib/postgres.py b/sdk/python/feast/infra/online_stores/contrib/postgres.py
index a12e66f1090..308528aaec2 100644
--- a/sdk/python/feast/infra/online_stores/contrib/postgres.py
+++ b/sdk/python/feast/infra/online_stores/contrib/postgres.py
@@ -2,14 +2,13 @@
import logging
from collections import defaultdict
from datetime import datetime
-from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
+from typing import Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple
import psycopg2
import pytz
from psycopg2 import sql
from psycopg2.extras import execute_values
from psycopg2.pool import SimpleConnectionPool
-from pydantic.schema import Literal
from feast import Entity
from feast.feature_view import FeatureView
@@ -99,6 +98,7 @@ def online_write_batch(
cur_batch,
page_size=batch_size,
)
+ conn.commit()
if progress:
progress(len(cur_batch))
diff --git a/sdk/python/feast/infra/online_stores/datastore.py b/sdk/python/feast/infra/online_stores/datastore.py
index ed4e7612ba5..ae96e16c640 100644
--- a/sdk/python/feast/infra/online_stores/datastore.py
+++ b/sdk/python/feast/infra/online_stores/datastore.py
@@ -17,10 +17,19 @@
from multiprocessing.pool import ThreadPool
from queue import Empty, Queue
from threading import Lock, Thread
-from typing import Any, Callable, Dict, Iterator, List, Optional, Sequence, Tuple
+from typing import (
+ Any,
+ Callable,
+ Dict,
+ Iterator,
+ List,
+ Literal,
+ Optional,
+ Sequence,
+ Tuple,
+)
from pydantic import PositiveInt, StrictStr
-from pydantic.typing import Literal
from feast import Entity, utils
from feast.errors import FeastProviderLoginError
diff --git a/sdk/python/feast/infra/online_stores/dynamodb.py b/sdk/python/feast/infra/online_stores/dynamodb.py
index 525978e736b..a049189de7f 100644
--- a/sdk/python/feast/infra/online_stores/dynamodb.py
+++ b/sdk/python/feast/infra/online_stores/dynamodb.py
@@ -14,10 +14,9 @@
import itertools
import logging
from datetime import datetime
-from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
+from typing import Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple, Union
from pydantic import StrictBool, StrictStr
-from pydantic.typing import Literal, Union
from feast import Entity, FeatureView, utils
from feast.infra.infra_object import DYNAMODB_INFRA_OBJECT_CLASS_TYPE, InfraObject
@@ -288,12 +287,12 @@ def _get_dynamodb_resource(self, region: str, endpoint_url: Optional[str] = None
)
return self._dynamodb_resource
- def _sort_dynamodb_response(self, responses: list, order: list):
+ def _sort_dynamodb_response(self, responses: list, order: list) -> Any:
"""DynamoDB Batch Get Item doesn't return items in a particular order."""
# Assign an index to order
order_with_index = {value: idx for idx, value in enumerate(order)}
# Sort table responses by index
- table_responses_ordered = [
+ table_responses_ordered: Any = [
(order_with_index[tbl_res["entity_id"]], tbl_res) for tbl_res in responses
]
table_responses_ordered = sorted(
diff --git a/sdk/python/feast/infra/online_stores/redis.py b/sdk/python/feast/infra/online_stores/redis.py
index 8af20970764..ad84e8db7c9 100644
--- a/sdk/python/feast/infra/online_stores/redis.py
+++ b/sdk/python/feast/infra/online_stores/redis.py
@@ -21,6 +21,7 @@
Callable,
Dict,
List,
+ Literal,
Optional,
Sequence,
Tuple,
@@ -30,7 +31,6 @@
import pytz
from google.protobuf.timestamp_pb2 import Timestamp
from pydantic import StrictStr
-from pydantic.typing import Literal
from feast import Entity, FeatureView, RepoConfig, utils
from feast.infra.online_stores.helpers import _mmh3, _redis_key, _redis_key_prefix
@@ -43,6 +43,7 @@
try:
from redis import Redis
from redis.cluster import ClusterNode, RedisCluster
+ from redis.sentinel import Sentinel
except ImportError as e:
from feast.errors import FeastExtrasDependencyImportError
@@ -54,6 +55,7 @@
class RedisType(str, Enum):
redis = "redis"
redis_cluster = "redis_cluster"
+ redis_sentinel = "redis_sentinel"
class RedisOnlineStoreConfig(FeastConfigBaseModel):
@@ -65,6 +67,9 @@ class RedisOnlineStoreConfig(FeastConfigBaseModel):
redis_type: RedisType = RedisType.redis
"""Redis type: redis or redis_cluster"""
+ sentinel_master: StrictStr = "mymaster"
+ """Sentinel's master name"""
+
connection_string: StrictStr = "localhost:6379"
"""Connection string containing the host, port, and configuration parameters for Redis
format: host:port,parameter1,parameter2 eg. redis:6379,db=0 """
@@ -89,15 +94,15 @@ class RedisOnlineStore(OnlineStore):
def delete_entity_values(self, config: RepoConfig, join_keys: List[str]):
client = self._get_client(config.online_store)
deleted_count = 0
- pipeline = client.pipeline(transaction=False)
prefix = _redis_key_prefix(join_keys)
- for _k in client.scan_iter(
- b"".join([prefix, b"*", config.project.encode("utf8")])
- ):
- pipeline.delete(_k)
- deleted_count += 1
- pipeline.execute()
+ with client.pipeline(transaction=False) as pipe:
+ for _k in client.scan_iter(
+ b"".join([prefix, b"*", config.project.encode("utf8")])
+ ):
+ pipe.delete(_k)
+ deleted_count += 1
+ pipe.execute()
logger.debug(f"Deleted {deleted_count} rows for entity {', '.join(join_keys)}")
@@ -178,6 +183,15 @@ def _get_client(self, online_store_config: RedisOnlineStoreConfig):
ClusterNode(**node) for node in startup_nodes
]
self._client = RedisCluster(**kwargs)
+ elif online_store_config.redis_type == RedisType.redis_sentinel:
+ sentinel_hosts = []
+
+ for item in startup_nodes:
+ sentinel_hosts.append((item["host"], int(item["port"])))
+
+ sentinel = Sentinel(sentinel_hosts, **kwargs)
+ master = sentinel.master_for(online_store_config.sentinel_master)
+ self._client = master
else:
kwargs["host"] = startup_nodes[0]["host"]
kwargs["port"] = startup_nodes[0]["port"]
diff --git a/sdk/python/feast/infra/online_stores/snowflake.py b/sdk/python/feast/infra/online_stores/snowflake.py
index c1a03a2862c..f5600249c91 100644
--- a/sdk/python/feast/infra/online_stores/snowflake.py
+++ b/sdk/python/feast/infra/online_stores/snowflake.py
@@ -2,11 +2,10 @@
import os
from binascii import hexlify
from datetime import datetime
-from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
+from typing import Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple
import pandas as pd
-from pydantic import Field, StrictStr
-from pydantic.schema import Literal
+from pydantic import ConfigDict, Field, StrictStr
from feast.entity import Entity
from feast.feature_view import FeatureView
@@ -57,9 +56,7 @@ class SnowflakeOnlineStoreConfig(FeastConfigBaseModel):
schema_: Optional[str] = Field("PUBLIC", alias="schema")
""" Snowflake schema name """
-
- class Config:
- allow_population_by_field_name = True
+ model_config = ConfigDict(populate_by_name=True)
class SnowflakeOnlineStore(OnlineStore):
diff --git a/sdk/python/feast/infra/online_stores/sqlite.py b/sdk/python/feast/infra/online_stores/sqlite.py
index 6949b2bf247..4a6aa28889d 100644
--- a/sdk/python/feast/infra/online_stores/sqlite.py
+++ b/sdk/python/feast/infra/online_stores/sqlite.py
@@ -16,10 +16,9 @@
import sqlite3
from datetime import datetime
from pathlib import Path
-from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
+from typing import Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple
from pydantic import StrictStr
-from pydantic.schema import Literal
from feast import Entity
from feast.feature_view import FeatureView
diff --git a/sdk/python/feast/infra/passthrough_provider.py b/sdk/python/feast/infra/passthrough_provider.py
index 28b10c12595..aca18f4856b 100644
--- a/sdk/python/feast/infra/passthrough_provider.py
+++ b/sdk/python/feast/infra/passthrough_provider.py
@@ -70,7 +70,7 @@ def batch_engine(self) -> BatchMaterializationEngine:
if self._batch_engine:
return self._batch_engine
else:
- engine_config = self.repo_config._batch_engine_config
+ engine_config = self.repo_config.batch_engine_config
config_is_dict = False
if isinstance(engine_config, str):
engine_config_type = engine_config
@@ -180,7 +180,7 @@ def online_read(
config: RepoConfig,
table: FeatureView,
entity_keys: List[EntityKeyProto],
- requested_features: List[str] = None,
+ requested_features: Optional[List[str]] = None,
) -> List:
set_usage_attribute("provider", self.__class__.__name__)
result = []
diff --git a/sdk/python/feast/infra/provider.py b/sdk/python/feast/infra/provider.py
index 82879b264af..2a9670cacef 100644
--- a/sdk/python/feast/infra/provider.py
+++ b/sdk/python/feast/infra/provider.py
@@ -211,7 +211,7 @@ def online_read(
config: RepoConfig,
table: FeatureView,
entity_keys: List[EntityKeyProto],
- requested_features: List[str] = None,
+ requested_features: Optional[List[str]] = None,
) -> List[Tuple[Optional[datetime], Optional[Dict[str, ValueProto]]]]:
"""
Reads features values for the given entity keys.
diff --git a/sdk/python/feast/infra/registry/base_registry.py b/sdk/python/feast/infra/registry/base_registry.py
index 14b098bb123..f23a820d239 100644
--- a/sdk/python/feast/infra/registry/base_registry.py
+++ b/sdk/python/feast/infra/registry/base_registry.py
@@ -51,6 +51,7 @@ def apply_entity(self, entity: Entity, project: str, commit: bool = True):
project: Feast project that this entity belongs to
commit: Whether the change should be persisted immediately
"""
+ raise NotImplementedError
@abstractmethod
def delete_entity(self, name: str, project: str, commit: bool = True):
@@ -62,6 +63,7 @@ def delete_entity(self, name: str, project: str, commit: bool = True):
project: Feast project that this entity belongs to
commit: Whether the change should be persisted immediately
"""
+ raise NotImplementedError
@abstractmethod
def get_entity(self, name: str, project: str, allow_cache: bool = False) -> Entity:
@@ -77,6 +79,7 @@ def get_entity(self, name: str, project: str, allow_cache: bool = False) -> Enti
Returns either the specified entity, or raises an exception if
none is found
"""
+ raise NotImplementedError
@abstractmethod
def list_entities(self, project: str, allow_cache: bool = False) -> List[Entity]:
@@ -90,6 +93,7 @@ def list_entities(self, project: str, allow_cache: bool = False) -> List[Entity]
Returns:
List of entities
"""
+ raise NotImplementedError
# Data source operations
@abstractmethod
@@ -104,6 +108,7 @@ def apply_data_source(
project: Feast project that this data source belongs to
commit: Whether to immediately commit to the registry
"""
+ raise NotImplementedError
@abstractmethod
def delete_data_source(self, name: str, project: str, commit: bool = True):
@@ -115,6 +120,7 @@ def delete_data_source(self, name: str, project: str, commit: bool = True):
project: Feast project that this data source belongs to
commit: Whether the change should be persisted immediately
"""
+ raise NotImplementedError
@abstractmethod
def get_data_source(
@@ -131,6 +137,7 @@ def get_data_source(
Returns:
Returns either the specified data source, or raises an exception if none is found
"""
+ raise NotImplementedError
@abstractmethod
def list_data_sources(
@@ -146,6 +153,7 @@ def list_data_sources(
Returns:
List of data sources
"""
+ raise NotImplementedError
# Feature service operations
@abstractmethod
@@ -159,6 +167,7 @@ def apply_feature_service(
feature_service: A feature service that will be registered
project: Feast project that this entity belongs to
"""
+ raise NotImplementedError
@abstractmethod
def delete_feature_service(self, name: str, project: str, commit: bool = True):
@@ -170,6 +179,7 @@ def delete_feature_service(self, name: str, project: str, commit: bool = True):
project: Feast project that this feature service belongs to
commit: Whether the change should be persisted immediately
"""
+ raise NotImplementedError
@abstractmethod
def get_feature_service(
@@ -187,6 +197,7 @@ def get_feature_service(
Returns either the specified feature service, or raises an exception if
none is found
"""
+ raise NotImplementedError
@abstractmethod
def list_feature_services(
@@ -202,6 +213,7 @@ def list_feature_services(
Returns:
List of feature services
"""
+ raise NotImplementedError
# Feature view operations
@abstractmethod
@@ -216,6 +228,7 @@ def apply_feature_view(
project: Feast project that this feature view belongs to
commit: Whether the change should be persisted immediately
"""
+ raise NotImplementedError
@abstractmethod
def delete_feature_view(self, name: str, project: str, commit: bool = True):
@@ -227,6 +240,7 @@ def delete_feature_view(self, name: str, project: str, commit: bool = True):
project: Feast project that this feature view belongs to
commit: Whether the change should be persisted immediately
"""
+ raise NotImplementedError
# stream feature view operations
@abstractmethod
@@ -245,6 +259,7 @@ def get_stream_feature_view(
Returns either the specified feature view, or raises an exception if
none is found
"""
+ raise NotImplementedError
@abstractmethod
def list_stream_feature_views(
@@ -260,6 +275,7 @@ def list_stream_feature_views(
Returns:
List of stream feature views
"""
+ raise NotImplementedError
# on demand feature view operations
@abstractmethod
@@ -278,6 +294,7 @@ def get_on_demand_feature_view(
Returns either the specified on demand feature view, or raises an exception if
none is found
"""
+ raise NotImplementedError
@abstractmethod
def list_on_demand_feature_views(
@@ -293,6 +310,7 @@ def list_on_demand_feature_views(
Returns:
List of on demand feature views
"""
+ raise NotImplementedError
# regular feature view operations
@abstractmethod
@@ -311,6 +329,7 @@ def get_feature_view(
Returns either the specified feature view, or raises an exception if
none is found
"""
+ raise NotImplementedError
@abstractmethod
def list_feature_views(
@@ -326,10 +345,13 @@ def list_feature_views(
Returns:
List of feature views
"""
+ raise NotImplementedError
# request feature view operations
@abstractmethod
- def get_request_feature_view(self, name: str, project: str) -> RequestFeatureView:
+ def get_request_feature_view(
+ self, name: str, project: str, allow_cache: bool = False
+ ) -> RequestFeatureView:
"""
Retrieves a request feature view.
@@ -342,6 +364,7 @@ def get_request_feature_view(self, name: str, project: str) -> RequestFeatureVie
Returns either the specified feature view, or raises an exception if
none is found
"""
+ raise NotImplementedError
@abstractmethod
def list_request_feature_views(
@@ -357,6 +380,7 @@ def list_request_feature_views(
Returns:
List of request feature views
"""
+ raise NotImplementedError
@abstractmethod
def apply_materialization(
@@ -377,6 +401,7 @@ def apply_materialization(
end_date (datetime): End date of the materialization interval to track
commit: Whether the change should be persisted immediately
"""
+ raise NotImplementedError
# Saved dataset operations
@abstractmethod
@@ -394,6 +419,7 @@ def apply_saved_dataset(
project: Feast project that this dataset belongs to
commit: Whether the change should be persisted immediately
"""
+ raise NotImplementedError
@abstractmethod
def get_saved_dataset(
@@ -411,6 +437,7 @@ def get_saved_dataset(
Returns either the specified SavedDataset, or raises an exception if
none is found
"""
+ raise NotImplementedError
def delete_saved_dataset(self, name: str, project: str, allow_cache: bool = False):
"""
@@ -425,6 +452,7 @@ def delete_saved_dataset(self, name: str, project: str, allow_cache: bool = Fals
Returns either the specified SavedDataset, or raises an exception if
none is found
"""
+ raise NotImplementedError
@abstractmethod
def list_saved_datasets(
@@ -440,6 +468,7 @@ def list_saved_datasets(
Returns:
Returns the list of SavedDatasets
"""
+ raise NotImplementedError
# Validation reference operations
@abstractmethod
@@ -457,6 +486,7 @@ def apply_validation_reference(
project: Feast project that this dataset belongs to
commit: Whether the change should be persisted immediately
"""
+ raise NotImplementedError
@abstractmethod
def delete_validation_reference(self, name: str, project: str, commit: bool = True):
@@ -468,6 +498,7 @@ def delete_validation_reference(self, name: str, project: str, commit: bool = Tr
project: Feast project that this object belongs to
commit: Whether the change should be persisted immediately
"""
+ raise NotImplementedError
@abstractmethod
def get_validation_reference(
@@ -485,6 +516,7 @@ def get_validation_reference(
Returns either the specified ValidationReference, or raises an exception if
none is found
"""
+ raise NotImplementedError
# TODO: Needs to be implemented.
def list_validation_references(
@@ -501,7 +533,9 @@ def list_validation_references(
Returns:
List of request feature views
"""
+ raise NotImplementedError
+ @abstractmethod
def list_project_metadata(
self, project: str, allow_cache: bool = False
) -> List[ProjectMetadata]:
@@ -515,6 +549,7 @@ def list_project_metadata(
Returns:
List of project metadata
"""
+ raise NotImplementedError
@abstractmethod
def update_infra(self, infra: Infra, project: str, commit: bool = True):
@@ -526,6 +561,7 @@ def update_infra(self, infra: Infra, project: str, commit: bool = True):
project: Feast project that the Infra object refers to
commit: Whether the change should be persisted immediately
"""
+ raise NotImplementedError
@abstractmethod
def get_infra(self, project: str, allow_cache: bool = False) -> Infra:
@@ -539,6 +575,7 @@ def get_infra(self, project: str, allow_cache: bool = False) -> Infra:
Returns:
The stored Infra object.
"""
+ raise NotImplementedError
@abstractmethod
def apply_user_metadata(
@@ -563,14 +600,17 @@ def proto(self) -> RegistryProto:
Returns:
The registry proto object.
"""
+ raise NotImplementedError
@abstractmethod
def commit(self):
"""Commits the state of the registry cache to the remote registry store."""
+ raise NotImplementedError
@abstractmethod
def refresh(self, project: Optional[str] = None):
"""Refreshes the state of the registry cache by fetching the registry state from the remote registry store."""
+ raise NotImplementedError
@staticmethod
def _message_to_sorted_dict(message: Message) -> Dict[str, Any]:
diff --git a/sdk/python/feast/infra/registry/proto_registry_utils.py b/sdk/python/feast/infra/registry/proto_registry_utils.py
index 2a275703dbb..e93f513b691 100644
--- a/sdk/python/feast/infra/registry/proto_registry_utils.py
+++ b/sdk/python/feast/infra/registry/proto_registry_utils.py
@@ -1,4 +1,5 @@
import uuid
+from functools import wraps
from typing import List, Optional
from feast import usage
@@ -23,6 +24,26 @@
from feast.stream_feature_view import StreamFeatureView
+def registry_proto_cache(func):
+ cache_key = None
+ cache_value = None
+
+ @wraps(func)
+ def wrapper(registry_proto: RegistryProto, project: str):
+ nonlocal cache_key, cache_value
+
+ key = tuple([id(registry_proto), registry_proto.version_id, project])
+
+ if key == cache_key:
+ return cache_value
+ else:
+ cache_value = func(registry_proto, project)
+ cache_key = key
+ return cache_value
+
+ return wrapper
+
+
def init_project_metadata(cached_registry_proto: RegistryProto, project: str):
new_project_uuid = f"{uuid.uuid4()}"
usage.set_current_project_uuid(new_project_uuid)
@@ -137,8 +158,9 @@ def get_validation_reference(
raise ValidationReferenceNotFound(name, project=project)
+@registry_proto_cache
def list_feature_services(
- registry_proto: RegistryProto, project: str, allow_cache: bool = False
+ registry_proto: RegistryProto, project: str
) -> List[FeatureService]:
feature_services = []
for feature_service_proto in registry_proto.feature_services:
@@ -147,6 +169,7 @@ def list_feature_services(
return feature_services
+@registry_proto_cache
def list_feature_views(
registry_proto: RegistryProto, project: str
) -> List[FeatureView]:
@@ -157,6 +180,7 @@ def list_feature_views(
return feature_views
+@registry_proto_cache
def list_request_feature_views(
registry_proto: RegistryProto, project: str
) -> List[RequestFeatureView]:
@@ -169,6 +193,7 @@ def list_request_feature_views(
return feature_views
+@registry_proto_cache
def list_stream_feature_views(
registry_proto: RegistryProto, project: str
) -> List[StreamFeatureView]:
@@ -181,6 +206,7 @@ def list_stream_feature_views(
return stream_feature_views
+@registry_proto_cache
def list_on_demand_feature_views(
registry_proto: RegistryProto, project: str
) -> List[OnDemandFeatureView]:
@@ -193,6 +219,7 @@ def list_on_demand_feature_views(
return on_demand_feature_views
+@registry_proto_cache
def list_entities(registry_proto: RegistryProto, project: str) -> List[Entity]:
entities = []
for entity_proto in registry_proto.entities:
@@ -201,6 +228,7 @@ def list_entities(registry_proto: RegistryProto, project: str) -> List[Entity]:
return entities
+@registry_proto_cache
def list_data_sources(registry_proto: RegistryProto, project: str) -> List[DataSource]:
data_sources = []
for data_source_proto in registry_proto.data_sources:
@@ -209,16 +237,18 @@ def list_data_sources(registry_proto: RegistryProto, project: str) -> List[DataS
return data_sources
+@registry_proto_cache
def list_saved_datasets(
registry_proto: RegistryProto, project: str
) -> List[SavedDataset]:
saved_datasets = []
for saved_dataset in registry_proto.saved_datasets:
- if saved_dataset.project == project:
+ if saved_dataset.spec.project == project:
saved_datasets.append(SavedDataset.from_proto(saved_dataset))
return saved_datasets
+@registry_proto_cache
def list_validation_references(
registry_proto: RegistryProto, project: str
) -> List[ValidationReference]:
@@ -231,6 +261,7 @@ def list_validation_references(
return validation_references
+@registry_proto_cache
def list_project_metadata(
registry_proto: RegistryProto, project: str
) -> List[ProjectMetadata]:
diff --git a/sdk/python/feast/infra/registry/registry.py b/sdk/python/feast/infra/registry/registry.py
index 1a72cbb4a58..fc7be75e0d3 100644
--- a/sdk/python/feast/infra/registry/registry.py
+++ b/sdk/python/feast/infra/registry/registry.py
@@ -528,8 +528,12 @@ def list_feature_views(
)
return proto_registry_utils.list_feature_views(registry_proto, project)
- def get_request_feature_view(self, name: str, project: str):
- registry_proto = self._get_registry_proto(project=project, allow_cache=False)
+ def get_request_feature_view(
+ self, name: str, project: str, allow_cache: bool = False
+ ):
+ registry_proto = self._get_registry_proto(
+ project=project, allow_cache=allow_cache
+ )
return proto_registry_utils.get_request_feature_view(
registry_proto, name, project
)
diff --git a/sdk/python/feast/infra/registry/registry_store.py b/sdk/python/feast/infra/registry/registry_store.py
index c42a55cd9d2..5151fd74b27 100644
--- a/sdk/python/feast/infra/registry/registry_store.py
+++ b/sdk/python/feast/infra/registry/registry_store.py
@@ -17,7 +17,7 @@ def get_registry_proto(self) -> RegistryProto:
Returns:
Returns either the registry proto stored at the registry path, or an empty registry proto.
"""
- pass
+ raise NotImplementedError
@abstractmethod
def update_registry_proto(self, registry_proto: RegistryProto):
@@ -40,7 +40,7 @@ def teardown(self):
class NoopRegistryStore(RegistryStore):
def get_registry_proto(self) -> RegistryProto:
- pass
+ return RegistryProto()
def update_registry_proto(self, registry_proto: RegistryProto):
pass
diff --git a/sdk/python/feast/infra/registry/snowflake.py b/sdk/python/feast/infra/registry/snowflake.py
index 56c7bc1f659..cdf79c78b5f 100644
--- a/sdk/python/feast/infra/registry/snowflake.py
+++ b/sdk/python/feast/infra/registry/snowflake.py
@@ -5,10 +5,9 @@
from datetime import datetime, timedelta
from enum import Enum
from threading import Lock
-from typing import Any, Callable, List, Optional, Set, Union
+from typing import Any, Callable, List, Literal, Optional, Set, Union
-from pydantic import Field, StrictStr
-from pydantic.schema import Literal
+from pydantic import ConfigDict, Field, StrictStr
import feast
from feast import usage
@@ -103,9 +102,7 @@ class SnowflakeRegistryConfig(RegistryConfig):
schema_: Optional[str] = Field("PUBLIC", alias="schema")
""" Snowflake schema name """
-
- class Config:
- allow_population_by_field_name = True
+ model_config = ConfigDict(populate_by_name=True)
class SnowflakeRegistry(BaseRegistry):
@@ -418,7 +415,7 @@ def _delete_object(
"""
cursor = execute_snowflake_statement(conn, query)
- if cursor.rowcount < 1 and not_found_exception:
+ if cursor.rowcount < 1 and not_found_exception: # type: ignore
raise not_found_exception(name, project)
self._set_last_updated_metadata(datetime.utcnow(), project)
diff --git a/sdk/python/feast/infra/registry/sql.py b/sdk/python/feast/infra/registry/sql.py
index 54ff7c9dc85..d57bcc7c0a3 100644
--- a/sdk/python/feast/infra/registry/sql.py
+++ b/sdk/python/feast/infra/registry/sql.py
@@ -81,7 +81,7 @@
data_sources = Table(
"data_sources",
metadata,
- Column("data_source_name", String(50), primary_key=True),
+ Column("data_source_name", String(255), primary_key=True),
Column("project_id", String(50), primary_key=True),
Column("last_updated_timestamp", BigInteger, nullable=False),
Column("data_source_proto", LargeBinary, nullable=False),
diff --git a/sdk/python/feast/infra/transformation_servers/Dockerfile b/sdk/python/feast/infra/transformation_servers/Dockerfile
index c072ed01604..41f272c757c 100644
--- a/sdk/python/feast/infra/transformation_servers/Dockerfile
+++ b/sdk/python/feast/infra/transformation_servers/Dockerfile
@@ -15,7 +15,7 @@ COPY README.md README.md
# Install dependencies
-RUN --mount=source=.git,target=.git,type=bind pip3 install --no-cache-dir -e '.[gcp,aws]'
+RUN --mount=source=.git,target=.git,type=bind pip3 install --no-cache-dir '.[gcp,aws]'
# Start feature transformation server
CMD [ "python", "app.py" ]
diff --git a/sdk/python/feast/infra/utils/aws_utils.py b/sdk/python/feast/infra/utils/aws_utils.py
index 5095ef42219..c3604ee41f0 100644
--- a/sdk/python/feast/infra/utils/aws_utils.py
+++ b/sdk/python/feast/infra/utils/aws_utils.py
@@ -351,7 +351,14 @@ def upload_arrow_table_to_redshift(
else:
# Write the PyArrow Table on disk in Parquet format and upload it to S3
with tempfile.TemporaryFile(suffix=".parquet") as parquet_temp_file:
- pq.write_table(table, parquet_temp_file)
+ # In Pyarrow v13.0, the parquet version was upgraded to v2.6 from v2.4.
+ # Set the coerce_timestamps to "us"(microseconds) for backward compatibility.
+ pq.write_table(
+ table,
+ parquet_temp_file,
+ coerce_timestamps="us",
+ allow_truncated_timestamps=True,
+ )
parquet_temp_file.seek(0)
s3_resource.Object(bucket, key).put(Body=parquet_temp_file)
@@ -755,7 +762,7 @@ def execute_athena_query_async(
# return athena_data_client.execute_statement(
return athena_data_client.start_query_execution(
QueryString=query,
- QueryExecutionContext={"Database": database},
+ QueryExecutionContext={"Database": database, "Catalog": data_source},
WorkGroup=workgroup,
)
@@ -809,7 +816,7 @@ def execute_athena_query(
database: str,
workgroup: str,
query: str,
- temp_table: str = None,
+ temp_table: Optional[str] = None,
) -> str:
"""Execute athena statement synchronously. Waits for the query to finish.
diff --git a/sdk/python/feast/infra/utils/hbase_utils.py b/sdk/python/feast/infra/utils/hbase_utils.py
index 4816a60087c..72afda2ef3d 100644
--- a/sdk/python/feast/infra/utils/hbase_utils.py
+++ b/sdk/python/feast/infra/utils/hbase_utils.py
@@ -1,9 +1,6 @@
-from typing import List
+from typing import List, Optional
-from happybase import Connection
-
-from feast.infra.key_encoding_utils import serialize_entity_key
-from feast.protos.feast.types.EntityKey_pb2 import EntityKey
+from happybase import ConnectionPool
class HbaseConstants:
@@ -28,7 +25,7 @@ def get_col_from_feature(feature):
return HbaseConstants.DEFAULT_COLUMN_FAMILY + ":" + feature
-class HbaseUtils:
+class HBaseConnector:
"""
Utils class to manage different Hbase operations.
@@ -40,14 +37,22 @@ class HbaseUtils:
"""
def __init__(
- self, conn: Connection = None, host: str = None, port: int = None, timeout=None
+ self,
+ pool: Optional[ConnectionPool] = None,
+ host: Optional[str] = None,
+ port: Optional[int] = None,
+ connection_pool_size: int = 4,
):
- if conn is None:
+ if pool is None:
self.host = host
self.port = port
- self.conn = Connection(host=host, port=port, timeout=timeout)
+ self.pool = ConnectionPool(
+ host=host,
+ port=port,
+ size=connection_pool_size,
+ )
else:
- self.conn = conn
+ self.pool = pool
def create_table(self, table_name: str, colm_family: List[str]):
"""
@@ -60,7 +65,9 @@ def create_table(self, table_name: str, colm_family: List[str]):
cf_dict: dict = {}
for cf in colm_family:
cf_dict[cf] = dict()
- return self.conn.create_table(table_name, cf_dict)
+
+ with self.pool.connection() as conn:
+ return conn.create_table(table_name, cf_dict)
def create_table_with_default_cf(self, table_name: str):
"""
@@ -69,7 +76,8 @@ def create_table_with_default_cf(self, table_name: str):
Arguments:
table_name: Name of the Hbase table.
"""
- return self.conn.create_table(table_name, {"default": dict()})
+ with self.pool.connection() as conn:
+ return conn.create_table(table_name, {"default": dict()})
def check_if_table_exist(self, table_name: str):
"""
@@ -78,16 +86,18 @@ def check_if_table_exist(self, table_name: str):
Arguments:
table_name: Name of the Hbase table.
"""
- return bytes(table_name, "utf-8") in self.conn.tables()
+ with self.pool.connection() as conn:
+ return bytes(table_name, "utf-8") in conn.tables()
def batch(self, table_name: str):
"""
- Returns a 'Batch' instance that can be used for mass data manipulation in the hbase table.
+ Returns a "Batch" instance that can be used for mass data manipulation in the hbase table.
Arguments:
table_name: Name of the Hbase table.
"""
- return self.conn.table(table_name).batch()
+ with self.pool.connection() as conn:
+ return conn.table(table_name).batch()
def put(self, table_name: str, row_key: str, data: dict):
"""
@@ -98,8 +108,9 @@ def put(self, table_name: str, row_key: str, data: dict):
row_key: Row key of the row to be inserted to hbase table.
data: Mapping of column family name:column name to column values
"""
- table = self.conn.table(table_name)
- table.put(row_key, data)
+ with self.pool.connection() as conn:
+ table = conn.table(table_name)
+ table.put(row_key, data)
def row(
self,
@@ -119,8 +130,9 @@ def row(
timestamp: timestamp specifies the maximum version the cells can have.
include_timestamp: specifies if (column, timestamp) to be return instead of only column.
"""
- table = self.conn.table(table_name)
- return table.row(row_key, columns, timestamp, include_timestamp)
+ with self.pool.connection() as conn:
+ table = conn.table(table_name)
+ return table.row(row_key, columns, timestamp, include_timestamp)
def rows(
self,
@@ -140,52 +152,69 @@ def rows(
timestamp: timestamp specifies the maximum version the cells can have.
include_timestamp: specifies if (column, timestamp) to be return instead of only column.
"""
- table = self.conn.table(table_name)
- return table.rows(row_keys, columns, timestamp, include_timestamp)
+ with self.pool.connection() as conn:
+ table = conn.table(table_name)
+ return table.rows(row_keys, columns, timestamp, include_timestamp)
def print_table(self, table_name):
"""Prints the table scanning all the rows of the hbase table."""
- table = self.conn.table(table_name)
- scan_data = table.scan()
- for row_key, cols in scan_data:
- print(row_key.decode("utf-8"), cols)
+ with self.pool.connection() as conn:
+ table = conn.table(table_name)
+ scan_data = table.scan()
+ for row_key, cols in scan_data:
+ print(row_key.decode("utf-8"), cols)
def delete_table(self, table: str):
"""Deletes the hbase table given the table name."""
if self.check_if_table_exist(table):
- self.conn.delete_table(table, disable=True)
+ with self.pool.connection() as conn:
+ conn.delete_table(table, disable=True)
def close_conn(self):
"""Closes the happybase connection."""
- self.conn.close()
+ with self.pool.connection() as conn:
+ conn.close()
def main():
+ from feast.infra.key_encoding_utils import serialize_entity_key
+ from feast.protos.feast.types.EntityKey_pb2 import EntityKey
from feast.protos.feast.types.Value_pb2 import Value
- connection = Connection(host="localhost", port=9090)
- table = connection.table("test_hbase_driver_hourly_stats")
- row_keys = [
- serialize_entity_key(
- EntityKey(join_keys=["driver_id"], entity_values=[Value(int64_val=1004)]),
- entity_key_serialization_version=2,
- ).hex(),
- serialize_entity_key(
- EntityKey(join_keys=["driver_id"], entity_values=[Value(int64_val=1005)]),
- entity_key_serialization_version=2,
- ).hex(),
- serialize_entity_key(
- EntityKey(join_keys=["driver_id"], entity_values=[Value(int64_val=1024)]),
- entity_key_serialization_version=2,
- ).hex(),
- ]
- rows = table.rows(row_keys)
-
- for row_key, row in rows:
- for key, value in row.items():
- col_name = bytes.decode(key, "utf-8").split(":")[1]
- print(col_name, value)
- print()
+ pool = ConnectionPool(
+ host="localhost",
+ port=9090,
+ size=2,
+ )
+ with pool.connection() as connection:
+ table = connection.table("test_hbase_driver_hourly_stats")
+ row_keys = [
+ serialize_entity_key(
+ EntityKey(
+ join_keys=["driver_id"], entity_values=[Value(int64_val=1004)]
+ ),
+ entity_key_serialization_version=2,
+ ).hex(),
+ serialize_entity_key(
+ EntityKey(
+ join_keys=["driver_id"], entity_values=[Value(int64_val=1005)]
+ ),
+ entity_key_serialization_version=2,
+ ).hex(),
+ serialize_entity_key(
+ EntityKey(
+ join_keys=["driver_id"], entity_values=[Value(int64_val=1024)]
+ ),
+ entity_key_serialization_version=2,
+ ).hex(),
+ ]
+ rows = table.rows(row_keys)
+
+ for _, row in rows:
+ for key, value in row.items():
+ col_name = bytes.decode(key, "utf-8").split(":")[1]
+ print(col_name, value)
+ print()
if __name__ == "__main__":
diff --git a/sdk/python/feast/infra/utils/postgres/postgres_config.py b/sdk/python/feast/infra/utils/postgres/postgres_config.py
index 9fbaed474d5..a4ebb456ef1 100644
--- a/sdk/python/feast/infra/utils/postgres/postgres_config.py
+++ b/sdk/python/feast/infra/utils/postgres/postgres_config.py
@@ -25,4 +25,4 @@ class PostgreSQLConfig(FeastConfigBaseModel):
sslkey_path: Optional[StrictStr] = None
sslcert_path: Optional[StrictStr] = None
sslrootcert_path: Optional[StrictStr] = None
- keepalives_idle: int = 0
+ keepalives_idle: Optional[int] = None
diff --git a/sdk/python/feast/infra/utils/snowflake/snowflake_utils.py b/sdk/python/feast/infra/utils/snowflake/snowflake_utils.py
index a4cda89a6f6..8548e4dbd86 100644
--- a/sdk/python/feast/infra/utils/snowflake/snowflake_utils.py
+++ b/sdk/python/feast/infra/utils/snowflake/snowflake_utils.py
@@ -43,7 +43,7 @@
class GetSnowflakeConnection:
- def __init__(self, config: str, autocommit=True):
+ def __init__(self, config: Any, autocommit=True):
self.config = config
self.autocommit = autocommit
diff --git a/sdk/python/feast/infra/utils/snowflake/snowpark/snowflake_python_udfs_creation.sql b/sdk/python/feast/infra/utils/snowflake/snowpark/snowflake_python_udfs_creation.sql
index a197a3ee4cd..a444c0b7c5c 100644
--- a/sdk/python/feast/infra/utils/snowflake/snowpark/snowflake_python_udfs_creation.sql
+++ b/sdk/python/feast/infra/utils/snowflake/snowpark/snowflake_python_udfs_creation.sql
@@ -14,6 +14,62 @@ CREATE FUNCTION IF NOT EXISTS feast_PROJECT_NAME_snowflake_varchar_to_string_pro
HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_varchar_to_string_proto'
IMPORTS = ('@STAGE_HOLDER/feast.zip');
+CREATE FUNCTION IF NOT EXISTS feast_PROJECT_NAME_snowflake_array_bytes_to_list_bytes_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_bytes_to_list_bytes_proto'
+ IMPORTS = ('@STAGE_HOLDER/feast.zip');
+
+CREATE FUNCTION IF NOT EXISTS feast_PROJECT_NAME_snowflake_array_varchar_to_list_string_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_varchar_to_list_string_proto'
+ IMPORTS = ('@STAGE_HOLDER/feast.zip');
+
+CREATE FUNCTION IF NOT EXISTS feast_PROJECT_NAME_snowflake_array_number_to_list_int32_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_number_to_list_int32_proto'
+ IMPORTS = ('@STAGE_HOLDER/feast.zip');
+
+CREATE FUNCTION IF NOT EXISTS feast_PROJECT_NAME_snowflake_array_number_to_list_int64_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_number_to_list_int64_proto'
+ IMPORTS = ('@STAGE_HOLDER/feast.zip');
+
+CREATE FUNCTION IF NOT EXISTS feast_PROJECT_NAME_snowflake_array_float_to_list_double_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_float_to_list_double_proto'
+ IMPORTS = ('@STAGE_HOLDER/feast.zip');
+
+CREATE FUNCTION IF NOT EXISTS feast_PROJECT_NAME_snowflake_array_boolean_to_list_bool_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_boolean_to_list_bool_proto'
+ IMPORTS = ('@STAGE_HOLDER/feast.zip');
+
+CREATE FUNCTION IF NOT EXISTS feast_PROJECT_NAME_snowflake_array_timestamp_to_list_unix_timestamp_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_timestamp_to_list_unix_timestamp_proto'
+ IMPORTS = ('@STAGE_HOLDER/feast.zip');
+
CREATE FUNCTION IF NOT EXISTS feast_PROJECT_NAME_snowflake_number_to_int32_proto(df NUMBER)
RETURNS BINARY
LANGUAGE PYTHON
diff --git a/sdk/python/feast/infra/utils/snowflake/snowpark/snowflake_udfs.py b/sdk/python/feast/infra/utils/snowflake/snowpark/snowflake_udfs.py
index 02311ca55d6..f5d5f10631f 100644
--- a/sdk/python/feast/infra/utils/snowflake/snowpark/snowflake_udfs.py
+++ b/sdk/python/feast/infra/utils/snowflake/snowpark/snowflake_udfs.py
@@ -1,6 +1,7 @@
import sys
from binascii import unhexlify
+import numpy as np
import pandas
from _snowflake import vectorized
@@ -59,6 +60,180 @@ def feast_snowflake_varchar_to_string_proto(df):
return df
+"""
+CREATE OR REPLACE FUNCTION feast_snowflake_array_bytes_to_list_bytes_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_bytes_to_list_bytes_proto'
+ IMPORTS = ('@feast_stage/feast.zip');
+"""
+# ValueType.STRING_LIST = 12
+@vectorized(input=pandas.DataFrame)
+def feast_snowflake_array_bytes_to_list_bytes_proto(df):
+ sys._xoptions["snowflake_partner_attribution"].append("feast")
+
+ # Sometimes bytes come in as strings so we need to convert back to float
+ numpy_arrays = np.asarray(df[0].to_list()).astype(bytes)
+
+ df = list(
+ map(
+ ValueProto.SerializeToString,
+ python_values_to_proto_values(numpy_arrays, ValueType.BYTES_LIST),
+ )
+ )
+ return df
+
+
+"""
+CREATE OR REPLACE FUNCTION feast_snowflake_array_varchar_to_list_string_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_varchar_to_list_string_proto'
+ IMPORTS = ('@feast_stage/feast.zip');
+"""
+
+
+@vectorized(input=pandas.DataFrame)
+def feast_snowflake_array_varchar_to_list_string_proto(df):
+ sys._xoptions["snowflake_partner_attribution"].append("feast")
+
+ df = list(
+ map(
+ ValueProto.SerializeToString,
+ python_values_to_proto_values(df[0].to_numpy(), ValueType.STRING_LIST),
+ )
+ )
+ return df
+
+
+"""
+CREATE OR REPLACE FUNCTION feast_snowflake_array_number_to_list_int32_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_number_to_list_int32_proto'
+ IMPORTS = ('@feast_stage/feast.zip');
+"""
+
+
+@vectorized(input=pandas.DataFrame)
+def feast_snowflake_array_number_to_list_int32_proto(df):
+ sys._xoptions["snowflake_partner_attribution"].append("feast")
+
+ df = list(
+ map(
+ ValueProto.SerializeToString,
+ python_values_to_proto_values(df[0].to_numpy(), ValueType.INT32_LIST),
+ )
+ )
+ return df
+
+
+"""
+CREATE OR REPLACE FUNCTION feast_snowflake_array_number_to_list_int64_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_number_to_list_int64_proto'
+ IMPORTS = ('@feast_stage/feast.zip');
+"""
+
+
+@vectorized(input=pandas.DataFrame)
+def feast_snowflake_array_number_to_list_int64_proto(df):
+ sys._xoptions["snowflake_partner_attribution"].append("feast")
+
+ df = list(
+ map(
+ ValueProto.SerializeToString,
+ python_values_to_proto_values(df[0].to_numpy(), ValueType.INT64_LIST),
+ )
+ )
+ return df
+
+
+"""
+CREATE OR REPLACE FUNCTION feast_snowflake_array_float_to_list_double_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_float_to_list_double_proto'
+ IMPORTS = ('@feast_stage/feast.zip');
+"""
+
+
+@vectorized(input=pandas.DataFrame)
+def feast_snowflake_array_float_to_list_double_proto(df):
+ sys._xoptions["snowflake_partner_attribution"].append("feast")
+
+ numpy_arrays = np.asarray(df[0].to_list()).astype(float)
+
+ df = list(
+ map(
+ ValueProto.SerializeToString,
+ python_values_to_proto_values(numpy_arrays, ValueType.DOUBLE_LIST),
+ )
+ )
+ return df
+
+
+"""
+CREATE OR REPLACE FUNCTION feast_snowflake_array_boolean_to_list_bool_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_boolean_to_list_bool_proto'
+ IMPORTS = ('@feast_stage/feast.zip');
+"""
+
+
+@vectorized(input=pandas.DataFrame)
+def feast_snowflake_array_boolean_to_list_bool_proto(df):
+ sys._xoptions["snowflake_partner_attribution"].append("feast")
+
+ df = list(
+ map(
+ ValueProto.SerializeToString,
+ python_values_to_proto_values(df[0].to_numpy(), ValueType.BOOL_LIST),
+ )
+ )
+ return df
+
+
+"""
+CREATE OR REPLACE FUNCTION feast_snowflake_array_timestamp_to_list_unix_timestamp_proto(df ARRAY)
+ RETURNS BINARY
+ LANGUAGE PYTHON
+ RUNTIME_VERSION = '3.8'
+ PACKAGES = ('protobuf', 'pandas')
+ HANDLER = 'feast.infra.utils.snowflake.snowpark.snowflake_udfs.feast_snowflake_array_timestamp_to_list_unix_timestamp_proto'
+ IMPORTS = ('@feast_stage/feast.zip');
+"""
+
+
+@vectorized(input=pandas.DataFrame)
+def feast_snowflake_array_timestamp_to_list_unix_timestamp_proto(df):
+ sys._xoptions["snowflake_partner_attribution"].append("feast")
+
+ numpy_arrays = np.asarray(df[0].to_list()).astype(np.datetime64)
+
+ df = list(
+ map(
+ ValueProto.SerializeToString,
+ python_values_to_proto_values(numpy_arrays, ValueType.UNIX_TIMESTAMP_LIST),
+ )
+ )
+ return df
+
+
"""
CREATE OR REPLACE FUNCTION feast_snowflake_number_to_int32_proto(df NUMBER)
RETURNS BINARY
diff --git a/sdk/python/feast/proto_json.py b/sdk/python/feast/proto_json.py
index a0a4dce86bc..41d2afa55a7 100644
--- a/sdk/python/feast/proto_json.py
+++ b/sdk/python/feast/proto_json.py
@@ -1,13 +1,13 @@
import uuid
from typing import Any, Callable, Type
-import pkg_resources
from google.protobuf.json_format import ( # type: ignore
_WKTJSONMETHODS,
ParseError,
_Parser,
_Printer,
)
+from importlib_metadata import version as importlib_version
from packaging import version
from feast.protos.feast.serving.ServingService_pb2 import FeatureList
@@ -118,7 +118,7 @@ def from_json_object_updated(
# https://github.com/feast-dev/feast/issues/2484 Certain feast users need a higher version of protobuf but the
# parameters of `from_json_object` changes in feast 3.20.1. This change gives users flexibility to use earlier versions.
- current_version = pkg_resources.get_distribution("protobuf").version
+ current_version = importlib_version("protobuf")
if version.parse(current_version) < version.parse("3.20"):
_patch_proto_json_encoding(Value, to_json_object, from_json_object)
else:
@@ -168,7 +168,7 @@ def from_json_object(
# https://github.com/feast-dev/feast/issues/2484 Certain feast users need a higher version of protobuf but the
# parameters of `from_json_object` changes in feast 3.20.1. This change gives users flexibility to use earlier versions.
- current_version = pkg_resources.get_distribution("protobuf").version
+ current_version = importlib_version("protobuf")
if version.parse(current_version) < version.parse("3.20"):
_patch_proto_json_encoding(RepeatedValue, to_json_object, from_json_object)
else:
@@ -221,7 +221,7 @@ def from_json_object_updated(
# https://github.com/feast-dev/feast/issues/2484 Certain feast users need a higher version of protobuf but the
# parameters of `from_json_object` changes in feast 3.20.1. This change gives users flexibility to use earlier versions.
- current_version = pkg_resources.get_distribution("protobuf").version
+ current_version = importlib_version("protobuf")
if version.parse(current_version) < version.parse("3.20"):
_patch_proto_json_encoding(FeatureList, to_json_object, from_json_object)
else:
diff --git a/sdk/python/feast/registry_server.py b/sdk/python/feast/registry_server.py
new file mode 100644
index 00000000000..221715480e5
--- /dev/null
+++ b/sdk/python/feast/registry_server.py
@@ -0,0 +1,202 @@
+from concurrent import futures
+
+import grpc
+from google.protobuf.empty_pb2 import Empty
+
+from feast import FeatureStore
+from feast.protos.feast.registry import RegistryServer_pb2, RegistryServer_pb2_grpc
+
+
+class RegistryServer(RegistryServer_pb2_grpc.RegistryServerServicer):
+ def __init__(self, store: FeatureStore) -> None:
+ super().__init__()
+ self.proxied_registry = store.registry
+
+ def GetEntity(self, request: RegistryServer_pb2.GetEntityRequest, context):
+ return self.proxied_registry.get_entity(
+ name=request.name, project=request.project, allow_cache=request.allow_cache
+ ).to_proto()
+
+ def ListEntities(self, request, context):
+ return RegistryServer_pb2.ListEntitiesResponse(
+ entities=[
+ entity.to_proto()
+ for entity in self.proxied_registry.list_entities(
+ project=request.project, allow_cache=request.allow_cache
+ )
+ ]
+ )
+
+ def GetDataSource(self, request: RegistryServer_pb2.GetDataSourceRequest, context):
+ return self.proxied_registry.get_data_source(
+ name=request.name, project=request.project, allow_cache=request.allow_cache
+ ).to_proto()
+
+ def ListDataSources(self, request, context):
+ return RegistryServer_pb2.ListDataSourcesResponse(
+ data_sources=[
+ data_source.to_proto()
+ for data_source in self.proxied_registry.list_data_sources(
+ project=request.project, allow_cache=request.allow_cache
+ )
+ ]
+ )
+
+ def GetFeatureView(
+ self, request: RegistryServer_pb2.GetFeatureViewRequest, context
+ ):
+ return self.proxied_registry.get_feature_view(
+ name=request.name, project=request.project, allow_cache=request.allow_cache
+ ).to_proto()
+
+ def ListFeatureViews(self, request, context):
+ return RegistryServer_pb2.ListFeatureViewsResponse(
+ feature_views=[
+ feature_view.to_proto()
+ for feature_view in self.proxied_registry.list_feature_views(
+ project=request.project, allow_cache=request.allow_cache
+ )
+ ]
+ )
+
+ def GetRequestFeatureView(
+ self, request: RegistryServer_pb2.GetRequestFeatureViewRequest, context
+ ):
+ return self.proxied_registry.get_request_feature_view(
+ name=request.name, project=request.project, allow_cache=request.allow_cache
+ ).to_proto()
+
+ def ListRequestFeatureViews(self, request, context):
+ return RegistryServer_pb2.ListRequestFeatureViewsResponse(
+ request_feature_views=[
+ request_feature_view.to_proto()
+ for request_feature_view in self.proxied_registry.list_request_feature_views(
+ project=request.project, allow_cache=request.allow_cache
+ )
+ ]
+ )
+
+ def GetStreamFeatureView(
+ self, request: RegistryServer_pb2.GetStreamFeatureViewRequest, context
+ ):
+ return self.proxied_registry.get_stream_feature_view(
+ name=request.name, project=request.project, allow_cache=request.allow_cache
+ ).to_proto()
+
+ def ListStreamFeatureViews(self, request, context):
+ return RegistryServer_pb2.ListStreamFeatureViewsResponse(
+ stream_feature_views=[
+ stream_feature_view.to_proto()
+ for stream_feature_view in self.proxied_registry.list_stream_feature_views(
+ project=request.project, allow_cache=request.allow_cache
+ )
+ ]
+ )
+
+ def GetOnDemandFeatureView(
+ self, request: RegistryServer_pb2.GetOnDemandFeatureViewRequest, context
+ ):
+ return self.proxied_registry.get_on_demand_feature_view(
+ name=request.name, project=request.project, allow_cache=request.allow_cache
+ ).to_proto()
+
+ def ListOnDemandFeatureViews(self, request, context):
+ return RegistryServer_pb2.ListOnDemandFeatureViewsResponse(
+ on_demand_feature_views=[
+ on_demand_feature_view.to_proto()
+ for on_demand_feature_view in self.proxied_registry.list_on_demand_feature_views(
+ project=request.project, allow_cache=request.allow_cache
+ )
+ ]
+ )
+
+ def GetFeatureService(
+ self, request: RegistryServer_pb2.GetFeatureServiceRequest, context
+ ):
+ return self.proxied_registry.get_feature_service(
+ name=request.name, project=request.project, allow_cache=request.allow_cache
+ ).to_proto()
+
+ def ListFeatureServices(
+ self, request: RegistryServer_pb2.ListFeatureServicesRequest, context
+ ):
+ return RegistryServer_pb2.ListFeatureServicesResponse(
+ feature_services=[
+ feature_service.to_proto()
+ for feature_service in self.proxied_registry.list_feature_services(
+ project=request.project, allow_cache=request.allow_cache
+ )
+ ]
+ )
+
+ def GetSavedDataset(
+ self, request: RegistryServer_pb2.GetSavedDatasetRequest, context
+ ):
+ return self.proxied_registry.get_saved_dataset(
+ name=request.name, project=request.project, allow_cache=request.allow_cache
+ ).to_proto()
+
+ def ListSavedDatasets(
+ self, request: RegistryServer_pb2.ListSavedDatasetsRequest, context
+ ):
+ return RegistryServer_pb2.ListSavedDatasetsResponse(
+ saved_datasets=[
+ saved_dataset.to_proto()
+ for saved_dataset in self.proxied_registry.list_saved_datasets(
+ project=request.project, allow_cache=request.allow_cache
+ )
+ ]
+ )
+
+ def GetValidationReference(
+ self, request: RegistryServer_pb2.GetValidationReferenceRequest, context
+ ):
+ return self.proxied_registry.get_validation_reference(
+ name=request.name, project=request.project, allow_cache=request.allow_cache
+ ).to_proto()
+
+ def ListValidationReferences(
+ self, request: RegistryServer_pb2.ListValidationReferencesRequest, context
+ ):
+ return RegistryServer_pb2.ListValidationReferencesResponse(
+ validation_references=[
+ validation_reference.to_proto()
+ for validation_reference in self.proxied_registry.list_validation_references(
+ project=request.project, allow_cache=request.allow_cache
+ )
+ ]
+ )
+
+ def ListProjectMetadata(
+ self, request: RegistryServer_pb2.ListProjectMetadataRequest, context
+ ):
+ return RegistryServer_pb2.ListProjectMetadataResponse(
+ project_metadata=[
+ project_metadata.to_proto()
+ for project_metadata in self.proxied_registry.list_project_metadata(
+ project=request.project, allow_cache=request.allow_cache
+ )
+ ]
+ )
+
+ def GetInfra(self, request: RegistryServer_pb2.GetInfraRequest, context):
+ return self.proxied_registry.get_infra(
+ project=request.project, allow_cache=request.allow_cache
+ ).to_proto()
+
+ def Refresh(self, request, context):
+ self.proxied_registry.refresh(request.project)
+ return Empty()
+
+ def Proto(self, request, context):
+ return self.proxied_registry.proto()
+
+
+def start_server(store: FeatureStore, port: int):
+ server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+ RegistryServer_pb2_grpc.add_RegistryServerServicer_to_server(
+ RegistryServer(store), server
+ )
+ server.add_insecure_port(f"[::]:{port}")
+ server.start()
+ server.wait_for_termination()
diff --git a/sdk/python/feast/repo_config.py b/sdk/python/feast/repo_config.py
index 3461ae058bd..d500059c6b9 100644
--- a/sdk/python/feast/repo_config.py
+++ b/sdk/python/feast/repo_config.py
@@ -2,20 +2,19 @@
import os
import warnings
from pathlib import Path
-from typing import Any
+from typing import Any, Dict, Optional
import yaml
from pydantic import (
BaseModel,
+ ConfigDict,
Field,
StrictInt,
StrictStr,
ValidationError,
- root_validator,
- validator,
+ field_validator,
+ model_validator,
)
-from pydantic.error_wrappers import ErrorWrapper
-from pydantic.typing import Dict, Optional
from feast.errors import (
FeastFeatureServerTypeInvalidError,
@@ -75,6 +74,7 @@
"postgres": "feast.infra.offline_stores.contrib.postgres_offline_store.postgres.PostgreSQLOfflineStore",
"athena": "feast.infra.offline_stores.contrib.athena_offline_store.athena.AthenaOfflineStore",
"mssql": "feast.infra.offline_stores.contrib.mssql_offline_store.mssql.MsSqlServerOfflineStore",
+ "duckdb": "feast.infra.offline_stores.contrib.duckdb_offline_store.duckdb.DuckDBOfflineStore",
}
FEATURE_SERVER_CONFIG_CLASS_FOR_TYPE = {
@@ -93,17 +93,13 @@
class FeastBaseModel(BaseModel):
"""Feast Pydantic Configuration Class"""
- class Config:
- arbitrary_types_allowed = True
- extra = "allow"
+ model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")
class FeastConfigBaseModel(BaseModel):
"""Feast Pydantic Configuration Class"""
- class Config:
- arbitrary_types_allowed = True
- extra = "forbid"
+ model_config = ConfigDict(arbitrary_types_allowed=True, extra="forbid")
class RegistryConfig(FeastBaseModel):
@@ -112,7 +108,7 @@ class RegistryConfig(FeastBaseModel):
registry_type: StrictStr = "file"
""" str: Provider name or a class name that implements Registry."""
- registry_store_type: Optional[StrictStr]
+ registry_store_type: Optional[StrictStr] = None
""" str: Provider name or a class name that implements RegistryStore. """
path: StrictStr = ""
@@ -126,7 +122,7 @@ class RegistryConfig(FeastBaseModel):
set to infinity by setting TTL to 0 seconds, which means the cache will only be loaded once and will never
expire. Users can manually refresh the cache by calling feature_store.refresh_registry() """
- s3_additional_kwargs: Optional[Dict[str, str]]
+ s3_additional_kwargs: Optional[Dict[str, str]] = None
""" Dict[str, str]: Extra arguments to pass to boto3 when writing the registry file to S3. """
@@ -142,7 +138,7 @@ class RepoConfig(FeastBaseModel):
provider: StrictStr
""" str: local or gcp or aws """
- _registry_config: Any = Field(alias="registry", default="data/registry.db")
+ registry_config: Any = Field(alias="registry", default="data/registry.db")
""" Configures the registry.
Can be:
1. str: a path to a file based registry (a local path, or remote object storage path, e.g. a GCS URI)
@@ -150,19 +146,19 @@ class RepoConfig(FeastBaseModel):
3. SnowflakeRegistryConfig: Using a Snowflake table to store the registry
"""
- _online_config: Any = Field(alias="online_store")
+ online_config: Any = Field(None, alias="online_store")
""" OnlineStoreConfig: Online store configuration (optional depending on provider) """
- _offline_config: Any = Field(alias="offline_store")
+ offline_config: Any = Field(None, alias="offline_store")
""" OfflineStoreConfig: Offline store configuration (optional depending on provider) """
- _batch_engine_config: Any = Field(alias="batch_engine")
+ batch_engine_config: Any = Field(None, alias="batch_engine")
""" BatchMaterializationEngine: Batch materialization configuration (optional depending on provider)"""
- feature_server: Optional[Any]
+ feature_server: Optional[Any] = None
""" FeatureServerConfig: Feature server configuration (optional depending on provider) """
- flags: Any
+ flags: Any = None
""" Flags (deprecated field): Feature flags for experimental features """
repo_path: Optional[Path] = None
@@ -187,42 +183,42 @@ def __init__(self, **data: Any):
self._registry = None
if "registry" not in data:
raise FeastRegistryNotSetError()
- self._registry_config = data["registry"]
+ self.registry_config = data["registry"]
self._offline_store = None
if "offline_store" in data:
- self._offline_config = data["offline_store"]
+ self.offline_config = data["offline_store"]
else:
if data["provider"] == "local":
- self._offline_config = "file"
+ self.offline_config = "file"
elif data["provider"] == "gcp":
- self._offline_config = "bigquery"
+ self.offline_config = "bigquery"
elif data["provider"] == "aws":
- self._offline_config = "redshift"
+ self.offline_config = "redshift"
elif data["provider"] == "azure":
- self._offline_config = "mssql"
+ self.offline_config = "mssql"
self._online_store = None
if "online_store" in data:
- self._online_config = data["online_store"]
+ self.online_config = data["online_store"]
else:
if data["provider"] == "local":
- self._online_config = "sqlite"
+ self.online_config = "sqlite"
elif data["provider"] == "gcp":
- self._online_config = "datastore"
+ self.online_config = "datastore"
elif data["provider"] == "aws":
- self._online_config = "dynamodb"
+ self.online_config = "dynamodb"
elif data["provider"] == "rockset":
- self._online_config = "rockset"
+ self.online_config = "rockset"
self._batch_engine = None
if "batch_engine" in data:
- self._batch_engine_config = data["batch_engine"]
+ self.batch_engine_config = data["batch_engine"]
elif "batch_engine_config" in data:
- self._batch_engine_config = data["batch_engine_config"]
+ self.batch_engine_config = data["batch_engine_config"]
else:
# Defaults to using local in-process materialization engine.
- self._batch_engine_config = "local"
+ self.batch_engine_config = "local"
if isinstance(self.feature_server, Dict):
self.feature_server = get_feature_server_config_from_type(
@@ -242,71 +238,71 @@ def __init__(self, **data: Any):
@property
def registry(self):
if not self._registry:
- if isinstance(self._registry_config, Dict):
- if "registry_type" in self._registry_config:
+ if isinstance(self.registry_config, Dict):
+ if "registry_type" in self.registry_config:
self._registry = get_registry_config_from_type(
- self._registry_config["registry_type"]
- )(**self._registry_config)
+ self.registry_config["registry_type"]
+ )(**self.registry_config)
else:
# This may be a custom registry store, which does not need a 'registry_type'
- self._registry = RegistryConfig(**self._registry_config)
- elif isinstance(self._registry_config, str):
+ self._registry = RegistryConfig(**self.registry_config)
+ elif isinstance(self.registry_config, str):
# User passed in just a path to file registry
self._registry = get_registry_config_from_type("file")(
- path=self._registry_config
+ path=self.registry_config
)
- elif self._registry_config:
- self._registry = self._registry_config
+ elif self.registry_config:
+ self._registry = self.registry_config
return self._registry
@property
def offline_store(self):
if not self._offline_store:
- if isinstance(self._offline_config, Dict):
+ if isinstance(self.offline_config, Dict):
self._offline_store = get_offline_config_from_type(
- self._offline_config["type"]
- )(**self._offline_config)
- elif isinstance(self._offline_config, str):
+ self.offline_config["type"]
+ )(**self.offline_config)
+ elif isinstance(self.offline_config, str):
self._offline_store = get_offline_config_from_type(
- self._offline_config
+ self.offline_config
)()
- elif self._offline_config:
- self._offline_store = self._offline_config
+ elif self.offline_config:
+ self._offline_store = self.offline_config
return self._offline_store
@property
def online_store(self):
if not self._online_store:
- if isinstance(self._online_config, Dict):
+ if isinstance(self.online_config, Dict):
self._online_store = get_online_config_from_type(
- self._online_config["type"]
- )(**self._online_config)
- elif isinstance(self._online_config, str):
- self._online_store = get_online_config_from_type(self._online_config)()
- elif self._online_config:
- self._online_store = self._online_config
+ self.online_config["type"]
+ )(**self.online_config)
+ elif isinstance(self.online_config, str):
+ self._online_store = get_online_config_from_type(self.online_config)()
+ elif self.online_config:
+ self._online_store = self.online_config
return self._online_store
@property
def batch_engine(self):
if not self._batch_engine:
- if isinstance(self._batch_engine_config, Dict):
+ if isinstance(self.batch_engine_config, Dict):
self._batch_engine = get_batch_engine_config_from_type(
- self._batch_engine_config["type"]
- )(**self._batch_engine_config)
- elif isinstance(self._batch_engine_config, str):
+ self.batch_engine_config["type"]
+ )(**self.batch_engine_config)
+ elif isinstance(self.batch_engine_config, str):
self._batch_engine = get_batch_engine_config_from_type(
- self._batch_engine_config
+ self.batch_engine_config
)()
- elif self._batch_engine_config:
+ elif self.batch_engine_config:
self._batch_engine = self._batch_engine
return self._batch_engine
- @root_validator(pre=True)
+ @model_validator(mode="before")
@log_exceptions
- def _validate_online_store_config(cls, values):
+ def _validate_online_store_config(cls, values: Any) -> Any:
# This method will validate whether the online store configurations are set correctly. This explicit validation
# is necessary because Pydantic Unions throw very verbose and cryptic exceptions. We also use this method to
# impute the default online store type based on the selected provider. For the time being this method should be
@@ -347,14 +343,12 @@ def _validate_online_store_config(cls, values):
online_config_class = get_online_config_from_type(online_store_type)
online_config_class(**values["online_store"])
except ValidationError as e:
- raise ValidationError(
- [ErrorWrapper(e, loc="online_store")],
- model=RepoConfig,
- )
+ raise e
return values
- @root_validator(pre=True)
- def _validate_offline_store_config(cls, values):
+ @model_validator(mode="before")
+ @classmethod
+ def _validate_offline_store_config(cls, values: Any) -> Any:
# Set empty offline_store config if it isn't set explicitly
if "offline_store" not in values:
values["offline_store"] = dict()
@@ -385,15 +379,13 @@ def _validate_offline_store_config(cls, values):
offline_config_class = get_offline_config_from_type(offline_store_type)
offline_config_class(**values["offline_store"])
except ValidationError as e:
- raise ValidationError(
- [ErrorWrapper(e, loc="offline_store")],
- model=RepoConfig,
- )
+ raise e
return values
- @root_validator(pre=True)
- def _validate_feature_server_config(cls, values):
+ @model_validator(mode="before")
+ @classmethod
+ def _validate_feature_server_config(cls, values: Any) -> Any:
# Having no feature server is the default.
if "feature_server" not in values:
return values
@@ -420,15 +412,13 @@ def _validate_feature_server_config(cls, values):
)
feature_server_config_class(**values["feature_server"])
except ValidationError as e:
- raise ValidationError(
- [ErrorWrapper(e, loc="feature_server")],
- model=RepoConfig,
- )
+ raise e
return values
- @validator("project")
- def _validate_project_name(cls, v):
+ @field_validator("project")
+ @classmethod
+ def _validate_project_name(cls, v: str) -> str:
from feast.repo_operations import is_valid_name
if not is_valid_name(v):
@@ -438,10 +428,11 @@ def _validate_project_name(cls, v):
)
return v
- @validator("flags")
- def _validate_flags(cls, v):
- if not isinstance(v, Dict):
- return
+ @field_validator("flags")
+ @classmethod
+ def _validate_flags(cls, v: Optional[dict]) -> Optional[dict]:
+ if not isinstance(v, dict):
+ return v
_logger.warning(
"Flags are no longer necessary in Feast. Experimental features will log warnings instead."
@@ -463,8 +454,7 @@ def write_to_path(self, repo_path: Path):
sort_keys=False,
)
- class Config:
- allow_population_by_field_name = True
+ model_config = ConfigDict(populate_by_name=True)
class FeastConfigError(Exception):
diff --git a/sdk/python/feast/repo_operations.py b/sdk/python/feast/repo_operations.py
index 0cd425a46be..120f6e7a422 100644
--- a/sdk/python/feast/repo_operations.py
+++ b/sdk/python/feast/repo_operations.py
@@ -296,8 +296,6 @@ def apply_total_with_repo_instance(
for data_source in data_sources:
data_source.validate(store.config)
- registry_diff, infra_diff, new_infra = store.plan(repo)
-
# For each object in the registry, determine whether it should be kept or deleted.
(
all_to_apply,
@@ -306,9 +304,10 @@ def apply_total_with_repo_instance(
views_to_delete,
) = extract_objects_for_apply_delete(project, registry, repo)
- click.echo(registry_diff.to_string())
-
if store._should_use_plan():
+ registry_diff, infra_diff, new_infra = store.plan(repo)
+ click.echo(registry_diff.to_string())
+
store._apply_diffs(registry_diff, infra_diff, new_infra)
click.echo(infra_diff.to_string())
else:
diff --git a/sdk/python/feast/stream_feature_view.py b/sdk/python/feast/stream_feature_view.py
index d3a2164788f..6a204d68136 100644
--- a/sdk/python/feast/stream_feature_view.py
+++ b/sdk/python/feast/stream_feature_view.py
@@ -3,9 +3,10 @@
import warnings
from datetime import datetime, timedelta
from types import FunctionType
-from typing import Dict, List, Optional, Tuple, Union
+from typing import Dict, List, Optional, Tuple, Type, Union
import dill
+from google.protobuf.message import Message
from typeguard import typechecked
from feast import flags_helper, utils
@@ -298,6 +299,10 @@ def __copy__(self):
fv.projection = copy.copy(self.projection)
return fv
+ @property
+ def proto_class(self) -> Type[Message]:
+ return StreamFeatureViewProto
+
def stream_feature_view(
*,
diff --git a/sdk/python/feast/type_map.py b/sdk/python/feast/type_map.py
index df853462836..ad3e273d37b 100644
--- a/sdk/python/feast/type_map.py
+++ b/sdk/python/feast/type_map.py
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import json
from collections import defaultdict
from datetime import datetime, timezone
from typing import (
@@ -50,7 +51,7 @@
import pyarrow
# null timestamps get converted to -9223372036854775808
-NULL_TIMESTAMP_INT_VALUE = np.datetime64("NaT").astype(int)
+NULL_TIMESTAMP_INT_VALUE: int = np.datetime64("NaT").astype(int)
def feast_value_type_to_python_type(field_value_proto: ProtoValue) -> Any:
@@ -113,7 +114,10 @@ def feast_value_type_to_pandas_type(value_type: ValueType) -> Any:
def python_type_to_feast_value_type(
- name: str, value: Any = None, recurse: bool = True, type_name: Optional[str] = None
+ name: str,
+ value: Optional[Any] = None,
+ recurse: bool = True,
+ type_name: Optional[str] = None,
) -> ValueType:
"""
Finds the equivalent Feast Value Type for a Python value. Both native
@@ -297,7 +301,7 @@ def _type_err(item, dtype):
None,
),
ValueType.FLOAT: ("float_val", lambda x: float(x), None),
- ValueType.DOUBLE: ("double_val", lambda x: x, {float, np.float64}),
+ ValueType.DOUBLE: ("double_val", lambda x: x, {float, np.float64, int, np.int_}),
ValueType.STRING: ("string_val", lambda x: str(x), None),
ValueType.BYTES: ("bytes_val", lambda x: x, {bytes}),
ValueType.BOOL: ("bool_val", lambda x: x, {bool, np.bool_, int, np.int_}),
@@ -320,7 +324,7 @@ def _python_datetime_to_int_timestamp(
elif isinstance(value, Timestamp):
int_timestamps.append(int(value.ToSeconds()))
elif isinstance(value, np.datetime64):
- int_timestamps.append(value.astype("datetime64[s]").astype(np.int_))
+ int_timestamps.append(value.astype("datetime64[s]").astype(np.int_)) # type: ignore[attr-defined]
elif isinstance(value, type(np.nan)):
int_timestamps.append(NULL_TIMESTAMP_INT_VALUE)
else:
@@ -353,6 +357,19 @@ def _python_value_to_proto_value(
feast_value_type
]
+ # Bytes to array type conversion
+ if isinstance(sample, (bytes, bytearray)):
+ # Bytes of an array containing elements of bytes not supported
+ if feast_value_type == ValueType.BYTES_LIST:
+ raise _type_err(sample, ValueType.BYTES_LIST)
+
+ json_value = json.loads(sample)
+ if isinstance(json_value, list):
+ if feast_value_type == ValueType.BOOL_LIST:
+ json_value = [bool(item) for item in json_value]
+ return [ProtoValue(**{field_name: proto_type(val=json_value)})] # type: ignore
+ raise _type_err(sample, valid_types[0])
+
if sample is not None and not all(
type(item) in valid_types for item in sample
):
@@ -428,12 +445,15 @@ def _python_value_to_proto_value(
for value in values
]
if feast_value_type in PYTHON_SCALAR_VALUE_TYPE_TO_PROTO_VALUE:
- return [
- ProtoValue(**{field_name: func(value)})
- if not pd.isnull(value)
- else ProtoValue()
- for value in values
- ]
+ out = []
+ for value in values:
+ if isinstance(value, ProtoValue):
+ out.append(value)
+ elif not pd.isnull(value):
+ out.append(ProtoValue(**{field_name: func(value)}))
+ else:
+ out.append(ProtoValue())
+ return out
raise Exception(f"Unsupported data type: ${str(type(values[0]))}")
@@ -528,6 +548,7 @@ def bq_to_feast_value_type(bq_type_as_str: str) -> ValueType:
"DATETIME": ValueType.UNIX_TIMESTAMP,
"TIMESTAMP": ValueType.UNIX_TIMESTAMP,
"INTEGER": ValueType.INT64,
+ "NUMERIC": ValueType.INT64,
"INT64": ValueType.INT64,
"STRING": ValueType.STRING,
"FLOAT": ValueType.DOUBLE,
@@ -627,6 +648,7 @@ def redshift_to_feast_value_type(redshift_type_as_str: str) -> ValueType:
"varchar": ValueType.STRING,
"timestamp": ValueType.UNIX_TIMESTAMP,
"timestamptz": ValueType.UNIX_TIMESTAMP,
+ "super": ValueType.BYTES,
# skip date, geometry, hllsketch, time, timetz
}
@@ -661,6 +683,14 @@ def _convert_value_name_to_snowflake_udf(value_name: str, project_name: str) ->
"FLOAT": f"feast_{project_name}_snowflake_float_to_double_proto",
"BOOL": f"feast_{project_name}_snowflake_boolean_to_bool_proto",
"UNIX_TIMESTAMP": f"feast_{project_name}_snowflake_timestamp_to_unix_timestamp_proto",
+ "BYTES_LIST": f"feast_{project_name}_snowflake_array_bytes_to_list_bytes_proto",
+ "STRING_LIST": f"feast_{project_name}_snowflake_array_varchar_to_list_string_proto",
+ "INT32_LIST": f"feast_{project_name}_snowflake_array_number_to_list_int32_proto",
+ "INT64_LIST": f"feast_{project_name}_snowflake_array_number_to_list_int64_proto",
+ "DOUBLE_LIST": f"feast_{project_name}_snowflake_array_float_to_list_double_proto",
+ "FLOAT_LIST": f"feast_{project_name}_snowflake_array_float_to_list_double_proto",
+ "BOOL_LIST": f"feast_{project_name}_snowflake_array_boolean_to_list_bool_proto",
+ "UNIX_TIMESTAMP_LIST": f"feast_{project_name}_snowflake_array_timestamp_to_list_unix_timestamp_proto",
}
return name_map[value_name].upper()
@@ -745,7 +775,7 @@ def spark_to_feast_value_type(spark_type_as_str: str) -> ValueType:
"array": ValueType.UNIX_TIMESTAMP_LIST,
}
# TODO: Find better way of doing this.
- if type(spark_type_as_str) != str or spark_type_as_str not in type_map:
+ if not isinstance(spark_type_as_str, str) or spark_type_as_str not in type_map:
return ValueType.NULL
return type_map[spark_type_as_str.lower()]
@@ -873,13 +903,26 @@ def feast_value_type_to_pa(
def pg_type_code_to_pg_type(code: int) -> str:
- return {
+ """Map the postgres type code a Feast type string
+
+ Rather than raise an exception on an unknown type, we return the
+ string representation of the type code. This way rather than raising
+ an exception on unknown types, Feast will just skip the problem columns.
+
+ Note that json and jsonb are not supported but this shows up in the
+ log as a warning. Since postgres allows custom types we return an unknown for those cases.
+
+ See: https://jdbc.postgresql.org/documentation/publicapi/index.html?constant-values.html
+ """
+ PG_TYPE_MAP = {
16: "boolean",
17: "bytea",
20: "bigint",
21: "smallint",
23: "integer",
25: "text",
+ 114: "json",
+ 199: "json[]",
700: "real",
701: "double precision",
1000: "boolean[]",
@@ -905,7 +948,11 @@ def pg_type_code_to_pg_type(code: int) -> str:
1700: "numeric",
2950: "uuid",
2951: "uuid[]",
- }[code]
+ 3802: "jsonb",
+ 3807: "jsonb[]",
+ }
+
+ return PG_TYPE_MAP.get(code, "unknown")
def pg_type_code_to_arrow(code: int) -> str:
diff --git a/sdk/python/feast/ui/package.json b/sdk/python/feast/ui/package.json
index 547e21b690e..f142b0b6448 100644
--- a/sdk/python/feast/ui/package.json
+++ b/sdk/python/feast/ui/package.json
@@ -6,7 +6,7 @@
"@elastic/datemath": "^5.0.3",
"@elastic/eui": "^55.0.1",
"@emotion/react": "^11.9.0",
- "@feast-dev/feast-ui": "0.30.2",
+ "@feast-dev/feast-ui": "0.35.0",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.2.0",
"@testing-library/user-event": "^13.5.0",
@@ -24,7 +24,7 @@
"typescript": "^4.6.4",
"use-query-params": "^1.2.3",
"web-vitals": "^2.1.4",
- "zod": "^3.15.1"
+ "zod": "^3.22.3"
},
"scripts": {
"start": "react-scripts start",
diff --git a/sdk/python/feast/ui/yarn.lock b/sdk/python/feast/ui/yarn.lock
index b375ef68813..06f4d3f12bb 100644
--- a/sdk/python/feast/ui/yarn.lock
+++ b/sdk/python/feast/ui/yarn.lock
@@ -26,6 +26,14 @@
dependencies:
"@babel/highlight" "^7.16.7"
+"@babel/code-frame@^7.22.13":
+ version "7.22.13"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
+ integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
+ dependencies:
+ "@babel/highlight" "^7.22.13"
+ chalk "^2.4.2"
+
"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.10":
version "7.17.10"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab"
@@ -70,6 +78,16 @@
"@jridgewell/gen-mapping" "^0.1.0"
jsesc "^2.5.1"
+"@babel/generator@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
+ integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
+ dependencies:
+ "@babel/types" "^7.23.0"
+ "@jridgewell/gen-mapping" "^0.3.2"
+ "@jridgewell/trace-mapping" "^0.3.17"
+ jsesc "^2.5.1"
+
"@babel/helper-annotate-as-pure@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862"
@@ -77,6 +95,13 @@
dependencies:
"@babel/types" "^7.16.7"
+"@babel/helper-annotate-as-pure@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882"
+ integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b"
@@ -137,6 +162,11 @@
dependencies:
"@babel/types" "^7.16.7"
+"@babel/helper-environment-visitor@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
+ integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
+
"@babel/helper-explode-assignable-expression@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz#12a6d8522fdd834f194e868af6354e8650242b7a"
@@ -152,6 +182,14 @@
"@babel/template" "^7.16.7"
"@babel/types" "^7.17.0"
+"@babel/helper-function-name@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+ integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
+ dependencies:
+ "@babel/template" "^7.22.15"
+ "@babel/types" "^7.23.0"
+
"@babel/helper-hoist-variables@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246"
@@ -159,6 +197,13 @@
dependencies:
"@babel/types" "^7.16.7"
+"@babel/helper-hoist-variables@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
+ integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
"@babel/helper-member-expression-to-functions@^7.16.7", "@babel/helper-member-expression-to-functions@^7.17.7":
version "7.17.7"
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4"
@@ -166,6 +211,13 @@
dependencies:
"@babel/types" "^7.17.0"
+"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c"
+ integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437"
@@ -199,6 +251,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5"
integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==
+"@babel/helper-plugin-utils@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295"
+ integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==
+
"@babel/helper-remap-async-to-generator@^7.16.8":
version "7.16.8"
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3"
@@ -240,11 +297,33 @@
dependencies:
"@babel/types" "^7.16.7"
+"@babel/helper-split-export-declaration@^7.22.6":
+ version "7.22.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
+ integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
+"@babel/helper-string-parser@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
+ integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
+
"@babel/helper-validator-identifier@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad"
integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
+"@babel/helper-validator-identifier@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
+ integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
+
+"@babel/helper-validator-identifier@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
+ integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==
+
"@babel/helper-validator-option@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23"
@@ -278,11 +357,25 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
+"@babel/highlight@^7.22.13":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
+ integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.22.20"
+ chalk "^2.4.2"
+ js-tokens "^4.0.0"
+
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.10":
version "7.17.10"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.10.tgz#873b16db82a8909e0fbd7f115772f4b739f6ce78"
integrity sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==
+"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
+ integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
+
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050"
@@ -516,6 +609,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.16.7"
+"@babel/plugin-syntax-jsx@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz#a6b68e84fb76e759fc3b93e901876ffabbe1d918"
+ integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
@@ -1025,6 +1125,13 @@
dependencies:
regenerator-runtime "^0.13.4"
+"@babel/runtime@^7.10.4", "@babel/runtime@^7.3.1":
+ version "7.22.6"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438"
+ integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==
+ dependencies:
+ regenerator-runtime "^0.13.11"
+
"@babel/template@^7.16.7", "@babel/template@^7.3.3":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155"
@@ -1034,19 +1141,28 @@
"@babel/parser" "^7.16.7"
"@babel/types" "^7.16.7"
-"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.10", "@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9", "@babel/traverse@^7.7.2":
- version "7.17.10"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.10.tgz#1ee1a5ac39f4eac844e6cf855b35520e5eb6f8b5"
- integrity sha512-VmbrTHQteIdUUQNTb+zE12SHS/xQVIShmBPhlNP12hD5poF2pbITW1Z4172d03HegaQWhLffdkRJYtAzp0AGcw==
- dependencies:
- "@babel/code-frame" "^7.16.7"
- "@babel/generator" "^7.17.10"
- "@babel/helper-environment-visitor" "^7.16.7"
- "@babel/helper-function-name" "^7.17.9"
- "@babel/helper-hoist-variables" "^7.16.7"
- "@babel/helper-split-export-declaration" "^7.16.7"
- "@babel/parser" "^7.17.10"
- "@babel/types" "^7.17.10"
+"@babel/template@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
+ integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
+ dependencies:
+ "@babel/code-frame" "^7.22.13"
+ "@babel/parser" "^7.22.15"
+ "@babel/types" "^7.22.15"
+
+"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.10", "@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.2":
+ version "7.23.2"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
+ integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
+ dependencies:
+ "@babel/code-frame" "^7.22.13"
+ "@babel/generator" "^7.23.0"
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-function-name" "^7.23.0"
+ "@babel/helper-hoist-variables" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/parser" "^7.23.0"
+ "@babel/types" "^7.23.0"
debug "^4.1.0"
globals "^11.1.0"
@@ -1058,6 +1174,24 @@
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
+"@babel/types@^7.22.15", "@babel/types@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
+ integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
+ dependencies:
+ "@babel/helper-string-parser" "^7.22.5"
+ "@babel/helper-validator-identifier" "^7.22.20"
+ to-fast-properties "^2.0.0"
+
+"@babel/types@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe"
+ integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==
+ dependencies:
+ "@babel/helper-string-parser" "^7.22.5"
+ "@babel/helper-validator-identifier" "^7.22.5"
+ to-fast-properties "^2.0.0"
+
"@base2/pretty-print-object@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz#371ba8be66d556812dc7fb169ebc3c08378f69d4"
@@ -1236,11 +1370,23 @@
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
+"@emotion/is-prop-valid@^1.1.0":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz#23116cf1ed18bfeac910ec6436561ecb1a3885cc"
+ integrity sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==
+ dependencies:
+ "@emotion/memoize" "^0.8.1"
+
"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
+"@emotion/memoize@^0.8.1":
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17"
+ integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==
+
"@emotion/react@^11.7.1", "@emotion/react@^11.9.0":
version "11.9.0"
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.9.0.tgz#b6d42b1db3bd7511e7a7c4151dc8bc82e14593b8"
@@ -1270,7 +1416,12 @@
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2"
integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==
-"@emotion/unitless@^0.7.5":
+"@emotion/stylis@^0.8.4":
+ version "0.8.5"
+ resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
+ integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
+
+"@emotion/unitless@^0.7.4", "@emotion/unitless@^0.7.5":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
@@ -1300,10 +1451,10 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
-"@feast-dev/feast-ui@0.30.2":
- version "0.30.2"
- resolved "https://registry.yarnpkg.com/@feast-dev/feast-ui/-/feast-ui-0.30.2.tgz#867db94daba3dcb7d91f767bf104e489174dd666"
- integrity sha512-qfsJYQb9eGaTLuk5tqi24nCE6YaP8SU8uf6ukENjj5Y8yRJhVy6IeZrIl/qpUsvAQd1PmmX0ZDr/zndD4QQsPA==
+"@feast-dev/feast-ui@0.35.0":
+ version "0.35.0"
+ resolved "https://registry.yarnpkg.com/@feast-dev/feast-ui/-/feast-ui-0.35.0.tgz#f28eb82ae4855673230f14e3740a7786f545fdd7"
+ integrity sha512-t0Rd2TWUMim6ITfVVlQU8aBZboLvxla6Z7udGW+tQ3UUGcq1VbM6/y+GobuYQfbdHHeF2GmlYqp6zw5DuoIM+Q==
dependencies:
"@elastic/datemath" "^5.0.3"
"@elastic/eui" "^55.0.1"
@@ -1319,6 +1470,7 @@
prop-types "^15.8.1"
protobufjs "^7.1.1"
query-string "^7.1.1"
+ react-code-blocks "^0.0.9-0"
react-query "^3.34.12"
react-router-dom "6"
react-scripts "^5.0.0"
@@ -1582,7 +1734,16 @@
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9"
-"@jridgewell/resolve-uri@^3.0.3":
+"@jridgewell/gen-mapping@^0.3.2":
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098"
+ integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==
+ dependencies:
+ "@jridgewell/set-array" "^1.0.1"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
@@ -1605,11 +1766,19 @@
"@jridgewell/gen-mapping" "^0.3.0"
"@jridgewell/trace-mapping" "^0.3.9"
-"@jridgewell/sourcemap-codec@^1.4.10":
+"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.14"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
+"@jridgewell/trace-mapping@^0.3.17":
+ version "0.3.18"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6"
+ integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==
+ dependencies:
+ "@jridgewell/resolve-uri" "3.1.0"
+ "@jridgewell/sourcemap-codec" "1.4.14"
+
"@jridgewell/trace-mapping@^0.3.9":
version "0.3.14"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
@@ -3233,6 +3402,17 @@ babel-plugin-polyfill-regenerator@^0.3.0:
dependencies:
"@babel/helper-define-polyfill-provider" "^0.3.1"
+"babel-plugin-styled-components@>= 1.12.0":
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.4.tgz#9a1f37c7f32ef927b4b008b529feb4a2c82b1092"
+ integrity sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.22.5"
+ "@babel/helper-module-imports" "^7.22.5"
+ "@babel/plugin-syntax-jsx" "^7.22.5"
+ lodash "^4.17.21"
+ picomatch "^2.3.1"
+
babel-plugin-transform-react-remove-prop-types@^0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a"
@@ -3479,6 +3659,11 @@ camelcase@^6.2.0, camelcase@^6.2.1:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
+camelize@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3"
+ integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
+
caniuse-api@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
@@ -3504,7 +3689,7 @@ ccount@^1.0.0:
resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043"
integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==
-chalk@^2.0.0, chalk@^2.4.1:
+chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -3616,6 +3801,15 @@ clean-css@^5.2.2:
dependencies:
source-map "~0.6.0"
+clipboard@^2.0.0:
+ version "2.0.11"
+ resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.11.tgz#62180360b97dd668b6b3a84ec226975762a70be5"
+ integrity sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==
+ dependencies:
+ good-listener "^1.2.2"
+ select "^1.1.2"
+ tiny-emitter "^2.0.0"
+
cliui@^7.0.2:
version "7.0.4"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
@@ -3862,6 +4056,11 @@ css-box-model@^1.2.0:
dependencies:
tiny-invariant "^1.0.6"
+css-color-keywords@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
+ integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==
+
css-declaration-sorter@^6.2.2:
version "6.2.2"
resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.2.2.tgz#bfd2f6f50002d6a3ae779a87d3a0c5d5b10e0f02"
@@ -3931,6 +4130,15 @@ css-select@^4.1.3:
domutils "^2.8.0"
nth-check "^2.0.1"
+css-to-react-native@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32"
+ integrity sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==
+ dependencies:
+ camelize "^1.0.0"
+ css-color-keywords "^1.0.0"
+ postcss-value-parser "^4.0.2"
+
css-tree@1.0.0-alpha.37:
version "1.0.0-alpha.37"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22"
@@ -4400,6 +4608,11 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
+delegate@^3.1.2:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
+ integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
+
depd@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
@@ -5127,6 +5340,13 @@ fastq@^1.6.0:
dependencies:
reusify "^1.0.4"
+fault@^1.0.2:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13"
+ integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==
+ dependencies:
+ format "^0.2.0"
+
faye-websocket@^0.11.3:
version "0.11.4"
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da"
@@ -5265,9 +5485,9 @@ focus-lock@^0.11.2:
tslib "^2.0.3"
follow-redirects@^1.0.0:
- version "1.15.0"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.0.tgz#06441868281c86d0dda4ad8bdaead2d02dca89d4"
- integrity sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==
+ version "1.15.4"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf"
+ integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==
fork-ts-checker-webpack-plugin@^6.5.0:
version "6.5.2"
@@ -5297,6 +5517,11 @@ form-data@^3.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
+format@^0.2.0:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b"
+ integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==
+
forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
@@ -5489,6 +5714,13 @@ globby@^11.0.4:
merge2 "^1.4.1"
slash "^3.0.0"
+good-listener@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
+ integrity sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==
+ dependencies:
+ delegate "^3.1.2"
+
graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
@@ -5636,6 +5868,16 @@ hast-util-whitespace@^1.0.0:
resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz#e4fe77c4a9ae1cb2e6c25e02df0043d0164f6e41"
integrity sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==
+hastscript@^5.0.0:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-5.1.2.tgz#bde2c2e56d04c62dd24e8c5df288d050a355fb8a"
+ integrity sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ==
+ dependencies:
+ comma-separated-tokens "^1.0.0"
+ hast-util-parse-selector "^2.0.0"
+ property-information "^5.0.0"
+ space-separated-tokens "^1.0.0"
+
hastscript@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640"
@@ -5652,6 +5894,11 @@ he@^1.2.0:
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+highlight.js@~9.15.0, highlight.js@~9.15.1:
+ version "9.15.10"
+ resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.10.tgz#7b18ed75c90348c045eef9ed08ca1319a2219ad2"
+ integrity sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw==
+
history@^5.2.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b"
@@ -5659,7 +5906,7 @@ history@^5.2.0:
dependencies:
"@babel/runtime" "^7.7.6"
-hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
+hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@@ -6980,6 +7227,14 @@ lower-case@^2.0.2:
dependencies:
tslib "^2.0.3"
+lowlight@1.12.1:
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.12.1.tgz#014acf8dd73a370e02ff1cc61debcde3bb1681eb"
+ integrity sha512-OqaVxMGIESnawn+TU/QMV5BJLbUghUfjDWPAtFqDYDmDtr4FnB+op8xM+pR7nKlauHNUHXGt0VgWatFB8voS5w==
+ dependencies:
+ fault "^1.0.2"
+ highlight.js "~9.15.0"
+
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
@@ -7540,6 +7795,18 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
+parse-entities@^1.1.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50"
+ integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==
+ dependencies:
+ character-entities "^1.0.0"
+ character-entities-legacy "^1.0.0"
+ character-reference-invalid "^1.0.0"
+ is-alphanumerical "^1.0.0"
+ is-decimal "^1.0.0"
+ is-hexadecimal "^1.0.0"
+
parse-entities@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8"
@@ -8166,7 +8433,7 @@ postcss-unique-selectors@^5.1.1:
dependencies:
postcss-selector-parser "^6.0.5"
-postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
+postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
@@ -8230,6 +8497,18 @@ pretty-format@^28.1.0:
ansi-styles "^5.0.0"
react-is "^18.0.0"
+prismjs@^1.8.4:
+ version "1.29.0"
+ resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12"
+ integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==
+
+prismjs@~1.17.0:
+ version "1.17.1"
+ resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.17.1.tgz#e669fcbd4cdd873c35102881c33b14d0d68519be"
+ integrity sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q==
+ optionalDependencies:
+ clipboard "^2.0.0"
+
prismjs@~1.27.0:
version "1.27.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057"
@@ -8272,9 +8551,9 @@ property-information@^5.0.0, property-information@^5.3.0:
xtend "^4.0.0"
protobufjs@^7.1.1:
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.1.2.tgz#a0cf6aeaf82f5625bffcf5a38b7cd2a7de05890c"
- integrity sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==
+ version "7.2.4"
+ resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.4.tgz#3fc1ec0cdc89dd91aef9ba6037ba07408485c3ae"
+ integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==
dependencies:
"@protobufjs/aspromise" "^1.1.2"
"@protobufjs/base64" "^1.1.2"
@@ -8410,6 +8689,16 @@ react-clientside-effect@^1.2.6:
dependencies:
"@babel/runtime" "^7.12.13"
+react-code-blocks@^0.0.9-0:
+ version "0.0.9-0"
+ resolved "https://registry.yarnpkg.com/react-code-blocks/-/react-code-blocks-0.0.9-0.tgz#0c6d04d8a40b74cffe95f24f1a8e62a0fda8c014"
+ integrity sha512-jdYJVZwGtsr6WIUaqILy5fkF1acf57YV5s0V3+w5o9v3omYnqBeO6EuZi1Vf2x1hahkYGEedsp46+ofdkYlqyw==
+ dependencies:
+ "@babel/runtime" "^7.10.4"
+ react-syntax-highlighter "^12.2.1"
+ styled-components "^5.1.1"
+ tslib "^2.0.0"
+
react-dev-utils@^12.0.1:
version "12.0.1"
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.1.tgz#ba92edb4a1f379bd46ccd6bcd4e7bc398df33e73"
@@ -8643,6 +8932,17 @@ react-style-singleton@^2.2.0:
invariant "^2.2.4"
tslib "^2.0.0"
+react-syntax-highlighter@^12.2.1:
+ version "12.2.1"
+ resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-12.2.1.tgz#14d78352da1c1c3f93c6698b70ec7c706b83493e"
+ integrity sha512-CTsp0ZWijwKRYFg9xhkWD4DSpQqE4vb2NKVMdPAkomnILSmsNBHE0n5GuI5zB+PU3ySVvXvdt9jo+ViD9XibCA==
+ dependencies:
+ "@babel/runtime" "^7.3.1"
+ highlight.js "~9.15.1"
+ lowlight "1.12.1"
+ prismjs "^1.8.4"
+ refractor "^2.4.1"
+
react-virtualized-auto-sizer@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.6.tgz#66c5b1c9278064c5ef1699ed40a29c11518f97ca"
@@ -8715,6 +9015,15 @@ redux@^4.0.0, redux@^4.0.4:
dependencies:
"@babel/runtime" "^7.9.2"
+refractor@^2.4.1:
+ version "2.10.1"
+ resolved "https://registry.yarnpkg.com/refractor/-/refractor-2.10.1.tgz#166c32f114ed16fd96190ad21d5193d3afc7d34e"
+ integrity sha512-Xh9o7hQiQlDbxo5/XkOX6H+x/q8rmlmZKr97Ie1Q8ZM32IRRd3B/UxuA/yXDW79DBSXGWxm2yRTbcTVmAciJRw==
+ dependencies:
+ hastscript "^5.0.0"
+ parse-entities "^1.1.2"
+ prismjs "~1.17.0"
+
refractor@^3.5.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a"
@@ -8736,6 +9045,11 @@ regenerate@^1.4.2:
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
+regenerator-runtime@^0.13.11:
+ version "0.13.11"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
+ integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
+
regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.9:
version "0.13.9"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
@@ -9090,6 +9404,11 @@ select-hose@^2.0.0:
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
+select@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
+ integrity sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==
+
selfsigned@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.0.1.tgz#8b2df7fa56bf014d19b6007655fff209c0ef0a56"
@@ -9103,14 +9422,14 @@ semver@7.0.0:
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.3.2, semver@^7.3.5:
- version "7.3.7"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
- integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
@@ -9185,6 +9504,11 @@ setprototypeof@1.2.0:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+shallowequal@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
+ integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
+
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@@ -9529,6 +9853,22 @@ style-to-object@^0.3.0:
dependencies:
inline-style-parser "0.1.1"
+styled-components@^5.1.1:
+ version "5.3.11"
+ resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.11.tgz#9fda7bf1108e39bf3f3e612fcc18170dedcd57a8"
+ integrity sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==
+ dependencies:
+ "@babel/helper-module-imports" "^7.0.0"
+ "@babel/traverse" "^7.4.5"
+ "@emotion/is-prop-valid" "^1.1.0"
+ "@emotion/stylis" "^0.8.4"
+ "@emotion/unitless" "^0.7.4"
+ babel-plugin-styled-components ">= 1.12.0"
+ css-to-react-native "^3.0.0"
+ hoist-non-react-statics "^3.0.0"
+ shallowequal "^1.1.0"
+ supports-color "^5.5.0"
+
stylehacks@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520"
@@ -9542,7 +9882,7 @@ stylis@4.0.13:
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91"
integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==
-supports-color@^5.3.0:
+supports-color@^5.3.0, supports-color@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
@@ -9733,6 +10073,11 @@ thunky@^1.0.2:
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==
+tiny-emitter@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
+ integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
+
tiny-invariant@^1.0.6:
version "1.2.0"
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9"
@@ -9761,13 +10106,14 @@ toidentifier@1.0.1:
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
tough-cookie@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4"
- integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf"
+ integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
dependencies:
psl "^1.1.33"
punycode "^2.1.1"
- universalify "^0.1.2"
+ universalify "^0.2.0"
+ url-parse "^1.5.3"
tr46@^1.0.1:
version "1.0.1"
@@ -10021,10 +10367,10 @@ unist-util-visit@^2.0.0, unist-util-visit@^2.0.3:
unist-util-is "^4.0.0"
unist-util-visit-parents "^3.0.0"
-universalify@^0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
- integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+universalify@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0"
+ integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==
universalify@^2.0.0:
version "2.0.0"
@@ -10061,7 +10407,7 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
-url-parse@^1.5.10:
+url-parse@^1.5.10, url-parse@^1.5.3:
version "1.5.10"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1"
integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==
@@ -10676,10 +11022,10 @@ yocto-queue@^0.1.0:
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
-zod@^3.11.6, zod@^3.15.1:
- version "3.15.1"
- resolved "https://registry.yarnpkg.com/zod/-/zod-3.15.1.tgz#9e404cd8002ccffb03baa94cff2e1638ed49d82f"
- integrity sha512-WAdjcoOxa4S9oc/u7fTbC3CC7uVqptLLU0LKqS8RDBOrCXp2t5avM8BUfgNVZJymGWAx6SEUYxWPPoYuQ5rgwQ==
+zod@^3.11.6, zod@^3.22.3:
+ version "3.22.3"
+ resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.3.tgz#2fbc96118b174290d94e8896371c95629e87a060"
+ integrity sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==
zwitch@^1.0.0:
version "1.0.5"
diff --git a/sdk/python/feast/ui_server.py b/sdk/python/feast/ui_server.py
index e750f280ad7..8a39293f918 100644
--- a/sdk/python/feast/ui_server.py
+++ b/sdk/python/feast/ui_server.py
@@ -2,7 +2,7 @@
import threading
from typing import Callable, Optional
-import pkg_resources
+import importlib_resources
import uvicorn
from fastapi import FastAPI, Response
from fastapi.middleware.cors import CORSMiddleware
@@ -51,20 +51,21 @@ def shutdown_event():
async_refresh()
- ui_dir = pkg_resources.resource_filename(__name__, "ui/build/")
- # Initialize with the projects-list.json file
- with open(ui_dir + "projects-list.json", mode="w") as f:
- projects_dict = {
- "projects": [
- {
- "name": "Project",
- "description": "Test project",
- "id": project_id,
- "registryPath": f"{root_path}/registry",
- }
- ]
- }
- f.write(json.dumps(projects_dict))
+ ui_dir_ref = importlib_resources.files(__name__) / "ui/build/"
+ with importlib_resources.as_file(ui_dir_ref) as ui_dir:
+ # Initialize with the projects-list.json file
+ with ui_dir.joinpath("projects-list.json").open(mode="w") as f:
+ projects_dict = {
+ "projects": [
+ {
+ "name": "Project",
+ "description": "Test project",
+ "id": project_id,
+ "registryPath": f"{root_path}/registry",
+ }
+ ]
+ }
+ f.write(json.dumps(projects_dict))
@app.get("/registry")
def read_registry():
@@ -76,7 +77,7 @@ def read_registry():
# For all other paths (such as paths that would otherwise be handled by react router), pass to React
@app.api_route("/p/{path_name:path}", methods=["GET"])
def catch_all():
- filename = ui_dir + "index.html"
+ filename = ui_dir.joinpath("index.html")
with open(filename) as f:
content = f.read()
diff --git a/sdk/python/requirements/py3.10-ci-requirements.txt b/sdk/python/requirements/py3.10-ci-requirements.txt
index 6586bdef335..f20bc05df90 100644
--- a/sdk/python/requirements/py3.10-ci-requirements.txt
+++ b/sdk/python/requirements/py3.10-ci-requirements.txt
@@ -4,132 +4,104 @@
#
# pip-compile --extra=ci --output-file=sdk/python/requirements/py3.10-ci-requirements.txt
#
-adal==1.2.7
- # via msrestazure
-adlfs==0.5.9
- # via feast (setup.py)
-aiohttp==3.8.4
- # via
- # adlfs
- # gcsfs
-aiosignal==1.3.1
- # via aiohttp
-alabaster==0.7.13
+alabaster==0.7.16
# via sphinx
-altair==4.2.0
+altair==4.2.2
# via great-expectations
-anyio==3.7.0
+annotated-types==0.6.0
+ # via pydantic
+anyio==4.2.0
# via
- # httpcore
+ # httpx
# jupyter-server
# starlette
# watchfiles
appdirs==1.4.4
# via fissix
-appnope==0.1.3
- # via
- # ipykernel
- # ipython
-argon2-cffi==21.3.0
- # via
- # jupyter-server
- # nbclassic
- # notebook
+argon2-cffi==23.1.0
+ # via jupyter-server
argon2-cffi-bindings==21.2.0
# via argon2-cffi
-arrow==1.2.3
+arrow==1.3.0
# via isoduration
asn1crypto==1.5.1
- # via
- # oscrypto
- # snowflake-connector-python
+ # via snowflake-connector-python
assertpy==1.1
# via feast (setup.py)
-asttokens==2.2.1
+asttokens==2.4.1
# via stack-data
-async-timeout==4.0.2
- # via
- # aiohttp
- # redis
-attrs==23.1.0
+async-lru==2.0.4
+ # via jupyterlab
+async-timeout==4.0.3
+ # via redis
+attrs==23.2.0
# via
- # aiohttp
# bowler
# jsonschema
+ # referencing
avro==1.10.0
# via feast (setup.py)
-azure-core==1.27.0
+azure-core==1.30.0
# via
- # adlfs
# azure-identity
# azure-storage-blob
- # msrest
-azure-datalake-store==0.0.53
- # via adlfs
-azure-identity==1.13.0
- # via
- # adlfs
- # feast (setup.py)
-azure-storage-blob==12.16.0
+azure-identity==1.15.0
+ # via feast (setup.py)
+azure-storage-blob==12.19.0
+ # via feast (setup.py)
+babel==2.14.0
# via
- # adlfs
- # feast (setup.py)
-babel==2.12.1
- # via sphinx
-backcall==0.2.0
- # via ipython
-beautifulsoup4==4.12.2
+ # jupyterlab-server
+ # sphinx
+beautifulsoup4==4.12.3
# via nbconvert
black==22.12.0
# via feast (setup.py)
-bleach==6.0.0
+bleach==6.1.0
# via nbconvert
-boto3==1.26.146
+boto3==1.34.42
# via
# feast (setup.py)
# moto
-botocore==1.29.146
+botocore==1.34.42
# via
# boto3
# moto
# s3transfer
bowler==0.9.0
# via feast (setup.py)
-build==0.10.0
+build==1.0.3
# via
# feast (setup.py)
# pip-tools
bytewax==0.15.1
# via feast (setup.py)
-cachecontrol==0.13.0
+cachecontrol==0.14.0
# via firebase-admin
-cachetools==5.3.1
+cachetools==5.3.2
# via google-auth
-cassandra-driver==3.27.0
+cassandra-driver==3.29.0
# via feast (setup.py)
-certifi==2023.5.7
+certifi==2024.2.2
# via
# httpcore
# httpx
# kubernetes
# minio
- # msrest
# requests
# snowflake-connector-python
-cffi==1.15.1
+cffi==1.16.0
# via
# argon2-cffi-bindings
- # azure-datalake-store
# cryptography
# snowflake-connector-python
-cfgv==3.3.1
+cfgv==3.4.0
# via pre-commit
-charset-normalizer==3.1.0
+charset-normalizer==3.3.2
# via
- # aiohttp
# requests
# snowflake-connector-python
-click==8.1.3
+click==8.1.7
# via
# black
# bowler
@@ -140,22 +112,22 @@ click==8.1.3
# moreorless
# pip-tools
# uvicorn
-cloudpickle==2.2.1
+cloudpickle==3.0.0
# via dask
colorama==0.4.6
# via
# feast (setup.py)
# great-expectations
-comm==0.1.3
- # via ipykernel
-coverage[toml]==7.2.7
+comm==0.2.1
+ # via
+ # ipykernel
+ # ipywidgets
+coverage[toml]==7.4.1
# via pytest-cov
-cryptography==40.0.2
+cryptography==41.0.7
# via
- # adal
# azure-identity
# azure-storage-blob
- # cassandra-driver
# feast (setup.py)
# great-expectations
# moto
@@ -165,30 +137,26 @@ cryptography==40.0.2
# snowflake-connector-python
# types-pyopenssl
# types-redis
-dask==2023.5.1
+dask==2024.2.0
# via feast (setup.py)
-db-dtypes==1.1.1
+db-dtypes==1.2.0
# via google-cloud-bigquery
-debugpy==1.6.7
+debugpy==1.8.1
# via ipykernel
decorator==5.1.1
- # via
- # gcsfs
- # ipython
+ # via ipython
defusedxml==0.7.1
# via nbconvert
-deprecated==1.2.14
- # via redis
deprecation==2.1.0
# via testcontainers
-dill==0.3.6
+dill==0.3.8
# via
# bytewax
# feast (setup.py)
# multiprocess
-distlib==0.3.6
+distlib==0.3.8
# via virtualenv
-docker==6.1.3
+docker==7.0.0
# via
# feast (setup.py)
# testcontainers
@@ -196,23 +164,24 @@ docutils==0.19
# via sphinx
entrypoints==0.4
# via altair
-exceptiongroup==1.1.1
+exceptiongroup==1.2.0
# via
# anyio
+ # ipython
# pytest
-execnet==1.9.0
+execnet==2.0.2
# via pytest-xdist
-executing==1.2.0
+executing==2.0.1
# via stack-data
-fastapi==0.95.2
+fastapi==0.109.2
# via feast (setup.py)
-fastavro==1.7.4
+fastavro==1.9.4
# via
# feast (setup.py)
# pandavro
-fastjsonschema==2.17.1
+fastjsonschema==2.19.1
# via nbformat
-filelock==3.12.0
+filelock==3.13.1
# via
# snowflake-connector-python
# virtualenv
@@ -224,22 +193,15 @@ flake8==6.0.0
# via feast (setup.py)
fqdn==1.5.1
# via jsonschema
-frozenlist==1.3.3
+fsspec==2023.12.2
# via
- # aiohttp
- # aiosignal
-fsspec==2022.1.0
- # via
- # adlfs
# dask
- # gcsfs
-gcsfs==2022.1.0
- # via feast (setup.py)
+ # feast (setup.py)
geojson==2.5.0
# via rockset
geomet==0.2.1.post1
# via cassandra-driver
-google-api-core[grpc]==2.11.0
+google-api-core[grpc]==2.17.1
# via
# feast (setup.py)
# firebase-admin
@@ -251,82 +213,86 @@ google-api-core[grpc]==2.11.0
# google-cloud-datastore
# google-cloud-firestore
# google-cloud-storage
-google-api-python-client==2.88.0
+google-api-python-client==2.118.0
# via firebase-admin
-google-auth==2.19.1
+google-auth==2.27.0
# via
- # gcsfs
# google-api-core
# google-api-python-client
# google-auth-httplib2
- # google-auth-oauthlib
# google-cloud-core
# google-cloud-storage
# kubernetes
-google-auth-httplib2==0.1.0
+google-auth-httplib2==0.2.0
# via google-api-python-client
-google-auth-oauthlib==1.0.0
- # via gcsfs
-google-cloud-bigquery[pandas]==3.11.0
+google-cloud-bigquery[pandas]==3.12.0
+ # via
+ # feast (setup.py)
+ # google-cloud-bigquery
+google-cloud-bigquery-storage==2.24.0
# via feast (setup.py)
-google-cloud-bigquery-storage==2.20.0
+google-cloud-bigquery-storage==2.24.0
# via feast (setup.py)
-google-cloud-bigtable==2.18.1
+google-cloud-bigtable==2.23.0
# via feast (setup.py)
-google-cloud-core==2.3.2
+google-cloud-core==2.4.1
# via
# google-cloud-bigquery
# google-cloud-bigtable
# google-cloud-datastore
# google-cloud-firestore
# google-cloud-storage
-google-cloud-datastore==2.15.2
+google-cloud-datastore==2.19.0
# via feast (setup.py)
-google-cloud-firestore==2.11.1
+google-cloud-firestore==2.14.0
# via firebase-admin
-google-cloud-storage==2.9.0
+google-cloud-storage==2.14.0
# via
# feast (setup.py)
# firebase-admin
- # gcsfs
google-crc32c==1.5.0
- # via google-resumable-media
-google-resumable-media==2.5.0
+ # via
+ # google-cloud-storage
+ # google-resumable-media
+google-resumable-media==2.7.0
# via
# google-cloud-bigquery
# google-cloud-storage
-googleapis-common-protos[grpc]==1.59.0
+googleapis-common-protos[grpc]==1.62.0
# via
# feast (setup.py)
# google-api-core
# grpc-google-iam-v1
# grpcio-status
-great-expectations==0.15.50
+great-expectations==0.18.8
# via feast (setup.py)
-greenlet==2.0.2
+greenlet==3.0.3
# via sqlalchemy
-grpc-google-iam-v1==0.12.6
+grpc-google-iam-v1==0.13.0
# via google-cloud-bigtable
-grpcio==1.54.2
+grpcio==1.60.1
# via
# feast (setup.py)
# google-api-core
# google-cloud-bigquery
# googleapis-common-protos
# grpc-google-iam-v1
+ # grpcio-health-checking
# grpcio-reflection
# grpcio-status
# grpcio-testing
# grpcio-tools
-grpcio-reflection==1.54.2
+grpcio-health-checking==1.60.1
# via feast (setup.py)
-grpcio-status==1.54.2
+grpcio-reflection==1.60.1
+ # via feast (setup.py)
+grpcio-status==1.60.1
# via google-api-core
-grpcio-testing==1.54.2
+grpcio-testing==1.60.1
# via feast (setup.py)
-grpcio-tools==1.54.2
+grpcio-tools==1.60.1
# via feast (setup.py)
-gunicorn==20.1.0
+gunicorn==21.2.0
# via feast (setup.py)
h11==0.14.0
# via
@@ -334,133 +300,140 @@ h11==0.14.0
# uvicorn
happybase==1.2.0
# via feast (setup.py)
-hazelcast-python-client==5.2.0
+hazelcast-python-client==5.3.0
# via feast (setup.py)
-hiredis==2.2.3
+hiredis==2.3.2
# via feast (setup.py)
-httpcore==0.17.2
+httpcore==1.0.3
# via httpx
httplib2==0.22.0
# via
# google-api-python-client
# google-auth-httplib2
-httptools==0.5.0
+httptools==0.6.1
# via uvicorn
-httpx==0.24.1
- # via feast (setup.py)
-identify==2.5.24
+httpx==0.26.0
+ # via
+ # feast (setup.py)
+ # jupyterlab
+identify==2.5.34
# via pre-commit
-idna==3.4
+idna==3.6
# via
# anyio
# httpx
# jsonschema
# requests
# snowflake-connector-python
- # yarl
imagesize==1.4.1
# via sphinx
-importlib-metadata==6.6.0
+importlib-metadata==6.11.0
# via
# dask
- # great-expectations
+ # feast (setup.py)
+importlib-resources==6.1.1
+ # via feast (setup.py)
iniconfig==2.0.0
# via pytest
-ipykernel==6.23.1
- # via
- # ipywidgets
- # nbclassic
- # notebook
-ipython==8.14.0
+ipykernel==6.29.2
+ # via jupyterlab
+ipython==8.21.0
# via
# great-expectations
# ipykernel
# ipywidgets
-ipython-genutils==0.2.0
- # via
- # nbclassic
- # notebook
-ipywidgets==8.0.6
+ipywidgets==8.1.2
# via great-expectations
isodate==0.6.1
- # via
- # azure-storage-blob
- # msrest
+ # via azure-storage-blob
isoduration==20.11.0
# via jsonschema
-isort==5.12.0
+isort==5.13.2
# via feast (setup.py)
-jedi==0.18.2
+jedi==0.19.1
# via ipython
-jinja2==3.1.2
+jinja2==3.1.3
# via
# altair
# feast (setup.py)
# great-expectations
# jupyter-server
+ # jupyterlab
+ # jupyterlab-server
# moto
- # nbclassic
# nbconvert
- # notebook
# sphinx
jmespath==1.0.1
# via
# boto3
# botocore
-jsonpatch==1.32
+json5==0.9.14
+ # via jupyterlab-server
+jsonpatch==1.33
# via great-expectations
-jsonpointer==2.3
+jsonpointer==2.4
# via
# jsonpatch
# jsonschema
-jsonschema[format-nongpl]==4.17.3
+jsonschema[format-nongpl]==4.21.1
# via
# altair
# feast (setup.py)
# great-expectations
# jupyter-events
+ # jupyterlab-server
# nbformat
-jupyter-client==8.2.0
+jsonschema-specifications==2023.12.1
+ # via jsonschema
+jupyter-client==8.6.0
# via
# ipykernel
# jupyter-server
- # nbclassic
# nbclient
- # notebook
-jupyter-core==5.3.0
+jupyter-core==5.7.1
# via
# ipykernel
# jupyter-client
# jupyter-server
- # nbclassic
+ # jupyterlab
# nbclient
# nbconvert
# nbformat
- # notebook
-jupyter-events==0.6.3
+jupyter-events==0.9.0
# via jupyter-server
-jupyter-server==2.6.0
+jupyter-lsp==2.2.2
+ # via jupyterlab
+jupyter-server==2.12.5
# via
- # nbclassic
+ # jupyter-lsp
+ # jupyterlab
+ # jupyterlab-server
+ # notebook
# notebook-shim
-jupyter-server-terminals==0.4.4
+jupyter-server-terminals==0.5.2
# via jupyter-server
-jupyterlab-pygments==0.2.2
+jupyterlab==4.1.1
+ # via notebook
+jupyterlab-pygments==0.3.0
# via nbconvert
-jupyterlab-widgets==3.0.7
+jupyterlab-server==2.25.3
+ # via
+ # jupyterlab
+ # notebook
+jupyterlab-widgets==3.0.10
# via ipywidgets
kubernetes==20.13.0
# via feast (setup.py)
locket==1.0.0
# via partd
-makefun==1.15.1
+makefun==1.15.2
# via great-expectations
-markupsafe==2.1.3
+markupsafe==2.1.5
# via
# jinja2
# nbconvert
# werkzeug
-marshmallow==3.19.0
+marshmallow==3.20.2
# via great-expectations
matplotlib-inline==0.1.6
# via
@@ -470,38 +443,29 @@ mccabe==0.7.0
# via flake8
minio==7.1.0
# via feast (setup.py)
-mistune==2.0.5
+mistune==3.0.2
# via
# great-expectations
# nbconvert
-mmh3==4.0.0
+mmh3==4.1.0
# via feast (setup.py)
mock==2.0.0
# via feast (setup.py)
moreorless==0.4.0
# via bowler
-moto==4.1.10
+moto==4.2.14
# via feast (setup.py)
-msal==1.22.0
+msal==1.26.0
# via
- # azure-datalake-store
# azure-identity
# msal-extensions
-msal-extensions==1.0.0
+msal-extensions==1.1.0
# via azure-identity
-msgpack==1.0.5
+msgpack==1.0.7
# via cachecontrol
-msrest==0.7.1
- # via msrestazure
-msrestazure==0.6.4
- # via adlfs
-multidict==6.0.4
- # via
- # aiohttp
- # yarl
-multiprocess==0.70.14
+multiprocess==0.70.16
# via bytewax
-mypy==0.982
+mypy==1.8.0
# via
# feast (setup.py)
# sqlalchemy
@@ -509,39 +473,29 @@ mypy-extensions==1.0.0
# via
# black
# mypy
-mypy-protobuf==3.1
- # via feast (setup.py)
-mysqlclient==2.1.1
+mypy-protobuf==3.1.0
# via feast (setup.py)
-nbclassic==1.0.0
- # via notebook
-nbclient==0.8.0
+nbclient==0.9.0
# via nbconvert
-nbconvert==7.4.0
- # via
- # jupyter-server
- # nbclassic
- # notebook
-nbformat==5.9.0
+nbconvert==7.16.0
+ # via jupyter-server
+nbformat==5.9.2
# via
# great-expectations
# jupyter-server
- # nbclassic
# nbclient
# nbconvert
- # notebook
-nest-asyncio==1.5.6
- # via
- # ipykernel
- # nbclassic
- # notebook
+nest-asyncio==1.6.0
+ # via ipykernel
nodeenv==1.8.0
# via pre-commit
-notebook==6.5.4
+notebook==7.1.0
# via great-expectations
notebook-shim==0.2.3
- # via nbclassic
-numpy==1.24.3
+ # via
+ # jupyterlab
+ # notebook
+numpy==1.24.4
# via
# altair
# db-dtypes
@@ -553,11 +507,9 @@ numpy==1.24.3
# scipy
oauthlib==3.2.2
# via requests-oauthlib
-oscrypto==1.3.0
- # via snowflake-connector-python
-overrides==7.3.1
+overrides==7.7.0
# via jupyter-server
-packaging==23.1
+packaging==23.2
# via
# build
# dask
@@ -566,12 +518,15 @@ packaging==23.1
# docker
# google-cloud-bigquery
# great-expectations
+ # gunicorn
# ipykernel
# jupyter-server
+ # jupyterlab
+ # jupyterlab-server
# marshmallow
+ # msal-extensions
# nbconvert
# pytest
- # redis
# snowflake-connector-python
# sphinx
pandas==1.5.3
@@ -585,43 +540,39 @@ pandas==1.5.3
# snowflake-connector-python
pandavro==1.5.2
# via feast (setup.py)
-pandocfilters==1.5.0
+pandocfilters==1.5.1
# via nbconvert
parso==0.8.3
# via jedi
-partd==1.4.0
+partd==1.4.1
# via dask
-pathspec==0.11.1
+pathspec==0.12.1
# via black
-pbr==5.11.1
+pbr==6.0.0
# via mock
-pexpect==4.8.0
+pexpect==4.9.0
# via ipython
-pickleshare==0.7.5
- # via ipython
-pip-tools==6.13.0
+pip-tools==7.3.0
# via feast (setup.py)
-platformdirs==3.5.1
+platformdirs==3.11.0
# via
# black
# jupyter-core
+ # snowflake-connector-python
# virtualenv
-pluggy==1.0.0
+pluggy==1.4.0
# via pytest
ply==3.11
# via thriftpy2
-portalocker==2.7.0
+portalocker==2.8.2
# via msal-extensions
-pre-commit==3.3.2
+pre-commit==3.3.1
# via feast (setup.py)
-prometheus-client==0.17.0
- # via
- # jupyter-server
- # nbclassic
- # notebook
-prompt-toolkit==3.0.38
+prometheus-client==0.20.0
+ # via jupyter-server
+prompt-toolkit==3.0.43
# via ipython
-proto-plus==1.22.2
+proto-plus==1.23.0
# via
# feast (setup.py)
# google-cloud-bigquery
@@ -629,7 +580,7 @@ proto-plus==1.22.2
# google-cloud-bigtable
# google-cloud-datastore
# google-cloud-firestore
-protobuf==4.23.2
+protobuf==4.23.3
# via
# feast (setup.py)
# google-api-core
@@ -640,6 +591,7 @@ protobuf==4.23.2
# google-cloud-firestore
# googleapis-common-protos
# grpc-google-iam-v1
+ # grpcio-health-checking
# grpcio-reflection
# grpcio-status
# grpcio-testing
@@ -650,7 +602,7 @@ psutil==5.9.0
# via
# feast (setup.py)
# ipykernel
-psycopg2-binary==2.9.6
+psycopg2-binary==2.9.9
# via feast (setup.py)
ptyprocess==0.7.0
# via
@@ -664,13 +616,13 @@ py-cpuinfo==9.0.0
# via pytest-benchmark
py4j==0.10.9.7
# via pyspark
-pyarrow==10.0.1
+pyarrow==15.0.0
# via
# db-dtypes
# feast (setup.py)
# google-cloud-bigquery
# snowflake-connector-python
-pyasn1==0.5.0
+pyasn1==0.5.1
# via
# pyasn1-modules
# rsa
@@ -682,45 +634,42 @@ pycodestyle==2.10.0
# via flake8
pycparser==2.21
# via cffi
-pycryptodomex==3.18.0
- # via snowflake-connector-python
-pydantic==1.10.8
+pydantic==2.6.1
# via
# fastapi
# feast (setup.py)
# great-expectations
+pydantic-core==2.16.2
+ # via pydantic
pyflakes==3.0.1
# via flake8
-pygments==2.15.1
+pygments==2.17.2
# via
# feast (setup.py)
# ipython
# nbconvert
# sphinx
-pyjwt[crypto]==2.7.0
+pyjwt[crypto]==2.8.0
# via
- # adal
# msal
# snowflake-connector-python
-pymssql==2.2.7
+pymssql==2.2.11
# via feast (setup.py)
-pymysql==1.0.3
+pymysql==1.1.0
# via feast (setup.py)
-pyodbc==4.0.39
+pyodbc==5.1.0
# via feast (setup.py)
-pyopenssl==23.2.0
+pyopenssl==23.3.0
# via snowflake-connector-python
-pyparsing==3.0.9
+pyparsing==3.1.1
# via
# great-expectations
# httplib2
pyproject-hooks==1.0.0
# via build
-pyrsistent==0.19.3
- # via jsonschema
-pyspark==3.4.0
+pyspark==3.5.0
# via feast (setup.py)
-pytest==7.3.1
+pytest==7.4.4
# via
# feast (setup.py)
# pytest-benchmark
@@ -742,11 +691,10 @@ pytest-ordering==0.6
# via feast (setup.py)
pytest-timeout==1.4.2
# via feast (setup.py)
-pytest-xdist==3.3.1
+pytest-xdist==3.5.0
# via feast (setup.py)
python-dateutil==2.8.2
# via
- # adal
# arrow
# botocore
# google-cloud-bigquery
@@ -757,17 +705,17 @@ python-dateutil==2.8.2
# pandas
# rockset
# trino
-python-dotenv==1.0.0
+python-dotenv==1.0.1
# via uvicorn
python-json-logger==2.0.7
# via jupyter-events
-pytz==2023.3
+pytz==2024.1
# via
# great-expectations
# pandas
# snowflake-connector-python
# trino
-pyyaml==6.0
+pyyaml==6.0.1
# via
# dask
# feast (setup.py)
@@ -776,46 +724,42 @@ pyyaml==6.0
# pre-commit
# responses
# uvicorn
-pyzmq==25.1.0
+pyzmq==25.1.2
# via
# ipykernel
# jupyter-client
# jupyter-server
- # nbclassic
- # notebook
-redis==4.2.2
+redis==4.6.0
# via feast (setup.py)
-regex==2023.5.5
+referencing==0.33.0
+ # via
+ # jsonschema
+ # jsonschema-specifications
+ # jupyter-events
+regex==2023.12.25
# via feast (setup.py)
requests==2.31.0
# via
- # adal
- # adlfs
# azure-core
- # azure-datalake-store
# cachecontrol
# docker
# feast (setup.py)
- # gcsfs
# google-api-core
# google-cloud-bigquery
# google-cloud-storage
# great-expectations
+ # jupyterlab-server
# kubernetes
# moto
# msal
- # msrest
# requests-oauthlib
# responses
# snowflake-connector-python
# sphinx
# trino
requests-oauthlib==1.3.1
- # via
- # google-auth-oauthlib
- # kubernetes
- # msrest
-responses==0.23.1
+ # via kubernetes
+responses==0.25.0
# via moto
rfc3339-validator==0.1.4
# via
@@ -825,36 +769,32 @@ rfc3986-validator==0.1.1
# via
# jsonschema
# jupyter-events
-rockset==2.0.0
+rockset==2.1.0
# via feast (setup.py)
+rpds-py==0.18.0
+ # via
+ # jsonschema
+ # referencing
rsa==4.9
# via google-auth
ruamel-yaml==0.17.17
# via great-expectations
-s3transfer==0.6.1
+s3transfer==0.10.0
# via boto3
-scipy==1.10.1
+scipy==1.12.0
# via great-expectations
send2trash==1.8.2
- # via
- # jupyter-server
- # nbclassic
- # notebook
+ # via jupyter-server
six==1.16.0
# via
# asttokens
# azure-core
- # azure-identity
# bleach
- # cassandra-driver
# geomet
- # google-auth
- # google-auth-httplib2
# happybase
# isodate
# kubernetes
# mock
- # msrestazure
# pandavro
# python-dateutil
# rfc3339-validator
@@ -862,51 +802,48 @@ six==1.16.0
sniffio==1.3.0
# via
# anyio
- # httpcore
# httpx
snowballstemmer==2.2.0
# via sphinx
-snowflake-connector-python[pandas]==3.0.4
+snowflake-connector-python[pandas]==3.7.0
# via feast (setup.py)
sortedcontainers==2.4.0
# via snowflake-connector-python
-soupsieve==2.4.1
+soupsieve==2.5
# via beautifulsoup4
sphinx==6.2.1
# via feast (setup.py)
-sphinxcontrib-applehelp==1.0.4
+sphinxcontrib-applehelp==1.0.8
# via sphinx
-sphinxcontrib-devhelp==1.0.2
+sphinxcontrib-devhelp==1.0.6
# via sphinx
-sphinxcontrib-htmlhelp==2.0.1
+sphinxcontrib-htmlhelp==2.0.5
# via sphinx
sphinxcontrib-jsmath==1.0.1
# via sphinx
-sphinxcontrib-qthelp==1.0.3
+sphinxcontrib-qthelp==1.0.7
# via sphinx
-sphinxcontrib-serializinghtml==1.1.5
+sphinxcontrib-serializinghtml==1.1.10
# via sphinx
-sqlalchemy[mypy]==1.4.48
+sqlalchemy[mypy]==1.4.51
# via feast (setup.py)
-sqlalchemy2-stubs==0.0.2a34
+sqlalchemy2-stubs==0.0.2a38
# via sqlalchemy
-stack-data==0.6.2
+stack-data==0.6.3
# via ipython
-starlette==0.27.0
+starlette==0.36.3
# via fastapi
tabulate==0.9.0
# via feast (setup.py)
-tenacity==8.2.2
+tenacity==8.2.3
# via feast (setup.py)
-terminado==0.17.1
+terminado==0.18.0
# via
# jupyter-server
# jupyter-server-terminals
- # nbclassic
- # notebook
testcontainers==3.7.1
# via feast (setup.py)
-thriftpy2==0.4.16
+thriftpy2==0.4.17
# via happybase
tinycss2==1.2.1
# via nbconvert
@@ -917,27 +854,31 @@ tomli==2.0.1
# black
# build
# coverage
+ # jupyterlab
# mypy
+ # pip-tools
# pyproject-hooks
# pytest
-toolz==0.12.0
+tomlkit==0.12.3
+ # via snowflake-connector-python
+toolz==0.12.1
# via
# altair
# dask
# partd
-tornado==6.3.2
+tornado==6.4
# via
# ipykernel
# jupyter-client
# jupyter-server
- # nbclassic
+ # jupyterlab
# notebook
# terminado
-tqdm==4.65.0
+tqdm==4.66.2
# via
# feast (setup.py)
# great-expectations
-traitlets==5.9.0
+traitlets==5.14.1
# via
# comm
# ipykernel
@@ -947,83 +888,87 @@ traitlets==5.9.0
# jupyter-core
# jupyter-events
# jupyter-server
+ # jupyterlab
# matplotlib-inline
- # nbclassic
# nbclient
# nbconvert
# nbformat
- # notebook
-trino==0.326.0
+trino==0.327.0
# via feast (setup.py)
-typeguard==2.13.3
+typeguard==4.1.5
# via feast (setup.py)
types-protobuf==3.19.22
# via
# feast (setup.py)
# mypy-protobuf
-types-pymysql==1.0.19.7
+types-pymysql==1.1.0.1
# via feast (setup.py)
-types-pyopenssl==23.2.0.0
+types-pyopenssl==24.0.0.20240130
# via types-redis
-types-python-dateutil==2.8.19.13
- # via feast (setup.py)
-types-pytz==2023.3.0.0
- # via feast (setup.py)
-types-pyyaml==6.0.12.10
+types-python-dateutil==2.8.19.20240106
# via
+ # arrow
# feast (setup.py)
- # responses
-types-redis==4.5.5.2
+types-pytz==2024.1.0.20240203
+ # via feast (setup.py)
+types-pyyaml==6.0.12.12
# via feast (setup.py)
-types-requests==2.31.0.1
+types-redis==4.6.0.20240106
# via feast (setup.py)
-types-setuptools==67.8.0.0
+types-requests==2.30.0.0
# via feast (setup.py)
-types-tabulate==0.9.0.2
+types-setuptools==69.0.0.20240125
# via feast (setup.py)
-types-urllib3==1.26.25.13
+types-tabulate==0.9.0.20240106
+ # via feast (setup.py)
+types-urllib3==1.26.25.14
# via types-requests
-typing-extensions==4.6.3
+typing-extensions==4.9.0
# via
+ # anyio
+ # async-lru
# azure-core
# azure-storage-blob
+ # fastapi
# great-expectations
# mypy
# pydantic
+ # pydantic-core
# snowflake-connector-python
# sqlalchemy2-stubs
-tzlocal==5.0.1
+ # uvicorn
+tzlocal==5.2
# via
# great-expectations
# trino
-uri-template==1.2.0
+uri-template==1.3.0
# via jsonschema
uritemplate==4.1.1
# via google-api-python-client
-urllib3==1.26.16
+urllib3==1.26.18
# via
# botocore
# docker
# feast (setup.py)
- # google-auth
# great-expectations
# kubernetes
# minio
# requests
# responses
# rockset
- # snowflake-connector-python
-uvicorn[standard]==0.22.0
+uvicorn[standard]==0.27.1
# via feast (setup.py)
-uvloop==0.17.0
+uvloop==0.19.0
# via uvicorn
virtualenv==20.23.0
- # via pre-commit
+ # via
+ # feast (setup.py)
+ # pre-commit
volatile==2.1.0
# via bowler
-watchfiles==0.19.0
+watchfiles==0.21.0
# via uvicorn
-wcwidth==0.2.6
+wcwidth==0.2.13
# via prompt-toolkit
webcolors==1.13
# via jsonschema
@@ -1031,28 +976,23 @@ webencodings==0.5.1
# via
# bleach
# tinycss2
-websocket-client==1.5.2
+websocket-client==1.7.0
# via
- # docker
# jupyter-server
# kubernetes
-websockets==11.0.3
+websockets==12.0
# via uvicorn
-werkzeug==2.3.4
+werkzeug==3.0.1
# via moto
-wheel==0.40.0
+wheel==0.42.0
# via pip-tools
-widgetsnbextension==4.0.7
+widgetsnbextension==4.0.10
# via ipywidgets
-wrapt==1.15.0
- # via
- # deprecated
- # testcontainers
+wrapt==1.16.0
+ # via testcontainers
xmltodict==0.13.0
# via moto
-yarl==1.9.2
- # via aiohttp
-zipp==3.15.0
+zipp==3.17.0
# via importlib-metadata
# The following packages are considered to be unsafe in a requirements file:
diff --git a/sdk/python/requirements/py3.10-requirements.txt b/sdk/python/requirements/py3.10-requirements.txt
index 3eab83fe48c..3943662d010 100644
--- a/sdk/python/requirements/py3.10-requirements.txt
+++ b/sdk/python/requirements/py3.10-requirements.txt
@@ -4,142 +4,172 @@
#
# pip-compile --output-file=sdk/python/requirements/py3.10-requirements.txt
#
-anyio==3.7.0
+annotated-types==0.6.0
+ # via pydantic
+anyio==4.2.0
# via
- # httpcore
+ # httpx
# starlette
# watchfiles
appdirs==1.4.4
# via fissix
-attrs==23.1.0
+attrs==23.2.0
# via
# bowler
# jsonschema
+ # referencing
bowler==0.9.0
# via feast (setup.py)
-certifi==2023.5.7
+certifi==2024.2.2
# via
# httpcore
# httpx
# requests
-charset-normalizer==3.1.0
+charset-normalizer==3.3.2
# via requests
-click==8.1.3
+click==8.1.7
# via
# bowler
# dask
# feast (setup.py)
# moreorless
# uvicorn
-cloudpickle==2.2.1
+cloudpickle==3.0.0
# via dask
colorama==0.4.6
# via feast (setup.py)
-dask==2023.5.1
+dask==2024.2.0
# via feast (setup.py)
-dill==0.3.6
+dill==0.3.8
# via feast (setup.py)
-exceptiongroup==1.1.1
+exceptiongroup==1.2.0
# via anyio
-fastapi==0.95.2
+fastapi==0.109.2
# via feast (setup.py)
-fastavro==1.7.4
+fastavro==1.9.4
# via
# feast (setup.py)
# pandavro
fissix==21.11.13
# via bowler
-fsspec==2023.5.0
+fsspec==2024.2.0
# via dask
-greenlet==2.0.2
+greenlet==3.0.3
# via sqlalchemy
-grpcio==1.54.2
+grpcio==1.60.1
# via
# feast (setup.py)
+ # grpcio-health-checking
# grpcio-reflection
-grpcio-reflection==1.54.2
+ # grpcio-tools
+grpcio-health-checking==1.60.1
+ # via feast (setup.py)
+grpcio-reflection==1.60.1
+ # via feast (setup.py)
+grpcio-tools==1.60.1
# via feast (setup.py)
-gunicorn==20.1.0
+gunicorn==21.2.0
# via feast (setup.py)
h11==0.14.0
# via
# httpcore
# uvicorn
-httpcore==0.17.2
+httpcore==1.0.3
# via httpx
-httptools==0.5.0
+httptools==0.6.1
# via uvicorn
-httpx==0.24.1
+httpx==0.26.0
# via feast (setup.py)
-idna==3.4
+idna==3.6
# via
# anyio
# httpx
# requests
-importlib-metadata==6.6.0
- # via dask
-jinja2==3.1.2
+importlib-metadata==6.11.0
+ # via
+ # dask
+ # feast (setup.py)
+importlib-resources==6.1.1
# via feast (setup.py)
-jsonschema==4.17.3
+jinja2==3.1.3
# via feast (setup.py)
+jsonschema==4.21.1
+ # via feast (setup.py)
+jsonschema-specifications==2023.12.1
+ # via jsonschema
locket==1.0.0
# via partd
-markupsafe==2.1.3
+markupsafe==2.1.5
# via jinja2
-mmh3==4.0.0
+mmh3==4.1.0
# via feast (setup.py)
moreorless==0.4.0
# via bowler
-mypy==1.3.0
+mypy==1.8.0
# via sqlalchemy
mypy-extensions==1.0.0
# via mypy
-numpy==1.24.3
+mypy-protobuf==3.1.0
+ # via feast (setup.py)
+numpy==1.24.4
# via
# feast (setup.py)
# pandas
# pandavro
# pyarrow
-packaging==23.1
- # via dask
+packaging==23.2
+ # via
+ # dask
+ # gunicorn
pandas==1.5.3
# via
# feast (setup.py)
# pandavro
pandavro==1.5.2
# via feast (setup.py)
-partd==1.4.0
+partd==1.4.1
# via dask
-proto-plus==1.22.2
+proto-plus==1.23.0
# via feast (setup.py)
-protobuf==4.23.2
+protobuf==4.23.3
# via
# feast (setup.py)
+ # grpcio-health-checking
# grpcio-reflection
+ # grpcio-tools
+ # mypy-protobuf
# proto-plus
-pyarrow==11.0.0
+pyarrow==15.0.0
# via feast (setup.py)
-pydantic==1.10.8
+pydantic==2.6.1
# via
# fastapi
# feast (setup.py)
-pygments==2.15.1
+pydantic-core==2.16.2
+ # via pydantic
+pygments==2.17.2
# via feast (setup.py)
-pyrsistent==0.19.3
- # via jsonschema
python-dateutil==2.8.2
# via pandas
-python-dotenv==1.0.0
+python-dotenv==1.0.1
# via uvicorn
-pytz==2023.3
+pytz==2024.1
# via pandas
-pyyaml==6.0
+pyyaml==6.0.1
# via
# dask
# feast (setup.py)
# uvicorn
+referencing==0.33.0
+ # via
+ # jsonschema
+ # jsonschema-specifications
requests==2.31.0
# via feast (setup.py)
+rpds-py==0.18.0
+ # via
+ # jsonschema
+ # referencing
six==1.16.0
# via
# pandavro
@@ -147,46 +177,58 @@ six==1.16.0
sniffio==1.3.0
# via
# anyio
- # httpcore
# httpx
-sqlalchemy[mypy]==1.4.48
- # via feast (setup.py)
-sqlalchemy2-stubs==0.0.2a34
+sqlalchemy[mypy]==1.4.51
+ # via
+ # feast (setup.py)
+ # sqlalchemy
+sqlalchemy2-stubs==0.0.2a38
# via sqlalchemy
-starlette==0.27.0
+starlette==0.36.3
# via fastapi
tabulate==0.9.0
# via feast (setup.py)
-tenacity==8.2.2
+tenacity==8.2.3
# via feast (setup.py)
toml==0.10.2
# via feast (setup.py)
tomli==2.0.1
# via mypy
-toolz==0.12.0
+toolz==0.12.1
# via
# dask
# partd
-tqdm==4.65.0
+tqdm==4.66.2
# via feast (setup.py)
-typeguard==2.13.3
+typeguard==4.1.5
# via feast (setup.py)
-typing-extensions==4.6.3
+types-protobuf==4.24.0.20240129
+ # via mypy-protobuf
+typing-extensions==4.9.0
# via
+ # anyio
+ # fastapi
# mypy
# pydantic
+ # pydantic-core
# sqlalchemy2-stubs
-urllib3==2.0.2
+ # uvicorn
+urllib3==2.2.0
# via requests
-uvicorn[standard]==0.22.0
- # via feast (setup.py)
-uvloop==0.17.0
+uvicorn[standard]==0.27.1
+ # via
+ # feast (setup.py)
+ # uvicorn
+uvloop==0.19.0
# via uvicorn
volatile==2.1.0
# via bowler
-watchfiles==0.19.0
+watchfiles==0.21.0
# via uvicorn
-websockets==11.0.3
+websockets==12.0
# via uvicorn
-zipp==3.15.0
+zipp==3.17.0
# via importlib-metadata
+
+# The following packages are considered to be unsafe in a requirements file:
+# setuptools
diff --git a/sdk/python/requirements/py3.8-ci-requirements.txt b/sdk/python/requirements/py3.8-ci-requirements.txt
index 85e089b03a9..afa43ec2a2b 100644
--- a/sdk/python/requirements/py3.8-ci-requirements.txt
+++ b/sdk/python/requirements/py3.8-ci-requirements.txt
@@ -4,136 +4,111 @@
#
# pip-compile --extra=ci --output-file=sdk/python/requirements/py3.8-ci-requirements.txt
#
-adal==1.2.7
- # via msrestazure
-adlfs==0.5.9
- # via feast (setup.py)
-aiohttp==3.8.4
- # via
- # adlfs
- # gcsfs
-aiosignal==1.3.1
- # via aiohttp
+
alabaster==0.7.13
# via sphinx
-altair==4.2.0
+altair==4.2.2
# via great-expectations
-anyio==3.7.0
+annotated-types==0.6.0
+ # via pydantic
+anyio==4.2.0
# via
- # httpcore
+ # httpx
# jupyter-server
# starlette
# watchfiles
appdirs==1.4.4
# via fissix
-appnope==0.1.3
- # via
- # ipykernel
- # ipython
-argon2-cffi==21.3.0
- # via
- # jupyter-server
- # nbclassic
- # notebook
+argon2-cffi==23.1.0
+ # via jupyter-server
argon2-cffi-bindings==21.2.0
# via argon2-cffi
-arrow==1.2.3
+arrow==1.3.0
# via isoduration
asn1crypto==1.5.1
- # via
- # oscrypto
- # snowflake-connector-python
+ # via snowflake-connector-python
assertpy==1.1
# via feast (setup.py)
-asttokens==2.2.1
+asttokens==2.4.1
# via stack-data
-async-timeout==4.0.2
- # via
- # aiohttp
- # redis
-attrs==23.1.0
+async-lru==2.0.4
+ # via jupyterlab
+async-timeout==4.0.3
+ # via redis
+attrs==23.2.0
# via
- # aiohttp
# bowler
# jsonschema
+ # referencing
avro==1.10.0
# via feast (setup.py)
-azure-core==1.27.0
+azure-core==1.30.0
# via
- # adlfs
# azure-identity
# azure-storage-blob
- # msrest
-azure-datalake-store==0.0.53
- # via adlfs
-azure-identity==1.13.0
- # via
- # adlfs
- # feast (setup.py)
-azure-storage-blob==12.16.0
+azure-identity==1.15.0
+ # via feast (setup.py)
+azure-storage-blob==12.19.0
+ # via feast (setup.py)
+babel==2.14.0
# via
- # adlfs
- # feast (setup.py)
-babel==2.12.1
- # via sphinx
+ # jupyterlab-server
+ # sphinx
backcall==0.2.0
# via ipython
backports-zoneinfo==0.2.1
# via
# trino
# tzlocal
-beautifulsoup4==4.12.2
+beautifulsoup4==4.12.3
# via nbconvert
black==22.12.0
# via feast (setup.py)
-bleach==6.0.0
+bleach==6.1.0
# via nbconvert
-boto3==1.26.146
+boto3==1.34.42
# via
# feast (setup.py)
# moto
-botocore==1.29.146
+botocore==1.34.42
# via
# boto3
# moto
# s3transfer
bowler==0.9.0
# via feast (setup.py)
-build==0.10.0
+build==1.0.3
# via
# feast (setup.py)
# pip-tools
bytewax==0.15.1
# via feast (setup.py)
-cachecontrol==0.13.0
+cachecontrol==0.14.0
# via firebase-admin
-cachetools==5.3.1
+cachetools==5.3.2
# via google-auth
-cassandra-driver==3.27.0
+cassandra-driver==3.29.0
# via feast (setup.py)
-certifi==2023.5.7
+certifi==2024.2.2
# via
# httpcore
# httpx
# kubernetes
# minio
- # msrest
# requests
# snowflake-connector-python
-cffi==1.15.1
+cffi==1.16.0
# via
# argon2-cffi-bindings
- # azure-datalake-store
# cryptography
# snowflake-connector-python
-cfgv==3.3.1
+cfgv==3.4.0
# via pre-commit
-charset-normalizer==3.1.0
+charset-normalizer==3.3.2
# via
- # aiohttp
# requests
# snowflake-connector-python
-click==8.1.3
+click==8.1.7
# via
# black
# bowler
@@ -144,22 +119,22 @@ click==8.1.3
# moreorless
# pip-tools
# uvicorn
-cloudpickle==2.2.1
+cloudpickle==3.0.0
# via dask
colorama==0.4.6
# via
# feast (setup.py)
# great-expectations
-comm==0.1.3
- # via ipykernel
-coverage[toml]==7.2.7
+comm==0.2.1
+ # via
+ # ipykernel
+ # ipywidgets
+coverage[toml]==7.4.1
# via pytest-cov
-cryptography==40.0.2
+cryptography==41.0.7
# via
- # adal
# azure-identity
# azure-storage-blob
- # cassandra-driver
# feast (setup.py)
# great-expectations
# moto
@@ -171,28 +146,24 @@ cryptography==40.0.2
# types-redis
dask==2023.5.0
# via feast (setup.py)
-db-dtypes==1.1.1
+db-dtypes==1.2.0
# via google-cloud-bigquery
-debugpy==1.6.7
+debugpy==1.8.1
# via ipykernel
decorator==5.1.1
- # via
- # gcsfs
- # ipython
+ # via ipython
defusedxml==0.7.1
# via nbconvert
-deprecated==1.2.14
- # via redis
deprecation==2.1.0
# via testcontainers
-dill==0.3.6
+dill==0.3.8
# via
# bytewax
# feast (setup.py)
# multiprocess
-distlib==0.3.6
+distlib==0.3.8
# via virtualenv
-docker==6.1.3
+docker==7.0.0
# via
# feast (setup.py)
# testcontainers
@@ -200,23 +171,23 @@ docutils==0.19
# via sphinx
entrypoints==0.4
# via altair
-exceptiongroup==1.1.1
+exceptiongroup==1.2.0
# via
# anyio
# pytest
-execnet==1.9.0
+execnet==2.0.2
# via pytest-xdist
-executing==1.2.0
+executing==2.0.1
# via stack-data
-fastapi==0.95.2
+fastapi==0.109.2
# via feast (setup.py)
-fastavro==1.7.4
+fastavro==1.9.4
# via
# feast (setup.py)
# pandavro
-fastjsonschema==2.17.1
+fastjsonschema==2.19.1
# via nbformat
-filelock==3.12.0
+filelock==3.13.1
# via
# snowflake-connector-python
# virtualenv
@@ -228,22 +199,15 @@ flake8==6.0.0
# via feast (setup.py)
fqdn==1.5.1
# via jsonschema
-frozenlist==1.3.3
- # via
- # aiohttp
- # aiosignal
-fsspec==2022.1.0
+fsspec==2023.12.2
# via
- # adlfs
# dask
- # gcsfs
-gcsfs==2022.1.0
- # via feast (setup.py)
+ # feast (setup.py)
geojson==2.5.0
# via rockset
geomet==0.2.1.post1
# via cassandra-driver
-google-api-core[grpc]==2.11.0
+google-api-core[grpc]==2.17.1
# via
# feast (setup.py)
# firebase-admin
@@ -255,82 +219,86 @@ google-api-core[grpc]==2.11.0
# google-cloud-datastore
# google-cloud-firestore
# google-cloud-storage
-google-api-python-client==2.88.0
+google-api-python-client==2.118.0
# via firebase-admin
-google-auth==2.19.1
+google-auth==2.27.0
# via
- # gcsfs
# google-api-core
# google-api-python-client
# google-auth-httplib2
- # google-auth-oauthlib
# google-cloud-core
# google-cloud-storage
# kubernetes
-google-auth-httplib2==0.1.0
+google-auth-httplib2==0.2.0
# via google-api-python-client
-google-auth-oauthlib==1.0.0
- # via gcsfs
-google-cloud-bigquery[pandas]==3.11.0
+google-cloud-bigquery[pandas]==3.12.0
+ # via
+ # feast (setup.py)
+ # google-cloud-bigquery
+google-cloud-bigquery-storage==2.24.0
# via feast (setup.py)
-google-cloud-bigquery-storage==2.20.0
+google-cloud-bigquery-storage==2.24.0
# via feast (setup.py)
-google-cloud-bigtable==2.18.1
+google-cloud-bigtable==2.23.0
# via feast (setup.py)
-google-cloud-core==2.3.2
+google-cloud-core==2.4.1
# via
# google-cloud-bigquery
# google-cloud-bigtable
# google-cloud-datastore
# google-cloud-firestore
# google-cloud-storage
-google-cloud-datastore==2.15.2
+google-cloud-datastore==2.19.0
# via feast (setup.py)
-google-cloud-firestore==2.11.1
+google-cloud-firestore==2.14.0
# via firebase-admin
-google-cloud-storage==2.9.0
+google-cloud-storage==2.14.0
# via
# feast (setup.py)
# firebase-admin
- # gcsfs
google-crc32c==1.5.0
- # via google-resumable-media
-google-resumable-media==2.5.0
+ # via
+ # google-cloud-storage
+ # google-resumable-media
+google-resumable-media==2.7.0
# via
# google-cloud-bigquery
# google-cloud-storage
-googleapis-common-protos[grpc]==1.59.0
+googleapis-common-protos[grpc]==1.62.0
# via
# feast (setup.py)
# google-api-core
# grpc-google-iam-v1
# grpcio-status
-great-expectations==0.15.50
+great-expectations==0.18.8
# via feast (setup.py)
-greenlet==2.0.2
+greenlet==3.0.3
# via sqlalchemy
-grpc-google-iam-v1==0.12.6
+grpc-google-iam-v1==0.13.0
# via google-cloud-bigtable
-grpcio==1.54.2
+grpcio==1.60.1
# via
# feast (setup.py)
# google-api-core
# google-cloud-bigquery
# googleapis-common-protos
# grpc-google-iam-v1
+ # grpcio-health-checking
# grpcio-reflection
# grpcio-status
# grpcio-testing
# grpcio-tools
-grpcio-reflection==1.54.2
+grpcio-health-checking==1.60.1
+ # via feast (setup.py)
+grpcio-reflection==1.60.1
# via feast (setup.py)
-grpcio-status==1.54.2
+grpcio-status==1.60.1
# via google-api-core
-grpcio-testing==1.54.2
+grpcio-testing==1.60.1
# via feast (setup.py)
-grpcio-tools==1.54.2
+grpcio-tools==1.60.1
# via feast (setup.py)
-gunicorn==20.1.0
+gunicorn==21.2.0
# via feast (setup.py)
h11==0.14.0
# via
@@ -338,138 +306,151 @@ h11==0.14.0
# uvicorn
happybase==1.2.0
# via feast (setup.py)
-hazelcast-python-client==5.2.0
+hazelcast-python-client==5.3.0
# via feast (setup.py)
-hiredis==2.2.3
+hiredis==2.3.2
# via feast (setup.py)
-httpcore==0.17.2
+httpcore==1.0.3
# via httpx
httplib2==0.22.0
# via
# google-api-python-client
# google-auth-httplib2
-httptools==0.5.0
+httptools==0.6.1
# via uvicorn
-httpx==0.24.1
- # via feast (setup.py)
-identify==2.5.24
+httpx==0.26.0
+ # via
+ # feast (setup.py)
+ # jupyterlab
+identify==2.5.34
# via pre-commit
-idna==3.4
+idna==3.6
# via
# anyio
# httpx
# jsonschema
# requests
# snowflake-connector-python
- # yarl
imagesize==1.4.1
# via sphinx
-importlib-metadata==6.6.0
+importlib-metadata==6.11.0
# via
+ # build
# dask
- # great-expectations
+ # feast (setup.py)
# jupyter-client
+ # jupyter-lsp
+ # jupyterlab
+ # jupyterlab-server
# nbconvert
# sphinx
-importlib-resources==5.12.0
- # via jsonschema
+importlib-resources==6.1.1
+ # via
+ # feast (setup.py)
+ # jsonschema
+ # jsonschema-specifications
+ # jupyterlab
iniconfig==2.0.0
# via pytest
-ipykernel==6.23.1
- # via
- # ipywidgets
- # nbclassic
- # notebook
-ipython==8.12.2
+ipykernel==6.29.2
+ # via jupyterlab
+ipython==8.12.3
# via
# great-expectations
# ipykernel
# ipywidgets
-ipython-genutils==0.2.0
- # via
- # nbclassic
- # notebook
-ipywidgets==8.0.6
+ipywidgets==8.1.2
# via great-expectations
isodate==0.6.1
- # via
- # azure-storage-blob
- # msrest
+ # via azure-storage-blob
isoduration==20.11.0
# via jsonschema
-isort==5.12.0
+isort==5.13.2
# via feast (setup.py)
-jedi==0.18.2
+jedi==0.19.1
# via ipython
-jinja2==3.1.2
+jinja2==3.1.3
# via
# altair
# feast (setup.py)
# great-expectations
# jupyter-server
+ # jupyterlab
+ # jupyterlab-server
# moto
- # nbclassic
# nbconvert
- # notebook
# sphinx
jmespath==1.0.1
# via
# boto3
# botocore
-jsonpatch==1.32
+json5==0.9.14
+ # via jupyterlab-server
+jsonpatch==1.33
# via great-expectations
-jsonpointer==2.3
+jsonpointer==2.4
# via
# jsonpatch
# jsonschema
-jsonschema[format-nongpl]==4.17.3
+jsonschema[format-nongpl]==4.21.1
# via
# altair
# feast (setup.py)
# great-expectations
# jupyter-events
+ # jupyterlab-server
# nbformat
-jupyter-client==8.2.0
+jsonschema-specifications==2023.12.1
+ # via jsonschema
+jupyter-client==8.6.0
# via
# ipykernel
# jupyter-server
- # nbclassic
# nbclient
- # notebook
-jupyter-core==5.3.0
+jupyter-core==5.7.1
# via
# ipykernel
# jupyter-client
# jupyter-server
- # nbclassic
+ # jupyterlab
# nbclient
# nbconvert
# nbformat
- # notebook
-jupyter-events==0.6.3
+jupyter-events==0.9.0
# via jupyter-server
-jupyter-server==2.6.0
+jupyter-lsp==2.2.2
+ # via jupyterlab
+jupyter-server==2.12.5
# via
- # nbclassic
+ # jupyter-lsp
+ # jupyterlab
+ # jupyterlab-server
+ # notebook
# notebook-shim
-jupyter-server-terminals==0.4.4
+jupyter-server-terminals==0.5.2
# via jupyter-server
-jupyterlab-pygments==0.2.2
+jupyterlab==4.1.1
+ # via notebook
+jupyterlab-pygments==0.3.0
# via nbconvert
-jupyterlab-widgets==3.0.7
+jupyterlab-server==2.25.3
+ # via
+ # jupyterlab
+ # notebook
+jupyterlab-widgets==3.0.10
# via ipywidgets
kubernetes==20.13.0
# via feast (setup.py)
locket==1.0.0
# via partd
-makefun==1.15.1
+makefun==1.15.2
# via great-expectations
-markupsafe==2.1.3
+markupsafe==2.1.5
# via
# jinja2
# nbconvert
# werkzeug
-marshmallow==3.19.0
+marshmallow==3.20.2
# via great-expectations
matplotlib-inline==0.1.6
# via
@@ -479,38 +460,29 @@ mccabe==0.7.0
# via flake8
minio==7.1.0
# via feast (setup.py)
-mistune==2.0.5
+mistune==3.0.2
# via
# great-expectations
# nbconvert
-mmh3==4.0.0
+mmh3==4.1.0
# via feast (setup.py)
mock==2.0.0
# via feast (setup.py)
moreorless==0.4.0
# via bowler
-moto==4.1.10
+moto==4.2.14
# via feast (setup.py)
-msal==1.22.0
+msal==1.26.0
# via
- # azure-datalake-store
# azure-identity
# msal-extensions
-msal-extensions==1.0.0
+msal-extensions==1.1.0
# via azure-identity
-msgpack==1.0.5
+msgpack==1.0.7
# via cachecontrol
-msrest==0.7.1
- # via msrestazure
-msrestazure==0.6.4
- # via adlfs
-multidict==6.0.4
- # via
- # aiohttp
- # yarl
-multiprocess==0.70.14
+multiprocess==0.70.16
# via bytewax
-mypy==0.982
+mypy==1.8.0
# via
# feast (setup.py)
# sqlalchemy
@@ -518,39 +490,29 @@ mypy-extensions==1.0.0
# via
# black
# mypy
-mypy-protobuf==3.1
+mypy-protobuf==3.1.0
# via feast (setup.py)
-mysqlclient==2.1.1
- # via feast (setup.py)
-nbclassic==1.0.0
- # via notebook
-nbclient==0.8.0
+nbclient==0.9.0
# via nbconvert
-nbconvert==7.4.0
- # via
- # jupyter-server
- # nbclassic
- # notebook
-nbformat==5.9.0
+nbconvert==7.16.0
+ # via jupyter-server
+nbformat==5.9.2
# via
# great-expectations
# jupyter-server
- # nbclassic
# nbclient
# nbconvert
- # notebook
-nest-asyncio==1.5.6
- # via
- # ipykernel
- # nbclassic
- # notebook
+nest-asyncio==1.6.0
+ # via ipykernel
nodeenv==1.8.0
# via pre-commit
-notebook==6.5.4
+notebook==7.1.0
# via great-expectations
notebook-shim==0.2.3
- # via nbclassic
-numpy==1.24.3
+ # via
+ # jupyterlab
+ # notebook
+numpy==1.24.4
# via
# altair
# db-dtypes
@@ -562,11 +524,9 @@ numpy==1.24.3
# scipy
oauthlib==3.2.2
# via requests-oauthlib
-oscrypto==1.3.0
- # via snowflake-connector-python
-overrides==7.3.1
+overrides==7.7.0
# via jupyter-server
-packaging==23.1
+packaging==23.2
# via
# build
# dask
@@ -575,12 +535,15 @@ packaging==23.1
# docker
# google-cloud-bigquery
# great-expectations
+ # gunicorn
# ipykernel
# jupyter-server
+ # jupyterlab
+ # jupyterlab-server
# marshmallow
+ # msal-extensions
# nbconvert
# pytest
- # redis
# snowflake-connector-python
# sphinx
pandas==1.5.3
@@ -594,45 +557,43 @@ pandas==1.5.3
# snowflake-connector-python
pandavro==1.5.2
# via feast (setup.py)
-pandocfilters==1.5.0
+pandocfilters==1.5.1
# via nbconvert
parso==0.8.3
# via jedi
-partd==1.4.0
+partd==1.4.1
# via dask
-pathspec==0.11.1
+pathspec==0.12.1
# via black
-pbr==5.11.1
+pbr==6.0.0
# via mock
-pexpect==4.8.0
+pexpect==4.9.0
# via ipython
pickleshare==0.7.5
# via ipython
-pip-tools==6.13.0
+pip-tools==7.3.0
# via feast (setup.py)
pkgutil-resolve-name==1.3.10
# via jsonschema
-platformdirs==3.5.1
+platformdirs==3.11.0
# via
# black
# jupyter-core
+ # snowflake-connector-python
# virtualenv
-pluggy==1.0.0
+pluggy==1.4.0
# via pytest
ply==3.11
# via thriftpy2
-portalocker==2.7.0
+portalocker==2.8.2
# via msal-extensions
-pre-commit==3.3.2
+pre-commit==3.3.1
# via feast (setup.py)
-prometheus-client==0.17.0
- # via
- # jupyter-server
- # nbclassic
- # notebook
-prompt-toolkit==3.0.38
+prometheus-client==0.20.0
+ # via jupyter-server
+prompt-toolkit==3.0.43
# via ipython
-proto-plus==1.22.2
+proto-plus==1.23.0
# via
# feast (setup.py)
# google-cloud-bigquery
@@ -640,7 +601,7 @@ proto-plus==1.22.2
# google-cloud-bigtable
# google-cloud-datastore
# google-cloud-firestore
-protobuf==4.23.2
+protobuf==4.23.3
# via
# feast (setup.py)
# google-api-core
@@ -651,6 +612,7 @@ protobuf==4.23.2
# google-cloud-firestore
# googleapis-common-protos
# grpc-google-iam-v1
+ # grpcio-health-checking
# grpcio-reflection
# grpcio-status
# grpcio-testing
@@ -661,7 +623,7 @@ psutil==5.9.0
# via
# feast (setup.py)
# ipykernel
-psycopg2-binary==2.9.6
+psycopg2-binary==2.9.9
# via feast (setup.py)
ptyprocess==0.7.0
# via
@@ -675,13 +637,13 @@ py-cpuinfo==9.0.0
# via pytest-benchmark
py4j==0.10.9.7
# via pyspark
-pyarrow==10.0.1
+pyarrow==15.0.0
# via
# db-dtypes
# feast (setup.py)
# google-cloud-bigquery
# snowflake-connector-python
-pyasn1==0.5.0
+pyasn1==0.5.1
# via
# pyasn1-modules
# rsa
@@ -693,45 +655,42 @@ pycodestyle==2.10.0
# via flake8
pycparser==2.21
# via cffi
-pycryptodomex==3.18.0
- # via snowflake-connector-python
-pydantic==1.10.8
+pydantic==2.6.1
# via
# fastapi
# feast (setup.py)
# great-expectations
+pydantic-core==2.16.2
+ # via pydantic
pyflakes==3.0.1
# via flake8
-pygments==2.15.1
+pygments==2.17.2
# via
# feast (setup.py)
# ipython
# nbconvert
# sphinx
-pyjwt[crypto]==2.7.0
+pyjwt[crypto]==2.8.0
# via
- # adal
# msal
# snowflake-connector-python
-pymssql==2.2.7
+pymssql==2.2.11
# via feast (setup.py)
-pymysql==1.0.3
+pymysql==1.1.0
# via feast (setup.py)
-pyodbc==4.0.39
+pyodbc==5.1.0
# via feast (setup.py)
-pyopenssl==23.2.0
+pyopenssl==23.3.0
# via snowflake-connector-python
-pyparsing==3.0.9
+pyparsing==3.1.1
# via
# great-expectations
# httplib2
pyproject-hooks==1.0.0
# via build
-pyrsistent==0.19.3
- # via jsonschema
-pyspark==3.4.0
+pyspark==3.5.0
# via feast (setup.py)
-pytest==7.3.1
+pytest==7.4.4
# via
# feast (setup.py)
# pytest-benchmark
@@ -753,11 +712,10 @@ pytest-ordering==0.6
# via feast (setup.py)
pytest-timeout==1.4.2
# via feast (setup.py)
-pytest-xdist==3.3.1
+pytest-xdist==3.5.0
# via feast (setup.py)
python-dateutil==2.8.2
# via
- # adal
# arrow
# botocore
# google-cloud-bigquery
@@ -768,18 +726,18 @@ python-dateutil==2.8.2
# pandas
# rockset
# trino
-python-dotenv==1.0.0
+python-dotenv==1.0.1
# via uvicorn
python-json-logger==2.0.7
# via jupyter-events
-pytz==2023.3
+pytz==2024.1
# via
# babel
# great-expectations
# pandas
# snowflake-connector-python
# trino
-pyyaml==6.0
+pyyaml==6.0.1
# via
# dask
# feast (setup.py)
@@ -788,46 +746,42 @@ pyyaml==6.0
# pre-commit
# responses
# uvicorn
-pyzmq==25.1.0
+pyzmq==25.1.2
# via
# ipykernel
# jupyter-client
# jupyter-server
- # nbclassic
- # notebook
-redis==4.2.2
+redis==4.6.0
# via feast (setup.py)
-regex==2023.5.5
+referencing==0.33.0
+ # via
+ # jsonschema
+ # jsonschema-specifications
+ # jupyter-events
+regex==2023.12.25
# via feast (setup.py)
requests==2.31.0
# via
- # adal
- # adlfs
# azure-core
- # azure-datalake-store
# cachecontrol
# docker
# feast (setup.py)
- # gcsfs
# google-api-core
# google-cloud-bigquery
# google-cloud-storage
# great-expectations
+ # jupyterlab-server
# kubernetes
# moto
# msal
- # msrest
# requests-oauthlib
# responses
# snowflake-connector-python
# sphinx
# trino
requests-oauthlib==1.3.1
- # via
- # google-auth-oauthlib
- # kubernetes
- # msrest
-responses==0.23.1
+ # via kubernetes
+responses==0.25.0
# via moto
rfc3339-validator==0.1.4
# via
@@ -837,38 +791,34 @@ rfc3986-validator==0.1.1
# via
# jsonschema
# jupyter-events
-rockset==2.0.0
+rockset==2.1.0
# via feast (setup.py)
+rpds-py==0.18.0
+ # via
+ # jsonschema
+ # referencing
rsa==4.9
# via google-auth
ruamel-yaml==0.17.17
# via great-expectations
-ruamel-yaml-clib==0.2.7
+ruamel-yaml-clib==0.2.8
# via ruamel-yaml
-s3transfer==0.6.1
+s3transfer==0.10.0
# via boto3
scipy==1.10.1
# via great-expectations
send2trash==1.8.2
- # via
- # jupyter-server
- # nbclassic
- # notebook
+ # via jupyter-server
six==1.16.0
# via
# asttokens
# azure-core
- # azure-identity
# bleach
- # cassandra-driver
# geomet
- # google-auth
- # google-auth-httplib2
# happybase
# isodate
# kubernetes
# mock
- # msrestazure
# pandavro
# python-dateutil
# rfc3339-validator
@@ -876,15 +826,14 @@ six==1.16.0
sniffio==1.3.0
# via
# anyio
- # httpcore
# httpx
snowballstemmer==2.2.0
# via sphinx
-snowflake-connector-python[pandas]==3.0.4
+snowflake-connector-python[pandas]==3.7.0
# via feast (setup.py)
sortedcontainers==2.4.0
# via snowflake-connector-python
-soupsieve==2.4.1
+soupsieve==2.5
# via beautifulsoup4
sphinx==6.2.1
# via feast (setup.py)
@@ -900,27 +849,25 @@ sphinxcontrib-qthelp==1.0.3
# via sphinx
sphinxcontrib-serializinghtml==1.1.5
# via sphinx
-sqlalchemy[mypy]==1.4.48
+sqlalchemy[mypy]==1.4.51
# via feast (setup.py)
-sqlalchemy2-stubs==0.0.2a34
+sqlalchemy2-stubs==0.0.2a38
# via sqlalchemy
-stack-data==0.6.2
+stack-data==0.6.3
# via ipython
-starlette==0.27.0
+starlette==0.36.3
# via fastapi
tabulate==0.9.0
# via feast (setup.py)
-tenacity==8.2.2
+tenacity==8.2.3
# via feast (setup.py)
-terminado==0.17.1
+terminado==0.18.0
# via
# jupyter-server
# jupyter-server-terminals
- # nbclassic
- # notebook
testcontainers==3.7.1
# via feast (setup.py)
-thriftpy2==0.4.16
+thriftpy2==0.4.17
# via happybase
tinycss2==1.2.1
# via nbconvert
@@ -931,27 +878,31 @@ tomli==2.0.1
# black
# build
# coverage
+ # jupyterlab
# mypy
+ # pip-tools
# pyproject-hooks
# pytest
-toolz==0.12.0
+tomlkit==0.12.3
+ # via snowflake-connector-python
+toolz==0.12.1
# via
# altair
# dask
# partd
-tornado==6.3.2
+tornado==6.4
# via
# ipykernel
# jupyter-client
# jupyter-server
- # nbclassic
+ # jupyterlab
# notebook
# terminado
-tqdm==4.65.0
+tqdm==4.66.2
# via
# feast (setup.py)
# great-expectations
-traitlets==5.9.0
+traitlets==5.14.1
# via
# comm
# ipykernel
@@ -961,68 +912,71 @@ traitlets==5.9.0
# jupyter-core
# jupyter-events
# jupyter-server
+ # jupyterlab
# matplotlib-inline
- # nbclassic
# nbclient
# nbconvert
# nbformat
- # notebook
-trino==0.326.0
+trino==0.327.0
# via feast (setup.py)
-typeguard==2.13.3
+typeguard==4.1.5
# via feast (setup.py)
types-protobuf==3.19.22
# via
# feast (setup.py)
# mypy-protobuf
-types-pymysql==1.0.19.7
+types-pymysql==1.1.0.1
# via feast (setup.py)
-types-pyopenssl==23.2.0.0
+types-pyopenssl==24.0.0.20240130
# via types-redis
-types-python-dateutil==2.8.19.13
- # via feast (setup.py)
-types-pytz==2023.3.0.0
- # via feast (setup.py)
-types-pyyaml==6.0.12.10
+types-python-dateutil==2.8.19.20240106
# via
+ # arrow
# feast (setup.py)
- # responses
-types-redis==4.5.5.2
+types-pytz==2024.1.0.20240203
+ # via feast (setup.py)
+types-pyyaml==6.0.12.12
+ # via feast (setup.py)
+types-redis==4.6.0.20240106
# via feast (setup.py)
-types-requests==2.31.0.1
+types-requests==2.30.0.0
# via feast (setup.py)
-types-setuptools==67.8.0.0
+types-setuptools==69.0.0.20240125
# via feast (setup.py)
-types-tabulate==0.9.0.2
+types-tabulate==0.9.0.20240106
# via feast (setup.py)
-types-urllib3==1.26.25.13
+types-urllib3==1.26.25.14
# via types-requests
-typing-extensions==4.6.3
+typing-extensions==4.9.0
# via
+ # anyio
+ # async-lru
# azure-core
# azure-storage-blob
# black
+ # fastapi
# great-expectations
# ipython
# mypy
# pydantic
+ # pydantic-core
# snowflake-connector-python
# sqlalchemy2-stubs
# starlette
-tzlocal==5.0.1
+ # uvicorn
+tzlocal==5.2
# via
# great-expectations
# trino
-uri-template==1.2.0
+uri-template==1.3.0
# via jsonschema
uritemplate==4.1.1
# via google-api-python-client
-urllib3==1.26.16
+urllib3==1.26.18
# via
# botocore
# docker
# feast (setup.py)
- # google-auth
# great-expectations
# kubernetes
# minio
@@ -1030,17 +984,19 @@ urllib3==1.26.16
# responses
# rockset
# snowflake-connector-python
-uvicorn[standard]==0.22.0
+uvicorn[standard]==0.27.1
# via feast (setup.py)
-uvloop==0.17.0
+uvloop==0.19.0
# via uvicorn
virtualenv==20.23.0
- # via pre-commit
+ # via
+ # feast (setup.py)
+ # pre-commit
volatile==2.1.0
# via bowler
-watchfiles==0.19.0
+watchfiles==0.21.0
# via uvicorn
-wcwidth==0.2.6
+wcwidth==0.2.13
# via prompt-toolkit
webcolors==1.13
# via jsonschema
@@ -1048,28 +1004,23 @@ webencodings==0.5.1
# via
# bleach
# tinycss2
-websocket-client==1.5.2
+websocket-client==1.7.0
# via
- # docker
# jupyter-server
# kubernetes
-websockets==11.0.3
+websockets==12.0
# via uvicorn
-werkzeug==2.3.4
+werkzeug==3.0.1
# via moto
-wheel==0.40.0
+wheel==0.42.0
# via pip-tools
-widgetsnbextension==4.0.7
+widgetsnbextension==4.0.10
# via ipywidgets
-wrapt==1.15.0
- # via
- # deprecated
- # testcontainers
+wrapt==1.16.0
+ # via testcontainers
xmltodict==0.13.0
# via moto
-yarl==1.9.2
- # via aiohttp
-zipp==3.15.0
+zipp==3.17.0
# via
# importlib-metadata
# importlib-resources
diff --git a/sdk/python/requirements/py3.8-requirements.txt b/sdk/python/requirements/py3.8-requirements.txt
index b374356b24d..079064a9ecc 100644
--- a/sdk/python/requirements/py3.8-requirements.txt
+++ b/sdk/python/requirements/py3.8-requirements.txt
@@ -4,146 +4,177 @@
#
# pip-compile --output-file=sdk/python/requirements/py3.8-requirements.txt
#
-anyio==3.7.0
+annotated-types==0.6.0
+ # via pydantic
+anyio==4.2.0
# via
- # httpcore
+ # httpx
# starlette
# watchfiles
appdirs==1.4.4
# via fissix
-attrs==23.1.0
+attrs==23.2.0
# via
# bowler
# jsonschema
+ # referencing
bowler==0.9.0
# via feast (setup.py)
-certifi==2023.5.7
+certifi==2024.2.2
# via
# httpcore
# httpx
# requests
-charset-normalizer==3.1.0
+charset-normalizer==3.3.2
# via requests
-click==8.1.3
+click==8.1.7
# via
# bowler
# dask
# feast (setup.py)
# moreorless
# uvicorn
-cloudpickle==2.2.1
+cloudpickle==3.0.0
# via dask
colorama==0.4.6
# via feast (setup.py)
dask==2023.5.0
# via feast (setup.py)
-dill==0.3.6
+dill==0.3.8
# via feast (setup.py)
-exceptiongroup==1.1.1
+exceptiongroup==1.2.0
# via anyio
-fastapi==0.95.2
+fastapi==0.109.2
# via feast (setup.py)
-fastavro==1.7.4
+fastavro==1.9.4
# via
# feast (setup.py)
# pandavro
fissix==21.11.13
# via bowler
-fsspec==2023.5.0
+fsspec==2024.2.0
# via dask
-greenlet==2.0.2
+greenlet==3.0.3
# via sqlalchemy
-grpcio==1.54.2
+grpcio==1.60.1
# via
# feast (setup.py)
+ # grpcio-health-checking
# grpcio-reflection
-grpcio-reflection==1.54.2
+ # grpcio-tools
+grpcio-health-checking==1.60.1
+ # via feast (setup.py)
+grpcio-reflection==1.60.1
+ # via feast (setup.py)
+grpcio-tools==1.60.1
# via feast (setup.py)
-gunicorn==20.1.0
+gunicorn==21.2.0
# via feast (setup.py)
h11==0.14.0
# via
# httpcore
# uvicorn
-httpcore==0.17.2
+httpcore==1.0.3
# via httpx
-httptools==0.5.0
+httptools==0.6.1
# via uvicorn
-httpx==0.24.1
+httpx==0.26.0
# via feast (setup.py)
-idna==3.4
+idna==3.6
# via
# anyio
# httpx
# requests
-importlib-metadata==6.6.0
- # via dask
-importlib-resources==5.12.0
- # via jsonschema
-jinja2==3.1.2
+importlib-metadata==6.11.0
+ # via
+ # dask
+ # feast (setup.py)
+importlib-resources==6.1.1
+ # via
+ # feast (setup.py)
+ # jsonschema
+ # jsonschema-specifications
+jinja2==3.1.3
# via feast (setup.py)
-jsonschema==4.17.3
+jsonschema==4.21.1
# via feast (setup.py)
+jsonschema-specifications==2023.12.1
+ # via jsonschema
locket==1.0.0
# via partd
-markupsafe==2.1.3
+markupsafe==2.1.5
# via jinja2
-mmh3==4.0.0
+mmh3==4.1.0
# via feast (setup.py)
moreorless==0.4.0
# via bowler
-mypy==1.3.0
+mypy==1.8.0
# via sqlalchemy
mypy-extensions==1.0.0
# via mypy
-numpy==1.24.3
+mypy-protobuf==3.1.0
+ # via feast (setup.py)
+numpy==1.24.4
# via
# feast (setup.py)
# pandas
# pandavro
# pyarrow
-packaging==23.1
- # via dask
+packaging==23.2
+ # via
+ # dask
+ # gunicorn
pandas==1.5.3
# via
# feast (setup.py)
# pandavro
pandavro==1.5.2
# via feast (setup.py)
-partd==1.4.0
+partd==1.4.1
# via dask
pkgutil-resolve-name==1.3.10
# via jsonschema
-proto-plus==1.22.2
+proto-plus==1.23.0
# via feast (setup.py)
-protobuf==4.23.2
+protobuf==4.23.3
# via
# feast (setup.py)
+ # grpcio-health-checking
# grpcio-reflection
+ # grpcio-tools
+ # mypy-protobuf
# proto-plus
-pyarrow==11.0.0
+pyarrow==15.0.0
# via feast (setup.py)
-pydantic==1.10.8
+pydantic==2.6.1
# via
# fastapi
# feast (setup.py)
-pygments==2.15.1
+pydantic-core==2.16.2
+ # via pydantic
+pygments==2.17.2
# via feast (setup.py)
-pyrsistent==0.19.3
- # via jsonschema
python-dateutil==2.8.2
# via pandas
-python-dotenv==1.0.0
+python-dotenv==1.0.1
# via uvicorn
-pytz==2023.3
+pytz==2024.1
# via pandas
-pyyaml==6.0
+pyyaml==6.0.1
# via
# dask
# feast (setup.py)
# uvicorn
+referencing==0.33.0
+ # via
+ # jsonschema
+ # jsonschema-specifications
requests==2.31.0
# via feast (setup.py)
+rpds-py==0.18.0
+ # via
+ # jsonschema
+ # referencing
six==1.16.0
# via
# pandavro
@@ -151,49 +182,59 @@ six==1.16.0
sniffio==1.3.0
# via
# anyio
- # httpcore
# httpx
-sqlalchemy[mypy]==1.4.48
+sqlalchemy[mypy]==1.4.51
# via feast (setup.py)
-sqlalchemy2-stubs==0.0.2a34
+sqlalchemy2-stubs==0.0.2a38
# via sqlalchemy
-starlette==0.27.0
+starlette==0.36.3
# via fastapi
tabulate==0.9.0
# via feast (setup.py)
-tenacity==8.2.2
+tenacity==8.2.3
# via feast (setup.py)
toml==0.10.2
# via feast (setup.py)
tomli==2.0.1
# via mypy
-toolz==0.12.0
+toolz==0.12.1
# via
# dask
# partd
-tqdm==4.65.0
+tqdm==4.66.2
# via feast (setup.py)
-typeguard==2.13.3
+typeguard==4.1.5
# via feast (setup.py)
-typing-extensions==4.6.3
+types-protobuf==4.24.0.20240129
+ # via mypy-protobuf
+typing-extensions==4.9.0
# via
+ # anyio
+ # fastapi
# mypy
# pydantic
+ # pydantic-core
# sqlalchemy2-stubs
# starlette
-urllib3==2.0.2
+ # uvicorn
+urllib3==2.2.0
# via requests
-uvicorn[standard]==0.22.0
- # via feast (setup.py)
-uvloop==0.17.0
+uvicorn[standard]==0.27.1
+ # via
+ # feast (setup.py)
+ # uvicorn
+uvloop==0.19.0
# via uvicorn
volatile==2.1.0
# via bowler
-watchfiles==0.19.0
+watchfiles==0.21.0
# via uvicorn
-websockets==11.0.3
+websockets==12.0
# via uvicorn
-zipp==3.15.0
+zipp==3.17.0
# via
# importlib-metadata
# importlib-resources
+
+# The following packages are considered to be unsafe in a requirements file:
+# setuptools
diff --git a/sdk/python/requirements/py3.9-ci-requirements.txt b/sdk/python/requirements/py3.9-ci-requirements.txt
index 55a283fb245..6c26f889e27 100644
--- a/sdk/python/requirements/py3.9-ci-requirements.txt
+++ b/sdk/python/requirements/py3.9-ci-requirements.txt
@@ -1,135 +1,107 @@
#
-# This file is autogenerated by pip-compile with python 3.9
-# To update, run:
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
#
# pip-compile --extra=ci --output-file=sdk/python/requirements/py3.9-ci-requirements.txt
#
-adal==1.2.7
- # via msrestazure
-adlfs==0.5.9
- # via feast (setup.py)
-aiohttp==3.8.4
- # via
- # adlfs
- # gcsfs
-aiosignal==1.3.1
- # via aiohttp
-alabaster==0.7.13
+alabaster==0.7.16
# via sphinx
-altair==4.2.0
+altair==4.2.2
# via great-expectations
-anyio==3.7.0
+annotated-types==0.6.0
+ # via pydantic
+anyio==4.2.0
# via
- # httpcore
+ # httpx
# jupyter-server
# starlette
# watchfiles
appdirs==1.4.4
# via fissix
-appnope==0.1.3
- # via
- # ipykernel
- # ipython
-argon2-cffi==21.3.0
- # via
- # jupyter-server
- # nbclassic
- # notebook
+argon2-cffi==23.1.0
+ # via jupyter-server
argon2-cffi-bindings==21.2.0
# via argon2-cffi
-arrow==1.2.3
+arrow==1.3.0
# via isoduration
asn1crypto==1.5.1
- # via
- # oscrypto
- # snowflake-connector-python
+ # via snowflake-connector-python
assertpy==1.1
# via feast (setup.py)
-asttokens==2.2.1
+asttokens==2.4.1
# via stack-data
-async-timeout==4.0.2
- # via
- # aiohttp
- # redis
-attrs==23.1.0
+async-lru==2.0.4
+ # via jupyterlab
+async-timeout==4.0.3
+ # via redis
+attrs==23.2.0
# via
- # aiohttp
# bowler
# jsonschema
+ # referencing
avro==1.10.0
# via feast (setup.py)
-azure-core==1.27.0
+azure-core==1.30.0
# via
- # adlfs
# azure-identity
# azure-storage-blob
- # msrest
-azure-datalake-store==0.0.53
- # via adlfs
-azure-identity==1.13.0
- # via
- # adlfs
- # feast (setup.py)
-azure-storage-blob==12.16.0
+azure-identity==1.15.0
+ # via feast (setup.py)
+azure-storage-blob==12.19.0
+ # via feast (setup.py)
+babel==2.14.0
# via
- # adlfs
- # feast (setup.py)
-babel==2.12.1
- # via sphinx
-backcall==0.2.0
- # via ipython
-beautifulsoup4==4.12.2
+ # jupyterlab-server
+ # sphinx
+beautifulsoup4==4.12.3
# via nbconvert
black==22.12.0
# via feast (setup.py)
-bleach==6.0.0
+bleach==6.1.0
# via nbconvert
-boto3==1.26.146
+boto3==1.34.42
# via
# feast (setup.py)
# moto
-botocore==1.29.146
+botocore==1.34.42
# via
# boto3
# moto
# s3transfer
bowler==0.9.0
# via feast (setup.py)
-build==0.10.0
+build==1.0.3
# via
# feast (setup.py)
# pip-tools
bytewax==0.15.1
# via feast (setup.py)
-cachecontrol==0.13.0
+cachecontrol==0.14.0
# via firebase-admin
-cachetools==5.3.1
+cachetools==5.3.2
# via google-auth
-cassandra-driver==3.27.0
+cassandra-driver==3.29.0
# via feast (setup.py)
-certifi==2023.5.7
+certifi==2024.2.2
# via
# httpcore
# httpx
# kubernetes
# minio
- # msrest
# requests
# snowflake-connector-python
-cffi==1.15.1
+cffi==1.16.0
# via
# argon2-cffi-bindings
- # azure-datalake-store
# cryptography
# snowflake-connector-python
-cfgv==3.3.1
+cfgv==3.4.0
# via pre-commit
-charset-normalizer==3.1.0
+charset-normalizer==3.3.2
# via
- # aiohttp
# requests
# snowflake-connector-python
-click==8.1.3
+click==8.1.7
# via
# black
# bowler
@@ -140,22 +112,22 @@ click==8.1.3
# moreorless
# pip-tools
# uvicorn
-cloudpickle==2.2.1
+cloudpickle==3.0.0
# via dask
colorama==0.4.6
# via
# feast (setup.py)
# great-expectations
-comm==0.1.3
- # via ipykernel
-coverage[toml]==7.2.7
+comm==0.2.1
+ # via
+ # ipykernel
+ # ipywidgets
+coverage[toml]==7.4.1
# via pytest-cov
-cryptography==40.0.2
+cryptography==41.0.7
# via
- # adal
# azure-identity
# azure-storage-blob
- # cassandra-driver
# feast (setup.py)
# great-expectations
# moto
@@ -165,30 +137,26 @@ cryptography==40.0.2
# snowflake-connector-python
# types-pyopenssl
# types-redis
-dask==2023.5.1
+dask==2024.2.0
# via feast (setup.py)
-db-dtypes==1.1.1
+db-dtypes==1.2.0
# via google-cloud-bigquery
-debugpy==1.6.7
+debugpy==1.8.1
# via ipykernel
decorator==5.1.1
- # via
- # gcsfs
- # ipython
+ # via ipython
defusedxml==0.7.1
# via nbconvert
-deprecated==1.2.14
- # via redis
deprecation==2.1.0
# via testcontainers
-dill==0.3.6
+dill==0.3.8
# via
# bytewax
# feast (setup.py)
# multiprocess
-distlib==0.3.6
+distlib==0.3.8
# via virtualenv
-docker==6.1.3
+docker==7.0.0
# via
# feast (setup.py)
# testcontainers
@@ -196,23 +164,24 @@ docutils==0.19
# via sphinx
entrypoints==0.4
# via altair
-exceptiongroup==1.1.1
+exceptiongroup==1.2.0
# via
# anyio
+ # ipython
# pytest
-execnet==1.9.0
+execnet==2.0.2
# via pytest-xdist
-executing==1.2.0
+executing==2.0.1
# via stack-data
-fastapi==0.95.2
+fastapi==0.109.2
# via feast (setup.py)
-fastavro==1.7.4
+fastavro==1.9.4
# via
# feast (setup.py)
# pandavro
-fastjsonschema==2.17.1
+fastjsonschema==2.19.1
# via nbformat
-filelock==3.12.0
+filelock==3.13.1
# via
# snowflake-connector-python
# virtualenv
@@ -224,22 +193,15 @@ flake8==6.0.0
# via feast (setup.py)
fqdn==1.5.1
# via jsonschema
-frozenlist==1.3.3
+fsspec==2023.12.2
# via
- # aiohttp
- # aiosignal
-fsspec==2022.1.0
- # via
- # adlfs
# dask
- # gcsfs
-gcsfs==2022.1.0
- # via feast (setup.py)
+ # feast (setup.py)
geojson==2.5.0
# via rockset
geomet==0.2.1.post1
# via cassandra-driver
-google-api-core[grpc]==2.11.0
+google-api-core[grpc]==2.17.1
# via
# feast (setup.py)
# firebase-admin
@@ -251,82 +213,86 @@ google-api-core[grpc]==2.11.0
# google-cloud-datastore
# google-cloud-firestore
# google-cloud-storage
-google-api-python-client==2.88.0
+google-api-python-client==2.118.0
# via firebase-admin
-google-auth==2.19.1
+google-auth==2.27.0
# via
- # gcsfs
# google-api-core
# google-api-python-client
# google-auth-httplib2
- # google-auth-oauthlib
# google-cloud-core
# google-cloud-storage
# kubernetes
-google-auth-httplib2==0.1.0
+google-auth-httplib2==0.2.0
# via google-api-python-client
-google-auth-oauthlib==1.0.0
- # via gcsfs
-google-cloud-bigquery[pandas]==3.11.0
+google-cloud-bigquery[pandas]==3.12.0
+ # via
+ # feast (setup.py)
+ # google-cloud-bigquery
+google-cloud-bigquery-storage==2.24.0
# via feast (setup.py)
-google-cloud-bigquery-storage==2.20.0
+google-cloud-bigquery-storage==2.24.0
# via feast (setup.py)
-google-cloud-bigtable==2.18.1
+google-cloud-bigtable==2.23.0
# via feast (setup.py)
-google-cloud-core==2.3.2
+google-cloud-core==2.4.1
# via
# google-cloud-bigquery
# google-cloud-bigtable
# google-cloud-datastore
# google-cloud-firestore
# google-cloud-storage
-google-cloud-datastore==2.15.2
+google-cloud-datastore==2.19.0
# via feast (setup.py)
-google-cloud-firestore==2.11.1
+google-cloud-firestore==2.14.0
# via firebase-admin
-google-cloud-storage==2.9.0
+google-cloud-storage==2.14.0
# via
# feast (setup.py)
# firebase-admin
- # gcsfs
google-crc32c==1.5.0
- # via google-resumable-media
-google-resumable-media==2.5.0
+ # via
+ # google-cloud-storage
+ # google-resumable-media
+google-resumable-media==2.7.0
# via
# google-cloud-bigquery
# google-cloud-storage
-googleapis-common-protos[grpc]==1.59.0
+googleapis-common-protos[grpc]==1.62.0
# via
# feast (setup.py)
# google-api-core
# grpc-google-iam-v1
# grpcio-status
-great-expectations==0.15.50
+great-expectations==0.18.8
# via feast (setup.py)
-greenlet==2.0.2
+greenlet==3.0.3
# via sqlalchemy
-grpc-google-iam-v1==0.12.6
+grpc-google-iam-v1==0.13.0
# via google-cloud-bigtable
-grpcio==1.54.2
+grpcio==1.60.1
# via
# feast (setup.py)
# google-api-core
# google-cloud-bigquery
# googleapis-common-protos
# grpc-google-iam-v1
+ # grpcio-health-checking
# grpcio-reflection
# grpcio-status
# grpcio-testing
# grpcio-tools
-grpcio-reflection==1.54.2
+grpcio-health-checking==1.60.1
# via feast (setup.py)
-grpcio-status==1.54.2
+grpcio-reflection==1.60.1
+ # via feast (setup.py)
+grpcio-status==1.60.1
# via google-api-core
-grpcio-testing==1.54.2
+grpcio-testing==1.60.1
# via feast (setup.py)
-grpcio-tools==1.54.2
+grpcio-tools==1.60.1
# via feast (setup.py)
-gunicorn==20.1.0
+gunicorn==21.2.0
# via feast (setup.py)
h11==0.14.0
# via
@@ -334,136 +300,147 @@ h11==0.14.0
# uvicorn
happybase==1.2.0
# via feast (setup.py)
-hazelcast-python-client==5.2.0
+hazelcast-python-client==5.3.0
# via feast (setup.py)
-hiredis==2.2.3
+hiredis==2.3.2
# via feast (setup.py)
-httpcore==0.17.2
+httpcore==1.0.3
# via httpx
httplib2==0.22.0
# via
# google-api-python-client
# google-auth-httplib2
-httptools==0.5.0
+httptools==0.6.1
# via uvicorn
-httpx==0.24.1
- # via feast (setup.py)
-identify==2.5.24
+httpx==0.26.0
+ # via
+ # feast (setup.py)
+ # jupyterlab
+identify==2.5.34
# via pre-commit
-idna==3.4
+idna==3.6
# via
# anyio
# httpx
# jsonschema
# requests
# snowflake-connector-python
- # yarl
imagesize==1.4.1
# via sphinx
-importlib-metadata==6.6.0
+importlib-metadata==6.11.0
# via
+ # build
# dask
- # great-expectations
+ # feast (setup.py)
# jupyter-client
+ # jupyter-lsp
+ # jupyterlab
+ # jupyterlab-server
# nbconvert
# sphinx
+importlib-resources==6.1.1
+ # via feast (setup.py)
iniconfig==2.0.0
# via pytest
-ipykernel==6.23.1
- # via
- # ipywidgets
- # nbclassic
- # notebook
-ipython==8.14.0
+ipykernel==6.29.2
+ # via jupyterlab
+ipython==8.18.1
# via
# great-expectations
# ipykernel
# ipywidgets
-ipython-genutils==0.2.0
- # via
- # nbclassic
- # notebook
-ipywidgets==8.0.6
+ipywidgets==8.1.2
# via great-expectations
isodate==0.6.1
- # via
- # azure-storage-blob
- # msrest
+ # via azure-storage-blob
isoduration==20.11.0
# via jsonschema
-isort==5.12.0
+isort==5.13.2
# via feast (setup.py)
-jedi==0.18.2
+jedi==0.19.1
# via ipython
-jinja2==3.1.2
+jinja2==3.1.3
# via
# altair
# feast (setup.py)
# great-expectations
# jupyter-server
+ # jupyterlab
+ # jupyterlab-server
# moto
- # nbclassic
# nbconvert
- # notebook
# sphinx
jmespath==1.0.1
# via
# boto3
# botocore
-jsonpatch==1.32
+json5==0.9.14
+ # via jupyterlab-server
+jsonpatch==1.33
# via great-expectations
-jsonpointer==2.3
+jsonpointer==2.4
# via
# jsonpatch
# jsonschema
-jsonschema[format-nongpl]==4.17.3
+jsonschema[format-nongpl]==4.21.1
# via
# altair
# feast (setup.py)
# great-expectations
# jupyter-events
+ # jupyterlab-server
# nbformat
-jupyter-client==8.2.0
+jsonschema-specifications==2023.12.1
+ # via jsonschema
+jupyter-client==8.6.0
# via
# ipykernel
# jupyter-server
- # nbclassic
# nbclient
- # notebook
-jupyter-core==5.3.0
+jupyter-core==5.7.1
# via
# ipykernel
# jupyter-client
# jupyter-server
- # nbclassic
+ # jupyterlab
# nbclient
# nbconvert
# nbformat
- # notebook
-jupyter-events==0.6.3
+jupyter-events==0.9.0
# via jupyter-server
-jupyter-server==2.6.0
+jupyter-lsp==2.2.2
+ # via jupyterlab
+jupyter-server==2.12.5
# via
- # nbclassic
+ # jupyter-lsp
+ # jupyterlab
+ # jupyterlab-server
+ # notebook
# notebook-shim
-jupyter-server-terminals==0.4.4
+jupyter-server-terminals==0.5.2
# via jupyter-server
-jupyterlab-pygments==0.2.2
+jupyterlab==4.1.1
+ # via notebook
+jupyterlab-pygments==0.3.0
# via nbconvert
-jupyterlab-widgets==3.0.7
+jupyterlab-server==2.25.3
+ # via
+ # jupyterlab
+ # notebook
+jupyterlab-widgets==3.0.10
# via ipywidgets
kubernetes==20.13.0
# via feast (setup.py)
locket==1.0.0
# via partd
-makefun==1.15.1
+makefun==1.15.2
# via great-expectations
-markupsafe==2.1.3
+markupsafe==2.1.5
# via
# jinja2
# nbconvert
# werkzeug
-marshmallow==3.19.0
+marshmallow==3.20.2
# via great-expectations
matplotlib-inline==0.1.6
# via
@@ -473,38 +450,29 @@ mccabe==0.7.0
# via flake8
minio==7.1.0
# via feast (setup.py)
-mistune==2.0.5
+mistune==3.0.2
# via
# great-expectations
# nbconvert
-mmh3==4.0.0
+mmh3==4.1.0
# via feast (setup.py)
mock==2.0.0
# via feast (setup.py)
moreorless==0.4.0
# via bowler
-moto==4.1.10
+moto==4.2.14
# via feast (setup.py)
-msal==1.22.0
+msal==1.26.0
# via
- # azure-datalake-store
# azure-identity
# msal-extensions
-msal-extensions==1.0.0
+msal-extensions==1.1.0
# via azure-identity
-msgpack==1.0.5
+msgpack==1.0.7
# via cachecontrol
-msrest==0.7.1
- # via msrestazure
-msrestazure==0.6.4
- # via adlfs
-multidict==6.0.4
- # via
- # aiohttp
- # yarl
-multiprocess==0.70.14
+multiprocess==0.70.16
# via bytewax
-mypy==0.982
+mypy==1.8.0
# via
# feast (setup.py)
# sqlalchemy
@@ -512,39 +480,29 @@ mypy-extensions==1.0.0
# via
# black
# mypy
-mypy-protobuf==3.1
+mypy-protobuf==3.1.0
# via feast (setup.py)
-mysqlclient==2.1.1
- # via feast (setup.py)
-nbclassic==1.0.0
- # via notebook
-nbclient==0.8.0
+nbclient==0.9.0
# via nbconvert
-nbconvert==7.4.0
- # via
- # jupyter-server
- # nbclassic
- # notebook
-nbformat==5.9.0
+nbconvert==7.16.0
+ # via jupyter-server
+nbformat==5.9.2
# via
# great-expectations
# jupyter-server
- # nbclassic
# nbclient
# nbconvert
- # notebook
-nest-asyncio==1.5.6
- # via
- # ipykernel
- # nbclassic
- # notebook
+nest-asyncio==1.6.0
+ # via ipykernel
nodeenv==1.8.0
# via pre-commit
-notebook==6.5.4
+notebook==7.1.0
# via great-expectations
notebook-shim==0.2.3
- # via nbclassic
-numpy==1.24.3
+ # via
+ # jupyterlab
+ # notebook
+numpy==1.24.4
# via
# altair
# db-dtypes
@@ -556,11 +514,9 @@ numpy==1.24.3
# scipy
oauthlib==3.2.2
# via requests-oauthlib
-oscrypto==1.3.0
- # via snowflake-connector-python
-overrides==7.3.1
+overrides==7.7.0
# via jupyter-server
-packaging==23.1
+packaging==23.2
# via
# build
# dask
@@ -569,12 +525,15 @@ packaging==23.1
# docker
# google-cloud-bigquery
# great-expectations
+ # gunicorn
# ipykernel
# jupyter-server
+ # jupyterlab
+ # jupyterlab-server
# marshmallow
+ # msal-extensions
# nbconvert
# pytest
- # redis
# snowflake-connector-python
# sphinx
pandas==1.5.3
@@ -588,43 +547,39 @@ pandas==1.5.3
# snowflake-connector-python
pandavro==1.5.2
# via feast (setup.py)
-pandocfilters==1.5.0
+pandocfilters==1.5.1
# via nbconvert
parso==0.8.3
# via jedi
-partd==1.4.0
+partd==1.4.1
# via dask
-pathspec==0.11.1
+pathspec==0.12.1
# via black
-pbr==5.11.1
+pbr==6.0.0
# via mock
-pexpect==4.8.0
- # via ipython
-pickleshare==0.7.5
+pexpect==4.9.0
# via ipython
-pip-tools==6.13.0
+pip-tools==7.3.0
# via feast (setup.py)
-platformdirs==3.5.1
+platformdirs==3.11.0
# via
# black
# jupyter-core
+ # snowflake-connector-python
# virtualenv
-pluggy==1.0.0
+pluggy==1.4.0
# via pytest
ply==3.11
# via thriftpy2
-portalocker==2.7.0
+portalocker==2.8.2
# via msal-extensions
-pre-commit==3.3.2
+pre-commit==3.3.1
# via feast (setup.py)
-prometheus-client==0.17.0
- # via
- # jupyter-server
- # nbclassic
- # notebook
-prompt-toolkit==3.0.38
+prometheus-client==0.20.0
+ # via jupyter-server
+prompt-toolkit==3.0.43
# via ipython
-proto-plus==1.22.2
+proto-plus==1.23.0
# via
# feast (setup.py)
# google-cloud-bigquery
@@ -632,7 +587,7 @@ proto-plus==1.22.2
# google-cloud-bigtable
# google-cloud-datastore
# google-cloud-firestore
-protobuf==4.23.2
+protobuf==4.23.3
# via
# feast (setup.py)
# google-api-core
@@ -643,6 +598,7 @@ protobuf==4.23.2
# google-cloud-firestore
# googleapis-common-protos
# grpc-google-iam-v1
+ # grpcio-health-checking
# grpcio-reflection
# grpcio-status
# grpcio-testing
@@ -653,7 +609,7 @@ psutil==5.9.0
# via
# feast (setup.py)
# ipykernel
-psycopg2-binary==2.9.6
+psycopg2-binary==2.9.9
# via feast (setup.py)
ptyprocess==0.7.0
# via
@@ -667,13 +623,13 @@ py-cpuinfo==9.0.0
# via pytest-benchmark
py4j==0.10.9.7
# via pyspark
-pyarrow==10.0.1
+pyarrow==15.0.0
# via
# db-dtypes
# feast (setup.py)
# google-cloud-bigquery
# snowflake-connector-python
-pyasn1==0.5.0
+pyasn1==0.5.1
# via
# pyasn1-modules
# rsa
@@ -685,45 +641,42 @@ pycodestyle==2.10.0
# via flake8
pycparser==2.21
# via cffi
-pycryptodomex==3.18.0
- # via snowflake-connector-python
-pydantic==1.10.8
+pydantic==2.6.1
# via
# fastapi
# feast (setup.py)
# great-expectations
+pydantic-core==2.16.2
+ # via pydantic
pyflakes==3.0.1
# via flake8
-pygments==2.15.1
+pygments==2.17.2
# via
# feast (setup.py)
# ipython
# nbconvert
# sphinx
-pyjwt[crypto]==2.7.0
+pyjwt[crypto]==2.8.0
# via
- # adal
# msal
# snowflake-connector-python
-pymssql==2.2.7
+pymssql==2.2.11
# via feast (setup.py)
-pymysql==1.0.3
+pymysql==1.1.0
# via feast (setup.py)
-pyodbc==4.0.39
+pyodbc==5.1.0
# via feast (setup.py)
-pyopenssl==23.2.0
+pyopenssl==23.3.0
# via snowflake-connector-python
-pyparsing==3.0.9
+pyparsing==3.1.1
# via
# great-expectations
# httplib2
pyproject-hooks==1.0.0
# via build
-pyrsistent==0.19.3
- # via jsonschema
-pyspark==3.4.0
+pyspark==3.5.0
# via feast (setup.py)
-pytest==7.3.1
+pytest==7.4.4
# via
# feast (setup.py)
# pytest-benchmark
@@ -745,11 +698,10 @@ pytest-ordering==0.6
# via feast (setup.py)
pytest-timeout==1.4.2
# via feast (setup.py)
-pytest-xdist==3.3.1
+pytest-xdist==3.5.0
# via feast (setup.py)
python-dateutil==2.8.2
# via
- # adal
# arrow
# botocore
# google-cloud-bigquery
@@ -760,17 +712,17 @@ python-dateutil==2.8.2
# pandas
# rockset
# trino
-python-dotenv==1.0.0
+python-dotenv==1.0.1
# via uvicorn
python-json-logger==2.0.7
# via jupyter-events
-pytz==2023.3
+pytz==2024.1
# via
# great-expectations
# pandas
# snowflake-connector-python
# trino
-pyyaml==6.0
+pyyaml==6.0.1
# via
# dask
# feast (setup.py)
@@ -779,46 +731,42 @@ pyyaml==6.0
# pre-commit
# responses
# uvicorn
-pyzmq==25.1.0
+pyzmq==25.1.2
# via
# ipykernel
# jupyter-client
# jupyter-server
- # nbclassic
- # notebook
-redis==4.2.2
+redis==4.6.0
# via feast (setup.py)
-regex==2023.5.5
+referencing==0.33.0
+ # via
+ # jsonschema
+ # jsonschema-specifications
+ # jupyter-events
+regex==2023.12.25
# via feast (setup.py)
requests==2.31.0
# via
- # adal
- # adlfs
# azure-core
- # azure-datalake-store
# cachecontrol
# docker
# feast (setup.py)
- # gcsfs
# google-api-core
# google-cloud-bigquery
# google-cloud-storage
# great-expectations
+ # jupyterlab-server
# kubernetes
# moto
# msal
- # msrest
# requests-oauthlib
# responses
# snowflake-connector-python
# sphinx
# trino
requests-oauthlib==1.3.1
- # via
- # google-auth-oauthlib
- # kubernetes
- # msrest
-responses==0.23.1
+ # via kubernetes
+responses==0.25.0
# via moto
rfc3339-validator==0.1.4
# via
@@ -828,38 +776,34 @@ rfc3986-validator==0.1.1
# via
# jsonschema
# jupyter-events
-rockset==2.0.0
+rockset==2.1.0
# via feast (setup.py)
+rpds-py==0.18.0
+ # via
+ # jsonschema
+ # referencing
rsa==4.9
# via google-auth
ruamel-yaml==0.17.17
# via great-expectations
-ruamel-yaml-clib==0.2.7
+ruamel-yaml-clib==0.2.8
# via ruamel-yaml
-s3transfer==0.6.1
+s3transfer==0.10.0
# via boto3
-scipy==1.10.1
+scipy==1.12.0
# via great-expectations
send2trash==1.8.2
- # via
- # jupyter-server
- # nbclassic
- # notebook
+ # via jupyter-server
six==1.16.0
# via
# asttokens
# azure-core
- # azure-identity
# bleach
- # cassandra-driver
# geomet
- # google-auth
- # google-auth-httplib2
# happybase
# isodate
# kubernetes
# mock
- # msrestazure
# pandavro
# python-dateutil
# rfc3339-validator
@@ -867,51 +811,48 @@ six==1.16.0
sniffio==1.3.0
# via
# anyio
- # httpcore
# httpx
snowballstemmer==2.2.0
# via sphinx
-snowflake-connector-python[pandas]==3.0.4
+snowflake-connector-python[pandas]==3.7.0
# via feast (setup.py)
sortedcontainers==2.4.0
# via snowflake-connector-python
-soupsieve==2.4.1
+soupsieve==2.5
# via beautifulsoup4
sphinx==6.2.1
# via feast (setup.py)
-sphinxcontrib-applehelp==1.0.4
+sphinxcontrib-applehelp==1.0.8
# via sphinx
-sphinxcontrib-devhelp==1.0.2
+sphinxcontrib-devhelp==1.0.6
# via sphinx
-sphinxcontrib-htmlhelp==2.0.1
+sphinxcontrib-htmlhelp==2.0.5
# via sphinx
sphinxcontrib-jsmath==1.0.1
# via sphinx
-sphinxcontrib-qthelp==1.0.3
+sphinxcontrib-qthelp==1.0.7
# via sphinx
-sphinxcontrib-serializinghtml==1.1.5
+sphinxcontrib-serializinghtml==1.1.10
# via sphinx
-sqlalchemy[mypy]==1.4.48
+sqlalchemy[mypy]==1.4.51
# via feast (setup.py)
-sqlalchemy2-stubs==0.0.2a34
+sqlalchemy2-stubs==0.0.2a38
# via sqlalchemy
-stack-data==0.6.2
+stack-data==0.6.3
# via ipython
-starlette==0.27.0
+starlette==0.36.3
# via fastapi
tabulate==0.9.0
# via feast (setup.py)
-tenacity==8.2.2
+tenacity==8.2.3
# via feast (setup.py)
-terminado==0.17.1
+terminado==0.18.0
# via
# jupyter-server
# jupyter-server-terminals
- # nbclassic
- # notebook
testcontainers==3.7.1
# via feast (setup.py)
-thriftpy2==0.4.16
+thriftpy2==0.4.17
# via happybase
tinycss2==1.2.1
# via nbconvert
@@ -922,27 +863,31 @@ tomli==2.0.1
# black
# build
# coverage
+ # jupyterlab
# mypy
+ # pip-tools
# pyproject-hooks
# pytest
-toolz==0.12.0
+tomlkit==0.12.3
+ # via snowflake-connector-python
+toolz==0.12.1
# via
# altair
# dask
# partd
-tornado==6.3.2
+tornado==6.4
# via
# ipykernel
# jupyter-client
# jupyter-server
- # nbclassic
+ # jupyterlab
# notebook
# terminado
-tqdm==4.65.0
+tqdm==4.66.2
# via
# feast (setup.py)
# great-expectations
-traitlets==5.9.0
+traitlets==5.14.1
# via
# comm
# ipykernel
@@ -952,68 +897,71 @@ traitlets==5.9.0
# jupyter-core
# jupyter-events
# jupyter-server
+ # jupyterlab
# matplotlib-inline
- # nbclassic
# nbclient
# nbconvert
# nbformat
- # notebook
-trino==0.326.0
+trino==0.327.0
# via feast (setup.py)
-typeguard==2.13.3
+typeguard==4.1.5
# via feast (setup.py)
types-protobuf==3.19.22
# via
# feast (setup.py)
# mypy-protobuf
-types-pymysql==1.0.19.7
+types-pymysql==1.1.0.1
# via feast (setup.py)
-types-pyopenssl==23.2.0.0
+types-pyopenssl==24.0.0.20240130
# via types-redis
-types-python-dateutil==2.8.19.13
- # via feast (setup.py)
-types-pytz==2023.3.0.0
- # via feast (setup.py)
-types-pyyaml==6.0.12.10
+types-python-dateutil==2.8.19.20240106
# via
+ # arrow
# feast (setup.py)
- # responses
-types-redis==4.5.5.2
+types-pytz==2024.1.0.20240203
+ # via feast (setup.py)
+types-pyyaml==6.0.12.12
# via feast (setup.py)
-types-requests==2.31.0.1
+types-redis==4.6.0.20240106
# via feast (setup.py)
-types-setuptools==67.8.0.0
+types-requests==2.30.0.0
# via feast (setup.py)
-types-tabulate==0.9.0.2
+types-setuptools==69.0.0.20240125
# via feast (setup.py)
-types-urllib3==1.26.25.13
+types-tabulate==0.9.0.20240106
+ # via feast (setup.py)
+types-urllib3==1.26.25.14
# via types-requests
-typing-extensions==4.6.3
+typing-extensions==4.9.0
# via
+ # anyio
+ # async-lru
# azure-core
# azure-storage-blob
# black
+ # fastapi
# great-expectations
# ipython
# mypy
# pydantic
+ # pydantic-core
# snowflake-connector-python
# sqlalchemy2-stubs
# starlette
-tzlocal==5.0.1
+ # uvicorn
+tzlocal==5.2
# via
# great-expectations
# trino
-uri-template==1.2.0
+uri-template==1.3.0
# via jsonschema
uritemplate==4.1.1
# via google-api-python-client
-urllib3==1.26.16
+urllib3==1.26.18
# via
# botocore
# docker
# feast (setup.py)
- # google-auth
# great-expectations
# kubernetes
# minio
@@ -1021,17 +969,19 @@ urllib3==1.26.16
# responses
# rockset
# snowflake-connector-python
-uvicorn[standard]==0.22.0
+uvicorn[standard]==0.27.1
# via feast (setup.py)
-uvloop==0.17.0
+uvloop==0.19.0
# via uvicorn
virtualenv==20.23.0
- # via pre-commit
+ # via
+ # feast (setup.py)
+ # pre-commit
volatile==2.1.0
# via bowler
-watchfiles==0.19.0
+watchfiles==0.21.0
# via uvicorn
-wcwidth==0.2.6
+wcwidth==0.2.13
# via prompt-toolkit
webcolors==1.13
# via jsonschema
@@ -1039,29 +989,26 @@ webencodings==0.5.1
# via
# bleach
# tinycss2
-websocket-client==1.5.2
+websocket-client==1.7.0
# via
- # docker
# jupyter-server
# kubernetes
-websockets==11.0.3
+websockets==12.0
# via uvicorn
-werkzeug==2.3.4
+werkzeug==3.0.1
# via moto
-wheel==0.40.0
+wheel==0.42.0
# via pip-tools
-widgetsnbextension==4.0.7
+widgetsnbextension==4.0.10
# via ipywidgets
-wrapt==1.15.0
- # via
- # deprecated
- # testcontainers
+wrapt==1.16.0
+ # via testcontainers
xmltodict==0.13.0
# via moto
-yarl==1.9.2
- # via aiohttp
-zipp==3.15.0
- # via importlib-metadata
+zipp==3.17.0
+ # via
+ # importlib-metadata
+ # importlib-resources
# The following packages are considered to be unsafe in a requirements file:
# pip
diff --git a/sdk/python/requirements/py3.9-requirements.txt b/sdk/python/requirements/py3.9-requirements.txt
index a96864ef531..182cb7ad076 100644
--- a/sdk/python/requirements/py3.9-requirements.txt
+++ b/sdk/python/requirements/py3.9-requirements.txt
@@ -1,145 +1,175 @@
#
-# This file is autogenerated by pip-compile with python 3.9
-# To update, run:
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
#
# pip-compile --output-file=sdk/python/requirements/py3.9-requirements.txt
#
-anyio==3.7.0
+annotated-types==0.6.0
+ # via pydantic
+anyio==4.2.0
# via
- # httpcore
+ # httpx
# starlette
# watchfiles
appdirs==1.4.4
# via fissix
-attrs==23.1.0
+attrs==23.2.0
# via
# bowler
# jsonschema
+ # referencing
bowler==0.9.0
# via feast (setup.py)
-certifi==2023.5.7
+certifi==2024.2.2
# via
# httpcore
# httpx
# requests
-charset-normalizer==3.1.0
+charset-normalizer==3.3.2
# via requests
-click==8.1.3
+click==8.1.7
# via
# bowler
# dask
# feast (setup.py)
# moreorless
# uvicorn
-cloudpickle==2.2.1
+cloudpickle==3.0.0
# via dask
colorama==0.4.6
# via feast (setup.py)
-dask==2023.5.1
+dask==2024.2.0
# via feast (setup.py)
-dill==0.3.6
+dill==0.3.8
# via feast (setup.py)
-exceptiongroup==1.1.1
+exceptiongroup==1.2.0
# via anyio
-fastapi==0.95.2
+fastapi==0.109.2
# via feast (setup.py)
-fastavro==1.7.4
+fastavro==1.9.4
# via
# feast (setup.py)
# pandavro
fissix==21.11.13
# via bowler
-fsspec==2023.5.0
+fsspec==2024.2.0
# via dask
-greenlet==2.0.2
+greenlet==3.0.3
# via sqlalchemy
-grpcio==1.54.2
+grpcio==1.60.1
# via
# feast (setup.py)
+ # grpcio-health-checking
# grpcio-reflection
-grpcio-reflection==1.54.2
+ # grpcio-tools
+grpcio-health-checking==1.60.1
+ # via feast (setup.py)
+grpcio-reflection==1.60.1
# via feast (setup.py)
-gunicorn==20.1.0
+grpcio-tools==1.60.1
+ # via feast (setup.py)
+gunicorn==21.2.0
# via feast (setup.py)
h11==0.14.0
# via
# httpcore
# uvicorn
-httpcore==0.17.2
+httpcore==1.0.3
# via httpx
-httptools==0.5.0
+httptools==0.6.1
# via uvicorn
-httpx==0.24.1
+httpx==0.26.0
# via feast (setup.py)
-idna==3.4
+idna==3.6
# via
# anyio
# httpx
# requests
-importlib-metadata==6.6.0
- # via dask
-jinja2==3.1.2
+importlib-metadata==6.11.0
+ # via
+ # dask
+ # feast (setup.py)
+importlib-resources==6.1.1
+ # via feast (setup.py)
+jinja2==3.1.3
# via feast (setup.py)
-jsonschema==4.17.3
+jsonschema==4.21.1
# via feast (setup.py)
+jsonschema-specifications==2023.12.1
+ # via jsonschema
locket==1.0.0
# via partd
-markupsafe==2.1.3
+markupsafe==2.1.5
# via jinja2
-mmh3==4.0.0
+mmh3==4.1.0
# via feast (setup.py)
moreorless==0.4.0
# via bowler
-mypy==1.3.0
+mypy==1.8.0
# via sqlalchemy
mypy-extensions==1.0.0
# via mypy
-numpy==1.24.3
+mypy-protobuf==3.1.0
+ # via feast (setup.py)
+numpy==1.24.4
# via
# feast (setup.py)
# pandas
# pandavro
# pyarrow
-packaging==23.1
- # via dask
+packaging==23.2
+ # via
+ # dask
+ # gunicorn
pandas==1.5.3
# via
# feast (setup.py)
# pandavro
pandavro==1.5.2
# via feast (setup.py)
-partd==1.4.0
+partd==1.4.1
# via dask
-proto-plus==1.22.2
+proto-plus==1.23.0
# via feast (setup.py)
-protobuf==4.23.2
+protobuf==4.23.3
# via
# feast (setup.py)
+ # grpcio-health-checking
# grpcio-reflection
+ # grpcio-tools
+ # mypy-protobuf
# proto-plus
-pyarrow==11.0.0
+pyarrow==15.0.0
# via feast (setup.py)
-pydantic==1.10.8
+pydantic==2.6.1
# via
# fastapi
# feast (setup.py)
-pygments==2.15.1
+pydantic-core==2.16.2
+ # via pydantic
+pygments==2.17.2
# via feast (setup.py)
-pyrsistent==0.19.3
- # via jsonschema
python-dateutil==2.8.2
# via pandas
-python-dotenv==1.0.0
+python-dotenv==1.0.1
# via uvicorn
-pytz==2023.3
+pytz==2024.1
# via pandas
-pyyaml==6.0
+pyyaml==6.0.1
# via
# dask
# feast (setup.py)
# uvicorn
+referencing==0.33.0
+ # via
+ # jsonschema
+ # jsonschema-specifications
requests==2.31.0
# via feast (setup.py)
+rpds-py==0.18.0
+ # via
+ # jsonschema
+ # referencing
six==1.16.0
# via
# pandavro
@@ -147,47 +177,57 @@ six==1.16.0
sniffio==1.3.0
# via
# anyio
- # httpcore
# httpx
-sqlalchemy[mypy]==1.4.48
+sqlalchemy[mypy]==1.4.51
# via feast (setup.py)
-sqlalchemy2-stubs==0.0.2a34
+sqlalchemy2-stubs==0.0.2a38
# via sqlalchemy
-starlette==0.27.0
+starlette==0.36.3
# via fastapi
tabulate==0.9.0
# via feast (setup.py)
-tenacity==8.2.2
+tenacity==8.2.3
# via feast (setup.py)
toml==0.10.2
# via feast (setup.py)
tomli==2.0.1
# via mypy
-toolz==0.12.0
+toolz==0.12.1
# via
# dask
# partd
-tqdm==4.65.0
+tqdm==4.66.2
# via feast (setup.py)
-typeguard==2.13.3
+typeguard==4.1.5
# via feast (setup.py)
-typing-extensions==4.6.3
+types-protobuf==4.24.0.20240129
+ # via mypy-protobuf
+typing-extensions==4.9.0
# via
+ # anyio
+ # fastapi
# mypy
# pydantic
+ # pydantic-core
# sqlalchemy2-stubs
# starlette
-urllib3==2.0.2
+ # uvicorn
+urllib3==2.2.0
# via requests
-uvicorn[standard]==0.22.0
+uvicorn[standard]==0.27.1
# via feast (setup.py)
-uvloop==0.17.0
+uvloop==0.19.0
# via uvicorn
volatile==2.1.0
# via bowler
-watchfiles==0.19.0
+watchfiles==0.21.0
# via uvicorn
-websockets==11.0.3
+websockets==12.0
# via uvicorn
-zipp==3.15.0
- # via importlib-metadata
+zipp==3.17.0
+ # via
+ # importlib-metadata
+ # importlib-resources
+
+# The following packages are considered to be unsafe in a requirements file:
+# setuptools
diff --git a/sdk/python/tests/conftest.py b/sdk/python/tests/conftest.py
index 728bd9b34f7..743a1ce4a0f 100644
--- a/sdk/python/tests/conftest.py
+++ b/sdk/python/tests/conftest.py
@@ -18,7 +18,7 @@
from datetime import datetime, timedelta
from multiprocessing import Process
from sys import platform
-from typing import Any, Dict, List, Tuple
+from typing import Any, Dict, List, Tuple, no_type_check
import pandas as pd
import pytest
@@ -187,9 +187,10 @@ def environment(request, worker_id):
e.online_store_creator.teardown()
-_config_cache = {}
+_config_cache: Any = {}
+@no_type_check
def pytest_generate_tests(metafunc: pytest.Metafunc):
"""
This function receives each test function (wrapped in Metafunc)
diff --git a/sdk/python/tests/data/data_creator.py b/sdk/python/tests/data/data_creator.py
index 2155468445a..1fc66aee845 100644
--- a/sdk/python/tests/data/data_creator.py
+++ b/sdk/python/tests/data/data_creator.py
@@ -9,7 +9,7 @@
def create_basic_driver_dataset(
entity_type: FeastType = Int32,
- feature_dtype: str = None,
+ feature_dtype: Optional[str] = None,
feature_is_list: bool = False,
list_has_empty_list: bool = False,
) -> pd.DataFrame:
@@ -59,6 +59,7 @@ def get_feature_values_for_dtype(
"int64": [1, 2, 3, 4, 5],
"float": [1.0, None, 3.0, 4.0, 5.0],
"string": ["1", None, "3", "4", "5"],
+ "bytes": [b"1", None, b"3", b"4", b"5"],
"bool": [True, None, False, True, False],
"datetime": [
datetime(1980, 1, 1),
diff --git a/sdk/python/tests/foo_provider.py b/sdk/python/tests/foo_provider.py
index d27e2645d4e..ba256a3813c 100644
--- a/sdk/python/tests/foo_provider.py
+++ b/sdk/python/tests/foo_provider.py
@@ -71,16 +71,16 @@ def get_historical_features(
project: str,
full_feature_names: bool = False,
) -> RetrievalJob:
- pass
+ return RetrievalJob()
def online_read(
self,
config: RepoConfig,
table: FeatureView,
entity_keys: List[EntityKeyProto],
- requested_features: List[str] = None,
+ requested_features: Optional[List[str]] = None,
) -> List[Tuple[Optional[datetime], Optional[Dict[str, ValueProto]]]]:
- pass
+ return []
def retrieve_saved_dataset(self, config: RepoConfig, dataset: SavedDataset):
pass
@@ -102,4 +102,4 @@ def retrieve_feature_service_logs(
config: RepoConfig,
registry: BaseRegistry,
) -> RetrievalJob:
- pass
+ return RetrievalJob()
diff --git a/sdk/python/tests/integration/feature_repos/repo_configuration.py b/sdk/python/tests/integration/feature_repos/repo_configuration.py
index fda5b3c11de..7d742998e9c 100644
--- a/sdk/python/tests/integration/feature_repos/repo_configuration.py
+++ b/sdk/python/tests/integration/feature_repos/repo_configuration.py
@@ -68,7 +68,7 @@
)
DYNAMO_CONFIG = {"type": "dynamodb", "region": "us-west-2"}
-REDIS_CONFIG = {"type": "redis", "connection_string": "localhost:6379,db=0"}
+REDIS_CONFIG = {"type": "redis", "connection_string": "host.docker.internal:6379,db=0"}
REDIS_CLUSTER_CONFIG = {
"type": "redis",
"redis_type": "redis_cluster",
@@ -83,8 +83,8 @@
"password": os.getenv("SNOWFLAKE_CI_PASSWORD", ""),
"role": os.getenv("SNOWFLAKE_CI_ROLE", ""),
"warehouse": os.getenv("SNOWFLAKE_CI_WAREHOUSE", ""),
- "database": "FEAST",
- "schema": "ONLINE",
+ "database": os.getenv("SNOWFLAKE_CI_DATABASE", "FEAST"),
+ "schema": os.getenv("SNOWFLAKE_CI_SCHEMA_ONLINE", "ONLINE"),
}
BIGTABLE_CONFIG = {
@@ -99,7 +99,7 @@
"host": os.getenv("ROCKSET_APISERVER", "api.rs2.usw2.rockset.com"),
}
-OFFLINE_STORE_TO_PROVIDER_CONFIG: Dict[str, DataSourceCreator] = {
+OFFLINE_STORE_TO_PROVIDER_CONFIG: Dict[str, Tuple[str, Type[DataSourceCreator]]] = {
"file": ("local", FileDataSourceCreator),
"bigquery": ("gcp", BigQueryDataSourceCreator),
"redshift": ("aws", RedshiftDataSourceCreator),
@@ -111,7 +111,7 @@
]
AVAILABLE_ONLINE_STORES: Dict[
- str, Tuple[Union[str, Dict[str, str]], Optional[Type[OnlineStoreCreator]]]
+ str, Tuple[Union[str, Dict[Any, Any]], Optional[Type[OnlineStoreCreator]]]
] = {
"sqlite": ({"type": "sqlite"}, None),
}
@@ -169,7 +169,7 @@
AVAILABLE_ONLINE_STORES = {
c.online_store["type"]
if isinstance(c.online_store, dict)
- else c.online_store: (c.online_store, c.online_store_creator)
+ else c.online_store: (c.online_store, c.online_store_creator) # type: ignore
for c in FULL_REPO_CONFIGS
}
@@ -328,7 +328,7 @@ class UniversalFeatureViews:
customer: FeatureView
global_fv: FeatureView
driver: FeatureView
- driver_odfv: OnDemandFeatureView
+ driver_odfv: Optional[OnDemandFeatureView]
order: FeatureView
location: FeatureView
field_mapping: FeatureView
@@ -410,9 +410,7 @@ def construct_test_environment(
online_creator = test_repo_config.online_store_creator(
project, fixture_request=fixture_request
)
- online_store = (
- test_repo_config.online_store
- ) = online_creator.create_online_store()
+ online_store = online_creator.create_online_store()
else:
online_creator = None
online_store = test_repo_config.online_store
@@ -422,7 +420,7 @@ def construct_test_environment(
AwsLambdaFeatureServerConfig,
)
- feature_server = AwsLambdaFeatureServerConfig(
+ feature_server: Any = AwsLambdaFeatureServerConfig(
enabled=True,
execution_role_name=os.getenv(
"AWS_LAMBDA_ROLE",
@@ -465,7 +463,7 @@ def construct_test_environment(
# Create feature_store.yaml out of the config
with open(Path(repo_dir_name) / "feature_store.yaml", "w") as f:
- yaml.safe_dump(json.loads(config.json()), f)
+ yaml.safe_dump(json.loads(config.model_dump_json(by_alias=True)), f)
fs = FeatureStore(repo_dir_name)
# We need to initialize the registry, because if nothing is applied in the test before tearing down
diff --git a/sdk/python/tests/integration/feature_repos/universal/data_source_creator.py b/sdk/python/tests/integration/feature_repos/universal/data_source_creator.py
index b36af0db472..5e5062291d5 100644
--- a/sdk/python/tests/integration/feature_repos/universal/data_source_creator.py
+++ b/sdk/python/tests/integration/feature_repos/universal/data_source_creator.py
@@ -20,7 +20,7 @@ def create_data_source(
destination_name: str,
event_timestamp_column="ts",
created_timestamp_column="created_ts",
- field_mapping: Dict[str, str] = None,
+ field_mapping: Optional[Dict[str, str]] = None,
timestamp_field: Optional[str] = None,
) -> DataSource:
"""
@@ -42,19 +42,20 @@ def create_data_source(
A Data source object, pointing to a table or file that is uploaded/persisted for the purpose of the
test.
"""
- ...
+ raise NotImplementedError
@abstractmethod
def create_offline_store_config(self) -> FeastConfigBaseModel:
- ...
+ raise NotImplementedError
@abstractmethod
def create_saved_dataset_destination(self) -> SavedDatasetStorage:
- ...
+ raise NotImplementedError
+ @abstractmethod
def create_logged_features_destination(self) -> LoggingDestination:
- pass
+ raise NotImplementedError
@abstractmethod
def teardown(self):
- ...
+ raise NotImplementedError
diff --git a/sdk/python/tests/integration/feature_repos/universal/data_sources/bigquery.py b/sdk/python/tests/integration/feature_repos/universal/data_sources/bigquery.py
index 384037eef14..066497a0bcd 100644
--- a/sdk/python/tests/integration/feature_repos/universal/data_sources/bigquery.py
+++ b/sdk/python/tests/integration/feature_repos/universal/data_sources/bigquery.py
@@ -64,10 +64,9 @@ def create_data_source(
self,
df: pd.DataFrame,
destination_name: str,
- timestamp_field="ts",
created_timestamp_column="created_ts",
- field_mapping: Dict[str, str] = None,
- **kwargs,
+ field_mapping: Optional[Dict[str, str]] = None,
+ timestamp_field: Optional[str] = "ts",
) -> DataSource:
destination_name = self.get_prefixed_table_name(destination_name)
diff --git a/sdk/python/tests/integration/feature_repos/universal/data_sources/file.py b/sdk/python/tests/integration/feature_repos/universal/data_sources/file.py
index 124dd4c88d6..008bb8d8815 100644
--- a/sdk/python/tests/integration/feature_repos/universal/data_sources/file.py
+++ b/sdk/python/tests/integration/feature_repos/universal/data_sources/file.py
@@ -39,9 +39,9 @@ def create_data_source(
self,
df: pd.DataFrame,
destination_name: str,
- timestamp_field="ts",
created_timestamp_column="created_ts",
- field_mapping: Dict[str, str] = None,
+ field_mapping: Optional[Dict[str, str]] = None,
+ timestamp_field: Optional[str] = "ts",
) -> DataSource:
destination_name = self.get_prefixed_table_name(destination_name)
@@ -94,9 +94,9 @@ def create_data_source(
self,
df: pd.DataFrame,
destination_name: str,
- timestamp_field="ts",
created_timestamp_column="created_ts",
- field_mapping: Dict[str, str] = None,
+ field_mapping: Optional[Dict[str, str]] = None,
+ timestamp_field: Optional[str] = "ts",
) -> DataSource:
destination_name = self.get_prefixed_table_name(destination_name)
@@ -167,11 +167,10 @@ def _upload_parquet_file(self, df, file_name, minio_endpoint):
def create_data_source(
self,
df: pd.DataFrame,
- destination_name: Optional[str] = None,
- suffix: Optional[str] = None,
- timestamp_field="ts",
+ destination_name: str,
created_timestamp_column="created_ts",
- field_mapping: Dict[str, str] = None,
+ field_mapping: Optional[Dict[str, str]] = None,
+ timestamp_field: Optional[str] = "ts",
) -> DataSource:
filename = f"{destination_name}.parquet"
port = self.minio.get_exposed_port("9000")
diff --git a/sdk/python/tests/integration/feature_repos/universal/data_sources/redshift.py b/sdk/python/tests/integration/feature_repos/universal/data_sources/redshift.py
index dfe8e3d33bf..5a4e3f10854 100644
--- a/sdk/python/tests/integration/feature_repos/universal/data_sources/redshift.py
+++ b/sdk/python/tests/integration/feature_repos/universal/data_sources/redshift.py
@@ -42,16 +42,17 @@ def __init__(self, project_name: str, *args, **kwargs):
iam_role=os.getenv(
"AWS_IAM_ROLE", "arn:aws:iam::402087665549:role/redshift_s3_access_role"
),
+ workgroup="",
)
def create_data_source(
self,
df: pd.DataFrame,
destination_name: str,
- suffix: Optional[str] = None,
- timestamp_field="ts",
+ event_timestamp_column="ts",
created_timestamp_column="created_ts",
- field_mapping: Dict[str, str] = None,
+ field_mapping: Optional[Dict[str, str]] = None,
+ timestamp_field: Optional[str] = "ts",
) -> DataSource:
destination_name = self.get_prefixed_table_name(destination_name)
diff --git a/sdk/python/tests/integration/feature_repos/universal/data_sources/snowflake.py b/sdk/python/tests/integration/feature_repos/universal/data_sources/snowflake.py
index c7e5961a88a..1481b11a106 100644
--- a/sdk/python/tests/integration/feature_repos/universal/data_sources/snowflake.py
+++ b/sdk/python/tests/integration/feature_repos/universal/data_sources/snowflake.py
@@ -36,8 +36,8 @@ def __init__(self, project_name: str, *args, **kwargs):
password=os.environ["SNOWFLAKE_CI_PASSWORD"],
role=os.environ["SNOWFLAKE_CI_ROLE"],
warehouse=os.environ["SNOWFLAKE_CI_WAREHOUSE"],
- database="FEAST",
- schema="OFFLINE",
+ database=os.environ.get("SNOWFLAKE_CI_DATABASE", "FEAST"),
+ schema=os.environ.get("SNOWFLAKE_CI_SCHEMA_OFFLINE", "OFFLINE"),
storage_integration_name=os.getenv("BLOB_EXPORT_STORAGE_NAME", "FEAST_S3"),
blob_export_location=os.getenv(
"BLOB_EXPORT_URI", "s3://feast-snowflake-offload/export"
@@ -48,10 +48,10 @@ def create_data_source(
self,
df: pd.DataFrame,
destination_name: str,
- suffix: Optional[str] = None,
- timestamp_field="ts",
+ event_timestamp_column="ts",
created_timestamp_column="created_ts",
- field_mapping: Dict[str, str] = None,
+ field_mapping: Optional[Dict[str, str]] = None,
+ timestamp_field: Optional[str] = "ts",
) -> DataSource:
destination_name = self.get_prefixed_table_name(destination_name)
diff --git a/sdk/python/tests/integration/feature_repos/universal/feature_views.py b/sdk/python/tests/integration/feature_repos/universal/feature_views.py
index 5938a0c936e..9bb8aae77f3 100644
--- a/sdk/python/tests/integration/feature_repos/universal/feature_views.py
+++ b/sdk/python/tests/integration/feature_repos/universal/feature_views.py
@@ -14,6 +14,7 @@
StreamFeatureView,
)
from feast.data_source import DataSource, RequestSource
+from feast.feature_view_projection import FeatureViewProjection
from feast.types import Array, FeastType, Float32, Float64, Int32, Int64
from tests.integration.feature_repos.universal.entities import (
customer,
@@ -55,7 +56,7 @@ def conv_rate_plus_100(features_df: pd.DataFrame) -> pd.DataFrame:
def conv_rate_plus_100_feature_view(
- sources: Dict[str, Union[RequestSource, FeatureView]],
+ sources: List[Union[FeatureView, RequestSource, FeatureViewProjection]],
infer_features: bool = False,
features: Optional[List[Field]] = None,
) -> OnDemandFeatureView:
diff --git a/sdk/python/tests/integration/feature_repos/universal/online_store/redis.py b/sdk/python/tests/integration/feature_repos/universal/online_store/redis.py
index 11d62d9d30a..108ca3b3906 100644
--- a/sdk/python/tests/integration/feature_repos/universal/online_store/redis.py
+++ b/sdk/python/tests/integration/feature_repos/universal/online_store/redis.py
@@ -20,7 +20,10 @@ def create_online_store(self) -> Dict[str, str]:
container=self.container, predicate=log_string_to_wait_for, timeout=10
)
exposed_port = self.container.get_exposed_port("6379")
- return {"type": "redis", "connection_string": f"localhost:{exposed_port},db=0"}
+ return {
+ "type": "redis",
+ "connection_string": f"host.docker.internal:{exposed_port},db=0",
+ }
def teardown(self):
self.container.stop()
diff --git a/sdk/python/tests/integration/feature_repos/universal/online_store_creator.py b/sdk/python/tests/integration/feature_repos/universal/online_store_creator.py
index c3872ea697f..4932001e76f 100644
--- a/sdk/python/tests/integration/feature_repos/universal/online_store_creator.py
+++ b/sdk/python/tests/integration/feature_repos/universal/online_store_creator.py
@@ -1,4 +1,4 @@
-from abc import ABC
+from abc import ABC, abstractmethod
from feast.repo_config import FeastConfigBaseModel
@@ -8,7 +8,8 @@ def __init__(self, project_name: str, **kwargs):
self.project_name = project_name
def create_online_store(self) -> FeastConfigBaseModel:
- ...
+ raise NotImplementedError
+ @abstractmethod
def teardown(self):
- ...
+ raise NotImplementedError
diff --git a/sdk/python/tests/integration/materialization/test_lambda.py b/sdk/python/tests/integration/materialization/test_lambda.py
index d93508c156a..07ab93e2e13 100644
--- a/sdk/python/tests/integration/materialization/test_lambda.py
+++ b/sdk/python/tests/integration/materialization/test_lambda.py
@@ -21,6 +21,7 @@
@pytest.mark.integration
+@pytest.mark.skip(reason="Very flaky test")
def test_lambda_materialization_consistency():
lambda_config = IntegrationTestRepoConfig(
provider="aws",
@@ -64,7 +65,6 @@ def test_lambda_materialization_consistency():
)
try:
-
fs.apply([driver, driver_stats_fv])
print(df)
diff --git a/sdk/python/tests/integration/materialization/test_snowflake.py b/sdk/python/tests/integration/materialization/test_snowflake.py
index 0cf1471dfeb..daa96a87c97 100644
--- a/sdk/python/tests/integration/materialization/test_snowflake.py
+++ b/sdk/python/tests/integration/materialization/test_snowflake.py
@@ -1,10 +1,13 @@
import os
-from datetime import timedelta
+from datetime import datetime, timedelta
import pytest
+from pytz import utc
+from feast import Field
from feast.entity import Entity
from feast.feature_view import FeatureView
+from feast.types import Array, Bool, Bytes, Float64, Int32, Int64, String, UnixTimestamp
from tests.data.data_creator import create_basic_driver_dataset
from tests.integration.feature_repos.integration_test_repo_config import (
IntegrationTestRepoConfig,
@@ -24,8 +27,8 @@
"password": os.getenv("SNOWFLAKE_CI_PASSWORD", ""),
"role": os.getenv("SNOWFLAKE_CI_ROLE", ""),
"warehouse": os.getenv("SNOWFLAKE_CI_WAREHOUSE", ""),
- "database": "FEAST",
- "schema": "MATERIALIZATION",
+ "database": os.getenv("SNOWFLAKE_CI_DATABASE", "FEAST"),
+ "schema": os.getenv("SNOWFLAKE_CI_SCHEMA_MATERIALIZATION", "MATERIALIZATION"),
}
SNOWFLAKE_ONLINE_CONFIG = {
@@ -35,15 +38,16 @@
"password": os.getenv("SNOWFLAKE_CI_PASSWORD", ""),
"role": os.getenv("SNOWFLAKE_CI_ROLE", ""),
"warehouse": os.getenv("SNOWFLAKE_CI_WAREHOUSE", ""),
- "database": "FEAST",
- "schema": "ONLINE",
+ "database": os.getenv("SNOWFLAKE_CI_DATABASE", "FEAST"),
+ "schema": os.getenv("SNOWFLAKE_CI_SCHEMA_ONLINE", "ONLINE"),
}
+@pytest.mark.parametrize("online_store", [SNOWFLAKE_ONLINE_CONFIG, "sqlite"])
@pytest.mark.integration
-def test_snowflake_materialization_consistency_internal():
+def test_snowflake_materialization_consistency(online_store):
snowflake_config = IntegrationTestRepoConfig(
- online_store=SNOWFLAKE_ONLINE_CONFIG,
+ online_store=online_store,
offline_store_creator=SnowflakeDataSourceCreator,
batch_engine=SNOWFLAKE_ENGINE_CONFIG,
)
@@ -84,15 +88,32 @@ def test_snowflake_materialization_consistency_internal():
snowflake_environment.data_source_creator.teardown()
+@pytest.mark.parametrize(
+ "feature_dtype, feast_dtype",
+ [
+ ("string", Array(String)),
+ ("bytes", Array(Bytes)),
+ ("int32", Array(Int32)),
+ ("int64", Array(Int64)),
+ ("float", Array(Float64)),
+ ("bool", Array(Bool)),
+ ("datetime", Array(UnixTimestamp)),
+ ],
+)
+@pytest.mark.parametrize("feature_is_empty_list", [False])
+@pytest.mark.parametrize("online_store", [SNOWFLAKE_ONLINE_CONFIG, "sqlite"])
@pytest.mark.integration
-def test_snowflake_materialization_consistency_external():
+def test_snowflake_materialization_consistency_internal_with_lists(
+ feature_dtype, feast_dtype, feature_is_empty_list, online_store
+):
snowflake_config = IntegrationTestRepoConfig(
+ online_store=online_store,
offline_store_creator=SnowflakeDataSourceCreator,
batch_engine=SNOWFLAKE_ENGINE_CONFIG,
)
snowflake_environment = construct_test_environment(snowflake_config, None)
- df = create_basic_driver_dataset()
+ df = create_basic_driver_dataset(Int32, feature_dtype, True, feature_is_empty_list)
ds = snowflake_environment.data_source_creator.create_data_source(
df,
snowflake_environment.feature_store.project,
@@ -105,23 +126,62 @@ def test_snowflake_materialization_consistency_external():
join_keys=["driver_id"],
)
+ schema = [
+ Field(name="driver_id", dtype=Int32),
+ Field(name="value", dtype=feast_dtype),
+ ]
driver_stats_fv = FeatureView(
name="driver_hourly_stats",
entities=[driver],
ttl=timedelta(weeks=52),
+ schema=schema,
source=ds,
)
try:
fs.apply([driver, driver_stats_fv])
- # materialization is run in two steps and
- # we use timestamp from generated dataframe as a split point
split_dt = df["ts_1"][4].to_pydatetime() - timedelta(seconds=1)
print(f"Split datetime: {split_dt}")
+ now = datetime.utcnow()
+
+ full_feature_names = True
+ start_date = (now - timedelta(hours=5)).replace(tzinfo=utc)
+ end_date = split_dt
+ fs.materialize(
+ feature_views=[driver_stats_fv.name],
+ start_date=start_date,
+ end_date=end_date,
+ )
+
+ expected_values = {
+ "int32": [3] * 2,
+ "int64": [3] * 2,
+ "float": [3.0] * 2,
+ "string": ["3"] * 2,
+ "bytes": [b"3"] * 2,
+ "bool": [False] * 2,
+ "datetime": [datetime(1981, 1, 1, tzinfo=utc)] * 2,
+ }
+ expected_value = [] if feature_is_empty_list else expected_values[feature_dtype]
+
+ response_dict = fs.get_online_features(
+ [f"{driver_stats_fv.name}:value"],
+ [{"driver_id": 1}],
+ full_feature_names=full_feature_names,
+ ).to_dict()
+
+ actual_value = response_dict[f"{driver_stats_fv.name}__value"][0]
+ assert actual_value is not None, f"Response: {response_dict}"
+ if feature_dtype == "float":
+ for actual_num, expected_num in zip(actual_value, expected_value):
+ assert (
+ abs(actual_num - expected_num) < 1e-6
+ ), f"Response: {response_dict}, Expected: {expected_value}"
+ else:
+ assert actual_value == expected_value
- validate_offline_online_store_consistency(fs, driver_stats_fv, split_dt)
finally:
fs.teardown()
snowflake_environment.data_source_creator.teardown()
diff --git a/sdk/python/tests/unit/cli/test_cli_chdir.py b/sdk/python/tests/unit/cli/test_cli_chdir.py
index cf1d0312272..12ca8f6b084 100644
--- a/sdk/python/tests/unit/cli/test_cli_chdir.py
+++ b/sdk/python/tests/unit/cli/test_cli_chdir.py
@@ -15,7 +15,7 @@ def test_cli_chdir() -> None:
# Make sure the path is absolute by resolving any symlinks
temp_path = Path(temp_dir).resolve()
result = runner.run(["init", "my_project"], cwd=temp_path)
- repo_path = temp_path / "my_project" / "feature_repo"
+ repo_path = str(temp_path / "my_project" / "feature_repo")
assert result.returncode == 0
result = runner.run(["--chdir", repo_path, "apply"], cwd=temp_path)
@@ -44,7 +44,12 @@ def test_cli_chdir() -> None:
assert result.returncode == 0
result = runner.run(
- ["--chdir", repo_path, "materialize-incremental", end_date.isoformat()],
+ [
+ "--chdir",
+ repo_path,
+ "materialize-incremental",
+ end_date.isoformat(),
+ ],
cwd=temp_path,
)
assert result.returncode == 0
diff --git a/sdk/python/tests/unit/infra/offline_stores/test_offline_store.py b/sdk/python/tests/unit/infra/offline_stores/test_offline_store.py
index ef0cce04707..f93237fce5e 100644
--- a/sdk/python/tests/unit/infra/offline_stores/test_offline_store.py
+++ b/sdk/python/tests/unit/infra/offline_stores/test_offline_store.py
@@ -39,6 +39,9 @@
class MockRetrievalJob(RetrievalJob):
+ def to_sql(self) -> str:
+ return ""
+
def _to_df_internal(self, timeout: Optional[int] = None) -> pd.DataFrame:
"""
Synchronously executes the underlying query and returns the result as a pandas dataframe.
@@ -46,7 +49,7 @@ def _to_df_internal(self, timeout: Optional[int] = None) -> pd.DataFrame:
Does not handle on demand transformations or dataset validation. For either of those,
`to_df` should be used.
"""
- pass
+ return pd.DataFrame()
def _to_arrow_internal(self, timeout: Optional[int] = None) -> pyarrow.Table:
"""
@@ -55,17 +58,17 @@ def _to_arrow_internal(self, timeout: Optional[int] = None) -> pyarrow.Table:
Does not handle on demand transformations or dataset validation. For either of those,
`to_arrow` should be used.
"""
- pass
+ return pyarrow.Table()
@property
- def full_feature_names(self) -> bool:
+ def full_feature_names(self) -> bool: # type: ignore
"""Returns True if full feature names should be applied to the results of the query."""
- pass
+ return False
@property
- def on_demand_feature_views(self) -> List[OnDemandFeatureView]:
+ def on_demand_feature_views(self) -> List[OnDemandFeatureView]: # type: ignore
"""Returns a list containing all the on demand feature views to be handled."""
- pass
+ return []
def persist(
self,
@@ -87,7 +90,7 @@ def persist(
@property
def metadata(self) -> Optional[RetrievalMetadata]:
"""Returns metadata about the retrieval job."""
- pass
+ raise NotImplementedError
# Since RetreivalJob are not really tested for subclasses we add some tests here.
@@ -115,6 +118,7 @@ def retrieval_job(request, environment):
database="feast",
s3_staging_location="s3://feast-integration-tests/redshift/tests/ingestion",
iam_role="arn:aws:iam::402087665549:role/redshift_s3_access_role",
+ workgroup="",
)
environment.test_repo_config.offline_store = offline_store_config
return RedshiftRetrievalJob(
@@ -208,7 +212,7 @@ def retrieval_job(request, environment):
def test_to_sql():
- assert MockRetrievalJob().to_sql() is None
+ assert MockRetrievalJob().to_sql() == ""
@pytest.mark.parametrize("timeout", (None, 30))
diff --git a/sdk/python/tests/unit/infra/offline_stores/test_redshift.py b/sdk/python/tests/unit/infra/offline_stores/test_redshift.py
new file mode 100644
index 00000000000..48ee99e89ff
--- /dev/null
+++ b/sdk/python/tests/unit/infra/offline_stores/test_redshift.py
@@ -0,0 +1,68 @@
+from unittest.mock import MagicMock, patch
+
+import pandas as pd
+import pyarrow as pa
+
+from feast import FeatureView
+from feast.infra.offline_stores import offline_utils
+from feast.infra.offline_stores.redshift import (
+ RedshiftOfflineStore,
+ RedshiftOfflineStoreConfig,
+)
+from feast.infra.offline_stores.redshift_source import RedshiftSource
+from feast.infra.utils import aws_utils
+from feast.repo_config import RepoConfig
+
+
+@patch.object(aws_utils, "upload_arrow_table_to_redshift")
+def test_offline_write_batch(
+ mock_upload_arrow_table_to_redshift: MagicMock,
+ simple_dataset_1: pd.DataFrame,
+):
+ repo_config = RepoConfig(
+ registry="registry",
+ project="project",
+ provider="local",
+ offline_store=RedshiftOfflineStoreConfig(
+ type="redshift",
+ region="us-west-2",
+ cluster_id="cluster_id",
+ database="database",
+ user="user",
+ iam_role="abcdef",
+ s3_staging_location="s3://bucket/path",
+ workgroup="",
+ ),
+ )
+
+ batch_source = RedshiftSource(
+ name="test_source",
+ timestamp_field="ts",
+ table="table_name",
+ schema="schema_name",
+ )
+ feature_view = FeatureView(
+ name="test_view",
+ source=batch_source,
+ )
+
+ pa_dataset = pa.Table.from_pandas(simple_dataset_1)
+
+ # patch some more things so that the function can run
+ def mock_get_pyarrow_schema_from_batch_source(*args, **kwargs) -> pa.Schema:
+ return pa_dataset.schema, pa_dataset.column_names
+
+ with patch.object(
+ offline_utils,
+ "get_pyarrow_schema_from_batch_source",
+ new=mock_get_pyarrow_schema_from_batch_source,
+ ):
+ RedshiftOfflineStore.offline_write_batch(
+ repo_config, feature_view, pa_dataset, progress=None
+ )
+
+ # check that we have included the fully qualified table name
+ mock_upload_arrow_table_to_redshift.assert_called_once()
+
+ call = mock_upload_arrow_table_to_redshift.call_args_list[0]
+ assert call.kwargs["table_name"] == "schema_name.table_name"
diff --git a/sdk/python/tests/unit/infra/offline_stores/test_snowflake.py b/sdk/python/tests/unit/infra/offline_stores/test_snowflake.py
new file mode 100644
index 00000000000..ac55f123bbb
--- /dev/null
+++ b/sdk/python/tests/unit/infra/offline_stores/test_snowflake.py
@@ -0,0 +1,83 @@
+import re
+from unittest.mock import ANY, MagicMock, patch
+
+import pandas as pd
+import pytest
+from pytest_mock import MockFixture
+
+from feast import FeatureView, Field, FileSource
+from feast.infra.offline_stores.snowflake import (
+ SnowflakeOfflineStoreConfig,
+ SnowflakeRetrievalJob,
+)
+from feast.infra.online_stores.sqlite import SqliteOnlineStoreConfig
+from feast.repo_config import RepoConfig
+from feast.types import Array, String
+
+
+@pytest.fixture(params=["s3", "s3gov"])
+def retrieval_job(request):
+ offline_store_config = SnowflakeOfflineStoreConfig(
+ type="snowflake.offline",
+ account="snow",
+ user="snow",
+ password="snow",
+ role="snow",
+ warehouse="snow",
+ database="FEAST",
+ schema="OFFLINE",
+ storage_integration_name="FEAST_S3",
+ blob_export_location=f"{request.param}://feast-snowflake-offload/export",
+ )
+ retrieval_job = SnowflakeRetrievalJob(
+ query="SELECT * FROM snowflake",
+ snowflake_conn=MagicMock(),
+ config=RepoConfig(
+ registry="s3://ml-test/repo/registry.db",
+ project="test",
+ provider="snowflake.offline",
+ online_store=SqliteOnlineStoreConfig(type="sqlite"),
+ offline_store=offline_store_config,
+ ),
+ full_feature_names=True,
+ on_demand_feature_views=[],
+ )
+ return retrieval_job
+
+
+def test_to_remote_storage(retrieval_job):
+ stored_files = ["just a path", "maybe another"]
+ with patch.object(
+ retrieval_job, "to_snowflake", return_value=None
+ ) as mock_to_snowflake, patch.object(
+ retrieval_job, "_get_file_names_from_copy_into", return_value=stored_files
+ ) as mock_get_file_names_from_copy:
+ assert (
+ retrieval_job.to_remote_storage() == stored_files
+ ), "should return the list of files"
+ mock_to_snowflake.assert_called_once()
+ mock_get_file_names_from_copy.assert_called_once_with(ANY, ANY)
+ native_path = mock_get_file_names_from_copy.call_args[0][1]
+ assert re.match("^s3://.*", native_path), "path should be s3://*"
+
+
+def test_snowflake_to_df_internal(
+ retrieval_job: SnowflakeRetrievalJob, mocker: MockFixture
+):
+ mock_execute = mocker.patch(
+ "feast.infra.offline_stores.snowflake.execute_snowflake_statement"
+ )
+ mock_execute.return_value.fetch_pandas_all.return_value = pd.DataFrame.from_dict(
+ {"feature1": ['["1", "2", "3"]', None, "[]"]} # For Valid, Null, and Empty
+ )
+
+ feature_view = FeatureView(
+ name="my-feature-view",
+ entities=[],
+ schema=[
+ Field(name="feature1", dtype=Array(String)),
+ ],
+ source=FileSource(path="dummy.path"), # Dummy value
+ )
+ retrieval_job._feature_views = [feature_view]
+ retrieval_job._to_df_internal()
diff --git a/sdk/python/tests/unit/infra/scaffolding/test_repo_config.py b/sdk/python/tests/unit/infra/scaffolding/test_repo_config.py
index 42229f8683f..ca4ed6472b9 100644
--- a/sdk/python/tests/unit/infra/scaffolding/test_repo_config.py
+++ b/sdk/python/tests/unit/infra/scaffolding/test_repo_config.py
@@ -45,8 +45,7 @@ def test_nullable_online_store_aws():
entity_key_serialization_version: 2
"""
),
- expect_error="__root__ -> offline_store -> __root__\n"
- " please specify either cluster_id & user if using provisioned clusters, or workgroup if using serverless (type=value_error)",
+ expect_error="4 validation errors for RepoConfig\nregion\n Field required",
)
@@ -154,8 +153,7 @@ def test_extra_field():
path: "online_store.db"
"""
),
- expect_error="__root__ -> online_store -> that_field_should_not_be_here\n"
- " extra fields not permitted (type=value_error.extra)",
+ expect_error="1 validation error for RepoConfig\nthat_field_should_not_be_here\n Extra inputs are not permitted",
)
@@ -186,7 +184,7 @@ def test_bad_type():
path: 100500
"""
),
- expect_error="__root__ -> online_store -> path\n str type expected",
+ expect_error="1 validation error for RepoConfig\npath\n Input should be a valid string",
)
@@ -201,9 +199,7 @@ def test_no_project():
entity_key_serialization_version: 2
"""
),
- expect_error="1 validation error for RepoConfig\n"
- "project\n"
- " field required (type=value_error.missing)",
+ expect_error="1 validation error for RepoConfig\nproject\n Field required",
)
diff --git a/sdk/python/tests/unit/test_data_sources.py b/sdk/python/tests/unit/test_data_sources.py
index 30b030feb67..990c5d3b698 100644
--- a/sdk/python/tests/unit/test_data_sources.py
+++ b/sdk/python/tests/unit/test_data_sources.py
@@ -190,3 +190,46 @@ def test_column_conflict():
timestamp_field="event_timestamp",
created_timestamp_column="event_timestamp",
)
+
+
+@pytest.mark.parametrize(
+ "source_kwargs,expected_name",
+ [
+ (
+ {
+ "database": "test_database",
+ "schema": "test_schema",
+ "table": "test_table",
+ },
+ "test_database.test_schema.test_table",
+ ),
+ (
+ {"database": "test_database", "table": "test_table"},
+ "test_database.public.test_table",
+ ),
+ ({"table": "test_table"}, "public.test_table"),
+ ({"database": "test_database", "table": "b.c"}, "test_database.b.c"),
+ ({"database": "test_database", "table": "a.b.c"}, "a.b.c"),
+ (
+ {
+ "database": "test_database",
+ "schema": "test_schema",
+ "query": "select * from abc",
+ },
+ "",
+ ),
+ ],
+)
+def test_redshift_fully_qualified_table_name(source_kwargs, expected_name):
+ redshift_source = RedshiftSource(
+ name="test_source",
+ timestamp_field="event_timestamp",
+ created_timestamp_column="created_timestamp",
+ field_mapping={"foo": "bar"},
+ description="test description",
+ tags={"test": "test"},
+ owner="test@gmail.com",
+ **source_kwargs,
+ )
+
+ assert redshift_source.redshift_options.fully_qualified_table_name == expected_name
diff --git a/sdk/python/tests/unit/test_feature_views.py b/sdk/python/tests/unit/test_feature_views.py
index 379396e5c63..20863645b77 100644
--- a/sdk/python/tests/unit/test_feature_views.py
+++ b/sdk/python/tests/unit/test_feature_views.py
@@ -1,6 +1,7 @@
from datetime import timedelta
import pytest
+from typeguard import TypeCheckError
from feast.aggregation import Aggregation
from feast.batch_feature_view import BatchFeatureView
@@ -10,6 +11,9 @@
from feast.feature_view import FeatureView
from feast.field import Field
from feast.infra.offline_stores.file_source import FileSource
+from feast.protos.feast.core.StreamFeatureView_pb2 import (
+ StreamFeatureView as StreamFeatureViewProto,
+)
from feast.protos.feast.types.Value_pb2 import ValueType
from feast.stream_feature_view import StreamFeatureView, stream_feature_view
from feast.types import Float32
@@ -275,5 +279,24 @@ def test_hash():
def test_field_types():
- with pytest.raises(TypeError):
+ with pytest.raises(TypeCheckError):
Field(name="name", dtype=ValueType.INT32)
+
+
+def test_stream_feature_view_proto_type():
+ stream_source = KafkaSource(
+ name="kafka",
+ timestamp_field="event_timestamp",
+ kafka_bootstrap_servers="",
+ message_format=AvroFormat(""),
+ topic="topic",
+ batch_source=FileSource(path="some path"),
+ )
+ sfv = StreamFeatureView(
+ name="test stream featureview proto class",
+ entities=[],
+ ttl=timedelta(days=30),
+ source=stream_source,
+ aggregations=[],
+ )
+ assert sfv.proto_class is StreamFeatureViewProto
diff --git a/sdk/python/tests/unit/test_registry_server.py b/sdk/python/tests/unit/test_registry_server.py
new file mode 100644
index 00000000000..734bbfe19b8
--- /dev/null
+++ b/sdk/python/tests/unit/test_registry_server.py
@@ -0,0 +1,60 @@
+import assertpy
+import grpc_testing
+import pytest
+from google.protobuf.empty_pb2 import Empty
+
+from feast import Entity, FeatureStore
+from feast.protos.feast.registry import RegistryServer_pb2
+from feast.registry_server import RegistryServer
+
+
+def call_registry_server(server, method: str, request=None):
+ service = RegistryServer_pb2.DESCRIPTOR.services_by_name["RegistryServer"]
+ rpc = server.invoke_unary_unary(
+ service.methods_by_name[method], (), request if request else Empty(), None
+ )
+
+ return rpc.termination()
+
+
+@pytest.fixture
+def registry_server(environment):
+ store: FeatureStore = environment.feature_store
+
+ servicer = RegistryServer(store=store)
+
+ return grpc_testing.server_from_dictionary(
+ {RegistryServer_pb2.DESCRIPTOR.services_by_name["RegistryServer"]: servicer},
+ grpc_testing.strict_real_time(),
+ )
+
+
+def test_registry_server_get_entity(environment, registry_server):
+ store: FeatureStore = environment.feature_store
+ entity = Entity(name="driver", join_keys=["driver_id"])
+ store.apply(entity)
+
+ expected = store.get_entity(entity.name)
+
+ get_entity_request = RegistryServer_pb2.GetEntityRequest(
+ name=entity.name, project=store.project, allow_cache=False
+ )
+ response, trailing_metadata, code, details = call_registry_server(
+ registry_server, "GetEntity", get_entity_request
+ )
+ response_entity = Entity.from_proto(response)
+
+ assertpy.assert_that(response_entity).is_equal_to(expected)
+
+
+def test_registry_server_proto(environment, registry_server):
+ store: FeatureStore = environment.feature_store
+ entity = Entity(name="driver", join_keys=["driver_id"])
+ store.apply(entity)
+
+ expected = store.registry.proto()
+ response, trailing_metadata, code, details = call_registry_server(
+ registry_server, "Proto"
+ )
+
+ assertpy.assert_that(response).is_equal_to(expected)
diff --git a/sdk/python/tests/unit/test_sql_registry.py b/sdk/python/tests/unit/test_sql_registry.py
index 1c2b5a36ddf..b96dc6fe770 100644
--- a/sdk/python/tests/unit/test_sql_registry.py
+++ b/sdk/python/tests/unit/test_sql_registry.py
@@ -91,7 +91,7 @@ def mysql_registry():
container.start()
# The log string uses '8.0.*' since the version might be changed as new Docker images are pushed.
- log_string_to_wait_for = "/usr/sbin/mysqld: ready for connections. Version: '8.0.*' socket: '/var/run/mysqld/mysqld.sock' port: 3306"
+ log_string_to_wait_for = "/usr/sbin/mysqld: ready for connections. Version: '(\d+(\.\d+){1,2})' socket: '/var/run/mysqld/mysqld.sock' port: 3306" # noqa: W605
waited = wait_for_logs(
container=container,
predicate=log_string_to_wait_for,
@@ -103,7 +103,7 @@ def mysql_registry():
registry_config = RegistryConfig(
registry_type="sql",
- path=f"mysql+mysqldb://{POSTGRES_USER}:{POSTGRES_PASSWORD}@127.0.0.1:{container_port}/{POSTGRES_DB}",
+ path=f"mysql+pymysql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@127.0.0.1:{container_port}/{POSTGRES_DB}",
)
yield SqlRegistry(registry_config, "project", None)
diff --git a/sdk/python/tests/unit/test_type_map.py b/sdk/python/tests/unit/test_type_map.py
index 78ff15fe931..9b21900e6d7 100644
--- a/sdk/python/tests/unit/test_type_map.py
+++ b/sdk/python/tests/unit/test_type_map.py
@@ -48,3 +48,35 @@ def test_python_values_to_proto_values_bool(values):
converted = feast_value_type_to_python_type(protos[0])
assert converted is bool(values[0])
+
+
+@pytest.mark.parametrize(
+ "values, value_type, expected",
+ (
+ (np.array([b"[1,2,3]"]), ValueType.INT64_LIST, [1, 2, 3]),
+ (np.array([b"[1,2,3]"]), ValueType.INT32_LIST, [1, 2, 3]),
+ (np.array([b"[1.5,2.5,3.5]"]), ValueType.FLOAT_LIST, [1.5, 2.5, 3.5]),
+ (np.array([b"[1.5,2.5,3.5]"]), ValueType.DOUBLE_LIST, [1.5, 2.5, 3.5]),
+ (np.array([b'["a","b","c"]']), ValueType.STRING_LIST, ["a", "b", "c"]),
+ (np.array([b"[true,false]"]), ValueType.BOOL_LIST, [True, False]),
+ (np.array([b"[1,0]"]), ValueType.BOOL_LIST, [True, False]),
+ (np.array([None]), ValueType.STRING_LIST, None),
+ ([b"[1,2,3]"], ValueType.INT64_LIST, [1, 2, 3]),
+ ([b"[1,2,3]"], ValueType.INT32_LIST, [1, 2, 3]),
+ ([b"[1.5,2.5,3.5]"], ValueType.FLOAT_LIST, [1.5, 2.5, 3.5]),
+ ([b"[1.5,2.5,3.5]"], ValueType.DOUBLE_LIST, [1.5, 2.5, 3.5]),
+ ([b'["a","b","c"]'], ValueType.STRING_LIST, ["a", "b", "c"]),
+ ([b"[true,false]"], ValueType.BOOL_LIST, [True, False]),
+ ([b"[1,0]"], ValueType.BOOL_LIST, [True, False]),
+ ([None], ValueType.STRING_LIST, None),
+ ),
+)
+def test_python_values_to_proto_values_bytes_to_list(values, value_type, expected):
+ protos = python_values_to_proto_values(values, value_type)
+ converted = feast_value_type_to_python_type(protos[0])
+ assert converted == expected
+
+
+def test_python_values_to_proto_values_bytes_to_list_not_supported():
+ with pytest.raises(TypeError):
+ _ = python_values_to_proto_values([b"[]"], ValueType.BYTES_LIST)
diff --git a/sdk/python/tests/utils/e2e_test_validation.py b/sdk/python/tests/utils/e2e_test_validation.py
index bacc8c17206..d8c769f12c9 100644
--- a/sdk/python/tests/utils/e2e_test_validation.py
+++ b/sdk/python/tests/utils/e2e_test_validation.py
@@ -193,7 +193,7 @@ def make_feature_store_yaml(
repo_path=str(Path(repo_dir_name)),
entity_key_serialization_version=2,
)
- config_dict = config.dict()
+ config_dict = config.model_dump(by_alias=True)
if (
isinstance(config_dict["online_store"], dict)
and "redis_type" in config_dict["online_store"]
diff --git a/setup.py b/setup.py
index aee2ed0b3eb..d2327d36c57 100644
--- a/setup.py
+++ b/setup.py
@@ -31,7 +31,6 @@
from setuptools.command.install import install
except ImportError:
- from distutils.command.build_ext import build_ext as _build_ext
from distutils.command.build_py import build_py
from distutils.core import setup
@@ -46,19 +45,23 @@
"colorama>=0.3.9,<1",
"dill~=0.3.0",
"fastavro>=1.1.0,<2",
- "grpcio>=1.47.0,<2",
- "grpcio-reflection>=1.47.0,<2",
+ "grpcio>=1.56.2,<2",
+ "grpcio-tools>=1.56.2,<2",
+ "grpcio-reflection>=1.56.2,<2",
+ "grpcio-health-checking>=1.56.2,<2",
+ "mypy-protobuf==3.1",
"Jinja2>=2,<4",
"jsonschema",
"mmh3",
- "numpy>=1.22,<3",
+ "numpy>=1.22,<1.25",
"pandas>=1.4.3,<2",
# For some reason pandavro higher than 1.5.* only support pandas less than 1.3.
"pandavro~=1.5.0",
- "protobuf<5,>3.20",
+ # Higher than 4.23.4 seems to cause a seg fault
+ "protobuf<4.23.4,>3.20",
"proto-plus>=1.20.0,<2",
- "pyarrow>=4,<12",
- "pydantic>=1,<2",
+ "pyarrow>=4",
+ "pydantic>=2.0.0",
"pygments>=2.12.0,<3",
"PyYAML>=5.4.0,<7",
"requests",
@@ -67,32 +70,35 @@
"tenacity>=7,<9",
"toml>=0.10.0,<1",
"tqdm>=4,<5",
- "typeguard==2.13.3",
- "fastapi>=0.68.0,<1",
+ "typeguard>=4.0.0",
+ "fastapi>=0.68.0",
"uvicorn[standard]>=0.14.0,<1",
"gunicorn",
"dask>=2021.1.0",
"bowler", # Needed for automatic repo upgrades
# FastAPI does not correctly pull starlette dependency on httpx see thread(https://github.com/tiangolo/fastapi/issues/5656).
"httpx>=0.23.3",
+ "importlib-resources>=6.0.0,<7",
+ "importlib_metadata>=6.8.0,<7",
]
GCP_REQUIRED = [
"google-api-core>=1.23.0,<3",
"googleapis-common-protos>=1.52.0,<2",
- "google-cloud-bigquery[pandas]>=2,<4",
+ "google-cloud-bigquery[pandas]>=2,<3.13.0",
"google-cloud-bigquery-storage >= 2.0.0,<3",
"google-cloud-datastore>=2.1.0,<3",
"google-cloud-storage>=1.34.0,<3",
"google-cloud-bigtable>=2.11.0,<3",
+ "fsspec<=2024.1.0",
]
REDIS_REQUIRED = [
- "redis==4.2.2",
+ "redis>=4.2.2,<5",
"hiredis>=2.0.0,<3",
]
-AWS_REQUIRED = ["boto3>=1.17.0,<2", "docker>=5.0.2"]
+AWS_REQUIRED = ["boto3>=1.17.0,<2", "docker>=5.0.2", "fsspec<=2024.1.0"]
BYTEWAX_REQUIRED = ["bytewax==0.15.1", "docker>=5.0.2", "kubernetes<=20.13.0"]
@@ -110,7 +116,7 @@
"psycopg2-binary>=2.8.3,<3",
]
-MYSQL_REQUIRED = ["mysqlclient", "pymysql", "types-PyMySQL"]
+MYSQL_REQUIRED = ["pymysql", "types-PyMySQL"]
HBASE_REQUIRED = [
"happybase>=1.2.0,<3",
@@ -120,7 +126,7 @@
"cassandra-driver>=3.24.0,<4",
]
-GE_REQUIRED = ["great_expectations>=0.15.41,<0.16.0"]
+GE_REQUIRED = ["great_expectations>=0.15.41"]
AZURE_REQUIRED = [
"azure-storage-blob>=0.37.0",
@@ -141,20 +147,18 @@
CI_REQUIRED = (
[
"build",
+ "virtualenv==20.23.0",
"cryptography>=35.0,<42",
- "flake8",
+ "flake8>=6.0.0,<6.1.0",
"black>=22.6.0,<23",
"isort>=5,<6",
- "grpcio-tools>=1.47.0",
- "grpcio-testing>=1.47.0",
+ "grpcio-testing>=1.56.2,<2",
"minio==7.1.0",
"mock==2.0.0",
- "moto",
- "mypy>=0.981,<0.990",
- "mypy-protobuf==3.1",
+ "moto<5",
+ "mypy>=1.4.1",
"avro==1.10.0",
- "gcsfs>=0.4.0,<=2022.01.0",
- "urllib3>=1.25.4,<2",
+ "urllib3>=1.25.4,<3",
"psutil==5.9.0",
"py>=1.11.0", # https://github.com/pytest-dev/pytest/issues/10420
"pytest>=6.0.0,<8",
@@ -167,9 +171,8 @@
"pytest-mock==1.10.4",
"Sphinx>4.0.0,<7",
"testcontainers>=3.5,<4",
- "adlfs==0.5.9",
"firebase-admin>=5.2.0,<6",
- "pre-commit",
+ "pre-commit<3.3.2",
"assertpy==1.1",
"pip-tools",
"pybindgen",
@@ -178,9 +181,10 @@
"types-pytz",
"types-PyYAML",
"types-redis",
- "types-requests",
+ "types-requests<2.31.0",
"types-setuptools",
"types-tabulate",
+ "virtualenv<20.24.2",
]
+ GCP_REQUIRED
+ REDIS_REQUIRED
@@ -197,6 +201,7 @@
+ AZURE_REQUIRED
+ ROCKSET_REQUIRED
+ HAZELCAST_REQUIRED
+ + ["ibis-framework[duckdb]"]
)
@@ -229,7 +234,7 @@
else:
use_scm_version = None
-PROTO_SUBDIRS = ["core", "serving", "types", "storage"]
+PROTO_SUBDIRS = ["core", "registry", "serving", "types", "storage"]
PYTHON_CODE_PREFIX = "sdk/python"
@@ -379,8 +384,8 @@ def run(self):
use_scm_version=use_scm_version,
setup_requires=[
"setuptools_scm",
- "grpcio>=1.47.0",
- "grpcio-tools>=1.47.0",
+ "grpcio>=1.56.2,<2",
+ "grpcio-tools>=1.56.2,<2",
"mypy-protobuf==3.1",
"pybindgen==0.22.0",
],
diff --git a/ui/CONTRIBUTING.md b/ui/CONTRIBUTING.md
index 970bd3676cd..3c13759e260 100644
--- a/ui/CONTRIBUTING.md
+++ b/ui/CONTRIBUTING.md
@@ -91,7 +91,7 @@ The Feast UI is published as a module to NPM and can be found here: https://www.
### Requirements
To publish a new version of the module, you will need:
-- to be part of the @feast-dev team in NPM. Ask `#feast-development` on http://slack.feast.dev to add you if necessary.
+- to be part of the @feast-dev team in NPM.
- to [login to your NPM account on the command line](https://docs.npmjs.com/cli/v8/commands/npm-adduser).
### Steps for Publishing
diff --git a/ui/README.md b/ui/README.md
index e91a8741ec5..a9ce5d3ec73 100644
--- a/ui/README.md
+++ b/ui/README.md
@@ -46,7 +46,7 @@ ReactDOM.render(
);
```
-When you start the React app, it will look for `project-list.json` to find a list of your projects. The JSON should looks something like this.
+When you start the React app, it will look for `projects-list.json` to find a list of your projects. The JSON should looks something like this.
```json
{
diff --git a/ui/package.json b/ui/package.json
index 298efeffab7..c826737cf63 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -1,6 +1,6 @@
{
"name": "@feast-dev/feast-ui",
- "version": "0.31.0",
+ "version": "0.35.0",
"private": false,
"files": [
"dist"
diff --git a/ui/src/index.tsx b/ui/src/index.tsx
index 82c709d5d39..7559d02ebfd 100644
--- a/ui/src/index.tsx
+++ b/ui/src/index.tsx
@@ -97,7 +97,7 @@ ReactDOM.render(
reactQueryClient={queryClient}
feastUIConfigs={{
tabsRegistry: tabsRegistry,
- projectListPromise: fetch(process.env.PUBLIC_URL || "" + "/projects-list.json", {
+ projectListPromise: fetch((process.env.PUBLIC_URL || "") + "/projects-list.json", {
headers: {
"Content-Type": "application/json",
},
diff --git a/ui/yarn.lock b/ui/yarn.lock
index db6dacc906e..becb6bbd7ba 100644
--- a/ui/yarn.lock
+++ b/ui/yarn.lock
@@ -25,12 +25,13 @@
dependencies:
"@babel/highlight" "^7.16.7"
-"@babel/code-frame@^7.18.6", "@babel/code-frame@^7.21.4":
- version "7.21.4"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39"
- integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==
+"@babel/code-frame@^7.22.13":
+ version "7.22.13"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
+ integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
dependencies:
- "@babel/highlight" "^7.18.6"
+ "@babel/highlight" "^7.22.13"
+ chalk "^2.4.2"
"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.4", "@babel/compat-data@^7.16.8":
version "7.16.8"
@@ -106,12 +107,12 @@
jsesc "^2.5.1"
source-map "^0.5.0"
-"@babel/generator@^7.21.4":
- version "7.21.4"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.4.tgz#64a94b7448989f421f919d5239ef553b37bb26bc"
- integrity sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==
+"@babel/generator@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
+ integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
dependencies:
- "@babel/types" "^7.21.4"
+ "@babel/types" "^7.23.0"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
@@ -190,10 +191,10 @@
dependencies:
"@babel/types" "^7.16.7"
-"@babel/helper-environment-visitor@^7.18.9":
- version "7.18.9"
- resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
- integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
+"@babel/helper-environment-visitor@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
+ integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
"@babel/helper-explode-assignable-expression@^7.16.7":
version "7.16.7"
@@ -211,13 +212,13 @@
"@babel/template" "^7.16.7"
"@babel/types" "^7.16.7"
-"@babel/helper-function-name@^7.21.0":
- version "7.21.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4"
- integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==
+"@babel/helper-function-name@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+ integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
dependencies:
- "@babel/template" "^7.20.7"
- "@babel/types" "^7.21.0"
+ "@babel/template" "^7.22.15"
+ "@babel/types" "^7.23.0"
"@babel/helper-get-function-arity@^7.16.7":
version "7.16.7"
@@ -233,12 +234,12 @@
dependencies:
"@babel/types" "^7.16.7"
-"@babel/helper-hoist-variables@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
- integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
+"@babel/helper-hoist-variables@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
+ integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
dependencies:
- "@babel/types" "^7.18.6"
+ "@babel/types" "^7.22.5"
"@babel/helper-member-expression-to-functions@^7.16.7":
version "7.16.7"
@@ -328,28 +329,38 @@
dependencies:
"@babel/types" "^7.16.7"
-"@babel/helper-split-export-declaration@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
- integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
+"@babel/helper-split-export-declaration@^7.22.6":
+ version "7.22.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
+ integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
dependencies:
- "@babel/types" "^7.18.6"
+ "@babel/types" "^7.22.5"
"@babel/helper-string-parser@^7.19.4":
version "7.19.4"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
+"@babel/helper-string-parser@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
+ integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
+
"@babel/helper-validator-identifier@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad"
integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
-"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
+"@babel/helper-validator-identifier@^7.19.1":
version "7.19.1"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
+"@babel/helper-validator-identifier@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
+ integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
+
"@babel/helper-validator-option@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23"
@@ -392,16 +403,16 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@babel/highlight@^7.18.6":
- version "7.18.6"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
- integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
+"@babel/highlight@^7.22.13":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
+ integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
dependencies:
- "@babel/helper-validator-identifier" "^7.18.6"
- chalk "^2.0.0"
+ "@babel/helper-validator-identifier" "^7.22.20"
+ chalk "^2.4.2"
js-tokens "^4.0.0"
-"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.10", "@babel/parser@^7.16.12", "@babel/parser@^7.16.7":
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.12", "@babel/parser@^7.16.7":
version "7.16.12"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.12.tgz#9474794f9a650cf5e2f892444227f98e28cdf8b6"
integrity sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A==
@@ -411,10 +422,10 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0"
integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==
-"@babel/parser@^7.20.7", "@babel/parser@^7.21.4":
- version "7.21.4"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.4.tgz#94003fdfc520bbe2875d4ae557b43ddb6d880f17"
- integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==
+"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
+ integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
"@babel/parser@^7.9.4":
version "7.19.0"
@@ -1176,60 +1187,28 @@
"@babel/parser" "^7.16.7"
"@babel/types" "^7.16.7"
-"@babel/template@^7.20.7":
- version "7.20.7"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8"
- integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==
- dependencies:
- "@babel/code-frame" "^7.18.6"
- "@babel/parser" "^7.20.7"
- "@babel/types" "^7.20.7"
-
-"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.10", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.7.2":
- version "7.16.10"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.10.tgz#448f940defbe95b5a8029975b051f75993e8239f"
- integrity sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw==
- dependencies:
- "@babel/code-frame" "^7.16.7"
- "@babel/generator" "^7.16.8"
- "@babel/helper-environment-visitor" "^7.16.7"
- "@babel/helper-function-name" "^7.16.7"
- "@babel/helper-hoist-variables" "^7.16.7"
- "@babel/helper-split-export-declaration" "^7.16.7"
- "@babel/parser" "^7.16.10"
- "@babel/types" "^7.16.8"
- debug "^4.1.0"
- globals "^11.1.0"
-
-"@babel/traverse@^7.17.0", "@babel/traverse@^7.17.3":
- version "7.17.3"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57"
- integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==
- dependencies:
- "@babel/code-frame" "^7.16.7"
- "@babel/generator" "^7.17.3"
- "@babel/helper-environment-visitor" "^7.16.7"
- "@babel/helper-function-name" "^7.16.7"
- "@babel/helper-hoist-variables" "^7.16.7"
- "@babel/helper-split-export-declaration" "^7.16.7"
- "@babel/parser" "^7.17.3"
- "@babel/types" "^7.17.0"
- debug "^4.1.0"
- globals "^11.1.0"
-
-"@babel/traverse@^7.4.5":
- version "7.21.4"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.4.tgz#a836aca7b116634e97a6ed99976236b3282c9d36"
- integrity sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==
- dependencies:
- "@babel/code-frame" "^7.21.4"
- "@babel/generator" "^7.21.4"
- "@babel/helper-environment-visitor" "^7.18.9"
- "@babel/helper-function-name" "^7.21.0"
- "@babel/helper-hoist-variables" "^7.18.6"
- "@babel/helper-split-export-declaration" "^7.18.6"
- "@babel/parser" "^7.21.4"
- "@babel/types" "^7.21.4"
+"@babel/template@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
+ integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
+ dependencies:
+ "@babel/code-frame" "^7.22.13"
+ "@babel/parser" "^7.22.15"
+ "@babel/types" "^7.22.15"
+
+"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.10", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.0", "@babel/traverse@^7.17.3", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.2":
+ version "7.23.2"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
+ integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
+ dependencies:
+ "@babel/code-frame" "^7.22.13"
+ "@babel/generator" "^7.23.0"
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-function-name" "^7.23.0"
+ "@babel/helper-hoist-variables" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/parser" "^7.23.0"
+ "@babel/types" "^7.23.0"
debug "^4.1.0"
globals "^11.1.0"
@@ -1249,7 +1228,7 @@
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
-"@babel/types@^7.18.6", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.4":
+"@babel/types@^7.18.6", "@babel/types@^7.21.4":
version "7.21.4"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.4.tgz#2d5d6bb7908699b3b416409ffd3b5daa25b030d4"
integrity sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==
@@ -1258,6 +1237,15 @@
"@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0"
+"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
+ integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
+ dependencies:
+ "@babel/helper-string-parser" "^7.22.5"
+ "@babel/helper-validator-identifier" "^7.22.20"
+ to-fast-properties "^2.0.0"
+
"@base2/pretty-print-object@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz#371ba8be66d556812dc7fb169ebc3c08378f69d4"
@@ -2576,12 +2564,7 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
-"@types/node@*":
- version "17.0.13"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.13.tgz#5ed7ed7c662948335fcad6c412bb42d99ea754e3"
- integrity sha512-Y86MAxASe25hNzlDbsviXl8jQHb0RDvKt4c40ZJQ1Don0AAL0STLZSs4N+6gLEO55pedy7r2cLwS+ZDxPm/2Bw==
-
-"@types/node@>=13.7.0":
+"@types/node@*", "@types/node@>=13.7.0":
version "18.7.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.18.tgz#633184f55c322e4fb08612307c274ee6d5ed3154"
integrity sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==
@@ -3778,7 +3761,7 @@ chalk@4.1.1:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
-chalk@^2.0.0, chalk@^2.4.1:
+chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -5713,9 +5696,9 @@ focus-lock@^0.11.2:
tslib "^2.0.3"
follow-redirects@^1.0.0:
- version "1.14.7"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
- integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
+ version "1.15.4"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf"
+ integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==
fork-ts-checker-webpack-plugin@^6.5.0:
version "6.5.0"
@@ -9048,9 +9031,9 @@ protobufjs-cli@^1.0.2:
uglify-js "^3.7.7"
protobufjs@^7.1.1:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.1.1.tgz#0117befb4b0f5a49d028e93f2ca62c3c1f5e7c65"
- integrity sha512-d0nMQqS/aT3lfV8bKi9Gbg73vPd2LcDdTDOu6RE/M+h9DY8g1EmDzk3ADPccthEWfTBjkR2oxNdx9Gs8YubT+g==
+ version "7.2.4"
+ resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.4.tgz#3fc1ec0cdc89dd91aef9ba6037ba07408485c3ae"
+ integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==
dependencies:
"@protobufjs/aspromise" "^1.1.2"
"@protobufjs/base64" "^1.1.2"
@@ -9987,21 +9970,14 @@ semver@7.0.0:
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-
-semver@^7.1.2:
- version "7.3.7"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
- integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
- dependencies:
- lru-cache "^6.0.0"
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
-semver@^7.3.2, semver@^7.3.5:
- version "7.3.5"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
- integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
+semver@^7.1.2, semver@^7.3.2, semver@^7.3.5:
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
@@ -10740,13 +10716,14 @@ toidentifier@1.0.1:
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
tough-cookie@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4"
- integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf"
+ integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
dependencies:
psl "^1.1.33"
punycode "^2.1.1"
- universalify "^0.1.2"
+ universalify "^0.2.0"
+ url-parse "^1.5.3"
tr46@^1.0.1:
version "1.0.1"
@@ -11030,11 +11007,16 @@ unist-util-visit@^2.0.0, unist-util-visit@^2.0.3:
unist-util-is "^4.0.0"
unist-util-visit-parents "^3.0.0"
-universalify@^0.1.0, universalify@^0.1.2:
+universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+universalify@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0"
+ integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==
+
universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
@@ -11070,7 +11052,7 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
-url-parse@^1.5.10:
+url-parse@^1.5.10, url-parse@^1.5.3:
version "1.5.10"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1"
integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==
@@ -11727,9 +11709,9 @@ yocto-queue@^0.1.0:
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
zod@^3.11.6:
- version "3.19.1"
- resolved "https://registry.yarnpkg.com/zod/-/zod-3.19.1.tgz#112f074a97b50bfc4772d4ad1576814bd8ac4473"
- integrity sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==
+ version "3.22.3"
+ resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.3.tgz#2fbc96118b174290d94e8896371c95629e87a060"
+ integrity sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==
zwitch@^1.0.0:
version "1.0.5"