Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,6 @@ Desktop.ini
schema_cache_test/
hed_cache/
spec_tests/hed-specification/tests
spec_tests/hed-examples
spec_tests/hed-tests
spec_tests/*.json

# GitHub Copilot instructions (project-specific)
Expand Down
9 changes: 7 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,10 @@

[submodule "spec_tests/hed-examples"]
path = spec_tests/hed-examples
url = https://github.com/hed-standard/hed-examples/
branch = main
url = https://github.com/hed-standard/hed-examples.git
branch = main

[submodule "spec_tests/hed-schemas"]
path = spec_tests/hed-schemas
url = https://github.com/hed-standard/hed-schemas.git
branch = main
18 changes: 17 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,23 @@ This project adheres to a code of conduct that we expect all contributors to fol
pip install -e .[dev,test,docs,examples]
```

4. **Run tests to verify setup:**
4. **Initialize git submodules:**

HED-Python uses git submodules for test data and schemas. Initialize them with:

```bash
git submodule update --init --recursive
```

This will fetch:

- `spec_tests/hed-examples/` - Example datasets for specification tests
- `spec_tests/hed-tests/` - Official HED specification tests
- `spec_tests/hed-schemas/` - Official HED schema repository for testing

**Note:** The submodule contents are not stored in the hed-python repository. They are fetched on-demand and ignored by git.

5. **Run tests to verify setup:**

```bash
python -m unittest discover tests
Expand Down
1 change: 1 addition & 0 deletions spec_tests/hed-examples
Submodule hed-examples added at a788cd
1 change: 1 addition & 0 deletions spec_tests/hed-schemas
Submodule hed-schemas added at 36b108
1 change: 1 addition & 0 deletions spec_tests/hed-tests
Submodule hed-tests added at 129f96
4 changes: 2 additions & 2 deletions spec_tests/test_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class MyTestCase(unittest.TestCase):
def setUpClass(cls):
# New directory structure: hed-tests/json_test_data/
test_base_dir = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "hed-tests/json_test_data"))
schema_test_dir = os.path.join(test_base_dir, "schema_tests")
validation_test_dir = os.path.join(test_base_dir, "validation_tests")
schema_test_dir = os.path.join(test_base_dir, "schema_test_data")
validation_test_dir = os.path.join(test_base_dir, "validation_test_data")

cls.test_base_dir = test_base_dir
cls.fail_count = []
Expand Down
74 changes: 74 additions & 0 deletions tests/data/schema_tests/HED_testunpart_1.0.0.mediawiki
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
HED version="1.0.0" library="testunpart"

'''Prologue'''
This schema is a standalone.

!# start schema

'''Test-some''' <nowiki>[Unknown stuff.]</nowiki>
* Unknown1 <nowiki>[Unknown1 stuff]</nowiki>
* Unknown2 <nowiki>{suggestedTag=Fruit} [Unknown2 stuff]</nowiki>
** <nowiki># {takesValue, valueClass=digitClass, unitClass=myAngleUnits} [Try this out]</nowiki>

'''Fruit''' <nowiki>[Fruit stuff.]</nowiki>
* Apple <nowiki>{annotation=foodonto:has_botanical_name} [Apple stuff]</nowiki>
** Honey-crisp <nowiki>[Type of apple]</nowiki>

'''Vegetable''' <nowiki>[Vegetable stuff.]</nowiki>
* Carrot <nowiki>{annotation=foodonto:has_botanical_name} [Carrot stuff]</nowiki>


!# end schema

'''Unit classes'''
* myAngleUnits <nowiki>{defaultUnits=deg}</nowiki>
** deg <nowiki>{conversionFactor=1.0}</nowiki>

'''Unit modifiers'''

'''Value classes'''
* digitClass <nowiki>{allowedCharacter=digits} [Values that can only have digits.]</nowiki>

'''Schema attributes'''
* myAnnotation <nowiki>{elementDomain, stringRange, annotationProperty} [Special annotations.]</nowiki>
* annotation <nowiki>{elementDomain, stringRange, annotationProperty} [A annotation link to an item in another ontology or item.]</nowiki>
* takesValue <nowiki>{tagDomain, boolRange, annotationProperty} [This tag is a hashtag placeholder that is expected to be replaced with a user-defined value.]</nowiki>
* defaultUnits <nowiki>{unitClassDomain, unitRange} [The default units to use if the placeholder has a unit class but the substituted value has no units.]</nowiki>
* suggestedTag <nowiki>{tagDomain, tagRange} [A tag that is often associated with this tag. This attribute is used by tagging tools to provide tagging suggestions.]</nowiki>
* unitClass <nowiki>{tagDomain, unitClassRange} [The unit class that the value of a placeholder node can belong to.]</nowiki>
* valueClass <nowiki>{tagDomain, valueClassRange} [Type of value taken on by the value of a placeholder node.]</nowiki>
* allowedCharacter <nowiki>{unitDomain, unitModifierDomain, valueClassDomain, stringRange} [A special character that is allowed in expressing the value of a placeholder of a specified value class. Allowed characters may be listed individual, named individually, or named as a group as specified in Section 2.2 Character sets and restrictions of the HED specification.]</nowiki>
* conversionFactor <nowiki>{unitDomain, unitModifierDomain, numericRange} [The factor to multiply these units or unit modifiers by to convert to default units.]</nowiki>
* deprecatedFrom <nowiki>{elementDomain, stringRange} [The latest schema version in which the element was not deprecated.]</nowiki>
* extensionAllowed <nowiki>{tagDomain, boolRange} [Users can add unlimited levels of child nodes under this tag. This tag is propagated to child nodes except for hashtag placeholders.]</nowiki>
* inLibrary <nowiki>{elementDomain, stringRange} [The named library schema that this schema element is from. This attribute is added by tools when a library schema is merged into its partnered standard schema.]</nowiki>

'''Properties'''
* annotationProperty <nowiki>[The value is not inherited by child nodes.]</nowiki>
* boolRange <nowiki>[This schema attribute's value can be true or false. This property was formerly named boolProperty.]</nowiki>
* elementDomain <nowiki>[This schema attribute can apply to any type of element class (i.e., tag, unit, unit class, unit modifier, or value class). This property was formerly named elementProperty.]</nowiki>
* tagDomain <nowiki>[This schema attribute can apply to node (tag-term) elements. This was added so attributes could apply to multiple types of elements. This property was formerly named nodeProperty.]</nowiki>
* tagRange <nowiki>[This schema attribute's value can be a node. This property was formerly named nodeProperty.]</nowiki>
* numericRange <nowiki>[This schema attribute's value can be numeric.]</nowiki>
* stringRange <nowiki>[This schema attribute's value can be a string.]</nowiki>
* unitClassDomain <nowiki>[This schema attribute can apply to unit classes. This property was formerly named unitClassProperty.]</nowiki>
* unitClassRange <nowiki>[This schema attribute's value can be a unit class.]</nowiki>
* unitModifierDomain <nowiki>[This schema attribute can apply to unit modifiers. This property was formerly named unitModifierProperty.]</nowiki>
* unitDomain <nowiki>[This schema attribute can apply to units. This property was formerly named unitProperty.]</nowiki>
* unitRange <nowiki>[This schema attribute's value can be units.]</nowiki>
* valueClassDomain <nowiki>[This schema attribute can apply to value classes. This property was formerly named valueClassProperty.]</nowiki>
* valueClassRange <nowiki>[This schema attribute's value can be a value class.]</nowiki>

'''Epilogue'''
A final section.

'''Sources'''
* <nowiki>source=FoodDB,link=https://fooddb.example.org,description=Botanical and nutritional database for fruits and vegetables.</nowiki>

'''Prefixes'''
* <nowiki>prefix=foodonto:,namespace=http://purl.obolibrary.org/obo/foodon.owl,description=Food Ontology (FOODON)</nowiki>

'''External annotations'''
* <nowiki>prefix=foodonto:,id=has_botanical_name,iri=http://purl.obolibrary.org/obo/FOODON_00001234,description=The botanical or scientific name of a food item.</nowiki>

!# end hed
16 changes: 13 additions & 3 deletions tests/schema/test_schema_format_roundtrip.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ def test_edge_case_schemas_roundtrip(self):
"added_prop_with_usage.xml",
"unknown_attribute.xml",
"HED8.0.0_2_value_classes.xml",
"HED_testunpart_1.0.0.mediawiki",
Comment thread
VisLab marked this conversation as resolved.
]

for schema_name in edge_case_schemas:
Expand All @@ -485,20 +486,29 @@ def test_edge_case_schemas_roundtrip(self):
with self.subTest(schema=schema_name):
original = load_schema(schema_path)

# Strip extension from schema_name for base naming
base_name = os.path.splitext(schema_name)[0]

# Test XML roundtrip
xml_path = os.path.join(self.temp_dir, f"edge_case_{schema_name}")
xml_path = os.path.join(self.temp_dir, f"edge_case_{base_name}.xml")
original.save_as_xml(xml_path)
xml_reloaded = load_schema(xml_path)
self.assertEqual(original, xml_reloaded, f"XML roundtrip failed for {schema_name}")

# Test MediaWiki roundtrip
wiki_path = xml_path.replace(".xml", ".mediawiki")
wiki_path = os.path.join(self.temp_dir, f"edge_case_{base_name}.mediawiki")
original.save_as_mediawiki(wiki_path)
wiki_reloaded = load_schema(wiki_path)
self.assertEqual(original, wiki_reloaded, f"MediaWiki roundtrip failed for {schema_name}")

# Test TSV roundtrip
tsv_dir = os.path.join(self.temp_dir, "tsv", f"edge_case_{base_name}")
original.save_as_dataframes(tsv_dir)
tsv_reloaded = load_schema(tsv_dir)
self.assertEqual(original, tsv_reloaded, f"TSV roundtrip failed for {schema_name}")

# Test JSON roundtrip
json_path = xml_path.replace(".xml", ".json")
json_path = os.path.join(self.temp_dir, f"edge_case_{base_name}.json")
original.save_as_json(json_path)
json_reloaded = load_schema(json_path)
self.assertEqual(original, json_reloaded, f"JSON roundtrip failed for {schema_name}")
Expand Down
Loading