Parse EXTENDS/RESTRICTS with shape references; fix chardet decode crash - #4
Merged
Merged
Conversation
This was referenced Jul 12, 2026
ericprud
pushed a commit
to ericprud/PyShEx
that referenced
this pull request
Jul 28, 2026
Implements ShEx 2.1 EXTENDS/ABSTRACT/RESTRICTS evaluation: - satisfiesExtendedShape: neighbourhood triples are allocated to the triple constraints of the extension targets (through references, AND/OR branches and extends chains); a constraint reached through several chains (diamond inheritance) allocates its triples to every one of them, so a triple cannot evade one chain's constraints by hiding in another. Extension targets are evaluated through ordinary satisfies() against their allocated part, so ShapeOr / ShapeAnd / ShapeNot parents work uniformly. - Node-scoped restriction stack: extension evaluation sees only its allocated part while value-expression recursion on other nodes sees the whole graph; the (node, shape) evaluation cache is bypassed under a restriction (the same pair can genuinely differ between parts). - satisfiesShapeDecl: restricts are conjuncts; an abstract declaration is satisfied only through a non-abstract descendant (except as an EXTENDS target); labeled shapes with registered extensions get the same descendant fallback. Handles both ShExJ 2.1 ShapeDecl and legacy inline-id flavours. - pyshex/utils/feasibility.py: a sound refutation test over partial bags of TripleConstraint matches, used to prune hopeless neighbourhoods before partition enumeration and to pre-filter EXTRA permutations. Ported from the same analysis implemented for Apache Jena, rudof and shex.js. shexSpec/shexTest validation manifest: ShExJ: 1182 tests = 1093 passed, 0 failed, 89 trait-skips ShExC: 1184 tests = 1091 passed, 0 failed, 93 trait-skips (baseline could not run: NotImplementedError on the first ShapeDecl) pyshexc is temporarily sourced from the EXTENDS-grammar PR branch (linkml/grammar-python-antlr-linkml#4); repoint to PyPI when released. Requires tests/data/shexTest (git submodule) for the manifest tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- ShExDoc grammar: extension and restrictions take shapeRef ('EXTENDS @<label>'),
matching usage everywhere (shexTest, shex.js, Apache Jena, rudof). The bare
shapeExprLabel form was never correct and never deployed, so it is not accepted.
Parser regenerated with ANTLR 4.9.3 to match the antlr4-python3-runtime~=4.9.3 pin.
(Companion grammar change PRed at shexSpec/grammar#17.)
- visitQualifier / shapeExprDecl restrictions route shapeRef through shapeRef_to_iriref.
- ShExC serializer emits the @-form for EXTENDS/RESTRICTS so output re-parses.
- generate_shexj.load_shex_file: chardet.detect can return {'encoding': None}; never
pass None to bytes.decode (crashed on the shexTest ShExC manifest).
Verified against shexSpec/shexTest validation manifest via linkml/PyShEx:
1184 tests = 1180 passed, 0 failed, 4 skips (schemas pyshexc cannot parse).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
<S1> against base .../validation/1dot-relative.shex resolved to .../1dot-relative.shexS1; urljoin gives .../validation/S1 (shexTest 1dot-relative_pass-*). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ericprud
force-pushed
the
extends-shaperef
branch
from
July 28, 2026 00:52
b66152e to
7e3a6b5
Compare
ericprud
pushed a commit
to ericprud/PyShEx
that referenced
this pull request
Jul 28, 2026
shexSpec/grammar#17 and linkml/grammar-python-antlr-linkml#4 dropped the never-deployed bare shapeExprLabel form; EXTENDS/RESTRICTS now require a shape reference (EXTENDS @<label>). All shexTest EXTENDS schemas already use the @-form, so results are unchanged: 129 passed, 21 skipped, 1 xfailed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ericprud
pushed a commit
to ericprud/PyShEx
that referenced
this pull request
Jul 28, 2026
Implements ShEx 2.1 EXTENDS/ABSTRACT/RESTRICTS evaluation: - satisfiesExtendedShape: neighbourhood triples are allocated to the triple constraints of the extension targets (through references, AND/OR branches and extends chains); a constraint reached through several chains (diamond inheritance) allocates its triples to every one of them, so a triple cannot evade one chain's constraints by hiding in another. Extension targets are evaluated through ordinary satisfies() against their allocated part, so ShapeOr / ShapeAnd / ShapeNot parents work uniformly. - Node-scoped restriction stack: extension evaluation sees only its allocated part while value-expression recursion on other nodes sees the whole graph; the (node, shape) evaluation cache is bypassed under a restriction (the same pair can genuinely differ between parts). - satisfiesShapeDecl: restricts are conjuncts; an abstract declaration is satisfied only through a non-abstract descendant (except as an EXTENDS target); labeled shapes with registered extensions get the same descendant fallback. Handles both ShExJ 2.1 ShapeDecl and legacy inline-id flavours. - pyshex/utils/feasibility.py: a sound refutation test over partial bags of TripleConstraint matches, used to prune hopeless neighbourhoods before partition enumeration and to pre-filter EXTRA permutations. Ported from the same analysis implemented for Apache Jena, rudof and shex.js. shexSpec/shexTest validation manifest: ShExJ: 1182 tests = 1093 passed, 0 failed, 89 trait-skips ShExC: 1184 tests = 1091 passed, 0 failed, 93 trait-skips (baseline could not run: NotImplementedError on the first ShapeDecl) pyshexc is temporarily sourced from the EXTENDS-grammar PR branch (linkml/grammar-python-antlr-linkml#4); repoint to PyPI when released. Requires tests/data/shexTest (git submodule) for the manifest tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ericprud
pushed a commit
to ericprud/PyShEx
that referenced
this pull request
Sep 24, 2026
Implements ShEx 2.1 EXTENDS/ABSTRACT/RESTRICTS evaluation: - satisfiesExtendedShape: neighbourhood triples are allocated to the triple constraints of the extension targets (through references, AND/OR branches and extends chains); a constraint reached through several chains (diamond inheritance) allocates its triples to every one of them, so a triple cannot evade one chain's constraints by hiding in another. Extension targets are evaluated through ordinary satisfies() against their allocated part, so ShapeOr / ShapeAnd / ShapeNot parents work uniformly. - Node-scoped restriction stack: extension evaluation sees only its allocated part while value-expression recursion on other nodes sees the whole graph; the (node, shape) evaluation cache is bypassed under a restriction (the same pair can genuinely differ between parts). - satisfiesShapeDecl: restricts are conjuncts; an abstract declaration is satisfied only through a non-abstract descendant (except as an EXTENDS target); labeled shapes with registered extensions get the same descendant fallback. Handles both ShExJ 2.1 ShapeDecl and legacy inline-id flavours. - pyshex/utils/feasibility.py: a sound refutation test over partial bags of TripleConstraint matches, used to prune hopeless neighbourhoods before partition enumeration and to pre-filter EXTRA permutations. Ported from the same analysis implemented for Apache Jena, rudof and shex.js. shexSpec/shexTest validation manifest: ShExJ: 1182 tests = 1093 passed, 0 failed, 89 trait-skips ShExC: 1184 tests = 1091 passed, 0 failed, 93 trait-skips (baseline could not run: NotImplementedError on the first ShapeDecl) pyshexc is temporarily sourced from the EXTENDS-grammar PR branch (linkml/grammar-python-antlr-linkml#4); repoint to PyPI when released. Requires tests/data/shexTest (git submodule) for the manifest tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
Author
|
@melonora could you review this when you have a moment? PyShEx master (linkml/PyShEx#105) now depends on it through a git source, and its release workflow refuses to publish to PyPI until a pyshexc release with these changes is available. CI here is green on Ubuntu and Windows, Python 3.10–3.14. |
Collaborator
|
Will review today |
melonora
approved these changes
Sep 25, 2026
melonora
left a comment
Collaborator
There was a problem hiding this comment.
I do not see anything wrong with this, also tested on mac.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
extensionandrestrictionstakeshapeRef(EXTENDS @<label>), matching usage everywhere (shexTest, shex.js, Apache Jena, rudof). The bareshapeExprLabelform was never correct and never deployed, so it is not accepted. The parser is regenerated with ANTLR 4.9.3, matching theantlr4-python3-runtime~=4.9.3pin. The companionShExDoc.g4change is merged at extension/restrictions accept shape references (EXTENDS @<label>) shexSpec/grammar#17.ShExCemits the@-form for EXTENDS/RESTRICTS so its output re-parses under the strict grammar.visitQualifier(extension) andshapeExprDeclrestrictions routeshapeRefthrough the existingshapeRef_to_iriref.generate_shexj.load_shex_filecrashed withdecode() argument 'encoding' must be str, not Nonewhenchardet.detectreturned{'encoding': None}— this aborted the shexTest ShExC manifest on its first schema.urljoin) instead of string concatenation.Verification
Repo test suite: 16 passed, 1 skipped. Via linkml/PyShEx against the shexSpec/shexTest validation manifest from ShExC: 1184 tests = 1180 passed / 0 failed / 4 skips (schemas pyshexc cannot parse).
🤖 Generated with Claude Code