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
24 changes: 18 additions & 6 deletions packtools/sps/validation/article_abstract.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from packtools.sps.models.v2.abstract import XMLAbstracts
from packtools.sps.validation.utils import format_response, build_response
from packtools.sps.validation.utils import build_response
import gettext

# Configuração de internacionalização
Expand Down Expand Up @@ -517,32 +517,42 @@ def validate_exists(self):
error_level = self.params["default_error_level"]
is_valid = True
advice = None
advice_text = None
advice_params = {}

if self.article_type in self.params["article_type_requires"]:
expected = f"Abstract is required"
is_valid = bool(data)
error_level = self.params["article_type_requires_abstract_error_level"]
advice = f"Mark abstract which is required for {self.article_type}"
advice_text = "Mark abstract which is required for {article_type}"
advice_params = {"article_type": self.article_type}
elif self.article_type in self.params["article_type_unexpects"]:
expected = f"Abstract is unexpected"
is_valid = not bool(data)
error_level = self.params["article_type_unexpects_abstract_error_level"]
advice = f"Abstract is not expected for {self.article_type}"
advice_text = "Abstract is not expected for {article_type}"
advice_params = {"article_type": self.article_type}
elif self.article_type in self.params["article_type_neutral"]:
is_valid = True
expected = f"Abstract is optional"
advice = None
advice_text = None
advice_params = {}
else:
raise ValueError(
f"Unable to identify if abstract is required or unexpected or neutral for article-type '{self.article_type}'"
)

return format_response(
return build_response(
title="abstract",
parent="article",
parent_id=None,
parent_article_type=self.article_type,
parent_lang=self.lang,
parent={
"parent": "article",
"parent_id": None,
"parent_article_type": self.article_type,
"parent_lang": self.lang,
},
item="abstract",
sub_item=None,
validation_type="exist",
Expand All @@ -552,6 +562,8 @@ def validate_exists(self):
advice=advice,
data=data,
error_level=error_level,
advice_text=advice_text,
advice_params=advice_params,
)

def validate(self):
Expand Down
80 changes: 59 additions & 21 deletions packtools/sps/validation/article_and_subarticles.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
ValidationArticleAndSubArticlesSubjectsException,
)
from packtools.sps.validation.similarity_utils import most_similar, similarity
from packtools.sps.validation.utils import build_response, format_response
from packtools.sps.validation.utils import build_response


class ArticleLangValidation:
Expand Down Expand Up @@ -93,17 +93,23 @@ def validate_language(self):
if article_lang:
xml = f'<{parent}{parent_id} xml:lang="{article_lang}">'
advice = f'Replace {article_lang} in {xml} with one of {language_codes_list}'
advice_text = 'Replace {lang} in {xml} with one of {lang_list}'
advice_params = {"lang": article_lang, "xml": xml, "lang_list": str(language_codes_list)}
else:
xml = f'<{parent}{parent_id}>'
xml2 = f'<{parent}{parent_id} xml:lang="VALUE">'

advice = f'Add xml:lang="VALUE" in {xml}: {xml2} and replace VALUE with one of {language_codes_list}'
yield format_response(
advice_text = 'Add xml:lang="VALUE" in {xml}: {xml2} and replace VALUE with one of {lang_list}'
advice_params = {"xml": xml, "xml2": xml2, "lang_list": str(language_codes_list)}
yield build_response(
title=f"{name} language",
parent=parent,
parent_id=article_id,
parent_article_type=article_type,
parent_lang=article_lang,
parent={
"parent": parent,
"parent_id": article_id,
"parent_article_type": article_type,
"parent_lang": article_lang,
},
item=parent,
sub_item="@xml:lang",
validation_type="value in list",
Expand All @@ -113,6 +119,8 @@ def validate_language(self):
advice=advice,
data=article,
error_level=self.params["language_error_level"],
advice_text=advice_text,
advice_params=advice_params,
)


Expand Down Expand Up @@ -163,12 +171,16 @@ def validate_article_type(self):
name = article_id or parent
xml = f'<{parent} article-type=""/>'
advice = None if valid else f'Complete {name} article-type {xml} with valid value {article_type_list}'
yield format_response(
advice_text = None if valid else 'Complete {name} article-type {xml} with valid value {type_list}'
advice_params = {} if valid else {"name": name, "xml": xml, "type_list": str(article_type_list)}
yield build_response(
title=f"{name} article-type",
parent=parent,
parent_id=article_id,
parent_article_type=article_type,
parent_lang=article_type,
parent={
"parent": parent,
"parent_id": article_id,
"parent_article_type": article_type,
"parent_lang": article_type,
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Em parent, o campo parent_lang está recebendo article_type, que não é um código de idioma. Isso tende a corromper o contexto de idioma do response (e.g., seleção de mensagem traduzida, filtros por lang). Ajuste para passar o idioma (provavelmente article_lang/main_lang ou equivalente já disponível no escopo) em vez de article_type.

Suggested change
"parent_lang": article_type,
"parent_lang": article_lang,

Copilot uses AI. Check for mistakes.
},
item=parent,
sub_item="article-type",
validation_type="value in list",
Expand All @@ -178,6 +190,8 @@ def validate_article_type(self):
advice=advice,
data=article,
error_level=self.params["article_type_error_level"],
advice_text=advice_text,
advice_params=advice_params,
)

def validate_article_type_vs_subject_similarity(self):
Expand Down Expand Up @@ -230,16 +244,28 @@ def validate_article_type_vs_subject_similarity(self):
title = f"article type and table of contents section"
choices = " | ".join(most_similar_article_type)
advice = None
advice_text = None
advice_params = {}
if not valid:
advice = (
f"Check {xml_article_type} and {xml_subject}. Other values for article-type seems to be more suitable: {choices}. "
)
yield format_response(
advice_text = (
"Check {xml_article_type} and {xml_subject}. Other values for article-type seems to be more suitable: {choices}. "
)
Comment on lines +253 to +255
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ajuste gramatical: em inglês, o sujeito é plural ('Other values'), então o correto é 'seem' em vez de 'seems'.

Copilot uses AI. Check for mistakes.
advice_params = {
"xml_article_type": xml_article_type,
"xml_subject": xml_subject,
"choices": choices
}
yield build_response(
title=title,
parent="article",
parent_article_type=self.articles.main_article_type,
parent_lang=self.articles.main_lang,
parent_id=None,
parent={
"parent": "article",
"parent_id": None,
"parent_article_type": self.articles.main_article_type,
"parent_lang": self.articles.main_lang,
},
item="article",
sub_item="@article-type",
validation_type="similarity",
Expand All @@ -249,6 +275,8 @@ def validate_article_type_vs_subject_similarity(self):
advice=advice,
data=data,
error_level=self.params["article_type_and_subject_expected_similarity_error_level"],
advice_text=advice_text,
advice_params=advice_params,
)


Expand Down Expand Up @@ -339,12 +367,18 @@ def validate(self):
expected_jats_versions = versions.get(sps_version) or []

advice = None
advice_text = None
advice_params = {}
if not versions:
advice = f'Complete SPS version <article specific-use=""/> with valid value: {list(versions.keys())}',
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A vírgula no final da linha 373 faz com que advice vire uma tupla (tuple) ao invés de str, o que deve quebrar o consumo do campo (ex.: serialização JSON, concatenação, renderização). Remova a vírgula para manter advice como string.

Suggested change
advice = f'Complete SPS version <article specific-use=""/> with valid value: {list(versions.keys())}',
advice = f'Complete SPS version <article specific-use=""/> with valid value: {list(versions.keys())}'

Copilot uses AI. Check for mistakes.
advice_text = 'Complete SPS version <article specific-use=""/> with valid value: {versions}'
advice_params = {"versions": str(list(versions.keys()))}

elif jats_version not in expected_jats_versions:
xml = f'<article specific-use="" dtd-version=""/>'
advice = f'Complete SPS (specific-use="") and JATS (dtd-version="") versions in {xml} with compatible values: {versions}'
advice_text = 'Complete SPS (specific-use="") and JATS (dtd-version="") versions in {xml} with compatible values: {versions}'
advice_params = {"xml": xml, "versions": str(versions)}

expected = expected_jats_versions or versions
got = {
Expand All @@ -356,12 +390,14 @@ def validate(self):
"dtd-version": jats_version,
"expected values": expected,
}
yield format_response(
yield build_response(
title='SPS and JATS versions',
parent="article",
parent_id=None,
parent_article_type=self.article_and_sub_articles.main_article_type,
parent_lang=self.article_and_sub_articles.main_lang,
parent={
"parent": "article",
"parent_id": None,
"parent_article_type": self.article_and_sub_articles.main_article_type,
"parent_lang": self.article_and_sub_articles.main_lang,
},
item="specific-use and dtd-version",
sub_item=None,
validation_type="match",
Expand All @@ -371,4 +407,6 @@ def validate(self):
advice=advice,
data=data,
error_level=self.params["jats_and_dtd_version_error_level"],
advice_text=advice_text,
advice_params=advice_params,
)
33 changes: 22 additions & 11 deletions packtools/sps/validation/article_license.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
ValidationLicenseException,
ValidationLicenseCodeException
)
from packtools.sps.validation.utils import format_response
from packtools.sps.validation.utils import build_response


class ArticleLicenseValidation:
Expand Down Expand Up @@ -123,12 +123,14 @@ def validate_license(self, expected_value, error_level="ERROR"):
is_valid = expected_license_p == obtained_license_p
expected_value_msg = expected_value.get(
lang) if is_valid else 'License data that matches the language {}'.format(lang)
yield format_response(
yield build_response(
title='Article license validation',
parent=data.get("parent"),
parent_id=data.get("parent_id"),
parent_article_type=data.get("parent_article_type"),
parent_lang=data.get("parent_lang"),
parent={
"parent": data.get("parent"),
"parent_id": data.get("parent_id"),
"parent_article_type": data.get("parent_article_type"),
"parent_lang": data.get("parent_lang"),
},
item="permissions",
sub_item="license",
validation_type="value",
Expand All @@ -141,6 +143,11 @@ def validate_license(self, expected_value, error_level="ERROR"):
f'<license-p>{expected_license_p["license_p"]}</license-p></license>',
data=obtained_license_p,
error_level=error_level,
advice_text=f'Mark license information with '
f'<license license-type="open-access" xlink:href={{link}} '
f'xml:lang={{lang}}>'
f'<license-p>{{license_p}}</license-p></license>',
Comment on lines +146 to +149
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

advice_text é um template e não precisa ser f-string. Do jeito atual, ele depende de escapes {{...}} para preservar placeholders, o que aumenta risco de erro e dificulta manutenção. Prefira usar string literal normal (sem f) contendo {link}, {lang}, {license_p}; mantém o propósito de template mais claro e evita interpolação acidental.

Suggested change
advice_text=f'Mark license information with '
f'<license license-type="open-access" xlink:href={{link}} '
f'xml:lang={{lang}}>'
f'<license-p>{{license_p}}</license-p></license>',
advice_text='Mark license information with '
'<license license-type="open-access" xlink:href={link} '
'xml:lang={lang}>'
'<license-p>{license_p}</license-p></license>',

Copilot uses AI. Check for mistakes.
advice_params=expected_license_p,
)

def validate_license_code(self, expected_code, error_level="ERROR"):
Expand Down Expand Up @@ -202,12 +209,14 @@ def validate_license_code(self, expected_code, error_level="ERROR"):
obtained_link = licenses.get('link')
obtained_code = obtained_link.split('/')[4] if obtained_link else None
is_valid = expected_code == obtained_code
yield format_response(
yield build_response(
title='Article license code validation',
parent=licenses.get("parent"),
parent_id=licenses.get("parent_id"),
parent_article_type=licenses.get("parent_article_type"),
parent_lang=licenses.get("parent_lang"),
parent={
"parent": licenses.get("parent"),
"parent_id": licenses.get("parent_id"),
"parent_article_type": licenses.get("parent_article_type"),
"parent_lang": licenses.get("parent_lang"),
},
item="permissions",
sub_item="license",
validation_type="value",
Expand All @@ -217,6 +226,8 @@ def validate_license_code(self, expected_code, error_level="ERROR"):
advice=f'add <permissions><license xlink:href="http://creativecommons.org/licenses/VALUE/4.0/"> and replace VALUE with {expected_code}',
data=licenses,
error_level=error_level,
advice_text='add <permissions><license xlink:href="http://creativecommons.org/licenses/VALUE/4.0/"> and replace VALUE with {code}',
advice_params={"code": expected_code},
)


Expand Down
50 changes: 37 additions & 13 deletions packtools/sps/validation/article_xref.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from packtools.sps.models.v2.article_xref import XMLCrossReference
from packtools.sps.validation.utils import format_response, build_response
from packtools.sps.validation.utils import build_response


class ArticleXrefValidation:
Expand Down Expand Up @@ -70,14 +70,16 @@ def validate_xref_rid_has_corresponding_element_id(self):
f'Found {xref.get("xml")}, but not found the corresponding {xref.get("elem_xml")}'
)

yield format_response(
yield build_response(
title=f'<xref> is linked to {element_name}',
parent="article",
parent_id=None,
parent_article_type=self.xml_tree.get("article-type"),
parent_lang=self.xml_tree.get(
"{http://www.w3.org/XML/1998/namespace}lang"
),
parent={
"parent": "article",
"parent_id": None,
"parent_article_type": self.xml_tree.get("article-type"),
"parent_lang": self.xml_tree.get(
"{http://www.w3.org/XML/1998/namespace}lang"
),
},
item="xref",
sub_item="@rid",
validation_type="match",
Expand All @@ -87,6 +89,8 @@ def validate_xref_rid_has_corresponding_element_id(self):
advice=advice,
data={"xref": xref, "element": element_data, "missing_xrefs": self.missing_xrefs, "missing_elems": self.missing_elems},
error_level=self.params["xref_rid_error_level"],
advice_text='Found {xml}, but not found the corresponding {elem_xml}',
advice_params={"xml": xref.get("xml"), "elem_xml": xref.get("elem_xml")},
)

def validate_element_id_has_corresponding_xref_rid(self):
Expand Down Expand Up @@ -119,17 +123,35 @@ def validate_element_id_has_corresponding_xref_rid(self):
f'Found {tag_and_attribs}, but no corresponding {xref_xml} was found. '
f'Mark {label}, mention to {tag_and_attribs}, with {xref_xml}'
)
advice_text = (
'Found {tag_and_attribs}, but no corresponding {xref_xml} was found. '
'Mark {label}, mention to {tag_and_attribs}, with {xref_xml}'
)
advice_params = {
"tag_and_attribs": tag_and_attribs,
"xref_xml": xref_xml,
"label": label
}
else:
advice = (
f'Found {tag_and_attribs}, but no corresponding {xref_xml} was found. '
)
advice_text = (
'Found {tag_and_attribs}, but no corresponding {xref_xml} was found. '
)
advice_params = {
"tag_and_attribs": tag_and_attribs,
"xref_xml": xref_xml
}

yield format_response(
yield build_response(
title=f'{tag_and_attribs} is linked to <xref>',
parent=elem_data.get("parent"),
parent_id=elem_data.get("parent_id"),
parent_article_type=elem_data.get("parent_article_type"),
parent_lang=elem_data.get("parent_lang"),
parent={
"parent": elem_data.get("parent"),
"parent_id": elem_data.get("parent_id"),
"parent_article_type": elem_data.get("parent_article_type"),
"parent_lang": elem_data.get("parent_lang"),
},
item=elem_data.get("tag"),
sub_item="@id",
validation_type="match",
Expand All @@ -139,6 +161,8 @@ def validate_element_id_has_corresponding_xref_rid(self):
advice=advice,
data={"element": elem_data, "xref": xrefs, "missing_xrefs": self.missing_xrefs, "missing_elems": self.missing_elems},
error_level=error_level,
advice_text=advice_text,
advice_params=advice_params,
)

def validate_attrib_name_and_value_has_corresponding_xref(self):
Expand Down
Loading
Loading