bench(gfql): add cpu gpu filter pagerank pipeline benchmark #10523
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI Tests | |
| on: | |
| #NOTE: All jobs gated by auth job | |
| #Regular dev | |
| push: | |
| pull_request: | |
| #Enable UI-driven branch testing | |
| workflow_dispatch: | |
| #Test main bidaily @ 1a | |
| schedule: | |
| - cron: '0 1 1-31/2 * *' | |
| jobs: | |
| changes: | |
| # Determine which files changed to run only relevant jobs | |
| runs-on: ubuntu-latest | |
| outputs: | |
| python: ${{ steps.filter.outputs.python }} | |
| docs: ${{ steps.filter.outputs.docs }} | |
| infra: ${{ steps.filter.outputs.infra }} | |
| gfql: ${{ steps.filter.outputs.gfql }} | |
| benchmarks: ${{ steps.filter.outputs.benchmarks }} | |
| docs_only_latest: ${{ steps.docs_only_latest.outputs.docs_only_latest }} | |
| steps: | |
| - uses: actions/checkout@v3 | |
| - uses: dorny/paths-filter@v3 | |
| id: filter | |
| with: | |
| filters: | | |
| # Infrastructure changes that affect all tests | |
| infra: | |
| - '.github/workflows/ci.yml' | |
| - 'docker/**' | |
| - 'bin/**' | |
| - 'setup.py' | |
| - 'setup.cfg' | |
| - 'MANIFEST.in' | |
| # Python code changes | |
| python: | |
| - '**.py' | |
| - 'graphistry/**' | |
| - 'setup.py' | |
| - 'setup.cfg' | |
| - 'pytest.ini' | |
| - 'mypy.ini' | |
| - 'bin/lint.sh' | |
| - 'bin/typecheck.sh' | |
| # GFQL-specific changes | |
| gfql: | |
| - 'graphistry/gfql/**' | |
| - 'graphistry/compute/gfql/**' | |
| - 'graphistry/compute/gfql_unified.py' | |
| - 'graphistry/models/gfql/**' | |
| - 'graphistry/Plottable.py' | |
| - 'tests/gfql/**' | |
| # Benchmark-specific changes | |
| benchmarks: | |
| - 'benchmarks/**' | |
| # Documentation changes | |
| docs: | |
| - 'docs/**' | |
| - '**.md' | |
| - '**.rst' | |
| - 'demos/**' | |
| - 'notebooks/**' | |
| - name: Detect docs-only change on tip | |
| id: docs_only_latest | |
| run: | | |
| # Only apply the latest-commit docs-only optimization on push. | |
| # PR runs already have path-filter gating and should not infer commit ancestry from merge refs. | |
| docs_only=false | |
| if [[ "${{ github.event_name }}" != "pull_request" ]]; then | |
| base_ref="${{ github.event.before }}" | |
| if [[ -z "$base_ref" ]]; then | |
| base_ref=$(git rev-parse HEAD^ 2>/dev/null || true) | |
| fi | |
| changed_files="" | |
| if [[ -n "${base_ref:-}" ]]; then | |
| changed_files=$(git diff --name-only "$base_ref" HEAD 2>/dev/null || true) | |
| fi | |
| if [[ -n "$changed_files" ]]; then | |
| docs_only=true | |
| for f in $changed_files; do | |
| if [[ "$f" == "README.md" || "$f" == "CHANGELOG.md" || "$f" == docs/* || "$f" == demos/* || "$f" == notebooks/* || "$f" == *.md || "$f" == *.rst ]]; then | |
| continue | |
| else | |
| docs_only=false | |
| break | |
| fi | |
| done | |
| else | |
| echo "Could not determine latest-commit diff; conservatively disabling docs-only skip." | |
| fi | |
| fi | |
| echo "docs_only_latest=${docs_only}" >> "$GITHUB_OUTPUT" | |
| tck-gfql: | |
| needs: changes | |
| if: ${{ (needs.changes.outputs.gfql == 'true' || needs.changes.outputs.infra == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule') && !(needs.changes.outputs.docs_only_latest == 'true' && (github.event_name == 'push' || github.event_name == 'pull_request')) }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v3 | |
| with: | |
| lfs: true | |
| - name: Set up Python 3.12 | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: "3.12" | |
| - name: Install dependencies | |
| run: | | |
| python -m venv pygraphistry | |
| source pygraphistry/bin/activate | |
| python -m pip install --upgrade pip | |
| python -m pip install -e . | |
| python -m pip install pytest pandas | |
| - name: Resolve tck-gfql ref | |
| id: tck_gfql | |
| run: | | |
| tck_repo="https://github.com/graphistry/tck-gfql.git" | |
| candidate_ref="main" | |
| if [[ "${{ github.event_name }}" == "pull_request" && -n "${{ github.head_ref }}" ]]; then | |
| candidate_ref="${{ github.head_ref }}" | |
| elif [[ -n "${{ github.ref_name }}" ]]; then | |
| candidate_ref="${{ github.ref_name }}" | |
| fi | |
| tck_ref="main" | |
| if git ls-remote --exit-code --heads "${tck_repo}" "${candidate_ref}" >/dev/null 2>&1; then | |
| tck_ref="${candidate_ref}" | |
| fi | |
| echo "repo=${tck_repo}" >> "$GITHUB_OUTPUT" | |
| echo "ref=${tck_ref}" >> "$GITHUB_OUTPUT" | |
| echo "Using tck-gfql ref: ${tck_ref}" | |
| - name: Run tck-gfql | |
| run: | | |
| source pygraphistry/bin/activate | |
| git clone --depth 1 --branch "${{ steps.tck_gfql.outputs.ref }}" "${{ steps.tck_gfql.outputs.repo }}" tck-gfql | |
| cd tck-gfql | |
| echo "### tck-gfql conformance report" >> "$GITHUB_STEP_SUMMARY" | |
| echo "- tck-gfql ref: \`${{ steps.tck_gfql.outputs.ref }}\`" >> "$GITHUB_STEP_SUMMARY" | |
| PYGRAPHISTRY_PATH="${{ github.workspace }}" PYGRAPHISTRY_INSTALL=1 ./bin/ci.sh | |
| gfql-benchmarks: | |
| needs: changes | |
| if: ${{ (needs.changes.outputs.gfql == 'true' || needs.changes.outputs.benchmarks == 'true' || github.event_name == 'workflow_dispatch') && !(needs.changes.outputs.docs_only_latest == 'true' && (github.event_name == 'push' || github.event_name == 'pull_request')) }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v3 | |
| with: | |
| lfs: true | |
| - name: Set up Python 3.12 | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: "3.12" | |
| - name: Install dependencies | |
| run: | | |
| python -m venv pygraphistry | |
| source pygraphistry/bin/activate | |
| python -m pip install --upgrade pip | |
| python -m pip install -e .[test] | |
| - name: Run GFQL benchmarks (small) | |
| run: | | |
| source pygraphistry/bin/activate | |
| if [[ ! -f graphistry/compute/gfql/df_executor.py ]]; then | |
| echo "df_executor missing; skipping benchmarks." >> "$GITHUB_STEP_SUMMARY" | |
| exit 0 | |
| fi | |
| python benchmarks/gfql/chain_vs_samepath.py \ | |
| --runs 1 \ | |
| --warmup 0 \ | |
| --max-scenario-seconds 10 \ | |
| --graph-filter tiny,small \ | |
| --scenario-filter 1hop_simple,2hop_where_nonadj_eq_lowcard,2hop_where_nonadj_multi_eq \ | |
| --output gfql-bench.md | |
| cat gfql-bench.md | |
| cat gfql-bench.md >> "$GITHUB_STEP_SUMMARY" | |
| - name: Upload benchmark artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: gfql-benchmarks | |
| path: gfql-bench.md | |
| python-lint-types: | |
| needs: changes | |
| # Run if Python files changed OR infrastructure changed OR manual/scheduled run | |
| if: ${{ (needs.changes.outputs.python == 'true' || needs.changes.outputs.infra == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule') && !(needs.changes.outputs.docs_only_latest == 'true' && (github.event_name == 'push' || github.event_name == 'pull_request')) }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| strategy: | |
| matrix: | |
| python-version: [3.8, 3.9, '3.10', 3.11, 3.12, '3.13', '3.14'] # Run lint/types on all versions | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v3 | |
| with: | |
| lfs: true | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install dependencies | |
| run: | | |
| python -m venv pygraphistry | |
| source pygraphistry/bin/activate | |
| python -m pip install --upgrade pip | |
| python -m pip install -e .[test] | |
| - name: Lint | |
| run: | | |
| source pygraphistry/bin/activate | |
| ./bin/lint.sh | |
| - name: Type check | |
| run: | | |
| source pygraphistry/bin/activate | |
| ./bin/typecheck.sh | |
| test-minimal-python: | |
| needs: [changes, python-lint-types] | |
| # Run if Python files changed OR infrastructure changed OR manual/scheduled run | |
| if: ${{ (needs.changes.outputs.python == 'true' || needs.changes.outputs.infra == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule') && !(needs.changes.outputs.docs_only_latest == 'true' && (github.event_name == 'push' || github.event_name == 'pull_request')) }} | |
| runs-on: ubuntu-latest | |
| # Python 3.14 minimal runs are now close to the hosted-runner wall clock budget | |
| # even when the suite passes cleanly, so keep a small buffer for env setup. | |
| timeout-minutes: 8 | |
| strategy: | |
| matrix: | |
| python-version: [3.8, 3.9, '3.10', 3.11, 3.12, '3.13', '3.14'] | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v3 | |
| with: | |
| lfs: true | |
| - name: Checkout LFS objects | |
| run: git lfs pull | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install test dependencies | |
| run: | | |
| python -m venv pygraphistry | |
| source pygraphistry/bin/activate | |
| python -m pip install --upgrade pip | |
| python -m pip install -e .[test] | |
| - name: Test pip install (Docker) | |
| env: | |
| PYTHON_VERSION: ${{ matrix.python-version }} | |
| run: | | |
| ./docker/test-pip-install.sh | |
| - name: Minimal tests | |
| run: | | |
| source pygraphistry/bin/activate | |
| ./bin/test-minimal.sh | |
| test-pandas-compat: | |
| needs: [changes] | |
| # Run if Python files changed OR infrastructure changed OR manual/scheduled run | |
| if: ${{ (needs.changes.outputs.python == 'true' || needs.changes.outputs.infra == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule') && !(needs.changes.outputs.docs_only_latest == 'true' && (github.event_name == 'push' || github.event_name == 'pull_request')) }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 6 | |
| strategy: | |
| matrix: | |
| include: | |
| - python-version: '3.11' | |
| pandas-version: '2.2.3' | |
| - python-version: '3.11' | |
| pandas-version: '3.0.0' | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v3 | |
| with: | |
| lfs: true | |
| - name: Checkout LFS objects | |
| run: git lfs pull | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install test dependencies | |
| run: | | |
| python -m venv pygraphistry | |
| source pygraphistry/bin/activate | |
| python -m pip install --upgrade pip | |
| python -m pip install -e .[test,bolt,nodexl] | |
| python -m pip install "pandas==${{ matrix.pandas-version }}" | |
| - name: Pandas compatibility minimal suite | |
| run: | | |
| source pygraphistry/bin/activate | |
| ./bin/test-minimal.sh | |
| - name: Pandas compatibility extra coverage | |
| run: | | |
| source pygraphistry/bin/activate | |
| python -m pytest -vv \ | |
| graphistry/tests/test_bolt_util.py \ | |
| graphistry/tests/test_nodexl.py | |
| test-core-python: | |
| needs: [ test-minimal-python ] | |
| # Inherit condition from test-minimal-python | |
| if: ${{ success() }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| strategy: | |
| matrix: | |
| python-version: [3.8, 3.9, '3.10', 3.11, 3.12, '3.13', '3.14'] | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v3 | |
| with: | |
| lfs: true | |
| - name: Checkout LFS objects | |
| run: git lfs pull | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install test dependencies | |
| run: | | |
| python -m venv pygraphistry | |
| source pygraphistry/bin/activate | |
| python -m pip install --upgrade pip | |
| python -m pip install -e .[test,build,bolt,igraph,networkx,gremlin,nodexl,jupyter] | |
| - name: Core tests | |
| run: | | |
| source pygraphistry/bin/activate | |
| ./bin/test.sh | |
| test-graphviz: | |
| needs: [ test-minimal-python ] | |
| # Inherit condition from test-minimal-python | |
| if: ${{ success() }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 # Accommodate retry logic: 3 attempts × 2min + 1.5min backoff/cleanup | |
| strategy: | |
| matrix: | |
| python-version: [3.8, 3.9, '3.10', 3.11, 3.12, '3.13', '3.14'] | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v3 | |
| with: | |
| lfs: true | |
| - name: Checkout LFS objects | |
| run: git lfs pull | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install system dependencies | |
| run: | | |
| # Install graphviz system packages (typically fast: 10-30s) | |
| sudo apt-get install -y graphviz graphviz-dev | |
| - name: Install Python dependencies with retry | |
| run: | | |
| python -m venv pygraphistry | |
| source pygraphistry/bin/activate | |
| # Retry pip install up to 3 times with exponential backoff | |
| # This handles network issues and transient PyPI problems | |
| for attempt in 1 2 3; do | |
| echo "==== Attempt $attempt of 3 ====" | |
| if python -m pip install -e .[test,pygraphviz] \ | |
| --timeout 120 \ | |
| --retries 3; then | |
| echo "✅ Installation successful on attempt $attempt" | |
| break | |
| fi | |
| if [ $attempt -lt 3 ]; then | |
| wait_time=$((attempt * 30)) | |
| echo "⚠️ Installation failed, retrying in ${wait_time}s..." | |
| # Clear pip cache after failure to avoid bad intermediate state | |
| echo "🧹 Clearing pip cache to ensure fresh state..." | |
| python -m pip cache purge || true | |
| sleep $wait_time | |
| else | |
| echo "❌ Installation failed after 3 attempts" | |
| exit 1 | |
| fi | |
| done | |
| - name: Graphviz tests | |
| run: | | |
| source pygraphistry/bin/activate | |
| ./bin/test-graphviz.sh | |
| test-core-umap: | |
| needs: [ test-minimal-python ] | |
| # Inherit condition from test-minimal-python | |
| if: ${{ success() }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| strategy: | |
| matrix: | |
| # RAPIDS (umap-learn/numba) lacks Python 3.14 wheels as of 2025-11, so keep <=3.13 here | |
| python-version: [3.9, '3.10', 3.11, 3.12, '3.13'] | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v3 | |
| with: | |
| lfs: true | |
| - name: Checkout LFS objects | |
| run: git lfs pull | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Set HF cache env | |
| run: | | |
| echo "HF_HOME=${RUNNER_TEMP}/hf-cache" >> "$GITHUB_ENV" | |
| echo "HF_HUB_CACHE=${RUNNER_TEMP}/hf-cache" >> "$GITHUB_ENV" | |
| echo "PIP_EXTRA_INDEX_URL=https://download.pytorch.org/whl/cpu" >> "$GITHUB_ENV" | |
| echo "PIP_PREFER_BINARY=1" >> "$GITHUB_ENV" | |
| - name: Prepare HF cache directory | |
| run: | | |
| mkdir -p "${HF_HOME}" | |
| - name: Restore HF cache | |
| id: hf-cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ env.HF_HOME }} | |
| key: hf-cache-${{ runner.os }}-v1 | |
| restore-keys: | | |
| hf-cache-${{ runner.os }}- | |
| - name: Install test dependencies | |
| run: | | |
| python -m venv pygraphistry | |
| source pygraphistry/bin/activate | |
| python -m pip install --upgrade pip | |
| python -m pip install --upgrade torch==2.8.0+cpu -f https://download.pytorch.org/whl/cpu | |
| python -m pip install -e .[test,testai,umap-learn] | |
| - name: Warm HF cache (sentence-transformers) | |
| id: warm-hf | |
| if: steps['hf-cache'].outputs['cache-hit'] != 'true' | |
| run: | | |
| mkdir -p "${HF_HOME}" | |
| source pygraphistry/bin/activate | |
| # Ensure sentence_transformers is available for warm step | |
| python -m pip install --upgrade sentence-transformers | |
| python - <<'PY' | |
| import os | |
| from pathlib import Path | |
| from sentence_transformers import SentenceTransformer | |
| models = [ | |
| "sentence-transformers/average_word_embeddings_komninos", | |
| "sentence-transformers/paraphrase-MiniLM-L6-v2", | |
| "sentence-transformers/paraphrase-albert-small-v2", | |
| ] | |
| cache_dir = os.environ["HF_HOME"] | |
| status_file = Path(cache_dir) / ".hf_cache_warmed" | |
| status_file.parent.mkdir(parents=True, exist_ok=True) | |
| success = True | |
| for model in models: | |
| try: | |
| SentenceTransformer(model, cache_folder=cache_dir) | |
| except Exception as exc: # pragma: no cover - logging only | |
| success = False | |
| print(f"⚠️ HF warm failed for {model}: {exc}") | |
| status_file.write_text("ok\n" if success else "partial\n") | |
| with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh: | |
| fh.write(f"success={str(success).lower()}\n") | |
| print(f"✅ HF cache warm {'succeeded' if success else 'partial/fail'} at {cache_dir}") | |
| PY | |
| - name: Enable HF offline for tests | |
| run: | | |
| cache_hit="${{ steps['hf-cache'].outputs['cache-hit'] }}" | |
| warm_success="${{ steps['warm-hf'].outputs.success }}" | |
| if [ "${cache_hit}" = "true" ] || [ "${warm_success}" = "true" ]; then | |
| echo "HF_HUB_OFFLINE=1" >> "$GITHUB_ENV" | |
| echo "Using HF cache at ${HF_HOME} (cache-hit: ${cache_hit}, warm_success: ${warm_success})" | |
| else | |
| echo "HF_HUB_OFFLINE=0" >> "$GITHUB_ENV" | |
| echo "HF cache not available; HF-dependent tests may skip or go online." | |
| fi | |
| - name: Core feature tests (weak featurize) | |
| run: | | |
| source pygraphistry/bin/activate | |
| ./bin/test-features.sh | |
| - name: Core umap tests (weak featurize) | |
| run: | | |
| source pygraphistry/bin/activate | |
| ./bin/test-umap-learn-core.sh | |
| test-full-ai: | |
| needs: [ test-minimal-python ] | |
| # Inherit condition from test-minimal-python | |
| if: ${{ success() }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| strategy: | |
| matrix: | |
| # RAPIDS stack not available on Python 3.14 yet | |
| python-version: [3.9, '3.10', 3.11, 3.12, '3.13'] | |
| #include: | |
| # - python-version: 3.12 | |
| # continue-on-error: true | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v3 | |
| with: | |
| lfs: true | |
| - name: Checkout LFS objects | |
| run: git lfs pull | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Set HF cache env | |
| run: | | |
| echo "HF_HOME=${RUNNER_TEMP}/hf-cache" >> "$GITHUB_ENV" | |
| echo "HF_HUB_CACHE=${RUNNER_TEMP}/hf-cache" >> "$GITHUB_ENV" | |
| echo "PIP_EXTRA_INDEX_URL=https://download.pytorch.org/whl/cpu" >> "$GITHUB_ENV" | |
| echo "PIP_PREFER_BINARY=1" >> "$GITHUB_ENV" | |
| - name: Prepare HF cache directory | |
| run: | | |
| mkdir -p "${HF_HOME}" | |
| - name: Restore HF cache | |
| id: hf-cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ env.HF_HOME }} | |
| key: hf-cache-${{ runner.os }}-v1 | |
| restore-keys: | | |
| hf-cache-${{ runner.os }}- | |
| - name: Install test dependencies | |
| run: | | |
| python -m venv pygraphistry | |
| source pygraphistry/bin/activate | |
| python -m pip install --upgrade pip | |
| python -m pip install --upgrade torch==2.8.0+cpu -f https://download.pytorch.org/whl/cpu | |
| python -m pip install -e .[test,testai,ai] | |
| echo "skrub: `pip show skrub | grep Version`" | |
| echo "pandas: `pip show pandas | grep Version`" | |
| echo "numpy: `pip show numpy | grep Version`" | |
| echo "scikit-learn: `pip show scikit-learn | grep Version`" | |
| echo "scipy: `pip show scipy | grep Version`" | |
| echo "umap-learn: `pip show umap-learn | grep Version`" | |
| - name: Warm HF cache (sentence-transformers) | |
| id: warm-hf | |
| if: steps['hf-cache'].outputs['cache-hit'] != 'true' | |
| run: | | |
| mkdir -p "${HF_HOME}" | |
| source pygraphistry/bin/activate | |
| # Ensure sentence_transformers is available for warm step | |
| python -m pip install --upgrade sentence-transformers | |
| python - <<'PY' | |
| import os | |
| from pathlib import Path | |
| from sentence_transformers import SentenceTransformer | |
| models = [ | |
| "sentence-transformers/average_word_embeddings_komninos", | |
| "sentence-transformers/paraphrase-MiniLM-L6-v2", | |
| "sentence-transformers/paraphrase-albert-small-v2", | |
| ] | |
| cache_dir = os.environ["HF_HOME"] | |
| status_file = Path(cache_dir) / ".hf_cache_warmed" | |
| status_file.parent.mkdir(parents=True, exist_ok=True) | |
| success = True | |
| for model in models: | |
| try: | |
| SentenceTransformer(model, cache_folder=cache_dir) | |
| except Exception as exc: # pragma: no cover - logging only | |
| success = False | |
| print(f"⚠️ HF warm failed for {model}: {exc}") | |
| status_file.write_text("ok\n" if success else "partial\n") | |
| with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh: | |
| fh.write(f"success={str(success).lower()}\n") | |
| print(f"✅ HF cache warm {'succeeded' if success else 'partial/fail'} at {cache_dir}") | |
| PY | |
| - name: Enable HF offline for tests | |
| run: | | |
| cache_hit="${{ steps['hf-cache'].outputs['cache-hit'] }}" | |
| warm_success="${{ steps['warm-hf'].outputs.success }}" | |
| if [ "${cache_hit}" = "true" ] || [ "${warm_success}" = "true" ]; then | |
| echo "HF_HUB_OFFLINE=1" >> "$GITHUB_ENV" | |
| echo "Using HF cache at ${HF_HOME} (cache-hit: ${cache_hit}, warm_success: ${warm_success})" | |
| else | |
| echo "HF_HUB_OFFLINE=0" >> "$GITHUB_ENV" | |
| echo "HF cache not available; HF-dependent tests may skip or go online." | |
| fi | |
| - name: Full dbscan tests (rich featurize) | |
| run: | | |
| source pygraphistry/bin/activate | |
| ./bin/test-dbscan.sh | |
| - name: Full feature tests (rich featurize) | |
| run: | | |
| source pygraphistry/bin/activate | |
| ./bin/test-features.sh | |
| - name: Full search tests (rich featurize) | |
| run: | | |
| source pygraphistry/bin/activate | |
| ./bin/test-text.sh | |
| - name: Full umap tests (rich featurize) | |
| run: | | |
| source pygraphistry/bin/activate | |
| ./bin/test-umap-learn-core.sh | |
| test-dgl-cpu: | |
| needs: [changes, test-minimal-python] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| env: | |
| PIP_EXTRA_INDEX_URL: https://download.pytorch.org/whl/cpu | |
| PIP_PREFER_BINARY: "1" | |
| DGLBACKEND: pytorch | |
| steps: | |
| - uses: actions/checkout@v3 | |
| with: | |
| lfs: true | |
| - name: Set up Python 3.10 | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: '3.10' | |
| - name: Install DGL stack (CPU, legacy) | |
| run: | | |
| python -m venv pygraphistry | |
| source pygraphistry/bin/activate | |
| python -m pip install --upgrade pip | |
| cat <<'EOF' > /tmp/dgl-constraints.txt | |
| torch==2.0.1 | |
| torchdata==0.6.1 | |
| dgl==2.1.0 | |
| sentence-transformers==5.1.2 | |
| faiss-cpu | |
| EOF | |
| python -m pip install --constraint /tmp/dgl-constraints.txt torch==2.0.1 torchdata==0.6.1 dgl==2.1.0 | |
| python -m pip install --constraint /tmp/dgl-constraints.txt -e .[test,testai,ai,dgl-cpu] | |
| - name: Run DGL tests | |
| env: | |
| HF_HUB_OFFLINE: 1 | |
| HF_HOME: /tmp/hf-cache | |
| HF_HUB_CACHE: /tmp/hf-cache | |
| run: | | |
| source pygraphistry/bin/activate | |
| mkdir -p "${HF_HOME}" | |
| pytest graphistry/tests/test_embed_utils.py graphistry/tests/test_dgl_utils.py -vv --disable-warnings -x | |
| ./bin/test-embed.sh | |
| ./bin/test-dgl.sh | |
| test-neo4j: | |
| needs: [ test-minimal-python ] | |
| # Inherit condition from test-minimal-python | |
| if: ${{ success() }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 3 | |
| env: | |
| COMPOSE_DOCKER_CLI_BUILD: 1 | |
| DOCKER_BUILDKIT: 1 | |
| steps: | |
| - uses: actions/checkout@v3 | |
| with: | |
| lfs: true | |
| - name: Checkout LFS objects | |
| run: git lfs pull | |
| - name: Neo4j connector tests | |
| run: | | |
| cd docker && WITH_SUDO=" " ./test-cpu-local-neo4j-only.sh | |
| test-build: | |
| needs: [ test-minimal-python ] | |
| # Inherit condition from test-minimal-python | |
| if: ${{ success() }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 2 | |
| steps: | |
| - uses: actions/checkout@v3 | |
| with: | |
| lfs: true | |
| - name: Checkout LFS objects | |
| run: git lfs pull | |
| - name: Set up Python 3.8 | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: 3.8 | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install -e .[build] | |
| - name: Test building | |
| run: | | |
| ./bin/build.sh | |
| - name: Validate py.typed in wheel | |
| run: | | |
| unzip -l dist/graphistry*.whl | grep -q "graphistry/py.typed" || (echo "ERROR: py.typed marker missing from wheel - users won't get type information" && exit 1) | |
| echo "✅ py.typed marker confirmed in wheel distribution" | |
| test-docs: | |
| needs: [changes, python-lint-types] | |
| # Run if docs changed OR Python changed OR infrastructure changed OR manual/scheduled run | |
| if: ${{ needs.changes.outputs.docs == 'true' || needs.changes.outputs.python == 'true' || needs.changes.outputs.infra == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v3 | |
| - name: Test building docs | |
| env: | |
| VALIDATE_NOTEBOOK_EXECUTION: 1 | |
| run: | | |
| cd docs && ./ci.sh | |
| test-readme: | |
| needs: [changes] | |
| # Run if docs changed OR infrastructure changed OR manual/scheduled run | |
| if: ${{ needs.changes.outputs.docs == 'true' || needs.changes.outputs.infra == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 1 | |
| steps: | |
| - uses: actions/checkout@v3 | |
| - name: Set up Python 3.8 | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: 3.8 | |
| - name: Test building docs | |
| continue-on-error: true | |
| run: | | |
| docker run --rm -v "$(pwd)/README.md:/workdir/README.md:ro" -v "$(pwd)/.markdownlint.yaml:/workdir/.markdownlint.yaml:ro" ghcr.io/igorshubovych/markdownlint-cli:v0.37.0 README.md | |