Skip to content

Commit 0f9ef87

Browse files
Merge pull request #110 from gridsmartercities/currency
Currency
2 parents 393309a + a76fc1a commit 0f9ef87

File tree

9 files changed

+151
-12
lines changed

9 files changed

+151
-12
lines changed

.coveragerc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[run]
2+
3+
branch = True
4+
5+
omit =
6+
*__init__.py
7+
examples/*
8+
setup.py
9+
tests/*
10+
11+
[report]
12+
13+
show_missing = True
14+
15+
omit =
16+
*__init__.py
17+
examples/*
18+
setup.py
19+
tests/*
20+
21+
fail_under = 100

CONTRIBUTING.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@ Before submitting a PR, please ensure that:
1818

1919
- you run [__Coverage__](https://pypi.org/project/coverage/) and all unit tests are passing:
2020

21-
`coverage run --branch --source='.' -m unittest`
22-
23-
- you have 100% unit test coverage:
24-
25-
`coverage report -m --fail-under=100 --omit=*/__init__.py,tests/*,setup.py,examples/test_examples.py`
26-
21+
`coverage run --source='.' -m unittest`
22+
23+
`coverage report`
24+
2725
- you can run the test examples like this:
2826

2927
`python -m unittest examples.test_examples`

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ The current list of AWS Lambda Python Decorators includes:
4848

4949
### [Validators](https://github.com/gridsmartercities/aws-lambda-decorators/blob/master/aws_lambda_decorators/validators.py)
5050

51-
Currently, the package offers 5 validators:
51+
Currently, the package offers 12 validators:
5252

5353
* __Mandatory__: Checks if a parameter has a value.
5454
* __RegexValidator__: Checks a parameter against a regular expression.
@@ -61,6 +61,7 @@ Currently, the package offers 5 validators:
6161
* __EnumValidator__: Checks if an optional object value is in a list of valid values.
6262
* __NonEmpty__: Checks if an optional object value is not an empty value.
6363
* __DateValidator__: Checks if a given string is a valid date according to a passed in date format.
64+
* __CurrencyCodeValidator__: Checks if a given string is a valid currency code (ISO 4217).
6465

6566
### [Decoders](https://github.com/gridsmartercities/aws-lambda-decorators/blob/master/aws_lambda_decorators/decoders.py)
6667

aws_lambda_decorators/classes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def validate(self, value, group_errors):
120120
if hasattr(validator, "_error_message"):
121121
errors.append(validator.message(value))
122122
else: # calling the validator statically
123-
errors.append(validator.ERROR_MESSAGE)
123+
errors.append(validator.ERROR_MESSAGE.format(value=value))
124124
if not group_errors:
125125
return errors
126126

aws_lambda_decorators/validators.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@
33
import re
44
from schema import SchemaError
55

6+
CURRENCIES = {"LKR", "ETB", "RWF", "NZD", "SBD", "MKD", "NPR", "LAK", "KWD", "INR", "HUF", "AFN", "BTN", "ISK", "MVR",
7+
"WST", "MNT", "AZN", "SAR", "JMD", "BIF", "BMD", "CAD", "GEL", "MXN", "BHD", "HKD", "RSD", "PKR", "SLL",
8+
"NGN", "TOP", "SCR", "SVC", "CHW", "UYW", "IDR", "IQD", "THB", "GBP", "MYR", "SDG", "CNY", "GNF", "LRD",
9+
"KHR", "TJS", "BYN", "SHP", "AED", "BOB", "CUC", "PHP", "SSP", "USN", "MZN", "COP", "SEK", "EUR", "CDF",
10+
"CRC", "KMF", "JPY", "ZWL", "ALL", "GHS", "GIP", "QAR", "GYD", "HTG", "VUV", "CZK", "ANG", "AWG", "AMD",
11+
"DOP", "TRY", "ZMW", "MGA", "KZT", "XUA", "ARS", "XPF", "BRL", "MXV", "LSL", "CLP", "KES", "PYG", "TND",
12+
"MAD", "DZD", "MWK", "BSD", "BBD", "FKP", "KGS", "BWP", "CVE", "HRK", "DKK", "COU", "SYP", "LYD", "PLN",
13+
"TZS", "KPW", "UGX", "BOV", "UAH", "NAD", "AOA", "VES", "SOS", "CUP", "SGD", "PAB", "UZS", "STN", "SRD",
14+
"CHE", "XOF", "DJF", "PGK", "UYI", "XCD", "BZD", "EGP", "ERN", "RON", "TWD", "USD", "FJD", "VND", "SZL",
15+
"BND", "HNL", "KRW", "XAF", "MDL", "BDT", "MUR", "PEN", "OMR", "NIO", "TMT", "YER", "TTD", "GMD", "XDR",
16+
"CHF", "NOK", "GTQ", "JOD", "KYD", "UYU", "RUB", "ZAR", "AUD", "BGN", "MOP", "LBP", "MRU", "CLF", "XSU",
17+
"BAM", "MMK", "IRR", "ILS"}
18+
619

720
class Validator: # noqa: pylint - too-few-public-methods
821
"""Validation rule to check if the given mandatory value exists."""
@@ -337,3 +350,31 @@ def validate(self, value=None):
337350
return False
338351
else:
339352
return True
353+
354+
355+
class CurrencyValidator(Validator):
356+
"""Validation rule to check if a string is a valid currency according to ISO 4217 Currency Code."""
357+
ERROR_MESSAGE = "'{value}' is not a valid currency code."
358+
359+
def __init__(self, error_message=None):
360+
"""
361+
Checks if a string is a valid currency based on ISO 4217
362+
363+
Args:
364+
error_message (str): A custom error message to output if validation fails
365+
"""
366+
super().__init__(error_message)
367+
368+
@staticmethod
369+
def validate(value=None):
370+
"""
371+
Check if a string is a valid currency based on ISO 4217
372+
373+
Args:
374+
value (str): value to validate against a ISO 4217
375+
"""
376+
377+
if value is None:
378+
return True
379+
380+
return value.upper() in CURRENCIES

examples/examples.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
handle_exceptions, response_body_as_json, Parameter, SSMParameter,
88
ValidatedParameter, ExceptionHandler, Mandatory, RegexValidator,
99
handle_all_exceptions, cors, SchemaValidator, Maximum, Minimum, Type, EnumValidator,
10-
NonEmpty, DateValidator)
10+
NonEmpty, DateValidator, CurrencyValidator)
1111

1212

1313
@extract(parameters=[
@@ -205,3 +205,11 @@ def to_int(arg):
205205
])
206206
def extract_with_custom_transform_example(a_dictionary, my_param=None):
207207
return {}
208+
209+
210+
@extract(parameters=[
211+
Parameter(path="/params/currency_example", func_param_name="a_dictionary",
212+
validators=[CurrencyValidator])
213+
])
214+
def extract_currency_param(a_dictionary, currency_example=None):
215+
return currency_example

examples/test_examples.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
cors_example, extract_multiple_param_example,
99
extract_minimum_param_with_custom_error_example, extract_dictionary_example,
1010
extract_type_param, extract_enum_param, extract_non_empty_param, extract_date_param,
11-
extract_with_transform_example, extract_with_custom_transform_example)
11+
extract_with_transform_example, extract_with_custom_transform_example,
12+
extract_currency_param)
1213

1314

1415
# pylint:disable=too-many-public-methods
@@ -334,6 +335,20 @@ def test_extract_date_param(self):
334335
# will return the extracted values in a dictionary.
335336
self.assertEqual("2001-01-01 00:00:00", response)
336337

338+
def test_extract_currency_param(self):
339+
# Given this dictionary:
340+
a_dictionary = {
341+
"params": {
342+
"currency_example": "GBP"
343+
}
344+
}
345+
346+
# calling the decorated extract_dictionary_example:
347+
response = extract_currency_param(a_dictionary)
348+
349+
# will return the extracted values in a dictionary.
350+
self.assertEqual("GBP", response)
351+
337352
def test_extract_with_transform(self):
338353
# Given this dictionary:
339354
a_dictionary = {

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
LONG_DESCRIPTION = open("README.md").read()
44

55
setup(name="aws-lambda-decorators",
6-
version="0.45",
6+
version="0.46",
77
description="A set of python decorators to simplify aws python lambda development",
88
long_description=LONG_DESCRIPTION,
99
long_description_content_type="text/markdown",

tests/test_decorators.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from aws_lambda_decorators.decorators import extract, extract_from_event, extract_from_context, handle_exceptions, \
1414
log, response_body_as_json, extract_from_ssm, validate, handle_all_exceptions, cors
1515
from aws_lambda_decorators.validators import Mandatory, RegexValidator, SchemaValidator, Minimum, Maximum, MaxLength, \
16-
MinLength, Type, EnumValidator, NonEmpty, DateValidator
16+
MinLength, Type, EnumValidator, NonEmpty, DateValidator, CurrencyValidator
1717

1818
TEST_JWT = "eyJraWQiOiJEQlwvK0lGMVptekNWOGNmRE1XVUxBRlBwQnVObW5CU2NcL2RoZ3pnTVhcL2NzPSIsImFsZyI6IlJTMjU2In0." \
1919
"eyJzdWIiOiJhYWRkMWUwZS01ODA3LTQ3NjMtYjFlOC01ODIzYmY2MzFiYjYiLCJhdWQiOiIycjdtMW1mdWFiODg3ZmZvdG9iNWFjcX" \
@@ -1679,6 +1679,61 @@ def handler(event, a=None): # noqa: pylint - unused-argument
16791679
response = handler(event)
16801680
self.assertEqual(None, response)
16811681

1682+
def test_extract_currency_parameter(self):
1683+
event = {
1684+
"a": "GBP"
1685+
}
1686+
1687+
@extract([Parameter("/a", "event", [CurrencyValidator])])
1688+
def handler(event, a=None): # noqa: pylint - unused-argument
1689+
return a
1690+
1691+
response = handler(event)
1692+
self.assertEqual("GBP", response)
1693+
1694+
def test_currency_validator_returns_true_when_none_is_passed_in(self):
1695+
path = "/a/b/c"
1696+
dictionary = {
1697+
"a": {
1698+
"b": {
1699+
"c": None
1700+
}
1701+
}
1702+
}
1703+
1704+
@extract([Parameter(path, "event", [CurrencyValidator])])
1705+
def handler(event, c=None): # noqa
1706+
return c
1707+
1708+
response = handler(dictionary, None)
1709+
self.assertEqual(None, response)
1710+
1711+
def test_currency_validator_returns_false_when_invalid_code_passed_in(self):
1712+
event = {
1713+
"a": "GBT"
1714+
}
1715+
1716+
@extract([Parameter("/a", "event", [CurrencyValidator])])
1717+
def handler(event, a=None): # noqa: pylint - unused-argument
1718+
return {}
1719+
1720+
response = handler(event)
1721+
self.assertEqual(400, response["statusCode"])
1722+
self.assertEqual("{\"message\": [{\"a\": [\"\'GBT\' is not a valid currency code.\"]}]}",
1723+
response["body"])
1724+
1725+
def test_currency_validator_can_be_called_non_statically(self):
1726+
event = {
1727+
"a": "GBP"
1728+
}
1729+
1730+
@extract([Parameter("/a", "event", [CurrencyValidator()])])
1731+
def handler(event, a=None): # noqa: pylint - unused-argument
1732+
return a
1733+
1734+
response = handler(event)
1735+
self.assertEqual("GBP", response)
1736+
16821737
def test_can_apply_transformation(self):
16831738
event = {
16841739
"a": "2"

0 commit comments

Comments
 (0)