| 897 | The following has been enabled in :trac:`11791`:: |
| 898 | |
| 899 | sage: cython_code = [ |
| 900 | ... 'from sage.structure.dynamic_class import dynamic_class', |
| 901 | ... 'from sage.misc.classcall_metaclass import ClasscallMetaclass', |
| 902 | ... 'from sage.all import cached_function', |
| 903 | ... 'MyMetaclass = dynamic_class("MyMetaclass",(ClasscallMetaclass,))', |
| 904 | ... 'class Bar2:', |
| 905 | ... ' __metaclass__ = MyMetaclass', |
| 906 | ... ' @cached_function', |
| 907 | ... ' def __classcall__(cls, R):', |
| 908 | ... ' return type.__call__(cls, R)', |
| 909 | ... ' def __init__(self,R):', |
| 910 | ... ' self.R = R', |
| 911 | ... ' def __repr__(self):', |
| 912 | ... ' return "[%s]"%self.R', |
| 913 | ... ' def __hash__(self):', |
| 914 | ... ' print "computing the hash"', |
| 915 | ... ' return int(12345)'] |
| 916 | sage: cython('\n'.join(cython_code)) |
| 917 | sage: print ''.join(open(sage_getfile(Bar2)).readlines()) |
| 918 | <BLANKLINE> |
| 919 | include "interrupt.pxi" # ctrl-c interrupt block support |
| 920 | include "stdsage.pxi" # ctrl-c interrupt block support |
| 921 | <BLANKLINE> |
| 922 | include "cdefs.pxi" |
| 923 | from sage.structure.dynamic_class import dynamic_class |
| 924 | from sage.misc.classcall_metaclass import ClasscallMetaclass |
| 925 | from sage.all import cached_function |
| 926 | MyMetaclass = dynamic_class("MyMetaclass",(ClasscallMetaclass,)) |
| 927 | class Bar2: |
| 928 | __metaclass__ = MyMetaclass |
| 929 | @cached_function |
| 930 | def __classcall__(cls, R): |
| 931 | return type.__call__(cls, R) |
| 932 | def __init__(self,R): |
| 933 | self.R = R |
| 934 | def __repr__(self): |
| 935 | return "[%s]"%self.R |
| 936 | def __hash__(self): |
| 937 | print "computing the hash" |
| 938 | return int(12345) |
| 939 | |
| 940 | The following was fixed in :trac:`9107` and :trac:`11791`:: |
| 941 | |
| 942 | sage: cython_code = [ |
| 943 | ... "from sage.structure.unique_representation import UniqueRepresentation", |
| 944 | ... "class A1(UniqueRepresentation):", |
| 945 | ... " class B1(UniqueRepresentation):", |
| 946 | ... " class C1: pass", |
| 947 | ... " class B2:", |
| 948 | ... " class C2: pass"] |
| 949 | sage: import os |
| 950 | sage: cython(os.linesep.join(cython_code)) |
| 951 | sage: from sage.misc.sageinspect import sage_getsource |
| 952 | sage: print sage_getsource(A1.B1) |
| 953 | class B1(UniqueRepresentation): |
| 954 | class C1: pass |
| 955 | |
906 | | return filename |
| 967 | # Verify that it is the correct file. Move on to a temporary file, |
| 968 | # if it turns out that it can not be found in the sage library: |
| 969 | try: |
| 970 | source_lines = open(filename).readlines() |
| 971 | return filename |
| 972 | except IOError: |
| 973 | try: |
| 974 | from sage.all import SAGE_TMP |
| 975 | raw_name = filename.split(os.sep)[-1] |
| 976 | newname = os.path.join(SAGE_TMP,'spyx','_'.join(raw_name.split('_')[:-1]),raw_name) |
| 977 | source_lines = open(newname).readlines() |
| 978 | return newname |
| 979 | except IOError: |
| 980 | pass |
| 1590 | The following has been enabled in trac ticket #11791:: |
| 1591 | |
| 1592 | sage: cython_code = [ |
| 1593 | ... 'from sage.structure.dynamic_class import dynamic_class', |
| 1594 | ... 'from sage.all import cached_function', |
| 1595 | ... 'from sage.misc.classcall_metaclass import ClasscallMetaclass', |
| 1596 | ... 'MyMetaclass = dynamic_class("MyMetaclass",(ClasscallMetaclass,))', |
| 1597 | ... 'class Bar2:', |
| 1598 | ... ' __metaclass__ = MyMetaclass', |
| 1599 | ... ' @cached_function', |
| 1600 | ... ' def __classcall__(cls, R):', |
| 1601 | ... ' return type.__call__(cls, R)', |
| 1602 | ... ' def __init__(self,R):', |
| 1603 | ... ' self.R = R', |
| 1604 | ... ' def __repr__(self):', |
| 1605 | ... ' return "[%s]"%self.R', |
| 1606 | ... ' def __hash__(self):', |
| 1607 | ... ' print "computing the hash"', |
| 1608 | ... ' return int(12345)'] |
| 1609 | sage: cython('\n'.join(cython_code)) |
| 1610 | sage: print ''.join(sage_getsourcelines(Bar2)[0]) |
| 1611 | class Bar2: |
| 1612 | __metaclass__ = MyMetaclass |
| 1613 | @cached_function |
| 1614 | def __classcall__(cls, R): |
| 1615 | return type.__call__(cls, R) |
| 1616 | def __init__(self,R): |
| 1617 | self.R = R |
| 1618 | def __repr__(self): |
| 1619 | return "[%s]"%self.R |
| 1620 | def __hash__(self): |
| 1621 | print "computing the hash" |
| 1622 | return int(12345) |
| 1623 | |
| 1634 | # If there is a custom _sage_src_lines_ that belongs to obj (and not to obj.__class__), |
| 1635 | # then we use it |
| 1636 | if getattr(obj,'_sage_src_lines_',None) is not getattr(type(obj),'_sage_src_lines_',None): |
| 1637 | # Rationale: |
| 1638 | # 1. If obj._sage_src_lines_ does not exist, then both are None. |
| 1639 | # 2. If obj.__class__._sage_src_lines_ exists and is the same as obj._sage_src_lines_, then |
| 1640 | # obj._sage_src_lines_() would return the source of obj.__class__ |
| 1641 | # In both cases, obj._sage_src_lines_() would not give the result that we want. |
| 1642 | try: |
| 1643 | return obj._sage_src_lines_() |
| 1644 | except TypeError: |
| 1645 | # In some cases (e.g., QQ['x','y']), obj._sage_src_lines_() dispatches to a function |
| 1646 | # that takes no arguments. |
| 1647 | pass |
1537 | | # If we can handle it, we do. We first try Python's inspect, and |
1538 | | # if that fails then we try _sage_getdoc_unformatted. We can not use |
1539 | | # the latter right away, since otherwise there is an import problem |
1540 | | # at sage startup, believe it or not. |
| 1656 | # If the above attempts fail then we test whether we face nested classes: |
| 1657 | from sage.misc.nested_class import NestedClassMetaclass |
| 1658 | if (isinstance(type(obj), NestedClassMetaclass) or issubclass(type(obj), NestedClassMetaclass) or not hasattr(obj,'__class__')): # and '.' in obj.__name__: |
| 1659 | return _sage_getsourcelines_name_with_dot(obj) |
| 1660 | |
| 1661 | # We try to find the position of the object's definition in its source file. |
| 1662 | # First, we try with the information provided by inspect.getdoc. |
1549 | | except IOError: |
1550 | | if (not hasattr(obj, '__class__')) or hasattr(obj,'__metaclass__'): |
1551 | | # That hapens for ParentMethods |
1552 | | # of categories |
1553 | | if '.' in obj.__name__: |
1554 | | return _sage_getsourcelines_name_with_dot(obj) |
1555 | | if inspect.isclass(obj): |
1556 | | try: |
1557 | | B = obj.__base__ |
1558 | | except AttributeError: |
1559 | | B = None |
1560 | | if B is not None and B is not obj: |
1561 | | return sage_getsourcelines(B) |
1562 | | if obj.__class__ != type: |
1563 | | return sage_getsourcelines(obj.__class__) |
1564 | | raise |
| 1673 | except (IOError, TypeError): |
| 1674 | pass |
1566 | | (orig, filename, lineno) = pos |
| 1676 | # Every attempt has failed. We thus resort |
| 1677 | # to the base, if obj is a class, or to |
| 1678 | # the object's class otherwise. |
| 1679 | if isinstance(obj, type): |
| 1680 | try: |
| 1681 | B = obj.__base__ |
| 1682 | except AttributeError: |
| 1683 | B = None |
| 1684 | if B is not None and B is not obj: |
| 1685 | return sage_getsourcelines(B) |
| 1686 | if obj.__class__ != type: |
| 1687 | return sage_getsourcelines(obj.__class__) |
| 1688 | raise |
| 1689 | |
| 1690 | # We know the position, but it could be that the file is not in |
| 1691 | # the sage library. sage_getfile knows how to cope with that case |
| 1692 | (orig, _, lineno) = pos |