Issue #18621: Prevent the site module's patched builtins from keeping too many references alive for too long.
This commit is contained in:
parent
79ba3882ad
commit
853395b448
|
@ -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)
|
||||||
|
|
101
Lib/site.py
101
Lib/site.py
|
@ -72,6 +72,7 @@ import sys
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import builtins
|
import builtins
|
||||||
|
import _sitebuiltins
|
||||||
|
|
||||||
# Prefixes for site-packages; add additional prefixes like /usr/local here
|
# Prefixes for site-packages; add additional prefixes like /usr/local here
|
||||||
PREFIXES = [sys.prefix, sys.exec_prefix]
|
PREFIXES = [sys.prefix, sys.exec_prefix]
|
||||||
|
@ -344,116 +345,30 @@ def setquit():
|
||||||
else:
|
else:
|
||||||
eof = 'Ctrl-D (i.e. EOF)'
|
eof = 'Ctrl-D (i.e. EOF)'
|
||||||
|
|
||||||
class Quitter(object):
|
builtins.quit = _sitebuiltins.Quitter('quit', eof)
|
||||||
def __init__(self, name):
|
builtins.exit = _sitebuiltins.Quitter('exit', eof)
|
||||||
self.name = name
|
|
||||||
def __repr__(self):
|
|
||||||
return 'Use %s() or %s to exit' % (self.name, 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)
|
|
||||||
builtins.quit = Quitter('quit')
|
|
||||||
builtins.exit = Quitter('exit')
|
|
||||||
|
|
||||||
|
|
||||||
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=()):
|
|
||||||
self.__name = name
|
|
||||||
self.__data = data
|
|
||||||
self.__files = files
|
|
||||||
self.__dirs = dirs
|
|
||||||
self.__lines = None
|
|
||||||
|
|
||||||
def __setup(self):
|
|
||||||
if self.__lines:
|
|
||||||
return
|
|
||||||
data = None
|
|
||||||
for dir in self.__dirs:
|
|
||||||
for filename in self.__files:
|
|
||||||
filename = os.path.join(dir, filename)
|
|
||||||
try:
|
|
||||||
with open(filename, "r") as fp:
|
|
||||||
data = fp.read()
|
|
||||||
break
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
if data:
|
|
||||||
break
|
|
||||||
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
|
|
||||||
|
|
||||||
def setcopyright():
|
def setcopyright():
|
||||||
"""Set 'copyright' and 'credits' in builtins"""
|
"""Set 'copyright' and 'credits' in builtins"""
|
||||||
builtins.copyright = _Printer("copyright", sys.copyright)
|
builtins.copyright = _sitebuiltins._Printer("copyright", sys.copyright)
|
||||||
if sys.platform[:4] == 'java':
|
if sys.platform[:4] == 'java':
|
||||||
builtins.credits = _Printer(
|
builtins.credits = _sitebuiltins._Printer(
|
||||||
"credits",
|
"credits",
|
||||||
"Jython is maintained by the Jython developers (www.jython.org).")
|
"Jython is maintained by the Jython developers (www.jython.org).")
|
||||||
else:
|
else:
|
||||||
builtins.credits = _Printer("credits", """\
|
builtins.credits = _sitebuiltins._Printer("credits", """\
|
||||||
Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
|
Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
|
||||||
for supporting Python development. See www.python.org for more information.""")
|
for supporting Python development. See www.python.org for more information.""")
|
||||||
here = os.path.dirname(os.__file__)
|
here = os.path.dirname(os.__file__)
|
||||||
builtins.license = _Printer(
|
builtins.license = _sitebuiltins._Printer(
|
||||||
"license", "See http://www.python.org/%.3s/license.html" % sys.version,
|
"license", "See http://www.python.org/%.3s/license.html" % sys.version,
|
||||||
["LICENSE.txt", "LICENSE"],
|
["LICENSE.txt", "LICENSE"],
|
||||||
[os.path.join(here, os.pardir), here, os.curdir])
|
[os.path.join(here, os.pardir), here, os.curdir])
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
def sethelper():
|
def sethelper():
|
||||||
builtins.help = _Helper()
|
builtins.help = _sitebuiltins._Helper()
|
||||||
|
|
||||||
def enablerlcompleter():
|
def enablerlcompleter():
|
||||||
"""Enable default readline configuration on interactive prompts, by
|
"""Enable default readline configuration on interactive prompts, by
|
||||||
|
|
|
@ -19,6 +19,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #18621: Prevent the site module's patched builtins from keeping
|
||||||
|
too many references alive for too long.
|
||||||
|
|
||||||
- Issue #4885: Add weakref support to mmap objects. Patch by Valerie Lambert.
|
- Issue #4885: Add weakref support to mmap objects. Patch by Valerie Lambert.
|
||||||
|
|
||||||
- Issue #8860: Fixed rounding in timedelta constructor.
|
- Issue #8860: Fixed rounding in timedelta constructor.
|
||||||
|
|
Loading…
Reference in New Issue