A fast time mocking alternative to freezegun that wraps libfaketime.

Overview

python-libfaketime: fast date/time mocking

https://img.shields.io/badge/dynamic/json.svg?label=release&query=%24.status&maxAge=43200&uri=https%3A%2F%2Fwww.repominder.com%2Fbadge%2FeyJmdWxsX25hbWUiOiAic2ltb24td2ViZXIvcHl0aG9uLWxpYmZha2V0aW1lIn0%3D%2F&link=https%3A%2F%2Fwww.repominder.com%2F

python-libfaketime is a wrapper of libfaketime for python. Some brief details:

  • Linux and OS X, Pythons 3.5 through 3.8, pypy and pypy3
  • Mostly compatible with freezegun.
  • Microsecond resolution.
  • Accepts datetimes and strings that can be parsed by dateutil.
  • Not threadsafe.
  • Will break profiling. A workaround: use libfaketime.{begin, end}_callback to disable/enable your profiler (nosetest example).

Installation

$ pip install libfaketime

Usage

import datetime
from libfaketime import fake_time, reexec_if_needed

# libfaketime needs to be preloaded by the dynamic linker.
# This will exec the same command, but with the proper environment variables set.
# You can also skip this and manually manage your env (see "How to avoid re-exec").
reexec_if_needed()

def test_datetime_now():

    # fake_time can be used as a context_manager
    with fake_time('1970-01-01 00:00:01'):

        # Every calls to a date or datetime function returns the mocked date
        assert datetime.datetime.utcnow() == datetime.datetime(1970, 1, 1, 0, 0, 1)
        assert datetime.datetime.now() == datetime.datetime(1970, 1, 1, 0, 0, 1)
        assert time.time() == 1


# fake_time can also be used as a decorator
@fake_time('1970-01-01 00:00:01', tz_offset=12)
def test_datetime_now_with_offset():

    # datetime.utcnow returns the mocked datetime without offset
    assert datetime.datetime.utcnow() == datetime.datetime(1970, 1, 1, 0, 0, 1)

    # datetime.now returns the mocked datetime with the offset passed to fake_time
    assert datetime.datetime.now() == datetime.datetime(1970, 1, 1, 12, 0, 1)

Performance

libfaketime tends to be significantly faster than freezegun. Here's the output of a totally unscientific benchmark on my laptop:

$ python benchmark.py
re-exec with libfaketime dependencies
timing 1000 executions of <class 'libfaketime.fake_time'>
0.021755 seconds

$ python benchmark.py freezegun
timing 1000 executions of <function freeze_time at 0x10aaa1140>
6.561472 seconds

Use with py.test

The pytest-libfaketime plugin will automatically configure python-libfaketime for you:

$ pip install pytest-libfaketime

Alternatively, you can reexec manually from inside the pytest_configure hook:

# conftest.py
import os
import libfaketime

def pytest_configure():
    libfaketime.reexec_if_needed()
    _, env_additions = libfaketime.get_reload_information()
    os.environ.update(env_additions)

Use with tox

In your tox configuration file, under the testenv bloc, add the libfaketime environment variables to avoid re-execution:

setenv =
    LD_PRELOAD = {envsitepackagesdir}/libfaketime/vendor/libfaketime/src/libfaketime.so.1
    DONT_FAKE_MONOTONIC = 1
    FAKETIME_DID_REEXEC = true

Migration from freezegun

python-libfaketime should have the same behavior as freezegun when running on supported code. To migrate to it, you can run:

find . -type f -name "*.py" -exec sed -i 's/freezegun/libfaketime/g' "{}" \;

How to avoid re-exec

In some cases - especially when your tests start other processes - re-execing can cause unexpected problems. To avoid this, you can preload the necessary environment variables yourself. The necessary environment for your system can be found by running python-libfaketime on the command line:

$ python-libfaketime
export LD_PRELOAD="/home/foo/<snip>/vendor/libfaketime/src/libfaketime.so.1"
export DONT_FAKE_MONOTONIC="1"
export FAKETIME_DID_REEXEC=true

You can easily put this in a script like:

$ eval $(python-libfaketime)
$ pytest  # ...or any other code that imports libfaketime

Contributing and testing

Contributions are welcome! You should compile libfaketime before running tests:

make -C libfaketime/vendor/libfaketime

Then you can install requirements with pip install -r requirements.txt and use pytest and tox to run the tests.

uuid1 deadlock

Calling uuid.uuid1() multiple times while in a fake_time context can result in a deadlock when an OS-level uuid library is available. To avoid this, python-libtaketime will monkeypatch uuid._uuid_generate_time (or similar, it varies by version) to None inside a fake_time context. This may slow down uuid1 generation but should not affect correctness.

Comments
  • Seems to ignore timezones

    Seems to ignore timezones

    I am passing in strings which dateutil docs say should result in a timezone aware datetime being returned, eg @fake_time('7 Jul 2015 00:00:00 -0700')

    in my test I get:

    ipdb> datetime.utcnow()
    datetime.datetime(2015, 7, 6, 23, 0)
    

    i.e. it has parsed the date string, discarded the tzinfo which dateutil should have parsed, then returned '7 Jul 2015 00:00:00' in my local timezone as UTC

    It appears the tzinfo is being discarded by code in fake_time decorator

    opened by anentropic 13
  • Timezone issue on Python 3

    Timezone issue on Python 3

    Hello,

    The following test is failing on Ubuntu & Python 3.6.4 & Pytest:

    
    def test_libfaketime():
        now = datetime.now()
    
        with fake_time(now):
            new_now = datetime.now()
        assert abs((new_now - now).total_seconds()) < 2
    
        another_now = datetime.now()
        assert abs((another_now - now).total_seconds()) < 2
    
    

    with the stacktrace:

    >       assert abs((another_now - now).total_seconds()) < 2
    E       assert 7199.9999 < 2
    E        +  where 7199.9999 = abs(-7199.9999)
    E        +    where -7199.9999 = <built-in method total_seconds of datetime.timedelta object at 0x7fb9173b4210>()
    E        +      where <built-in method total_seconds of datetime.timedelta object at 0x7fb9173b4210> = (datetime.datetime(2018, 4, 12, 13, 0, 0, 22061) - datetime.datetime(2018, 4, 12, 15, 0, 0, 21961)).total_seconds
    
    

    It looks like the contextmanager is not configuring the time (or timezone?) back.

    It works fine with libfaketime==0.4.4

    opened by benjaminrigaud 10
  • Add console command that prints needed envvars

    Add console command that prints needed envvars

    When running nosetests or python manage.py test there are often left-over processes that are never reaped. As I use watch to run the tests every tenth of a second, that results in many, many processes :smile:

    I've traced this back to the re-exec that is performed. I would like to avoid that re-exec cleanly, but currently I have to have read the libfaketime source code to find out which envvars it wants. And keep the vars in sync ofcourse.

    So, let's add a console script that prints out the needed envvars, like ssh-agent does on start. Then you can call libfaketime and it will output:

    export LD_PRELOAD="/home/.../vendor/libfaketime/src/libfaketime.so.1"
    export FAKETIME_DID_REEXEC=true
    

    This can then be used at startup:

    eval $(libfaketime)
    nosetests
    
    opened by allardhoeve 10
  • Async process testing

    Async process testing

    I am running my unittest through a shell script Using this to set the env : eval $(python-libfaketime) and this to run : exec python -m unittest discover -v

    One of my functions calls async function, and the faketime is causing it loop forever.

    I went through the approaches mentioned here: https://github.com/simon-weber/python-libfaketime/issues/18

    But my python script is already on a different thread so can't reload the information from the main thread. Appreciate your help here.

    opened by shardool-freightwalla 8
  • Fix compatibility with non-pytz tzinfo objects

    Fix compatibility with non-pytz tzinfo objects

    My understanding of timezone code in Python is fairly limited, so please treat this as a proposal or a discussion point – it certainly needs review from someone with more understanding of the timezone ecosystem than myself.

    That said, I believe what has happened here is that python-libfaketime is depending on pytz specific functionality – the zone attribute. From my exploration of the pytz and dateutil codebases, it looks like the tzname method returns the same data. My understanding of the difference between pytz and dateutil is that with the former, tzinfo objects know about their owning datetime, whereas in the latter they don't (I could be wrong on this!).

    This PR uses these assumptions to change fake_time to call tzname(datetime_spec) instead of using .zone in the case that the datetime_spec is a datetime. A test is included to prevent regressions, although a review on whether this is the best wording of this test would be appreciated.

    This change fixes behaviour of python-libfaketime in a codebase that makes extensive use of dateutil and does not use pytz, where previously we had many test failures.

    opened by danpalmer 7
  • Work as a pytest plugin

    Work as a pytest plugin

    It would be trivial to work as a pytest plugin rather than mention the two lines of copy/paste that are necessary to integrate with pytest in the README. I'd be happy to add this functionality, I've written a few pytest plugins.

    opened by adamchainz 6
  • Should fake time work outside main thread if specified explicitly?

    Should fake time work outside main thread if specified explicitly?

    Hi,

    While debugging an issue on a different project I used python-libfaketime and accidentally noticed the fake_time context manager has an argument only_main_thread=True. Curious I tried only_main_thread=False, but got an exception:

    self = <libfaketime.fake_time object at 0x107308c50>
    
        def _should_patch_uuid(self):
            return hasattr(uuid, '_uuid_generate_time') and \
    >               not self._prev_spec and \
                    self._should_fake()
    E       AttributeError: 'fake_time' object has no attribute '_prev_spec'
    

    At first I thought it is just simply the case of _prev_spec missing and changed it to getattr(self, '_prev_spec', None), but now, upon closer inspection of the issue, it is only being set when only_main_thread=True.

    Therefore before submitting any pull request I wonder - is this expected behavior?

    opened by seporaitis 6
  • Add support for .tick()

    Add support for .tick()

    Freezegun provides support for the tick method so I added it in here as well.

    I didn't have much luck with the tests, two tests were already failing and when I added the tick test, the tests using the _assert_time_not_faked broke.

    Thanks!

    opened by canassa 6
  • LD_PRELOAD cannot be preload (cannont open share object file)

    LD_PRELOAD cannot be preload (cannont open share object file)

    When starting my tests I have this message in output when calling reexec_if_needed:

    ERROR: ld.so: object '[..]/src/libfaketimepytest/libfaketime/vendor/libfaketime/src/libfaketime.so.1' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
    ERROR: ld.so: object '[..]/src/libfaketimepytest/libfaketime/vendor/libfaketime/src/libfaketime.so.1' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
    

    Everything were working like a charm yesterday. Tests still running but failed because datetimes are wrong. I have already done: pip install --force --ignore-installed libfaketime in doubt, and problem still here.

    How can I debug it?

    opened by toxinu 6
  • Add proper timezone support

    Add proper timezone support

    • When passing in a datetime object with a timezone, adjust system clock correctly.
    • tz_offset is still supported when passing in a string as timestamp.
    • When passing in a datetime with timezone info, tz_offset is unsupported.
    opened by pieterdd 5
  • time.time gives unexpected results

    time.time gives unexpected results

    time.time does not seem to be mocked.

    import time, freezegun, libfaketime
    with freezegun.freeze_time("1970-01-01 00:00:01"):
        print(time.time())
    with libfaketime.fake_time("1970-01-01 00:00:01"):
        print(time.time())
    
    1.0
    1503929407.4042642
    

    I think we could expect it to work.

    $ env TZ=UTC faketime '1970-01-01 00:00:01' python -c "import time; print(time.time())"
    
    1.765857203
    
    opened by azmeuk 5
  • libfaketime build issues on gcc 11 and glibc 2.34

    libfaketime build issues on gcc 11 and glibc 2.34

    This patch resolves the issue for me https://github.com/wolfcw/libfaketime/commit/0d964363a4352b7ee358f523c3416d07378d4583

      make[1]: Entering directory '/build/libfaketime-2.0.0/libfaketime/vendor/libfaketime/src'
      gcc -o libfaketime.o -c -std=gnu99 -Wall -Wextra -Werror -Wno-nonnull-compare -fPIC -DPREFIX='"'/usr/local'"' -DLIBDIRNAME='"'/lib/faketime'"'   libfaketime.c
      In file included from /nix/store/1dlzfarjz8g5hx8zhcvsglbp8bqing4r-glibc-2.34-210-dev/include/string.h:519,
                       from libfaketime.c:36:
      In function ‘strncpy’,
          inlined from ‘fake_clock_gettime.part.0’ at libfaketime.c:2095:5:
      /nix/store/1dlzfarjz8g5hx8zhcvsglbp8bqing4r-glibc-2.34-210-dev/include/bits/string_fortified.h:95:10: error: ‘__builtin_strncpy’ specified bound 256 equals destination size [-Werror=stringop-truncation]
         95 |   return __builtin___strncpy_chk (__dest, __src, __len,
            |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         96 |                                   __glibc_objsize (__dest));
            |                                   ~~~~~~~~~~~~~~~~~~~~~~~~~
      cc1: all warnings being treated as errors
    
    opened by vlaci 0
  • Upgrade to libfaketime 0.9.10 to unbreak OSX Monterey support

    Upgrade to libfaketime 0.9.10 to unbreak OSX Monterey support

    libfaketime recently updated to 0.9.10, partly to fix an issue caused by upgrades to OSX Monterey. We're working around it currently using freezegun, but would prefer to drop that and keep on with python-libfaketime.

    opened by saltdotac 3
  • Support for tz offset in string datetime spec

    Support for tz offset in string datetime spec

    freezegun allows a datetime spec string to encode a timezone offset like this:

    >>> with freeze_time('2020-04-15 12:00 +1'):
    ...     print(repr(datetime.datetime.now(tz=dateutil.tz.UTC)))
    FakeDatetime(2020, 4, 15, 11, 0, tzinfo=tzutc())
    

    This produces a datetime with the offset given in the string, meaning that now will return datetimes relative to this.

    tz_offset behaviour differs from offset string

    This behaviour differs to the tz_offset parameter that fake_time takes, as with freezegun it's essentially pre-baked into the time, whereas fake_time then treats it as additive on top of the time spec.

    Depending on how this is implemented/documented, this might be a breaking change. I'm not sure how much this library aims to maintain compatibility with freezegun. From reading the documentation I had assumed it was API compatible for the public API, but issues like this ended up causing issues in porting our codebase.

    I'm not reporting this as a separate issue because it's not strictly an issue, but more just a gotcha for working around the main issue here – it bit us when we tried to use it as a workaround.


    Note: to implement support for this will likely require addressing #59.

    opened by danpalmer 0
  • Support offset-only tzinfo objects

    Support offset-only tzinfo objects

    It's possible for a tzinfo object to only have an offset and no named timezone. For example:

    >>> dateutil.parser.parse('2020-04-12 00:26 +1')
    datetime.datetime(2020, 4, 12, 0, 26, tzinfo=tzoffset(None, 3600))
    

    Because these don't have a name, we can't set the TZ environment variable with the name straight from tzname or zone (see #58 for some context on that difference).

    I'd suggest that a good solution might be to use the same behaviour as already exists here

    self.timezone_str = 'Etc/GMT{0:+}'.format(-tz_offset)
    

    It may be necessary to support both the tz_offset argument and the offset in the datetime_spec.tzinfo in the case that it's a datetime. It may also be necessary to combine these, but I'm not quite sure what the desired behaviour is when both a tz_offset and a timezone-aware datetime are provided.

    opened by danpalmer 0
  • pytest fixture makes 'python setup.py test' fail

    pytest fixture makes 'python setup.py test' fail

    Let's create an empty directory with a setup.cfg configured to use pytest.

    mkdir test; cd test
    virtualenv env
    echo "def test_foobar(): assert True" > test_foobar.py
    echo "from setuptools import setup; setup()" > setup.py
    cat > setup.cfg << EOL
    [options]
    setup_requires =
        pytest-runner
    
    [aliases]
    test=pytest
    EOL
    env/bin/pip install pytest libfaketime
    

    Without libfaketime fixtures, everything goes well.

    
    env/bin/python setup.py test
    # running pytest
    # running egg_info
    # creating UNKNOWN.egg-info
    # writing UNKNOWN.egg-info/PKG-INFO
    # writing dependency_links to UNKNOWN.egg-info/dependency_links.txt
    # writing top-level names to UNKNOWN.egg-info/top_level.txt
    # writing manifest file 'UNKNOWN.egg-info/SOURCES.txt'
    # reading manifest file 'UNKNOWN.egg-info/SOURCES.txt'
    # writing manifest file 'UNKNOWN.egg-info/SOURCES.txt'
    # running build_ext
    # ==== test session starts ====
    # platform linux -- Python 3.7.2, pytest-4.1.1, py-1.7.0, pluggy-0.8.1
    # rootdir: /home/eloi/test, inifile:
    # collected 1 item                                                                                                                                                                              
    # 
    # test_foobar.py .                                                                                                                                                                        # [100%]
    # 
    # ==== 1 passed in 0.01 seconds ====
    

    With the pytest fixture, python setup.py test fails.

    cat > conftest.py << EOL
    import os, libfaketime
    
    def pytest_configure():
        libfaketime.reexec_if_needed()
        _, env_additions = libfaketime.get_reload_information()
        os.environ.update(env_additions)
    EOL
    env/bin/python setup.py test
    # running pytest
    # running egg_info
    # writing UNKNOWN.egg-info/PKG-INFO
    # writing dependency_links to UNKNOWN.egg-info/dependency_links.txt
    # writing top-level names to UNKNOWN.egg-info/top_level.txt
    # reading manifest file 'UNKNOWN.egg-info/SOURCES.txt'
    # writing manifest file 'UNKNOWN.egg-info/SOURCES.txt'
    # running build_ext
    # re-exec with libfaketime dependencies
    # usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
    #    or: setup.py --help [cmd1 cmd2 ...]
    #    or: setup.py --help-commands
    #    or: setup.py cmd --help
    # 
    # error: no commands supplied
    
    opened by azmeuk 1
Owner
Simon Weber
Simon Weber
The blazing-fast Discord bot.

Wavy Wavy is an open-source multipurpose Discord bot built with pycord. Wavy is still in development, so use it at your own risk. Tools and services u

Wavy 7 Dec 27, 2022
Fast, efficient Blowfish cipher implementation in pure Python (3.4+).

blowfish This module implements the Blowfish cipher using only Python (3.4+). Blowfish is a block cipher that can be used for symmetric-key encryption

Jashandeep Sohi 41 Dec 31, 2022
Fully reproducible, Dockerized, step-by-step, tutorial on how to mock a "real-time" Kafka data stream from a timestamped csv file. Detailed blog post published on Towards Data Science.

time-series-kafka-demo Mock stream producer for time series data using Kafka. I walk through this tutorial and others here on GitHub and on my Medium

Maria Patterson 26 Nov 15, 2022
An interview engine for businesses, interview those who are actually qualified and are worth your time!

easyInterview V0.8B An interview engine for businesses, interview those who are actually qualified and are worth your time! Quick Overview You/the com

Vatsal Shukla 1 Nov 19, 2021
This is a small project written to help build documentation for projects in less time.

Documentation-Builder This is a small project written to help build documentation for projects in less time. About This project builds documentation f

Tom Jebbo 2 Jan 17, 2022
Sphinx-performance - CLI tool to measure the build time of different, free configurable Sphinx-Projects

CLI tool to measure the build time of different, free configurable Sphinx-Projec

useblocks 11 Nov 25, 2022
Wraps any WSGI application and makes it easy to send test requests to that application, without starting up an HTTP server.

WebTest This wraps any WSGI application and makes it easy to send test requests to that application, without starting up an HTTP server. This provides

Pylons Project 325 Dec 30, 2022
A scikit-learn compatible neural network library that wraps PyTorch

A scikit-learn compatible neural network library that wraps PyTorch. Resources Documentation Source Code Examples To see more elaborate examples, look

null 3.8k Feb 13, 2021
A scikit-learn compatible neural network library that wraps PyTorch

A scikit-learn compatible neural network library that wraps PyTorch. Resources Documentation Source Code Examples To see more elaborate examples, look

null 4.9k Jan 3, 2023
Wraps GEOS geometry functions in numpy ufuncs.

PyGEOS PyGEOS is a C/Python library with vectorized geometry functions. The geometry operations are done in the open-source geometry library GEOS. PyG

null 362 Dec 23, 2022
CLIPImageClassifier wraps clip image model from transformers

CLIPImageClassifier CLIPImageClassifier wraps clip image model from transformers. CLIPImageClassifier is initialized with the argument classes, these

Jina AI 6 Sep 12, 2022
TM1py is a Python package that wraps the TM1 REST API in a simple to use library.

By wrapping the IBM Planning Analytics (TM1) REST API in a concise Python framework, TM1py facilitates Python developments for TM1. Interacting with T

Cubewise CODE 147 Dec 15, 2022
An executor that wraps 3D mesh models and encodes 3D content documents to d-dimension vector.

3D Mesh Encoder An Executor that receives Documents containing point sets data in its blob attribute, with shape (N, 3) and encodes it to embeddings o

Jina AI 11 Dec 14, 2022
A Python script that wraps the gitleaks tool to enable scanning of multiple repositories in parallel

mpgitleaks A Python script that wraps the gitleaks tool to enable scanning of multiple repositories in parallel. The motivation behind writing this sc

Emilio Reyes 7 Dec 29, 2022
EasyRequests is a minimalistic HTTP-Request Library that wraps aiohttp and asyncio in a small package that allows for sequential, parallel or even single requests

EasyRequests EasyRequests is a minimalistic HTTP-Request Library that wraps aiohttp and asyncio in a small package that allows for sequential, paralle

Avi 1 Jan 27, 2022
Library written in Python that wraps Halo Infinite API.

haloinfinite Library written in Python that wraps Halo Infinite API. Before start It's unofficial, reverse-engineered, neither stable nor production r

Miguel Ferrer 4 Dec 28, 2022
Faster Twitch Alerts is a highly customizable, lightning-fast alternative to Twitch's slow mobile notification system

Faster Twitch Alerts What is "Faster Twitch Alerts"? Faster Twitch Alerts is a highly customizable, lightning-fast alternative to Twitch's slow mobile

null 6 Dec 22, 2022
A mocking library for requests

httmock A mocking library for requests for Python 2.7 and 3.4+. Installation pip install httmock Or, if you are a Gentoo user: emerge dev-python/httm

Patryk Zawadzki 452 Dec 28, 2022
HTTP client mocking tool for Python - inspired by Fakeweb for Ruby

HTTPretty 1.0.5 HTTP Client mocking tool for Python created by Gabriel Falcão . It provides a full fake TCP socket module. Inspired by FakeWeb Github

Gabriel Falcão 2k Jan 6, 2023
A utility for mocking out the Python Requests library.

Responses A utility library for mocking out the requests Python library. Note Responses requires Python 2.7 or newer, and requests >= 2.0 Installing p

Sentry 3.8k Jan 3, 2023