diff --git a/tests/tapregext/TAPRegExt-v1.0-with-erratum1.xsd b/tests/tapregext/TAPRegExt-v1.0-with-erratum1.xsd
new file mode 100644
index 0000000..95d2e2b
--- /dev/null
+++ b/tests/tapregext/TAPRegExt-v1.0-with-erratum1.xsd
@@ -0,0 +1,384 @@
+
+
+
+
+
+
+
+ TAPRegExt
+ xs
+
+ tr
+
+ A description of the capabilities metadata for TAP services.
+
+
+
+
+ An abstract capability that fixes the standardID to the IVOA ID for the TAP
+ standard.
+ See vr:Capability for documentation on inherited children.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The capabilities of a TAP server.
+ The capabilities attempt to define most issues that the TAP standard leaves
+ to the implementors ("may", "should").
+
+
+
+
+
+
+
+ Identifier of IVOA-approved data model supported by the service.
+
+
+
+
+
+ Language supported by the service.
+
+
+
+
+
+ Output format supported by the service.
+
+
+
+
+
+ Upload method supported by the service.
+ The absence of upload methods indicates that the service does not
+ support uploads at all.
+
+
+
+
+
+ Limits on the time between job creation and destruction time.
+
+
+
+
+
+ Limits on executionDuration.
+
+
+
+
+
+ Limits on the size of data returned.
+
+
+
+
+
+ Limits on the size of uploaded data.
+
+
+
+
+
+
+
+
+
+
+
+ An IVOA defined data model, identified by an IVORN intended for machine
+ consumption and a short label intended for human comsumption.
+
+
+
+
+
+
+ The IVORN of the data model.
+
+
+
+
+
+
+
+
+ A query language supported by the service.
+ Each language element can describe one or more versions of a language.
+ Either name alone or name-version can be used as values for the server's LANG parameter.
+
+
+
+
+
+ The name of the language without a version suffix.
+
+
+
+
+
+ A version of the language supported by the server.
+
+
+
+
+
+ A short, human-readable description of the query language.
+
+
+
+
+
+ Optional features of the query language, grouped by feature type.
+ This includes listing user defined functions, geometry support, or
+ similar concepts.
+
+
+
+
+
+
+
+ One version of the language supported by the service.
+ If the service supports more than one version of the language, include
+ multiple version elements. It is recommended that you use a version numbering scheme like
+ MAJOR.MINOR in such a way that sorting by ascending character codes will leave the most
+ recent version at the bottom of the list.
+
+
+
+
+
+
+ An optional IVORN of the language.
+ To more formally define a language supported by a service, a resource
+ record for the language can be created, either centrally on the Registry of Registries
+ or by other registry operators. When such a record exists, the language element's
+ ivo-id should point to it.
+
+
+
+
+
+
+
+
+ An enumeration of non-standard or non-mandatory features of a specific type
+ implemented by the language.
+ A feature type is a language-dependent concept like "user defined
+ function", "geometry support", or possibly "units supported". A featureList gives all
+ features of a given type applicable for the service. Multiple featureLists are possible. All
+ feature in a given list are of the same type. This type is declared using the mandatory type
+ attribute, the value of which will typically be an IVORN. To see values defined in
+ TAPRegExt, retrieve the ivo://ivoa.net/std/TAPRegExt resource record and look for keys
+ starting with "features-".
+
+
+
+
+ A language feature of the type given by this element's type attribute.
+
+
+
+
+
+ The type of the features given here.
+ This is in general an IVORN. TAPRegExt itself gives IVORNs for defining
+ user defined functions and geometry support.
+
+
+
+
+
+
+ A non-standard or non-mandatory feature implemented by the language..
+
+
+
+
+ Formal notation for the language feature.
+ The syntax for the content of this element is defined by the type
+ attribute of its parent language list.
+
+
+
+
+ Human-readable freeform documentation for the language feature.
+
+
+
+
+
+
+
+ An output format supported by the service.
+ All TAP services must support VOTable output, preserving the MIME type of
+ the input. Other output formats are optional. The primary identifier for an output format is
+ the MIME type. If you want to register an output format, you must use a MIME type (or make
+ one up using the x- syntax), although the concrete MIME syntax is not enforced by the
+ schema. For more detailed specification, an IVORN may be used.
+
+
+
+
+
+ The MIME type of this format.
+ The format of this string is specified by RFC 2045. The service has to
+ accept this string as a value of the FORMAT parameter.
+
+
+
+
+
+ Other values of FORMAT ("shorthands") that make the service return
+ documents with the MIME type.
+
+
+
+
+
+
+
+ An optional IVORN of the output format.
+ When the MIME type does not uniquely define the format (or a generic MIME
+ like application/octet-stream or text/plain is given), the IVORN can point to a key or
+ StandardsRegExt document defining the format more precisely. To see values defined in
+ TAPRegExt, retrieve the ivo://ivoa.net/std/TAPRegExt resource record and look for keys
+ starting with "output-".
+
+
+
+
+
+
+
+ An upload method as defined by IVOA.
+ Upload methods are always identified by an IVORN. Descriptions can be
+ obtained by dereferencing this IVORN. To see values defined in TAPRegExt, retrieve the
+ ivo://ivoa.net/std/TAPRegExt resource record and look for keys starting with "upload-". You
+ can register custom upload methods, but you must use the standard IVORNs for the upload
+ methods defined in the TAP specification.
+
+
+
+
+
+
+ The IVORN of the upload method.
+
+
+
+
+
+
+
+
+
+ Time-valued limits, all values given in seconds.
+
+
+
+
+
+ The value of this limit for newly-created jobs, given in seconds.
+
+
+
+
+ The value this limit cannot be raised above, given in seconds.
+
+
+
+
+
+
+
+ Limits on data sizes, given in rows or bytes.
+
+
+
+
+
+ The value of this limit for newly-created jobs.
+
+
+
+
+ The value this limit cannot be raised above.
+
+
+
+
+
+
+
+ A limit on some data size, either in rows or in bytes.
+
+
+
+
+
+
+ The unit of the limit specified.
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/tapregext/TAPRegExt-v1.0-with-erratum1.xsd.xml b/tests/tapregext/TAPRegExt-v1.0-with-erratum1.xsd.xml
deleted file mode 100644
index c1e9ccd..0000000
--- a/tests/tapregext/TAPRegExt-v1.0-with-erratum1.xsd.xml
+++ /dev/null
@@ -1,521 +0,0 @@
-
-
-
-
-
-
-
- TAPRegExt
- xs
- tr
-
-
- A description of the capabilities metadata for TAP services.
-
-
-
-
-
-
- An abstract capability that fixes the standardID to the
- IVOA ID for the TAP standard.
-
-
- See vr:Capability for documentation on inherited children.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The capabilities of a TAP server.
-
-
- The capabilities attempt to define most issues that the
- TAP standard leaves to the implementors ("may", "should").
-
-
-
-
-
-
-
-
-
- Identifier of IVOA-approved data model supported by the
- service.
-
-
-
-
-
-
-
- Language supported by the service.
-
-
-
-
-
-
-
- Output format supported by the service.
-
-
-
-
-
-
-
- Upload method supported by the service.
-
-
- The absence of upload methods indicates
- that the service does not support uploads
- at all.
-
-
-
-
-
-
-
- Limits on the time between job creation and
- destruction time.
-
-
-
-
-
-
-
- Limits on executionDuration.
-
-
-
-
-
-
-
- Limits on the size of data returned.
-
-
-
-
-
-
-
- Limits on the size of uploaded data.
-
-
-
-
-
-
-
-
-
-
-
-
-
- An IVOA defined data model, identified by an IVORN
- intended for machine consumption and a short label
- intended for human comsumption.
-
-
-
-
-
-
-
-
- The IVORN of the data model.
-
-
-
-
-
-
-
-
-
-
- A query language supported by the service.
-
-
- Each language element can describe one or more versions
- of a language. Either name alone or name-version can be
- used as values for the server's LANG parameter.
-
-
-
-
-
-
-
- The name of the language without a version suffix.
-
-
-
-
-
-
-
- A version of the language supported by the server.
-
-
-
-
-
-
-
- A short, human-readable description of the
- query language.
-
-
-
-
-
-
-
- Optional features of the query language, grouped by
- feature type.
-
-
- This includes listing user defined functions, geometry support,
- or similar concepts.
-
-
-
-
-
-
-
-
-
- One version of the language supported by the service.
-
-
- If the service supports more than one version of the
- language, include multiple version elements.
- It is recommended that you use a version numbering
- scheme like MAJOR.MINOR in such a way that sorting
- by ascending character codes will leave the most
- recent version at the bottom of the list.
-
-
-
-
-
-
-
-
- An optional IVORN of the language.
-
-
- To more formally define a language supported by a service,
- a resource record for the language can be created, either
- centrally on the Registry of Registries or by other registry operators.
- When such a record exists, the language element's ivo-id
- should point to it.
-
-
-
-
-
-
-
-
-
-
- An enumeration of non-standard or non-mandatory features of
- a specific type implemented by the language.
-
-
- A feature type is a language-dependent concept like
- "user defined function", "geometry support", or possibly
- "units supported". A featureList gives all features of
- a given type applicable for the service. Multiple featureLists
- are possible.
-
- All feature in a given list are of the same type. This type
- is declared using the mandatory type attribute,
- the value of which will typically be an IVORN.
- To see values defined in TAPRegExt,
- retrieve the ivo://ivoa.net/std/TAPRegExt
- resource record and look for keys starting with "features-".
-
-
-
-
-
-
- A language feature of the type given by this
- element's type attribute.
-
-
-
-
-
-
-
- The type of the features given here.
-
-
- This is in general an IVORN. TAPRegExt itself gives
- IVORNs for defining user defined functions and geometry
- support.
-
-
-
-
-
-
-
-
- A non-standard or non-mandatory feature implemented
- by the language..
-
-
-
-
-
-
- Formal notation for the language feature.
-
-
- The syntax for the content of this element is defined by the
- type attribute of its parent language list.
-
-
-
-
-
-
- Human-readable freeform documentation for the language feature.
-
-
-
-
-
-
-
-
-
- An output format supported by the service.
-
-
- All TAP services must support VOTable output, preserving
- the MIME type of the input. Other output formats are
- optional.
-
- The primary identifier for an output format is the MIME
- type. If you want to register an output format, you must
- use a MIME type (or make one up using the x- syntax), although
- the concrete MIME syntax is not enforced by the schema.
-
- For more detailed specification, an IVORN may be used.
-
-
-
-
-
-
-
- The MIME type of this format.
-
-
- The format of this string is specified by RFC 2045.
- The service has to accept this string as a
- value of the FORMAT parameter.
-
-
-
-
-
-
-
- Other values of FORMAT ("shorthands") that make the service return
- documents with the MIME type.
-
-
-
-
-
-
-
-
-
- An optional IVORN of the output format.
-
-
- When the MIME type does not uniquely define the
- format (or a generic MIME like application/octet-stream or
- text/plain is given), the IVORN can point to a key
- or StandardsRegExt document defining the format more
- precisely. To see values defined in TAPRegExt,
- retrieve the ivo://ivoa.net/std/TAPRegExt
- resource record and look for keys starting with "output-".
-
-
-
-
-
-
-
-
-
- An upload method as defined by IVOA.
-
-
- Upload methods are always identified by an IVORN.
- Descriptions can be obtained by dereferencing this
- IVORN. To see values defined in TAPRegExt,
- retrieve the ivo://ivoa.net/std/TAPRegExt
- resource record and look for keys starting with "upload-".
-
-
- You can register custom upload methods, but you must use the
- standard IVORNs for the upload methods defined in the TAP
- specification.
-
-
-
-
-
-
-
-
- The IVORN of the upload method.
-
-
-
-
-
-
-
-
-
-
-
- Time-valued limits, all values given in seconds.
-
-
-
-
-
-
-
- The value of this limit for newly-created jobs, given in seconds.
-
-
-
-
-
-
- The value this limit cannot be raised above, given in seconds.
-
-
-
-
-
-
-
-
-
- Limits on data sizes, given in rows or bytes.
-
-
-
-
-
-
-
- The value of this limit for newly-created jobs.
-
-
-
-
-
-
- The value this limit cannot be raised above.
-
-
-
-
-
-
-
-
-
- A limit on some data size, either in rows or in bytes.
-
-
-
-
-
-
-
-
- The unit of the limit specified.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tests/tapregext/tapregext_models_test.py b/tests/tapregext/tapregext_models_test.py
new file mode 100644
index 0000000..b859a8c
--- /dev/null
+++ b/tests/tapregext/tapregext_models_test.py
@@ -0,0 +1,380 @@
+"""Tests for TAPRegExt models."""
+
+from unittest import TestCase
+from xml.etree.ElementTree import canonicalize
+
+from lxml import etree
+
+from vo_models.tapregext import (
+ DataLimit,
+ DataLimits,
+ DataModelType,
+ Language,
+ LanguageFeature,
+ LanguageFeatureList,
+ OutputFormat,
+ TableAccess,
+ TAPCapRestriction,
+ TimeLimits,
+ UploadMethod,
+ Version,
+)
+from vo_models.voresource import Validation
+
+TAPREGEXT_NAMESPACE_HEADER = """xmlns:xs="http://www.w3.org/2001/XMLSchema"
+xmlns:vr="http://www.ivoa.net/xml/VOResource/v1.0"
+xmlns:vm="http://www.ivoa.net/xml/VOMetadata/v0.1"
+xmlns="http://www.ivoa.net/xml/TAPRegExt/v1.0"
+"""
+
+with open("tests/tapregext/TAPRegExt-v1.0-with-erratum1.xsd") as schema_file:
+ tapregext_schema = etree.XMLSchema(etree.parse(schema_file))
+
+
+class TestVersion(TestCase):
+ """Tests the Version model."""
+
+ test_version_model = Version(value="1.0", ivo_id="ivo://ivoa.net/std/TAP")
+ test_version_xml = f'1.0'
+
+ def test_read_from_xml(self):
+ """Test reading a Version element from XML."""
+ version = Version.from_xml(self.test_version_xml)
+ self.assertEqual(version.value, "1.0")
+ self.assertEqual(version.ivo_id, "ivo://ivoa.net/std/TAP")
+
+ def test_write_xml(self):
+ """Test we can write a Version element to XML."""
+ version_xml = self.test_version_model.to_xml()
+ self.assertEqual(
+ canonicalize(etree.tostring(etree.fromstring(self.test_version_xml))),
+ canonicalize(
+ etree.tostring(etree.fromstring(version_xml)),
+ ),
+ )
+
+
+class TestLanguageFeature(TestCase):
+ """Tests the LanguageFeature model."""
+
+ test_language_feature_model = LanguageFeature(form="Formal notation", description="A description")
+ test_language_feature_xml = f"A description"
+
+ def test_read_from_xml(self):
+ """Test reading a LanguageFeature element from XML."""
+ language_feature = LanguageFeature.from_xml(self.test_language_feature_xml)
+ self.assertEqual(language_feature.form, "Formal notation")
+ self.assertEqual(language_feature.description, "A description")
+
+ def test_write_xml(self):
+ """Test we can write a LanguageFeature element to XML."""
+ language_feature_xml = self.test_language_feature_model.to_xml()
+ self.assertEqual(
+ canonicalize(etree.tostring(etree.fromstring(self.test_language_feature_xml))),
+ canonicalize(
+ etree.tostring(etree.fromstring(language_feature_xml)),
+ ),
+ )
+
+
+class TestOutputFormat(TestCase):
+ """Tests the OutputFormat model."""
+
+ test_output_format_model = OutputFormat(
+ mime="application/x-votable+xml",
+ alias=["VOTABLE"],
+ )
+ test_output_format_xml = (
+ f""
+ "application/x-votable+xml"
+ "VOTABLE"
+ ""
+ )
+
+ def test_read_from_xml(self):
+ """Test reading an OutputFormat element from XML."""
+ output_format = OutputFormat.from_xml(self.test_output_format_xml)
+ self.assertEqual(output_format.mime, "application/x-votable+xml")
+ self.assertEqual(output_format.alias[0], "VOTABLE")
+
+ def test_write_xml(self):
+ """Test we can write an OutputFormat element to XML."""
+ output_format_xml = self.test_output_format_model.to_xml()
+ self.assertEqual(
+ canonicalize(etree.tostring(etree.fromstring(self.test_output_format_xml))),
+ canonicalize(
+ etree.tostring(etree.fromstring(output_format_xml)),
+ ),
+ )
+
+
+class TestUploadMethod(TestCase):
+ """Tests the UploadMethod model."""
+
+ test_upload_method_model = UploadMethod(
+ ivo_id="ivo://ivoa.net/std/TAP",
+ )
+ test_upload_method_xml = f''
+
+ def test_read_from_xml(self):
+ """Test reading an UploadMethod element from XML."""
+ upload_method = UploadMethod.from_xml(self.test_upload_method_xml)
+ self.assertEqual(upload_method.ivo_id, "ivo://ivoa.net/std/TAP")
+
+ def test_write_xml(self):
+ """Test we can write an UploadMethod element to XML."""
+ upload_method_xml = self.test_upload_method_model.to_xml()
+ self.assertEqual(
+ canonicalize(etree.tostring(etree.fromstring(self.test_upload_method_xml))),
+ canonicalize(
+ etree.tostring(etree.fromstring(upload_method_xml)),
+ ),
+ )
+
+
+class TestTimeLimitsElement(TestCase):
+ """Tests the TimeLimits model."""
+
+ test_time_limits_model = TimeLimits(default=10, hard=100)
+ test_time_limits_xml = (
+ f"10100"
+ )
+
+ def test_read_from_xml(self):
+ """Test reading a TimeLimits element from XML."""
+ time_limits = TimeLimits.from_xml(self.test_time_limits_xml)
+ self.assertEqual(time_limits.default, 10)
+ self.assertEqual(time_limits.hard, 100)
+
+ def test_write_xml(self):
+ """Test we can write a TimeLimits element to XML."""
+ time_limits_xml = self.test_time_limits_model.to_xml()
+ self.assertEqual(
+ canonicalize(etree.tostring(etree.fromstring(self.test_time_limits_xml))),
+ canonicalize(
+ etree.tostring(etree.fromstring(time_limits_xml)),
+ ),
+ )
+
+
+class TestDataLimitsElement(TestCase):
+ """Tests the DataLimits model."""
+
+ test_data_limits_model = DataLimits(
+ default={"value": 10, "unit": "row"},
+ hard={"value": 100, "unit": "row"},
+ )
+ test_data_limits_xml = (
+ f""
+ '10'
+ '100'
+ ""
+ )
+
+ def test_read_from_xml(self):
+ """Test reading a DataLimits element from XML."""
+ data_limits = DataLimits.from_xml(self.test_data_limits_xml)
+ self.assertEqual(data_limits.default.value, 10)
+ self.assertEqual(data_limits.hard.value, 100)
+
+ def test_write_xml(self):
+ """Test we can write a DataLimits element to XML."""
+ data_limits_xml = self.test_data_limits_model.to_xml()
+ self.assertEqual(
+ canonicalize(etree.tostring(etree.fromstring(self.test_data_limits_xml))),
+ canonicalize(
+ etree.tostring(etree.fromstring(data_limits_xml)),
+ ),
+ )
+
+
+class TestDataLimitElement(TestCase):
+ """Tests the DataLimit model."""
+
+ test_data_limit_model = DataLimit(value=10, unit="byte")
+ test_data_limit_xml = f'10'
+
+ def test_read_from_xml(self):
+ """Test reading a DataLimit element from XML."""
+ data_limit = DataLimit.from_xml(self.test_data_limit_xml)
+ self.assertEqual(data_limit.value, 10)
+ self.assertEqual(data_limit.unit, "byte")
+
+ def test_write_xml(self):
+ """Test we can write a DataLimit element to XML."""
+ data_limit_xml = self.test_data_limit_model.to_xml()
+ self.assertEqual(
+ canonicalize(etree.tostring(etree.fromstring(self.test_data_limit_xml))),
+ canonicalize(
+ etree.tostring(etree.fromstring(data_limit_xml)),
+ ),
+ )
+
+
+class TestLanguageFeatureList(TestCase):
+ """Tests the LanguageFeatureList model."""
+
+ test_language_feature_list_model = LanguageFeatureList(
+ feature=[
+ LanguageFeature(form="Formal notation", description="A description"),
+ LanguageFeature(form="Informal notation", description="Another description"),
+ ],
+ type="adql-some-feature",
+ )
+ test_language_feature_list_xml = (
+ f''
+ "A description"
+ "Another description"
+ ""
+ )
+
+ def test_read_from_xml(self):
+ """Test reading a LanguageFeatureList element from XML."""
+ language_feature_list = LanguageFeatureList.from_xml(self.test_language_feature_list_xml)
+ self.assertEqual(language_feature_list.feature[0].form, "Formal notation")
+ self.assertEqual(language_feature_list.feature[0].description, "A description")
+ self.assertEqual(language_feature_list.feature[1].form, "Informal notation")
+ self.assertEqual(language_feature_list.feature[1].description, "Another description")
+
+ def test_write_xml(self):
+ """Test we can write a LanguageFeatureList element to XML."""
+ language_feature_list_xml = self.test_language_feature_list_model.to_xml()
+ self.assertEqual(
+ canonicalize(etree.tostring(etree.fromstring(self.test_language_feature_list_xml))),
+ canonicalize(
+ etree.tostring(etree.fromstring(language_feature_list_xml)),
+ ),
+ )
+
+
+class TestLanguage(TestCase):
+ """Tests the Language model."""
+
+ test_language_model = Language(
+ name="ADQL",
+ version=[Version(value="2.0", ivo_id="ivo://ivoa.net/std/ADQL")],
+ description="Astronomical Data Query Language",
+ language_features=[
+ LanguageFeatureList(
+ feature=[
+ LanguageFeature(form="Formal notation", description="A description"),
+ LanguageFeature(form="Informal notation", description="Another description"),
+ ],
+ type="adql-some-feature",
+ )
+ ],
+ )
+ test_language_xml = (
+ f""
+ "ADQL"
+ "2.0"
+ "Astronomical Data Query Language"
+ ''
+ "A description"
+ "Another description"
+ ""
+ ""
+ )
+
+ def test_read_from_xml(self):
+ """Test reading a Language element from XML."""
+ language = Language.from_xml(self.test_language_xml)
+ self.assertEqual(language.name, "ADQL")
+ self.assertEqual(language.version[0].value, "2.0")
+ self.assertEqual(language.description, "Astronomical Data Query Language")
+ self.assertEqual(language.language_features[0].feature[0].form, "Formal notation")
+ self.assertEqual(language.language_features[0].feature[0].description, "A description")
+ self.assertEqual(language.language_features[0].feature[1].form, "Informal notation")
+ self.assertEqual(language.language_features[0].feature[1].description, "Another description")
+
+ def test_write_xml(self):
+ """Test we can write a Language element to XML."""
+ language_xml = self.test_language_model.to_xml()
+ self.assertEqual(
+ canonicalize(etree.tostring(etree.fromstring(self.test_language_xml))),
+ canonicalize(
+ etree.tostring(etree.fromstring(language_xml)),
+ ),
+ )
+
+
+class TestTableAccess(TestCase):
+ """Tests the TableAccess model."""
+
+ test_table_access_model = TableAccess(
+ data_model=[DataModelType(value="VOTable", ivo_id="ivo://ivoa.net/std/VOTable")],
+ language=[
+ Language(
+ name="ADQL",
+ version=[Version(value="2.0", ivo_id="ivo://ivoa.net/std/ADQL")],
+ description="Astronomical Data Query Language",
+ language_features=[
+ LanguageFeatureList(
+ feature=[
+ LanguageFeature(form="Formal notation", description="A description"),
+ LanguageFeature(form="Informal notation", description="Another description"),
+ ],
+ type="adql-some-feature",
+ )
+ ],
+ )
+ ],
+ output_format=[
+ OutputFormat(
+ mime="application/x-votable+xml",
+ alias=["VOTABLE"],
+ )
+ ],
+ upload_method=[
+ UploadMethod(
+ value="HTTP",
+ ivo_id="ivo://ivoa.net/std/TAP",
+ )
+ ],
+ retention_period=TimeLimits(default=10, hard=100),
+ output_limit=DataLimits(
+ default={"value": 10, "unit": "row"},
+ hard={"value": 100, "unit": "row"},
+ ),
+ )
+ test_table_access_xml = (
+ f""
+ "VOTable"
+ ""
+ "ADQL"
+ "2.0"
+ "Astronomical Data Query Language"
+ ""
+ "A description"
+ "Another description"
+ ""
+ ""
+ "application/x-votable+xml;content=datalink"
+ ""
+ "10100"
+ ""
+ '10'
+ '100'
+ ""
+ ""
+ )
+
+ def test_read_from_xml(self):
+ """Test reading a TableAccess element from XML."""
+ table_access = TableAccess.from_xml(self.test_table_access_xml)
+ self.assertEqual(table_access.data_model[0].value, "VOTable")
+ self.assertEqual(table_access.data_model[0].ivo_id, "ivo://ivoa.net/std/VOTable")
+ self.assertEqual(table_access.language[0].name, "ADQL")
+ self.assertEqual(table_access.language[0].version[0].value, "2.0")
+ self.assertEqual(table_access.language[0].description, "Astronomical Data Query Language")
+ self.assertEqual(table_access.language[0].language_features[0].feature[0].form, "Formal notation")
+ self.assertEqual(table_access.language[0].language_features[0].feature[0].description, "A description")
+ self.assertEqual(table_access.language[0].language_features[0].feature[1].form, "Informal notation")
+ self.assertEqual(table_access.language[0].language_features[0].feature[1].description, "Another description")
+ self.assertEqual(table_access.output_format[0].mime, "application/x-votable+xml")
+ self.assertEqual(table_access.output_format[0].alias[0], "VOTABLE")
+ self.assertEqual(table_access.upload_method[0].ivo_id, "ivo://ivoa.net/std/TAP")
+ self.assertEqual(table_access.retention_period.default, 10)
+ self.assertEqual(table_access.retention_period.hard, 100)
+ self.assertEqual(table_access.output_limit.default.value, 10)
+ self.assertEqual(table_access.output_limit.hard.value, 100)
diff --git a/tests/voresource/voresource_models_test.py b/tests/voresource/voresource_models_test.py
new file mode 100644
index 0000000..b390046
--- /dev/null
+++ b/tests/voresource/voresource_models_test.py
@@ -0,0 +1,29 @@
+"""Tests for VOResource models."""
+
+from unittest import TestCase
+from xml.etree.ElementTree import canonicalize
+
+from lxml import etree
+
+from vo_models.voresource import (
+ AccessURL,
+ Capability,
+ Contact,
+ Content,
+ Creator,
+ Curation,
+ Date,
+ Interface,
+ MirrorURL,
+ Organisation,
+ Relationship,
+ Resource,
+ ResourceName,
+ Rights,
+ SecurityMethod,
+ Service,
+ Source,
+ Validation,
+ WebBrowser,
+ WebService,
+)
diff --git a/vo_models/tapregext/__init__.py b/vo_models/tapregext/__init__.py
index 94de027..8346993 100644
--- a/vo_models/tapregext/__init__.py
+++ b/vo_models/tapregext/__init__.py
@@ -3,3 +3,18 @@
IVOA UWS Spec: https://ivoa.net/documents/TAPRegExt/20120827/REC-TAPRegExt-1.0.html
"""
+
+from vo_models.tapregext.models import (
+ DataLimit,
+ DataLimits,
+ DataModelType,
+ Language,
+ LanguageFeature,
+ LanguageFeatureList,
+ OutputFormat,
+ TableAccess,
+ TAPCapRestriction,
+ TimeLimits,
+ UploadMethod,
+ Version,
+)
diff --git a/vo_models/tapregext/models.py b/vo_models/tapregext/models.py
index aeb7f4d..1e42feb 100644
--- a/vo_models/tapregext/models.py
+++ b/vo_models/tapregext/models.py
@@ -11,21 +11,21 @@
"xs": "http://www.w3.org/2001/XMLSchema",
"vr": "http://www.ivoa.net/xml/VOResource/v1.0",
"vm": "http://www.ivoa.net/xml/VOMetadata/v0.1",
- "tr": "http://www.ivoa.net/xml/TAPRegExt/v1.0",
+ "": "http://www.ivoa.net/xml/TAPRegExt/v1.0",
}
class TAPCapRestriction(Capability, nsmap=NSMAP):
"""An abstract capability that fixes the standardID to the IVOA ID for the TAP standard."""
- validation_level: Optional[list[Validation]] = element(tag="validationLevel", default_factory=[])
+ validation_level: Optional[list[Validation]] = element(tag="validationLevel", default_factory=list)
description: Optional[str] = element(tag="description", default=None)
- interface: Optional[list[Interface]] = element(tag="interface", default_factory=[])
+ interface: Optional[list[Interface]] = element(tag="interface", default_factory=list)
- standard_id: IdentifierURI = attr(tag="standardID", default="ivo://ivoa.net/std/TAP")
+ standard_id: IdentifierURI = attr(name="standardID", default="ivo://ivoa.net/std/TAP")
-class DataModelType(BaseXmlModel, nsmap=NSMAP):
+class DataModelType(BaseXmlModel, tag="dataModel", nsmap=NSMAP):
"""IVOA defined data model, identified by an IVORN.
Parameters:
@@ -36,10 +36,10 @@ class DataModelType(BaseXmlModel, nsmap=NSMAP):
"""
value: str
- ivo_id: str = attr(tag="ivo-id")
+ ivo_id: str = attr(name="ivo-id")
-class Version(BaseXmlModel, nsmap=NSMAP):
+class Version(BaseXmlModel, tag="version", nsmap=NSMAP):
"""One version of the language supported by the service.
Parameters:
@@ -50,10 +50,10 @@ class Version(BaseXmlModel, nsmap=NSMAP):
"""
value: str
- ivo_id: Optional[str] = attr(tag="ivo-id", default=None)
+ ivo_id: Optional[str] = attr(name="ivo-id", default=None)
-class LanguageFeature(BaseXmlModel, nsmap=NSMAP):
+class LanguageFeature(BaseXmlModel, tag="languageFeature", nsmap=NSMAP):
"""A non-standard or non-mandatory feature implemented by the language.
Parameters:
@@ -67,7 +67,7 @@ class LanguageFeature(BaseXmlModel, nsmap=NSMAP):
description: Optional[str] = element(tag="description", default=None)
-class OutputFormat(BaseXmlModel, nsmap=NSMAP):
+class OutputFormat(BaseXmlModel, tag="outputFormat", nsmap=NSMAP):
"""An output format supported by the service.
Parameters:
@@ -78,10 +78,10 @@ class OutputFormat(BaseXmlModel, nsmap=NSMAP):
"""
mime: str = element(tag="mime")
- alias: Optional[list[str]] = element(tag="alias", default_factory=[])
+ alias: Optional[list[str]] = element(tag="alias", default_factory=list)
-class UploadMethod(BaseXmlModel, nsmap=NSMAP):
+class UploadMethod(BaseXmlModel, tag="uploadMethod", nsmap=NSMAP):
"""An upload method as defined by IVOA.
Parameters:
@@ -89,10 +89,10 @@ class UploadMethod(BaseXmlModel, nsmap=NSMAP):
(attribute) - The IVORN of the upload method.
"""
- ivo_id: str = attr(tag="ivo-id")
+ ivo_id: str = attr(name="ivo-id")
-class TimeLimits(BaseXmlModel, nsmap=NSMAP):
+class TimeLimits(BaseXmlModel, tag="timeLimits", nsmap=NSMAP):
"""Time-valued limits, all values given in seconds.
Parameters:
@@ -106,21 +106,7 @@ class TimeLimits(BaseXmlModel, nsmap=NSMAP):
hard: Optional[int] = element(tag="hard", default=None)
-class DataLimits(BaseXmlModel, nsmap=NSMAP):
- """Limits on data sizes, given in rows or bytes.
-
- Parameters:
- default:
- (element) - The value of this limit for newly-created jobs.
- hard:
- (element) - The value this limit cannot be raised above.
- """
-
- default: Optional[int] = element(tag="default", default=None)
- hard: Optional[int] = element(tag="hard", default=None)
-
-
-class DataLimit(BaseXmlModel, nsmap=NSMAP):
+class DataLimit(BaseXmlModel, tag="dataLimit", nsmap=NSMAP):
"""A limit on some data size, either in rows or in bytes.
Parameters:
@@ -131,10 +117,24 @@ class DataLimit(BaseXmlModel, nsmap=NSMAP):
"""
value: int
- unit: Literal["byte", "row"] = attr(tag="unit")
+ unit: Literal["byte", "row"] = attr(name="unit")
+
+
+class DataLimits(BaseXmlModel, tag="dataLimits", nsmap=NSMAP):
+ """Limits on data sizes, given in rows or bytes.
+
+ Parameters:
+ default:
+ (element) - The value of this limit for newly-created jobs.
+ hard:
+ (element) - The value this limit cannot be raised above.
+ """
+
+ default: Optional[DataLimit] = element(tag="default", default=None)
+ hard: Optional[DataLimit] = element(tag="hard", default=None)
-class LanguageFeatureList(BaseXmlModel, nsmap=NSMAP):
+class LanguageFeatureList(BaseXmlModel, tag="languageFeatures", nsmap=NSMAP):
"""An enumeration of non-standard or non-mandatory features of a specific type implemented by the language.
Parameters:
@@ -144,11 +144,11 @@ class LanguageFeatureList(BaseXmlModel, nsmap=NSMAP):
(attribute) - The type of the language feature.
"""
- feature: Optional[list[LanguageFeature]] = element(tag="feature", default_factory=[])
- type: str = attr(tag="type")
+ feature: Optional[list[LanguageFeature]] = element(tag="feature", default_factory=list)
+ type: str = attr(name="type")
-class Language(BaseXmlModel, nsmap=NSMAP):
+class Language(BaseXmlModel, tag="language", nsmap=NSMAP):
"""A query language supported by the service.
Parameters:
@@ -168,7 +168,7 @@ class Language(BaseXmlModel, nsmap=NSMAP):
language_features: Optional[list[LanguageFeatureList]] = element(tag="languageFeatures", default_factory=[])
-class TableAccess(TAPCapRestriction):
+class TableAccess(TAPCapRestriction, tag="capability", ns="vr", nsmap=NSMAP):
"""The capabilities of a TAP server.
Parameters:
diff --git a/vo_models/voresource/models.py b/vo_models/voresource/models.py
index 55c62dc..1b591ee 100644
--- a/vo_models/voresource/models.py
+++ b/vo_models/voresource/models.py
@@ -2,10 +2,10 @@
import datetime
from typing import Literal, Optional
-from pydantic import field_validator, networks, types
-from pydantic_xml import BaseXmlModel, RootXmlModel, attr, element
+from pydantic import field_validator, networks
+from pydantic_xml import BaseXmlModel, attr, element
-from vo_models.voresource.types import IdentifierURI, UTCDateTime, UTCTimestamp, ValidationLevel
+from vo_models.voresource.types import IdentifierURI, UTCTimestamp, ValidationLevel
# pylint: disable=no-self-argument
# pylint: disable=too-few-public-methods