diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2013-08-06 20:56:40 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2013-08-06 20:56:40 (GMT) |
commit | 853395b44819f04aff85e575e746da4eabaa8347 (patch) | |
tree | 46d418bfea15bc6807412a2f95d8087d587504bf /Lib/_sitebuiltins.py | |
parent | 79ba3882ad189018ee21e2bd592a3ec6cd5d6094 (diff) | |
download | cpython-853395b44819f04aff85e575e746da4eabaa8347.zip cpython-853395b44819f04aff85e575e746da4eabaa8347.tar.gz cpython-853395b44819f04aff85e575e746da4eabaa8347.tar.bz2 |
Issue #18621: Prevent the site module's patched builtins from keeping too many references alive for too long.
Diffstat (limited to 'Lib/_sitebuiltins.py')
-rw-r--r-- | Lib/_sitebuiltins.py | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/Lib/_sitebuiltins.py b/Lib/_sitebuiltins.py new file mode 100644 index 0000000..9aafa98 --- /dev/null +++ b/Lib/_sitebuiltins.py @@ -0,0 +1,100 @@ +""" +The objects used by the site module to add custom builtins. +""" + +# Those objects are almost immortal and they keep a reference to their module +# globals. Defining them in the site module would keep too many references +# alive. +# Note this means this module should also avoid keep things alive in its +# globals. + +import sys + +class Quitter(object): + def __init__(self, name, eof): + self.name = name + self.eof = eof + def __repr__(self): + return 'Use %s() or %s to exit' % (self.name, self.eof) + def __call__(self, code=None): + # Shells like IDLE catch the SystemExit, but listen when their + # stdin wrapper is closed. + try: + sys.stdin.close() + except: + pass + raise SystemExit(code) + + +class _Printer(object): + """interactive prompt objects for printing the license text, a list of + contributors and the copyright notice.""" + + MAXLINES = 23 + + def __init__(self, name, data, files=(), dirs=()): + import os + self.__name = name + self.__data = data + self.__lines = None + self.__filenames = [os.path.join(dir, filename) + for dir in dirs + for filename in files] + + def __setup(self): + if self.__lines: + return + data = None + for filename in self.__filenames: + try: + with open(filename, "r") as fp: + data = fp.read() + break + except OSError: + pass + if not data: + data = self.__data + self.__lines = data.split('\n') + self.__linecnt = len(self.__lines) + + def __repr__(self): + self.__setup() + if len(self.__lines) <= self.MAXLINES: + return "\n".join(self.__lines) + else: + return "Type %s() to see the full %s text" % ((self.__name,)*2) + + def __call__(self): + self.__setup() + prompt = 'Hit Return for more, or q (and Return) to quit: ' + lineno = 0 + while 1: + try: + for i in range(lineno, lineno + self.MAXLINES): + print(self.__lines[i]) + except IndexError: + break + else: + lineno += self.MAXLINES + key = None + while key is None: + key = input(prompt) + if key not in ('', 'q'): + key = None + if key == 'q': + break + + +class _Helper(object): + """Define the builtin 'help'. + This is a wrapper around pydoc.help (with a twist). + + """ + + def __repr__(self): + return "Type help() for interactive help, " \ + "or help(object) for help about object." + def __call__(self, *args, **kwds): + import pydoc + return pydoc.help(*args, **kwds) + |