diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index f6413de91e8..7830c674573 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -1079,6 +1079,26 @@ framework. Here is a comprehensive list: sage: SloaneEncyclopedia[60843] # optional - sloane_database + .. NOTE:: + + If one of the first 10 lines of a file starts with any of + ``r""" sage.doctest: optional - keyword`` + (or ``""" sage.doctest: optional - keyword`` + or ``# sage.doctest: optional - keyword`` + or ``% sage.doctest: optional - keyword`` + or ``.. sage.doctest: optional - keyword``, + or any of these with different spacing), + then that file will be skipped unless + the ``--optional=keyword`` flag is passed to ``sage -t``. + + This does not apply to files which are explicitly given + as command line arguments: those are always tested. + + If you add such a line to a file, you are strongly encouraged + to add a note to the module-level documentation, saying that + the doctests in this file will be skipped unless the + appropriate conditions are met. + - **internet:** For lines that require an internet connection:: sage: oeis(60843) # optional - internet diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 06446de4e6a..8ba552e6806 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -38,9 +38,11 @@ from .reporting import DocTestReporter from .util import Timer, count_noun, dict_difference from .external import external_software, available_software +from .parsing import parse_optional_tags nodoctest_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*nodoctest') optionaltag_regex = re.compile(r'^\w+$') +optionalfiledirective_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*sage\.doctest: (.*)') # Optional tags which are always automatically added @@ -204,11 +206,23 @@ def skipdir(dirname): return True return False -def skipfile(filename): +def skipfile(filename, tested_optional_tags=False): """ Return True if and only if the file ``filename`` should not be doctested. + INPUT: + + - ``filename`` - name of a file + + - ``tested_optional_tags`` - a list or tuple or set of optional tags to test, + or ``False`` (no optional test) or ``True`` (all optional tests) + + If ``filename`` contains a line of the form ``"# sage.doctest: + optional - xyz")``, then this will return ``False`` if "xyz" is in + ``tested_optional_tags``. Otherwise, it returns the matching tag + ("optional - xyz"). + EXAMPLES:: sage: from sage.doctest.control import skipfile @@ -221,6 +235,18 @@ def skipfile(filename): ....: _ = f.write("# nodoctest") sage: skipfile(filename) True + sage: with open(filename, "w") as f: + ....: _ = f.write("# sage.doctest: optional - xyz") + sage: skipfile(filename, False) + 'optional - xyz' + sage: bool(skipfile(filename, False)) + True + sage: skipfile(filename, ['abc']) + 'optional - xyz' + sage: skipfile(filename, ['abc', 'xyz']) + False + sage: skipfile(filename, True) + False """ base, ext = os.path.splitext(filename) if ext not in ('.py', '.pyx', '.pxd', '.pxi', '.sage', '.spyx', '.rst', '.tex'): @@ -230,6 +256,16 @@ def skipfile(filename): for line in F: if nodoctest_regex.match(line): return True + if tested_optional_tags is not True: + # Adapted from code in SageDocTestParser.parse + m = optionalfiledirective_regex.match(line) + if m: + if tested_optional_tags is False: + return m.group(2) + optional_tags = parse_optional_tags('#' + m.group(2)) + extra = optional_tags - set(tested_optional_tags) + if extra: + return m.group(2) line_count += 1 if line_count >= 10: break @@ -786,7 +822,7 @@ def expand(): if dir[0] == "." or skipdir(os.path.join(root,dir)): dirs.remove(dir) for file in files: - if not skipfile(os.path.join(root,file)): + if not skipfile(os.path.join(root, file), self.options.optional): yield os.path.join(root, file) else: # the user input this file explicitly, so we don't skip it diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index affaa351af6..32b77a861fa 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -1,11 +1,11 @@ # distutils: libraries = mtx # sage_setup: distribution = sagemath-meataxe +# sage.doctest: optional - meataxe r""" Dense Matrices over `\mathbb F_q`, with `q<255`. -This module is a wrapper for version 2.4.24 of the Aachen -`C-MeatAxe `_, +This module is a wrapper for the `Aachen C-MeatAxe library <../spkg/meataxe.html>`_, improved by an implementation of the Winograd-Strassen multiplication algorithm. It provides matrices over the finite field `\mathbb F_q`, where `q\le 255`. @@ -14,6 +14,11 @@ By default, it is only used when `q` is odd and not prime, because other matrix implementations in SageMath perform better for prime fields or in characteristic two. +.. NOTE:: + + The examples shown here will only work when the `meataxe + <../spkg/meataxe.html>` package has been installed. + AUTHORS: - Simon King (2015-09): initial version @@ -94,15 +99,15 @@ cdef class FieldConverter_class: EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense sage: F. = GF(125) - sage: M = MatrixSpace(F, 2, 2, implementation=Matrix_gfpn_dense).one() # optional: meataxe - sage: C = M._converter # optional: meataxe - sage: C.fel_to_field(15) # optional: meataxe + sage: M = MatrixSpace(F, 2, 2, implementation=Matrix_gfpn_dense).one() + sage: C = M._converter + sage: C.fel_to_field(15) 3*y sage: F.fetch_int(15) 3*y - sage: C.field_to_fel(y) # optional: meataxe + sage: C.field_to_fel(y) 5 sage: y.integer_representation() 5 @@ -116,8 +121,8 @@ cdef class FieldConverter_class: EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class # optional: meataxe - sage: FieldConverter_class(GF(13^2)) # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class + sage: FieldConverter_class(GF(13^2)) """ self.field = field._cache.fetch_int @@ -129,10 +134,10 @@ cdef class FieldConverter_class: EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class sage: F. = GF(125) - sage: C = FieldConverter_class(F) # optional: meataxe - sage: C.fel_to_field(15) # optional: meataxe + sage: C = FieldConverter_class(F) + sage: C.fel_to_field(15) 3*y sage: F.fetch_int(15) 3*y @@ -145,10 +150,10 @@ cdef class FieldConverter_class: EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class sage: F. = GF(125) - sage: C = FieldConverter_class(F) # optional: meataxe - sage: C.field_to_fel(y) # optional: meataxe + sage: C = FieldConverter_class(F) + sage: C.field_to_fel(y) 5 sage: y.integer_representation() 5 @@ -157,7 +162,7 @@ cdef class FieldConverter_class: Test invalid input:: - sage: C.field_to_fel('foo') # optional: meataxe + sage: C.field_to_fel('foo') Traceback (most recent call last): ... AttributeError: 'str' object has no attribute 'integer_representation' @@ -187,15 +192,15 @@ cdef class PrimeFieldConverter_class(FieldConverter_class): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense sage: F = GF(5) - sage: M = MatrixSpace(F, 2, 2, implementation=Matrix_gfpn_dense).one() # optional: meataxe - sage: C = M._converter # optional: meataxe - sage: C.fel_to_field(2) # optional: meataxe + sage: M = MatrixSpace(F, 2, 2, implementation=Matrix_gfpn_dense).one() + sage: C = M._converter + sage: C.fel_to_field(2) 2 sage: F(2) 2 - sage: C.field_to_fel(F(2)) # optional: meataxe + sage: C.field_to_fel(F(2)) 2 sage: int(F(2)) 2 @@ -209,8 +214,8 @@ cdef class PrimeFieldConverter_class(FieldConverter_class): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class # optional: meataxe - sage: PrimeFieldConverter_class(GF(251)) # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class + sage: PrimeFieldConverter_class(GF(251)) """ self.field = field @@ -221,10 +226,10 @@ cdef class PrimeFieldConverter_class(FieldConverter_class): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class sage: F = GF(5) - sage: C = PrimeFieldConverter_class(F) # optional: meataxe - sage: C.fel_to_field(2) # optional: meataxe + sage: C = PrimeFieldConverter_class(F) + sage: C.fel_to_field(2) 2 """ return IntegerMod_int(self.field, FfToInt(x)) @@ -235,17 +240,17 @@ cdef class PrimeFieldConverter_class(FieldConverter_class): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class sage: F = GF(5) - sage: C = PrimeFieldConverter_class(F) # optional: meataxe - sage: C.field_to_fel(F(2)) # optional: meataxe + sage: C = PrimeFieldConverter_class(F) + sage: C.field_to_fel(F(2)) 2 TESTS: Test invalid input:: - sage: C.field_to_fel('foo') # optional: meataxe + sage: C.field_to_fel('foo') Traceback (most recent call last): ... TypeError: an integer is required @@ -339,7 +344,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: print(M) [1 2 3] [4 0 1] - sage: type(M) # optional: meataxe + sage: type(M) The documentation of the ``__init__`` methods shows further @@ -355,11 +360,11 @@ cdef class Matrix_gfpn_dense(Matrix_dense): TESTS:: sage: MS = MatrixSpace(GF(64), 0) - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe - sage: Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, MS) # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense + sage: Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, MS) [] sage: M = None - sage: M = Matrix_gfpn_dense(MatrixSpace(GF(64,'z'),4), None) # optional: meataxe + sage: M = Matrix_gfpn_dense(MatrixSpace(GF(64,'z'),4), None) sage: del M # indirect doctest """ if self.Data != NULL: @@ -384,27 +389,27 @@ cdef class Matrix_gfpn_dense(Matrix_dense): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense 1. Creating a zero (3x2)-matrix:: - sage: Matrix_gfpn_dense(MatrixSpace(GF(4,'z'),3,2)) # optional: meataxe + sage: Matrix_gfpn_dense(MatrixSpace(GF(4,'z'),3,2)) [0 0] [0 0] [0 0] 2. Creating a matrix from a list or list of lists:: - sage: Matrix_gfpn_dense(MatrixSpace(GF(5),2,3),[1,2,3,4,5,6]) # optional: meataxe + sage: Matrix_gfpn_dense(MatrixSpace(GF(5),2,3),[1,2,3,4,5,6]) [1 2 3] [4 0 1] - sage: Matrix_gfpn_dense(MatrixSpace(GF(5),2,3),[[1,2,3],[4,5,6]]) # optional: meataxe + sage: Matrix_gfpn_dense(MatrixSpace(GF(5),2,3),[[1,2,3],[4,5,6]]) [1 2 3] [4 0 1] 3. Creating a diagonal matrix:: - sage: M = Matrix_gfpn_dense(MatrixSpace(GF(7),5),2); M # optional: meataxe + sage: M = Matrix_gfpn_dense(MatrixSpace(GF(7),5),2); M [2 0 0 0 0] [0 2 0 0 0] [0 0 2 0 0] @@ -457,12 +462,12 @@ cdef class Matrix_gfpn_dense(Matrix_dense): does not exist, an error raised by the MeatAxe library is propagated:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe - sage: Matrix_gfpn_dense.from_filename('foobarNONEXISTING_FILE') # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense + sage: Matrix_gfpn_dense.from_filename('foobarNONEXISTING_FILE') Traceback (most recent call last): ... OSError: foobarNONEXISTING_FILE: No such file or directory in file os.c (line 255) - sage: Matrix_gfpn_dense.from_filename('') # optional: meataxe + sage: Matrix_gfpn_dense.from_filename('') Traceback (most recent call last): ... ValueError: cannot construct meataxe matrix from empty filename @@ -496,9 +501,9 @@ cdef class Matrix_gfpn_dense(Matrix_dense): True sage: N is M False - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe - sage: M = Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, parent(M)) # optional: meataxe - sage: copy(M) # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense + sage: M = Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, parent(M)) + sage: copy(M) Traceback (most recent call last): ... ValueError: cannot copy an uninitialized matrix @@ -559,7 +564,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: F. = GF(9) sage: M = MatrixSpace(F,3)(sorted(list(F))) - sage: type(M) # optional: meataxe + sage: type(M) sage: M # indirect doctest [ 0 1 2] @@ -606,18 +611,18 @@ cdef class Matrix_gfpn_dense(Matrix_dense): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX # optional: meataxe - sage: M = MTX(MatrixSpace(GF(7), 5, 3), [[0,1,2], [1,2,3], [2,3,4], [3,4,5], [4,5,6]]) # optional: meataxe - sage: M # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX + sage: M = MTX(MatrixSpace(GF(7), 5, 3), [[0,1,2], [1,2,3], [2,3,4], [3,4,5], [4,5,6]]) + sage: M [0 1 2] [1 2 3] [2 3 4] [3 4 5] [4 5 6] - sage: M.get_slice(1,3) # optional: meataxe + sage: M.get_slice(1,3) [1 2 3] [2 3 4] - sage: type(_) is MTX # optional: meataxe + sage: type(_) is MTX True """ @@ -696,23 +701,23 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: MS = MatrixSpace(GF(27,'z'),6,6) sage: M = MS.random_element() # indirect doctest - sage: M # optional: meataxe + sage: M [ 1 z + 1 z^2 + z + 1 z^2 2*z^2 + z z + 1] [2*z^2 + 2*z + 2 2*z^2 + z + 2 z^2 + 1 2*z^2 + 2*z + 2 z^2 + z 2*z^2 + z + 1] [ 2*z + 2 z^2 + z + 2 z + 2 2*z^2 + 2*z + 2 2*z^2 2*z^2] [ 2*z^2 + z + 2 z^2 z + 2 z^2 + z 2*z^2 + 2 z^2 + 2] [ 2*z^2 + z 2*z 2*z^2 + 2*z + 1 2*z^2 + 1 2*z^2 + 2*z + 1 2*z^2 + z] [ 2*z + 1 z^2 + z z^2 z^2 2*z^2 + 2*z z + 1] - sage: type(M) # optional: meataxe + sage: type(M) - sage: MS.random_element(nonzero=True) # optional: meataxe + sage: MS.random_element(nonzero=True) [ 2*z 1 z^2 + 2*z + 1 2*z^2 + z + 1 z^2 z^2 + z + 1] [ 2*z^2 + 2*z 2*z^2 + z + 2 2*z + 1 z^2 + 2*z 2*z^2 + 2*z z^2] [ z^2 + z z^2 + z + 2 2*z^2 + 2*z + 1 z^2 + 2 1 2*z^2] [ z 2*z^2 + 2*z 2*z^2 2*z + 1 z + 2 z + 2] [ z^2 + z z^2 z + 2 2*z^2 + 2*z 2*z + 1 z^2 + z] [ z^2 + z + 2 2*z^2 + z z^2 z + 1 2*z^2 + 2*z z^2 + 2*z + 1] - sage: MS.random_element(density=0.5) # optional: meataxe + sage: MS.random_element(density=0.5) [ z^2 + 2 0 z^2 + 2*z + 2 2*z^2 + z 0 z^2 + z + 2] [ 0 1 0 0 0 0] [ 2*z^2 + z + 1 2*z^2 + z + 2 0 z^2 + z + 2 0 z^2 + z + 1] @@ -723,7 +728,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): The following tests against a bug that was fixed in :trac:`23352`:: sage: MS = MatrixSpace(GF(9,'x'),1,5) - sage: MS.random_element() # optional: meataxe + sage: MS.random_element() [x + 1 x 2 x + 2 x + 2] """ @@ -897,19 +902,19 @@ cdef class Matrix_gfpn_dense(Matrix_dense): EXAMPLES:: sage: M = random_matrix(GF(25,'x'), 5,5) - sage: M # optional: meataxe + sage: M [ 4 4*x x + 3 4*x + 2 3*x + 4] [ x + 2 3*x + 1 3 0 3] [ 3*x 2*x + 4 1 0 2*x] [4*x + 4 2*x + 3 4*x 1 3*x + 1] [3*x + 3 x + 3 x + 2 x + 1 3*x + 2] - sage: M._rowlist_(1) # optional: meataxe + sage: M._rowlist_(1) [7, 16, 3, 0, 3] - sage: [M[1,i]._int_repr() for i in range(5)] # optional: meataxe + sage: [M[1,i]._int_repr() for i in range(5)] ['7', '16', '3', '0', '3'] - sage: M._rowlist_(2,4) # optional: meataxe + sage: M._rowlist_(2,4) [15, 14, 1, 0, 10, 24, 13, 20, 1, 16, 18, 8, 7, 6, 17] - sage: [[M[i,j]._int_repr() for j in range(5)] for i in range(2,5)] # optional: meataxe + sage: [[M[i,j]._int_repr() for j in range(5)] for i in range(2,5)] [['15', '14', '1', '0', '10'], ['24', '13', '20', '1', '16'], ['18', '8', '7', '6', '17']] @@ -1340,7 +1345,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: M = MatrixSpace(GF(9,'x'),1000,500).random_element() sage: N = MatrixSpace(GF(9,'x'),500,2000).random_element() - sage: M*N == M._multiply_classical(N) # optional: meataxe + sage: M*N == M._multiply_classical(N) True """ @@ -1376,7 +1381,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: M = MatrixSpace(GF(9,'x'),1500,600).random_element() sage: N = MatrixSpace(GF(9,'x'),600,1500).random_element() - sage: M._multiply_strassen(N) == M._multiply_strassen(N,80) == M._multiply_strassen(N,2) # optional: meataxe + sage: M._multiply_strassen(N) == M._multiply_strassen(N,80) == M._multiply_strassen(N,2) True """ @@ -1483,7 +1488,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): ....: M = MS.random_element(density=0.4) ....: if M.rank() < 5: ....: break - sage: ~M # optional: meataxe + sage: ~M Traceback (most recent call last): ... ZeroDivisionError: Division by zero in file matinv.c (line 50) @@ -1540,7 +1545,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: M = MatrixSpace(K, 4)([2*x^2 + 2*x, 2*x^2 + x, 2*x^2 + x + 1, ....: x^2 + x + 2, x + 2, x^2, 2*x + 2, 2*x^2 + 2*x, 2*x^2 + 1, ....: 1, 2, x^2 + 2*x + 1, x^2 + x + 2, x + 1, 2*x^2 + 2*x, x^2 + x]) - sage: M.order() # optional: meataxe + sage: M.order() 104 sage: M^104 == 1 True @@ -1594,7 +1599,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): Basis matrix: [0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 0 0 1 0 0] - sage: M.left_kernel_matrix() # optional: meataxe + sage: M.left_kernel_matrix() [0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 0 0 1 0 0] @@ -1707,9 +1712,9 @@ cdef class Matrix_gfpn_dense(Matrix_dense): method directly:: sage: N = copy(M) - sage: N._echelon_in_place_classical(reduced=False) # optional: meataxe + sage: N._echelon_in_place_classical(reduced=False) (2, 1, 3, 4, 5, 6, 7, 8) - sage: N # optional: meataxe + sage: N [ 0 0 x 0 3*x + 2 0 0 0 2*x 0] [ 0 x + 3 0 0 0 3*x x + 4 0 0 0] [ 0 0 0 2*x 0 4*x + 1 4 0 0 0] @@ -1726,7 +1731,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): We verify that the above echelon form is consistent with Sage's generic implementation of dense matrices:: - sage: type(M) # optional: meataxe + sage: type(M) sage: MS = MatrixSpace(M.base_ring(), M.nrows(), M.ncols(), implementation='generic') sage: X = MS(M) @@ -1864,19 +1869,19 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): sage: s = b'Uq\x82\xa7\x8bh' sage: len(s) 6 - sage: from sage.matrix.matrix_gfpn_dense import mtx_unpickle, Matrix_gfpn_dense # optional: meataxe - sage: MS = MatrixSpace(GF(13), 2, 5, implementation=Matrix_gfpn_dense) # optional: meataxe - sage: N = mtx_unpickle(MS, 2, 5, s, True) # optional: meataxe - sage: N # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import mtx_unpickle, Matrix_gfpn_dense + sage: MS = MatrixSpace(GF(13), 2, 5, implementation=Matrix_gfpn_dense) + sage: N = mtx_unpickle(MS, 2, 5, s, True) + sage: N [ 6 7 8 9 10] [12 11 10 9 8] - sage: type(N) # optional: meataxe + sage: type(N) We demonstrate that a slightly different pickle format can be understood as well, that was at some point used by some optional package:: - sage: N == mtx_unpickle(int(13), 2, 5, s, True) # optional: meataxe + sage: N == mtx_unpickle(int(13), 2, 5, s, True) True In a previous version of this optional module, the whole memory chunk @@ -1887,7 +1892,7 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): sage: t = b'Uq\x82\x00\x00\x00\x00\x00\xa7\x8bh\x00\x00\x00\x00\x00' sage: len(t) 16 - sage: N == mtx_unpickle(MS, 2, 5, t, True) # optional: meataxe + sage: N == mtx_unpickle(MS, 2, 5, t, True) doctest:warning ... DeprecationWarning: Reading this pickle may be machine dependent @@ -1900,12 +1905,12 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): sage: t = b'Uq\x82\x00\x00\x00\x00\x00\x00\xa7\x8bh\x00\x00\x00\x00\x00\x00' sage: len(t) 18 - sage: N == mtx_unpickle(MS, 2, 5, t, True) # optional: meataxe + sage: N == mtx_unpickle(MS, 2, 5, t, True) True The data may be empty, which results in the zero matrix:: - sage: mtx_unpickle(MS, 2, 5, b'', True) # optional: meataxe + sage: mtx_unpickle(MS, 2, 5, b'', True) [0 0 0 0 0] [0 0 0 0 0] @@ -1914,27 +1919,27 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): pickle format (we test several code paths here):: sage: t = b'Uq\x82\x00\x00\x00\x00\x00\xa7\x8bh\x00\x00\x00\x00\x00\x00' - sage: mtx_unpickle(MS, 2, 5, t, True) # optional: meataxe + sage: mtx_unpickle(MS, 2, 5, t, True) Traceback (most recent call last): ... ValueError: Expected a pickle with 3*2 bytes, got 17 instead sage: t = b'Uq\x82\x00\x00\x00\x00\x00\xa7\x8bh\x00\x00\x00\x00\x00\x00' - sage: mtx_unpickle(MS, 2, 5, t[:4], True) # optional: meataxe + sage: mtx_unpickle(MS, 2, 5, t[:4], True) Traceback (most recent call last): ... ValueError: Expected a pickle with 3*2 bytes, got 2*2 instead sage: MS = MatrixSpace(GF(13), 0, 5) - sage: mtx_unpickle(MS, 0, 5, s, True) # optional: meataxe + sage: mtx_unpickle(MS, 0, 5, s, True) Traceback (most recent call last): ... ValueError: This matrix pickle contains data, thus, the number of rows and columns must be positive sage: MS = MatrixSpace(GF(13), 3, 5) - sage: mtx_unpickle(MS, 2, 5, s, True) # optional: meataxe + sage: mtx_unpickle(MS, 2, 5, s, True) Traceback (most recent call last): ... ValueError: Inconsistent dimensions in this matrix pickle - sage: mtx_unpickle(MatrixSpace(GF(19),0,5), 0, 5, b'', True) # optional: meataxe + sage: mtx_unpickle(MatrixSpace(GF(19),0,5), 0, 5, b'', True) [] """ # The expected input type is bytes. However, Python-2 legacy pickles do diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 2c31ee55ae5..d079f9e6931 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -2061,6 +2061,15 @@ def sage_getdoc(obj, obj_name='', embedded=False): return '' r = sage_getdoc_original(obj) s = sage.misc.sagedoc.format(r, embedded=embedded) + f = sage_getfile(obj) + if f and os.path.exists(f): + from sage.doctest.control import skipfile + skip = skipfile(f) + if isinstance(skip, str): + warn = """WARNING: the enclosing module is marked '{}', +so doctests may not pass.""".format(skip) + s = warn + "\n\n" + s + pass # Fix object naming if obj_name != '':