Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Lib/_strptime.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
strptime -- Calculates the time struct represented by the passed-in string

"""
import cachesreg
import time
import locale
import calendar
Expand Down Expand Up @@ -268,6 +269,7 @@ def compile(self, format):
_TimeRE_cache = TimeRE()
_CACHE_MAX_SIZE = 5 # Max number of regexes stored in _regex_cache
_regex_cache = {}
cachesreg.register(_regex_cache.clear)

def _calc_julian_from_U_or_W(year, week_of_year, day_of_week, week_starts_Mon):
"""Calculate the Julian day based on the year, week of the year, and day of
Expand Down
8 changes: 8 additions & 0 deletions Lib/cachesreg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
_clearers = []

def register(callback):
_clearers.append(callback)

def clear_caches():
for clear in _clearers[::-1]:
clear()
3 changes: 3 additions & 0 deletions Lib/ctypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from _ctypes import ArgumentError

from struct import calcsize as _calcsize
import cachesreg as _cachesreg

if __version__ != _ctypes_version:
raise Exception("Version number mismatch", __version__, _ctypes_version)
Expand Down Expand Up @@ -267,6 +268,8 @@ def _reset_cache():
POINTER(c_char).from_param = c_char_p.from_param
_pointer_type_cache[None] = c_void_p

_cachesreg.register(_reset_cache)

def create_unicode_buffer(init, size=None):
"""create_unicode_buffer(aString) -> character array
create_unicode_buffer(anInteger) -> character array
Expand Down
2 changes: 2 additions & 0 deletions Lib/distutils/dir_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
Utility functions for manipulating directories and directory trees."""

import os
import cachesreg as _cachesreg
import errno
from distutils.errors import DistutilsFileError, DistutilsInternalError
from distutils import log

# cache for by mkpath() -- in addition to cheapening redundant calls,
# eliminates redundant "creating /foo/bar/baz" messages in dry-run mode
_path_created = {}
_cachesreg.register(_path_created.clear)

# I don't use os.makedirs because a) it's new to Python 1.5.2, and
# b) it blows up if the directory already exists (I want to silently
Expand Down
6 changes: 6 additions & 0 deletions Lib/doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def _test():
]

import __future__
import cachesreg
import difflib
import inspect
import linecache
Expand Down Expand Up @@ -1853,6 +1854,11 @@ def report_failure(self, out, test, example, got):
# class, updated by testmod.
master = None

def _reset_master():
master = None

cachesreg.register(_reset_master)

def testmod(m=None, name=None, globs=None, verbose=None,
report=True, optionflags=0, extraglobs=None,
raise_on_error=False, exclude_empty=False):
Expand Down
3 changes: 3 additions & 0 deletions Lib/filecmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

"""

import cachesreg
import os
import stat
from itertools import filterfalse
Expand All @@ -26,6 +27,8 @@ def clear_cache():
"""Clear the filecmp cache."""
_cache.clear()

cachesreg.register(clear_cache)

def cmp(f1, f2, shallow=True):
"""Compare two files.

Expand Down
2 changes: 2 additions & 0 deletions Lib/functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
'partialmethod', 'singledispatch', 'singledispatchmethod']

from abc import get_cache_token
import cachesreg
from collections import namedtuple
# import types, weakref # Deferred to single_dispatch()
from reprlib import recursive_repr
Expand Down Expand Up @@ -630,6 +631,7 @@ def cache_clear():

wrapper.cache_info = cache_info
wrapper.cache_clear = cache_clear
cachesreg.register(cache_clear)
return wrapper

try:
Expand Down
2 changes: 2 additions & 0 deletions Lib/linecache.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
that name.
"""

import cachesreg
import functools
import sys
import os
Expand Down Expand Up @@ -33,6 +34,7 @@ def clearcache():
global cache
cache = {}

cachesreg.register(clearcache)

def getlines(filename, module_globals=None):
"""Get the lines for a Python source file from the cache.
Expand Down
2 changes: 2 additions & 0 deletions Lib/mimetypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
read_mime_types(file) -- parse one file, return a dictionary or None
"""

import cachesreg
import os
import sys
import posixpath
Expand Down Expand Up @@ -548,6 +549,7 @@ def _default_mime_types():
}


cachesreg.register(_default_mime_types)
_default_mime_types()


Expand Down
3 changes: 3 additions & 0 deletions Lib/re.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@

"""

import cachesreg
import enum
import sre_compile
import sre_parse
Expand Down Expand Up @@ -238,6 +239,8 @@ def purge():
_cache.clear()
_compile_repl.cache_clear()

cachesreg.register(purge)

def template(pattern, flags=0):
"Compile a template pattern, returning a Pattern object"
return _compile(pattern, flags|T)
Expand Down
3 changes: 3 additions & 0 deletions Lib/struct.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@
from _struct import *
from _struct import _clearcache
from _struct import __doc__
import cachesreg

cachesreg.register(_clearcache)
89 changes: 2 additions & 87 deletions Lib/test/libregrtest/refleak.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,100 +158,15 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs):


def clear_caches():
import gc

# Clear the warnings registry, so they can be displayed again
for mod in sys.modules.values():
if hasattr(mod, '__warningregistry__'):
del mod.__warningregistry__
import gc, cachesreg

# Flush standard output, so that buffered data is sent to the OS and
# associated Python objects are reclaimed.
for stream in (sys.stdout, sys.stderr, sys.__stdout__, sys.__stderr__):
if stream is not None:
stream.flush()

# Clear assorted module caches.
# Don't worry about resetting the cache if the module is not loaded
try:
distutils_dir_util = sys.modules['distutils.dir_util']
except KeyError:
pass
else:
distutils_dir_util._path_created.clear()
re.purge()

try:
_strptime = sys.modules['_strptime']
except KeyError:
pass
else:
_strptime._regex_cache.clear()

try:
urllib_parse = sys.modules['urllib.parse']
except KeyError:
pass
else:
urllib_parse.clear_cache()

try:
urllib_request = sys.modules['urllib.request']
except KeyError:
pass
else:
urllib_request.urlcleanup()

try:
linecache = sys.modules['linecache']
except KeyError:
pass
else:
linecache.clearcache()

try:
mimetypes = sys.modules['mimetypes']
except KeyError:
pass
else:
mimetypes._default_mime_types()

try:
filecmp = sys.modules['filecmp']
except KeyError:
pass
else:
filecmp._cache.clear()

try:
struct = sys.modules['struct']
except KeyError:
pass
else:
struct._clearcache()

try:
doctest = sys.modules['doctest']
except KeyError:
pass
else:
doctest.master = None

try:
ctypes = sys.modules['ctypes']
except KeyError:
pass
else:
ctypes._reset_cache()

try:
typing = sys.modules['typing']
except KeyError:
pass
else:
for f in typing._cleanups:
f()

cachesreg.clear_caches()
gc.collect()


Expand Down
3 changes: 1 addition & 2 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ def assertNotIsSubclass(self, cls, class_or_tuple, msg=None):
raise self.failureException(message)

def clear_caches(self):
for f in typing._cleanups:
f()
typing._clear_caches()


class Employee:
Expand Down
7 changes: 7 additions & 0 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"""

from abc import abstractmethod, abstractproperty
import cachesreg
import collections
import collections.abc
import contextlib
Expand Down Expand Up @@ -233,6 +234,12 @@ def _remove_dups_flatten(parameters):

_cleanups = []

def _clear_caches():
for f in _cleanups:
f()

cachesreg.register(_clear_caches)


def _tp_cache(func):
"""Internal wrapper caching __getitem__ of generic types with a fallback to
Expand Down
2 changes: 2 additions & 0 deletions Lib/urllib/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
test_urlparse.py provides a good indicator of parsing behavior.
"""

import cachesreg
import re
import sys
import collections
Expand Down Expand Up @@ -86,6 +87,7 @@ def clear_cache():
_parse_cache.clear()
_safe_quoters.clear()

cachesreg.register(clear_cache)

# Helpers for bytes handling
# For 3.2, we deliberately require applications that
Expand Down
3 changes: 3 additions & 0 deletions Lib/urllib/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@

import base64
import bisect
import cachesreg
import email
import hashlib
import http.client
Expand Down Expand Up @@ -302,6 +303,8 @@ def urlcleanup():
if _opener:
_opener = None

cachesreg.register(urlcleanup)

# copied from cookielib.py
_cut_port_re = re.compile(r":\d+$", re.ASCII)
def request_host(request):
Expand Down
10 changes: 10 additions & 0 deletions Lib/warnings.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Python part of the warnings subsystem."""

import sys
import cachesreg


__all__ = ["warn", "warn_explicit", "showwarning",
Expand Down Expand Up @@ -538,6 +539,15 @@ def _filters_mutated():
_warnings_defaults = False



def _clear_warning_registry():
# Clear the warnings registry, so they can be displayed again
for mod in sys.modules.values():
if hasattr(mod, '__warningregistry__'):
del mod.__warningregistry__

cachesreg.register(_clear_warning_registry)

# Module initialization
_processoptions(sys.warnoptions)
if not _warnings_defaults:
Expand Down
2 changes: 2 additions & 0 deletions Lib/xml/etree/ElementPath.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
# you, if needed.
##

import cachesreg as _cachesreg
import re

xpath_tokenizer_re = re.compile(
Expand Down Expand Up @@ -251,6 +252,7 @@ def select(context, result):
}

_cache = {}
_cachesreg.register(_cache.clear)

class _SelectorContext:
parent_map = None
Expand Down