From 0fe7f42efcdde1010d16e93ca392059d000c0c01 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Sun, 17 Mar 2019 18:28:39 -0400 Subject: [PATCH 1/5] Remove internal checks for Python 3.5 --- hy/compiler.py | 20 ++++++++++---------- hy/core/shadow.hy | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 8bd2aae..32610c5 100755 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -15,7 +15,7 @@ from hy.errors import (HyCompileError, HyTypeError, HyLanguageError, from hy.lex import mangle, unmangle, hy_parse, parse_one_thing, LexException from hy._compat import (string_types, str_type, bytes_type, long_type, PY3, - PY35, PY36, reraise) + PY36, reraise) from hy.macros import require, load_macros, macroexpand, tag_macroexpand import hy.core @@ -106,7 +106,7 @@ def ast_str(x, piecewise=False): _special_form_compilers = {} _model_compilers = {} _decoratables = (ast.FunctionDef, ast.ClassDef) -if PY35: +if PY3: _decoratables += (ast.AsyncFunctionDef,) # _bad_roots are fake special operators, which are used internally # by other special forms (e.g., `except` in `try`) but can't be @@ -279,7 +279,7 @@ class Result(object): var.arg = new_name elif isinstance(var, ast.FunctionDef): var.name = new_name - elif PY35 and isinstance(var, ast.AsyncFunctionDef): + elif PY3 and isinstance(var, ast.AsyncFunctionDef): var.name = new_name else: raise TypeError("Don't know how to rename a %s!" % ( @@ -475,7 +475,7 @@ class HyASTCompiler(object): exprs_iter = iter(exprs) for expr in exprs_iter: - if not PY35 and oldpy_unpack and is_unpack("iterable", expr): + if not PY3 and oldpy_unpack and is_unpack("iterable", expr): if oldpy_starargs: raise self._syntax_error(expr, "Pythons < 3.5 allow only one `unpack-iterable` per call") @@ -485,7 +485,7 @@ class HyASTCompiler(object): elif is_unpack("mapping", expr): ret += self.compile(expr[1]) - if PY35: + if PY3: if dict_display: compiled_exprs.append(None) compiled_exprs.append(ret.force_expr) @@ -912,7 +912,7 @@ class HyASTCompiler(object): ret += self.compile(arg) return ret + asty.Yield(expr, value=ret.force_expr) - @special([(PY3, "yield-from"), (PY35, "await")], [FORM]) + @special([(PY3, "yield-from"), (PY3, "await")], [FORM]) def compile_yield_from_or_await_expression(self, expr, root, arg): ret = Result() + self.compile(arg) node = asty.YieldFrom if root == "yield-from" else asty.Await @@ -991,7 +991,7 @@ class HyASTCompiler(object): fn.stmts[-1].decorator_list = decs + fn.stmts[-1].decorator_list return ret + fn - @special(["with*", (PY35, "with/a*")], + @special(["with*", (PY3, "with/a*")], [brackets(FORM, maybe(FORM)), many(FORM)]) def compile_with_expression(self, expr, root, args, body): thing, ctx = (None, args[0]) if args[1] is None else args @@ -1348,11 +1348,11 @@ class HyASTCompiler(object): "|": ast.BitOr, "^": ast.BitXor, "&": ast.BitAnd} - if PY35: + if PY3: m_ops["@"] = ast.MatMult @special(["+", "*", "|"], [many(FORM)]) - @special(["-", "/", "&", (PY35, "@")], [oneplus(FORM)]) + @special(["-", "/", "&", (PY3, "@")], [oneplus(FORM)]) @special(["**", "//", "<<", ">>"], [times(2, Inf, FORM)]) @special(["%", "^"], [times(2, 2, FORM)]) def compile_maths_expression(self, expr, root, args): @@ -1478,7 +1478,7 @@ class HyASTCompiler(object): NASYM = some(lambda x: isinstance(x, HySymbol) and x not in ( "&optional", "&rest", "&kwonly", "&kwargs")) - @special(["fn", "fn*", (PY35, "fn/a")], [ + @special(["fn", "fn*", (PY3, "fn/a")], [ # The starred version is for internal use (particularly, in the # definition of `defn`). It ensures that a FunctionDef is # produced rather than a Lambda. diff --git a/hy/core/shadow.hy b/hy/core/shadow.hy index 9560d97..2135400 100644 --- a/hy/core/shadow.hy +++ b/hy/core/shadow.hy @@ -5,7 +5,7 @@ ;;;; Hy shadow functions (import operator) -(import [hy._compat [PY3 PY35]]) +(import [hy._compat [PY3]]) (require [hy.core.bootstrap [*]]) @@ -60,7 +60,7 @@ "Shadowed `%` operator takes `x` modulo `y`." (% x y)) -(if PY35 +(if PY3 (defn @ [a1 &rest a-rest] "Shadowed `@` operator matrix multiples `a1` by each `a-rest`." (reduce operator.matmul a-rest a1))) @@ -173,5 +173,5 @@ 'and 'or 'not 'is 'is-not 'in 'not-in 'get]) -(if (not PY35) +(if (not PY3) (.remove EXPORTS '@)) From 85f203ba439e18606865699fd020bad737182e98 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Sun, 17 Mar 2019 18:30:42 -0400 Subject: [PATCH 2/5] Remove checks in tests for Python 3.5 --- tests/native_tests/language.hy | 4 ++-- tests/native_tests/mathematics.hy | 6 +++--- tests/native_tests/operators.hy | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 04936dd..01af5d5 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -11,7 +11,7 @@ pytest) (import sys) -(import [hy._compat [PY3 PY35 PY37]]) +(import [hy._compat [PY3 PY37]]) (defn test-sys-argv [] "NATIVE: test sys.argv" @@ -1550,7 +1550,7 @@ cee\"} dee" "ey bee\ncee dee")) (defn test-disassemble [] "NATIVE: Test the disassemble function" (assert (= (disassemble '(do (leaky) (leaky) (macros))) (cond - [PY35 "Module( + [PY3 "Module( body=[Expr(value=Call(func=Name(id='leaky'), args=[], keywords=[])), Expr(value=Call(func=Name(id='leaky'), args=[], keywords=[])), Expr(value=Call(func=Name(id='macros'), args=[], keywords=[]))])"] diff --git a/tests/native_tests/mathematics.hy b/tests/native_tests/mathematics.hy index a4a61b0..aa4ad78 100644 --- a/tests/native_tests/mathematics.hy +++ b/tests/native_tests/mathematics.hy @@ -2,7 +2,7 @@ ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. -(import [hy._compat [PY35]]) +(import [hy._compat [PY3]]) (setv square (fn [x] (* x x))) @@ -191,7 +191,7 @@ (defn test-matmul [] "NATIVE: test matrix multiplication" - (if PY35 + (if PY3 (assert (= (@ first-test-matrix second-test-matrix) product-of-test-matrices)) ;; Python <= 3.4 @@ -205,6 +205,6 @@ (setv matrix first-test-matrix matmul-attempt (try (@= matrix second-test-matrix) (except [e [Exception]] e))) - (if PY35 + (if PY3 (assert (= product-of-test-matrices matrix)) (assert (isinstance matmul-attempt NameError)))) diff --git a/tests/native_tests/operators.hy b/tests/native_tests/operators.hy index e08edbb..cb0851e 100644 --- a/tests/native_tests/operators.hy +++ b/tests/native_tests/operators.hy @@ -2,7 +2,7 @@ ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. -(import pytest [hy._compat [PY35]]) +(import pytest [hy._compat [PY3]]) (defmacro op-and-shadow-test [op &rest body] ; Creates two tests with the given `body`, one where all occurrences @@ -102,7 +102,7 @@ (forbid (f 1 2 3))) -(when PY35 (op-and-shadow-test @ +(when PY3 (op-and-shadow-test @ (defclass C [object] [ __init__ (fn [self content] (setv self.content content)) __matmul__ (fn [self other] (C (+ self.content other.content)))]) From efed0b6c2323b9615cfd260464517d4d1ce0c318 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Sun, 17 Mar 2019 18:33:06 -0400 Subject: [PATCH 3/5] Move Python 3.5 tests to `py3_only_tests.hy` --- tests/native_tests/py35_only_tests.hy | 103 -------------------------- tests/native_tests/py3_only_tests.hy | 98 ++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 103 deletions(-) delete mode 100644 tests/native_tests/py35_only_tests.hy diff --git a/tests/native_tests/py35_only_tests.hy b/tests/native_tests/py35_only_tests.hy deleted file mode 100644 index fe17443..0000000 --- a/tests/native_tests/py35_only_tests.hy +++ /dev/null @@ -1,103 +0,0 @@ -;; Copyright 2019 the authors. -;; This file is part of Hy, which is free software licensed under the Expat -;; license. See the LICENSE. - -;; Tests where the emitted code relies on Python ≥3.5. -;; conftest.py skips this file when running on Python <3.5. - -(import [asyncio [get-event-loop sleep]]) - - -(defn test-unpacking-pep448-1star [] - (setv l [1 2 3]) - (setv p [4 5]) - (assert (= ["a" #*l "b" #*p #*l] ["a" 1 2 3 "b" 4 5 1 2 3])) - (assert (= (, "a" #*l "b" #*p #*l) (, "a" 1 2 3 "b" 4 5 1 2 3))) - (assert (= #{"a" #*l "b" #*p #*l} #{"a" "b" 1 2 3 4 5})) - (defn f [&rest args] args) - (assert (= (f "a" #*l "b" #*p #*l) (, "a" 1 2 3 "b" 4 5 1 2 3))) - (assert (= (+ #*l #*p) 15)) - (assert (= (and #*l) 3))) - - -(defn test-unpacking-pep448-2star [] - (setv d1 {"a" 1 "b" 2}) - (setv d2 {"c" 3 "d" 4}) - (assert (= {1 "x" #**d1 #**d2 2 "y"} {"a" 1 "b" 2 "c" 3 "d" 4 1 "x" 2 "y"})) - (defn fun [&optional a b c d e f] [a b c d e f]) - (assert (= (fun #**d1 :e "eee" #**d2) [1 2 3 4 "eee" None]))) - - -(defn run-coroutine [coro] - "Run a coroutine until its done in the default event loop.""" - (.run_until_complete (get-event-loop) (coro))) - - -(defn test-fn/a [] - (assert (= (run-coroutine (fn/a [] (await (sleep 0)) [1 2 3])) - [1 2 3]))) - - -(defn test-defn/a [] - (defn/a coro-test [] - (await (sleep 0)) - [1 2 3]) - (assert (= (run-coroutine coro-test) [1 2 3]))) - - -(defn test-decorated-defn/a [] - (defn decorator [func] (fn/a [] (/ (await (func)) 2))) - - #@(decorator - (defn/a coro-test [] - (await (sleep 0)) - 42)) - (assert (= (run-coroutine coro-test) 21))) - - -(defclass AsyncWithTest [] - (defn --init-- [self val] - (setv self.val val) - None) - - (defn/a --aenter-- [self] - self.val) - - (defn/a --aexit-- [self tyle value traceback] - (setv self.val None))) - - -(defn test-single-with/a [] - (run-coroutine - (fn/a [] - (with/a [t (AsyncWithTest 1)] - (assert (= t 1)))))) - -(defn test-two-with/a [] - (run-coroutine - (fn/a [] - (with/a [t1 (AsyncWithTest 1) - t2 (AsyncWithTest 2)] - (assert (= t1 1)) - (assert (= t2 2)))))) - -(defn test-thrice-with/a [] - (run-coroutine - (fn/a [] - (with/a [t1 (AsyncWithTest 1) - t2 (AsyncWithTest 2) - t3 (AsyncWithTest 3)] - (assert (= t1 1)) - (assert (= t2 2)) - (assert (= t3 3)))))) - -(defn test-quince-with/a [] - (run-coroutine - (fn/a [] - (with/a [t1 (AsyncWithTest 1) - t2 (AsyncWithTest 2) - t3 (AsyncWithTest 3) - _ (AsyncWithTest 4)] - (assert (= t1 1)) - (assert (= t2 2)) - (assert (= t3 3)))))) diff --git a/tests/native_tests/py3_only_tests.hy b/tests/native_tests/py3_only_tests.hy index e9fd24a..4c79ad5 100644 --- a/tests/native_tests/py3_only_tests.hy +++ b/tests/native_tests/py3_only_tests.hy @@ -107,3 +107,101 @@ (assert (= (. (MyClass) member-names) ["__module__" "__qualname__" "method1" "method2"]))) + + +(import [asyncio [get-event-loop sleep]]) + + +(defn test-unpacking-pep448-1star [] + (setv l [1 2 3]) + (setv p [4 5]) + (assert (= ["a" #*l "b" #*p #*l] ["a" 1 2 3 "b" 4 5 1 2 3])) + (assert (= (, "a" #*l "b" #*p #*l) (, "a" 1 2 3 "b" 4 5 1 2 3))) + (assert (= #{"a" #*l "b" #*p #*l} #{"a" "b" 1 2 3 4 5})) + (defn f [&rest args] args) + (assert (= (f "a" #*l "b" #*p #*l) (, "a" 1 2 3 "b" 4 5 1 2 3))) + (assert (= (+ #*l #*p) 15)) + (assert (= (and #*l) 3))) + + +(defn test-unpacking-pep448-2star [] + (setv d1 {"a" 1 "b" 2}) + (setv d2 {"c" 3 "d" 4}) + (assert (= {1 "x" #**d1 #**d2 2 "y"} {"a" 1 "b" 2 "c" 3 "d" 4 1 "x" 2 "y"})) + (defn fun [&optional a b c d e f] [a b c d e f]) + (assert (= (fun #**d1 :e "eee" #**d2) [1 2 3 4 "eee" None]))) + + +(defn run-coroutine [coro] + "Run a coroutine until its done in the default event loop.""" + (.run_until_complete (get-event-loop) (coro))) + + +(defn test-fn/a [] + (assert (= (run-coroutine (fn/a [] (await (sleep 0)) [1 2 3])) + [1 2 3]))) + + +(defn test-defn/a [] + (defn/a coro-test [] + (await (sleep 0)) + [1 2 3]) + (assert (= (run-coroutine coro-test) [1 2 3]))) + + +(defn test-decorated-defn/a [] + (defn decorator [func] (fn/a [] (/ (await (func)) 2))) + + #@(decorator + (defn/a coro-test [] + (await (sleep 0)) + 42)) + (assert (= (run-coroutine coro-test) 21))) + + +(defclass AsyncWithTest [] + (defn --init-- [self val] + (setv self.val val) + None) + + (defn/a --aenter-- [self] + self.val) + + (defn/a --aexit-- [self tyle value traceback] + (setv self.val None))) + + +(defn test-single-with/a [] + (run-coroutine + (fn/a [] + (with/a [t (AsyncWithTest 1)] + (assert (= t 1)))))) + +(defn test-two-with/a [] + (run-coroutine + (fn/a [] + (with/a [t1 (AsyncWithTest 1) + t2 (AsyncWithTest 2)] + (assert (= t1 1)) + (assert (= t2 2)))))) + +(defn test-thrice-with/a [] + (run-coroutine + (fn/a [] + (with/a [t1 (AsyncWithTest 1) + t2 (AsyncWithTest 2) + t3 (AsyncWithTest 3)] + (assert (= t1 1)) + (assert (= t2 2)) + (assert (= t3 3)))))) + +(defn test-quince-with/a [] + (run-coroutine + (fn/a [] + (with/a [t1 (AsyncWithTest 1) + t2 (AsyncWithTest 2) + t3 (AsyncWithTest 3) + _ (AsyncWithTest 4)] + (assert (= t1 1)) + (assert (= t2 2)) + (assert (= t3 3)))))) From ad97042b6b9ceaee494c61815ccedc13ac768d90 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Sun, 17 Mar 2019 18:36:53 -0400 Subject: [PATCH 4/5] Don't test Python 3.4 --- .travis.yml | 1 - conftest.py | 3 +-- hy/_compat.py | 1 - setup.py | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7a10e06..a7adf4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ sudo: false language: python python: - "2.7" - - "3.4" - "3.5" - "3.6" - pypy diff --git a/conftest.py b/conftest.py index 7d84e11..adc035b 100644 --- a/conftest.py +++ b/conftest.py @@ -4,7 +4,7 @@ import importlib import py import pytest import hy -from hy._compat import PY3, PY35, PY36 +from hy._compat import PY3, PY36 NATIVE_TESTS = os.path.join("", "tests", "native_tests", "") @@ -13,7 +13,6 @@ _fspath_pyimport = py.path.local.pyimport def pytest_ignore_collect(path, config): return (("py3_only" in path.basename and not PY3) or - ("py35_only" in path.basename and not PY35) or ("py36_only" in path.basename and not PY36) or None) diff --git a/hy/_compat.py b/hy/_compat.py index 92aa392..ddeb859 100644 --- a/hy/_compat.py +++ b/hy/_compat.py @@ -9,7 +9,6 @@ except ImportError: import sys, keyword, textwrap PY3 = sys.version_info[0] >= 3 -PY35 = sys.version_info >= (3, 5) PY36 = sys.version_info >= (3, 6) PY37 = sys.version_info >= (3, 7) diff --git a/setup.py b/setup.py index 54aba2b..67b2062 100755 --- a/setup.py +++ b/setup.py @@ -79,7 +79,6 @@ setup( "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", From 30fc1425c1bb0d587f86092bc4dc7adbbd054acd Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Sun, 17 Mar 2019 18:40:37 -0400 Subject: [PATCH 5/5] Update docs and README --- NEWS.rst | 4 ++++ docs/language/api.rst | 10 ++-------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index cccb8eb..8fda6eb 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -3,6 +3,10 @@ Unreleased ============================== +Removals +------------------------------ +* Python 3.4 is no longer supported. + New Features ------------------------------ * Format strings with embedded Hy code (e.g., `f"The sum is {(+ x y)}"`) diff --git a/docs/language/api.rst b/docs/language/api.rst index c406679..93993d1 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -1678,20 +1678,14 @@ object (respectively) to provide positional or keywords arguments => (f #* [1 2] #** {"c" 3 "d" 4}) [1, 2, 3, 4] -With Python 3, you can unpack in an assignment list (:pep:`3132`). +With Python 3, unpacking is allowed in more contexts, and you can unpack +more than once in one expression (:pep:`3132`, :pep:`448`). .. code-block:: clj => (setv [a #* b c] [1 2 3 4 5]) => [a b c] [1, [2, 3, 4], 5] - -With Python 3.5 or greater, unpacking is allowed in more contexts than just -function calls, and you can unpack more than once in the same expression -(:pep:`448`). - -.. code-block:: clj - => [#* [1 2] #* [3 4]] [1, 2, 3, 4] => {#** {1 2} #** {3 4}}