Skip to content

Commit 63d828e

Browse files
Merge pull request #285 from tigergraph/release_2.0.2
Release 2.0.2
2 parents 7dfa7a1 + 4dcb054 commit 63d828e

28 files changed

Lines changed: 2829 additions & 198 deletions

CHANGELOG.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,40 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.0.2] - 2026-04-07
9+
10+
### New Features
11+
12+
- **Schema Change Job APIs**`createSchemaChangeJob()`, `getSchemaChangeJobs()`, `runSchemaChangeJob()`, `dropSchemaChangeJobs()` for managing schema change jobs via REST.
13+
- **`createGraph()` accepts vertex/edge types** — optional `vertexTypes` and `edgeTypes` parameters to include existing global types when creating a graph (e.g. `createGraph("g", vertexTypes=["Person"], edgeTypes=["Knows"])`). Pass `vertexTypes=["*"]` to include all global types.
14+
- **`force` parameter for `runSchemaChange()`** — allows forcing schema changes even when they would cause data loss. Also accepts `dict` (JSON format) for TigerGraph >= 4.0 and supports global schema changes.
15+
- **Graph scope control**`useGraph(graphName)` and `useGlobal()` methods on the connection object, mirroring GSQL's `USE GRAPH` / `USE GLOBAL`. `useGlobal()` doubles as a context manager for temporary global scoping (`with conn.useGlobal(): ...`).
16+
- **GSQL reserved keyword helpers**`getReservedKeywords()` and `isReservedKeyword(name)` static methods to query the canonical set of GSQL reserved keywords.
17+
- **Conda build support**`build.sh` now supports `--conda-build`, `--conda-upload`, `--conda-all`, and `--conda-forge-test` for building and validating conda packages.
18+
- **`installQueries()` now supports a `wait` parameter** — controls whether the call blocks until installation completes. Defaults to `True` for sync and `False` for async connections.
19+
- **`customizeHeader()` now supports `threadLimit` and `memoryLimit`** — sets connection-wide `GSQL-THREAD-LIMIT` and `GSQL-QueryLocalMemLimitMB` headers for query resource control.
20+
21+
### Improved
22+
23+
- **Token-based auth for GSQL endpoints** — GSQL endpoints (e.g. `installQueries`) now use API token or JWT when available, instead of always requiring username/password.
24+
- **Automatic token refresh on expiration** — tokens obtained via `getToken()` are automatically refreshed when the server returns a 401; user-provided tokens raise an error instead.
25+
26+
### Fixed
27+
28+
- **`installQueries()` polling robustness** — handles missing `message` key in server responses and times out after 1 hour instead of hanging indefinitely.
29+
- **`useGlobal()` context manager** — now correctly restores the graph name when used as a deferred context manager.
30+
- **`_refresh_auth_headers()` called earlier in `__init__`** — auth header cache is now built immediately after credentials are set.
31+
- **tgCloud auto-detection simplified** — removed the HTTP ping to `/api/ping`; detection now relies solely on the hostname containing `"tgcloud"`.
32+
- **`threading.local()` init ordering**`self._local` and `self._restpp_failover_lock` are now created before `super().__init__()` in `pyTigerGraphBase`.
33+
- **Boolean query parameter conversion**`upsertEdge()`, `upsertEdges()` (`vertexMustExist`), `getVersion()` (`verbose`), and `rebuildGraph()` (`force`) now convert boolean values to lowercase strings.
34+
- **`dropVertices()`** now correctly falls back to `self.graphname` when the `graph` parameter is `None`.
35+
- **`dropAllDataSources()`** now correctly uses `self.graphname` fallback for the 4.x REST API path.
36+
- **`getVectorIndexStatus()`** no longer produces a malformed URL when called without a graph name; now supports global scope (returns status for all graphs).
37+
- **`previewSampleData()`** now raises `TigerGraphException` when no graph name is available, instead of sending an empty graph name to the server.
38+
- **Docstring fixes** — corrected `timeout` parameter descriptions across vertex and edge query methods.
39+
40+
---
41+
842
## [2.0.1] - 2026-03-23
943

1044
### Breaking Changes

build.sh

Lines changed: 149 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,42 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4+
RECIPE_DIR="$(cd "$(dirname "$0")/pytigergraph-recipe/recipe" && pwd)"
5+
PYPI_PACKAGE="pytigergraph"
6+
CONDA_FORGE_PKG="pytigergraph"
7+
STAGED_RECIPES_DIR="${STAGED_RECIPES_DIR:-$(cd "$(dirname "$0")/../staged-recipes" 2>/dev/null && pwd || echo "")}"
8+
49
usage() {
510
cat <<EOF
611
Usage: $(basename "$0") [OPTIONS]
712
813
Options:
9-
-b, --build Build the package only
10-
-u, --upload Upload the existing dist/ to PyPI only
11-
-a, --all Build then upload (default when no option is given)
12-
-h, --help Show this help message
14+
-b, --build Build the PyPI package only
15+
-u, --upload Upload the existing dist/ to PyPI only
16+
-a, --all Build then upload to PyPI (default when no option is given)
17+
-cb, --conda-build Build the conda package locally (validates the recipe)
18+
-cu, --conda-upload Upload the built conda package to anaconda.org
19+
-ca, --conda-all conda-build then conda-upload
20+
-cft, --conda-forge-test Full conda-forge CI simulation via staged-recipes/build-locally.py
21+
-h, --help Show this help message
22+
23+
Environment variables:
24+
STAGED_RECIPES_DIR Path to your conda-forge/staged-recipes clone (default: ../staged-recipes)
1325
1426
Examples:
15-
$(basename "$0") # build + upload
16-
$(basename "$0") --build # build only
17-
$(basename "$0") --upload # upload only
18-
$(basename "$0") --all # build + upload (explicit)
27+
$(basename "$0") # PyPI build + upload (default)
28+
$(basename "$0") --build # PyPI build only
29+
$(basename "$0") --upload # PyPI upload only
30+
$(basename "$0") --conda-build # validate conda recipe locally
31+
$(basename "$0") --conda-forge-test # simulate full conda-forge CI build
1932
EOF
2033
}
2134

2235
DO_BUILD=false
2336
DO_UPLOAD=false
37+
DO_CONDA_BUILD=false
38+
DO_CONDA_UPLOAD=false
39+
DO_CONDA_FORGE_TEST=false
2440

2541
if [[ $# -eq 0 ]]; then
2642
DO_BUILD=true
@@ -29,20 +45,26 @@ fi
2945

3046
while [[ $# -gt 0 ]]; do
3147
case "$1" in
32-
-b|--build) DO_BUILD=true ;;
33-
-u|--upload) DO_UPLOAD=true ;;
34-
-a|--all) DO_BUILD=true; DO_UPLOAD=true ;;
35-
-h|--help) usage; exit 0 ;;
48+
-b|--build) DO_BUILD=true ;;
49+
-u|--upload) DO_UPLOAD=true ;;
50+
-cb|--conda-build) DO_CONDA_BUILD=true ;;
51+
-cu|--conda-upload) DO_CONDA_UPLOAD=true ;;
52+
-ca|--conda-all) DO_CONDA_BUILD=true; DO_CONDA_UPLOAD=true ;;
53+
-cft|--conda-forge-test) DO_CONDA_FORGE_TEST=true ;;
54+
-a|--all) DO_BUILD=true; DO_UPLOAD=true ;;
55+
-h|--help) usage; exit 0 ;;
3656
*) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
3757
esac
3858
shift
3959
done
4060

61+
# ── PyPI ────────────────────────────────────────────────────────────────────
62+
4163
if $DO_BUILD; then
4264
echo "---- Removing old dist ----"
4365
rm -rf dist
4466

45-
echo "---- Building new package ----"
67+
echo "---- Building PyPI package ----"
4668
python3 -m build
4769
fi
4870

@@ -54,4 +76,118 @@ if $DO_UPLOAD; then
5476

5577
echo "---- Uploading to PyPI ----"
5678
python3 -m twine upload dist/*
79+
80+
# Update conda recipe meta.yaml with the new version and sha256
81+
PKG_VERSION=$(grep "^version" pyproject.toml | awk -F'"' '{print $2}')
82+
TARBALL_URL="https://pypi.org/packages/source/p/$PYPI_PACKAGE/$PYPI_PACKAGE-$PKG_VERSION.tar.gz"
83+
84+
echo "---- Updating conda recipe to $PKG_VERSION ----"
85+
# Wait briefly for PyPI to make the tarball available
86+
for i in $(seq 1 30); do
87+
HTTP_CODE=$(curl -sL -o /dev/null -w "%{http_code}" "$TARBALL_URL")
88+
if [[ "$HTTP_CODE" == "200" ]]; then
89+
break
90+
fi
91+
echo " Waiting for PyPI tarball to become available... ($i/30)"
92+
sleep 5
93+
done
94+
if [[ "$HTTP_CODE" != "200" ]]; then
95+
echo "Warning: could not fetch tarball from PyPI. Update meta.yaml manually." >&2
96+
else
97+
NEW_SHA=$(curl -sL "$TARBALL_URL" | sha256sum | awk '{print $1}')
98+
sed -i.bak "s|^ version:.*| version: \"$PKG_VERSION\"|" "$RECIPE_DIR/meta.yaml"
99+
sed -i.bak "s|^ url:.*| url: $TARBALL_URL|" "$RECIPE_DIR/meta.yaml"
100+
sed -i.bak "s|^ sha256:.*| sha256: $NEW_SHA|" "$RECIPE_DIR/meta.yaml"
101+
sed -i.bak "s|^ # sha256:.*| sha256: $NEW_SHA|" "$RECIPE_DIR/meta.yaml"
102+
rm -f "$RECIPE_DIR/meta.yaml.bak"
103+
echo " ✓ Updated meta.yaml: version=$PKG_VERSION sha256=$NEW_SHA"
104+
fi
105+
fi
106+
107+
# ── Conda ───────────────────────────────────────────────────────────────────
108+
109+
if $DO_CONDA_BUILD; then
110+
if ! command -v conda-build &>/dev/null; then
111+
echo "Error: conda-build not found. Run: conda install conda-build" >&2
112+
exit 1
113+
fi
114+
115+
# Verify the required version is already published on PyPI before proceeding.
116+
RECIPE_VERSION=$(grep "^ version:" "$RECIPE_DIR/meta.yaml" | awk '{print $2}' | tr -d '"')
117+
echo "---- Checking PyPI for $PYPI_PACKAGE==$RECIPE_VERSION ----"
118+
PYPI_VERSIONS=$(curl -sf "https://pypi.org/pypi/$PYPI_PACKAGE/json" | python3 -c "import sys,json; print('\n'.join(json.load(sys.stdin)['releases'].keys()))" 2>/dev/null || true)
119+
if ! echo "$PYPI_VERSIONS" | grep -qx "$RECIPE_VERSION"; then
120+
echo " $PYPI_PACKAGE==$RECIPE_VERSION not found on PyPI. Running --all to build and publish first..."
121+
rm -rf dist
122+
python3 -m build
123+
python3 -m twine upload dist/*
124+
echo " ✓ Published $PYPI_PACKAGE==$RECIPE_VERSION to PyPI"
125+
else
126+
echo " ✓ Found $PYPI_PACKAGE==$RECIPE_VERSION on PyPI"
127+
fi
128+
129+
# Compute sha256 of the tarball declared in the recipe and verify it matches.
130+
TARBALL_URL=$(grep "url:" "$RECIPE_DIR/meta.yaml" | awk '{print $2}')
131+
echo "---- Computing sha256 for $TARBALL_URL ----"
132+
COMPUTED_SHA=$(curl -sL "$TARBALL_URL" | sha256sum | awk '{print $1}')
133+
RECIPE_SHA=$(grep "sha256:" "$RECIPE_DIR/meta.yaml" | awk '{print $2}' || true)
134+
if [[ -n "$RECIPE_SHA" && "$COMPUTED_SHA" != "$RECIPE_SHA" ]]; then
135+
echo "Error: sha256 mismatch!" >&2
136+
echo " recipe : $RECIPE_SHA" >&2
137+
echo " actual : $COMPUTED_SHA" >&2
138+
exit 1
139+
fi
140+
if [[ -z "$RECIPE_SHA" ]]; then
141+
echo "Warning: no sha256 in recipe. For conda-forge submission add:"
142+
echo " sha256: $COMPUTED_SHA"
143+
fi
144+
145+
echo "---- Building conda package ----"
146+
conda build -c conda-forge "$RECIPE_DIR"
147+
fi
148+
149+
if $DO_CONDA_UPLOAD; then
150+
if ! command -v anaconda &>/dev/null; then
151+
echo "Error: anaconda-client not found. Run: conda install anaconda-client" >&2
152+
exit 1
153+
fi
154+
155+
CONDA_PKG=$(conda build -c conda-forge "$RECIPE_DIR" --output)
156+
if [[ ! -f "$CONDA_PKG" ]]; then
157+
echo "Error: conda package not found at $CONDA_PKG. Run --conda-build first." >&2
158+
exit 1
159+
fi
160+
161+
echo "---- Uploading conda package to anaconda.org ----"
162+
anaconda upload --user tigergraph "$CONDA_PKG"
163+
fi
164+
165+
if $DO_CONDA_FORGE_TEST; then
166+
if [[ -z "$STAGED_RECIPES_DIR" || ! -f "$STAGED_RECIPES_DIR/build-locally.py" ]]; then
167+
echo "Error: staged-recipes not found at '${STAGED_RECIPES_DIR}'." >&2
168+
echo "Clone it with: git clone https://github.com/conda-forge/staged-recipes.git ../staged-recipes" >&2
169+
echo "Or set: export STAGED_RECIPES_DIR=/path/to/staged-recipes" >&2
170+
exit 1
171+
fi
172+
if [[ ! -f "$STAGED_RECIPES_DIR/recipes/$CONDA_FORGE_PKG/meta.yaml" ]]; then
173+
echo "Error: recipe not found at $STAGED_RECIPES_DIR/recipes/$CONDA_FORGE_PKG/meta.yaml" >&2
174+
echo "Copy your recipe: cp $RECIPE_DIR/meta.yaml $STAGED_RECIPES_DIR/recipes/$CONDA_FORGE_PKG/meta.yaml" >&2
175+
exit 1
176+
fi
177+
# Detect the local platform config for build-locally.py
178+
_OS="$(uname -s)"
179+
_ARCH="$(uname -m)"
180+
if [[ "$_OS" == "Darwin" && "$_ARCH" == "arm64" ]]; then
181+
_CONFIG="osx_arm64"
182+
elif [[ "$_OS" == "Darwin" ]]; then
183+
_CONFIG="osx64"
184+
elif [[ "$_OS" == "Linux" && "$_ARCH" == "aarch64" ]]; then
185+
_CONFIG="linux_aarch64"
186+
else
187+
_CONFIG="linux64"
188+
fi
189+
echo "---- Running conda-forge CI simulation (config: $_CONFIG) ----"
190+
echo "Note: build-locally.py builds ALL recipes in staged-recipes/recipes/"
191+
cd "$STAGED_RECIPES_DIR"
192+
python build-locally.py "$_CONFIG"
57193
fi

pyTigerGraph/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
try:
88
__version__ = _pkg_version("pyTigerGraph")
99
except PackageNotFoundError:
10-
__version__ = "2.0.1"
10+
__version__ = "2.0.2"
1111

1212
__license__ = "Apache 2"
1313

0 commit comments

Comments
 (0)