From ea2f5f859b47ccd1dec8c031055792e811161b1b Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Thu, 22 Mar 2018 13:27:42 -0700 Subject: [PATCH 1/3] Clean up NEWS --- NEWS.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index c8b5923..4a8d069 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -14,6 +14,7 @@ Other Breaking Changes * Non-shadow unary `=`, `is`, `<`, etc. now evaluate their argument instead of ignoring it. This change increases consistency a bit and makes accidental unary uses easier to notice. +* `hy-repr` uses registered functions instead of methods New Features ------------------------------ @@ -23,10 +24,6 @@ Bug Fixes ------------------------------ * Fix `(return)` so it works correctly to exit a Python 2 generator -Other Breaking Changes ------------------------------ -* `hy-repr` uses registered functions instead of methods - Misc. Improvements ---------------------------- * `hy-repr` supports more standard types From 75af667fa1a891c666b22d04b9f7c6d621428509 Mon Sep 17 00:00:00 2001 From: Simon Gomizelj Date: Sun, 11 Feb 2018 19:21:49 -0500 Subject: [PATCH 2/3] Fix test_hy2py not respecting 'only_py36' --- tests/test_bin.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_bin.py b/tests/test_bin.py index 94411cc..b1e0b25 100644 --- a/tests/test_bin.py +++ b/tests/test_bin.py @@ -12,7 +12,7 @@ import subprocess import pytest -from hy._compat import PY3, PY35, builtins +from hy._compat import PY3, PY35, PY36, builtins from hy.importer import get_bytecode_path @@ -229,9 +229,11 @@ def test_hy2py(): for dirpath, dirnames, filenames in os.walk("tests/native_tests"): for f in filenames: if f.endswith(".hy"): - if f == "py3_only_tests.hy" and not PY3: + if "py3_only" in f and not PY3: continue - if f == "py35_only_tests.hy" and not PY35: + if "py35_only" in f and not PY35: + continue + if "py36_only" in f and not PY36: continue i += 1 output, err = run_cmd("hy2py -s -a " + quote(os.path.join(dirpath, f))) From c663d38e33b1680760607fae591cbb8ffb438bb9 Mon Sep 17 00:00:00 2001 From: Simon Gomizelj Date: Sun, 11 Feb 2018 18:26:29 -0500 Subject: [PATCH 3/3] Add metaclass support, support PEP 3115 and PEP 487 --- NEWS.rst | 2 ++ hy/compiler.py | 5 +++-- tests/compilers/test_ast.py | 7 +++++++ tests/native_tests/py36_only_tests.hy | 8 ++++++++ tests/native_tests/py3_only_tests.hy | 23 +++++++++++++++++++++++ 5 files changed, 43 insertions(+), 2 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 4a8d069..311fd9a 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -19,6 +19,8 @@ Other Breaking Changes New Features ------------------------------ * Added `mangle` and `unmangle` as core functions +* `defclass` in Python 3 now supports specifying metaclasses and other + keyword arguments Bug Fixes ------------------------------ diff --git a/hy/compiler.py b/hy/compiler.py index bd19739..0eb067e 100755 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -2057,11 +2057,12 @@ class HyASTCompiler(object): bases_expr = [] bases = Result() + keywords = [] if expressions: base_list = expressions.pop(0) if not isinstance(base_list, HyList): raise HyTypeError(base_list, "Base classes must be a list.") - bases_expr, bases, _ = self._compile_collect(base_list) + bases_expr, bases, keywords = self._compile_collect(base_list, with_kwargs=PY3) body = Result() @@ -2092,7 +2093,7 @@ class HyASTCompiler(object): expressions, decorator_list=[], name=ast_str(class_name), - keywords=[], + keywords=keywords, starargs=None, kwargs=None, bases=bases_expr, diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index fe1c8a1..af87f8c 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -214,6 +214,13 @@ def test_ast_good_defclass(): can_compile("(defclass a [])") +@pytest.mark.skipif(not PY3, reason="Python 3 supports class keywords") +def test_ast_good_defclass_with_metaclass(): + "Make sure AST can compile valid defclass with keywords" + can_compile("(defclass a [:metaclass b])") + can_compile("(defclass a [:b c])") + + def test_ast_bad_defclass(): "Make sure AST can't compile invalid defclass" cant_compile("(defclass)") diff --git a/tests/native_tests/py36_only_tests.hy b/tests/native_tests/py36_only_tests.hy index c6e4637..6a71fcf 100644 --- a/tests/native_tests/py36_only_tests.hy +++ b/tests/native_tests/py36_only_tests.hy @@ -37,3 +37,11 @@ (setv x (+ x a)) (else (setv x (+ x 50)))) (assert (= x 53))))) + +(defn test-pep-487 [] + (defclass QuestBase [] + [--init-subclass-- (fn [cls swallow &kwargs kwargs] + (setv cls.swallow swallow))]) + + (defclass Quest [QuestBase :swallow "african"]) + (assert (= (. (Quest) swallow) "african"))) diff --git a/tests/native_tests/py3_only_tests.hy b/tests/native_tests/py3_only_tests.hy index d5d67e0..00cd448 100644 --- a/tests/native_tests/py3_only_tests.hy +++ b/tests/native_tests/py3_only_tests.hy @@ -84,3 +84,26 @@ (assert (= (foo :b 20 :a 10 :c 30) (, 10 20 30))))) +(defn test-pep-3115 [] + (defclass member-table [dict] + [--init-- (fn [self] (setv self.member-names [])) + + --setitem-- (fn [self key value] + (if (not-in key self) + (.append self.member-names key)) + (dict.--setitem-- self key value))]) + + (defclass OrderedClass [type] + [--prepare-- (classmethod (fn [metacls name bases] (member-table))) + + --new-- (fn [cls name bases classdict] + (setv result (type.--new-- cls name bases (dict classdict))) + (setv result.member-names classdict.member-names) + result)]) + + (defclass MyClass [:metaclass OrderedClass] + [method1 (fn [self] (pass)) + method2 (fn [self] (pass))]) + + (assert (= (. (MyClass) member-names) + ["__module__" "__qualname__" "method1" "method2"])))