summaryrefslogtreecommitdiffstats
path: root/Lib/_sitebuiltins.py
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2013-08-06 20:56:40 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2013-08-06 20:56:40 (GMT)
commit853395b44819f04aff85e575e746da4eabaa8347 (patch)
tree46d418bfea15bc6807412a2f95d8087d587504bf /Lib/_sitebuiltins.py
parent79ba3882ad189018ee21e2bd592a3ec6cd5d6094 (diff)
downloadcpython-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.py100
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)
+