# HG changeset patch
# User Simon King <simon.king@unijena.de>
# Date 1304590123 7200
# Node ID 592c0c930d1a191546007ccfe5b0aed8612c6f7b
# Parent 7ea0e1a8ca4e4675a320915b55c383ce955f3f1f
#11298: Improve introspection and interactive edit.
diff git a/doc/en/reference/misc.rst b/doc/en/reference/misc.rst
a

b


32  32  sage/misc/func_persist 
33  33  sage/misc/sage_eval 
34  34  sage/misc/random_testing 
 35  sage/misc/sageinspect 
35  36  sage/misc/sagedoc 
 37  sage/misc/edit_module 
36  38  sage/rings/arith 
37  39  sage/misc/nested_class 
38  40  sage/misc/nested_class_test 
diff git a/sage/misc/edit_module.py b/sage/misc/edit_module.py
a

b


1  1  """ 
2   edit_module 
 2  Edit the source code of Sage interactively 
3  3  
4   AUTHOR: * Nils Bruin 
5   * William Stein  touch up for inclusion in Sage. 
 4  AUTHORS: 
 5  
 6   Nils Bruin 
 7   William Stein  touch up for inclusion in Sage. 
 8   Simon King: Make it usable on extension classes that do not have 
 9  a docstring; include this module into the reference manual and 
 10  fix some syntax errors in the doc strings. 
6  11  
7  12  This module provides a routine to open the source file of a python 
8  13  object in an editor of your choice, if the source file can be figured 
… 
… 

68  73  the first line of a file is considered to be 1 rather than 0 
69  74  because most editors think that this is the case. 
70  75  
71   AUTHOR: 
72   Nils Bruin (20071003) 
 76  AUTHORS: 
 77  
 78   Nils Bruin (20071003) 
 79   Simon King (201105): Use :mod:`~sage.misc.sageinspect` to get the file 
 80  and the line. 
73  81  
74   EXAMPLE: 
 82  EXAMPLES:: 
 83  
75  84  sage: import sage.misc.edit_module as edit_module 
76   sage: edit_module.file_and_line(sage) # random output 
77   ('/usr/local/sage/default/devel/sage/sage/__init__.py', 1) 
 85  sage: edit_module.file_and_line(sage) 
 86  ('...sage/__init__.py', 0) 
 87  
 88  The following tests against a bug that was fixed in trac ticket #11298:: 
 89  
 90  sage: edit_module.file_and_line(x) 
 91  ('...sage/symbolic/expression.pyx', 191) 
 92  
78  93  """ 
79   d = inspect.getdoc(obj) 
80   ret = sage.misc.sageinspect._extract_embedded_position(d); 
81   if ret is not None: 
82   (_, filename, lineno) = ret 
83   else: 
84   filename = inspect.getsourcefile(obj) 
85   _,lineno = inspect.findsource(obj) 
 94  #d = inspect.getdoc(obj) 
 95  #ret = sage.misc.sageinspect._extract_embedded_position(d); 
 96  #if ret is not None: 
 97  # (_, filename, lineno) = ret 
 98  #else: 
 99  # filename = inspect.getsourcefile(obj) 
 100  # _,lineno = inspect.findsource(obj) 
 101  
86  102  # 
87  103  # for sage files, the registered source file is the result of the preparsing 
88  104  # these files end in ".py" and have "*autogenerated*" on the second line 
… 
… 

90  106  # 3 from the line number to compensate for the 3 lines that were prefixed 
91  107  # in the preparsing process 
92  108  # 
93   if filename.endswith('.py'): 
94   infile=open(filename,'r') 
95   infile.readline() 
96   if infile.readline().find("*autogenerated*") >= 0: 
97   filename=filename[:3]+'.sage' 
98   lineno = lineno3 
 109  from sage.misc.sageinspect import sage_getfile, sage_getsourcelines 
 110  filename = sage_getfile(obj) 
 111  lineno = sage_getsourcelines(obj)[1]  1 
 112  if filename.endswith('.py'): 
 113  infile=open(filename,'r') 
 114  infile.readline() 
 115  if infile.readline().find("*autogenerated*") >= 0: 
 116  filename=filename[:3]+'.sage' 
 117  lineno = lineno3 
99  118  
100  119  sageroot = sage.misc.sageinspect.SAGE_ROOT+'/' 
101  120  runpathpattern = '^'+sageroot+'local/lib/python[^/]*/sitepackages' 
… 
… 

110  129  Given a String.Template object, returns the fields. 
111  130  
112  131  AUTHOR: 
113   Nils Bruin (20071022) 
 132  
 133   Nils Bruin (20071022) 
114  134  
115   EXAMPLE: 
 135  EXAMPLES:: 
 136  
116  137  sage: from sage.misc.edit_module import template_fields 
117  138  sage: from string import Template 
118  139  sage: t=Template("Template ${one} with ${two} and ${three}") 
… 
… 

136  157  r""" 
137  158  Sets default edit template string. 
138  159  
139   It should reference ${file} and ${line}. This routine normally 
 160  It should reference ``${file}`` and ``${line}``. This routine normally 
140  161  needs to be called prior to using 'edit'. However, if the editor 
141  162  set in the shell variable EDITOR is known, then the system will 
142  163  substitute an appropriate template for you. See 
143  164  edit_module.template_defaults for the recognised templates. 
144  165  
145  166  AUTHOR: 
146   Nils Bruin (20071003) 
 167  
 168   Nils Bruin (20071003) 
147  169  
148   EXAMPLE: 
 170  EXAMPLES:: 
 171  
149  172  sage: from sage.misc.edit_module import set_edit_template 
150  173  sage: set_edit_template("echo EDIT ${file}:${line}") 
151  174  sage: edit(sage) # not tested 
… 
… 

173  196  of editors. If you want to use another editor, you should set the 
174  197  whole edit template via set_edit_template. 
175  198  
176   AUTHOR: 
177   Nils Bruin (20071005) 
 199  AUTHOR: 
178  200  
179   EXAMPLE: 
 201   Nils Bruin (20071005) 
 202  
 203  EXAMPLES:: 
 204  
180  205  sage: from sage.misc.edit_module import set_editor 
181  206  sage: set_editor('vi') 
182  207  sage: sage.misc.edit_module.edit_template.template 
… 
… 

193  218  Open source code of obj in editor of your choice. 
194  219  
195  220  INPUT: 
196   editor  str (default: None); If given, use specified editor. 
197   Choice is stored for next time. 
 221  
 222   editor  str (default: None); If given, use specified editor. Choice is stored for next time. 
198  223  
199  224  AUTHOR: 
200   Nils Bruin (20071003) 
201  225  
202   EXAMPLE: 
 226   Nils Bruin (20071003) 
 227  
 228  EXAMPLES: 
203  229  
204  230  This is a typical example of how to use this routine. 
 231  :: 
205  232  
206  233  # make some object obj 
207  234  sage: edit(obj) # not tested 
208  235  
209   Now for more details and customization: 
 236  Now for more details and customization:: 
210  237  
211  238  sage: import sage.misc.edit_module as m 
212  239  sage: m.set_edit_template("vi c ${line} ${file}") 
213  240  
214  241  In fact, since vi is a wellknown editor, you could also just use 
 242  :: 
215  243  
216  244  sage: m.set_editor("vi") 
217  245  
218   To illustrate: 
 246  To illustrate:: 
219  247  
220  248  sage: m.edit_template.template 
221  249  'vi c ${line} ${file}' 
… 
… 

223  251  And if your environment variable EDITOR is set to a recognised 
224  252  editor, you would not have to set anything. 
225  253  
226   To edit the source of an object, just type something like: 
 254  To edit the source of an object, just type something like:: 
227  255  
228  256  sage: edit(edit) # not tested 
229  257  """ 
diff git a/sage/misc/sageinspect.py b/sage/misc/sageinspect.py
a

b


188  188  sage: _extract_embedded_position(inspect.getdoc(var))[1][21:] 
189  189  'sage/calculus/var.pyx' 
190  190  
191   AUTHOR: 
192    William Stein 
193    Extensions by Nick Alexander 
 191  AUTHORS: 
 192  
 193   William Stein 
 194   Extensions by Nick Alexander 
194  195  """ 
195  196  if docstring is None: 
196  197  return None 
… 
… 

887  888  sage: sage_getfile(obj) 
888  889  '...sage/combinat/partition_algebra.py' 
889  890  
890   AUTHOR: 
 891  And here is another bug, fixed in trac ticket #11298:: 
 892  
 893  sage: P.<x,y> = QQ[] 
 894  sage: sage_getfile(P) 
 895  '...sage/rings/polynomial/multi_polynomial_libsingular.pyx' 
 896  
 897  AUTHORS: 
891  898  
892  899   Nick Alexander 
 900   Simon King 
893  901  """ 
894   # We try to extract from docstrings, because Python's inspect 
895   # will happily report compiled .so files 
896   d = inspect.getdoc(obj) 
 902  # We try to extract from docstrings, but not using Python's inspect 
 903  # because _sage_getdoc_unformatted is more robust. 
 904  d = _sage_getdoc_unformatted(obj) 
897  905  pos = _extract_embedded_position(d) 
898  906  if pos is not None: 
899  907  (_, filename, _) = pos 
… 
… 

903  911  if isclassinstance(obj): 
904  912  if isinstance(obj, functools.partial): 
905  913  return sage_getfile(obj.func) 
906   return inspect.getabsfile(obj.__class__) 
 914  return sage_getfile(obj.__class__) #inspect.getabsfile(obj.__class__) 
 915  
907  916  # No go? fall back to inspect. 
908  917  return inspect.getabsfile(obj) 
909  918  
… 
… 

992  1001  an instance of that class does not coincide with the argspec 
993  1002  of its call method. That behaviour is intended, since a 
994  1003  decorated method appears to have the generic signature 
995   `*args,**kwds`, but in fact it is only supposed to be called 
 1004  ``*args,**kwds``, but in fact it is only supposed to be called 
996  1005  with the arguments requested by the underlying undecorated 
997  1006  method. We saw an easy example above, namely `I.groebner_basis`. 
998  1007  Here is a more difficult:: 
… 
… 

1341  1350  ... 
1342  1351  ' raise ValueError, "k must be an integer or an integer + 1/2"\n'], 31) 
1343  1352  
 1353  Here are some cases that where covered in trac ticket #11298:: 
 1354  
 1355  sage: P.<x,y> = QQ[] 
 1356  sage: I = P*[x,y] 
 1357  sage: sage_getsourcelines(P) 
 1358  (['cdef class MPolynomialRing_libsingular(MPolynomialRing_generic):\n', 
 1359  " def __init__(self, base_ring, n, names, order='degrevlex'):\n", 
 1360  ... 
 1361  ' M.append(new_MP(self, p_Copy(tempvector,_ring)))\n', 
 1362  ' return M\n'], 225) 
 1363  sage: sage_getsourcelines(I) 
 1364  (['class MPolynomialIdeal( MPolynomialIdeal_singular_repr, \\\n', 
 1365  ... 
 1366  ' return result_ring.ideal(result)\n'], 2612) 
 1367  sage: x = var('x') 
 1368  sage: sage_getsourcelines(x) 
 1369  (['cdef class Expression(CommutativeRingElement):\n', 
 1370  ' cpdef object pyobject(self):\n', 
 1371  ... 
 1372  ' return self / x\n'], 191) 
 1373  
 1374  
1344  1375  AUTHORS: 
1345  1376  
1346  1377   William Stein 
1347  1378   Extensions by Nick Alexander 
1348  1379   Extension to interactive Cython code by Simon King 
 1380   Simon King: If a class has no docstring then let the class 
 1381  definition be found starting from the ``__init__`` method. 
1349  1382  """ 
1350  1383  
1351  1384  try: 
… 
… 

1360  1393  else: 
1361  1394  obj=obj.__class__ 
1362  1395  
1363   # If we can handle it, we do. This is because Python's inspect will 
1364   # happily dump binary for cython extension source code. 
 1396  # If we can handle it, we do. We first try Python's inspect, and 
 1397  # if that fails then we try _sage_getdoc_unformatted. We can not use 
 1398  # the latter right away, since otherwise there is an import problem 
 1399  # at sage startup, believe it or not. 
1365  1400  d = inspect.getdoc(obj) 
1366  1401  pos = _extract_embedded_position(d) 
1367  1402  if pos is None: 
1368   return inspect.getsourcelines(obj) 
 1403  d = _sage_getdoc_unformatted(obj) 
 1404  pos = _extract_embedded_position(d) 
 1405  if pos is None: 
 1406  try: 
 1407  return inspect.getsourcelines(obj) 
 1408  except IOError: 
 1409  if obj.__class__ != type: 
 1410  return sage_getsourcelines(obj.__class__) 
 1411  raise 
1369  1412  
1370  1413  (orig, filename, lineno) = pos 
1371  1414  try: 
… 
… 

1378  1421  source_lines = open(newname).readlines() 
1379  1422  except IOError: 
1380  1423  return None 
1381   
 1424  
 1425  # It is possible that the source lines belong to the __init__ method, 
 1426  # rather than to the class. So, we try to look back and find the class 
 1427  # definition. 
 1428  first_line = source_lines[lineno1] 
 1429  leading_blanks = len(first_line)len(first_line.lstrip()) 
 1430  if first_line.lstrip().startswith('def ') and "__init__" in first_line and obj.__name__!='__init__': 
 1431  ignore = False 
 1432  double_quote = None 
 1433  for lnb in xrange(lineno,0,1): 
 1434  new_first_line = source_lines[lnb1] 
 1435  nfl_strip = new_first_line.lstrip() 
 1436  if nfl_strip.startswith('"""'): 
 1437  if double_quote is None: 
 1438  double_quote=True 
 1439  if double_quote: 
 1440  ignore = not ignore 
 1441  elif nfl_strip.startswith("'''"): 
 1442  if double_quote is None: 
 1443  double_quote=False 
 1444  if double_quote is False: 
 1445  ignore = not ignore 
 1446  if ignore: 
 1447  continue 
 1448  if len(new_first_line)len(nfl_strip)<leading_blanks and nfl_strip: 
 1449  # We are not inside a doc string. So, if the indentation 
 1450  # is less than the indentation of the __init__ method 
 1451  # then we must be at the class definition! 
 1452  lineno = lnb 
 1453  break 
1382  1454  return _extract_source(source_lines, lineno), lineno 
1383  1455  
1384  1456  def sage_getvariablename(obj, omit_underscore_names=True): 