Skip to content

Commit fe66389

Browse files
committed
release: 0.9.61 — fix Python 3.12/3.13 breakage from 0.9.60
- chinese extra: pin jieba-py from 3.12 (was 3.14); jieba's invalid escapes are a hard error on 3.12+ and broke graphify.serve import. - serve.py: suppress the tokenizer SyntaxWarning by category so -W error can't escalate it; catch SyntaxError as a fallback. - hooks.py: harden the Graphify-Labs#3492 rebuild-root guard for 3.13, whose resolve() no longer raises on a symlink loop — require a real directory. Verified full suite green on both 3.10 (5628) and 3.13 (5627).
1 parent 7464f5b commit fe66389

6 files changed

Lines changed: 84 additions & 48 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22

33
Full release notes with details on each version: [GitHub Releases](https://github.com/safishamsi/graphify/releases)
44

5-
## 0.9.60 (unreleased)
5+
## 0.9.61 (unreleased)
6+
7+
- Fix: `graphify.serve` now imports cleanly on Python 3.12 and 3.13. The `chinese` extra pins `jieba-py` from 3.12 onward (0.9.60 mistakenly kept the old `jieba` until 3.14, and its invalid regex escapes are a hard error on 3.12+), and the jieba import now suppresses the tokenizer's `SyntaxWarning` regardless of message or line so it never escalates under `-W error`.
8+
- Fix: the git hook's rebuild-root guard now rejects a symlink-loop or dangling `.graphify_root` on Python 3.13, whose `Path.resolve()` no longer raises on a loop — the saved root must resolve to a real directory inside the repo before it is adopted.
9+
10+
## 0.9.60 (2026-09-12)
611

712
- Fix: atomic writes now fall back correctly on Windows `WinError 17` (cannot move to a different drive), not just `PermissionError` — a shared `os_replace_with_fallback` copies through a temp in the target directory and restores the original if the swap fails, keeping install/export/cache writes crash-safe (#3508, thanks @ayushcodes10).
813
- Fix: files that could not be classified into any language or type are now surfaced (a count and top extensions in the console and GRAPH_REPORT) instead of vanishing from a "successful" run; noise and ignored paths are unaffected (#3511, thanks @ayushcodes10).

‎graphify/hooks.py‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,10 @@ def _bail():
192192
try:
193193
_cwd = Path.cwd().resolve()
194194
_resolved = _candidate.resolve()
195-
_in_repo = _resolved == _cwd or _cwd in _resolved.parents
195+
# Python 3.13 no longer raises on a symlink loop (resolve returns
196+
# the path unresolved), so require a real directory: a loop or a
197+
# dangling target is not a dir and correctly falls back.
198+
_in_repo = (_resolved == _cwd or _cwd in _resolved.parents) and _resolved.is_dir()
196199
except (OSError, RuntimeError):
197200
_in_repo = False
198201
if _in_repo:
@@ -264,7 +267,10 @@ def _bail():
264267
try:
265268
_cwd = Path.cwd().resolve()
266269
_resolved = _candidate.resolve()
267-
_in_repo = _resolved == _cwd or _cwd in _resolved.parents
270+
# Python 3.13 no longer raises on a symlink loop (resolve returns
271+
# the path unresolved), so require a real directory: a loop or a
272+
# dangling target is not a dir and correctly falls back.
273+
_in_repo = (_resolved == _cwd or _cwd in _resolved.parents) and _resolved.is_dir()
268274
except (OSError, RuntimeError):
269275
_in_repo = False
270276
if _in_repo:

‎graphify/serve.py‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@
1919

2020
try:
2121
with warnings.catch_warnings():
22-
warnings.filterwarnings(
23-
"ignore",
24-
message=r'^"\\\." is an invalid escape sequence\.',
25-
category=SyntaxWarning,
26-
lineno=7,
27-
)
22+
# jieba/jieba-py carry invalid regex escapes that emit a SyntaxWarning on
23+
# compile; the message and line moved across Python versions (3.12 also
24+
# reworded it), so ignore the category wholesale here rather than pinning
25+
# a message/lineno. Under `-W error::SyntaxWarning` this keeps the import
26+
# from escalating to a fatal SyntaxError.
27+
warnings.simplefilter("ignore", SyntaxWarning)
2828
import jieba as _jieba # type: ignore[import-untyped]
29-
except ImportError:
29+
except (ImportError, SyntaxError):
30+
# A stray/broken jieba must never take down the whole server import.
3031
_jieba = None
3132

3233

‎pyproject.toml‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "graphifyy"
7-
version = "0.9.60"
7+
version = "0.9.61"
88
description = "AI coding assistant skill (Claude Code, CodeBuddy, Codex, OpenCode, Kilo Code, Cursor, Gemini CLI, Aider, OpenClaw, Factory Droid, Trae, Hermes, Kiro, Pi, Devin CLI, Google Antigravity) - turn any folder of code, docs, papers, images, or videos into a queryable knowledge graph"
99
readme = "README.md"
1010
license = "Apache-2.0"
@@ -81,8 +81,8 @@ anthropic = ["anthropic"]
8181
gemini = ["openai", "tiktoken"]
8282
openai = ["openai", "tiktoken"]
8383
chinese = [
84-
"jieba; python_version < '3.14'",
85-
"jieba-py>=0.46.12,<1; python_version >= '3.14'",
84+
"jieba; python_version < '3.12'",
85+
"jieba-py>=0.46.12,<1; python_version >= '3.12'",
8686
]
8787
sql = ["tree-sitter-sql"]
8888
# extract_pascal() uses tree-sitter-pascal for AST-quality extraction (more
@@ -105,7 +105,7 @@ commonlisp = ["tree-sitter-commonlisp"]
105105
# every platform, no C toolchain; optional because Robot Framework corpora are
106106
# QA-automation specific.
107107
robot = ["robotframework>=4.0"]
108-
all = ["mcp>=1,<3", "starlette>=1.3.1,<2", "neo4j", "falkordb", "pypdf>=6.16.1", "markdownify", "watchdog", "graspologic; python_version < '3.13'", "graspologic-native>=1.3.1,<2; python_version >= '3.13'", "python-docx", "openpyxl", "psycopg[binary]", "faster-whisper; python_version >= '3.11'", "yt-dlp>=2026.7.4", "matplotlib", "numpy>=2.0; python_version >= '3.13'", "openai", "tiktoken", "boto3", "anthropic", "tree-sitter-sql", "jieba; python_version < '3.14'", "jieba-py>=0.46.12,<1; python_version >= '3.14'", "tree-sitter-dm", "tree-sitter-hcl", "tree-sitter-pascal", "tree-sitter-ocaml", "tree-sitter-commonlisp", "robotframework>=4.0"]
108+
all = ["mcp>=1,<3", "starlette>=1.3.1,<2", "neo4j", "falkordb", "pypdf>=6.16.1", "markdownify", "watchdog", "graspologic; python_version < '3.13'", "graspologic-native>=1.3.1,<2; python_version >= '3.13'", "python-docx", "openpyxl", "psycopg[binary]", "faster-whisper; python_version >= '3.11'", "yt-dlp>=2026.7.4", "matplotlib", "numpy>=2.0; python_version >= '3.13'", "openai", "tiktoken", "boto3", "anthropic", "tree-sitter-sql", "jieba; python_version < '3.12'", "jieba-py>=0.46.12,<1; python_version >= '3.12'", "tree-sitter-dm", "tree-sitter-hcl", "tree-sitter-pascal", "tree-sitter-ocaml", "tree-sitter-commonlisp", "robotframework>=4.0"]
109109

110110
[project.scripts]
111111
graphify = "graphify.__main__:main"

‎tests/test_backend_extras.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def test_version_gated_optional_backends_are_packaged():
4646
for extra in ("leiden", "all"):
4747
assert "graspologic-native>=1.3.1,<2; python_version >= '3.13'" in extras[extra]
4848
for extra in ("chinese", "all"):
49-
assert "jieba-py>=0.46.12,<1; python_version >= '3.14'" in extras[extra]
49+
assert "jieba-py>=0.46.12,<1; python_version >= '3.12'" in extras[extra]
5050

5151

5252
def test_backend_pkg_hint_points_at_uv_tool_and_extra():

‎uv.lock‎

Lines changed: 57 additions & 33 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)