Coverage for portality / lib / coerce.py: 86%
71 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-04 09:41 +0100
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-04 09:41 +0100
1# ~~Coerce:Library~~
2from portality.lib import dates
3from datetime import date, datetime
4from portality.lib import seamless
5from portality.datasets import get_country_code, get_currency_code
6from portality.lib.dates import FMT_DATETIME_MS_STD, FMT_DATE_STD
9def to_datestamp(in_format=None):
10 def stampify(val):
11 return dates.parse(val, format=in_format)
13 return stampify
16def date_str(in_format=None, out_format=None):
17 def datify(val):
18 if val is None or val == "":
19 return None
20 if isinstance(val, date) or isinstance(val, datetime):
21 return dates.format(val, format=out_format)
22 else:
23 return dates.reformat(val, in_format=in_format, out_format=out_format)
25 return datify
28def to_isolang(output_format=None, fail_if_not_found=True):
29 """
30 :param output_format: format from input source to putput. Must be one of:
31 * alpha3
32 * alt3
33 * alpha2
34 * name
35 * fr
36 Can be a list in order of preference, too
37 :param fail_if_not_found: Whether to raise ValueError if there's no match or return the input unchanged
38 ~~-> Languages:Data~~
39 :return:
40 """
41 # delayed import, since we may not always want to load the whole dataset for a dataobj
42 from portality.lib import isolang as dataset
44 # sort out the output format list
45 if output_format is None:
46 output_format = ["alpha3"]
47 if not isinstance(output_format, list):
48 output_format = [output_format]
50 def isolang(val):
51 if val is None:
52 return None
53 l = dataset.find(val)
55 # If we didn't find the language, either raise an error or return the provided value
56 if l is None:
57 if fail_if_not_found is True:
58 raise ValueError("Unable to find iso code for language {x}".format(x=val))
59 else:
60 return val
62 # Retrieve the correct output format from a successful match
63 for f in output_format:
64 v = l.get(f)
65 if v is None or v == "":
66 continue
67 return v.upper()
69 return isolang
72def to_currency_code(fail_if_not_found=True):
73 """
74 ~~-> Currencies:Data~~
75 :param val:
76 :param fail_if_not_found:
77 :return:
78 """
80 def codify(val):
81 if val is None:
82 return None
83 nv = get_currency_code(val, fail_if_not_found=fail_if_not_found)
84 if nv is None:
85 raise ValueError("Unable to convert {x} to a valid currency code".format(x=val))
86 uc = seamless.to_utf8_unicode
87 return uc(nv)
89 return codify
92def to_country_code(val):
93 """
94 ~~-> Countries:Data~~
95 :param val:
96 :return:
97 """
98 if val is None:
99 return None
100 nv = get_country_code(val, fail_if_not_found=True)
101 if nv is None:
102 raise ValueError("Unable to convert {x} to a valid country code".format(x=val))
103 uc = seamless.to_utf8_unicode
104 return uc(nv)
107def to_issn(issn):
108 if len(issn) > 9 or issn == '':
109 raise ValueError("Unable to normalise {x} to valid ISSN".format(x=issn))
111 issn = issn.upper()
112 if len(issn) == 9:
113 return issn
115 if len(issn) == 8:
116 if "-" in issn:
117 return "0" + issn
118 else:
119 return issn[:4] + "-" + issn[4:]
121 if len(issn) < 8:
122 if "-" in issn:
123 return ("0" * (9 - len(issn))) + issn
124 else:
125 issn = ("0" * (8 - len(issn))) + issn
126 return issn[:4] + "-" + issn[4:]
129# ~~-> Seamless:Library~~
130COERCE_MAP = {
131 "unicode": seamless.to_utf8_unicode,
132 "unicode_upper": seamless.to_unicode_upper,
133 "unicode_lower": seamless.to_unicode_lower,
134 "integer": seamless.intify,
135 "float": seamless.floatify,
136 "url": seamless.to_url,
137 "bool": seamless.to_bool,
138 "datetime": seamless.to_datetime,
139 "utcdatetime": date_str(),
140 "utcdatetimemicros": date_str(out_format=FMT_DATETIME_MS_STD),
141 "bigenddate": date_str(out_format=FMT_DATE_STD),
142 "isolang": to_isolang(),
143 "isolang_2letter_strict": to_isolang(output_format="alpha2", fail_if_not_found=True),
144 "isolang_2letter_lax": to_isolang(output_format="alpha2", fail_if_not_found=False),
145 "country_code": to_country_code,
146 "issn": to_issn,
147 "currency_code_strict": to_currency_code(fail_if_not_found=True),
148 "currency_code_lax": to_currency_code(fail_if_not_found=False)
149}