Skip to content

Commit

Permalink
Streamline transformer and test not-implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
CasperWA committed Jun 2, 2020
1 parent ee6f895 commit 44469c0
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 44 deletions.
1 change: 1 addition & 0 deletions aiida_optimade/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
)
APP.add_exception_handler(ValidationError, exc_handlers.validation_exception_handler)
APP.add_exception_handler(VisitError, exc_handlers.grammar_not_implemented_handler)
APP.add_exception_handler(NotImplementedError, exc_handlers.not_implemented_handler)
APP.add_exception_handler(Exception, exc_handlers.general_exception_handler)


Expand Down
42 changes: 13 additions & 29 deletions aiida_optimade/transformers/aiida.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def value(self, value):
@v_args(inline=True)
def non_string_value(self, value):
""" non_string_value: number | property """
# Note: Do nothing!
# NOTE: Do nothing!
return value

@v_args(inline=True)
Expand All @@ -63,26 +63,16 @@ def not_implemented_string(self, value):

def value_list(self, args):
"""value_list: [ OPERATOR ] value ( "," [ OPERATOR ] value )*"""
values = []
for value in args:
if value in self.reversed_operator_map:
if str(value) in self.reversed_operator_map:
# value is OPERATOR
# This is currently not supported
raise NotImplementedError(
f"OPERATOR {value} inside value_list {args} has not been "
"implemented."
)

try:
value = float(value)
except ValueError:
if value.startswith('"') and value.endswith('"'):
value = value[1:-1]
else:
if value.is_integer():
value = int(value)
values.append(value)
return values
return args

def value_zip(self, arg):
"""
Expand Down Expand Up @@ -170,18 +160,15 @@ def fuzzy_string_op_rhs(self, arg):
STARTS [ WITH ] string |
ENDS [ WITH ] string
"""
# The WITH keyword may be omitted.
if isinstance(arg[1], Token) and arg[1].type == "WITH":
pattern = arg[2]
else:
pattern = arg[1]

# Since the string pattern will always be the last argument,
# and there is always another keyword before the OPTIONAL "WITH",
# there is no need to test for the existence of "WITH"
if arg[0] == "CONTAINS":
like = f"%{pattern}%"
like = f"%{arg[-1]}%"
elif arg[0] == "STARTS":
like = f"{pattern}%"
like = f"{arg[-1]}%"
elif arg[0] == "ENDS":
like = f"%{pattern}"
like = f"%{arg[-1]}"
return {"like": like}

def set_op_rhs(self, arg):
Expand All @@ -200,13 +187,11 @@ def set_op_rhs(self, arg):
if arg[1] == "ANY":
return {"or": [{"contains": [value]} for value in arg[2]]}
if arg[1] == "ONLY":
raise NotImplementedError(
"'set_op_rhs: HAS ONLY value_list' has not been implemented."
)
raise NotImplementedError

# value with OPERATOR
raise NotImplementedError(
"'set_op_rhs: HAS OPERATOR value' has not been implemented."
f"set_op_rhs has not been implemented for use with OPERATOR. Given: {arg}"
)

def set_zip_op_rhs(self, arg):
Expand Down Expand Up @@ -239,8 +224,7 @@ def length_op_rhs(self, arg):
}

raise NotImplementedError(
f"length_comparison has failed with {arg}. "
"Unknown not-implemented operator."
f"Operator {operator} has not been implemented for the LENGTH filter."
)

def property_zip_addon(self, arg):
Expand Down Expand Up @@ -280,7 +264,7 @@ def number(self, number):
type_ = float
return type_(number)

def __default__(self, data, children, meta):
def __default__(self, data, children, meta): # pragma: no cover
raise NotImplementedError(
"Calling __default__, i.e., unknown grammar concept. "
f"data: {data}, children: {children}, meta: {meta}"
Expand Down
19 changes: 13 additions & 6 deletions tests/server/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def inner(
expected_title: str = None,
expected_detail: str = None,
):
response = None
try:
response = client.get(request)
assert response.status_code == expected_status, (
Expand All @@ -64,22 +65,28 @@ def inner(
)

response = response.json()
assert len(response["errors"]) == 1
assert response["meta"]["data_returned"] == 0
assert len(response["errors"]) == 1, response.get(
"errors", "'errors' not found"
)
assert response["meta"]["data_returned"] == 0, response.get(
"meta", "'meta' not found"
)

error = response["errors"][0]
assert str(expected_status) == error["status"]
assert expected_title == error["title"]
assert str(expected_status) == error["status"], error
assert expected_title == error["title"], error

if expected_detail is None:
expected_detail = "Error trying to process rule "
assert error["detail"].startswith(expected_detail)
assert error["detail"].startswith(expected_detail), error
else:
assert expected_detail == error["detail"]
assert expected_detail == error["detail"], error

except Exception as exc:
print("Request attempted:")
print(f"{client.base_url}{request}")
if response:
print(f"\nCaptured response:\n{response}")
raise exc

return inner
35 changes: 26 additions & 9 deletions tests/server/test_query_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def test_list_length_basic(check_response):
check_response(request, expected_ids)


def test_list_length(check_response):
def test_list_length_operators(check_response):
request = "/structures?filter=elements LENGTH = 17"
expected_ids = ["1047"]
check_response(request, expected_ids)
Expand All @@ -129,18 +129,35 @@ def test_list_length(check_response):
check_response(request, expected_ids)


@pytest.mark.skip("HAS ONLY is not implemented.")
def test_list_has_only(check_response):
def test_list_length_bad_operators(check_error_response):
"""Check NonImplementedError is raised when using a valid,
but not-supported operator"""
bad_valid_operator = "!="
request = f"/structures?filter=elements LENGTH {bad_valid_operator} 2"
check_error_response(
request,
expected_status=501,
expected_title="NotImplementedError",
expected_detail=(
f"Operator {bad_valid_operator} has not been implemented for the LENGTH filter."
),
)


def test_list_has_only(check_error_response):
# HAS ONLY is not yet implemented
request = '/structures?filter=elements HAS ONLY "Ac"'
expected_ids = [""]
check_response(request, expected_ids)
check_error_response(
request, expected_status=501, expected_title="NotImplementedError"
)


@pytest.mark.skip("Zips are not implemented.")
def test_list_correlated(check_response):
def test_list_correlated(check_error_response):
# Zipped lists are not yet implemented
request = '/structures?filter=elements:elements_ratios HAS "Ag":"0.2"'
expected_ids = [""]
check_response(request, expected_ids)
check_error_response(
request, expected_status=501, expected_title="NotImplementedError"
)


def test_saved_extras_is_known(check_response):
Expand Down

0 comments on commit 44469c0

Please sign in to comment.