diff options
author | Stefan Israelsson Tampe <stefan.itampe@gmail.com> | 2018-03-28 15:18:50 +0200 |
---|---|---|
committer | Stefan Israelsson Tampe <stefan.itampe@gmail.com> | 2018-03-28 15:18:50 +0200 |
commit | fc6e3d19ce60950e7465d018ff9b4d59c035c38c (patch) | |
tree | 78e443255428533c4063956824910040e2f96d62 /modules/language/python/module | |
parent | 944fc50b8b36455b9749ad6b60f3020d466f901c (diff) |
abc
Diffstat (limited to 'modules/language/python/module')
-rw-r--r-- | modules/language/python/module/abc.scm | 167 | ||||
-rw-r--r-- | modules/language/python/module/functools.scm | 73 | ||||
-rw-r--r-- | modules/language/python/module/python.scm | 20 | ||||
-rw-r--r-- | modules/language/python/module/weakref.scm | 5 |
4 files changed, 215 insertions, 50 deletions
diff --git a/modules/language/python/module/abc.scm b/modules/language/python/module/abc.scm new file mode 100644 index 0000000..f0b8442 --- /dev/null +++ b/modules/language/python/module/abc.scm @@ -0,0 +1,167 @@ +(define-module (language python module abc) + #:use-module (language python module weakref) + #:use-module (oop pf-objects) + #:use-module (ice-9 control) + #:use-module (language python for) + #:use-module (language python try) + #:use-module (language python dict) + #:use-module (language python set) + #:use-module (language python string) + #:use-module (language python list) + #:use-module (language python def) + #:use-module (language python bool) + #:use-module (language python exceptions) + #:use-module (language python property) + #:use-module ((language python module python) + #:select (objectmethod classmethod staticmethod type + isinstance super issubclass + getattr sorted dir)) + + #:export (get_cache_token ABC ABCMeta + abstractmethod abstractclassmethod + abstractstaticmethod abstractproperty + get_cache_token)) + +(define-syntax-rule (aif it p x y) (let ((it p)) (if it x y))) + +(define (abstractmethod f) + (set f '__isabstractmethod__ #t) + (objectmethod f)) + + +(define (abstractclassmethod f) + (set f '__isabstractmethod__ #t) + (classmethod f)) + +(define (abstractstaticmethod f) + (set f '__isabstractmethod__ #t) + f) + +(define (abstractproperty f) + (let ((f (property f))) + (set f '__isabstractmethod__ #t) + f)) + +(define-python-class ABCMeta (type) + (define _abc_invalidation_counter 0) + + (define __new__ + (lam (mcls name bases namespace (** kwargs)) + (let ((cls (py-apply (ref (super *class* mcls) '__new__) + mcls name bases namespace (** kwargs))) + + (abstracts + (py-set + (append (list name) + (for ((name value : (py-items namespace))) ((l '())) + (if (ref value '__isabstractmethod__) + (cons name l) + l) + #:final (reverse l)))))) + + (for ((base : bases)) () + (for ((name : (ref base '__abstractmethods__ (py-set '())))) () + (let ((value (getattr cls name None))) + (if (ref value '__isabstractmethod__) + ((ref abstracts 'add) name))))) + + (set cls '__abstractmethods__ (frozenset abstracts)) + (set cls '_abc_registry (WeakSet)) + (set cls '_abc_cache (WeakSet)) + (set cls '_abc_negative_cache (WeakSet)) + (set cls '_abc_negative_cache_version _abc_invalidation_counter) + + cls))) + + (define register + (lambda (cls subclass) + (if (not (isinstance subclass type)) + (raise TypeError "Can only register classes")) + + (if (issubclass subclass cls) + subclass + (if (issubclass cls subclass) + (raise RuntimeError "Refusing to create an inheritance cycle") + (begin + ((ref (ref cls '_abc_registry) 'add) subclass) + (set ABCMeta '_abc_invalidation_counter + (+ (ref ABCMeta '_abc_invalidation_counter) 1)) + subclass))))) + + (define _dump_registry + (lam (cls (= file None)) + (define port (if (eq? file None) #t file)) + (format port "Class: ~a.~a~%" + (ref cls '__module__) (ref cls '__name__)) + (format port "Inv.counter: ~a~%" (ref ABCMeta '_abc_invalidation_counter)) + (for ((name : (sorted (dir cls)))) () + (if (py-startswith name "_abc_") + (let ((value (getattr cls name))) + (format port "~a: ~a~%" name value)))))) + + (define __instancecheck__ + (lambda (cls instance) + (let ((subclass (ref instance '__class__))) + (if (in subclass (ref cls '_abc_cache)) + #t + (let ((subtype (type instance))) + (if (eq? subtype subclass) + (if (and (= (ref cls '_abc_negative_cache_version) + (ref ABCMeta '_abc_invalidation_counter)) + (in subclass (ref cls '_abc_negative_cache))) + #f + ((ref cls '__subclasscheck__) subclass)) + (or ((ref cls '__subclasscheck__) subclass) + ((ref cls '__subclasscheck__) subtype)))))))) + + (define __subclasscheck__ + (lambda (cls subclass) + (let/ec ret + (cond + ((in subclass (ref cls '_abc_cache)) + (ret #t)) + ((< (ref cls '_abc_negative_cache_version) + (ref ABCMeta '_abc_invalidation_counter)) + + (set cls '_abc_negative_cache (WeakSet)) + (set cls '_abc_negative_cache_version + (ref ABCMeta '_abc_invalidation_counter))) + ((in subclass (ref cls '_abc_negative_cache)) + (ret #f))) + + (aif it (ref cls '__subclasshook__) + (let ((ok (it subclass))) + (if (not (eq? ok NotImplemented)) + (begin + (if (bool ok) + ((ref (ref cls '_abc_cache) 'add) subclass) + ((ref (ref cls '_abc_negative_cache) 'add) subclass))) + (ret (bool ok)))) + #f) + + + (if (in cls (ref subclass '__mro__ '())) + (begin + ((ref (ref cls '_abc_cache) 'add) subclass) + (ret #t))) + + (for ((rcls : (ref cls '_abc_registry))) () + (when (issubclass subclass rcls) + ((ref (ref cls '_abc_cache) 'add) subclass) + (ret #t))) + + (aif it (ref cls '__subclasses__) + (for ((scls : (it))) () + (when (issubclass subclass scls) + ((ref (ref cls '_abc_cache) 'add) subclass) + (ret #t))) + #f) + + ((ref (ref cls '_abc_negative_cache) 'add) subclass) + #f)))) + +(define-python-class ABC (#:metaclass ABCMeta)) + + +(define (get_cache_token) + (ref ABCMeta '_abc_invalidation_counter)) diff --git a/modules/language/python/module/functools.scm b/modules/language/python/module/functools.scm index 5f2bd5e..e2a5ce1 100644 --- a/modules/language/python/module/functools.scm +++ b/modules/language/python/module/functools.scm @@ -9,7 +9,8 @@ #:use-module (language python module collections) #:use-module ((language python module python) #:select (iter getattr setattr repr isinstance callable - bool str int)) + bool str int enumerate reversed hasattr + issubclass any)) #:use-module (language python list) #:use-module (language python dict) #:use-module (language python set) @@ -509,13 +510,13 @@ (set wrapper 'cache_clear cache_clear) wrapper)) -#| + ;; single dispatch (define (_c3_merge sequences) (let lp ((result '())) (set! sequences (for ((s : sequences)) ((l '())) (if (bool s) - (cond s l) + (cons s l) l) #:final (reverse l))) (if (bool sequences) @@ -525,7 +526,7 @@ (let ((cand (pylist-ref (car s1) 0))) (let lp3 ((s2 sequences)) (if (pair? s2) - (if (in cand (pylist-slice! (car s2) 1 None None)) + (if (in cand (pylist-slice (car s2) 1 None None)) (lp2 (cdr s1)) (lp3 (cdr s2))) cand))) @@ -543,22 +544,6 @@ (py-list (reverse result))))) (def (_c3_mro cls (= abcs None)) - "Computes the method resolution order using extended C3 linearization. - - If no *abcs* are given, the algorithm works exactly like the built-in C3 - linearization used for method resolution. - - If given, *abcs* is a list of abstract base classes that should be inserted - into the resulting MRO. Unrelated ABCs are ignored and don't end up in the - result. The algorithm inserts ABCs where their functionality is introduced, - i.e. issubclass(cls, abc) returns True for the class itself but returns - False for all its direct base classes. Implicit ABCs for a given class - (either registered or inferred from the presence of a special method like - __len__) are inserted directly after the last ABC explicitly listed in the - MRO of said class. If two implicit ABCs end up next to each other in the - resulting MRO, their ordering depends on the order of types in *abcs*. - - " (define bases (ref cls '__bases__ '())) (define boundary (for ((i base : (enumerate (reversed bases)))) () @@ -576,7 +561,7 @@ (not (any (map (lambda (b) (issubclass b base)) bases)))) (pylist-append! abstract_bases base))) - (for ((base : abstract_bases)) + (for ((base : abstract_bases)) () (pylist-remove! abcs base)) (let* ((f (lambda (bases) @@ -594,7 +579,7 @@ abstract_c3_mros other_c3_mros (py-list explicit_bases) - (py-lit abstract_bases) + (py-list abstract_bases) (py-list other_bases))))) (define (_compose_mro cls types) @@ -616,7 +601,7 @@ (if (is_related n) (cons n l) l) - #final (reverse l))) + #:final (reverse l))) ;; Remove entries which are strict bases of other entries (they will end up ;; in the MRO anyway. @@ -631,7 +616,7 @@ (if (is_strict_base n) (cons n l) l) - #final (reverse l))) + #:final (reverse l))) ; Subclasses of the ABCs in *types* which are also implemented by ; *cls* can be used to stabilize ABC ordering. @@ -640,24 +625,24 @@ (for ((typ : types)) () (let ((found (py-list))) - (for ((sub in ((ref typ '__subclasses__ (lambda () '()))))) () + (for ((sub : ((ref typ '__subclasses__ (lambda () '()))))) () (if (and (not (in sub bases)) (issubclass cls sub)) - (pylist-append found - (for ((s in (ref sub '__mro__ '()))) - ((l '())) - (if (in s type_set) - (cons s l) - l) - #:final (py-list (reverse l)))))) - (f (not (bool found)) - (begin - (pylist-append! mro typ) - (pylist-sort! found #:key len #:reverse #t) - (for ((sub : found)) () - (for ((subcls : sub)) () - (if (not (in subcls mro)) - (pylist-append! mro subcls)))))))) + (pylist-append! found + (for ((s : (ref sub '__mro__ '()))) + ((l '())) + (if (in s type_set) + (cons s l) + l) + #:final (py-list (reverse l)))))) + (if (not (bool found)) + (begin + (pylist-append! mro typ) + (pylist-sort! found #:key len #:reverse #t) + (for ((sub : found)) () + (for ((subcls : sub)) () + (if (not (in subcls mro)) + (pylist-append! mro subcls)))))))) (_c3_mro cls #:abcs mro)) @@ -692,6 +677,8 @@ (py-get registry match)) +(define (get_cache_token) #t) + (define (singledispatch func) "Single-dispatch generic function decorator. @@ -718,7 +705,7 @@ (let ((current_token (get_cache_token))) (if (not (equal? cache_token current_token)) (begin - (pylist-clear! dispatch_cache) + (py-clear dispatch_cache) (set! cache_token current_token))))) (let ((impl (try @@ -742,7 +729,7 @@ (if (and (eq? cache_token None) (ref cls '__abstractmethods__)) (set! cache_token (get_cache_token))) - (pylist-clear! dispatch_cache) + (py-clear dispatch_cache) func))) (def (wrapper (* args) (** kw)) @@ -757,4 +744,4 @@ (update_wrapper wrapper func) wrapper) -|# + diff --git a/modules/language/python/module/python.scm b/modules/language/python/module/python.scm index 2b1e368..99db1c2 100644 --- a/modules/language/python/module/python.scm +++ b/modules/language/python/module/python.scm @@ -4,7 +4,8 @@ #:use-module (ice-9 readline) #:use-module ((oop pf-objects) #:select (<p> <property> class-method static-method ref - py-super-mac type object pylist-ref)) + py-super-mac type object pylist-ref define-python-class + object-method)) #:use-module (language python exceptions ) #:use-module ((language python module string ) #:select ()) #:use-module (language python def ) @@ -42,11 +43,12 @@ #:export (print repr complex float int str set all any bin callable reversed - chr classmethod staticmethod + chr classmethod staticmethod objectmethod divmod enumerate filter open getattr hasattr setattr hex isinstance issubclass iter map sum id input oct ord pow super - sorted zip)) + sorted zip + ClassMethod StaticMethod Funcobj)) (define-syntax-rule (aif it p x y) (let ((it p)) (if it x y))) @@ -87,6 +89,7 @@ (define chr integer->char) +(define objectmethod object-method) (define classmethod class-method) (define staticmethod static-method) @@ -121,8 +124,10 @@ (define-method (issubclass (sub <p>) (cls <p>)) (aif it (ref cls '__subclasscheck__) - (it sub) - (is-a? (ref sub '__goops__) (ref cls '__goops__)))) + (it cls sub) + (if (eq? sub cls) + #t + (is-a? (ref sub '__goops__) (ref cls '__goops__))))) (define-method (isinstance (o <p>) (cl <p>)) (aif it (ref cl '__instancecheck__) @@ -300,6 +305,11 @@ (setvbuf port 'block buffering))) port)) + + +(define-python-class ClassMethod ()) +(define-python-class StaticMethod ()) +(define-python-class Funcobj ()) diff --git a/modules/language/python/module/weakref.scm b/modules/language/python/module/weakref.scm index 61f845a..bd7b7dd 100644 --- a/modules/language/python/module/weakref.scm +++ b/modules/language/python/module/weakref.scm @@ -1,10 +1,11 @@ (define-module (language python module weakref) #:use-module (language python dict) - #:export (WeakKeyDictionary WeakValueDictionary)) + #:use-module (language python set) + #:export (WeakKeyDictionary WeakValueDictionary WeakSet)) (define WeakKeyDictionary weak-key-dict) (define WeakValueDictionary weak-value-dict) - +(define WeakSet weak-set) |