Repository: scieloorg/packtools

Issue:
Acusar erro quando atributo de @country estiver em minúsculo
Style não acusa erro quando atributo de @country="br".

Discussion:

Patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index f991788..0af685a 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -13,6 +13,9 @@ History
   ``packtools.domain.SchematronValidator``).
 * The stylechecker utility exits 0 on success, and >0 if an error occurs
   [https://github.com/scieloorg/packtools/issues/118].
+* The values in attribute ``@country`` are checked against ISO3166 alpha-2 
+  list.
+
 
 
 1.5 (2017-04-03)
diff --git a/packtools/catalogs/__init__.py b/packtools/catalogs/__init__.py
index 24d655e..94ecc89 100644
--- a/packtools/catalogs/__init__.py
+++ b/packtools/catalogs/__init__.py
@@ -36,3 +36,6 @@ XML_CATALOG = os.path.join(_CWD, 'scielo-publishing-schema.xml')
 XSLTS = {
     'root-html-1.2.xslt': os.path.join(_CWD, 'htmlgenerator/root-html-1.2.xslt'),
 }
+
+ISO3166_CODES = os.path.join(_CWD, 'iso3166-codes.json')
+
diff --git a/packtools/catalogs/iso3166-codes.json b/packtools/catalogs/iso3166-codes.json
new file mode 100644
index 0000000..b9aa006
--- /dev/null
+++ b/packtools/catalogs/iso3166-codes.json
@@ -0,0 +1,1 @@
+["FM", "CD", "YU", "BR", "NH", "SH", "MD", "EC", "PK", "LU", "TD", "IT", "WS", "CI", "GI", "AS", "NI", "AW", "AI", "BM", "BF", "BU", "WK", "UA", "ZA", "YD", "NA", "GF", "CX", "BO", "MX", "AU", "MR", "DK", "SA", "CG", "BN", "IQ", "VG", "SS", "CY", "AE", "OM", "MF", "TP", "RH", "AM", "TN", "AT", "NF", "BE", "GG", "IM", "MZ", "SX", "PM", "ER", "GL", "PY", "PL", "RS", "SL", "KY", "JE", "MV", "FK", "SE", "GB", "VE", "NQ", "LY", "PG", "UZ", "NZ", "MO", "LA", "GN", "ML", "MH", "TF", "MC", "KI", "TK", "GR", "HV", "AX", "PT", "JO", "HU", "BI", "MQ", "YT", "PH", "LC", "SM", "SN", "CU", "AZ", "CF", "LI", "MU", "DO", "MM", "ZM", "DM", "UY", "LT", "SC", "NO", "GU", "SB", "TZ", "LV", "NU", "BL", "LS", "FQ", "JP", "MT", "PE", "IR", "QA", "KE", "VU", "HT", "KR", "ME", "RO", "EH", "ZR", "GA", "PN", "CC", "PS", "BD", "TC", "AG", "AD", "GQ", "RW", "HR", "ZW", "AQ", "BB", "DJ", "VA", "BH", "HM", "GM", "SR", "BS", "VN", "BW", "CW", "NR", "AL", "PU", "WF", "SD", "GE", "AN", "EE", "MK", "CK", "PZ", "ST", "KN", "SG", "SZ", "UM", "KH", "GY", "VD", "MI", "NP", "KW", "ES", "NG", "TJ", "KM", "PC", "SI", "SK", "TG", "FI", "PW", "IE", "TL", "TO", "JM", "TH", "IN", "TW", "TT", "CR", "UG", "VI", "KG", "BG", "IL", "DD", "ID", "KZ", "NC", "MW", "TR", "GD", "IS", "LB", "PA", "US", "JT", "GP", "CL", "KP", "MA", "LK", "BQ", "BV", "GH", "DE", "NL", "BJ", "FJ", "CH", "SO", "EG", "CM", "FO", "DY", "YE", "FR", "BT", "MS", "IO", "BY", "GW", "AF", "CS", "HN", "RU", "VC", "HK", "BZ", "PR", "SJ", "MY", "SY", "SV", "BA", "GT", "TV", "RE", "DZ", "MG", "AO", "CO", "PF", "LR", "CA", "AR", "CZ", "NE", "ET", "TM", "CT", "MP", "NT", "GS", "CV", "CN", "MN"]
\ No newline at end of file
diff --git a/packtools/checks.py b/packtools/checks.py
index 19ce822..2d2cf4d 100644
--- a/packtools/checks.py
+++ b/packtools/checks.py
@@ -2,15 +2,21 @@
 from __future__ import unicode_literals
 import logging
 import itertools
+import json
 
 import plumber
 
 from .style_errors import StyleError
+from . import catalogs
 
 
 LOGGER = logging.getLogger(__name__)
 
 
+with open(catalogs.ISO3166_CODES) as f:
+    ISO3166_CODES_SET = set(json.load(f))
+
+
 # --------------------------------
 # Basic functionality
 # --------------------------------
@@ -36,7 +42,7 @@ def teardown(message):
 def StyleCheckingPipeline():
     """Factory for style checking pipelines.
     """
-    return plumber.Pipeline(setup, funding_group, doctype, teardown)
+    return plumber.Pipeline(setup, funding_group, doctype, country_code, teardown)
 
 
 # --------------------------------
@@ -135,3 +141,21 @@ def doctype(message):
 
     return message
 
+
+@plumber.filter
+def country_code(message):
+    """Check country codes against iso3166 alpha-2 list.
+    """
+    et, err_list = message
+
+    elements = et.findall('//*[@country]')
+    for elem in elements:
+        value = elem.attrib['country']
+        if value not in ISO3166_CODES_SET:
+            err = StyleError()
+            err.line = elem.sourceline
+            err.message = "Element '%s', attribute country: Invalid country code \"%s\"." % (elem.tag, value)
+            err_list.append(err)
+
+    return message
+


Test patch:
diff --git a/tests/test_checks.py b/tests/test_checks.py
index def4e34..5c59f5e 100644
--- a/tests/test_checks.py
+++ b/tests/test_checks.py
@@ -419,3 +419,89 @@ class DoctypePipeTests(unittest.TestCase):
 
         self.assertEqual(len(err_list), 0)
 
+
+class CountryCodesTests(unittest.TestCase):
+
+    def test_valid_code(self):
+        sample = io.BytesIO(b"""
+        <article>
+          <front>
+            <article-meta>
+              <aff id="aff1">
+                <label>I</label>
+                <institution content-type="orgdiv2">Departamento de Fonoaudiologia</institution>
+                <institution content-type="orgdiv1">Faculdade de Medicina</institution>
+                <institution content-type="orgname">Universidade Federal do Rio de Janeiro</institution>
+                <addr-line>
+                  <named-content content-type="city">Rio de Janeiro</named-content>
+                  <named-content content-type="state">RJ</named-content>
+                </addr-line>
+                <country country="BR">Brasil</country>
+                <institution content-type="original">Departamento de Fonoaudiologia. Faculdade de Medicina. Universidade Federal do Rio de Janeiro. Rio de Janeiro, RJ, Brasil</institution>
+              </aff>
+            </article-meta>
+          </front>
+        </article>
+        """)
+
+        et = etree.parse(sample)
+        _, err_list = checks.country_code((et, []))
+
+        self.assertEqual(len(err_list), 0)
+
+    def test_valid_code_in_lowercase(self):
+        sample = io.BytesIO(b"""
+        <article>
+          <front>
+            <article-meta>
+              <aff id="aff1">
+                <label>I</label>
+                <institution content-type="orgdiv2">Departamento de Fonoaudiologia</institution>
+                <institution content-type="orgdiv1">Faculdade de Medicina</institution>
+                <institution content-type="orgname">Universidade Federal do Rio de Janeiro</institution>
+                <addr-line>
+                  <named-content content-type="city">Rio de Janeiro</named-content>
+                  <named-content content-type="state">RJ</named-content>
+                </addr-line>
+                <country country="br">Brasil</country>
+                <institution content-type="original">Departamento de Fonoaudiologia. Faculdade de Medicina. Universidade Federal do Rio de Janeiro. Rio de Janeiro, RJ, Brasil</institution>
+              </aff>
+            </article-meta>
+          </front>
+        </article>
+        """)
+
+        et = etree.parse(sample)
+        _, err_list = checks.country_code((et, []))
+
+        self.assertEqual(len(err_list), 1)
+        self.assertTrue("country" in err_list[0].message)
+
+    def test_invalid_code(self):
+        sample = io.BytesIO(b"""
+        <article>
+          <front>
+            <article-meta>
+              <aff id="aff1">
+                <label>I</label>
+                <institution content-type="orgdiv2">Departamento de Fonoaudiologia</institution>
+                <institution content-type="orgdiv1">Faculdade de Medicina</institution>
+                <institution content-type="orgname">Universidade Federal do Rio de Janeiro</institution>
+                <addr-line>
+                  <named-content content-type="city">Rio de Janeiro</named-content>
+                  <named-content content-type="state">RJ</named-content>
+                </addr-line>
+                <country country="INVALID">Brasil</country>
+                <institution content-type="original">Departamento de Fonoaudiologia. Faculdade de Medicina. Universidade Federal do Rio de Janeiro. Rio de Janeiro, RJ, Brasil</institution>
+              </aff>
+            </article-meta>
+          </front>
+        </article>
+        """)
+
+        et = etree.parse(sample)
+        _, err_list = checks.country_code((et, []))
+
+        self.assertEqual(len(err_list), 1)
+        self.assertTrue("country" in err_list[0].message)
+