Merge pull request #1505 from vodik/metaclasses

Add metaclass support, support PEP 3115 and PEP 487
This commit is contained in:
Kodi Arfer 2018-03-22 13:37:30 -07:00 committed by GitHub
commit a48f009f1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 49 additions and 9 deletions

View File

@ -14,19 +14,18 @@ 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
------------------------------
* Added `mangle` and `unmangle` as core functions
* `defclass` in Python 3 now supports specifying metaclasses and other
keyword arguments
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

View File

@ -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,

View File

@ -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)")

View File

@ -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")))

View File

@ -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"])))

View File

@ -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)))