diff --git a/.github/workflows/build-reusable.yml b/.github/workflows/build-reusable.yml new file mode 100644 index 00000000..724d6e41 --- /dev/null +++ b/.github/workflows/build-reusable.yml @@ -0,0 +1,117 @@ +# Copyright 2026 The TensorFlow GNN Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +name: Reusable Build +on: + workflow_call: + inputs: + + python_version: + description: 'Python version (overridden by kokoro_config if set)' + required: false + type: string + default: '3.11' + bazel_version: + description: 'Bazel version (overridden by kokoro_config if set)' + required: false + type: string + default: '7.4.1' + tf_version_spec: + description: 'TensorFlow version specifier' + required: false + type: string + keras_version_spec: + description: 'Keras version specifier' + required: false + type: string + artifact_name: + description: 'Name for uploaded wheel artifact' + required: true + type: string + nightly_build: + description: 'Whether to modify setup.py for tf-nightly' + required: false + type: boolean + default: false + run_tests: + description: 'Whether to run tests after building' + required: false + type: boolean + default: false + legacy_keras: + description: 'Value for TF_USE_LEGACY_KERAS' + required: false + type: string + default: '0' + build_tag_filters: + description: 'Bazel build tag filters' + required: false + type: string + default: '-no_oss,-oss_excluded' + test_tag_filters: + description: 'Bazel test tag filters' + required: false + type: string + default: '-no_oss,-oss_excluded' + nightly_env: + description: 'Whether to run checks for tf-nightly' + required: false + type: boolean + default: false + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # ratchet:actions/checkout@v4 + with: + ref: ${{ github.sha }} + persist-credentials: false + + - name: Setup Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # ratchet:actions/setup-python@v5 + with: + python-version: ${{ inputs.python_version }} + + - name: Build wheel + env: + USE_BAZEL_VERSION: ${{ inputs.bazel_version }} + TF_VERSION_SPEC: ${{ inputs.tf_version_spec }} + KERAS_VERSION_SPEC: ${{ inputs.keras_version_spec }} + NIGHTLY_BUILD: ${{ inputs.nightly_build }} + run: bash build-gha.sh + + # TBD - decide if want to upload it to GitHub at all + #- name: Upload wheel artifact + # uses: actions/upload-artifact@v4 + # with: + # name: ${{ inputs.artifact_name }} + # path: dist/*.whl + + - name: Run tests + if: inputs.run_tests + env: + USE_BAZEL_VERSION: ${{ inputs.bazel_version }} + TF_VERSION_SPEC: ${{ inputs.tf_version_spec }} + KERAS_VERSION_SPEC: ${{ inputs.keras_version_spec }} + TF_USE_LEGACY_KERAS: ${{ inputs.legacy_keras }} + BUILD_TAG_FILTERS: ${{ inputs.build_tag_filters }} + TEST_TAG_FILTERS: ${{ inputs.test_tag_filters }} + NIGHTLY_ENV: ${{ inputs.nightly_env }} + WHEEL_DIR: dist + run: bash test-gha.sh diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml new file mode 100644 index 00000000..fc38af08 --- /dev/null +++ b/.github/workflows/ci-build.yml @@ -0,0 +1,52 @@ +# Copyright 2026 The TensorFlow GNN Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +name: CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + # Don't cancel in-progress jobs for main branches. + cancel-in-progress: ${{ github.ref != 'main' }} + +jobs: + build-and-test-oldest: + uses: ./.github/workflows/build-reusable.yml + with: + python_version: '3.11' + tf_version_spec: 'tensorflow==2.12.*' + legacy_keras: '0' + build_tag_filters: '-no_oss,-oss_excluded,-tf_at_least_2_13' + test_tag_filters: '-no_oss,-oss_excluded,-tf_at_least_2_13' + artifact_name: 'tensorflow_gnn_oldest' + run_tests: true + + build-and-test-newest: + uses: ./.github/workflows/build-reusable.yml + with: + python_version: '3.11' + tf_version_spec: 'tensorflow==2.20.*' + legacy_keras: '1' + artifact_name: 'tensorflow_gnn_newest' + run_tests: true diff --git a/.gitignore b/.gitignore index 9c9c8d0e..085db355 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,48 @@ bazel-* -build +build/ dist *.egg-info + +# Python bytecode +__pycache__/ +*.py[cod] +*$py.class + +# Logs +*.log + +# Temporary/debug files +*.tmp +*.bak +*.swp +*.swo + +# OS files +.DS_Store +Thumbs.db + +# Build/test artifacts +build_*.txt +test_*.txt +test_output.log +clean_build_log.txt +error_context*.txt +failure_detail*.txt +failures_*.txt +install_log*.txt +installed_packages.txt +snippet*.txt +sha256.txt +workflow_log.txt + +# Docker test logs +docker_test_results*.log + +# IDE +.idea/ +.vscode/ +*.iml + +# Virtual environments +venv/ +.venv/ diff --git a/BUILD b/BUILD index 78a7dcb4..87a7fcdf 100644 --- a/BUILD +++ b/BUILD @@ -3,6 +3,7 @@ py_library( # This is a dummy rule used as a absl dependency in open-source. # We expect absl to already be installed on the system, e.g. via # `pip install absl` + # strict_deps = False, visibility = ["//visibility:public"], deps = [], ) @@ -12,6 +13,7 @@ py_library( # This is a dummy rule used as a absl dependency in open-source. # We expect absl to already be installed on the system, e.g. via # `pip install absl` + # strict_deps = False, visibility = ["//visibility:public"], deps = [], ) @@ -21,6 +23,7 @@ py_library( # This is a dummy rule used as a absl dependency in open-source. # We expect absl to already be installed on the system, e.g. via # `pip install absl` + # strict_deps = False, visibility = ["//visibility:public"], deps = [], ) @@ -30,6 +33,7 @@ py_library( # This is a dummy rule used as a numpy dependency in open-source. # We expect numpy to already be installed on the system, e.g. via # `pip install numpy` + # strict_deps = False, visibility = ["//visibility:public"], deps = [], ) @@ -39,6 +43,7 @@ py_library( # This is a dummy rule used as a tensorflow dependency in open-source. # We expect tensorflow to already be installed on the system, e.g. via # `pip install tensorflow` + # strict_deps = False, visibility = ["//visibility:public"], deps = [], ) @@ -48,6 +53,7 @@ py_library( # This is a dummy rule used as a ai-edge-litert dependency in open-source. # We expect ai-edge-litert to already be installed on the system, e.g. via # `pip install ai-edge-litert` + # strict_deps = False, visibility = ["//visibility:public"], deps = [], ) @@ -57,6 +63,7 @@ py_library( # This is a dummy rule used as a tensorflow dependency in open-source. # We expect tensorflow to already be installed on the system, e.g. via # `pip install tensorflow` + # strict_deps = False, visibility = ["//visibility:public"], deps = [], ) @@ -66,6 +73,7 @@ py_library( # This is a dummy rule used as a dependency on vizier.service.pyvizier in open-source. # We expect Vizier to already be installed on the system, e.g. via # `pip install google-vizier` and extra steps if needed (b/254806045). + # strict_deps = False, visibility = ["//visibility:public"], deps = [], ) @@ -75,6 +83,7 @@ py_library( # This is a dummy rule used as a mock dependency in open-source tests. # We expect mock to already be installed on the system, e.g. via # `pip install mock` + # strict_deps = False, visibility = ["//visibility:public"], deps = [], ) diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 00000000..4b905801 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,29 @@ +# Copyright 2026 The TensorFlow GNN Authors. All Rights Reserved. +# +# 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. +# ============================================================================== +module( + name = "tensorflow_gnn", + repo_name = "tensorflow_gnn", +) + +bazel_dep(name = "rules_python", version = "0.26.0") +bazel_dep(name = "python_shim", version = "0.0.0", repo_name = "python") +local_path_override( + module_name = "python_shim", + path = "python_shim", +) + +bazel_dep(name = "platforms", version = "0.0.11") +bazel_dep(name = "rules_proto", version = "5.3.0-21.7") +bazel_dep(name = "rules_license", version = "0.0.4") \ No newline at end of file diff --git a/WORKSPACE b/WORKSPACE index f25901bc..4f5803b7 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -2,8 +2,25 @@ workspace(name = "tensorflow_gnn") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +http_archive( + name = "platforms", + sha256 = "29742e87275809b5e598dc2f04d86960cc7a55b3067d97221c9abbc9926bff0f", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.11/platforms-0.0.11.tar.gz", + "https://github.com/bazelbuild/platforms/releases/download/0.0.11/platforms-0.0.11.tar.gz", + ], +) + +# Load custom Python configuration to override local_config_python +load("//:python_configure.bzl", "python_repository") + +python_repository(name = "local_config_python") + +register_toolchains("@local_config_python//:py_toolchain") + # Define the TensorFlow archive. load("@tensorflow_gnn//package:tfdep.bzl", "tf_setup") + tf_setup() http_archive( @@ -25,15 +42,23 @@ http_archive( # Initialize the TensorFlow repository and all dependencies. # See @org_tensorflow//WORKSPACE for details. load("@org_tensorflow//tensorflow:workspace3.bzl", "tf_workspace3") + tf_workspace3() + load("@org_tensorflow//tensorflow:workspace2.bzl", "tf_workspace2") + tf_workspace2() + load("@org_tensorflow//tensorflow:workspace1.bzl", "tf_workspace1") + tf_workspace1() + load("@org_tensorflow//tensorflow:workspace0.bzl", "tf_workspace0") + tf_workspace0() load("@rules_python//python:repositories.bzl", "py_repositories") + py_repositories() # This seems required to avoid a proxy setup. @@ -53,4 +78,4 @@ http_archive( "https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/0.0.4/rules_license-0.0.4.tar.gz", "https://github.com/bazelbuild/rules_license/releases/download/0.0.4/rules_license-0.0.4.tar.gz", ], -) \ No newline at end of file +) diff --git a/build-gha.sh b/build-gha.sh new file mode 100644 index 00000000..ae49f852 --- /dev/null +++ b/build-gha.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Copyright 2026 The TensorFlow GNN Authors. All Rights Reserved. +# +# 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. +# ============================================================================== + +# Build script for GitHub Actions — extracted from build-reusable.yml +# Expects env vars: TF_VERSION_SPEC, KERAS_VERSION_SPEC, NIGHTLY_BUILD +set -e +set -x + +echo "=== Installing dependencies ===" +pip install --upgrade pip +pip install . --progress-bar off +pip install ${TF_VERSION_SPEC} ${KERAS_VERSION_SPEC} --progress-bar off --upgrade + +echo "=== Building wheel ===" +if [[ "${NIGHTLY_BUILD}" == "true" ]]; then + perl -i -lpe '$k+= s/tensorflow>=2\.[0-9]+\.[0-9]+(,<=?[0-9.]+)?;/tf-nightly;/g; END{exit($k != 1)}' setup.py +fi +python setup.py bdist_wheel + +echo "=== Build complete ===" +ls -la dist/*.whl diff --git a/kokoro/github/ubuntu/cpu/build.sh b/kokoro/github/ubuntu/cpu/build.sh index 980b7768..0e6a82dc 100644 --- a/kokoro/github/ubuntu/cpu/build.sh +++ b/kokoro/github/ubuntu/cpu/build.sh @@ -32,16 +32,18 @@ cd "${KOKORO_ARTIFACTS_DIR}/github/gnn/" PIP_TEST_PREFIX=bazel_pip -python -m venv venv -source venv/bin/activate +python -m venv build_venv +source build_venv/bin/activate # Check the python version python --version -python3 --version # update pip pip install --upgrade pip +# Install build +pip install build + TEST_ROOT=$(pwd)/${PIP_TEST_PREFIX} rm -rf "$TEST_ROOT" mkdir -p "$TEST_ROOT" @@ -55,25 +57,34 @@ if [[ -n "${USE_BAZEL_VERSION}" && $(bazel --version) != *${USE_BAZEL_VERSION}* fi bazel clean -pip install -r requirements-dev.txt --progress-bar off -pip install tf-keras-nightly tf-nightly --progress-bar off --upgrade -# We need to remove the dependency on tensorflow to test nightly -# The dependencies will be provided by tf-nightly -perl -i -lpe '$k+= s/tensorflow>=2\.[0-9]+\.[0-9]+(,<=?[0-9.]+)?;/tf-nightly;/g; END{exit($k != 1)}' setup.py -# tf-nightly 2.21 lifted the protobuf version to what google-vizier 0.1.24 wants -# but what google-vizier 0.1.21 together with apache-beam does not allow. -# TODO: b/482003228 - Replace this patch by a proper dependency cleanup. -perl -i -lpe '$k+= s/google-vizier>=0.0.13,!=0.1.23,!=0.1.24/google-vizier>=0.0.13,!=0.1.23/g; END{exit($k != 1)}' setup.py -python3 setup.py bdist_wheel -pip uninstall -y tensorflow_gnn +pip install --group test-nightly --progress-bar off --upgrade +python3 -m build --wheel +deactivate + +# Start the test environment. +python3 -m venv test_venv +source test_venv/bin/activate + +# Check the python version +python --version + +pip install --upgrade pip pip install dist/tensorflow_gnn-*.whl +pip uninstall -y tensorflow tf-keras ai-edge-litert +pip install --group test-nightly --progress-bar off --upgrade echo "Final packages after all pip commands:" pip list # Check that tf-nightly is installed but tensorflow is not # Also check that tf-keras-nightly is installed. -pip freeze | grep -q tf-nightly= && ! pip freeze | grep -q tensorflow= -pip freeze | grep -q tf-keras-nightly= && ! pip freeze | grep -q tf-keras= +if [[ $(pip freeze | grep -q tf_nightly=; echo $?) -eq 0 && $(pip freeze | grep -q tensorflow=; echo $?) -eq 0 ]]; then + echo "Found tensorflow and tf_nightly in the environment." + exit 1 +fi +if [[ $(pip freeze | grep -q tf_keras-nightly=; echo $?) -eq 0 && $(pip freeze | grep -q tf_keras=; echo $?) -eq 0 ]]; then + echo "Found tf_keras and tf_keras-nightly in the environment." + exit 1 +fi # The env variable is needed to ensure that TF keras still behaves like keras 2 bazel test --test_env="TF_USE_LEGACY_KERAS=1" --build_tag_filters="${tag_filters}" --test_tag_filters="${tag_filters}" --test_output=errors --verbose_failures=true --build_tests_only --define=no_tfgnn_py_deps=true --keep_going --experimental_repo_remote_exec //bazel_pip/tensorflow_gnn/... diff --git a/kokoro/github/ubuntu/cpu/build_versioned.sh b/kokoro/github/ubuntu/cpu/build_versioned.sh index e2e6238c..ba38fd7d 100644 --- a/kokoro/github/ubuntu/cpu/build_versioned.sh +++ b/kokoro/github/ubuntu/cpu/build_versioned.sh @@ -19,6 +19,18 @@ set -x PYENV_ROOT="/home/kbuilder/.pyenv" PYTHON_VERSION=${PYTHON_VERSION:-"3.11"} +function force_tensorflow_version() { + if [[ -z "${TF_VERSION}" ]]; then + echo "TF_VERSION is not set. Not forcing tensorflow version." + return + fi + + pip install tensorflow=="${TF_VERSION}" --progress-bar off --upgrade + if [[ "$TF_USE_LEGACY_KERAS" == 1 ]]; then + pip install tf-keras=="${TF_VERSION}" --progress-bar off --upgrade + fi +} + echo "Installing pyenv.." git clone https://github.com/pyenv/pyenv.git "$PYENV_ROOT" export PATH="/home/kbuilder/.local/bin:$PYENV_ROOT/bin:$PATH" @@ -32,16 +44,18 @@ cd "${KOKORO_ARTIFACTS_DIR}/github/gnn/" PIP_TEST_PREFIX=bazel_pip -python -m venv venv -source venv/bin/activate +python -m venv build_venv +source build_venv/bin/activate # Debug messages to indicate the python version python --version -python3 --version # update pip pip install --upgrade pip +# Install build +pip install build + TEST_ROOT=$(pwd)/${PIP_TEST_PREFIX} rm -rf "$TEST_ROOT" mkdir -p "$TEST_ROOT" @@ -62,13 +76,27 @@ if [[ -n "${USE_BAZEL_VERSION}" && $(bazel --version) != *${USE_BAZEL_VERSION}* fi bazel clean -pip install -r requirements-dev.txt --progress-bar off -pip install tensorflow=="${TF_VERSION}" --progress-bar off --upgrade +force_tensorflow_version +python3 -m build --wheel +deactivate + +# Start the test environment. +python3 -m venv test_venv +source test_venv/bin/activate + +# Check the python version +python --version + +# update pip +pip install --upgrade pip +force_tensorflow_version + if [[ "$TF_USE_LEGACY_KERAS" == 1 ]]; then - pip install tf-keras=="${TF_VERSION}" --progress-bar off --upgrade + pip install --group test-tf216plus --progress-bar off --upgrade +else + pip install --group test-pre-tf216 --progress-bar off --upgrade fi -python3 setup.py bdist_wheel -pip uninstall -y tensorflow_gnn + pip install dist/tensorflow_gnn-*.whl echo "Final packages after all pip commands:" diff --git a/kokoro/github/ubuntu/cpu/continuous.cfg b/kokoro/github/ubuntu/cpu/continuous.cfg index 37bda92b..dad6cf34 100644 --- a/kokoro/github/ubuntu/cpu/continuous.cfg +++ b/kokoro/github/ubuntu/cpu/continuous.cfg @@ -1,9 +1,5 @@ build_file: "gnn/kokoro/github/ubuntu/cpu/build.sh" -env_vars: { - key: "USE_BAZEL_VERSION" - value: "7.4.1" # TODO - b/390391579: Unpin once bazel 8 works. -} env_vars: { key: "PYTHON_VERSION" value: "3.11" diff --git a/kokoro/github/ubuntu/cpu/newest_stable/continuous.cfg b/kokoro/github/ubuntu/cpu/newest_stable/continuous.cfg index 890a2916..fe95bbb4 100644 --- a/kokoro/github/ubuntu/cpu/newest_stable/continuous.cfg +++ b/kokoro/github/ubuntu/cpu/newest_stable/continuous.cfg @@ -1,9 +1,5 @@ build_file: "gnn/kokoro/github/ubuntu/cpu/build_versioned.sh" -env_vars: { - key: "USE_BAZEL_VERSION" - value: "7.4.1" # TODO - b/390391579: Unpin once bazel 8 works. -} env_vars: { key: "PYTHON_VERSION" value: "3.11" diff --git a/kokoro/github/ubuntu/cpu/newest_stable/presubmit.cfg b/kokoro/github/ubuntu/cpu/newest_stable/presubmit.cfg index 890a2916..fe95bbb4 100644 --- a/kokoro/github/ubuntu/cpu/newest_stable/presubmit.cfg +++ b/kokoro/github/ubuntu/cpu/newest_stable/presubmit.cfg @@ -1,9 +1,5 @@ build_file: "gnn/kokoro/github/ubuntu/cpu/build_versioned.sh" -env_vars: { - key: "USE_BAZEL_VERSION" - value: "7.4.1" # TODO - b/390391579: Unpin once bazel 8 works. -} env_vars: { key: "PYTHON_VERSION" value: "3.11" diff --git a/kokoro/github/ubuntu/cpu/oldest/continuous.cfg b/kokoro/github/ubuntu/cpu/oldest/continuous.cfg index aa98234d..d5dc9298 100644 --- a/kokoro/github/ubuntu/cpu/oldest/continuous.cfg +++ b/kokoro/github/ubuntu/cpu/oldest/continuous.cfg @@ -1,9 +1,5 @@ build_file: "gnn/kokoro/github/ubuntu/cpu/build_versioned.sh" -env_vars: { - key: "USE_BAZEL_VERSION" - value: "7.4.1" # TODO - b/390391579: Unpin once bazel 8 works. -} env_vars: { key: "PYTHON_VERSION" value: "3.11" diff --git a/kokoro/github/ubuntu/cpu/oldest/presubmit.cfg b/kokoro/github/ubuntu/cpu/oldest/presubmit.cfg index aa98234d..d5dc9298 100644 --- a/kokoro/github/ubuntu/cpu/oldest/presubmit.cfg +++ b/kokoro/github/ubuntu/cpu/oldest/presubmit.cfg @@ -1,9 +1,5 @@ build_file: "gnn/kokoro/github/ubuntu/cpu/build_versioned.sh" -env_vars: { - key: "USE_BAZEL_VERSION" - value: "7.4.1" # TODO - b/390391579: Unpin once bazel 8 works. -} env_vars: { key: "PYTHON_VERSION" value: "3.11" diff --git a/kokoro/github/ubuntu/cpu/presubmit.cfg b/kokoro/github/ubuntu/cpu/presubmit.cfg index 37bda92b..dad6cf34 100644 --- a/kokoro/github/ubuntu/cpu/presubmit.cfg +++ b/kokoro/github/ubuntu/cpu/presubmit.cfg @@ -1,9 +1,5 @@ build_file: "gnn/kokoro/github/ubuntu/cpu/build.sh" -env_vars: { - key: "USE_BAZEL_VERSION" - value: "7.4.1" # TODO - b/390391579: Unpin once bazel 8 works. -} env_vars: { key: "PYTHON_VERSION" value: "3.11" diff --git a/package/tfdep.bzl b/package/tfdep.bzl index 59253cea..4929ef89 100644 --- a/package/tfdep.bzl +++ b/package/tfdep.bzl @@ -3,7 +3,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") def tf_setup(): - """Define tensorflow>=2.13.0 dependency for Bazel build. + """Define tensorflow>=2.15.0 dependency for Bazel build. This downloads the TensorFlow files required for building TFGNN protos (examples and graph_schema).This TF version should always be within our supported range and gets @@ -13,9 +13,9 @@ def tf_setup(): """ http_archive( name = "org_tensorflow", - sha256 = "e58c939079588623e6fa1d054aec2f90f95018266e0a970fd353a5244f5173dc", + sha256 = "9cec5acb0ecf2d47b16891f8bc5bc6fbfdffe1700bdadc0d9ebe27ea34f0c220", urls = [ - "https://github.com/tensorflow/tensorflow/archive/refs/tags/v2.13.0.tar.gz", + "https://github.com/tensorflow/tensorflow/archive/refs/tags/v2.15.0.tar.gz", ], - strip_prefix = "tensorflow-2.13.0", + strip_prefix = "tensorflow-2.15.0", ) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..04a89e97 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,91 @@ +[project] +name = "tensorflow_gnn" +description = "A library for building scalable graph neural networks in TensorFlow." +# TODO(b/316329189): The relative links from README.md don't work on PyPI. +readme = "README.md" +keywords = ["tensorflow", "gnn", "graph"] +dynamic = ["version"] +license = "Apache-2.0" +requires-python = ">=3.9, <4" +dependencies = [ + "google-vizier>=0.0.13, !=0.1.23, !=0.1.24", # b/394062744 + "ml-collections>=1.1.0", + "networkx>=3.6.1", + "pyarrow>=18.1.0", + "tensorflow>=2.12.0, <3; platform_machine != 'arm64' or platform_system != 'Darwin'", + "tensorflow-macos>=2.12.0, <3; platform_machine == 'arm64' and platform_system == 'Darwin'", + "apache-beam>=2.54.0,<2.67.0", + # This dependency comes from apache beam implementing it as an extra for 2.70. + # To maintain current compatibility with pre and post 2.70, we need to include it here. b/465442394 + "crcmod>=1.7, <2", +] +authors = [ + {name = "Google LLC", email = "tensorflow-gnn@googlegroups.com"}, +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Operating System :: MacOS :: MacOS X", + "Operating System :: POSIX :: Linux", + "Operating System :: Microsoft :: Windows", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Topic :: Scientific/Engineering", + "Topic :: Scientific/Engineering :: Artificial Intelligence", + "Topic :: Scientific/Engineering :: Mathematics", + "Topic :: Software Development", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Libraries :: Python Modules", +] + +[project.urls] +homepage = "https://github.com/tensorflow/gnn" +source = "https://github.com/tensorflow/gnn.git" + +[dependency-groups] +test-base = [ + "mock", +] +test-pre-tf216 = [ + "ai-edge-litert", + {include-group = "test-base"}, +] +test-tf216plus = [ + "tf-keras", + {include-group = "test-pre-tf216"}, +] +test-nightly = [ + "tf-nightly", + "tf-keras-nightly", + "ai-edge-litert-nightly", + "google-vizier==0.1.24", # b/394062744 + {include-group = "test-base"}, +] + +[project.scripts] +tfgnn_convert_ogb_dataset = 'tensorflow_gnn.converters.ogb.convert_ogb_dataset:main' +tfgnn_sampler = 'tensorflow_gnn.experimental.sampler.beam.sampler:main' +# copybara:comment_begin(NetworkX utils) +tfgnn_nx_converter = 'tensorflow_gnn.sampler.nx_converter:main' +tfgnn_nx_generator = 'tensorflow_gnn.sampler.nx_generator:main' +# copybara:comment_end +tfgnn_generate_training_data = 'tensorflow_gnn.tools.generate_training_data:main' +tfgnn_print_training_data = 'tensorflow_gnn.tools.print_training_data:main' +tfgnn_sampled_stats = 'tensorflow_gnn.tools.sampled_stats:main' +tfgnn_validate_graph_schema = 'tensorflow_gnn.tools.validate_graph_schema:main' + +[build-system] +requires = ["setuptools", "numpy"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.dynamic] +version = {attr = "tensorflow_gnn.version.__version__"} + +[tool.setuptools.packages.find] +exclude = ["examples*", "package*", "testdata*", "build*", "bazel*"] + +[tool.setuptools.package-data] +tensorflow_gnn = ["*.proto"] + diff --git a/python_configure.bzl b/python_configure.bzl new file mode 100644 index 00000000..c164c1be --- /dev/null +++ b/python_configure.bzl @@ -0,0 +1,37 @@ +"""Custom Python configuration for Bazel.""" + +def _python_repository_impl(repository_ctx): + """Implementation of custom Python repository rule.""" + python_bin = repository_ctx.os.environ.get("PYTHON_BIN_PATH", "/usr/bin/python3") + + # Generate BUILD file with explicit Python paths + repository_ctx.file("BUILD", """# Auto-generated by python_configure.bzl +# This file overrides TensorFlow's local_config_python to provide explicit Python paths + +load("@bazel_tools//tools/python:toolchain.bzl", "py_runtime_pair") + +py_runtime( + name = "py3_runtime", + interpreter_path = "{python_bin}", + python_version = "PY3", + visibility = ["//visibility:public"], +) + +py_runtime_pair( + name = "py_runtime_pair", + py2_runtime = None, + py3_runtime = ":py3_runtime", +) + +toolchain( + name = "py_toolchain", + toolchain = ":py_runtime_pair", + toolchain_type = "@bazel_tools//tools/python:toolchain_type", +) +""".format(python_bin = python_bin)) + +python_repository = repository_rule( + implementation = _python_repository_impl, + environ = ["PYTHON_BIN_PATH"], + local = True, +) diff --git a/python_shim/BUILD b/python_shim/BUILD new file mode 100644 index 00000000..41fc71b6 --- /dev/null +++ b/python_shim/BUILD @@ -0,0 +1 @@ +# Empty BUILD file diff --git a/python_shim/MODULE.bazel b/python_shim/MODULE.bazel new file mode 100644 index 00000000..9753a491 --- /dev/null +++ b/python_shim/MODULE.bazel @@ -0,0 +1,19 @@ +# Copyright 2026 The TensorFlow GNN Authors. All Rights Reserved. +# +# 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. +# ============================================================================== +module( + name = "python_shim", +) + +bazel_dep(name = "rules_python", version = "0.26.0") diff --git a/python_shim/defs.bzl b/python_shim/defs.bzl new file mode 100644 index 00000000..6c1644f8 --- /dev/null +++ b/python_shim/defs.bzl @@ -0,0 +1,9 @@ +"""Python shim definitions for TensorFlow GNN open source build.""" + +load("@rules_python//python:defs.bzl", _py_binary = "py_binary", _py_library = "py_library", _py_test = "py_test") + +py_binary = _py_binary +py_library = _py_library +py_test = _py_test + +interpreter = "python3" diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 680bce7d..00000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,4 +0,0 @@ -mock -wheel -# includes glibcxx older than 3.4.29 -ai-edge-litert-nightly \ No newline at end of file diff --git a/setup.py b/setup.py index 23504f8e..cc7a5c7c 100644 --- a/setup.py +++ b/setup.py @@ -16,19 +16,21 @@ import os import platform +import shutil import subprocess import sys import setuptools -from setuptools import find_namespace_packages +# from setuptools import find_namespace_packages from setuptools import setup from setuptools.command.install import install from setuptools.dist import Distribution # pylint:disable=g-bad-import-order # setuptools must be imported prior to distutils. # TODO(b/317036825): Stop using distutils, Python 3.12 doesn't have it. -from distutils import spawn +# pylint: disable=deprecated-module from distutils.command import build +# pylint: enable=deprecated-module # pylint:enable=g-bad-import-order @@ -46,7 +48,6 @@ class _BuildCommand(build.build): - pip install . (which invokes bdist_wheel) - python setup.py install (which invokes install command) - python setup.py bdist_wheel (which invokes bdist_wheel command) - """ def _build_cc_extensions(self): @@ -57,7 +58,8 @@ def _build_cc_extensions(self): # sequentially when running a "build" command, if the second item in the tuple # (predicate method) is evaluated to true. sub_commands = [ - ('bazel_build', _build_cc_extensions)] + build.build.sub_commands + ('bazel_build', _build_cc_extensions) + ] + build.build.sub_commands class _BazelBuildCommand(setuptools.Command): @@ -71,12 +73,13 @@ def initialize_options(self): pass def finalize_options(self): - self._bazel_cmd = spawn.find_executable('bazel') + self._bazel_cmd = shutil.which('bazel') if not self._bazel_cmd: raise RuntimeError( 'Could not find "bazel" binary. Please visit ' 'https://docs.bazel.build/versions/master/install.html for ' - 'installation instruction.') + 'installation instruction.' + ) self._additional_build_options = [] if platform.system() == 'Darwin': self._additional_build_options = ['--macos_minimum_os=10.9'] @@ -85,14 +88,14 @@ def finalize_options(self): def run(self): subprocess.check_call( - [self._bazel_cmd, - 'run', '-c', 'opt', '--experimental_repo_remote_exec'] + - self._additional_build_options + - ['@tensorflow_gnn//package:move_generated_files'], + [self._bazel_cmd, 'run', '-c', 'opt', '--experimental_repo_remote_exec'] + + self._additional_build_options + + ['package:move_generated_files'], # Bazel should be invoked in a directory containing bazel WORKSPACE # file, which is the root directory. cwd=os.path.dirname(os.path.realpath(__file__)), - env=dict(os.environ, PYTHON_BIN_PATH=sys.executable)) + env=dict(os.environ, PYTHON_BIN_PATH=sys.executable), + ) # TFDV is not a purelib. However because of the extension module is not built @@ -121,90 +124,17 @@ def get_version(): sys.path.insert(0, version_path) # pytype: disable=import-error # pylint: disable=g-import-not-at-top from version import __version__ as v - return v - -# Get the long description from the README file. -# TODO(b/316329189): The relative links from README.md don't work on PyPI. -with open('README.md') as fp: - _LONG_DESCRIPTION = fp.read() - - -console_scripts = [ - 'tensorflow_gnn.converters.ogb.convert_ogb_dataset', - 'tensorflow_gnn.experimental.sampler.beam.sampler', - # copybara:uncomment_begin(NetworkX utils) - # 'tensorflow_gnn.sampler.nx_converter', - # 'tensorflow_gnn.sampler.nx_generator', - # copybara:uncomment_end - 'tensorflow_gnn.tools.generate_training_data', - 'tensorflow_gnn.tools.print_training_data', - 'tensorflow_gnn.tools.sampled_stats', - 'tensorflow_gnn.tools.validate_graph_schema', -] + return v setup( name='tensorflow-gnn', version=get_version(), - author='Google LLC', - author_email='tensorflow-gnn@googlegroups.com', - license='Apache 2.0', - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: MacOS :: MacOS X', - 'Operating System :: POSIX :: Linux', - 'Operating System :: Microsoft :: Windows', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3 :: Only', - 'Topic :: Scientific/Engineering', - 'Topic :: Scientific/Engineering :: Artificial Intelligence', - 'Topic :: Scientific/Engineering :: Mathematics', - 'Topic :: Software Development', - 'Topic :: Software Development :: Libraries', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], - namespace_packages=[], - install_requires=[ - 'google-vizier>=0.0.13,!=0.1.23,!=0.1.24', # b/394062744 - 'ml-collections', - 'networkx', - 'pyarrow', - # pylint:disable=g-line-too-long - 'tensorflow>=2.12.0,<3; platform_machine != "arm64" or platform_system != "Darwin"', - 'tensorflow-macos>=2.12.0,<3; platform_machine == "arm64" and platform_system == "Darwin"', - # pylint:enable=g-line-too-long - 'apache-beam>=2.54.0', - 'crcmod>=1.7,<2', - ], - python_requires='>=3.9,<4', - packages=find_namespace_packages( - exclude=['examples*', 'package*', 'testdata*'], - ), - include_package_data=True, - package_data={'': ['*.proto']}, - zip_safe=False, distclass=_SourceDistributionWithProtos, - description='A library for building scalable graph neural networks in TensorFlow.', - long_description=_LONG_DESCRIPTION, - long_description_content_type='text/markdown', - keywords='tensorflow gnn graph', - url='https://github.com/tensorflow/gnn', - download_url='https://github.com/tensorflow/gnn.git', - requires=[], cmdclass={ 'install': _InstallPlatlibCommand, 'build': _BuildCommand, 'bazel_build': _BazelBuildCommand, }, - entry_points={ - 'console_scripts': [ - 'tfgnn_{}={}:main'.format(libname.split('.')[-1], libname) - for libname in console_scripts - ], - } ) diff --git a/tensorflow_gnn/BUILD b/tensorflow_gnn/BUILD index 83f2fde3..d6a4d901 100644 --- a/tensorflow_gnn/BUILD +++ b/tensorflow_gnn/BUILD @@ -34,6 +34,7 @@ pytype_strict_library( visibility = ["//visibility:public"], deps = [ ":version", + "//:expect_tensorflow_installed", "//tensorflow_gnn/experimental", "//tensorflow_gnn/graph:adjacency", "//tensorflow_gnn/graph:batching_utils", diff --git a/tensorflow_gnn/LICENSE b/tensorflow_gnn/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/tensorflow_gnn/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/tensorflow_gnn/__init__.py b/tensorflow_gnn/__init__.py index 7a4b2a70..e475d2e7 100644 --- a/tensorflow_gnn/__init__.py +++ b/tensorflow_gnn/__init__.py @@ -48,10 +48,26 @@ def _check_keras_version(): # pylint: disable=line-too-long +import typing as _typing + from tensorflow_gnn import experimental # Exposed as submodule. pylint: disable=unused-import from tensorflow_gnn import keras # Exposed as submodule. pylint: disable=unused-import -from tensorflow_gnn import proto # Exposed as submodule. pylint: disable=unused-import -from tensorflow_gnn import sampler # Exposed as submodule. pylint: disable=unused-import + +if _typing.TYPE_CHECKING: + from tensorflow_gnn import proto +else: + try: + from tensorflow_gnn import proto # Exposed as submodule. pylint: disable=unused-import + except ImportError: + proto = None + +if _typing.TYPE_CHECKING: + from tensorflow_gnn import sampler +else: + try: + from tensorflow_gnn import sampler # Exposed as submodule. pylint: disable=unused-import + except ImportError: + sampler = None from tensorflow_gnn import version from tensorflow_gnn.graph import adjacency from tensorflow_gnn.graph import batching_utils @@ -68,8 +84,13 @@ def _check_keras_version(): from tensorflow_gnn.graph import pool_ops from tensorflow_gnn.graph import preprocessing_common from tensorflow_gnn.graph import readout -from tensorflow_gnn.graph import schema_utils -from tensorflow_gnn.graph import schema_validation +# schema_utils and schema_validation depend on proto; import conditionally. +if proto is not None: + from tensorflow_gnn.graph import schema_utils + from tensorflow_gnn.graph import schema_validation +else: + schema_utils = None + schema_validation = None from tensorflow_gnn.graph import tag_utils from tensorflow_gnn.graph import tensor_utils from tensorflow_gnn.utils import api_utils @@ -138,8 +159,13 @@ def _check_keras_version(): homogeneous = graph_tensor.homogeneous # Legacy aliases from before tfgnn.proto.*. -GraphSchema = proto.GraphSchema -Feature = proto.Feature +# Legacy aliases from before tfgnn.proto.*. +if proto is not None: + GraphSchema = proto.GraphSchema + Feature = proto.Feature +else: + GraphSchema = _typing.Any + Feature = _typing.Any # Preprocessing (batching and padding) types. FeatureDefaultValues = preprocessing_common.FeatureDefaultValues @@ -214,20 +240,22 @@ def _check_keras_version(): readout_named_into_feature = readout.structured_readout_into_feature # Schema conversion and I/O functions. -parse_schema = schema_utils.parse_schema -read_schema = schema_utils.read_schema -write_schema = schema_utils.write_schema -check_compatible_with_schema_pb = schema_utils.check_compatible_with_schema_pb -create_graph_spec_from_schema_pb = schema_utils.create_graph_spec_from_schema_pb -create_schema_pb_from_graph_spec = schema_utils.create_schema_pb_from_graph_spec -iter_sets = schema_utils.iter_sets -iter_features = schema_utils.iter_features +if schema_utils is not None: + parse_schema = schema_utils.parse_schema + read_schema = schema_utils.read_schema + write_schema = schema_utils.write_schema + check_compatible_with_schema_pb = schema_utils.check_compatible_with_schema_pb + create_graph_spec_from_schema_pb = schema_utils.create_graph_spec_from_schema_pb + create_schema_pb_from_graph_spec = schema_utils.create_schema_pb_from_graph_spec + iter_sets = schema_utils.iter_sets + iter_features = schema_utils.iter_features # Schema validation. -ValidationError = schema_validation.ValidationError -validate_schema = schema_validation.validate_schema -check_required_features = schema_validation.check_required_features -assert_constraints = schema_validation.assert_constraints +if schema_validation is not None: + ValidationError = schema_validation.ValidationError + validate_schema = schema_validation.validate_schema + check_required_features = schema_validation.check_required_features + assert_constraints = schema_validation.assert_constraints # Tensor Validation Utils check_scalar_graph_tensor = graph_tensor.check_scalar_graph_tensor @@ -247,10 +275,11 @@ def _check_keras_version(): disable_graph_tensor_validation_at_runtime = graph_constants.disable_graph_tensor_validation_at_runtime # Remove all names added by module imports, unless explicitly allowed here. -api_utils.remove_submodules_except(__name__, [ - "experimental", - "keras", - "proto", - "sampler", -]) +_allowed = ["experimental", "keras"] +if proto is not None: + _allowed.append("proto") +if sampler is not None: + _allowed.append("sampler") +api_utils.remove_submodules_except(__name__, _allowed) +del _allowed # LINT.ThenChange(api_def/tfgnn-symbols.txt) diff --git a/tensorflow_gnn/converters/networkx_io.py b/tensorflow_gnn/converters/networkx_io.py index 32004752..942f4d20 100644 --- a/tensorflow_gnn/converters/networkx_io.py +++ b/tensorflow_gnn/converters/networkx_io.py @@ -75,10 +75,7 @@ def to_edge_list(tf_gnn_graph): node_cnt = 0 for node_set_name, node_set in sorted(tf_gnn_graph.node_sets.items()): - if len(node_set.sizes) > 1: - size = int(node_set.sizes[0]) - else: - size = int(node_set.sizes) + size = int(node_set.sizes[0]) if '#id' in node_set.features and list(node_set.features['#id']): id_range = [str(x.numpy()).encode('utf-8') for x in node_set['#id']] else: diff --git a/tensorflow_gnn/converters/networkx_io_test.py b/tensorflow_gnn/converters/networkx_io_test.py index 4017f207..90ab2982 100644 --- a/tensorflow_gnn/converters/networkx_io_test.py +++ b/tensorflow_gnn/converters/networkx_io_test.py @@ -59,10 +59,10 @@ def test_two_node_sets(self): nx_graph = networkx_io.to_networkx_graph(tf_gnn_graph) - num_tf_nodes = int(tf_gnn_graph.node_sets['nodes'].sizes) + int( - tf_gnn_graph.node_sets['node_set2'].sizes + num_tf_nodes = int(tf_gnn_graph.node_sets['nodes'].sizes[0]) + int( + tf_gnn_graph.node_sets['node_set2'].sizes[0] ) - num_tf_edges = int(tf_gnn_graph.edge_sets['edges'].sizes) + num_tf_edges = int(tf_gnn_graph.edge_sets['edges'].sizes[0]) self.assertEqual(num_tf_nodes, nx_graph.number_of_nodes()) self.assertEqual(num_tf_edges, nx_graph.number_of_edges()) @@ -92,8 +92,8 @@ def test_three_components(self): nx_graph = networkx_io.to_networkx_graph(tf_gnn_graph) - num_tf_nodes = int(tf_gnn_graph.node_sets['nodes'].sizes) - num_tf_edges = int(tf_gnn_graph.edge_sets['edges'].sizes) + num_tf_nodes = int(tf_gnn_graph.node_sets['nodes'].sizes[0]) + num_tf_edges = int(tf_gnn_graph.edge_sets['edges'].sizes[0]) self.assertEqual(num_tf_nodes, nx_graph.number_of_nodes()) self.assertEqual(num_tf_edges, nx_graph.number_of_edges()) diff --git a/tensorflow_gnn/converters/triples_test.py b/tensorflow_gnn/converters/triples_test.py index 7f67f4db..01119f5b 100644 --- a/tensorflow_gnn/converters/triples_test.py +++ b/tensorflow_gnn/converters/triples_test.py @@ -30,8 +30,8 @@ def test_triples_from_array(self): ["nns", "are", "awesome"]] gt = triples.triple_to_graphtensor(triples=spos) - is_source = int(gt.edge_sets["is"].adjacency.source) - is_target = int(gt.edge_sets["is"].adjacency.target) + is_source = int(gt.edge_sets["is"].adjacency.source[0]) + is_target = int(gt.edge_sets["is"].adjacency.target[0]) self.assertLen(gt.node_sets, 1) self.assertLen(gt.edge_sets, 2) diff --git a/tensorflow_gnn/experimental/sampler/BUILD b/tensorflow_gnn/experimental/sampler/BUILD index 0d351af9..39a13321 100644 --- a/tensorflow_gnn/experimental/sampler/BUILD +++ b/tensorflow_gnn/experimental/sampler/BUILD @@ -6,6 +6,7 @@ py_test( name = "core_test", srcs = ["core_test.py"], python_version = "PY3", + # strict_deps = False, deps = [], ) @@ -13,6 +14,7 @@ py_test( name = "ext_ops_test", srcs = ["ext_ops_test.py"], python_version = "PY3", + # strict_deps = False, deps = [], ) @@ -20,5 +22,6 @@ py_test( name = "eval_dag_test", srcs = ["eval_dag_test.py"], python_version = "PY3", + # strict_deps = False, deps = [], -) \ No newline at end of file +) diff --git a/tensorflow_gnn/experimental/sampler/beam/BUILD b/tensorflow_gnn/experimental/sampler/beam/BUILD index 57feaeca..4789ca60 100644 --- a/tensorflow_gnn/experimental/sampler/beam/BUILD +++ b/tensorflow_gnn/experimental/sampler/beam/BUILD @@ -203,6 +203,7 @@ pytype_strict_contrib_test( py_binary( name = "sampler", srcs = ["sampler.py"], + # strict_deps = False, deps = [ ":sampler-lib", "//third_party/py/google/protobuf:use_fast_cpp_protos", # Automatically added go/proto_python_upb_flip diff --git a/tensorflow_gnn/experimental/sampler/proto/BUILD b/tensorflow_gnn/experimental/sampler/proto/BUILD index 6d73ac44..b51d6096 100644 --- a/tensorflow_gnn/experimental/sampler/proto/BUILD +++ b/tensorflow_gnn/experimental/sampler/proto/BUILD @@ -13,6 +13,7 @@ py_library( name = "proto", srcs = ["__init__.py"], srcs_version = "PY3", + # strict_deps = False, visibility = ["//visibility:public"], deps = [ ":eval_dag_py_proto", @@ -20,7 +21,6 @@ py_library( ], ) - proto_library( name = "eval_dag_proto", srcs = ["eval_dag.proto"], diff --git a/tensorflow_gnn/graph/schema_utils.py b/tensorflow_gnn/graph/schema_utils.py index 377529ab..2fd9d8ab 100644 --- a/tensorflow_gnn/graph/schema_utils.py +++ b/tensorflow_gnn/graph/schema_utils.py @@ -22,7 +22,7 @@ from tensorflow_gnn.graph import graph_tensor as gt from tensorflow_gnn.graph import graph_tensor_io as io from tensorflow_gnn.keras import keras_tensors as kt -import tensorflow_gnn.proto.graph_schema_pb2 as schema_pb2 +from tensorflow_gnn.proto import graph_schema_pb2 as schema_pb2 from google.protobuf import text_format diff --git a/tensorflow_gnn/models/contrastive_losses/BUILD b/tensorflow_gnn/models/contrastive_losses/BUILD index bf242e94..23a3e713 100644 --- a/tensorflow_gnn/models/contrastive_losses/BUILD +++ b/tensorflow_gnn/models/contrastive_losses/BUILD @@ -10,7 +10,7 @@ load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "distribute_py_test") package( default_applicable_licenses = ["//tensorflow_gnn:license"], - default_visibility = ["//visibility:private"], + default_visibility = ["//visibility:public"], ) licenses(["notice"]) @@ -20,9 +20,7 @@ package_group(name = "users") pytype_strict_library( name = "contrastive_losses", srcs = ["__init__.py"], - visibility = [ - ":users", - ], + visibility = ["//visibility:public"], deps = [ ":layers", ":metrics", diff --git a/tensorflow_gnn/models/gat_v2/BUILD b/tensorflow_gnn/models/gat_v2/BUILD index ff0ab0c3..a7685672 100644 --- a/tensorflow_gnn/models/gat_v2/BUILD +++ b/tensorflow_gnn/models/gat_v2/BUILD @@ -11,7 +11,7 @@ load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "tf_py_test") licenses(["notice"]) package( - default_visibility = [":__subpackages__"], + default_visibility = ["//visibility:public"], ) package_group(name = "users") @@ -19,10 +19,7 @@ package_group(name = "users") pytype_strict_library( name = "gat_v2", srcs = ["__init__.py"], - visibility = [ - ":__subpackages__", - ":users", - ], + visibility = ["//visibility:public"], deps = [ ":config_dict", ":layers", diff --git a/tensorflow_gnn/models/gcn/BUILD b/tensorflow_gnn/models/gcn/BUILD index 83be83f4..0c276e97 100644 --- a/tensorflow_gnn/models/gcn/BUILD +++ b/tensorflow_gnn/models/gcn/BUILD @@ -8,7 +8,7 @@ load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "tf_py_test") licenses(["notice"]) package( - default_visibility = [":__subpackages__"], + default_visibility = ["//visibility:public"], ) package_group(name = "users") @@ -16,10 +16,7 @@ package_group(name = "users") pytype_strict_library( name = "gcn", srcs = ["__init__.py"], - visibility = [ - ":__subpackages__", - ":users", - ], + visibility = ["//visibility:public"], deps = [ ":gcn_conv", "//tensorflow_gnn/utils:api_utils", diff --git a/tensorflow_gnn/models/graph_sage/BUILD b/tensorflow_gnn/models/graph_sage/BUILD index cdb28780..3e07b6e5 100644 --- a/tensorflow_gnn/models/graph_sage/BUILD +++ b/tensorflow_gnn/models/graph_sage/BUILD @@ -7,17 +7,14 @@ load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "tf_py_test") licenses(["notice"]) -package(default_visibility = [ - "//tensorflow_gnn:__pkg__", - "//tensorflow_gnn/graph:__subpackages__", -]) +package(default_visibility = ["//visibility:public"]) package_group(name = "users") pytype_strict_library( name = "graph_sage", srcs = ["__init__.py"], - visibility = [":users"], + visibility = ["//visibility:public"], deps = [ ":layers", "//tensorflow_gnn/utils:api_utils", diff --git a/tensorflow_gnn/models/hgt/BUILD b/tensorflow_gnn/models/hgt/BUILD index e29286b2..c228d13f 100644 --- a/tensorflow_gnn/models/hgt/BUILD +++ b/tensorflow_gnn/models/hgt/BUILD @@ -11,7 +11,7 @@ load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "tf_py_test") licenses(["notice"]) package( - default_visibility = [":__subpackages__"], + default_visibility = ["//visibility:public"], ) package_group(name = "users") @@ -19,10 +19,7 @@ package_group(name = "users") pytype_strict_library( name = "hgt", srcs = ["__init__.py"], - visibility = [ - ":__subpackages__", - ":users", - ], + visibility = ["//visibility:public"], deps = [ ":config_dict", ":layers", diff --git a/tensorflow_gnn/models/multi_head_attention/BUILD b/tensorflow_gnn/models/multi_head_attention/BUILD index 84db0305..3c7e8cd9 100644 --- a/tensorflow_gnn/models/multi_head_attention/BUILD +++ b/tensorflow_gnn/models/multi_head_attention/BUILD @@ -11,7 +11,7 @@ load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "tf_py_test") licenses(["notice"]) package( - default_visibility = [":__subpackages__"], + default_visibility = ["//visibility:public"], ) package_group(name = "users") @@ -19,10 +19,7 @@ package_group(name = "users") pytype_strict_library( name = "multi_head_attention", srcs = ["__init__.py"], - visibility = [ - ":__subpackages__", - ":users", - ], + visibility = ["//visibility:public"], deps = [ ":config_dict", ":layers", diff --git a/tensorflow_gnn/models/vanilla_mpnn/BUILD b/tensorflow_gnn/models/vanilla_mpnn/BUILD index 56a4de8a..cceb7c0d 100644 --- a/tensorflow_gnn/models/vanilla_mpnn/BUILD +++ b/tensorflow_gnn/models/vanilla_mpnn/BUILD @@ -11,7 +11,7 @@ load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "tf_py_test") licenses(["notice"]) package( - default_visibility = [":__subpackages__"], + default_visibility = ["//visibility:public"], ) package_group(name = "users") @@ -20,10 +20,7 @@ package_group(name = "users") pytype_strict_library( name = "vanilla_mpnn", srcs = ["__init__.py"], - visibility = [ - ":__subpackages__", - ":users", - ], + visibility = ["//visibility:public"], deps = [ ":config_dict", ":layers", diff --git a/tensorflow_gnn/proto/BUILD b/tensorflow_gnn/proto/BUILD index ec3fd48d..0e5a18be 100644 --- a/tensorflow_gnn/proto/BUILD +++ b/tensorflow_gnn/proto/BUILD @@ -4,6 +4,7 @@ load("@rules_proto//proto:defs.bzl", "proto_library") # buildifier: disable=out-of-order-load, disable=same-origin-load load("@rules_python//python:proto.bzl", "py_proto_library") +load("@rules_python//python:defs.bzl", "py_library") package(default_visibility = ["//visibility:public"]) @@ -13,6 +14,7 @@ py_library( name = "proto", srcs = ["__init__.py"], srcs_version = "PY3", + # strict_deps = False, visibility = ["//visibility:public"], deps = [ ":graph_schema", @@ -39,6 +41,7 @@ py_library( name = "graph_schema", srcs = ["graph_schema.py"], srcs_version = "PY3", + # strict_deps = False, deps = [ ":graph_schema_py_proto", ], @@ -55,4 +58,4 @@ py_proto_library( deps = [ ":examples_proto", ], -) +) \ No newline at end of file diff --git a/test-gha.sh b/test-gha.sh new file mode 100644 index 00000000..f393b654 --- /dev/null +++ b/test-gha.sh @@ -0,0 +1,75 @@ +#!/bin/bash +# Copyright 2026 The TensorFlow GNN Authors. All Rights Reserved. +# +# 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. +# ============================================================================== + +# Test script for GitHub Actions — aligned with build_versioned.sh +# Expects env vars: +# TF_VERSION_SPEC, KERAS_VERSION_SPEC — pip version specifiers +# TF_USE_LEGACY_KERAS — '0' or '1' +# BUILD_TAG_FILTERS, TEST_TAG_FILTERS — bazel tag filters +# NIGHTLY_ENV — 'true'/'false' +# WHEEL_DIR — path to directory containing the .whl +set -e +set -x + +echo "=== Installing dependencies ===" +pip install --upgrade pip + +if [[ "$TF_USE_LEGACY_KERAS" == 1 ]]; then + pip install --group test-tf216plus --progress-bar off --upgrade +else + pip install --group test-pre-tf216 --progress-bar off --upgrade +fi + +echo "=== Installing wheel ===" +pip install "${WHEEL_DIR}"/tensorflow_gnn-*.whl +pip list + +echo "=== Verifying nightly (if applicable) ===" +if [[ "${NIGHTLY_ENV}" == "true" ]]; then + pip freeze | grep -q tf-nightly= && ! pip freeze | grep -q tensorflow= + pip freeze | grep -q tf-keras-nightly= && ! pip freeze | grep -q tf-keras= +fi + +echo "=== Running Bazel tests (build_versioned.sh approach) ===" +export PYTHON_BIN_PATH=$(which python3) + +# Setup bazel_pip/ symlink (matching build_versioned.sh lines 45-48) +PIP_TEST_PREFIX=bazel_pip +TEST_ROOT=$(pwd)/${PIP_TEST_PREFIX} +rm -rf "$TEST_ROOT" +mkdir -p "$TEST_ROOT" +ln -s "$(pwd)"/tensorflow_gnn "$TEST_ROOT"/tensorflow_gnn + +# Tag filters (matching build_versioned.sh line 56) +tag_filters="${BUILD_TAG_FILTERS:--no_oss,-oss_excluded}" + +# Fix CRLF line endings on shell scripts (Windows git autocrlf breaks sh_test) +find . -name '*.sh' -exec sed -i 's/\r$//' {} + + +bazel clean + +# Test command aligned with build_versioned.sh line 77 +bazel test \ + --test_env="TF_USE_LEGACY_KERAS=${TF_USE_LEGACY_KERAS}" \ + --build_tag_filters="${tag_filters}" \ + --test_tag_filters="${TEST_TAG_FILTERS:--no_oss,-oss_excluded}" \ + --test_output=errors \ + --verbose_failures=true \ + --build_tests_only \ + --define=no_tfgnn_py_deps=true \ + --keep_going \ + --experimental_repo_remote_exec \ + //bazel_pip/tensorflow_gnn/... diff --git a/third_party/py/absl/logging/BUILD b/third_party/py/absl/logging/BUILD new file mode 100644 index 00000000..289a7e2f --- /dev/null +++ b/third_party/py/absl/logging/BUILD @@ -0,0 +1,13 @@ +# OSS stub for third_party/py/absl/logging. +# This is a Google-internal Bazel target referenced in BUILD files. + +load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "pytype_strict_library") + +package(default_applicable_licenses = ["//tensorflow_gnn:license"]) + +pytype_strict_library( + name = "logging", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) diff --git a/third_party/py/absl/testing/BUILD b/third_party/py/absl/testing/BUILD new file mode 100644 index 00000000..d38a0580 --- /dev/null +++ b/third_party/py/absl/testing/BUILD @@ -0,0 +1,27 @@ +# OSS stub for third_party/py/absl/testing. +# This is a Google-internal Bazel target referenced in BUILD files. + +load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "pytype_strict_library") + +package(default_applicable_licenses = ["//tensorflow_gnn:license"]) + +pytype_strict_library( + name = "testing", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) + +pytype_strict_library( + name = "absltest", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) + +pytype_strict_library( + name = "parameterized", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) diff --git a/third_party/py/apache_beam/BUILD b/third_party/py/apache_beam/BUILD new file mode 100644 index 00000000..0de78664 --- /dev/null +++ b/third_party/py/apache_beam/BUILD @@ -0,0 +1,13 @@ +# OSS stub for third_party/py/apache_beam. +# This is a Google-internal Bazel target referenced in BUILD files. + +load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "pytype_strict_library") + +package(default_applicable_licenses = ["//tensorflow_gnn:license"]) + +pytype_strict_library( + name = "apache_beam", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) diff --git a/third_party/py/apache_beam/utils/BUILD b/third_party/py/apache_beam/utils/BUILD new file mode 100644 index 00000000..e345eab2 --- /dev/null +++ b/third_party/py/apache_beam/utils/BUILD @@ -0,0 +1,10 @@ +load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "pytype_strict_library") + +package(default_applicable_licenses = ["//tensorflow_gnn:license"]) + +pytype_strict_library( + name = "utils", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) diff --git a/third_party/py/google/protobuf/BUILD b/third_party/py/google/protobuf/BUILD new file mode 100644 index 00000000..b4497eba --- /dev/null +++ b/third_party/py/google/protobuf/BUILD @@ -0,0 +1,22 @@ +# OSS stub for third_party/py/google/protobuf. +# These are Google-internal Bazel targets referenced in BUILD files. + +load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "pytype_strict_library") + +package(default_applicable_licenses = ["//tensorflow_gnn:license"]) + +pytype_strict_library( + name = "protobuf", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) + +# No-op target. In Google's internal build, this selects fast C++ protos. +# In OSS builds, this is not needed. +pytype_strict_library( + name = "use_fast_cpp_protos", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) diff --git a/third_party/py/immutabledict/BUILD b/third_party/py/immutabledict/BUILD new file mode 100644 index 00000000..55ee2069 --- /dev/null +++ b/third_party/py/immutabledict/BUILD @@ -0,0 +1,13 @@ +# OSS stub for third_party/py/immutabledict. +# This is a Google-internal Bazel target referenced in BUILD files. + +load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "pytype_strict_library") + +package(default_applicable_licenses = ["//tensorflow_gnn:license"]) + +pytype_strict_library( + name = "immutabledict", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) diff --git a/third_party/py/ml_collections/BUILD b/third_party/py/ml_collections/BUILD new file mode 100644 index 00000000..75463b75 --- /dev/null +++ b/third_party/py/ml_collections/BUILD @@ -0,0 +1,20 @@ +# OSS stub for third_party/py/ml_collections. +# These are Google-internal Bazel targets referenced in BUILD files. + +load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "pytype_strict_library") + +package(default_applicable_licenses = ["//tensorflow_gnn:license"]) + +pytype_strict_library( + name = "config_dict", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) + +pytype_strict_library( + name = "config_flags", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) diff --git a/third_party/py/ml_collections/config_dict/BUILD b/third_party/py/ml_collections/config_dict/BUILD new file mode 100644 index 00000000..4bd58733 --- /dev/null +++ b/third_party/py/ml_collections/config_dict/BUILD @@ -0,0 +1,13 @@ +# OSS stub for third_party/py/ml_collections/config_dict. +# This is a Google-internal Bazel target referenced in BUILD files. + +load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "pytype_strict_library") + +package(default_applicable_licenses = ["//tensorflow_gnn:license"]) + +pytype_strict_library( + name = "config_dict", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) diff --git a/third_party/py/ml_collections/config_flags/BUILD b/third_party/py/ml_collections/config_flags/BUILD new file mode 100644 index 00000000..f1b9a827 --- /dev/null +++ b/third_party/py/ml_collections/config_flags/BUILD @@ -0,0 +1,13 @@ +# OSS stub for third_party/py/ml_collections/config_flags. +# This is a Google-internal Bazel target referenced in BUILD files. + +load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "pytype_strict_library") + +package(default_applicable_licenses = ["//tensorflow_gnn:license"]) + +pytype_strict_library( + name = "config_flags", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) diff --git a/third_party/py/mock/BUILD b/third_party/py/mock/BUILD new file mode 100644 index 00000000..4d079093 --- /dev/null +++ b/third_party/py/mock/BUILD @@ -0,0 +1,13 @@ +# OSS stub for third_party/py/mock. +# This is a Google-internal Bazel target referenced in BUILD files. + +load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "pytype_strict_library") + +package(default_applicable_licenses = ["//tensorflow_gnn:license"]) + +pytype_strict_library( + name = "mock", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +) diff --git a/third_party/py/pyarrow/BUILD b/third_party/py/pyarrow/BUILD new file mode 100644 index 00000000..53df6d15 --- /dev/null +++ b/third_party/py/pyarrow/BUILD @@ -0,0 +1,13 @@ +# OSS stub for third_party/py/pyarrow. +# This is a Google-internal Bazel target referenced in BUILD files. + +load("@tensorflow_gnn//tensorflow_gnn:tensorflow_gnn.bzl", "pytype_strict_library") + +package(default_applicable_licenses = ["//tensorflow_gnn:license"]) + +pytype_strict_library( + name = "pyarrow", + srcs = [], + visibility = ["//visibility:public"], + deps = [], +)