Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
7dca4f2
docs(samples): add samples for IN, NOT_IN, and != operators. (#312)
jlara310 Jun 16, 2022
4165569
fix: require python 3.7+ (#332)
gcf-owl-bot[bot] Jul 10, 2022
b8fc4a7
chore(deps): update all dependencies (#340)
renovate-bot Aug 2, 2022
9ac64db
docs: Move the schedule_export samples from python-docs-samples (#344)
Mariatta Aug 9, 2022
4c1a86e
docs(samples): Add an example of using read_time in queries and get()…
jlara310 Aug 12, 2022
5ba9865
chore(deps): update dependency google-cloud-datastore to v2.8.1 (#348)
renovate-bot Aug 17, 2022
9bc603d
chore(deps): update dependency pytest to v7.1.3 (#359)
renovate-bot Sep 6, 2022
926a83e
chore: detect samples tests in nested directories (#360)
gcf-owl-bot[bot] Sep 13, 2022
8acb74c
samples: Update the read_time snippet. (#363)
jlara310 Oct 3, 2022
420626c
chore(deps): update dependency google-cloud-datastore to v2.8.2 (#369)
renovate-bot Oct 4, 2022
5d87c1d
chore(deps): update dependency backoff to v2.2.1 (#371)
renovate-bot Oct 6, 2022
db4e1e5
chore(deps): update dependency google-cloud-datastore to v2.8.3 (#375)
renovate-bot Oct 18, 2022
d2a500c
chore(deps): update dependency google-cloud-datastore to v2.9.0 (#376)
renovate-bot Oct 19, 2022
5b20685
chore(deps): update dependency pytest to v7.2.0 (#377)
renovate-bot Oct 26, 2022
d548451
chore(deps): update dependency google-cloud-datastore to v2.10.0 (#381)
renovate-bot Nov 9, 2022
882a641
chore(python): drop flake8-import-order in samples noxfile (#387)
gcf-owl-bot[bot] Nov 25, 2022
bbf0e63
chore(deps): update dependency google-cloud-datastore to v2.11.0 (#389)
renovate-bot Dec 1, 2022
9bd061d
samples: Add snippets and samples for Count query (#383)
Mariatta Dec 9, 2022
332b10c
chore(deps): update dependency google-cloud-datastore to v2.11.1 (#394)
renovate-bot Jan 4, 2023
3a596ff
chore(python): add support for python 3.11 (#395)
gcf-owl-bot[bot] Jan 6, 2023
49582bd
chore(deps): update dependency google-cloud-datastore to v2.12.0 (#399)
renovate-bot Jan 10, 2023
c0eded0
chore(deps): update dependency pytest to v7.2.1 (#403)
renovate-bot Jan 14, 2023
5b29ad6
chore(deps): update dependency google-cloud-datastore to v2.13.0 (#405)
renovate-bot Jan 18, 2023
35a74b6
chore(deps): update dependency google-cloud-datastore to v2.13.1 (#409)
renovate-bot Jan 23, 2023
f1af17a
chore(deps): update dependency google-cloud-datastore to v2.13.2 (#411)
renovate-bot Jan 24, 2023
063ae13
chore(deps): update dependency google-cloud-datastore to v2.14.0 (#423)
renovate-bot Mar 1, 2023
4b2c1cf
chore(deps): update dependency pytest to v7.2.2 (#424)
renovate-bot Mar 3, 2023
34854c2
chore(deps): update dependency google-cloud-datastore to v2.15.0 (#426)
renovate-bot Mar 17, 2023
40f91e9
chore(deps): update dependency google-cloud-datastore to v2.15.1 (#431)
renovate-bot Apr 6, 2023
7afd3f9
chore(deps): update dependency pytest to v7.3.1 (#433)
renovate-bot Apr 18, 2023
7e8f382
chore(deps): update dependency google-cloud-datastore to v2.15.2 (#438)
renovate-bot Jun 1, 2023
2d9a735
chore(deps): update dependency pytest to v7.3.2 (#445)
renovate-bot Jun 12, 2023
f8664ee
chore(deps): update all dependencies (#449)
renovate-bot Jul 5, 2023
c932e56
chore(deps): update dependency google-cloud-datastore to v2.16.1 (#454)
renovate-bot Jul 5, 2023
8164e8d
chore(deps): update dependency google-cloud-datastore to v2.17.0 (#469)
renovate-bot Aug 9, 2023
4141fee
chore(deps): update all dependencies (#473)
renovate-bot Sep 5, 2023
d30a1a8
chore(deps): update all dependencies (#475)
renovate-bot Sep 15, 2023
9277a67
chore(deps): update all dependencies (#483)
renovate-bot Sep 18, 2023
62b7aec
samples: Add snippets for sum and avg (#480)
jlara310 Oct 3, 2023
9d881ec
chore(deps): update all dependencies (#493)
renovate-bot Oct 30, 2023
60ebad6
feat: Add support for Python 3.12 (#498)
gcf-owl-bot[bot] Dec 1, 2023
324bb24
chore(deps): update dependency google-cloud-datastore to v2.19.0 (#508)
renovate-bot Dec 12, 2023
702775e
chore(deps): update dependency pytest to v7.4.4 (#511)
renovate-bot Jan 22, 2024
dc7a4ad
feat: implement query profiling (#542)
daniel-sanche Aug 7, 2024
b705ba1
chore(deps): update all dependencies (#519)
renovate-bot Aug 14, 2024
9840d5d
chore(deps): update all dependencies (#563)
renovate-bot Sep 19, 2024
5ee3fdb
chore(python): update dependencies in .kokoro/docker/docs (#574)
gcf-owl-bot[bot] Nov 15, 2024
1ad71d8
chore(python): Add support for Python 3.14 (#644)
chalmerlowe Nov 11, 2025
9a4720d
chore(deps): update all dependencies (#660)
renovate-bot Feb 13, 2026
a0ce1b4
chore(deps): update all dependencies (#670)
renovate-bot Feb 13, 2026
38c1c94
Merge remote-tracking branch 'migration/main' into python-datastore-m…
chalmerlowe Feb 18, 2026
1ba5e19
fix: can't claim all rights reserved and be Apache 2.
iennae Feb 19, 2026
17a1442
fix: Update requirements-test.txt
iennae Feb 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
292 changes: 292 additions & 0 deletions datastore/samples/snippets/noxfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import print_function

import glob
import os
from pathlib import Path
import sys
from typing import Callable, Dict, Optional

import nox


# WARNING - WARNING - WARNING - WARNING - WARNING
# WARNING - WARNING - WARNING - WARNING - WARNING
# DO NOT EDIT THIS FILE EVER!
# WARNING - WARNING - WARNING - WARNING - WARNING
# WARNING - WARNING - WARNING - WARNING - WARNING

BLACK_VERSION = "black==22.3.0"
ISORT_VERSION = "isort==5.10.1"

# Copy `noxfile_config.py` to your directory and modify it instead.

# `TEST_CONFIG` dict is a configuration hook that allows users to
# modify the test configurations. The values here should be in sync
# with `noxfile_config.py`. Users will copy `noxfile_config.py` into
# their directory and modify it.

TEST_CONFIG = {
# You can opt out from the test for specific Python versions.
"ignored_versions": [],
# Old samples are opted out of enforcing Python type hints
# All new samples should feature them
"enforce_type_hints": False,
# An envvar key for determining the project id to use. Change it
# to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
# build specific Cloud project. You can also use your own string
# to use your own Cloud project.
"gcloud_project_env": "GOOGLE_CLOUD_PROJECT",
# 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
# If you need to use a specific version of pip,
# change pip_version_override to the string representation
# of the version number, for example, "20.2.4"
"pip_version_override": None,
# A dictionary you want to inject into your test. Don't put any
# secrets here. These values will override predefined values.
"envs": {},
}


try:
# Ensure we can import noxfile_config in the project's directory.
sys.path.append(".")
from noxfile_config import TEST_CONFIG_OVERRIDE
except ImportError as e:
print("No user noxfile_config found: detail: {}".format(e))
TEST_CONFIG_OVERRIDE = {}

# Update the TEST_CONFIG with the user supplied values.
TEST_CONFIG.update(TEST_CONFIG_OVERRIDE)


def get_pytest_env_vars() -> Dict[str, str]:
"""Returns a dict for pytest invocation."""
ret = {}

# Override the GCLOUD_PROJECT and the alias.
env_key = TEST_CONFIG["gcloud_project_env"]
# This should error out if not set.
ret["GOOGLE_CLOUD_PROJECT"] = os.environ[env_key]

# Apply user supplied envs.
ret.update(TEST_CONFIG["envs"])
return ret


# DO NOT EDIT - automatically generated.
# All versions used to test samples.
ALL_VERSIONS = ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]

# Any default versions that should be ignored.
IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"]

TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS])

INSTALL_LIBRARY_FROM_SOURCE = os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False) in (
"True",
"true",
)

# Error if a python version is missing
nox.options.error_on_missing_interpreters = True

#
# Style Checks
#


# Linting with flake8.
#
# We ignore the following rules:
# E203: whitespace before ‘:’
# E266: too many leading ‘#’ for block comment
# E501: line too long
# I202: Additional newline in a section of imports
#
# We also need to specify the rules which are ignored by default:
# ['E226', 'W504', 'E126', 'E123', 'W503', 'E24', 'E704', 'E121']
FLAKE8_COMMON_ARGS = [
"--show-source",
"--builtin=gettext",
"--max-complexity=20",
"--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py",
"--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202",
"--max-line-length=88",
]


@nox.session
def lint(session: nox.sessions.Session) -> None:
if not TEST_CONFIG["enforce_type_hints"]:
session.install("flake8")
else:
session.install("flake8", "flake8-annotations")

args = FLAKE8_COMMON_ARGS + [
".",
]
session.run("flake8", *args)


#
# Black
#


@nox.session
def blacken(session: nox.sessions.Session) -> None:
"""Run black. Format code to uniform standard."""
session.install(BLACK_VERSION)
python_files = [path for path in os.listdir(".") if path.endswith(".py")]

session.run("black", *python_files)


#
# format = isort + black
#

@nox.session
def format(session: nox.sessions.Session) -> None:
"""
Run isort to sort imports. Then run black
to format code to uniform standard.
"""
session.install(BLACK_VERSION, ISORT_VERSION)
python_files = [path for path in os.listdir(".") if path.endswith(".py")]

# Use the --fss option to sort imports using strict alphabetical order.
# See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections
session.run("isort", "--fss", *python_files)
session.run("black", *python_files)


#
# Sample Tests
#


PYTEST_COMMON_ARGS = ["--junitxml=sponge_log.xml"]


def _session_tests(
session: nox.sessions.Session, post_install: Callable = None
) -> None:
# check for presence of tests
test_list = glob.glob("**/*_test.py", recursive=True) + glob.glob("**/test_*.py", recursive=True)
test_list.extend(glob.glob("**/tests", recursive=True))

if len(test_list) == 0:
print("No tests found, skipping directory.")
return

if TEST_CONFIG["pip_version_override"]:
pip_version = TEST_CONFIG["pip_version_override"]
session.install(f"pip=={pip_version}")
"""Runs py.test for a particular project."""
Comment on lines +188 to +200
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The docstring for _session_tests is misplaced. It should be located immediately after the function signature on line 188 to follow standard Python conventions.

concurrent_args = []
if os.path.exists("requirements.txt"):
if os.path.exists("constraints.txt"):
session.install("-r", "requirements.txt", "-c", "constraints.txt")
else:
session.install("-r", "requirements.txt")
with open("requirements.txt") as rfile:
packages = rfile.read()

if os.path.exists("requirements-test.txt"):
if os.path.exists("constraints-test.txt"):
session.install(
"-r", "requirements-test.txt", "-c", "constraints-test.txt"
)
else:
session.install("-r", "requirements-test.txt")
with open("requirements-test.txt") as rtfile:
packages += rtfile.read()
Comment on lines +201 to +218
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The packages variable is used on line 218 but is only initialized if requirements.txt exists. If requirements.txt is not present but requirements-test.txt is, this will cause an UnboundLocalError. To prevent this, packages should be initialized to an empty string before the conditional blocks.

Suggested change
concurrent_args = []
if os.path.exists("requirements.txt"):
if os.path.exists("constraints.txt"):
session.install("-r", "requirements.txt", "-c", "constraints.txt")
else:
session.install("-r", "requirements.txt")
with open("requirements.txt") as rfile:
packages = rfile.read()
if os.path.exists("requirements-test.txt"):
if os.path.exists("constraints-test.txt"):
session.install(
"-r", "requirements-test.txt", "-c", "constraints-test.txt"
)
else:
session.install("-r", "requirements-test.txt")
with open("requirements-test.txt") as rtfile:
packages += rtfile.read()
concurrent_args = []
packages = ""
if os.path.exists("requirements.txt"):
if os.path.exists("constraints.txt"):
session.install("-r", "requirements.txt", "-c", "constraints.txt")
else:
session.install("-r", "requirements.txt")
with open("requirements.txt") as rfile:
packages = rfile.read()
if os.path.exists("requirements-test.txt"):
if os.path.exists("constraints-test.txt"):
session.install(
"-r", "requirements-test.txt", "-c", "constraints-test.txt"
)
else:
session.install("-r", "requirements-test.txt")
with open("requirements-test.txt") as rtfile:
packages += rtfile.read()


if INSTALL_LIBRARY_FROM_SOURCE:
session.install("-e", _get_repo_root())

if post_install:
post_install(session)

if "pytest-parallel" in packages:
concurrent_args.extend(['--workers', 'auto', '--tests-per-worker', 'auto'])
elif "pytest-xdist" in packages:
concurrent_args.extend(['-n', 'auto'])

session.run(
"pytest",
*(PYTEST_COMMON_ARGS + session.posargs + concurrent_args),
# Pytest will return 5 when no tests are collected. This can happen
# on travis where slow and flaky tests are excluded.
# See http://doc.pytest.org/en/latest/_modules/_pytest/main.html
success_codes=[0, 5],
env=get_pytest_env_vars(),
)


@nox.session(python=ALL_VERSIONS)
def py(session: nox.sessions.Session) -> None:
"""Runs py.test for a sample using the specified version of Python."""
if session.python in TESTED_VERSIONS:
_session_tests(session)
else:
session.skip(
"SKIPPED: {} tests are disabled for this sample.".format(session.python)
)


#
# Readmegen
#


def _get_repo_root() -> Optional[str]:
""" Returns the root folder of the project. """
# Get root of this repository. Assume we don't have directories nested deeper than 10 items.
p = Path(os.getcwd())
for i in range(10):
if p is None:
break
if Path(p / ".git").exists():
return str(p)
# .git is not available in repos cloned via Cloud Build
# setup.py is always in the library's root, so use that instead
# https://github.com/googleapis/synthtool/issues/792
if Path(p / "setup.py").exists():
return str(p)
p = p.parent
raise Exception("Unable to detect repository root.")


GENERATED_READMES = sorted([x for x in Path(".").rglob("*.rst.in")])


@nox.session
@nox.parametrize("path", GENERATED_READMES)
def readmegen(session: nox.sessions.Session, path: str) -> None:
"""(Re-)generates the readme for a sample."""
session.install("jinja2", "pyyaml")
dir_ = os.path.dirname(path)

if os.path.exists(os.path.join(dir_, "requirements.txt")):
session.install("-r", os.path.join(dir_, "requirements.txt"))

in_file = os.path.join(dir_, "README.rst.in")
session.run(
"python", _get_repo_root() + "/scripts/readme-gen/readme_gen.py", in_file
)
42 changes: 42 additions & 0 deletions datastore/samples/snippets/noxfile_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Default TEST_CONFIG_OVERRIDE for python repos.

# You can copy this file into your directory, then it will be imported from
# the noxfile.py.

# The source of truth:
# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/noxfile_config.py

TEST_CONFIG_OVERRIDE = {
# You can opt out from the test for specific Python versions.
"ignored_versions": [],
# Old samples are opted out of enforcing Python type hints
# All new samples should feature them
"enforce_type_hints": False,
# An envvar key for determining the project id to use. Change it
# to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
# build specific Cloud project. You can also use your own string
# to use your own Cloud project.
"gcloud_project_env": "BUILD_SPECIFIC_GCLOUD_PROJECT",
# 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
# If you need to use a specific version of pip,
# change pip_version_override to the string representation
# of the version number, for example, "20.2.4"
"pip_version_override": None,
# A dictionary you want to inject into your test. Don't put any
# secrets here. These values will override predefined values.
"envs": {},
}
7 changes: 7 additions & 0 deletions datastore/samples/snippets/requirements-test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
backoff===1.11.1; python_version < "3.7"
backoff==2.2.1; python_version >= "3.7"
pytest===7.4.3; python_version == '3.7'
pytest===8.3.5; python_version == '3.8'
pytest===8.4.2; python_version == '3.9'
pytest==9.0.2; python_version >= '3.10'
flaky==3.8.1
1 change: 1 addition & 0 deletions datastore/samples/snippets/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
google-cloud-datastore==2.23.0
5 changes: 5 additions & 0 deletions datastore/samples/snippets/schedule-export/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Scheduling Datastore exports with Cloud Functions and Cloud Scheduler

This sample application demonstrates how to schedule exports of your Datastore entities. To deploy this sample, see:

[Scheduling exports](https://cloud.google.com/datastore/docs/schedule-export)
Loading