Skip to content

Commit

Permalink
Merge b23129e into 88f6990
Browse files Browse the repository at this point in the history
  • Loading branch information
hltbra committed Mar 6, 2017
2 parents 88f6990 + b23129e commit 164c26b
Showing 1 changed file with 63 additions and 12 deletions.
75 changes: 63 additions & 12 deletions freezegun/api.py
@@ -1,5 +1,6 @@
import datetime
import functools
import hashlib
import inspect
import sys
import time
Expand All @@ -18,6 +19,8 @@
real_strftime = time.strftime
real_date = datetime.date
real_datetime = datetime.datetime
real_date_objects = [real_time, real_localtime, real_gmtime, real_strftime, real_date, real_datetime]


try:
real_uuid_generate_time = uuid._uuid_generate_time
Expand All @@ -35,6 +38,60 @@
import copyreg


# keep a cache of module attributes otherwise freezegun will need to analyze too many modules all the time
_GLOBAL_MODULES_CACHE = None


def _get_global_modules_cache():
global _GLOBAL_MODULES_CACHE
if _GLOBAL_MODULES_CACHE is None:
_GLOBAL_MODULES_CACHE = _setup_modules_cache()
return _GLOBAL_MODULES_CACHE


def _get_module_attributes(module):
result = []
for attribute_name in dir(module):
try:
attribute_value = getattr(module, attribute_name)
except (ImportError, AttributeError, TypeError):
# For certain libraries, this can result in ImportError(_winreg) or AttributeError (celery)
continue
else:
result.append((attribute_name, attribute_value))
return result


def _setup_modules_cache():
# FIXME: move this definition to be at the top-level
real_time_object_ids = set(id(obj) for obj in real_date_objects)
result = {}
for mod_name, module in list(sys.modules.items()):
# ignore this module
if mod_name == __name__:
continue
date_attrs = []
all_module_attributes = _get_module_attributes(module)
for attribute_name, attribute_value in all_module_attributes:
if id(attribute_value) in real_time_object_ids:
date_attrs.append((attribute_name, attribute_value))
result[mod_name] = (_get_module_attributes_hash(module), date_attrs)
return result


def _get_module_attributes_hash(module):
return '{0}-{1}'.format(id(module), hashlib.md5(','.join(dir(module)).encode('utf-8')).hexdigest())


def _get_cached_module_attributes(mod_name, module):
global_modules_cache = _get_global_modules_cache()
module_hash, cached_attrs = global_modules_cache.get(mod_name, ('0', []))
if _get_module_attributes_hash(module) == module_hash:
return cached_attrs
else:
return _get_module_attributes(module)


# Stolen from six
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
Expand Down Expand Up @@ -399,7 +456,6 @@ def start(self):
('real_strftime', real_strftime, 'FakeStrfTime', fake_strftime),
('real_time', real_time, 'FakeTime', fake_time),
]
real_names = tuple(real_name for real_name, real, fake_name, fake in to_patch)
self.fake_names = tuple(fake_name for real_name, real, fake_name, fake in to_patch)
self.reals = dict((id(fake), real) for real_name, real, fake_name, fake in to_patch)
fakes = dict((id(real), fake) for real_name, real, fake_name, fake in to_patch)
Expand All @@ -412,24 +468,19 @@ def start(self):
warnings.filterwarnings('ignore')

for mod_name, module in list(sys.modules.items()):
if mod_name is None or module is None:
if mod_name is None or module is None or mod_name == __name__:
continue
elif mod_name.startswith(self.ignore):
continue
elif (not hasattr(module, "__name__") or module.__name__ in ('datetime', 'time')):
continue
for module_attribute in dir(module):
if module_attribute in real_names:
continue
try:
attribute_value = getattr(module, module_attribute)
except (ImportError, AttributeError, TypeError):
# For certain libraries, this can result in ImportError(_winreg) or AttributeError (celery)
continue

module_attrs = _get_cached_module_attributes(mod_name, module)
for attribute_name, attribute_value in module_attrs:
fake = fakes.get(id(attribute_value))
if fake:
setattr(module, module_attribute, fake)
add_change((module, module_attribute, attribute_value))
setattr(module, attribute_name, fake)
add_change((module, attribute_name, attribute_value))

datetime.datetime.times_to_freeze.append(time_to_freeze)
datetime.datetime.tz_offsets.append(self.tz_offset)
Expand Down

0 comments on commit 164c26b

Please sign in to comment.