@@ -94,6 +94,154 @@ These instructions assume you are familiar with code development using Python an
9494#. When your profile & tests are written, open a pull request to contribute
9595 it back to the repository!
9696
97+ Overriding inherited checks
98+ ---------------------------
99+
100+ When a profile inherits from another profile (via ``prof:isProfileOf `` /
101+ ``prof:isTransitiveProfileOf ``), it automatically receives every check
102+ declared by its ancestors. The validator additionally supports
103+ **override-by-name **: a child profile can replace an inherited check by
104+ declaring a new check with the **same name **.
105+
106+ This allows an extension profile to *redefine * the content of an inherited
107+ check — for example, to make a constraint stricter or looser, change its
108+ severity, or, as described in the next section, fully deactivate it.
109+
110+ Override-by-name is enabled by default. It can be disabled via the
111+ ``allow_requirement_check_override `` validation setting (CLI / API), which
112+ will raise an error on duplicate check names instead.
113+
114+ SHACL checks
115+ ^^^^^^^^^^^^
116+
117+ Each SHACL ``NodeShape `` / ``PropertyShape `` becomes a check whose name is
118+ its ``sh:name ``. To override an inherited check, declare a shape in the
119+ extension profile with the **same ** ``sh:name `` as the inherited one:
120+
121+ .. code-block :: turtle
122+
123+ # Parent profile
124+ ro:ShapeC
125+ a sh:NodeShape ;
126+ sh:name "The Shape C" ;
127+ sh:targetNode ro:ro-crate-metadata.json ;
128+ sh:property [
129+ a sh:PropertyShape ;
130+ sh:name "Check Metadata File Descriptor entity existence" ;
131+ sh:path rdf:type ;
132+ sh:minCount 1 ;
133+ sh:message "Missing entity" ;
134+ ] .
135+
136+ .. code-block :: turtle
137+
138+ # Extension profile — overrides the inherited PropertyShape by sh:name
139+ ro:ShapeC
140+ a sh:NodeShape ;
141+ sh:name "The Shape C" ;
142+ sh:targetNode ro:ro-crate-metadata.json ;
143+ sh:property [
144+ a sh:PropertyShape ;
145+ sh:name "Check Metadata File Descriptor entity existence" ;
146+ sh:path rdf:type ;
147+ sh:minCount 1 ;
148+ sh:maxCount 1 ;
149+ sh:message "Stricter override from extension profile" ;
150+ ] .
151+
152+ Both top-level shapes and ``PropertyShape `` entries nested inside a parent
153+ ``NodeShape `` (i.e., declared inline, without an absolute IRI) can be
154+ overridden this way.
155+
156+ Python checks
157+ ^^^^^^^^^^^^^
158+
159+ Python checks declared via the ``@check `` decorator are matched by their
160+ ``name `` argument. To override an inherited Python check, declare a new
161+ function with the same ``name `` in the extension profile:
162+
163+ .. code-block :: python
164+
165+ # In the extension profile's checks module
166+ from rocrate_validator.requirements.python import check
167+
168+ @check (name = " Check Metadata File Descriptor entity existence" )
169+ def overridden_check (self , ctx ):
170+ # New implementation that replaces the inherited one
171+ ...
172+
173+ Deactivating inherited checks
174+ -----------------------------
175+
176+ A child profile can also **fully deactivate ** a check inherited from one of
177+ its ancestors. A deactivated check is skipped during validation and
178+ reported as such in the validation result. This is useful when an extension
179+ profile relaxes the parent's expectations, or replaces a coarse-grained
180+ check with a more specific one declared elsewhere in the same profile.
181+
182+ SHACL checks
183+ ^^^^^^^^^^^^
184+
185+ Two complementary mechanisms are supported, depending on whether the shape
186+ to disable has an absolute IRI of its own.
187+
188+ **Shape with an absolute IRI ** (e.g. a top-level ``NodeShape `` or a named
189+ ``PropertyShape ``): reference the shape by IRI from the extension profile
190+ and mark it as deactivated, without redeclaring it.
191+
192+ .. code-block :: turtle
193+
194+ # Extension profile
195+ <https://parent-profile/ShapeC> sh:deactivated true .
196+
197+ **Nested ``PropertyShape`` without an absolute IRI ** (a property declared
198+ inline inside a parent ``NodeShape ``): use the override-by-name mechanism
199+ described in the previous section. Declare a new ``PropertyShape `` in the
200+ extension profile with the same ``sh:name `` as the one to disable, and set
201+ ``sh:deactivated true `` on it. This overrides the parent's
202+ ``PropertyShape ``, and the validator reports the resulting check as
203+ deactivated.
204+
205+ .. code-block :: turtle
206+
207+ # Extension profile — disables the inherited PropertyShape by sh:name
208+ ro:ShapeC
209+ a sh:NodeShape ;
210+ sh:name "The Shape C" ;
211+ sh:targetNode ro:ro-crate-metadata.json ;
212+ sh:property [
213+ a sh:PropertyShape ;
214+ sh:name "Check Metadata File Descriptor entity existence" ;
215+ sh:path rdf:type ;
216+ sh:deactivated true ;
217+ ] .
218+
219+ .. note ::
220+
221+ Cross-profile deactivation is scoped to the shape's transitive
222+ descendants: a ``sh:deactivated true `` triple declared by a profile
223+ that does not inherit (directly or transitively) from the shape's
224+ owning profile is ignored. This prevents unrelated profiles loaded in
225+ the same process from interfering with one another.
226+
227+ Python checks
228+ ^^^^^^^^^^^^^
229+
230+ The ``@check `` decorator accepts a ``deactivated `` flag, mirroring SHACL's
231+ ``sh:deactivated ``. Combined with override-by-name, an extension profile
232+ can disable an inherited Python check by redeclaring it with
233+ ``deactivated=True ``:
234+
235+ .. code-block :: python
236+
237+ from rocrate_validator.requirements.python import check
238+
239+ @check (name = " Check Metadata File Descriptor entity existence" ,
240+ deactivated = True )
241+ def disabled (self , ctx ):
242+ # Body is irrelevant — the check is skipped during validation.
243+ return True
244+
97245 Running validator & tests during profile development
98246----------------------------------------------------
99247
0 commit comments