Utility functions¶
This module contains various utility functions and classes used in doctesting.
AUTHORS:
David Roe (2012-03-27) – initial version, based on Robert Bradshaw’s code.
- class sage.doctest.util.NestedName(base)[source]¶
Bases:
object
Class used to construct fully qualified names based on indentation level.
EXAMPLES:
sage: from sage.doctest.util import NestedName sage: qname = NestedName('sage.categories.algebras') sage: qname[0] = 'Algebras'; qname sage.categories.algebras.Algebras sage: qname[4] = '__contains__'; qname sage.categories.algebras.Algebras.__contains__ sage: qname[4] = 'ParentMethods' sage: qname[8] = 'from_base_ring'; qname sage.categories.algebras.Algebras.ParentMethods.from_base_ring
>>> from sage.all import * >>> from sage.doctest.util import NestedName >>> qname = NestedName('sage.categories.algebras') >>> qname[Integer(0)] = 'Algebras'; qname sage.categories.algebras.Algebras >>> qname[Integer(4)] = '__contains__'; qname sage.categories.algebras.Algebras.__contains__ >>> qname[Integer(4)] = 'ParentMethods' >>> qname[Integer(8)] = 'from_base_ring'; qname sage.categories.algebras.Algebras.ParentMethods.from_base_ring
- class sage.doctest.util.RecordingDict(*args, **kwds)[source]¶
Bases:
dict
This dictionary is used for tracking the dependencies of an example.
This feature allows examples in different doctests to be grouped for better timing data. It’s obtained by recording whenever anything is set or retrieved from this dictionary.
EXAMPLES:
sage: from sage.doctest.util import RecordingDict sage: D = RecordingDict(test=17) sage: D.got set() sage: D['test'] 17 sage: D.got {'test'} sage: D.set set() sage: D['a'] = 1 sage: D['a'] 1 sage: D.set {'a'} sage: D.got {'test'}
>>> from sage.all import * >>> from sage.doctest.util import RecordingDict >>> D = RecordingDict(test=Integer(17)) >>> D.got set() >>> D['test'] 17 >>> D.got {'test'} >>> D.set set() >>> D['a'] = Integer(1) >>> D['a'] 1 >>> D.set {'a'} >>> D.got {'test'}
- copy()[source]¶
Note that set and got are not copied.
EXAMPLES:
sage: from sage.doctest.util import RecordingDict sage: D = RecordingDict(d = 42) sage: D['a'] = 4 sage: D.set {'a'} sage: E = D.copy() sage: E.set set() sage: sorted(E.keys()) ['a', 'd']
>>> from sage.all import * >>> from sage.doctest.util import RecordingDict >>> D = RecordingDict(d = Integer(42)) >>> D['a'] = Integer(4) >>> D.set {'a'} >>> E = D.copy() >>> E.set set() >>> sorted(E.keys()) ['a', 'd']
- get(name, default=None)[source]¶
EXAMPLES:
sage: from sage.doctest.util import RecordingDict sage: D = RecordingDict(d = 42) sage: D.get('d') 42 sage: D.got {'d'} sage: D.get('not_here') sage: sorted(list(D.got)) ['d', 'not_here']
>>> from sage.all import * >>> from sage.doctest.util import RecordingDict >>> D = RecordingDict(d = Integer(42)) >>> D.get('d') 42 >>> D.got {'d'} >>> D.get('not_here') >>> sorted(list(D.got)) ['d', 'not_here']
- start()[source]¶
We track which variables have been set or retrieved. This function initializes these lists to be empty.
EXAMPLES:
sage: from sage.doctest.util import RecordingDict sage: D = RecordingDict(d = 42) sage: D.set set() sage: D['a'] = 4 sage: D.set {'a'} sage: D.start(); D.set set()
>>> from sage.all import * >>> from sage.doctest.util import RecordingDict >>> D = RecordingDict(d = Integer(42)) >>> D.set set() >>> D['a'] = Integer(4) >>> D.set {'a'} >>> D.start(); D.set set()
- class sage.doctest.util.Timer[source]¶
Bases:
object
A simple timer.
EXAMPLES:
sage: from sage.doctest.util import Timer sage: Timer() {} sage: TestSuite(Timer()).run()
>>> from sage.all import * >>> from sage.doctest.util import Timer >>> Timer() {} >>> TestSuite(Timer()).run()
- annotate(object)[source]¶
Annotates the given object with the cputime and walltime stored in this timer.
EXAMPLES:
sage: from sage.doctest.util import Timer sage: Timer().start().annotate(EllipticCurve) sage: EllipticCurve.cputime # random 2.817255 sage: EllipticCurve.walltime # random 1332649288.410404
>>> from sage.all import * >>> from sage.doctest.util import Timer >>> Timer().start().annotate(EllipticCurve) >>> EllipticCurve.cputime # random 2.817255 >>> EllipticCurve.walltime # random 1332649288.410404
- start()[source]¶
Start the timer.
Can be called multiple times to reset the timer.
EXAMPLES:
sage: from sage.doctest.util import Timer sage: Timer().start() {'cputime': ..., 'walltime': ...}
>>> from sage.all import * >>> from sage.doctest.util import Timer >>> Timer().start() {'cputime': ..., 'walltime': ...}
- stop()[source]¶
Stops the timer, recording the time that has passed since it was started.
EXAMPLES:
sage: from sage.doctest.util import Timer sage: import time sage: timer = Timer().start() sage: time.sleep(float(0.5)) sage: timer.stop() {'cputime': ..., 'walltime': ...}
>>> from sage.all import * >>> from sage.doctest.util import Timer >>> import time >>> timer = Timer().start() >>> time.sleep(float(RealNumber('0.5'))) >>> timer.stop() {'cputime': ..., 'walltime': ...}
- sage.doctest.util.count_noun(number, noun, plural=None, pad_number=False, pad_noun=False)[source]¶
EXAMPLES:
sage: from sage.doctest.util import count_noun sage: count_noun(1, "apple") '1 apple' sage: count_noun(1, "apple", pad_noun=True) '1 apple ' sage: count_noun(1, "apple", pad_number=3) ' 1 apple' sage: count_noun(2, "orange") '2 oranges' sage: count_noun(3, "peach", "peaches") '3 peaches' sage: count_noun(1, "peach", plural='peaches', pad_noun=True) '1 peach '
>>> from sage.all import * >>> from sage.doctest.util import count_noun >>> count_noun(Integer(1), "apple") '1 apple' >>> count_noun(Integer(1), "apple", pad_noun=True) '1 apple ' >>> count_noun(Integer(1), "apple", pad_number=Integer(3)) ' 1 apple' >>> count_noun(Integer(2), "orange") '2 oranges' >>> count_noun(Integer(3), "peach", "peaches") '3 peaches' >>> count_noun(Integer(1), "peach", plural='peaches', pad_noun=True) '1 peach '
- sage.doctest.util.dict_difference(self, other)[source]¶
Return a dict with all key-value pairs occurring in
self
but not inother
.EXAMPLES:
sage: from sage.doctest.util import dict_difference sage: d1 = {1: 'a', 2: 'b', 3: 'c'} sage: d2 = {1: 'a', 2: 'x', 4: 'c'} sage: dict_difference(d2, d1) {2: 'x', 4: 'c'}
>>> from sage.all import * >>> from sage.doctest.util import dict_difference >>> d1 = {Integer(1): 'a', Integer(2): 'b', Integer(3): 'c'} >>> d2 = {Integer(1): 'a', Integer(2): 'x', Integer(4): 'c'} >>> dict_difference(d2, d1) {2: 'x', 4: 'c'}
sage: from sage.doctest.control import DocTestDefaults sage: D1 = DocTestDefaults() sage: D2 = DocTestDefaults(foobar='hello', timeout=100) sage: dict_difference(D2.__dict__, D1.__dict__) {'foobar': 'hello', 'timeout': 100}
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults >>> D1 = DocTestDefaults() >>> D2 = DocTestDefaults(foobar='hello', timeout=Integer(100)) >>> dict_difference(D2.__dict__, D1.__dict__) {'foobar': 'hello', 'timeout': 100}
- sage.doctest.util.ensure_interruptible_after(*args, **kwds)[source]¶
Helper function for doctesting to ensure that the code is interruptible after a certain amount of time. This should only be used for internal doctesting purposes.
EXAMPLES:
sage: from sage.doctest.util import ensure_interruptible_after sage: with ensure_interruptible_after(1) as data: sleep(3)
>>> from sage.all import * >>> from sage.doctest.util import ensure_interruptible_after >>> with ensure_interruptible_after(Integer(1)) as data: sleep(Integer(3))
as data
is optional, but if it is used, it will contain a few useful values:sage: data # abs tol 1 {'alarm_raised': True, 'elapsed': 1.0}
>>> from sage.all import * >>> data # abs tol 1 {'alarm_raised': True, 'elapsed': 1.0}
max_wait_after_interrupt
can be passed if the function may take longer than usual to be interrupted:sage: # needs sage.misc.cython sage: cython(r''' ....: from posix.time cimport clock_gettime, CLOCK_REALTIME, timespec, time_t ....: from cysignals.signals cimport sig_check ....: ....: cpdef void uninterruptible_sleep(double seconds): ....: cdef timespec start_time, target_time ....: clock_gettime(CLOCK_REALTIME, &start_time) ....: ....: cdef time_t floor_seconds = <time_t>seconds ....: target_time.tv_sec = start_time.tv_sec + floor_seconds ....: target_time.tv_nsec = start_time.tv_nsec + <long>((seconds - floor_seconds) * 1e9) ....: if target_time.tv_nsec >= 1000000000: ....: target_time.tv_nsec -= 1000000000 ....: target_time.tv_sec += 1 ....: ....: while True: ....: clock_gettime(CLOCK_REALTIME, &start_time) ....: if start_time.tv_sec > target_time.tv_sec or (start_time.tv_sec == target_time.tv_sec and start_time.tv_nsec >= target_time.tv_nsec): ....: break ....: ....: cpdef void check_interrupt_only_occasionally(): ....: for i in range(10): ....: uninterruptible_sleep(0.8) ....: sig_check() ....: ''') sage: with ensure_interruptible_after(1): # not passing max_wait_after_interrupt will raise an error ....: check_interrupt_only_occasionally() Traceback (most recent call last): ... RuntimeError: Function is not interruptible within 1.0000 seconds, only after 1.60... seconds sage: with ensure_interruptible_after(1, max_wait_after_interrupt=0.9): ....: check_interrupt_only_occasionally()
>>> from sage.all import * >>> # needs sage.misc.cython >>> cython(r''' ... from posix.time cimport clock_gettime, CLOCK_REALTIME, timespec, time_t ... from cysignals.signals cimport sig_check ....: >>> cpdef void uninterruptible_sleep(double seconds): ... cdef timespec start_time, target_time ... clock_gettime(CLOCK_REALTIME, &start_time) ....: >>> cdef time_t floor_seconds = <time_t>seconds ... target_time.tv_sec = start_time.tv_sec + floor_seconds ... target_time.tv_nsec = start_time.tv_nsec + <long>((seconds - floor_seconds) * RealNumber('1e9')) ... if target_time.tv_nsec >= Integer(1000000000): ... target_time.tv_nsec -= Integer(1000000000) ... target_time.tv_sec += Integer(1) ....: >>> while True: ... clock_gettime(CLOCK_REALTIME, &start_time) ... if start_time.tv_sec > target_time.tv_sec or (start_time.tv_sec == target_time.tv_sec and start_time.tv_nsec >= target_time.tv_nsec): ... break ....: >>> cpdef void check_interrupt_only_occasionally(): ... for i in range(Integer(10)): ... uninterruptible_sleep(RealNumber('0.8')) ... sig_check() ... ''') >>> with ensure_interruptible_after(Integer(1)): # not passing max_wait_after_interrupt will raise an error ... check_interrupt_only_occasionally() Traceback (most recent call last): ... RuntimeError: Function is not interruptible within 1.0000 seconds, only after 1.60... seconds >>> with ensure_interruptible_after(Integer(1), max_wait_after_interrupt=RealNumber('0.9')): ... check_interrupt_only_occasionally()
- sage.doctest.util.make_recording_dict(D, st, gt)[source]¶
Auxiliary function for pickling.
EXAMPLES:
sage: from sage.doctest.util import make_recording_dict sage: D = make_recording_dict({'a':4,'d':42},set(),set(['not_here'])) sage: sorted(D.items()) [('a', 4), ('d', 42)] sage: D.got {'not_here'}
>>> from sage.all import * >>> from sage.doctest.util import make_recording_dict >>> D = make_recording_dict({'a':Integer(4),'d':Integer(42)},set(),set(['not_here'])) >>> sorted(D.items()) [('a', 4), ('d', 42)] >>> D.got {'not_here'}