Skip to content

Commit

Permalink
Trac #19923: Tab completion in interpreters is borked
Browse files Browse the repository at this point in the history
Tab completion broke in an IPython update; This fixes it:
{{{
sage: G = gap.SymmetricGroup(3)
sage: G.[TAB]
}}}

URL: http://trac.sagemath.org/19923
Reported by: vbraun
Ticket author(s): Volker Braun
Reviewer(s): Vincent Delecroix, Dima Pasechnik
  • Loading branch information
Release Manager authored and vbraun committed Feb 18, 2016
2 parents b9e84df + 93c3159 commit 3848d40
Show file tree
Hide file tree
Showing 19 changed files with 271 additions and 181 deletions.
15 changes: 8 additions & 7 deletions src/sage/interfaces/axiom.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,15 @@
from sage.env import DOT_SAGE
from pexpect import EOF
from sage.misc.multireplace import multiple_replace
from sage.interfaces.tab_completion import ExtraTabCompletion

# The Axiom commands ")what thing det" ")show Matrix" and ")display
# op det" commands, gives a list of all identifiers that begin in
# a certain way. This could maybe be useful somehow... (?) Also
# axiom has a lot a lot of ways for getting documentation from the
# system -- this could also be useful.

class PanAxiom(Expect):
class PanAxiom(ExtraTabCompletion, Expect):
"""
Interface to a PanAxiom interpreter.
"""
Expand Down Expand Up @@ -317,14 +318,14 @@ def _commands(self):
return s


def trait_names(self, verbose=True, use_disk_cache=True):
def _tab_completion(self, verbose=True, use_disk_cache=True):
"""
Returns a list of all the commands defined in Axiom and optionally
(per default) store them to disk.
EXAMPLES::
sage: c = axiom.trait_names(use_disk_cache=False, verbose=False) #optional - axiom
sage: c = axiom._tab_completion(use_disk_cache=False, verbose=False) #optional - axiom
sage: len(c) > 100 #optional - axiom
True
sage: 'factor' in c #optional - axiom
Expand All @@ -339,13 +340,13 @@ def trait_names(self, verbose=True, use_disk_cache=True):
True
"""
try:
return self.__trait_names
return self.__tab_completion
except AttributeError:
import sage.misc.persist
if use_disk_cache:
try:
self.__trait_names = sage.misc.persist.load(self._COMMANDS_CACHE)
return self.__trait_names
self.__tab_completion = sage.misc.persist.load(self._COMMANDS_CACHE)
return self.__tab_completion
except IOError:
pass
if verbose:
Expand All @@ -364,7 +365,7 @@ def trait_names(self, verbose=True, use_disk_cache=True):
names += [x[:-1]+"_q" for x in v if x.endswith("?")]
names += [x[:-1]+"_e" for x in v if x.endswith("!")]

self.__trait_names = names
self.__tab_completion = names
if len(v) > 200:
# Axiom is actually installed.
sage.misc.persist.save(v, self._COMMANDS_CACHE)
Expand Down
56 changes: 28 additions & 28 deletions src/sage/interfaces/gap.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,14 @@
from sage.env import SAGE_LOCAL, SAGE_EXTCODE, DOT_SAGE
from sage.misc.misc import is_in_string
from sage.misc.superseded import deprecation
from sage.misc.cachefunc import cached_method
from sage.interfaces.tab_completion import ExtraTabCompletion
import re
import os
import pexpect
import time
import platform
import string

GAP_DIR = os.path.join(DOT_SAGE, 'gap')

Expand Down Expand Up @@ -296,7 +299,7 @@ def _get_gap_memory_pool_size_MB():

############ Classes with methods for both the GAP3 and GAP4 interface

class Gap_generic(Expect):
class Gap_generic(ExtraTabCompletion, Expect):
r"""
Generic interface to the GAP3/GAP4 interpreters.
Expand Down Expand Up @@ -926,18 +929,6 @@ def function_call(self, function, args=None, kwds=None):
from sage.interfaces.expect import AsciiArtString
return AsciiArtString(res)

def trait_names(self):
"""
EXAMPLES::
sage: c = gap.trait_names()
sage: len(c) > 100
True
sage: 'Order' in c
True
"""
return []

def get_record_element(self, record, name):
r"""
Return the element of a GAP record identified by ``name``.
Expand Down Expand Up @@ -968,7 +959,7 @@ def get_record_element(self, record, name):
return self('%s.%s' % (record.name(), name))


class GapElement_generic(ExpectElement):
class GapElement_generic(ExtraTabCompletion, ExpectElement):
r"""
Generic interface to the GAP3/GAP4 interpreters.
Expand Down Expand Up @@ -1462,22 +1453,28 @@ def _function_element_class(self):
"""
return GapFunctionElement

def trait_names(self):
@cached_method
def _tab_completion(self):
"""
Return additional tab completion entries
OUTPUT:
List of strings
EXAMPLES::
sage: c = gap.trait_names()
sage: '{}' in gap._tab_completion()
False
sage: c = gap._tab_completion()
sage: len(c) > 100
True
sage: 'Order' in c
True
"""
try:
return self.__trait_names
except AttributeError:
self.__trait_names = eval(self.eval('NamesSystemGVars()')) + \
eval(self.eval('NamesUserGVars()'))
return self.__trait_names
names = eval(self.eval('NamesSystemGVars()')) + \
eval(self.eval('NamesUserGVars()'))
return [n for n in names if n[0] in string.ascii_letters]


############
Expand Down Expand Up @@ -1627,17 +1624,21 @@ def _latex_(self):
except RuntimeError:
return str(self)

def trait_names(self):
@cached_method
def _tab_completion(self):
"""
Return additional tab completion entries
OUTPUT:
List of strings
EXAMPLES::
sage: s5 = gap.SymmetricGroup(5)
sage: 'Centralizer' in s5.trait_names()
sage: 'Centralizer' in s5._tab_completion()
True
"""
if '__trait_names' in self.__dict__:
return self.__trait_names
import string
from sage.misc.misc import uniq
P = self.parent()
v = P.eval('$SAGE.OperationsAdmittingFirstArgument(%s)'%self.name())
Expand All @@ -1646,7 +1647,6 @@ def trait_names(self):
v = [ oper.split('"')[1] for oper in v ]
v = [ oper for oper in v if all(ch in string.ascii_letters for ch in oper) ]
v = uniq(v)
self.__trait_names = v
return v


Expand Down
34 changes: 27 additions & 7 deletions src/sage/interfaces/gap3.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@
#
# http://www.gnu.org/licenses/
#*****************************************************************************

from sage.misc.cachefunc import cached_method
from sage.interfaces.expect import Expect
from sage.interfaces.gap import Gap_generic, GapElement_generic

Expand All @@ -254,7 +256,7 @@ class Gap3(Gap_generic):
False
sage: gap3(2) == gap3(2) #optional - gap3
True
sage: gap3.trait_names() #optional - gap3
sage: gap3._tab_completion() #optional - gap3
[]
We test the interface behaves correctly after a keyboard interrupt::
Expand Down Expand Up @@ -607,6 +609,25 @@ def _install_hints(self):
gap3 = Gap3(command='/usr/local/bin/gap3')
""" % self.__gap3_command_string

@cached_method
def _tab_completion(self):
"""
Return additional tab completion entries
Currently this is empty
OUTPUT:
List of strings
EXAMPLES::
sage: gap3._tab_completion()
[]
"""
return []


gap3 = Gap3()

class GAP3Element(GapElement_generic):
Expand Down Expand Up @@ -822,7 +843,7 @@ def __getattr__(self, attrname):
return gap3_session.new('%s.%s' % (self.name(), attrname))
return gap3_session._function_element_class()(self, attrname)

def trait_names(self):
def _tab_completion(self):
r"""
Defines the list of methods and attributes that will appear for tab
completion.
Expand All @@ -835,15 +856,14 @@ def trait_names(self):
EXAMPLES::
sage: S5 = gap3.SymmetricGroup(5) #optional - gap3
sage: S5.trait_names() #optional - gap3
sage: S5._tab_completion() #optional - gap3
[..., 'ConjugacyClassesTry', 'ConjugateSubgroup', 'ConjugateSubgroups',
'Core', 'DegreeOperation', 'DerivedSeries', 'DerivedSubgroup',
'Difference', 'DimensionsLoewyFactors', 'DirectProduct', ...]
"""
if not hasattr(self, "__trait_names"):
self.__trait_names = self.recfields() + self.operations()
self.__trait_names.sort()
return self.__trait_names
names = self.recfields() + self.operations()
names.sort()
return names


import os
Expand Down
19 changes: 10 additions & 9 deletions src/sage/interfaces/giac.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@
import os

from sage.interfaces.expect import Expect, ExpectElement, ExpectFunction, FunctionElement, gc_disabled
from sage.interfaces.tab_completion import ExtraTabCompletion

import pexpect

Expand Down Expand Up @@ -476,35 +477,35 @@ def _commands(self):
v.sort()
return v

def trait_names(self, verbose=True, use_disk_cache=True):
def _tab_completion(self, verbose=True, use_disk_cache=True):
"""
Returns a list of all the commands defined in Giac and optionally
(per default) store them to disk.
EXAMPLES::
sage: c = giac.trait_names(use_disk_cache=False, verbose=False) # optional - giac
sage: c = giac._tab_completion(use_disk_cache=False, verbose=False) # optional - giac
sage: len(c) > 100 # optional - giac
True
sage: 'factors' in c # optional - giac
True
"""
try:
return self.__trait_names
return self.__tab_completion
except AttributeError:
import sage.misc.persist
if use_disk_cache:
try:
self.__trait_names = sage.misc.persist.load(COMMANDS_CACHE)
return self.__trait_names
self.__tab_completion = sage.misc.persist.load(COMMANDS_CACHE)
return self.__tab_completion
except IOError:
pass
if verbose:
print "\nBuilding Giac command completion list (this takes"
print "a few seconds only the first time you do it)."
print "To force rebuild later, delete %s."%COMMANDS_CACHE
v = self._commands()
self.__trait_names = v
self.__tab_completion = v
if len(v) > 200:
# Giac is actually installed.
sage.misc.persist.save(v, COMMANDS_CACHE)
Expand Down Expand Up @@ -887,15 +888,15 @@ def __cmp__(self, other):
else:
return 1

def trait_names(self):
def _tab_completion(self):
"""
EXAMPLES::
sage: a = giac(2) # optional - giac
sage: 'sin' in a.trait_names() # optional - giac
sage: 'sin' in a._tab_completion() # optional - giac
True
"""
return self.parent().trait_names()
return self.parent()._tab_completion()


def __len__(self):
Expand Down
13 changes: 7 additions & 6 deletions src/sage/interfaces/gp.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,12 @@

from expect import Expect, ExpectElement, ExpectFunction, FunctionElement
from sage.misc.misc import verbose
from sage.interfaces.tab_completion import ExtraTabCompletion
from sage.libs.pari.all import pari
import sage.rings.complex_field
## import sage.rings.all

class Gp(Expect):
class Gp(ExtraTabCompletion, Expect):
"""
Interface to the PARI gp interpreter.
Expand Down Expand Up @@ -329,11 +330,11 @@ def _read_in_file_command(self, filename):
"""
return 'read("%s")'%filename

def trait_names(self):
def _tab_completion(self):
"""
EXAMPLES::
sage: c = gp.trait_names()
sage: c = gp._tab_completion()
sage: len(c) > 100
True
sage: 'gcd' in c
Expand Down Expand Up @@ -1034,14 +1035,14 @@ def __del__(self):
# P = self._check_valid()
# return P.eval('printtex(%s)'%self.name())

def trait_names(self):
def _tab_completion(self):
"""
EXAMPLES::
sage: 'gcd' in gp(2).trait_names()
sage: 'gcd' in gp(2)._tab_completion()
True
"""
return self.parent().trait_names()
return self.parent()._tab_completion()


class GpFunctionElement(FunctionElement):
Expand Down
Loading

0 comments on commit 3848d40

Please sign in to comment.