From a1154c064b60e39dfbddae0ee9c373691c91eb12 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Dec 2021 21:00:40 -0800 Subject: [PATCH 1/3] src/sage/features/cython.py: New --- src/sage/features/cython.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/sage/features/cython.py diff --git a/src/sage/features/cython.py b/src/sage/features/cython.py new file mode 100644 index 00000000000..86a0b79bc8f --- /dev/null +++ b/src/sage/features/cython.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +r""" +Features for testing the presence of ``cython`` +""" + +from . import CythonFeature + + +class sage__misc__cython(CythonFeature): + r""" + A :class:`~sage.features.Feature` which describes whether :mod:`sage.misc.cython` + is available and functional. + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.cython import sage__misc__cython + sage: isinstance(sage__misc__cython(), CythonFeature) + True + """ + # It suffices to use a trivial CythonFeature because CythonFeature + # is implemented via sage.misc.cython. + CythonFeature.__init__(self, "sage.misc.cython", test_code="") + + +def all_features(): + return [sage__misc__cython()] From 9356cb926b5593a6a53bbac2ec97acdfde75ed62 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 15 Dec 2021 21:32:28 -0800 Subject: [PATCH 2/3] src/sage/misc/inherit_comparison.pyx: Mark doctests using cython # optional - sage.misc.cython --- src/sage/misc/inherit_comparison.pyx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/misc/inherit_comparison.pyx b/src/sage/misc/inherit_comparison.pyx index fc360533cad..15cdbdab547 100644 --- a/src/sage/misc/inherit_comparison.pyx +++ b/src/sage/misc/inherit_comparison.pyx @@ -51,7 +51,8 @@ cdef class InheritComparisonMetaclass(type): EXAMPLES:: - sage: cython(''' + sage: cython( # optional - sage.misc.cython + ....: ''' ....: from sage.misc.inherit_comparison cimport InheritComparisonMetaclass ....: ....: cdef class Base(object): @@ -70,11 +71,11 @@ cdef class InheritComparisonMetaclass(type): ....: def __hash__(self): ....: return 1 ....: ''') - sage: a = Derived() - sage: a == a + sage: a = Derived() # optional - sage.misc.cython + sage: a == a # optional - sage.misc.cython True - sage: b = DerivedWithRichcmp() - sage: b == b + sage: b = DerivedWithRichcmp() # optional - sage.misc.cython + sage: b == b # optional - sage.misc.cython Calling Base.__richcmp__ True """ From 1440273c80c8fd6da5e97a62bc0be0af6881b4b3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 8 May 2022 21:42:30 -0700 Subject: [PATCH 3/3] Mark tests using runtime Cython # optional - sage.misc.cython --- src/sage/arith/long.pxd | 4 +- src/sage/cpython/cython_metaclass.pyx | 4 +- src/sage/cpython/getattr.pyx | 12 +- src/sage/cpython/string.pyx | 2 +- src/sage/cpython/wrapperdescr.pxd | 2 +- src/sage/docs/instancedoc.pyx | 2 +- src/sage/env.py | 2 +- src/sage/ext/memory_allocator.pxd | 6 +- src/sage/ext/memory_allocator.pyx | 2 + src/sage/features/cython.py | 1 + src/sage/graphs/connectivity.pyx | 4 +- .../graph_decompositions/fast_digraph.pyx | 10 +- src/sage/misc/cachefunc.pyx | 116 +++++++++--------- src/sage/misc/cython.py | 7 +- src/sage/misc/lazy_attribute.pyx | 6 +- src/sage/misc/nested_class.pyx | 12 +- src/sage/misc/sagedoc.py | 4 +- src/sage/misc/sageinspect.py | 28 ++--- src/sage/misc/superseded.py | 6 +- src/sage/parallel/decorate.py | 4 +- src/sage/rings/integer_fake.pxd | 2 +- .../polynomial/ore_polynomial_element.pyx | 4 +- src/sage/rings/tate_algebra_ideal.pyx | 4 +- src/sage/structure/element.pyx | 90 +++++++------- src/sage/structure/factory.pyx | 16 +-- src/sage/symbolic/pynac.pxi | 2 +- 26 files changed, 178 insertions(+), 174 deletions(-) diff --git a/src/sage/arith/long.pxd b/src/sage/arith/long.pxd index c1034f5629f..b0c80f61480 100644 --- a/src/sage/arith/long.pxd +++ b/src/sage/arith/long.pxd @@ -113,7 +113,7 @@ cdef inline bint integer_check_long(x, long* value, int* err) except -1: We create a pure Python wrapper of this function:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.arith.long cimport * ....: from sage.rings.integer cimport smallInteger ....: def check_long(x): @@ -273,7 +273,7 @@ cdef inline bint is_small_python_int(obj): EXAMPLES:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.arith.long cimport is_small_python_int ....: def is_small_wrapper(x): ....: return is_small_python_int(x) diff --git a/src/sage/cpython/cython_metaclass.pyx b/src/sage/cpython/cython_metaclass.pyx index a5197e6734d..e8844ce6572 100644 --- a/src/sage/cpython/cython_metaclass.pyx +++ b/src/sage/cpython/cython_metaclass.pyx @@ -61,7 +61,7 @@ In Python, this would be ``meta.__init__(cls, name, bases, dict)``. EXAMPLES:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: cimport sage.cpython.cython_metaclass ....: cdef class MyCustomType(object): ....: def __getmetaclass__(_): @@ -98,7 +98,7 @@ TESTS: Check that a proper exception is raised if ``__getmetaclass__`` returns a non-type:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: cimport sage.cpython.cython_metaclass ....: cdef class MyCustomType(object): ....: def __getmetaclass__(_): diff --git a/src/sage/cpython/getattr.pyx b/src/sage/cpython/getattr.pyx index 04203a483fc..88a313878b7 100644 --- a/src/sage/cpython/getattr.pyx +++ b/src/sage/cpython/getattr.pyx @@ -406,13 +406,13 @@ def dir_with_other_class(self, *cls): Check that objects without dicts are well handled:: - sage: cython("cdef class A:\n cdef public int a") - sage: cython("cdef class B:\n cdef public int b") - sage: x = A() - sage: x.a = 1 - sage: hasattr(x,'__dict__') + sage: cython("cdef class A:\n cdef public int a") # optional - sage.misc.cython + sage: cython("cdef class B:\n cdef public int b") # optional - sage.misc.cython + sage: x = A() # optional - sage.misc.cython + sage: x.a = 1 # optional - sage.misc.cython + sage: hasattr(x,'__dict__') # optional - sage.misc.cython False - sage: dir_with_other_class(x, B) + sage: dir_with_other_class(x, B) # optional - sage.misc.cython [..., 'a', 'b'] TESTS: diff --git a/src/sage/cpython/string.pyx b/src/sage/cpython/string.pyx index b855f99a1e6..2bd86dbfcf6 100644 --- a/src/sage/cpython/string.pyx +++ b/src/sage/cpython/string.pyx @@ -6,7 +6,7 @@ TESTS: Check that this can be used outside of Sage (see :trac:`25549`):: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.cpython.string cimport char_to_str ....: print(char_to_str("hello world!")) ....: ''') diff --git a/src/sage/cpython/wrapperdescr.pxd b/src/sage/cpython/wrapperdescr.pxd index db8dff909ea..ba58443111f 100644 --- a/src/sage/cpython/wrapperdescr.pxd +++ b/src/sage/cpython/wrapperdescr.pxd @@ -39,7 +39,7 @@ cdef inline wrapperbase* get_slotdef(wrapper_descriptor slotwrapper) except NULL TESTS:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.cpython.wrapperdescr cimport get_slotdef ....: from cpython.long cimport PyLong_FromVoidPtr ....: def py_get_slotdef(slotwrapper): diff --git a/src/sage/docs/instancedoc.pyx b/src/sage/docs/instancedoc.pyx index 86f796600de..edfa3e876f3 100644 --- a/src/sage/docs/instancedoc.pyx +++ b/src/sage/docs/instancedoc.pyx @@ -36,7 +36,7 @@ EXAMPLES:: For a Cython ``cdef class``, a decorator cannot be used. Instead, call :func:`instancedoc` as a function after defining the class:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.misc.instancedoc import instancedoc ....: cdef class Y: ....: "Class docstring" diff --git a/src/sage/env.py b/src/sage/env.py index 6421de5e39a..5db78c76434 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -440,7 +440,7 @@ def cython_aliases(required_modules=None, We can use ``cython.parallel`` regardless of whether OpenMP is supported. This will run in parallel, if OpenMP is supported:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: #distutils: extra_compile_args = OPENMP_CFLAGS ....: #distutils: extra_link_args = OPENMP_CFLAGS ....: from cython.parallel import prange diff --git a/src/sage/ext/memory_allocator.pxd b/src/sage/ext/memory_allocator.pxd index d7c287b819a..b612df2110c 100644 --- a/src/sage/ext/memory_allocator.pxd +++ b/src/sage/ext/memory_allocator.pxd @@ -56,7 +56,7 @@ cdef class MemoryAllocator: TESTS:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.ext.memory_allocator cimport MemoryAllocator ....: cdef MemoryAllocator mem = MemoryAllocator() ....: cdef void* ptr @@ -85,7 +85,7 @@ cdef class MemoryAllocator: TESTS:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.ext.memory_allocator cimport MemoryAllocator ....: def foo(): ....: cdef MemoryAllocator mem = MemoryAllocator() @@ -120,7 +120,7 @@ cdef class MemoryAllocator: TESTS:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.ext.memory_allocator cimport MemoryAllocator ....: def foo(): ....: cdef MemoryAllocator mem = MemoryAllocator() diff --git a/src/sage/ext/memory_allocator.pyx b/src/sage/ext/memory_allocator.pyx index 819875efd65..cae760c9752 100644 --- a/src/sage/ext/memory_allocator.pyx +++ b/src/sage/ext/memory_allocator.pyx @@ -1,3 +1,5 @@ +# sage.doctest: optional - sage.misc.cython + from cysignals.memory cimport * from sage.misc.superseded import deprecation diff --git a/src/sage/features/cython.py b/src/sage/features/cython.py index 86a0b79bc8f..f537843f4f4 100644 --- a/src/sage/features/cython.py +++ b/src/sage/features/cython.py @@ -15,6 +15,7 @@ def __init__(self): r""" TESTS:: + sage: from sage.features import CythonFeature sage: from sage.features.cython import sage__misc__cython sage: isinstance(sage__misc__cython(), CythonFeature) True diff --git a/src/sage/graphs/connectivity.pyx b/src/sage/graphs/connectivity.pyx index df6af77ce0d..0d2140df36d 100644 --- a/src/sage/graphs/connectivity.pyx +++ b/src/sage/graphs/connectivity.pyx @@ -2712,7 +2712,7 @@ cdef class _Component: ....: 'comp.add_edge(3)', ....: 'comp.finish_tric_or_poly(4)', ....: 'print(comp)'] - sage: cython(os.linesep.join(cython_code)) + sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython Polygon: 2 3 4 """ self.mem = MemoryAllocator() @@ -2759,7 +2759,7 @@ cdef class _Component: ....: 'comp.add_edge(3)', ....: 'comp.finish_tric_or_poly(4)', ....: 'print(comp)'] - sage: cython(os.linesep.join(cython_code)) + sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython Polygon: 2 3 4 """ if self.component_type == 0: diff --git a/src/sage/graphs/graph_decompositions/fast_digraph.pyx b/src/sage/graphs/graph_decompositions/fast_digraph.pyx index 63e19e2e811..8cec1431c2f 100644 --- a/src/sage/graphs/graph_decompositions/fast_digraph.pyx +++ b/src/sage/graphs/graph_decompositions/fast_digraph.pyx @@ -42,7 +42,7 @@ cdef class FastDigraph: ....: 'cdef FastDigraph F = FastDigraph(G)', ....: 'cdef int i', ....: 'print([F.degree[i] for i in range(F.n)])'] - sage: cython(os.linesep.join(cython_code)) + sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython [1, 2, 1] """ if D.order() > 8*sizeof(int): @@ -99,7 +99,7 @@ cdef class FastDigraph: ....: 'from sage.graphs.graph import Graph', ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport FastDigraph', ....: 'FastDigraph(Graph([(0, 1), (1, 2)])).print_adjacency_matrix()'] - sage: cython(os.linesep.join(cython_code)) + sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython 010 101 010 @@ -129,7 +129,7 @@ cdef inline int compute_out_neighborhood_cardinality(FastDigraph g, int S): ....: 'cdef FastDigraph F = FastDigraph(Graph([(0, 1), (1, 2)]))', ....: 'cdef int i', ....: 'print([compute_out_neighborhood_cardinality(F, 1<> 1) & 0x55555555) @@ -199,7 +199,7 @@ cdef inline int slow_popcount32(int i): ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport slow_popcount32', ....: 'cdef int i', ....: 'print(all(popcount32(i) == slow_popcount32(i) for i in range(16)))'] - sage: cython(os.linesep.join(cython_code)) + sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython True """ # Slow popcount for 32bits integers diff --git a/src/sage/misc/cachefunc.pyx b/src/sage/misc/cachefunc.pyx index c74d9d83fd0..1656b9cc7a3 100644 --- a/src/sage/misc/cachefunc.pyx +++ b/src/sage/misc/cachefunc.pyx @@ -46,15 +46,15 @@ the name that the wrapped method or function should have, since otherwise the name of the original function would be used:: - sage: cython('''cpdef test_funct(x): return -x''') - sage: wrapped_funct = cached_function(test_funct, name='wrapped_funct') - sage: wrapped_funct + sage: cython('''cpdef test_funct(x): return -x''') # optional - sage.misc.cython + sage: wrapped_funct = cached_function(test_funct, name='wrapped_funct') # optional - sage.misc.cython + sage: wrapped_funct # optional - sage.misc.cython Cached version of - sage: wrapped_funct.__name__ + sage: wrapped_funct.__name__ # optional - sage.misc.cython 'wrapped_funct' - sage: wrapped_funct(5) + sage: wrapped_funct(5) # optional - sage.misc.cython -5 - sage: wrapped_funct(5) is wrapped_funct(5) + sage: wrapped_funct(5) is wrapped_funct(5) # optional - sage.misc.cython True We can proceed similarly for cached methods of Cython classes, @@ -77,21 +77,21 @@ approach is still needed for cpdef methods:: ....: ' "Some doc for direct method"', ....: ' return 2*x', ....: ' wrapped_method = cached_method(test_meth,name="wrapped_method")'] - sage: cython(os.linesep.join(cython_code)) - sage: O = MyClass() - sage: O.direct_method + sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: O = MyClass() # optional - sage.misc.cython + sage: O.direct_method # optional - sage.misc.cython Cached version of - sage: O.wrapped_method + sage: O.wrapped_method # optional - sage.misc.cython Cached version of - sage: O.wrapped_method.__name__ + sage: O.wrapped_method.__name__ # optional - sage.misc.cython 'wrapped_method' - sage: O.wrapped_method(5) + sage: O.wrapped_method(5) # optional - sage.misc.cython -5 - sage: O.wrapped_method(5) is O.wrapped_method(5) + sage: O.wrapped_method(5) is O.wrapped_method(5) # optional - sage.misc.cython True - sage: O.direct_method(5) + sage: O.direct_method(5) # optional - sage.misc.cython 10 - sage: O.direct_method(5) is O.direct_method(5) + sage: O.direct_method(5) is O.direct_method(5) # optional - sage.misc.cython True In some cases, one would only want to keep the result in cache as long @@ -126,8 +126,8 @@ category (previously, the cache would have been broken):: ....: " @cached_method", ....: " def invert(self, x):", ....: " return -x"] - sage: cython('\n'.join(cython_code)) - sage: C = MyCategory() + sage: cython('\n'.join(cython_code)) # optional - sage.misc.cython + sage: C = MyCategory() # optional - sage.misc.cython In order to keep the memory footprint of elements small, it was decided to not support the same freedom of using cached methods @@ -178,88 +178,88 @@ hardly by used. ....: "from sage.structure.parent cimport Parent", ....: "cdef class MyParent(Parent):", ....: " Element = MyElement"] - sage: cython('\n'.join(cython_code)) - sage: P = MyParent(category=C) - sage: ebroken = MyBrokenElement(P,5) - sage: e = MyElement(P,5) + sage: cython('\n'.join(cython_code)) # optional - sage.misc.cython + sage: P = MyParent(category=C) # optional - sage.misc.cython + sage: ebroken = MyBrokenElement(P, 5) # optional - sage.misc.cython + sage: e = MyElement(P, 5) # optional - sage.misc.cython The cached methods inherited by the parent works:: - sage: P.one() + sage: P.one() # optional - sage.misc.cython <1> - sage: P.one() is P.one() + sage: P.one() is P.one() # optional - sage.misc.cython True - sage: P.invert(e) + sage: P.invert(e) # optional - sage.misc.cython <-5> - sage: P.invert(e) is P.invert(e) + sage: P.invert(e) is P.invert(e) # optional - sage.misc.cython True The cached methods inherited by ``MyElement`` works:: - sage: e.element_cache_test() + sage: e.element_cache_test() # optional - sage.misc.cython <-5> - sage: e.element_cache_test() is e.element_cache_test() + sage: e.element_cache_test() is e.element_cache_test() # optional - sage.misc.cython True - sage: e.element_via_parent_test() + sage: e.element_via_parent_test() # optional - sage.misc.cython <-5> - sage: e.element_via_parent_test() is e.element_via_parent_test() + sage: e.element_via_parent_test() is e.element_via_parent_test() # optional - sage.misc.cython True The other element class can only inherit a ``cached_in_parent_method``, since the cache is stored in the parent. In fact, equal elements share the cache, even if they are of different types:: - sage: e == ebroken + sage: e == ebroken # optional - sage.misc.cython True - sage: type(e) == type(ebroken) + sage: type(e) == type(ebroken) # optional - sage.misc.cython False - sage: ebroken.element_via_parent_test() is e.element_via_parent_test() + sage: ebroken.element_via_parent_test() is e.element_via_parent_test() # optional - sage.misc.cython True However, the cache of the other inherited method breaks, although the method as such works:: - sage: ebroken.element_cache_test() + sage: ebroken.element_cache_test() # optional - sage.misc.cython <-5> - sage: ebroken.element_cache_test() is ebroken.element_cache_test() + sage: ebroken.element_cache_test() is ebroken.element_cache_test() # optional - sage.misc.cython False The cache can be emptied:: - sage: a = test_pfunc(5) - sage: test_pfunc.clear_cache() - sage: a is test_pfunc(5) + sage: a = test_pfunc(5) # optional - sage.misc.cython + sage: test_pfunc.clear_cache() # optional - sage.misc.cython + sage: a is test_pfunc(5) # optional - sage.misc.cython False - sage: a = P.one() - sage: P.one.clear_cache() - sage: a is P.one() + sage: a = P.one() # optional - sage.misc.cython + sage: P.one.clear_cache() # optional - sage.misc.cython + sage: a is P.one() # optional - sage.misc.cython False Since ``e`` and ``ebroken`` share the cache, when we empty it for one element it is empty for the other as well:: - sage: b = ebroken.element_via_parent_test() - sage: e.element_via_parent_test.clear_cache() - sage: b is ebroken.element_via_parent_test() + sage: b = ebroken.element_via_parent_test() # optional - sage.misc.cython + sage: e.element_via_parent_test.clear_cache() # optional - sage.misc.cython + sage: b is ebroken.element_via_parent_test() # optional - sage.misc.cython False Introspection works:: sage: from sage.misc.edit_module import file_and_line sage: from sage.misc.sageinspect import sage_getdoc, sage_getfile, sage_getsource - sage: print(sage_getdoc(test_pfunc)) + sage: print(sage_getdoc(test_pfunc)) # optional - sage.misc.cython Some documentation - sage: print(sage_getdoc(O.wrapped_method)) + sage: print(sage_getdoc(O.wrapped_method)) # optional - sage.misc.cython some doc for a wrapped cython method - sage: print(sage_getdoc(O.direct_method)) + sage: print(sage_getdoc(O.direct_method)) # optional - sage.misc.cython Some doc for direct method - sage: print(sage_getsource(O.wrapped_method)) + sage: print(sage_getsource(O.wrapped_method)) # optional - sage.misc.cython cpdef test_meth(self,x): "some doc for a wrapped cython method" return -x - sage: print(sage_getsource(O.direct_method)) + sage: print(sage_getsource(O.direct_method)) # optional - sage.misc.cython def direct_method(self, x): "Some doc for direct method" return 2*x @@ -301,11 +301,11 @@ latter is easy:: ....: " @cached_method", ....: " def f(self, a,b):", ....: " return a*b"] - sage: cython(os.linesep.join(cython_code)) - sage: P = MyClass() - sage: P.f(2,3) + sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: P = MyClass() # optional - sage.misc.cython + sage: P.f(2, 3) # optional - sage.misc.cython 6 - sage: P.f(2,3) is P.f(2,3) + sage: P.f(2, 3) is P.f(2, 3) # optional - sage.misc.cython True Providing attribute access is a bit more tricky, since it is needed that @@ -330,19 +330,19 @@ enough in the following example:: ....: " @cached_method", ....: " def f(self, a,b):", ....: " return a+b"] - sage: cython(os.linesep.join(cython_code)) - sage: Q = MyOtherClass() - sage: Q.f(2,3) + sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: Q = MyOtherClass() # optional - sage.misc.cython + sage: Q.f(2, 3) # optional - sage.misc.cython 5 - sage: Q.f(2,3) is Q.f(2,3) + sage: Q.f(2, 3) is Q.f(2, 3) # optional - sage.misc.cython True Note that supporting attribute access is somehow faster than the easier method:: - sage: timeit("a = P.f(2,3)") # random + sage: timeit("a = P.f(2,3)") # random # optional - sage.misc.cython 625 loops, best of 3: 1.3 µs per loop - sage: timeit("a = Q.f(2,3)") # random + sage: timeit("a = Q.f(2,3)") # random # optional - sage.misc.cython 625 loops, best of 3: 931 ns per loop Some immutable objects (such as `p`-adic numbers) cannot implement a diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 7eadbd39cc0..53b870649c9 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.misc.cython """ Cython support functions @@ -170,7 +171,7 @@ def cython(filename, verbose=0, compile_message=False, sage: os.chdir(d) sage: with open("helper.pxd", 'w') as f: ....: _ = f.write("cdef inline int the_answer(): return 42") - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from helper cimport the_answer ....: print(the_answer()) ....: ''') @@ -186,7 +187,7 @@ def cython(filename, verbose=0, compile_message=False, ....: ''' sage: cython(code, verbose=-1) sage: cython(code, verbose=0) - warning: ...:4:4: Unreachable code + warning: ...:4:4: Unreachable code... sage: cython("foo = bar\n") Traceback (most recent call last): @@ -207,7 +208,7 @@ def cython(filename, verbose=0, compile_message=False, As of :trac:`29139` the default is ``cdivision=True``:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: cdef size_t foo = 3/2 ....: ''') """ diff --git a/src/sage/misc/lazy_attribute.pyx b/src/sage/misc/lazy_attribute.pyx index c6e7b5110bb..d0d7612c683 100644 --- a/src/sage/misc/lazy_attribute.pyx +++ b/src/sage/misc/lazy_attribute.pyx @@ -354,9 +354,9 @@ class lazy_attribute(_lazy_attribute): ....: "cdef class MyElement(Element): pass", ....: "cdef class MyParent(Parent):", ....: " Element = MyElement"] - sage: cython('\n'.join(cython_code)) - sage: P = MyParent(category=Rings()) - sage: P.element_class # indirect doctest + sage: cython('\n'.join(cython_code)) # optional - sage.misc.cython + sage: P = MyParent(category=Rings()) # optional - sage.misc.cython + sage: P.element_class # indirect doctest # optional - sage.misc.cython .. rubric:: About descriptor specifications diff --git a/src/sage/misc/nested_class.pyx b/src/sage/misc/nested_class.pyx index d27ec59923b..2d6feeb2284 100644 --- a/src/sage/misc/nested_class.pyx +++ b/src/sage/misc/nested_class.pyx @@ -162,18 +162,18 @@ cpdef modify_for_nested_pickle(cls, str name_prefix, module, first_run=True): ....: " class B2:", ....: " class C2: pass"] sage: import os - sage: cython(os.linesep.join(cython_code)) + sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython Before :trac:`9107`, the name of ``A1.B1.C1`` would have been wrong:: - sage: A1.B1.C1.__name__ + sage: A1.B1.C1.__name__ # optional - sage.misc.cython 'A1.B1.C1' - sage: A1.B2.C2.__name__ + sage: A1.B2.C2.__name__ # optional - sage.misc.cython 'A1.B2.C2' - sage: A_module = sys.modules[A1.__module__] - sage: getattr(A_module, 'A1.B1.C1', 'Not found').__name__ + sage: A_module = sys.modules[A1.__module__] # optional - sage.misc.cython + sage: getattr(A_module, 'A1.B1.C1', 'Not found').__name__ # optional - sage.misc.cython 'A1.B1.C1' - sage: getattr(A_module, 'A1.B2.C2', 'Not found').__name__ + sage: getattr(A_module, 'A1.B2.C2', 'Not found').__name__ # optional - sage.misc.cython 'A1.B2.C2' """ diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index 37fd5d8b6e6..24f30291a02 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -650,9 +650,9 @@ def format(s, embedded=False): ....: " `x \\geq y`", ....: " '''", ....: " return -x"] - sage: cython('\n'.join(cython_code)) + sage: cython('\n'.join(cython_code)) # optional - sage.misc.cython sage: from sage.misc.sageinspect import sage_getdoc - sage: print(sage_getdoc(testfunc)) + sage: print(sage_getdoc(testfunc)) # optional - sage.misc.cython This is a doc string with raw latex diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 87df80ef514..7e9f1607ae5 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -105,10 +105,10 @@ By :trac:`9976` and :trac:`14017`, introspection also works for interactively defined Cython code, and with rather tricky argument lines:: - sage: cython('def foo(unsigned int x=1, a=\')"\', b={not (2+1==3):\'bar\'}, *args, **kwds): return') - sage: print(sage_getsource(foo)) + sage: cython('def foo(unsigned int x=1, a=\')"\', b={not (2+1==3):\'bar\'}, *args, **kwds): return') # optional - sage.misc.cython + sage: print(sage_getsource(foo)) # optional - sage.misc.cython def foo(unsigned int x=1, a=')"', b={not (2+1==3):'bar'}, *args, **kwds): return - sage: sage_getargspec(foo) + sage: sage_getargspec(foo) # optional - sage.misc.cython ArgSpec(args=['x', 'a', 'b'], varargs='args', keywords='kwds', defaults=(1, ')"', {False: 'bar'})) """ @@ -253,9 +253,9 @@ def _extract_embedded_position(docstring): The following has been fixed in :trac:`13916`:: - sage: cython('''cpdef test_funct(x,y): return''') - sage: func_doc = inspect.getdoc(test_funct) - sage: with open(_extract_embedded_position(func_doc)[1]) as f: + sage: cython('''cpdef test_funct(x,y): return''') # optional - sage.misc.cython + sage: func_doc = inspect.getdoc(test_funct) # optional - sage.misc.cython + sage: with open(_extract_embedded_position(func_doc)[1]) as f: # optional - sage.misc.cython ....: print(f.read()) cpdef test_funct(x,y): return @@ -266,10 +266,10 @@ def _extract_embedded_position(docstring): sage: from sage.env import DOT_SAGE sage: from sage.misc.sage_ostools import restore_cwd - sage: with restore_cwd(DOT_SAGE): + sage: with restore_cwd(DOT_SAGE): # optional - sage.misc.cython ....: cython('''cpdef test_funct(x,y): return''') - sage: func_doc = inspect.getdoc(test_funct) - sage: with open(_extract_embedded_position(func_doc)[1]) as f: + sage: func_doc = inspect.getdoc(test_funct) # optional - sage.misc.cython + sage: with open(_extract_embedded_position(func_doc)[1]) as f: # optional - sage.misc.cython ....: print(f.read()) cpdef test_funct(x,y): return @@ -1365,7 +1365,7 @@ def sage_getfile(obj): A problem fixed in :trac:`16309`:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: class Bar: pass ....: cdef class Foo: pass ....: ''') @@ -1541,7 +1541,7 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return The following was fixed in :trac:`16309`:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: class Foo: ....: @staticmethod ....: def join(categories, bint as_list = False, tuple ignore_axioms=(), tuple axioms=()): pass @@ -2125,7 +2125,7 @@ class ParentMethods: The following was fixed in :trac:`16309`:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: class A: ....: def __init__(self): ....: "some init doc" @@ -2274,8 +2274,8 @@ def sage_getsourcelines(obj): TESTS:: - sage: cython('''cpdef test_funct(x,y): return''') - sage: sage_getsourcelines(test_funct) + sage: cython('''cpdef test_funct(x,y): return''') # optional - sage.misc.cython + sage: sage_getsourcelines(test_funct) # optional - sage.misc.cython (['cpdef test_funct(x,y): return\n'], 1) The following tests that an instance of ``functools.partial`` is correctly diff --git a/src/sage/misc/superseded.py b/src/sage/misc/superseded.py index 0d20e025a23..4da7306432a 100644 --- a/src/sage/misc/superseded.py +++ b/src/sage/misc/superseded.py @@ -108,7 +108,7 @@ def deprecation_cython(trac_number, message, stacklevel=3): with the same callsite reference as `deprecation` in a python function, whereas `deprecation` in a cython function does not:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.misc.superseded import deprecation_cython, deprecation ....: def foo1(): ....: deprecation_cython(100,"boo") @@ -399,14 +399,14 @@ def __name__(self): sage: cls().old_meth.__name__ 'old_meth' - sage: cython('\n'.join([ + sage: cython('\n'.join([ # optional - sage.misc.cython ....: r"from sage.misc.superseded import deprecated_function_alias", ....: r"cdef class cython_cls(object):", ....: r" def new_cython_meth(self):", ....: r" return 1", ....: r" old_cython_meth = deprecated_function_alias(13109, new_cython_meth)" ....: ])) - sage: cython_cls().old_cython_meth.__name__ + sage: cython_cls().old_cython_meth.__name__ # optional - sage.misc.cython 'old_cython_meth' """ # first look through variables in stack frames diff --git a/src/sage/parallel/decorate.py b/src/sage/parallel/decorate.py index 38e4a784103..5f9ccbac80d 100644 --- a/src/sage/parallel/decorate.py +++ b/src/sage/parallel/decorate.py @@ -555,10 +555,10 @@ def fork(f=None, timeout=0, verbose=False): We illustrate that segfaulting subprocesses are no trouble at all:: - sage: cython('def f(): print(0)') + sage: cython('def f(): print(0)') # optional - sage.misc.cython sage: @fork ....: def g(): f() - sage: print("this works"); g() + sage: print("this works"); g() # optional - sage.misc.cython this works... ------------------------------------------------------------------------ diff --git a/src/sage/rings/integer_fake.pxd b/src/sage/rings/integer_fake.pxd index 8a60da7f572..de7672fa22e 100644 --- a/src/sage/rings/integer_fake.pxd +++ b/src/sage/rings/integer_fake.pxd @@ -17,7 +17,7 @@ This provides two functions: TESTS:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.rings.integer_fake cimport Integer_AS_MPZ, is_Integer ....: from sage.rings.integer cimport Integer ....: cdef Integer x = Integer(123456789) diff --git a/src/sage/rings/polynomial/ore_polynomial_element.pyx b/src/sage/rings/polynomial/ore_polynomial_element.pyx index 1a426ed1308..d1492a35946 100644 --- a/src/sage/rings/polynomial/ore_polynomial_element.pyx +++ b/src/sage/rings/polynomial/ore_polynomial_element.pyx @@ -1307,7 +1307,7 @@ cdef class OrePolynomial(AlgebraElement): TESTS:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.rings.polynomial.ore_polynomial_element cimport OrePolynomial ....: def left_lcm_cofactor(OrePolynomial P, OrePolynomial Q): ....: return P._left_lcm_cofactor(Q) @@ -1384,7 +1384,7 @@ cdef class OrePolynomial(AlgebraElement): TESTS:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.rings.polynomial.ore_polynomial_element cimport OrePolynomial ....: def right_lcm_cofactor(OrePolynomial P, OrePolynomial Q): ....: return P._right_lcm_cofactor(Q) diff --git a/src/sage/rings/tate_algebra_ideal.pyx b/src/sage/rings/tate_algebra_ideal.pyx index 12e12ce4791..d99a0332c38 100644 --- a/src/sage/rings/tate_algebra_ideal.pyx +++ b/src/sage/rings/tate_algebra_ideal.pyx @@ -625,7 +625,7 @@ cdef TateAlgebraElement regular_reduce(sgb, TateAlgebraTerm s, TateAlgebraElemen TESTS:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.rings.tate_algebra_ideal cimport regular_reduce ....: def python_regular_reduce(gb, s, v, stopval): ....: return regular_reduce(gb, s, v, stopval) @@ -703,7 +703,7 @@ cdef TateAlgebraElement reduce(gb, TateAlgebraElement v, stopval): TESTS:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.rings.tate_algebra_ideal cimport reduce ....: def python_reduce(gb, v, stopval): ....: return reduce(gb, v, stopval) diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index dfd6583b149..a0023b631f2 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -1138,7 +1138,7 @@ cdef class Element(SageObject): We now create an ``Element`` class where we define ``_richcmp_`` and check that comparison works:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.structure.richcmp cimport rich_to_bool ....: from sage.structure.element cimport Element ....: cdef class FloatCmp(Element): @@ -1150,9 +1150,9 @@ cdef class Element(SageObject): ....: cdef float x2 = (other).x ....: return rich_to_bool(op, (x1 > x2) - (x1 < x2)) ....: ''') - sage: a = FloatCmp(1) - sage: b = FloatCmp(2) - sage: a <= b, b <= a + sage: a = FloatCmp(1) # optional - sage.misc.cython + sage: b = FloatCmp(2) # optional - sage.misc.cython + sage: a <= b, b <= a # optional - sage.misc.cython (True, False) """ # Obvious case @@ -1287,16 +1287,16 @@ cdef class Element(SageObject): EXAMPLES:: - sage: cython( # long time + sage: cython( # long time # optional - sage.misc.cython ....: ''' ....: from sage.structure.element cimport Element ....: cdef class MyElement(Element): ....: cdef _add_long(self, long n): ....: return n ....: ''') - sage: e = MyElement(Parent()) # long time - sage: i = int(42) - sage: i + e, e + i # long time + sage: e = MyElement(Parent()) # long time # optional - sage.misc.cython + sage: i = int(42) # optional - sage.misc.cython + sage: i + e, e + i # long time # optional - sage.misc.cython (42, 42) """ return coercion_model.bin_op(self, n, add) @@ -1565,16 +1565,16 @@ cdef class Element(SageObject): EXAMPLES:: - sage: cython( # long time + sage: cython( # long time # optional - sage.misc.cython ....: ''' ....: from sage.structure.element cimport Element ....: cdef class MyElement(Element): ....: cdef _mul_long(self, long n): ....: return n ....: ''') - sage: e = MyElement(Parent()) # long time - sage: i = int(42) - sage: i * e, e * i # long time + sage: e = MyElement(Parent()) # long time # optional - sage.misc.cython + sage: i = int(42) # optional - sage.misc.cython + sage: i * e, e * i # long time # optional - sage.misc.cython (42, 42) """ return coercion_model.bin_op(self, n, mul) @@ -2226,7 +2226,7 @@ cdef class ElementWithCachedMethod(Element): ....: "from sage.structure.parent cimport Parent", ....: "cdef class MyParent(Parent):", ....: " Element = MyElement"] - sage: cython('\n'.join(cython_code)) + sage: cython('\n'.join(cython_code)) # optional - sage.misc.cython sage: cython_code = ["from sage.all import cached_method, cached_in_parent_method, Category, Objects", ....: "class MyCategory(Category):", ....: " @cached_method", @@ -2246,21 +2246,21 @@ cdef class ElementWithCachedMethod(Element): ....: " @cached_method", ....: " def invert(self, x):", ....: " return -x"] - sage: cython('\n'.join(cython_code)) - sage: C = MyCategory() - sage: P = MyParent(category=C) - sage: ebroken = MyBrokenElement(P,5) - sage: e = MyElement(P,5) + sage: cython('\n'.join(cython_code)) # optional - sage.misc.cython + sage: C = MyCategory() # optional - sage.misc.cython + sage: P = MyParent(category=C) # optional - sage.misc.cython + sage: ebroken = MyBrokenElement(P, 5) # optional - sage.misc.cython + sage: e = MyElement(P, 5) # optional - sage.misc.cython The cached methods inherited by ``MyElement`` works:: - sage: e.element_cache_test() + sage: e.element_cache_test() # optional - sage.misc.cython <-5> - sage: e.element_cache_test() is e.element_cache_test() + sage: e.element_cache_test() is e.element_cache_test() # optional - sage.misc.cython True - sage: e.element_via_parent_test() + sage: e.element_via_parent_test() # optional - sage.misc.cython <-5> - sage: e.element_via_parent_test() is e.element_via_parent_test() + sage: e.element_via_parent_test() is e.element_via_parent_test() # optional - sage.misc.cython True The other element class can only inherit a @@ -2268,36 +2268,36 @@ cdef class ElementWithCachedMethod(Element): parent. In fact, equal elements share the cache, even if they are of different types:: - sage: e == ebroken + sage: e == ebroken # optional - sage.misc.cython True - sage: type(e) == type(ebroken) + sage: type(e) == type(ebroken) # optional - sage.misc.cython False - sage: ebroken.element_via_parent_test() is e.element_via_parent_test() + sage: ebroken.element_via_parent_test() is e.element_via_parent_test() # optional - sage.misc.cython True However, the cache of the other inherited method breaks, although the method as such works:: - sage: ebroken.element_cache_test() + sage: ebroken.element_cache_test() # optional - sage.misc.cython <-5> - sage: ebroken.element_cache_test() is ebroken.element_cache_test() + sage: ebroken.element_cache_test() is ebroken.element_cache_test() # optional - sage.misc.cython False Since ``e`` and ``ebroken`` share the cache, when we empty it for one element it is empty for the other as well:: - sage: b = ebroken.element_via_parent_test() - sage: e.element_via_parent_test.clear_cache() - sage: b is ebroken.element_via_parent_test() + sage: b = ebroken.element_via_parent_test() # optional - sage.misc.cython + sage: e.element_via_parent_test.clear_cache() # optional - sage.misc.cython + sage: b is ebroken.element_via_parent_test() # optional - sage.misc.cython False Note that the cache only breaks for elements that do no allow attribute assignment. A Python version of ``MyBrokenElement`` therefore allows for cached methods:: - sage: epython = MyPythonElement(P,5) - sage: epython.element_cache_test() + sage: epython = MyPythonElement(P, 5) # optional - sage.misc.cython + sage: epython.element_cache_test() # optional - sage.misc.cython <-5> - sage: epython.element_cache_test() is epython.element_cache_test() + sage: epython.element_cache_test() is epython.element_cache_test() # optional - sage.misc.cython True """ @@ -2314,7 +2314,7 @@ cdef class ElementWithCachedMethod(Element): EXAMPLES:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.structure.element cimport ElementWithCachedMethod ....: cdef class MyElement(ElementWithCachedMethod): ....: cdef public object x @@ -2336,12 +2336,12 @@ cdef class ElementWithCachedMethod(Element): ....: def my_lazy_attr(self): ....: return 'lazy attribute of <%s>'%self.x ....: ''') - sage: C = MyCategory() - sage: P = MyParent(category=C) - sage: e = MyElement(P,5) - sage: e.my_lazy_attr + sage: C = MyCategory() # optional - sage.misc.cython + sage: P = MyParent(category=C) # optional - sage.misc.cython + sage: e = MyElement(P, 5) # optional - sage.misc.cython + sage: e.my_lazy_attr # optional - sage.misc.cython 'lazy attribute of <5>' - sage: e.my_lazy_attr is e.my_lazy_attr + sage: e.my_lazy_attr is e.my_lazy_attr # optional - sage.misc.cython True """ try: @@ -4090,14 +4090,14 @@ cdef class EuclideanDomainElement(PrincipalIdealDomainElement): EXAMPLES:: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.structure.element cimport EuclideanDomainElement ....: cdef class MyElt(EuclideanDomainElement): ....: def quo_rem(self, other): ....: return self._parent.var('quo,rem') ....: ''') - sage: e = MyElt(SR) - sage: e // e + sage: e = MyElt(SR) # optional - sage.misc.cython + sage: e // e # optional - sage.misc.cython quo """ Q, _ = self.quo_rem(right) @@ -4120,14 +4120,14 @@ cdef class EuclideanDomainElement(PrincipalIdealDomainElement): :: - sage: cython(''' + sage: cython(''' # optional - sage.misc.cython ....: from sage.structure.element cimport EuclideanDomainElement ....: cdef class MyElt(EuclideanDomainElement): ....: def quo_rem(self, other): ....: return self._parent.var('quo,rem') ....: ''') - sage: e = MyElt(SR) - sage: e % e + sage: e = MyElt(SR) # optional - sage.misc.cython + sage: e % e # optional - sage.misc.cython rem """ _, R = self.quo_rem(other) diff --git a/src/sage/structure/factory.pyx b/src/sage/structure/factory.pyx index 9a7f762646b..af40d99c0bc 100644 --- a/src/sage/structure/factory.pyx +++ b/src/sage/structure/factory.pyx @@ -196,7 +196,7 @@ cdef class UniqueFactory(SageObject): :class:`object`. The third allows attribute assignment and is derived from :class:`object`. :: - sage: cython("cdef class C: pass") + sage: cython("cdef class C: pass") # optional - sage.misc.cython sage: class D: ....: def __init__(self, *args): ....: self.t = args @@ -214,7 +214,7 @@ cdef class UniqueFactory(SageObject): It is impossible to create an instance of ``C`` with our factory, since it does not allow weak references:: - sage: F(1, impl='C') + sage: F(1, impl='C') # optional - sage.misc.cython Traceback (most recent call last): ... TypeError: cannot create weak reference to '....C' object @@ -222,12 +222,12 @@ cdef class UniqueFactory(SageObject): Let us try again, with a Cython class that does allow weak references. Now, creation of an instance using the factory works:: - sage: cython('''cdef class C: + sage: cython('''cdef class C: # optional - sage.misc.cython ....: cdef __weakref__ ....: ''') ....: - sage: c = F(1, impl='C') - sage: isinstance(c, C) + sage: c = F(1, impl='C') # optional - sage.misc.cython + sage: isinstance(c, C) # optional - sage.misc.cython True The cache is used when calling the factory again---even if it is suggested @@ -235,16 +235,16 @@ cdef class UniqueFactory(SageObject): only considered an "extra argument" that does not count for the key. :: - sage: c is F(1, impl='C') is F(1, impl="D") is F(1) + sage: c is F(1, impl='C') is F(1, impl="D") is F(1) # optional - sage.misc.cython True However, pickling and unpickling does not use the cache. This is because the factory has tried to assign an attribute to the instance that provides information on the key used to create the instance, but failed:: - sage: loads(dumps(c)) is c + sage: loads(dumps(c)) is c # optional - sage.misc.cython False - sage: hasattr(c, '_factory_data') + sage: hasattr(c, '_factory_data') # optional - sage.misc.cython False We have already seen that our factory will only take the requested diff --git a/src/sage/symbolic/pynac.pxi b/src/sage/symbolic/pynac.pxi index c8bdbde496b..e6ab54f4e0b 100644 --- a/src/sage/symbolic/pynac.pxi +++ b/src/sage/symbolic/pynac.pxi @@ -3,7 +3,7 @@ Declarations for pynac, a Python frontend for ginac Check that we can externally cimport this (:trac:`18825`):: - sage: cython(''' # long time; random compiler warnings + sage: cython(''' # long time; random compiler warnings # optional - sage.misc.cython ....: from sage.symbolic cimport expression ....: ''') """