diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,10 +31,11 @@ # find the system python 3 interpreter, only used for determining search paths. # must be called before find_package(KF5) because it searchs for python too, but finds python2 -find_package(Python 3.6 REQUIRED) +find_package(PythonInterp 3.5 REQUIRED) +find_package(PythonLibs 3.5 REQUIRED) configure_file( "${kdevpython_SOURCE_DIR}/kdevpythonversion.h.cmake" "${kdevpython_BINARY_DIR}/kdevpythonversion.h" @ONLY ) if ( (NOT PYTHON_LIBRARIES) OR "${PYTHON_VERSION_MINOR}" GREATER 6 ) - message(FATAL_ERROR "Python >= 3.6.0 but < 3.7 with --enable-shared is required to build kdev-python") + message(FATAL_ERROR "Python >= 3.5.0 but < 3.7 with --enable-shared is required to build kdev-python") endif() find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED Widgets Test) diff --git a/cmake/modules/FindPython.cmake b/cmake/modules/FindPython.cmake deleted file mode 100644 --- a/cmake/modules/FindPython.cmake +++ /dev/null @@ -1,193 +0,0 @@ -# This code sets the following variables: -# PYTHON_FOUND - boolean that indicates success -# PYTHON_EXEC - path to python executable -# PYTHON_LIBRARIES - path to the python library -# PYTHON_INCLUDE_DIRS - path to where Python.h is found -# PTYHON_SITE_MODULES - path to site-packages -# PYTHON_ARCH - name of architecture to be used for platform-specific -# binary modules -# PYTHON_VERSION - version of python -# PYTHON_VERSION_MAJOR - major version number -# PYTHON_VERSION_MAJOR - minor version number -# PYTHON_VERSION_MICRO - micro version number -# -# You can optionally include the version number when using this package -# like so: -# find_package(python 2.6) -# -# This code defines a helper function find_python_module(). It can be used -# like so: -# find_python_module(numpy [version] [REQUIRED|QUIET]) -# If numpy is found, the variable PY_NUMPY contains the location of the numpy -# module. If a particular minimum version or higher is required, use the -# version argument: -# find_python_module(numpy 1.9.0) -# If the module is required add the keyword "REQUIRED": -# find_python_module(numpy REQUIRED) -# If no output should be displayed about whether the module is found, use the -# QUIET argument: -# find_python_module(numpy QUIET) - -include(FindPackageHandleStandardArgs) - -# TODO -set(LOOKING_FOR_VERSION "3.6") - -# allow specifying which Python installation to use -if (NOT PYTHON_EXEC) - set(PYTHON_EXEC $ENV{PYTHON_EXEC}) -endif (NOT PYTHON_EXEC) - -if (NOT PYTHON_EXEC) - if (CMAKE_SYSTEM_NAME STREQUAL "Windows") - set(PYTHON_EXEC_NAME "python") - else() - set(PYTHON_EXEC_NAME "python${Python_FIND_VERSION}") - endif() - find_program(PYTHON_EXEC ${PYTHON_EXEC_NAME} - PATHS - [HKEY_LOCAL_MACHINE\\Software\\Python\\PythonCore\\${LOOKING_FOR_VERSION}\\InstallPath] - [HKEY_LOCAL_MACHINE\\Software\\Python\\PythonCore\\${LOOKING_FOR_VERSION}-32\\InstallPath] - [HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\${LOOKING_FOR_VERSION}\\InstallPath] - [HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\${LOOKING_FOR_VERSION}-32\\InstallPath] - DOC "Location of python executable to use") - message("RESULT: ${PYTHON_EXEC}") -endif(NOT PYTHON_EXEC) - -# if Python is still not found, return -if (NOT PYTHON_EXEC) - # dummy function - function(find_python_module module) - return() - endfunction(find_python_module) - return() -endif() - -# On OS X the python executable might be symlinked to the "real" location -# of the python executable. The header files and libraries are found relative -# to that path. -# For CMake 2.6 and below, the REALPATH option is included in the ABSOLUTE option -if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.6) - get_filename_component(PYTHON_EXEC_ "${PYTHON_EXEC}" REALPATH) -else() - get_filename_component(PYTHON_EXEC_ "${PYTHON_EXEC}" ABSOLUTE) -endif() -set(PYTHON_EXEC "${PYTHON_EXEC_}" CACHE FILEPATH "Path to Python interpreter") - -string(REGEX REPLACE "/bin/python.*" "" PYTHON_PREFIX "${PYTHON_EXEC_}") -string(REGEX REPLACE "/bin/python.*" "" PYTHON_PREFIX2 "${PYTHON_EXEC}") - -execute_process(COMMAND "${PYTHON_EXEC}" "-c" - "import sys; print('%d;%d;%d' % (sys.version_info[0],sys.version_info[1],sys.version_info[2]))" - OUTPUT_VARIABLE PYTHON_VERSION_INFO - OUTPUT_STRIP_TRAILING_WHITESPACE) -list(GET PYTHON_VERSION_INFO 0 PYTHON_VERSION_MAJOR) -list(GET PYTHON_VERSION_INFO 1 PYTHON_VERSION_MINOR) -list(GET PYTHON_VERSION_INFO 2 PYTHON_VERSION_MICRO) - -set(PYTHON_VERSION "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") -set(PYTHON_VERSION_NO_DOTS "${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}") - -find_library(PYTHON_LIBRARIES - NAMES "python${PYTHON_VERSION_NO_DOTS}" "python${PYTHON_VERSION}" "python${PYTHON_VERSION}m" - PATHS - "${PYTHON_PREFIX}/lib" - [HKEY_LOCAL_MACHINE\\Software\\Python\\PythonCore\\${PYTHON_VERSION}\\InstallPath]/libs - [HKEY_LOCAL_MACHINE\\Software\\Python\\PythonCore\\${PYTHON_VERSION}-32\\InstallPath]/libs - [HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\${PYTHON_VERSION}\\InstallPath]/libs - [HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\${PYTHON_VERSION}-32\\InstallPath]/libs - PATH_SUFFIXES "" "python${PYTHON_VERSION}/config" "${CMAKE_LIBRARY_ARCHITECTURE}" - DOC "Python libraries" NO_DEFAULT_PATH) - -find_path(PYTHON_INCLUDE_DIRS "Python.h" - PATHS - "${PYTHON_PREFIX}/include" - [HKEY_LOCAL_MACHINE\\Software\\Python\\PythonCore\\${PYTHON_VERSION}\\InstallPath]/include - [HKEY_LOCAL_MACHINE\\Software\\Python\\PythonCore\\${PYTHON_VERSION}-32\\InstallPath]/include - [HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\${PYTHON_VERSION}\\InstallPath]/include - [HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\${PYTHON_VERSION}-32\\InstallPath]/include - PATH_SUFFIXES python${PYTHON_VERSION} python${PYTHON_VERSION}m - DOC "Python include directories" NO_DEFAULT_PATH) - -execute_process(COMMAND "${PYTHON_EXEC}" "-c" - "from distutils.sysconfig import get_python_lib; print(get_python_lib())" - OUTPUT_VARIABLE PYTHON_SITE_MODULES_ - OUTPUT_STRIP_TRAILING_WHITESPACE) -string(REGEX REPLACE "^${PYTHON_PREFIX2}/" "" PYTHON_SITE_MODULES "${PYTHON_SITE_MODULES_}") - -function(find_python_module module) - string(TOUPPER ${module} module_upper) - set(_minversion "") - if(ARGC GREATER 2) - set(_minversion ${ARGV1}) - if (ARGV2 STREQUAL "REQUIRED") - set(PY_${module}_FIND_REQUIRED TRUE) - elseif (ARGV2 STREQUAL "QUIET") - set(PY_${module}_FIND_QUIETLY TRUE) - endif() - elseif (ARGC GREATER 1) - if (ARGV1 STREQUAL "REQUIRED") - set(PY_${module}_FIND_REQUIRED TRUE) - elseif (ARGV1 STREQUAL "QUIET") - set(PY_${module}_FIND_QUIETLY TRUE) - else() - set(_minversion ${ARGV1}) - endif() - endif() - if(NOT PY_${module_upper}) - # A module's location is usually a directory, but for binary modules - # it's a .so file. - if (_minversion STREQUAL "") - execute_process(COMMAND "${PYTHON_EXEC}" "-c" - "import re, ${module}; print(re.compile('/__init__.py.*').sub('',${module}.__file__))" - RESULT_VARIABLE _status OUTPUT_VARIABLE _location - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - if(NOT _status) - set(PY_${module_upper} ${_location} CACHE STRING - "Location of Python module ${module}") - endif(NOT _status) - else (_minversion STREQUAL "") - execute_process(COMMAND "${PYTHON_EXEC}" "-c" - "import re, ${module}; print(re.compile('/__init__.py.*').sub('',${module}.__version__+';'+${module}.__file__))" - RESULT_VARIABLE _status - OUTPUT_VARIABLE _verloc - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - list(GET _verloc 1 _location) - list(GET _verloc 0 _version) - message("${_status} ${_verloc} ${_version}") - if(NOT _status) - if (NOT ${_version} VERSION_LESS ${_minversion}) - set(PY_${module_upper} ${_location} CACHE STRING - "Location of Python module ${module}") - set(PY_${module_upper}_VERSION ${_version} CACHE STRING - "Version of Python module ${module}") - else() - message(SEND_ERROR "Module '${module}' version ${_version} found, but minimum version ${_minversion} required.") - endif() - endif(NOT _status) - endif (_minversion STREQUAL "") - endif(NOT PY_${module_upper}) - find_package_handle_standard_args(PY_${module} DEFAULT_MSG PY_${module_upper}) -endfunction(find_python_module) - -set(PYTHON_ARCH "unknown") -if(APPLE) - set(PYTHON_ARCH "darwin") -else(APPLE) - if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - set(PYTHON_ARCH "linux2") - else(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - set(PYTHON_ARCH "linux") - endif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - else(CMAKE_SYSTEM_NAME STREQUAL "Linux") - if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - set(PYTHON_ARCH "windows") - endif(CMAKE_SYSTEM_NAME STREQUAL "Windows") - endif(CMAKE_SYSTEM_NAME STREQUAL "Linux") -endif(APPLE) - -message(STATUS "Found Python version ${PYTHON_VERSION}\n Libraries: ${PYTHON_LIBRARIES}\n Includes: ${PYTHON_INCLUDE_DIRS}\n Modules: ${PYTHON_SITE_MODULES}") - -find_package_handle_standard_args(Python DEFAULT_MSG - PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS PYTHON_SITE_MODULES) diff --git a/cmake/modules/README-FindPython b/cmake/modules/README-FindPython deleted file mode 100644 --- a/cmake/modules/README-FindPython +++ /dev/null @@ -1,40 +0,0 @@ -The FindPython.cmake script in this directory is modified from -https://bitbucket.org/ompl/ompl/src/tip/CMakeModules/FindPython.cmake -(commit 00b24b3). The modifications added provide the additional -PYTHON_VERSION_{MAJOR,MINOR,MICRO} macros required by kdev-python. - -FindPython.cmake comes from the OMPL project, covered by the following -BSD license: - -The Open Motion Planning Library (OMPL) is released as Open Source -under the terms of a 3-clause BSD license. - -Copyright (c) 2010-2014, Rice University -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. -* Neither the name of the Rice University nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/duchain/helpers.cpp b/duchain/helpers.cpp --- a/duchain/helpers.cpp +++ b/duchain/helpers.cpp @@ -376,11 +376,11 @@ } // Find python 3 (https://www.python.org/dev/peps/pep-0394/) - auto result = QStandardPaths::findExecutable("python" PYTHON_VERSION_MAJOR "." PYTHON_VERSION_MINOR); + auto result = QStandardPaths::findExecutable("python" PYTHON_VERSION_STR); if ( ! result.isEmpty() ) { return result; } - result = QStandardPaths::findExecutable("python" PYTHON_VERSION_MAJOR); + result = QStandardPaths::findExecutable("python" PYTHON_VERSION_MAJOR_STR); if ( ! result.isEmpty() ) { return result; } @@ -399,7 +399,7 @@ "HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\PYTHON_VERSION\\InstallPath", "HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\PYTHON_VERSION-32\\InstallPath" }; - auto version = QString(PYTHON_VERSION_MAJOR) + "." + PYTHON_VERSION_MINOR; + auto version = QString(PYTHON_VERSION_STR); foreach ( QString key, keys ) { key.replace("PYTHON_VERSION", version); QSettings base(key.left(key.indexOf("Python")), QSettings::NativeFormat); diff --git a/kdevpythonversion.h.cmake b/kdevpythonversion.h.cmake --- a/kdevpythonversion.h.cmake +++ b/kdevpythonversion.h.cmake @@ -28,8 +28,10 @@ #define KDEVPYTHON_VERSION KDE_MAKE_VERSION(@KDEVPYTHON_VERSION_MAJOR@, @KDEVPYTHON_VERSION_MINOR@, @KDEVPYTHON_VERSION_PATCH@) -#define PYTHON_VERSION_MAJOR "@PYTHON_VERSION_MAJOR@" -#define PYTHON_VERSION_MINOR "@PYTHON_VERSION_MINOR@" +#define PYTHON_VERSION_MAJOR @PYTHON_VERSION_MAJOR@ +#define PYTHON_VERSION_MINOR @PYTHON_VERSION_MINOR@ +#define PYTHON_VERSION_MAJOR_STR "@PYTHON_VERSION_MAJOR@" +#define PYTHON_VERSION_STR "@PYTHON_VERSION_MAJOR@.@PYTHON_VERSION_MINOR@" #define PYTHON_EXECUTABLE "@PYTHON_EXEC@" #endif diff --git a/parser/conversionGenerator.py b/parser/conversionGenerator.py --- a/parser/conversionGenerator.py +++ b/parser/conversionGenerator.py @@ -120,9 +120,15 @@ kind = outline[1].split(' ')[1] kind_wo_suffix = kind.replace('_kind', '') actions = outline[2].split(' ')[1:] - code = False + code = None + since_version = None if len(outline) > 3: - code = ' '.join(';'.join(outline[3:]).split('CODE')[1:]) + ";" + if outline[3].startswith('SINCE'): + since_version = [int(n) for n in outline[3][6:].split('.')] + elif outline[3].startswith('CODE'): + code = ' '.join(';'.join(outline[3:]).split('CODE')[1:]) + ";" + else: + raise SyntaxError('Invalid syntax in sdef file, line: ' + rule) if rule_for not in results: results[rule_for] = list() @@ -202,6 +208,10 @@ current_stmt = current_actions else: current_stmt = switch_line.replace('%{KIND}', kind).replace('%{ACTIONS}', current_actions) + if since_version: + version_cpp_if = ("#if PYTHON_VERSION_MAJOR >= %d && PYTHON_VERSION_MINOR >= %d\n" + %(since_version[0], since_version[1])) + current_stmt = version_cpp_if + current_stmt + "\n#endif" results[rule_for].append(current_stmt) does_match_any[rule_for] = any @@ -211,6 +221,7 @@ */ #include +#include "kdevpythonversion.h" class PythonAstTransformer { public: diff --git a/parser/generated.h b/parser/generated.h --- a/parser/generated.h +++ b/parser/generated.h @@ -4,6 +4,7 @@ */ #include +#include "kdevpythonversion.h" class PythonAstTransformer { public: @@ -283,20 +284,24 @@ result = v; break; } +#if PYTHON_VERSION_MAJOR >= 3 && PYTHON_VERSION_MINOR >= 6 case JoinedStr_kind: { JoinedStringAst* v = new JoinedStringAst(parent()); nodeStack.push(v); v->values = visitNodeList<_expr, ExpressionAst>(node->v.JoinedStr.values); nodeStack.pop(); result = v; break; } +#endif +#if PYTHON_VERSION_MAJOR >= 3 && PYTHON_VERSION_MINOR >= 6 case FormattedValue_kind: { FormattedValueAst* v = new FormattedValueAst(parent()); nodeStack.push(v); v->value = static_cast(visitNode(node->v.FormattedValue.value)); nodeStack.pop(); v->conversion = node->v.FormattedValue.conversion; nodeStack.push(v); v->formatSpec = static_cast(visitNode(node->v.FormattedValue.format_spec)); nodeStack.pop(); result = v; break; } +#endif case Bytes_kind: { BytesAst* v = new BytesAst(parent()); v->value = PyUnicodeObjectToQString(node->v.Bytes.s); @@ -578,14 +583,16 @@ result = v; break; } +#if PYTHON_VERSION_MAJOR >= 3 && PYTHON_VERSION_MINOR >= 6 case AnnAssign_kind: { AnnotationAssignmentAst* v = new AnnotationAssignmentAst(parent()); nodeStack.push(v); v->target = static_cast(visitNode(node->v.AnnAssign.target)); nodeStack.pop(); nodeStack.push(v); v->annotation = static_cast(visitNode(node->v.AnnAssign.annotation)); nodeStack.pop(); nodeStack.push(v); v->value = static_cast(visitNode(node->v.AnnAssign.value)); nodeStack.pop(); result = v; break; } +#endif case For_kind: { ForAst* v = new ForAst(parent()); nodeStack.push(v); v->target = static_cast(visitNode(node->v.For.target)); nodeStack.pop(); diff --git a/parser/python36.sdef b/parser/python36.sdef --- a/parser/python36.sdef +++ b/parser/python36.sdef @@ -17,7 +17,7 @@ RULE_FOR _stmt;KIND Delete_kind;ACTIONS create|DeleteAst set|targets=>ExpressionAst,targets;; RULE_FOR _stmt;KIND Assign_kind;ACTIONS create|AssignmentAst set|targets=>ExpressionAst,targets set|value->ExpressionAst,value;; RULE_FOR _stmt;KIND AugAssign_kind;ACTIONS create|AugmentedAssignmentAst set|target->ExpressionAst,target set|op*>OperatorTypes,op set|value->ExpressionAst,value;; -RULE_FOR _stmt;KIND AnnAssign_kind;ACTIONS create|AnnotationAssignmentAst set|target->ExpressionAst,target set|annotation->ExpressionAst,annotation set|value->ExpressionAst,value;; +RULE_FOR _stmt;KIND AnnAssign_kind;ACTIONS create|AnnotationAssignmentAst set|target->ExpressionAst,target set|annotation->ExpressionAst,annotation set|value->ExpressionAst,value;SINCE 3.6;; RULE_FOR _stmt;KIND For_kind;ACTIONS create|ForAst set|target->ExpressionAst,target set|iterator->ExpressionAst,iter set|body=>Ast,body set|orelse=>Ast,orelse;; RULE_FOR _stmt;KIND AsyncFor_kind;ACTIONS create|ForAst set|target->ExpressionAst,target set|iterator->ExpressionAst,iter set|body=>Ast,body set|orelse=>Ast,orelse;; RULE_FOR _stmt;KIND While_kind;ACTIONS create|WhileAst set|condition->ExpressionAst,test set|body=>Ast,body set|orelse=>Ast,orelse;; @@ -54,8 +54,8 @@ RULE_FOR _expr;KIND Call_kind;ACTIONS create|CallAst set|function->ExpressionAst,func set|arguments=>ExpressionAst,args set|keywords=>KeywordAst,keywords;; RULE_FOR _expr;KIND Num_kind;ACTIONS create|NumberAst;CODE v->isInt = PyLong_Check(node->v.Num.n); v->value = PyLong_AsLong(node->v.Num.n);; RULE_FOR _expr;KIND Str_kind;ACTIONS create|StringAst set|value$>s;; -RULE_FOR _expr;KIND JoinedStr_kind;ACTIONS create|JoinedStringAst set|values=>ExpressionAst,values;; -RULE_FOR _expr;KIND FormattedValue_kind;ACTIONS create|FormattedValueAst set|value->ExpressionAst,value set|conversion:>conversion set|formatSpec->ExpressionAst,format_spec;; +RULE_FOR _expr;KIND JoinedStr_kind;ACTIONS create|JoinedStringAst set|values=>ExpressionAst,values;SINCE 3.6;; +RULE_FOR _expr;KIND FormattedValue_kind;ACTIONS create|FormattedValueAst set|value->ExpressionAst,value set|conversion:>conversion set|formatSpec->ExpressionAst,format_spec;SINCE 3.6;; RULE_FOR _expr;KIND Bytes_kind;ACTIONS create|BytesAst set|value$>s;; RULE_FOR _expr;KIND Attribute_kind;ACTIONS create|AttributeAst set|attribute~>attr set|value->ExpressionAst,value set|context*>Context,ctx;; RULE_FOR _expr;KIND Subscript_kind;ACTIONS create|SubscriptAst set|value->ExpressionAst,value set|slice->SliceAst,slice set|context*>Context,ctx;; diff --git a/parser/tests/pyasttest.cpp b/parser/tests/pyasttest.cpp --- a/parser/tests/pyasttest.cpp +++ b/parser/tests/pyasttest.cpp @@ -26,6 +26,7 @@ #include "parsesession.h" #include "pythoneditorintegrator.h" +#include "kdevpythonversion.h" #include "declarationbuilder.h" #include "usebuilder.h" #include "astdefaultvisitor.h" @@ -153,8 +154,10 @@ QTest::newRow("continue") << "while True: continue"; QTest::newRow("pass") << "pass"; QTest::newRow("nonlocal") << "nonlocal x"; +#if PYTHON_VERSION_MAJOR >= 3 && PYTHON_VERSION_MINOR >= 6 QTest::newRow("varannotation1") << "primes: List[int] = []"; QTest::newRow("varannotation2") << "captain: str # Note: no initial value!"; +#endif } void PyAstTest::testSlices() @@ -224,15 +227,17 @@ QTest::newRow("False") << "False"; QTest::newRow("True") << "True"; +#if PYTHON_VERSION_MAJOR >= 3 && PYTHON_VERSION_MINOR >= 6 QTest::newRow("async_generator") << "async def foo(): result = [i async for i in aiter() if i % 2]"; QTest::newRow("await_generator") << "async def foo(): result = [await fun() for fun in funcs]"; QTest::newRow("underscore_literals") << "0x_FF_FF_FF_FF"; + QTest::newRow("formatted_string_literal") << "f\"He said his name is {name}.\""; +#endif QTest::newRow("dstar_unpack") << "ext_map = {\n" " **{ext: self.obj_extension for ext in self.src_extensions},\n" " **{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions},\n" "}"; - QTest::newRow("formatted_string_literal") << "f\"He said his name is {name}.\""; } void PyAstTest::testCorrectedFuncRanges()