diff --git a/setup.py b/setup.py index a289552..c9a4113 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ # This call to setup() does all the work setup( name="to_cei", - version="0.1.3", + version="0.1.4", description="to-CEI", long_description=long_description, long_description_content_type="text/markdown", diff --git a/test/test_charter.py b/test/test_charter.py index a440084..d073dfd 100644 --- a/test/test_charter.py +++ b/test/test_charter.py @@ -1,17 +1,17 @@ -from datetime import datetime import pathlib +from datetime import datetime from typing import List import pytest from astropy.time.core import Time from lxml import etree +from pytest_helpers import xp, xps +from to_cei.charter import NO_DATE_TEXT, NO_DATE_VALUE, Charter from to_cei.config import CEI, CHARTER_NSS from to_cei.helpers import ln -from to_cei.charter import NO_DATE_TEXT, NO_DATE_VALUE, Charter from to_cei.seal import Seal from to_cei.validator import Validator -from pytest_helpers import xp, xps # --------------------------------------------------------------------# # Charter as a whole # @@ -77,6 +77,7 @@ def test_is_valid_charter(): ) Validator().validate_cei(charter.to_xml()) + def test_writes_correct_file(tmp_path): d = tmp_path charter = Charter("1A") @@ -86,6 +87,7 @@ def test_writes_correct_file(tmp_path): written = etree.parse(str(out)) Validator().validate_cei(written.getroot()) + # --------------------------------------------------------------------# # Charter abstract # # --------------------------------------------------------------------# @@ -117,6 +119,12 @@ def test_has_correct_xml_abstract(): assert pers_name_xml.text == pers_name +def test_has_no_abstract_for_empty_text(): + abstract = "" + charter = Charter(id_text="1", abstract=abstract) + assert charter.abstract == None + + def test_raises_exception_for_incorrect_xml_abstract(): incorrect_element = CEI.persName("A person") with pytest.raises(ValueError): @@ -139,6 +147,12 @@ def test_has_correct_charter_archive(): assert archive_xml.text == archive +def test_has_no_archive_for_empty_text(): + archive = "" + charter = Charter(id_text="1", archive=archive) + assert charter.archive == None + + # --------------------------------------------------------------------# # Charter bibliographies # # --------------------------------------------------------------------# @@ -155,6 +169,18 @@ def test_has_correct_abstract_bibl(): assert bibl.text == bibl_text +def test_has_no_sources_for_empty_string(): + bibl_texts = "" + sources = xp( + Charter( + id_text="1", + abstract_sources=bibl_texts, + ), + "/cei:text/cei:front/cei:sourceDesc/cei:sourceDescRegest/*", + ) + assert len(sources) == 0 + + def test_has_correct_abstract_sources(): bibl_texts = ["Bibl a", "Bibl b"] sources = xp( @@ -169,7 +195,7 @@ def test_has_correct_abstract_sources(): assert sources[1].text == bibl_texts[1] -def test_has_correct_transcription_bibl(): +def test_has_correct_transcription_source(): bibl_text = "Bibl a" charter = Charter( id_text="1", @@ -182,6 +208,15 @@ def test_has_correct_transcription_bibl(): assert sources.text == bibl_text +def test_has_no_transcription_sources_for_empty_text(): + bibl_text = "" + charter = Charter( + id_text="1", + transcription_sources=bibl_text, + ) + assert len(charter.transcription_sources) == 0 + + def test_has_correct_transcription_sources(): bibl_texts = ["Bibl a", "Bibl b"] sources = xp( @@ -205,7 +240,7 @@ def test_has_correct_single_chancellary_remark(): chancellary_remarks = "Remark" charter = Charter(id_text="1", chancellary_remarks=chancellary_remarks) assert isinstance(charter.chancellary_remarks, List) - assert charter._chancellary_remarks[0] == chancellary_remarks + assert charter.chancellary_remarks[0] == chancellary_remarks nota = xps(charter, "/cei:text/cei:body/cei:chDesc/cei:witnessOrig/cei:nota") assert nota.text == chancellary_remarks @@ -213,13 +248,19 @@ def test_has_correct_single_chancellary_remark(): def test_has_correct_chancellary_remarks_list(): chancellary_remarks = ["Remark a", "Remark b"] charter = Charter(id_text="1", chancellary_remarks=chancellary_remarks) - assert charter._chancellary_remarks == chancellary_remarks + assert charter.chancellary_remarks == chancellary_remarks nota = xp(charter, "/cei:text/cei:body/cei:chDesc/cei:witnessOrig/cei:nota") assert len(nota) == 2 assert nota[0].text == chancellary_remarks[0] assert nota[1].text == chancellary_remarks[1] +def test_has_no_chancellary_remarks_for_empty_text(): + chancellary_remarks = "" + charter = Charter(id_text="1", chancellary_remarks=chancellary_remarks) + assert len(charter.chancellary_remarks) == 0 + + # --------------------------------------------------------------------# # Charter comments # # --------------------------------------------------------------------# @@ -228,7 +269,7 @@ def test_has_correct_chancellary_remarks_list(): def test_has_correct_comments(): comments = ["Comment a", "Comment b"] charter = Charter(id_text="1", comments=comments) - assert charter._comments == comments + assert charter.comments == comments paragraphs = xp( charter, "/cei:text/cei:body/cei:chDesc/cei:diplomaticAnalysis/cei:p", @@ -238,6 +279,12 @@ def test_has_correct_comments(): assert paragraphs[1].text == comments[1] +def test_has_no_comments_for_empty_string(): + comments = "" + charter = Charter(id_text="1", comments=comments) + assert len(charter.comments) == 0 + + # --------------------------------------------------------------------# # Charter condition # # --------------------------------------------------------------------# @@ -254,6 +301,12 @@ def test_has_correct_charter_condition(): assert condition_xml.text == condition +def test_has_no_condition_for_empty_text(): + condition = "" + charter = Charter(id_text="1", condition=condition) + assert charter.condition == None + + # --------------------------------------------------------------------# # Charter date # # --------------------------------------------------------------------# @@ -268,6 +321,21 @@ def test_has_correct_date_range_with_99999999(): assert date_xml.get("value") == NO_DATE_VALUE +def test_has_no_date_for_empty_text(): + charter = Charter(id_text="1", date="") + assert charter.date == None + assert charter.date_value == None + + +def test_has_no_date_for_empty_value(): + charter = Charter(id_text="1", date="unknown", date_value="") + assert charter.date == "unknown" + assert charter.date_value == None + date_xml = xps(charter, "/cei:text/cei:body/cei:chDesc/cei:issued/cei:date") + assert date_xml.text == "unknown" + assert date_xml.get("value") == NO_DATE_VALUE + + def test_has_correct_date_with_99999999(): charter = Charter(id_text="1", date="unknown", date_value="99999999") assert charter.date == "unknown" @@ -501,6 +569,12 @@ def test_has_correct_text_date_quote(): assert date_quote_xml.text == date_quote +def test_has_no_quote_for_empty_text(): + date_quote = "" + charter = Charter(id_text="1", date_quote=date_quote) + assert charter.date_quote == None + + def test_has_correct_xml_date_quote(): date_quote = CEI.quoteOriginaldatierung( "Original dating with ", CEI.sup("a"), " superscript" @@ -536,6 +610,12 @@ def test_has_correct_charter_dimensions(): assert dimensions_xml.text == dimensions +def test_has_no_dimensions_for_empty_text(): + dimensions = "" + charter = Charter(id_text="1", dimensions=dimensions) + assert charter.dimensions == None + + # --------------------------------------------------------------------# # Charter external url # # --------------------------------------------------------------------# @@ -552,6 +632,12 @@ def test_has_correct_external_url(): assert external_link_xml.get("target") == external_link +def test_has_no_external_url_for_empty_text(): + external_link = "" + charter = Charter(id_text="1", external_link=external_link) + assert charter.external_link == None + + def test_raises_exception_for_invalid_external_link(): localhost = "http://localhost" with pytest.raises(ValueError): @@ -563,7 +649,7 @@ def test_raises_exception_for_invalid_external_link(): # --------------------------------------------------------------------# -def test_has_correct_list_figures(): +def test_has_correct_list_graphic_urls(): graphic_urls = ["Figure 1.jgp", "figure_2.png"] charter = Charter(id_text="1", graphic_urls=graphic_urls) assert charter.graphic_urls == graphic_urls @@ -575,7 +661,7 @@ def test_has_correct_list_figures(): assert graphics_xml[1].get("url") == graphic_urls[1] -def test_has_correct_single_figures(): +def test_has_correct_single_graphic_url(): graphic_urls = "Figure 1.jgp" charter = Charter(id_text="1", graphic_urls=graphic_urls) assert charter.graphic_urls[0] == graphic_urls @@ -585,6 +671,12 @@ def test_has_correct_single_figures(): assert graphics_xml.get("url") == graphic_urls +def test_has_empty_graphic_urls_for_empty_text(): + graphic_urls = "" + charter = Charter(id_text="1", graphic_urls=graphic_urls) + assert len(charter.graphic_urls) == 0 + + # --------------------------------------------------------------------# # Charter footnotes # # --------------------------------------------------------------------# @@ -603,6 +695,12 @@ def test_has_correct_footnotes(): assert notes[1].text == footnotes[1] +def test_has_no_footnotes_for_empty_text(): + footnotes = "" + charter = Charter(id_text="1", footnotes=footnotes) + assert len(charter._footnotes) == 0 + + # --------------------------------------------------------------------# # Charter id # # --------------------------------------------------------------------# @@ -630,6 +728,12 @@ def test_has_correct_id_norm(): assert idno.text == id_text +def test_has_correct_id_norm_for_empty_text(): + id = "1307-12-01" + charter = Charter(id_text=id, id_norm="") + assert charter.id_norm == id + + def test_has_correct_id_old(): id_old = "123456 α" idno = xps( @@ -638,6 +742,11 @@ def test_has_correct_id_old(): assert idno.get("old") == id_old +def test_has_no_id_old_for_empty_text(): + charter = Charter(id_text="1307-12-01", id_old="") + assert charter.id_old == None + + def test_raises_exception_for_missing_id(): with pytest.raises(ValueError): Charter(id_text="") @@ -777,6 +886,12 @@ def test_has_correct_text_issued_place(): assert issued_place_xml.text == issued_place +def test_has_no_issued_place_for_empty_text(): + issued_place = "" + charter = Charter(id_text="1", issued_place=issued_place) + assert charter.issued_place == None + + def test_has_correct_xml_issued_place(): issued_place = CEI.placeName("Wien") charter = Charter(id_text="1", issued_place=issued_place) @@ -810,6 +925,15 @@ def test_has_correct_abstract_with_text_issuer(): assert issuer_xml.text == issuer +def test_has_correct_abstract_with_empty_issuer(): + abstract = ( + "Konrad von Lintz, Caplan zu St. Pankraz, beurkundet den vorstehenden Vertrag." + ) + issuer = "" + charter = Charter(id_text="1", abstract=abstract, issuer=issuer) + assert charter.issuer == None + + def test_has_correct_abstract_with_xml_issuer(): abstract = ( "Konrad von Lintz, Caplan zu St. Pankraz, beurkundet den vorstehenden Vertrag." @@ -847,7 +971,13 @@ def test_has_correct_language(): charter, "/cei:text/cei:body/cei:chDesc/cei:lang_MOM", ) - language_xml.text == language + assert language_xml.text == language + + +def test_has_no_language_for_empty_string(): + language = "" + charter = Charter(id_text="1", language=language) + assert charter.language == None # --------------------------------------------------------------------# @@ -868,6 +998,12 @@ def test_has_correct_literature(): assert literature_xml[1].text == literature[1] +def test_has_no_literature_for_empty_text(): + literature = "" + charter = Charter(id_text="1", literature=literature) + assert len(charter.literature) == 0 + + def test_has_correct_literature_abstracts(): literature_abstracts = ["Entry 1", "Entry 2"] charter = Charter(id_text="1", literature_abstracts=literature_abstracts) @@ -881,6 +1017,12 @@ def test_has_correct_literature_abstracts(): assert literature_abstracts_xml[1].text == literature_abstracts[1] +def test_has_no_literature_abstracts_for_empty_text(): + literature_abstracts = "" + charter = Charter(id_text="1", literature_abstracts=literature_abstracts) + assert len(charter.literature_abstracts) == 0 + + def test_has_correct_literature_depictions(): literature_depictions = ["Entry 1", "Entry 2"] charter = Charter(id_text="1", literature_depictions=literature_depictions) @@ -894,6 +1036,12 @@ def test_has_correct_literature_depictions(): assert literature_depictions_xml[1].text == literature_depictions[1] +def test_has_no_literature_depictions_for_empty_text(): + literature_depictions = "" + charter = Charter(id_text="1", literature_depictions=literature_depictions) + assert len(charter.literature_depictions) == 0 + + def test_has_correct_literature_editions(): literature_editions = ["Entry 1", "Entry 2"] charter = Charter(id_text="1", literature_editions=literature_editions) @@ -907,6 +1055,12 @@ def test_has_correct_literature_editions(): assert literature_editions_xml[1].text == literature_editions[1] +def test_has_no_literature_editions_for_empty_text(): + literature_editions = "" + charter = Charter(id_text="1", literature_editions=literature_editions) + assert len(charter.literature_editions) == 0 + + def test_has_correct_literature_secondary(): literature_secondary = ["Entry 1", "Entry 2"] charter = Charter(id_text="1", literature_secondary=literature_secondary) @@ -920,6 +1074,12 @@ def test_has_correct_literature_secondary(): assert literature_secondary_xml[1].text == literature_secondary[1] +def test_has_no_literature_secondary_for_empty_text(): + literature_secondary = "" + charter = Charter(id_text="1", literature_secondary=literature_secondary) + assert len(charter.literature_secondary) == 0 + + # --------------------------------------------------------------------# # Charter material # # --------------------------------------------------------------------# @@ -936,6 +1096,12 @@ def test_has_correct_material(): assert material_xml.text == material +def test_has_no_material_for_empty_text(): + material = "" + charter = Charter(id_text="1", material=material) + assert charter.material == None + + # --------------------------------------------------------------------# # Charter notarial authentication # # --------------------------------------------------------------------# @@ -952,6 +1118,12 @@ def test_has_correct_text_notarial_authentication(): assert notarial_authentication_xml.text == notarial_authentication +def test_has_no_text_notarial_authentication_for_empty_text(): + notarial_authentication = "" + charter = Charter(id_text="1", notarial_authentication=notarial_authentication) + assert charter.notarial_authentication == None + + def test_has_correct_xml_notarial_authentication(): notarial_authentication = CEI.notariusDesc("An xml notarial authentication") charter = Charter(id_text="1", notarial_authentication=notarial_authentication) @@ -988,6 +1160,15 @@ def test_has_correct_abstract_with_text_recipient(): assert recipient_xml.text == recipient +def test_has_abstract_without_text_recipient_for_empty_text(): + abstract = ( + "Konrad von Lintz, Caplan zu St. Pankraz, beurkundet den vorstehenden Vertrag." + ) + recipient = "" + charter = Charter(id_text="1", abstract=abstract, recipient=recipient) + assert charter.recipient == None + + def test_has_correct_abstract_with_xml_recipient(): abstract = ( "Konrad von Lintz, Caplan zu St. Pankraz, beurkundet den vorstehenden Vertrag." @@ -1034,6 +1215,11 @@ def test_has_correct_seal_description_xml(): assert seals_xml[1].text == "Seal 2" +def test_has_no_seal_description_for_empty_text(): + charter = Charter(id_text="1", seals="") + assert charter.seals == None + + def test_has_correct_seal_text_description(): seals = "2 Siegel" charter = Charter(id_text="1", seals=seals) @@ -1111,6 +1297,12 @@ def test_has_correct_text_transcription(): assert transcription_xml.text == transcription +def test_has_no_text_transcription_for_empty_text(): + transcription = "" + charter = Charter(id_text="1", transcription=transcription) + assert charter.transcription == None + + def test_has_correct_xml_transcription(): transcription = CEI.tenor("Tenor with ", CEI.sup("a"), " superscript") charter = Charter(id_text="1", transcription=transcription) @@ -1143,6 +1335,12 @@ def test_has_correct_tradition(): assert tradition_xml.text == tradition +def test_has_no_tradition_for_empty_text(): + tradition = "" + charter = Charter(id_text="1", tradition=tradition) + assert charter.tradition == None + + # --------------------------------------------------------------------# # Charter type # # --------------------------------------------------------------------# diff --git a/to_cei/charter.py b/to_cei/charter.py index 4091c50..e4049ae 100644 --- a/to_cei/charter.py +++ b/to_cei/charter.py @@ -149,42 +149,42 @@ class Charter(XmlAssembler): def __init__( self, id_text: str, - abstract: str | etree._Element = None, - abstract_sources: str | List[str] = [], - archive: str = None, - chancellary_remarks: str | List[str] = [], - comments: str | List[str] = [], - condition: str = None, - date: str | etree._Element = None, - date_quote: str | etree._Element = None, - date_value: DateValue = None, - dimensions: str = None, - external_link: str = None, - footnotes: str | List[str] = [], - graphic_urls: str | List[str] = [], - id_norm: str = None, - id_old: str = None, - index: List[str | etree._Element] = [], - index_geo_features: List[str | etree._Element] = [], - index_organizations: List[str | etree._Element] = [], - index_persons: List[str | etree._Element] = [], - index_places: List[str | etree._Element] = [], - issued_place: str | etree._Element = None, - issuer: str | etree._Element = None, - language: str = None, - literature: str | List[str] = [], - literature_abstracts: str | List[str] = [], - literature_depictions: str | List[str] = [], - literature_editions: str | List[str] = [], - literature_secondary: str | List[str] = [], - material: str = None, - notarial_authentication: str | etree._Element = None, - recipient: str | etree._Element = None, - seals: etree._Element | str | Seal | List[str] | List[Seal] = None, - tradition: str = None, - transcription: str | etree._Element = None, - transcription_sources: str | List[str] = [], - witnesses: List[str | etree._Element] = [], + abstract: Optional[str | etree._Element] = None, + abstract_sources: Optional[str | List[str]] = [], + archive: Optional[str] = None, + chancellary_remarks: Optional[str | List[str]] = [], + comments: Optional[str | List[str]] = [], + condition: Optional[str] = None, + date: Optional[str | etree._Element] = None, + date_quote: Optional[str | etree._Element] = None, + date_value: Optional[DateValue] = None, + dimensions: Optional[str] = None, + external_link: Optional[str] = None, + footnotes: Optional[str | List[str]] = [], + graphic_urls: Optional[str | List[str]] = [], + id_norm: Optional[str] = None, + id_old: Optional[str] = None, + index: Optional[List[str | etree._Element]] = [], + index_geo_features: Optional[List[str | etree._Element]] = [], + index_organizations: Optional[List[str | etree._Element]] = [], + index_persons: Optional[List[str | etree._Element]] = [], + index_places: Optional[List[str | etree._Element]] = [], + issued_place: Optional[str | etree._Element] = None, + issuer: Optional[str | etree._Element] = None, + language: Optional[str] = None, + literature: Optional[str | List[str]] = [], + literature_abstracts: Optional[str | List[str]] = [], + literature_depictions: Optional[str | List[str]] = [], + literature_editions: Optional[str | List[str]] = [], + literature_secondary: Optional[str | List[str]] = [], + material: Optional[str] = None, + notarial_authentication: Optional[str | etree._Element] = None, + recipient: Optional[str | etree._Element] = None, + seals: Optional[etree._Element | str | Seal | List[str] | List[Seal]] = None, + tradition: Optional[str] = None, + transcription: Optional[str | etree._Element] = None, + transcription_sources: Optional[str] | List[str] = [], + witnesses: Optional[List[str | etree._Element]] = [], ) -> None: """ Creates a new charter object. @@ -281,7 +281,7 @@ def abstract(self): return self._abstract @abstract.setter - def abstract(self, value: str | etree._Element = None): + def abstract(self, value: Optional[str | etree._Element] = None): if self.issuer is not None and isinstance(self.issuer, etree._Element): raise ValueError( "XML element content for both issuer and abstract is not allowed, please join the issuer in the XML abstract yourself" @@ -293,47 +293,59 @@ def abstract_sources(self): return self._abstract_sources @abstract_sources.setter - def abstract_sources(self, value: str | List[str] = []): - self._abstract_sources = value if isinstance(value, List) else [value] + def abstract_sources(self, value: Optional[str | List[str]] = []): + self._abstract_sources = ( + [] + if value is None or (isinstance(value, str) and not len(value)) + else (value if isinstance(value, List) else [value]) + ) @property def archive(self): return self._archive @archive.setter - def archive(self, value: str = None): - self._archive = value + def archive(self, value: Optional[str] = None): + self._archive = value if value is not None and len(value) else None @property def chancellary_remarks(self): return self._chancellary_remarks @chancellary_remarks.setter - def chancellary_remarks(self, value: str | List[str] = []): - self._chancellary_remarks = [value] if isinstance(value, str) else value + def chancellary_remarks(self, value: Optional[str | List[str]] = []): + self._chancellary_remarks = ( + [] + if value is None or (isinstance(value, str) and not len(value)) + else ([value] if isinstance(value, str) else value) + ) @property def comments(self): return self._comments @comments.setter - def comments(self, value: str | List[str] = []): - self._comments = [value] if isinstance(value, str) else value + def comments(self, value: Optional[str | List[str]] = []): + self._comments = ( + [] + if value is None or (isinstance(value, str) and not len(value)) + else ([value] if isinstance(value, str) else value) + ) @property def condition(self): return self._condition @condition.setter - def condition(self, value: str = None): - self._condition = value + def condition(self, value: Optional[str] = None): + self._condition = value if isinstance(value, str) and len(value) else None @property def date(self): return self._date @date.setter - def date(self, value: str | etree._Element = None): + def date(self, value: Optional[str | etree._Element] = None): self._date = validate_element(value, "date", "dateRange") @property @@ -341,7 +353,7 @@ def date_quote(self): return self._date_quote @date_quote.setter - def date_quote(self, value: str | etree._Element = None): + def date_quote(self, value: Optional[str | etree._Element] = None): self._date_quote = validate_element(value, "quoteOriginaldatierung") @property @@ -349,14 +361,16 @@ def date_value(self): return self._date_value @date_value.setter - def date_value(self, value: DateValue = None): + def date_value(self, value: Optional[DateValue] = None): # Don't allow to directly set date values if an XML date element is present if isinstance(self.date, etree._Element): raise ValueError( "Not allowed to set date value directly if the date is already an XML element." ) # Unknown MOM date (99999999) - elif (isinstance(value, str) and value == NO_DATE_VALUE) or ( + elif ( + isinstance(value, str) and (value == NO_DATE_VALUE or not len(value)) + ) or ( isinstance(value, Tuple) and len(value) == 2 and value[0] == NO_DATE_VALUE @@ -408,16 +422,18 @@ def dimensions(self): return self._dimensions @dimensions.setter - def dimensions(self, value: str = None): - self._dimensions = value + def dimensions(self, value: Optional[str] = None): + self._dimensions = value if isinstance(value, str) and len(value) else None @property def external_link(self): return self._external_link @external_link.setter - def external_link(self, value: str = None): - if value and not re.match(SIMPLE_URL_REGEX, value): + def external_link(self, value: Optional[str] = None): + if not isinstance(value, str) or len(value) == 0: + return None + if not re.match(SIMPLE_URL_REGEX, value): raise ValueError( "'{}' does not look like a valid external URL. If you think it is valid, please contact the to-CEI library maintainers and tell them.".format( value @@ -430,32 +446,40 @@ def footnotes(self): return self._footnotes @footnotes.setter - def footnotes(self, value): - self._footnotes = value + def footnotes(self, value: Optional[str | List[str]] = []): + self._footnotes = ( + [] + if value is None or (isinstance(value, str) and not len(value)) + else ([value] if isinstance(value, str) else value) + ) @property def graphic_urls(self): return self._graphic_urls @graphic_urls.setter - def graphic_urls(self, value: str | List[str] = []): - self._graphic_urls = value if isinstance(value, List) else [value] + def graphic_urls(self, value: Optional[str | List[str]] = []): + self._graphic_urls = ( + [] + if value is None or (isinstance(value, str) and not len(value)) + else ([value] if isinstance(value, str) else value) + ) @property def id_norm(self): return quote(self._id_norm if self._id_norm else self.id_text) @id_norm.setter - def id_norm(self, value: str = None): - self._id_norm = value + def id_norm(self, value: Optional[str] = None): + self._id_norm = value if isinstance(value, str) and len(value) else None @property def id_old(self): return self._id_old @id_old.setter - def id_old(self, value: str = None): - self._id_old = value + def id_old(self, value: Optional[str] = None): + self._id_old = value if isinstance(value, str) and len(value) else None @property def id_text(self): @@ -470,47 +494,47 @@ def index(self): return self._index @index.setter - def index(self, value: List[str | etree._Element] = []): - self._index = [validate_element(item, "index") for item in value] # type: ignore + def index(self, value: Optional[List[str | etree._Element]] = []): + self._index = [validate_element(item, "index") for item in value] if isinstance(value, List) else [] # type: ignore @property def index_geo_features(self): return self._index_geo_features @index_geo_features.setter - def index_geo_features(self, value: List[str | etree._Element] = []): - self._index_geo_features = [validate_element(item, "geogName") for item in value] # type: ignore + def index_geo_features(self, value: Optional[List[str | etree._Element]] = []): + self._index_geo_features = [validate_element(item, "geogName") for item in value] if isinstance(value, List) else [] # type: ignore @property def index_organizations(self): return self._index_organizations @index_organizations.setter - def index_organizations(self, value: List[str | etree._Element] = []): - self._index_organizations = [validate_element(item, "orgName") for item in value] # type: ignore + def index_organizations(self, value: Optional[List[str | etree._Element]] = []): + self._index_organizations = [validate_element(item, "orgName") for item in value] if isinstance(value, List) else [] # type: ignore @property def index_persons(self): return self._index_persons @index_persons.setter - def index_persons(self, value: List[str | etree._Element] = []): - self._index_persons = [validate_element(item, "persName") for item in value] # type: ignore + def index_persons(self, value: Optional[List[str | etree._Element]] = []): + self._index_persons = [validate_element(item, "persName") for item in value] if isinstance(value, List) else [] # type: ignore @property def index_places(self): return self._index_places @index_places.setter - def index_places(self, value: List[str | etree._Element] = []): - self._index_places = [validate_element(item, "placeName") for item in value] # type: ignore + def index_places(self, value: Optional[List[str | etree._Element]] = []): + self._index_places = [validate_element(item, "placeName") for item in value] if isinstance(value, List) else [] # type: ignore @property def issued_place(self): return self._issued_place @issued_place.setter - def issued_place(self, value: str | etree._Element = None): + def issued_place(self, value: Optional[str | etree._Element] = None): self._issued_place = validate_element(value, "placeName") @property @@ -518,7 +542,7 @@ def issuer(self): return self._issuer @issuer.setter - def issuer(self, value: str | etree._Element = None): + def issuer(self, value: Optional[str | etree._Element] = None): if value is not None and isinstance(self.abstract, etree._Element): raise ValueError( "XML element content for both issuer and abstract is not allowed, please join the issuer in the XML abstract yourself" @@ -530,63 +554,83 @@ def language(self): return self._language @language.setter - def language(self, value: str = None): - self._language = value + def language(self, value: Optional[str] = None): + self._language = value if isinstance(value, str) and len(value) else None @property def literature(self): return self._literature @literature.setter - def literature(self, value: str | List[str] = []): - self._literature = value if isinstance(value, List) else [value] + def literature(self, value: Optional[str | List[str]] = []): + self._literature = ( + [] + if value is None or (isinstance(value, str) and not len(value)) + else ([value] if isinstance(value, str) else value) + ) @property def literature_abstracts(self): return self._literature_abstracts @literature_abstracts.setter - def literature_abstracts(self, value: str | List[str] = []): - self._literature_abstracts = value if isinstance(value, List) else [value] + def literature_abstracts(self, value: Optional[str | List[str]] = []): + self._literature_abstracts = ( + [] + if value is None or (isinstance(value, str) and not len(value)) + else ([value] if isinstance(value, str) else value) + ) @property def literature_depictions(self): return self._literature_depictions @literature_depictions.setter - def literature_depictions(self, value: str | List[str] = []): - self._literature_depictions = value if isinstance(value, List) else [value] + def literature_depictions(self, value: Optional[str | List[str]] = []): + self._literature_depictions = ( + [] + if value is None or (isinstance(value, str) and not len(value)) + else ([value] if isinstance(value, str) else value) + ) @property def literature_editions(self): return self._literature_editions @literature_editions.setter - def literature_editions(self, value: str | List[str] = []): - self._literature_editions = value if isinstance(value, List) else [value] + def literature_editions(self, value: Optional[str | List[str]] = []): + self._literature_editions = ( + [] + if value is None or (isinstance(value, str) and not len(value)) + else ([value] if isinstance(value, str) else value) + ) @property def literature_secondary(self): return self._literature_secondary @literature_secondary.setter - def literature_secondary(self, value: str | List[str] = []): - self._literature_secondary = value if isinstance(value, List) else [value] + def literature_secondary(self, value: Optional[str | List[str]] = []): + self._literature_secondary = ( + [] + if value is None or (isinstance(value, str) and not len(value)) + else ([value] if isinstance(value, str) else value) + ) @property def material(self): return self._material @material.setter - def material(self, value: str = None): - self._material = value + def material(self, value: Optional[str] = None): + self._material = value if isinstance(value, str) and len(value) else None @property def notarial_authentication(self): return self._notarial_authentication @notarial_authentication.setter - def notarial_authentication(self, value: str | etree._Element = None): + def notarial_authentication(self, value: Optional[str | etree._Element] = None): self._notarial_authentication = validate_element(value, "notariusDesc") @property @@ -594,7 +638,7 @@ def recipient(self): return self._recipient @recipient.setter - def recipient(self, value: str | etree._Element = None): + def recipient(self, value: Optional[str | etree._Element] = None): if value is not None and isinstance(self.abstract, etree._Element): raise ValueError( "XML element content for both recipient and abstract is not allowed, please join the recipient in the XML abstract yourself" @@ -608,8 +652,10 @@ def seals(self): @seals.setter def seals( self, - value: etree._Element | str | Seal | List[str] | List[Seal] = None, + value: Optional[etree._Element | str | Seal | List[str] | List[Seal]] = None, ): + if value is None or isinstance(value, str) and len(value) == 0: + return None validated = ( validate_element(value, "sealDesc") if isinstance(value, etree._Element) @@ -625,15 +671,15 @@ def tradition(self): return self._tradition @tradition.setter - def tradition(self, value: str = None): - self._tradition = value + def tradition(self, value: Optional[str] = None): + self._tradition = value if isinstance(value, str) and len(value) else None @property def transcription(self): return self._transcription @transcription.setter - def transcription(self, value: str | etree._Element = None): + def transcription(self, value: Optional[str | etree._Element] = None): self._transcription = validate_element(value, "tenor") @property @@ -641,16 +687,20 @@ def transcription_sources(self): return self._transcription_sources @transcription_sources.setter - def transcription_sources(self, value: str | List[str] = []): - self._transcription_sources = value if isinstance(value, List) else [value] + def transcription_sources(self, value: Optional[str | List[str]] = []): + self._transcription_sources = ( + [] + if value is None or (isinstance(value, str) and not len(value)) + else ([value] if isinstance(value, str) else value) + ) @property def witnesses(self): return self._witnesses @witnesses.setter - def witnesses(self, value: List[str | etree._Element] = []): - self._witnesses = [validate_element(item, "persName") for item in value] # type: ignore + def witnesses(self, value: Optional[List[str | etree._Element]] = []): + self._witnesses = [validate_element(item, "persName") for item in value] if isinstance(value, List) else [] # type: ignore # --------------------------------------------------------------------# # Private CEI creators # @@ -989,10 +1039,10 @@ def _create_cei_witness_orig(self) -> Optional[etree._Element]: def to_xml(self) -> etree._Element: return self._create_cei_text() - def to_file(self, folder: str = None): + def to_file(self, folder: Optional[str] = None): """Writes the xml representation of the charter to a file. The filename is generated from the normalized charter id. Args: - folder (str): The folder to write the file to. If this is ommitted, the file is written to the place where the script is + folder (str): The folder to write the file to. If this is ommitted, the file is written to the place where the script is """ return super(Charter, self).to_file(self.id_norm + ".cei", folder=folder) diff --git a/to_cei/charter_group.py b/to_cei/charter_group.py index 264f644..b5fcf8c 100644 --- a/to_cei/charter_group.py +++ b/to_cei/charter_group.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, Optional from lxml import etree @@ -46,7 +46,7 @@ def to_xml(self) -> etree._Element: ) return xml - def to_file(self, folder: str = None): + def to_file(self, folder: Optional[str] = None): return super(CharterGroup, self).to_file( self.name.lower().replace(" ", "_") + ".cei.group", folder=folder ) diff --git a/to_cei/helpers.py b/to_cei/helpers.py index c0cb892..b357b9b 100644 --- a/to_cei/helpers.py +++ b/to_cei/helpers.py @@ -31,6 +31,8 @@ def ns(element: etree._Element) -> str: def validate_element( value: Optional[str | etree._Element], *tags: str ) -> Optional[str | etree._Element]: + if isinstance(value, str) and not len(value): + return None if isinstance(value, etree._Element): if ns(value) != CEI_NS: raise ValueError( diff --git a/to_cei/seal.py b/to_cei/seal.py index 9d9e30c..c4ac047 100644 --- a/to_cei/seal.py +++ b/to_cei/seal.py @@ -16,11 +16,11 @@ class Seal(XmlAssembler): def __init__( self, - condition: str = None, - dimensions: str = None, - legend: str | List[Tuple[str, str]] = [], - material: str = None, - sigillant: str | etree._Element = None, + condition: Optional[str] = None, + dimensions: Optional[str] = None, + legend: Optional[str | List[Tuple[str, str]]] = [], + material: Optional[str] = None, + sigillant: Optional[str | etree._Element] = None, ) -> None: """ Creates a seal instance. @@ -52,39 +52,43 @@ def condition(self): return self._condition @condition.setter - def condition(self, value: str = None): - self._condition = value + def condition(self, value: Optional[str] = None): + self._condition = value if isinstance(value, str) and len(value) else None @property def dimensions(self): return self._dimensions @dimensions.setter - def dimensions(self, value: str = None): - self._dimensions = value + def dimensions(self, value: Optional[str] = None): + self._dimensions = value if isinstance(value, str) and len(value) else None @property def legend(self): return self._legend @legend.setter - def legend(self, value: str | List[Tuple[str, str]] = []): - self._legend = value + def legend(self, value: Optional[str | List[Tuple[str, str]]] = []): + self._legend = ( + [] + if value is None or (isinstance(value, str) and len(value) == 0) + else value + ) @property def material(self): return self._material @material.setter - def material(self, value: str = None): - self._material = value + def material(self, value: Optional[str] = None): + self._material = value if isinstance(value, str) and len(value) else None @property def sigillant(self): return self._sigillant @sigillant.setter - def sigillant(self, value: str | etree._Element = None): + def sigillant(self, value: Optional[str | etree._Element] = None): self._sigillant = validate_element(value, "persName", "orgName") # --------------------------------------------------------------------# diff --git a/to_cei/xml_assembler.py b/to_cei/xml_assembler.py index c1c9b05..d489d40 100644 --- a/to_cei/xml_assembler.py +++ b/to_cei/xml_assembler.py @@ -24,7 +24,7 @@ def to_string(self) -> str: def to_file( self, name: str, - folder: str | Path = None, + folder: Optional[str | Path] = None, inclusive_ns_prefixes: List[str] = [], ): xml = self.to_xml()