From 4039d32479e33d542b2669ce0f617df77c8fd73f Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Fri, 6 Jul 2018 23:25:43 +0300 Subject: [PATCH] PY-30563, PY-30768: Support parameter types for behave and pytest-bdd There are 2 parsers: * (cf)parse: supports syntax like {paramName:d} or custom types: {paramName:Foo}. Foo must be mapped to real type by behave and pytest-bdd using different approaches. * re: supports regexp. By default types are strings, but pytest-bdd can match param names to certain types. And there are 2 frameworks (each of them supports both parsers): * behave * pytest-bdd Parsers are implemented as PyBDDParser inheritors (and called *processors for historical reasons) and by PyBDDMatcher instances. Frameworks are implemented by PyStepDefinition inheritors. PyStepDefinition's know to how to: * fetch type-alias-to-type or argument-name-to-type mappings * find step definition expression in decorator Parsers know how to: * convert step definition to python regexp * get argument types using information from PyStepDefinition's --- .../python/psi/impl/PyEvaluator.java | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java b/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java index edeaaec947aa..c6453735022c 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java +++ b/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java @@ -60,6 +60,11 @@ public class PyEvaluator { */ private boolean myEnableResolve = true; + /** + * Store expressions as values if they can't be evaludated + */ + private boolean myAllowExpressionsAsValues = false; + public void setNamespace(@Nullable Map namespace) { myNamespace = namespace; } @@ -68,6 +73,10 @@ public class PyEvaluator { myEvaluateCollectionItems = evaluateCollectionItems; } + public void setAllowExpressionsAsValues(final boolean allowExpressionsAsValues) { + myAllowExpressionsAsValues = allowExpressionsAsValues; + } + public void setEvaluateKeys(boolean evaluateKeys) { myEvaluateKeys = evaluateKeys; } @@ -304,13 +313,34 @@ public class PyEvaluator { } return result; } - } + final PyExpression[] arguments = expression.getArguments(); + //dict(foo="spam") + if (arguments.length > 0) { + final Map result = new HashMap<>(); + for (final PyExpression argument : arguments) { + if (!(argument instanceof PyKeywordArgument)) { + continue; + } + final PyKeywordArgument keywordArgument = (PyKeywordArgument)argument; + final String keyword = keywordArgument.getKeyword(); + if (keyword == null) { + continue; + } + addRecordFromDict(result, keyword, keywordArgument.getValueExpression()); + } + return result; + } + } return null; } private void addRecordFromDict(@NotNull Map result, @NotNull PyExpression key, @Nullable PyExpression value) { - result.put(myEvaluateKeys ? evaluate(key) : key, myEvaluateCollectionItems ? evaluate(value) : value); + result.put(myEvaluateKeys ? evaluate(key) : key, myEvaluateCollectionItems ? evaluateOrGet(value) : value); + } + + private void addRecordFromDict(@NotNull Map result, @NotNull String key, @Nullable PyExpression value) { + result.put(key, myEvaluateCollectionItems ? evaluateOrGet(value) : value); } @NotNull @@ -430,4 +460,13 @@ public class PyEvaluator { return null; } + + @Nullable + private Object evaluateOrGet(@Nullable final PyExpression expression) { + final Object result = evaluate(expression); + if (result !=null) { + return result; + } + return myAllowExpressionsAsValues ? expression : null; + } }