Repository: timkpaine/temporal-cache

Issue:
Move to GHA

Discussion:

Patch:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..dd84ea7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Smartphone (please complete the following information):**
+ - Device: [e.g. iPhone6]
+ - OS: [e.g. iOS8.1]
+ - Browser [e.g. stock browser, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..bbcbbe7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..3eed045
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,48 @@
+name: Build Status
+
+on:
+  push:
+  pull_request:
+  schedule:
+    # run on sunday nights
+    - cron:  '0 0 * * 0'
+
+jobs:
+  build:
+    runs-on: ${{ matrix.os }}
+
+    strategy:
+      matrix:
+        os: [ubuntu-latest, macos-latest, windows-latest]
+        python-version: [3.7, 3.8]
+
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v2
+      with:
+        python-version: ${{ matrix.python-version }}
+
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        python -m pip install -e .[dev]
+
+    - name: Lint
+      run: |
+        make lint
+
+    - name: Test
+      run: |
+        make tests
+
+    - name: Upload test results
+      uses: actions/upload-artifact@v2
+      with:
+        name: pytest-results-${{ matrix.os }}-${{ matrix.python-version }}
+        path: python_junit.xml
+      if: ${{ always() }}
+
+    - name: Upload coverage
+      uses: codecov/codecov-action@v1
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..3c89b7c
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,44 @@
+# This workflows will upload a Python Package using Twine when a release is created
+# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
+name: Publish Package
+
+on:
+  release:
+    types: [created]
+
+jobs:
+  deploy:
+    runs-on: ${{ matrix.os }}
+
+    strategy:
+      matrix:
+        os: [ubuntu-latest, macos-latest, windows-latest]
+        python-version: [3.7, 3.8]
+        
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v2
+      with:
+        python-version: ${{ matrix.python-version }}
+
+    - name: Install dependencies
+      run: |
+        python -m pip install -U pip setuptools wheel twine
+        python -m pip install -e .[dev]
+
+    - name: Lint
+      run: |
+        make lint
+
+    - name: Test
+      run: |
+        make tests
+
+    - name: Build and publish
+      env:
+        TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
+        TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
+      run: |
+        make dist
diff --git a/Makefile b/Makefile
index d4196ab..98b9715 100644
--- a/Makefile
+++ b/Makefile
@@ -1,23 +1,14 @@
 build:  ## Build the repository
 	python setup.py build 
 
-testpy: ## Clean and Make unit tests
-	python -m pytest -v temporalcache/tests --cov=temporalcache --junitxml=python_junit.xml --cov-report=xml --cov-branch
-
 tests:  ## run the tests
 	python -m pytest -vvv temporalcache/tests --cov=temporalcache --junitxml=python_junit.xml --cov-report=xml --cov-branch
 
 lint: ## run linter
-	python -m flake8 temporalcache 
+	python -m flake8 temporalcache setup.py
 
 fix:  ## run autopep8/tslint fix
-	python -m autopep8 --in-place -r -a -a temporalcache/
-
-annotate: ## MyPy type annotation check
-	mypy -s temporalcache  
-
-annotate_l: ## MyPy type annotation check - count only
-	mypy -s temporalcache | wc -l 
+	python -m black temporalcache/ setup.py
 
 clean: ## clean the repository
 	find . -name "__pycache__" | xargs  rm -rf 
@@ -29,9 +20,8 @@ clean: ## clean the repository
 install:  ## install to site-packages
 	python -m pip install .
 
-preinstall:  ## install dependencies
-	python -m pip install -r requirements.txt
-
+dev:
+	python -m pip install .[dev]
 
 docs:  ## make documentation
 	make -C ./docs html
@@ -39,9 +29,8 @@ docs:  ## make documentation
 
 dist:  ## dist to pypi
 	rm -rf dist build
-	python setup.py sdist
-	python setup.py bdist_wheel
-	python -m twine check dist/* && twine upload dist/*
+	python setup.py sdist bdist_wheel
+	python -m twine check dist/* && python -m twine upload dist/* --skip-existing
 
 # Thanks to Francoise at marmelab.com for this
 .DEFAULT_GOAL := help
diff --git a/README.md b/README.md
index 5aa4bb2..6162f19 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,16 @@
 # temporal-cache
-Time-based cache invalidation
 
+Time-based cache invalidation
 
-[![Build Status](https://dev.azure.com/tpaine154/pyEX/_apis/build/status/timkpaine.temporal-cache?branchName=main)](https://dev.azure.com/tpaine154/pyEX/_build/latest?definitionId=5&branchName=main)
-[![Coverage](https://img.shields.io/azure-devops/coverage/tpaine154/pyEX/5/main)](https://img.shields.io/azure-devops/coverage/tpaine154/pyEX/5)
+[![Build Status](https://github.com/timkpaine/temporal-cache/workflows/Build%20Status/badge.svg?branch=main)](https://github.com/timkpaine/temporal-cache/actions?query=workflow%3A%22Build+Status%22)
+[![Coverage](https://codecov.io/gh/timkpaine/temporal-cache/branch/main/graph/badge.svg?token=ag2j2TV2wE)](https://codecov.io/gh/timkpaine/temporal-cache)
 [![License](https://img.shields.io/github/license/timkpaine/temporal-cache.svg)](https://pypi.python.org/pypi/temporal-cache/)
 [![PyPI](https://img.shields.io/pypi/v/temporal-cache.svg)](https://pypi.python.org/pypi/temporal-cache/)
 [![Docs](https://img.shields.io/readthedocs/temporal-cache.svg)](https://temporal-cache.readthedocs.io)
 
 
 ## Install
+
 From pip
 
 `pip install temporal-cache`
@@ -19,6 +20,7 @@ Or from source
 `python setup.py install`
 
 ## Why?
+
 I needed something that would automagically refresh at 4:00pm when markets close.
 
 ```python3
@@ -29,6 +31,7 @@ I needed something that would automagically refresh at 4:00pm when markets close
 ```
 
 ## Interval Cache
+
 The interval cache expires every `time` interval since its first use
 
 ```python3
@@ -40,6 +43,7 @@ The interval cache expires every `time` interval since its first use
 
 
 ## Expire Cache
+
 The expire cache expires on the time given, in scheduler/cron style.
 
 ```python3
@@ -51,5 +55,5 @@ The expire cache expires on the time given, in scheduler/cron style.
 
 
 ## Caveats
-Python hashing symantics persist. Dicts will be frozen, lists will be converted to tuples. Users are advised to pre-freeze to avoid issues.
 
+Python hashing symantics persist. Dicts will be frozen, lists will be converted to tuples. Users are advised to pre-freeze to avoid issues.
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
deleted file mode 100644
index 863e7a7..0000000
--- a/azure-pipelines.yml
+++ /dev/null
@@ -1,134 +0,0 @@
-trigger:
-- main
-
-jobs:
-- job: 'Linux'
-  pool:
-    vmImage: 'ubuntu-latest'
-
-  strategy:
-    matrix:
-      Python37:
-        python.version: '3.7'
-      Python38:
-        python.version: '3.8'
-  
-  steps:
-    - task: UsePythonVersion@0
-      inputs:
-        versionSpec: '$(python.version)'
-      displayName: 'Use Python $(python.version)'
-
-    - script: |
-        python -m pip install --upgrade pip
-        pip install -e .[dev]
-      displayName: 'Install dependencies'
-
-    - script: |
-        make lint
-      displayName: 'Lint'
-
-    - script:
-        make tests
-      displayName: 'Test'
-
-    - task: PublishTestResults@2
-      condition: succeededOrFailed()
-      inputs:
-        testResultsFiles: 'python_junit.xml'
-        testRunTitle: 'Publish test results for Python $(python.version) $(manylinux_flag)'
-
-    - task: PublishCodeCoverageResults@1
-      inputs: 
-        codeCoverageTool: Cobertura
-        summaryFileLocation: '$(System.DefaultWorkingDirectory)/*coverage.xml'
-
-- job: 'Mac'
-  pool:
-    vmImage: 'macos-10.14'
-
-  strategy:
-    matrix:
-      Python37:
-        python.version: '3.7'
-      Python38:
-        python.version: '3.8'
-  
-  steps:
-    - task: UsePythonVersion@0
-      inputs:
-        versionSpec: '$(python.version)'
-      displayName: 'Use Python $(python.version)'
-
-    - script: |
-        python -m pip install --upgrade pip
-        pip install -e .[dev]
-      displayName: 'Install dependencies'
-
-    - script: |
-        make lint
-      displayName: 'Lint'
-
-    - script: |
-        make tests
-      displayName: 'Test'
-
-    - task: PublishTestResults@2
-      condition: succeededOrFailed()
-      inputs:
-        testResultsFiles: 'python_junit.xml'
-        testRunTitle: 'Publish test results for Python $(python.version) $(manylinux_flag)'
-
-    - task: PublishCodeCoverageResults@1
-      inputs: 
-        codeCoverageTool: Cobertura
-        summaryFileLocation: '$(System.DefaultWorkingDirectory)/*coverage.xml'
-
-- job: 'Windows'
-  pool:
-    vmImage: 'vs2017-win2016'
-
-  strategy:
-    matrix:
-      Python37:
-        python.version: '3.7'
-      Python38:
-        python.version: '3.8'
-  
-  steps:
-    - task: UsePythonVersion@0
-      inputs:
-        versionSpec: '$(python.version)'
-      displayName: 'Use Python $(python.version)'
-
-    - script: |
-        which python > python.txt
-        set /p PYTHON=<python.txt
-        ln -s %PYTHON% %PYTHON%$(python.version)
-        python --version
-        which python$(python.version)
-      displayName: "Which python"
-
-    - script: |
-        python -m pip install --upgrade pip
-        pip install -e .[dev]
-      displayName: 'Install dependencies'
-
-    - script: |
-        make lint
-      displayName: 'Lint'
-
-    - script: |
-        make tests
-      displayName: 'Test'
-
-    - task: PublishTestResults@2
-      condition: succeededOrFailed()
-      inputs:
-        testResultsFiles: 'python_junit.xml'
-        testRunTitle: 'Publish test results for Python $(python.version) $(manylinux_flag)'
-
-    - task: PublishCodeCoverageResults@1
-      inputs: 
-        codeCoverageTool: Cobertura
-        summaryFileLocation: '$(System.DefaultWorkingDirectory)/*coverage.xml'
diff --git a/setup.cfg b/setup.cfg
index fae2fd5..ae5ecac 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -3,6 +3,10 @@ universal=1
 
 [metadata]
 description_file = README.md
+long_description_content_type=text/markdown
 
 [flake8]
-max-line-length=200
\ No newline at end of file
+ignore=E203, W503
+max-line-length=200
+per-file-ignores=
+    temporalcache/__init__.py:F401
diff --git a/setup.py b/setup.py
index bc4d919..471fa38 100644
--- a/setup.py
+++ b/setup.py
@@ -1,67 +1,74 @@
-from setuptools import setup, find_packages
-from codecs import open
+import io
 import os
 import os.path
-import io
+from codecs import open
 
-name = 'temporal-cache'
+from setuptools import find_packages, setup
+
+name = "temporal-cache"
 here = os.path.abspath(os.path.dirname(__file__))
 pjoin = os.path.join
 
 
-def get_version(file, name='__version__'):
+def get_version(file, name="__version__"):
     path = os.path.realpath(file)
     version_ns = {}
     with io.open(path, encoding="utf8") as f:
         exec(f.read(), {}, version_ns)
     return version_ns[name]
 
-version = get_version(pjoin(here, 'temporalcache', '_version.py'))
 
-with open(pjoin(here, 'README.md'), encoding='utf-8') as f:
+version = get_version(pjoin(here, "temporalcache", "_version.py"))
+
+with open(pjoin(here, "README.md"), encoding="utf-8") as f:
     long_description = f.read()
 
 
 requires = [
-    'frozendict>=1.2',
-    'tzlocal>=2.0.0',
+    "frozendict>=1.2",
+    "tzlocal>=2.0.0",
 ]
 
 requires_dev = [
-    'flake8>=3.7.8',
-    'mock',
-    'pytest>=4.3.0',
-    'pytest-cov>=2.6.1',
-    'Sphinx>=1.8.4',
-    'sphinx-markdown-builder>=0.5.2',
+    "black>=20.",
+    "bump2version>=1.0.0",
+    "flake8>=3.7.8",
+    "flake8-black>=0.2.1",
+    "mock",
+    "pytest>=4.3.0",
+    "pytest-cov>=2.6.1",
+    "Sphinx>=1.8.4",
+    "sphinx-markdown-builder>=0.5.2",
 ] + requires
 
 
 setup(
     name=name,
     version=version,
-    description='Time based function caching',
+    description="Time based function caching",
     long_description=long_description,
-    long_description_content_type='text/markdown',
-    url='https://github.com/timkpaine/{name}'.format(name=name),
-    author='Tim Paine',
-    author_email='timothy.k.paine@gmail.com',
-    license='Apache 2.0',
+    long_description_content_type="text/markdown",
+    url="https://github.com/timkpaine/{name}".format(name=name),
+    author="Tim Paine",
+    author_email="timothy.k.paine@gmail.com",
+    license="Apache 2.0",
     install_requires=requires,
     extras_require={
-        'dev': requires_dev,
+        "dev": requires_dev,
     },
-
     classifiers=[
-        'Development Status :: 3 - Alpha',
-        'Programming Language :: Python :: 3',
-        'Programming Language :: Python :: 3.6',
-        'Programming Language :: Python :: 3.7',
-        'Programming Language :: Python :: 3.8',
+        "Development Status :: 3 - Alpha",
+        "Programming Language :: Python :: 3",
+        "Programming Language :: Python :: 3.6",
+        "Programming Language :: Python :: 3.7",
+        "Programming Language :: Python :: 3.8",
     ],
-
-    keywords='analytics tools',
-    packages=find_packages(exclude=['tests', ]),
+    keywords="analytics tools",
+    packages=find_packages(
+        exclude=[
+            "tests",
+        ]
+    ),
     include_package_data=True,
-    zip_safe=False
+    zip_safe=False,
 )
diff --git a/temporalcache/__init__.py b/temporalcache/__init__.py
index 8b7b87f..7f51372 100644
--- a/temporalcache/__init__.py
+++ b/temporalcache/__init__.py
@@ -1,5 +1,8 @@
-from .interval import interval, minutely, hourly, daily, monthly  # noqa: F401
-from .expire import expire, minutely as expire_minutely, hourly as expire_hourly, daily as expire_daily, monthly as expire_monthly  # noqa: F401
-from .utils import TCException, StorageBase  # noqa: F401
-
-from ._version import __version__  # noqa: F401
+from ._version import __version__
+from .expire import daily as expire_daily
+from .expire import expire
+from .expire import hourly as expire_hourly
+from .expire import minutely as expire_minutely
+from .expire import monthly as expire_monthly
+from .interval import daily, hourly, interval, minutely, monthly
+from .utils import StorageBase, TCException
diff --git a/temporalcache/_version.py b/temporalcache/_version.py
index a3aed8a..7632d17 100644
--- a/temporalcache/_version.py
+++ b/temporalcache/_version.py
@@ -1,22 +1,21 @@
 from collections import namedtuple
 
-VersionInfo = namedtuple('VersionInfo', [
-    'major',
-    'minor',
-    'micro',
-    'releaselevel',
-    'serial'
-])
+VersionInfo = namedtuple(
+    "VersionInfo", ["major", "minor", "micro", "releaselevel", "serial"]
+)
 
 # DO NOT EDIT THIS DIRECTLY!  It is managed by bumpversion
-version_info = VersionInfo(0, 1, 2, 'final', 0)
+version_info = VersionInfo(0, 1, 2, "final", 0)
 
-_specifier_ = {'alpha': 'a', 'beta': 'b', 'candidate': 'rc', 'final': ''}
+_specifier_ = {"alpha": "a", "beta": "b", "candidate": "rc", "final": ""}
 
-__version__ = '{}.{}.{}{}'.format(
+__version__ = "{}.{}.{}{}".format(
     version_info.major,
     version_info.minor,
     version_info.micro,
-    (''
-     if version_info.releaselevel == 'final'
-     else _specifier_[version_info.releaselevel] + "." + str(version_info.serial)))
+    (
+        ""
+        if version_info.releaselevel == "final"
+        else _specifier_[version_info.releaselevel] + "." + str(version_info.serial)
+    ),
+)
diff --git a/temporalcache/expire.py b/temporalcache/expire.py
index b506e69..538fd06 100644
--- a/temporalcache/expire.py
+++ b/temporalcache/expire.py
@@ -8,38 +8,60 @@ from .persistent_lru_cache import persistent_lru_cache
 from .utils import should_expire, TCException
 
 
-def expire(second=None, minute=None, hour=None, day=None, day_of_week=None, week=None, month=None, tz=None, maxsize=128, persistent='', custom=None, **kwargs):
-    '''Expires all entries in the cache @ whole number time
-
-        for example, @expire(0, 30, 16) will expire the cache at 4:30pm every day
-    '''
-    if not any((second is not None, minute is not None, hour is not None, day is not None, week is not None, month is not None)):
+def expire(
+    second=None,
+    minute=None,
+    hour=None,
+    day=None,
+    day_of_week=None,
+    week=None,
+    month=None,
+    tz=None,
+    maxsize=128,
+    persistent="",
+    custom=None,
+    **kwargs
+):
+    """Expires all entries in the cache @ whole number time
+
+    for example, @expire(0, 30, 16) will expire the cache at 4:30pm every day
+    """
+    if not any(
+        (
+            second is not None,
+            minute is not None,
+            hour is not None,
+            day is not None,
+            week is not None,
+            month is not None,
+        )
+    ):
         second = 0
 
     if second is not None and second >= 60:
-        raise TCException('second must be < 60')
+        raise TCException("second must be < 60")
 
     if minute is not None and minute >= 60:
-        raise TCException('minute must be < 60')
+        raise TCException("minute must be < 60")
 
     if hour is not None and hour >= 24:
-        raise TCException('minute must be < 24')
+        raise TCException("minute must be < 24")
 
     if day is not None and (day <= 0 or day > 31):
-        raise TCException('day must be > 0, < 32')
+        raise TCException("day must be > 0, < 32")
     # elif day is not None:
     #     day += 1  # for convenience
 
     if day_of_week is not None and (day_of_week <= 0 or day > 8):
-        raise TCException('day_of_weel must be > 0, < 8')
+        raise TCException("day_of_weel must be > 0, < 8")
 
     if week is not None and (week <= 0 or week > 5):
-        raise TCException('day must be > 0, < 6')
+        raise TCException("day must be > 0, < 6")
     # elif week is not None:
     #     week += 1  # for convenience
 
     if month is not None and (month <= 0 or month > 12):
-        raise TCException('month must be >0, < 13')
+        raise TCException("month must be >0, < 13")
     # elif month is not None:
     #     month += 1  # for convenience
 
@@ -69,37 +91,89 @@ def expire(second=None, minute=None, hour=None, day=None, day_of_week=None, week
             nonlocal last
 
             now = datetime.datetime.now(tz=tz)
-            if should_expire(last, now, second, minute, hour, day, day_of_week, week, month):
+            if should_expire(
+                last, now, second, minute, hour, day, day_of_week, week, month
+            ):
                 foo.cache_clear()
             last = now
 
-            args = tuple([frozendict(arg) if isinstance(arg, dict) else tuple(arg) if isinstance(arg, list) else arg for arg in args])
-            kwargs = {k: frozendict(v) if isinstance(v, dict) else tuple(v) if isinstance(v, list) else v for k, v in kwargs.items()}
+            args = tuple(
+                [
+                    frozendict(arg)
+                    if isinstance(arg, dict)
+                    else tuple(arg)
+                    if isinstance(arg, list)
+                    else arg
+                    for arg in args
+                ]
+            )
+            kwargs = {
+                k: frozendict(v)
+                if isinstance(v, dict)
+                else tuple(v)
+                if isinstance(v, list)
+                else v
+                for k, v in kwargs.items()
+            }
 
             return foo(*args, **kwargs)
+
         return _wrapped_foo
+
     return _wrapper
 
 
-def minutely(on=0, tz=None, maxsize=128, persistent='', custom=None, **kwargs):
+def minutely(on=0, tz=None, maxsize=128, persistent="", custom=None, **kwargs):
     def _wrapper(foo):
-        return expire(second=on, tz=tz, maxsize=maxsize, persistent=persistent, custom=custom, **kwargs)(foo)
+        return expire(
+            second=on,
+            tz=tz,
+            maxsize=maxsize,
+            persistent=persistent,
+            custom=custom,
+            **kwargs
+        )(foo)
+
     return _wrapper
 
 
-def hourly(on=0, tz=None, maxsize=128, persistent='', custom=None, **kwargs):
+def hourly(on=0, tz=None, maxsize=128, persistent="", custom=None, **kwargs):
     def _wrapper(foo):
-        return expire(minute=on, tz=tz, maxsize=maxsize, persistent=persistent, custom=custom, **kwargs)(foo)
+        return expire(
+            minute=on,
+            tz=tz,
+            maxsize=maxsize,
+            persistent=persistent,
+            custom=custom,
+            **kwargs
+        )(foo)
+
     return _wrapper
 
 
-def daily(on=0, tz=None, maxsize=128, persistent='', custom=None, **kwargs):
+def daily(on=0, tz=None, maxsize=128, persistent="", custom=None, **kwargs):
     def _wrapper(foo):
-        return expire(hour=on, tz=tz, maxsize=maxsize, persistent=persistent, custom=custom, **kwargs)(foo)
+        return expire(
+            hour=on,
+            tz=tz,
+            maxsize=maxsize,
+            persistent=persistent,
+            custom=custom,
+            **kwargs
+        )(foo)
+
     return _wrapper
 
 
-def monthly(on=0, tz=None, maxsize=128, persistent='', custom=None, **kwargs):
+def monthly(on=0, tz=None, maxsize=128, persistent="", custom=None, **kwargs):
     def _wrapper(foo):
-        return expire(day=on, tz=tz, maxsize=maxsize, persistent=persistent, custom=custom, **kwargs)(foo)
+        return expire(
+            day=on,
+            tz=tz,
+            maxsize=maxsize,
+            persistent=persistent,
+            custom=custom,
+            **kwargs
+        )(foo)
+
     return _wrapper
diff --git a/temporalcache/interval.py b/temporalcache/interval.py
index 1370845..9f55a84 100644
--- a/temporalcache/interval.py
+++ b/temporalcache/interval.py
@@ -5,8 +5,20 @@ from .persistent_lru_cache import persistent_lru_cache
 from .utils import calc
 
 
-def interval(seconds=0, minutes=0, hours=0, days=0, weeks=0, months=0, years=0, maxsize=128, persistent='', custom=None, **kwargs):
-    '''Expires all entries in the cache every interval'''
+def interval(
+    seconds=0,
+    minutes=0,
+    hours=0,
+    days=0,
+    weeks=0,
+    months=0,
+    years=0,
+    maxsize=128,
+    persistent="",
+    custom=None,
+    **kwargs
+):
+    """Expires all entries in the cache every interval"""
     if not any((seconds, minutes, hours, days, weeks, months, years)):
         seconds = 1
 
@@ -25,36 +37,68 @@ def interval(seconds=0, minutes=0, hours=0, days=0, weeks=0, months=0, years=0,
             nonlocal last
 
             now = datetime.datetime.now()
-            if (now - last).total_seconds() > calc(seconds, minutes, hours, days, weeks, months, years):
+            if (now - last).total_seconds() > calc(
+                seconds, minutes, hours, days, weeks, months, years
+            ):
                 foo.cache_clear()
             last = now
 
-            args = tuple([frozendict(arg) if isinstance(arg, dict) else tuple(arg) if isinstance(arg, list) else arg for arg in args])
-            kwargs = {k: frozendict(v) if isinstance(v, dict) else tuple(v) if isinstance(v, list) else v for k, v in kwargs.items()}
+            args = tuple(
+                [
+                    frozendict(arg)
+                    if isinstance(arg, dict)
+                    else tuple(arg)
+                    if isinstance(arg, list)
+                    else arg
+                    for arg in args
+                ]
+            )
+            kwargs = {
+                k: frozendict(v)
+                if isinstance(v, dict)
+                else tuple(v)
+                if isinstance(v, list)
+                else v
+                for k, v in kwargs.items()
+            }
             return foo(*args, **kwargs)
+
         return _wrapped_foo
+
     return _wrapper
 
 
-def minutely(maxsize=128, persistent='', custom=None, **kwargs):
+def minutely(maxsize=128, persistent="", custom=None, **kwargs):
     def _wrapper(foo):
-        return interval(seconds=60, maxsize=maxsize, persistent=persistent, custom=custom, **kwargs)(foo)
+        return interval(
+            seconds=60, maxsize=maxsize, persistent=persistent, custom=custom, **kwargs
+        )(foo)
+
     return _wrapper
 
 
-def hourly(maxsize=128, persistent='', custom=None, **kwargs):
+def hourly(maxsize=128, persistent="", custom=None, **kwargs):
     def _wrapper(foo):
-        return interval(minutes=60, maxsize=maxsize, persistent=persistent, custom=custom, **kwargs)(foo)
+        return interval(
+            minutes=60, maxsize=maxsize, persistent=persistent, custom=custom, **kwargs
+        )(foo)
+
     return _wrapper
 
 
-def daily(maxsize=128, persistent='', custom=None, **kwargs):
+def daily(maxsize=128, persistent="", custom=None, **kwargs):
     def _wrapper(foo):
-        return interval(hours=24, maxsize=maxsize, persistent=persistent, custom=custom, **kwargs)(foo)
+        return interval(
+            hours=24, maxsize=maxsize, persistent=persistent, custom=custom, **kwargs
+        )(foo)
+
     return _wrapper
 
 
-def monthly(maxsize=128, persistent='', custom=None, **kwargs):
+def monthly(maxsize=128, persistent="", custom=None, **kwargs):
     def _wrapper(foo):
-        return interval(months=1, maxsize=maxsize, persistent=persistent, custom=custom, **kwargs)(foo)
+        return interval(
+            months=1, maxsize=maxsize, persistent=persistent, custom=custom, **kwargs
+        )(foo)
+
     return _wrapper
diff --git a/temporalcache/persistent_lru_cache.py b/temporalcache/persistent_lru_cache.py
index b691b51..f99f41c 100644
--- a/temporalcache/persistent_lru_cache.py
+++ b/temporalcache/persistent_lru_cache.py
@@ -1,4 +1,4 @@
-'''The MIT License (MIT)
+"""The MIT License (MIT)
 
 Copyright (c) 2013 abarnert
 
@@ -18,7 +18,7 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-'''
+"""
 """persistent_lru_cache.py - A persistent LRU cache decorator
 """
 # Based on lru_cache from functools in the standard library, which
@@ -26,7 +26,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 # Raymond Hettinger <python at rcn.com>. Persistence added by
 # Andrew Barnert <abarnert at yahoo.com>.
 
-__all__ = ['persistent_lru_cache']
+__all__ = ["persistent_lru_cache"]
 
 try:
     import atexit
@@ -35,11 +35,15 @@ try:
     from collections import namedtuple
     from _thread import RLock
 except BaseException:
+
     class RLock:
-        'Dummy reentrant lock for builds without threads'
+        "Dummy reentrant lock for builds without threads"
 
-        def __enter__(self): pass
-        def __exit__(self, exctype, excinst, exctb): pass
+        def __enter__(self):
+            pass
+
+        def __exit__(self, exctype, excinst, exctb):
+            pass
 
 
 ################################################################################
@@ -50,13 +54,13 @@ _CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])
 
 
 class _HashedSeq(list):
-    """ This class guarantees that hash() will be called no more than once
-        per element.  This is important because the lru_cache() will hash
-        the key multiple times on a cache miss.
+    """This class guarantees that hash() will be called no more than once
+    per element.  This is important because the lru_cache() will hash
+    the key multiple times on a cache miss.
 
     """
 
-    __slots__ = 'hashvalue'
+    __slots__ = "hashvalue"
 
     def __init__(self, tup, hash=hash):
         self[:] = tup
@@ -66,10 +70,17 @@ class _HashedSeq(list):
         return self.hashvalue
 
 
-def _make_key(args, kwds, typed,
-              kwd_mark=(object(),),
-              fasttypes={int, str, frozenset, type(None)},
-              sorted=sorted, tuple=tuple, type=type, len=len):
+def _make_key(
+    args,
+    kwds,
+    typed,
+    kwd_mark=(object(),),
+    fasttypes={int, str, frozenset, type(None)},
+    sorted=sorted,
+    tuple=tuple,
+    type=type,
+    len=len,
+):
     """Make a cache key from optionally typed positional and keyword arguments
 
     The key is constructed in a way that is flat as possible rather than
@@ -130,31 +141,32 @@ def persistent_lru_cache(filename, save_every=1, maxsize=128, typed=False):
     # to allow the implementation to change (including a possible C version).
 
     # Constants shared by all lru cache instances:
-    sentinel = object()          # unique object used to signal cache misses
-    make_key = _make_key         # build a key from the function arguments
-    PREV, NEXT, KEY, RESULT = 0, 1, 2, 3   # names for the link fields
+    sentinel = object()  # unique object used to signal cache misses
+    make_key = _make_key  # build a key from the function arguments
+    PREV, NEXT, KEY, RESULT = 0, 1, 2, 3  # names for the link fields
 
     def decorating_function(user_function):
 
-        lock = RLock()           # because linkedlist updates aren't threadsafe
+        lock = RLock()  # because linkedlist updates aren't threadsafe
 
         try:
-            with open(filename, 'rb') as f:
+            with open(filename, "rb") as f:
                 cache = pickle.load(f)
         except BaseException:
             cache = {}
 
         def cache_save():
             with lock:
-                with open(filename, 'wb') as f:
+                with open(filename, "wb") as f:
                     pickle.dump(cache, f)
+
         atexit.register(cache_save)
 
         hits = misses = 0
         full = False
-        cache_get = cache.get    # bound method to lookup a key or return None
-        root = []                # root of the circular doubly linked list
-        root[:] = [root, root, None, None]     # initialize by pointing to self
+        cache_get = cache.get  # bound method to lookup a key or return None
+        root = []  # root of the circular doubly linked list
+        root[:] = [root, root, None, None]  # initialize by pointing to self
 
         if maxsize == 0:
 
@@ -235,7 +247,7 @@ def persistent_lru_cache(filename, save_every=1, maxsize=128, typed=False):
                         last = root[PREV]
                         link = [last, root, key, result]
                         last[NEXT] = root[PREV] = cache[key] = link
-                        full = (len(cache) >= maxsize)
+                        full = len(cache) >= maxsize
                     misses += 1
                     if save_every and not misses % save_every:
                         cache_save()
diff --git a/temporalcache/utils.py b/temporalcache/utils.py
index f6f226b..820b16c 100644
--- a/temporalcache/utils.py
+++ b/temporalcache/utils.py
@@ -1,34 +1,35 @@
-from functools import lru_cache, wraps
-from six import with_metaclass
 from abc import ABCMeta, abstractmethod
+from functools import lru_cache, wraps
 
 
 class TCException(Exception):
     pass
 
 
-class StorageBase(with_metaclass(ABCMeta)):
+class StorageBase(metaclass=ABCMeta):
     @abstractmethod
     def cache_clear(self):
         pass
 
     def __call__(self, foo):
-        '''No caching by default'''
+        """No caching by default"""
+
         @wraps(foo)
         def _wrapper(*args, **kwargs):
             return foo(*args, **kwargs)
+
         return _wrapper
 
 
 def _base(last, now, lap, offset, multiple, attr):
-    '''
+    """
     last - last datetime
     now - current datetime
     lap - at what point to "roll over"
     offset - how many seconds between laps
     attr - what to look at
     multiple - what to multiply attr by to get seconds
-    '''
+    """
     # last started before :X, so if now > :X
 
     # handle windows timestamp issues
@@ -56,41 +57,83 @@ def _base(last, now, lap, offset, multiple, attr):
 
 
 def _secondly(last, now, secondly):
-    return _base(last=last, now=now, lap=secondly, offset=60, multiple=1, attr='second')
+    return _base(last=last, now=now, lap=secondly, offset=60, multiple=1, attr="second")
 
 
 def _minutely(last, now, minutely):
-    return _base(last=last, now=now, lap=minutely, offset=3600, multiple=60, attr='minute')
+    return _base(
+        last=last, now=now, lap=minutely, offset=3600, multiple=60, attr="minute"
+    )
 
 
 def _hourly(last, now, hourly, tz=None):
-    return _base(last=last, now=now, lap=hourly, offset=3600 * 24, multiple=3600, attr='hour')
+    return _base(
+        last=last, now=now, lap=hourly, offset=3600 * 24, multiple=3600, attr="hour"
+    )
 
 
 def _daily(last, now, daily, tz=None):
-    return _base(last=last, now=now, lap=daily, offset=3600 * 24 * 30, multiple=3600 * 24, attr='day')  # FIXME day should be derived from calendar
+    return _base(
+        last=last,
+        now=now,
+        lap=daily,
+        offset=3600 * 24 * 30,
+        multiple=3600 * 24,
+        attr="day",
+    )  # FIXME day should be derived from calendar
 
 
 def _day_of_week(last, now, day_of_week, tz=None):
-    return _base(last=last, now=now, lap=day_of_week, offset=3600 * 24 * 7, multiple=3600 * 24, attr='day')
+    return _base(
+        last=last,
+        now=now,
+        lap=day_of_week,
+        offset=3600 * 24 * 7,
+        multiple=3600 * 24,
+        attr="day",
+    )
 
 
 def _weekly(last, now, weekly, tz=None):
-    return _base(last=last, now=now, lap=weekly, offset=3600 * 24 * 7 * 4.34, multiple=3600 * 24 * 7, attr='week')  # FIXME # of weeks should be derived from calendar
+    return _base(
+        last=last,
+        now=now,
+        lap=weekly,
+        offset=3600 * 24 * 7 * 4.34,
+        multiple=3600 * 24 * 7,
+        attr="week",
+    )  # FIXME # of weeks should be derived from calendar
 
 
 def _monthly(last, now, monthly, tz=None):
-    return _base(last=last, now=now, lap=monthly, offset=3600 * 24 * 365, multiple=3600 * 24 * 7 * 4.34, attr='month')  # FIXME # of weeks should be derived from calendar
-
-
-def should_expire(last, now, secondly=None, minutely=None, hourly=None, daily=None, day_of_week=None, weekly=None, monthly=None):
-    '''should the cache expire?
+    return _base(
+        last=last,
+        now=now,
+        lap=monthly,
+        offset=3600 * 24 * 365,
+        multiple=3600 * 24 * 7 * 4.34,
+        attr="month",
+    )  # FIXME # of weeks should be derived from calendar
+
+
+def should_expire(
+    last,
+    now,
+    secondly=None,
+    minutely=None,
+    hourly=None,
+    daily=None,
+    day_of_week=None,
+    weekly=None,
+    monthly=None,
+):
+    """should the cache expire?
     last - datetime
     now - datetime
 
     if yearly:
         necessary_distance = calc(0, 0, 0, 0, 0, 0, yearly)
-    '''
+    """
     sec_res = _secondly(last, now, secondly) if secondly is not None else True
     min_res = _minutely(last, now, minutely) if minutely is not None else True
     hou_res = _hourly(last, now, hourly) if hourly is not None else True
@@ -103,10 +146,12 @@ def should_expire(last, now, secondly=None, minutely=None, hourly=None, daily=No
 
 @lru_cache(1000)
 def calc(seconds=0, minutes=0, hours=0, days=0, weeks=0, months=0, years=0):
-    return seconds + \
-        minutes * 60 + \
-        hours * 60 * 60 + \
-        days * 24 * 60 * 60 + \
-        weeks * 7 * 24 * 60 * 60 + \
-        months * 30 * 7 * 24 * 60 * 60 + \
-        years * 365 * 24 * 60 * 60
+    return (
+        seconds
+        + minutes * 60
+        + hours * 60 * 60
+        + days * 24 * 60 * 60
+        + weeks * 7 * 24 * 60 * 60
+        + months * 30 * 7 * 24 * 60 * 60
+        + years * 365 * 24 * 60 * 60
+    )


Test patch:
diff --git a/temporalcache/tests/test_expire.py b/temporalcache/tests/test_expire.py
index ad6c249..0c35410 100644
--- a/temporalcache/tests/test_expire.py
+++ b/temporalcache/tests/test_expire.py
@@ -31,16 +31,16 @@ class TestExpire:
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
-        print('checking cached')
+        print("checking cached")
         assert x == foo()
 
         # expire
         self._delay = datetime.timedelta(seconds=2)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_mutable(self):
         from random import random
@@ -53,16 +53,16 @@ class TestExpire:
         def foo(*args, **kwargs):
             return random()
 
-        print('running first')
-        x = foo([1, 2, 3], test={'a': 1, 'b': 2})
-        print('checking cached')
-        assert x == foo([1, 2, 3], test={'a': 1, 'b': 2})
+        print("running first")
+        x = foo([1, 2, 3], test={"a": 1, "b": 2})
+        print("checking cached")
+        assert x == foo([1, 2, 3], test={"a": 1, "b": 2})
 
         # expire
         self._delay = datetime.timedelta(seconds=61)
-        print('checking cache expired')
-        assert x != foo([1, 2, 3], test={'a': 1, 'b': 2})
-        print('success')
+        print("checking cache expired")
+        assert x != foo([1, 2, 3], test={"a": 1, "b": 2})
+        print("success")
 
     def test_seconds(self):
         from random import random
@@ -75,20 +75,20 @@ class TestExpire:
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
 
-        print('checking cached')
+        print("checking cached")
         self._delay = datetime.timedelta(seconds=58)
         assert x == foo()
 
-        print('checking cached')
+        print("checking cached")
 
         # expire
         self._delay = datetime.timedelta(seconds=59)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_minutes(self):
         from random import random
@@ -101,20 +101,20 @@ class TestExpire:
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
 
-        print('checking cached')
+        print("checking cached")
         self._delay = datetime.timedelta(minutes=3)
         assert x == foo()
 
-        print('checking cached')
+        print("checking cached")
 
         # expire
         self._delay = datetime.timedelta(minutes=4)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_minutely(self):
         from random import random
@@ -127,20 +127,20 @@ class TestExpire:
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
 
-        print('checking cached')
+        print("checking cached")
         self._delay = datetime.timedelta(seconds=3)
         assert x == foo()
 
-        print('checking cached')
+        print("checking cached")
 
         # expire
         self._delay = datetime.timedelta(seconds=4)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_hourly(self):
         from random import random
@@ -153,20 +153,20 @@ class TestExpire:
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
 
-        print('checking cached')
+        print("checking cached")
         self._delay = datetime.timedelta(minutes=3)
         assert x == foo()
 
-        print('checking cached')
+        print("checking cached")
 
         # expire
         self._delay = datetime.timedelta(minutes=4)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_hours(self):
         from random import random
@@ -179,20 +179,20 @@ class TestExpire:
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
 
-        print('checking cached')
+        print("checking cached")
         self._delay = datetime.timedelta(hours=3)
         assert x == foo()
 
-        print('checking cached')
+        print("checking cached")
 
         # expire
         self._delay = datetime.timedelta(hours=4)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_daily(self):
         from random import random
@@ -205,20 +205,20 @@ class TestExpire:
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
 
-        print('checking cached')
+        print("checking cached")
         self._delay = datetime.timedelta(hours=3)
         assert x == foo()
 
-        print('checking cached')
+        print("checking cached")
 
         # expire
         self._delay = datetime.timedelta(hours=4)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_days(self):
         from random import random
@@ -231,30 +231,32 @@ class TestExpire:
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
 
-        print('checking cached')
+        print("checking cached")
         self._delay = datetime.timedelta(days=3)
         assert x == foo()
 
-        print('checking cached')
+        print("checking cached")
 
         # expire
         self._delay = datetime.timedelta(days=4)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_checks1(self):
         from random import random
         from temporalcache import expire, TCException
 
         try:
+
             @expire(60)
             def foo():
                 return random()
-            raise Exception('')
+
+            raise Exception("")
         except TCException:
             pass
 
@@ -263,10 +265,12 @@ class TestExpire:
         from temporalcache import expire, TCException
 
         try:
+
             @expire(minute=60)
             def foo():
                 return random()
-            raise Exception('')
+
+            raise Exception("")
         except TCException:
             pass
 
@@ -275,10 +279,12 @@ class TestExpire:
         from temporalcache import expire, TCException
 
         try:
+
             @expire(hour=24)
             def foo():
                 return random()
-            raise Exception('')
+
+            raise Exception("")
         except TCException:
             pass
 
@@ -287,10 +293,12 @@ class TestExpire:
         from temporalcache import expire, TCException
 
         try:
+
             @expire(day=0)
             def foo():
                 return random()
-            raise Exception('')
+
+            raise Exception("")
         except TCException:
             pass
 
@@ -299,10 +307,12 @@ class TestExpire:
         from temporalcache import expire, TCException
 
         try:
+
             @expire(day=32)
             def foo():
                 return random()
-            raise Exception('')
+
+            raise Exception("")
         except TCException:
             pass
 
@@ -311,10 +321,12 @@ class TestExpire:
         from temporalcache import expire, TCException
 
         try:
+
             @expire(week=0)
             def foo():
                 return random()
-            raise Exception('')
+
+            raise Exception("")
         except TCException:
             pass
 
@@ -323,10 +335,12 @@ class TestExpire:
         from temporalcache import expire, TCException
 
         try:
+
             @expire(week=6)
             def foo():
                 return random()
-            raise Exception('')
+
+            raise Exception("")
         except TCException:
             pass
 
@@ -335,10 +349,12 @@ class TestExpire:
         from temporalcache import expire, TCException
 
         try:
+
             @expire(month=0)
             def foo():
                 return random()
-            raise Exception('')
+
+            raise Exception("")
         except TCException:
             pass
 
@@ -347,10 +363,12 @@ class TestExpire:
         from temporalcache import expire, TCException
 
         try:
+
             @expire(month=13)
             def foo():
                 return random()
-            raise Exception('')
+
+            raise Exception("")
         except TCException:
             pass
 
@@ -362,9 +380,10 @@ class TestExpireTZ:
 
         now = datetime.datetime.now(tz=pytz.UTC)
 
-        @expire(second=(now.second + 3) % 60, hour=now.hour, tz='UTC')
+        @expire(second=(now.second + 3) % 60, hour=now.hour, tz="UTC")
         def foo():
             return random()
+
         ret = foo()
         time.sleep(1)
         assert ret == foo()
diff --git a/temporalcache/tests/test_interval.py b/temporalcache/tests/test_interval.py
index 63771c1..c0825a5 100644
--- a/temporalcache/tests/test_interval.py
+++ b/temporalcache/tests/test_interval.py
@@ -29,16 +29,16 @@ class TestInterval:
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
-        print('checking cached')
+        print("checking cached")
         assert x == foo()
 
         # expire
         self._delay = datetime.timedelta(seconds=2)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_mutable(self):
         from random import random
@@ -50,16 +50,16 @@ class TestInterval:
         def foo(*args, **kwargs):
             return random()
 
-        print('running first')
-        x = foo([1, 2, 3], test={'a': 1, 'b': 2})
-        print('checking cached')
-        assert x == foo([1, 2, 3], test={'a': 1, 'b': 2})
+        print("running first")
+        x = foo([1, 2, 3], test={"a": 1, "b": 2})
+        print("checking cached")
+        assert x == foo([1, 2, 3], test={"a": 1, "b": 2})
 
         # expire
         self._delay = datetime.timedelta(seconds=2)
-        print('checking cache expired')
-        assert x != foo([1, 2, 3], test={'a': 1, 'b': 2})
-        print('success')
+        print("checking cache expired")
+        assert x != foo([1, 2, 3], test={"a": 1, "b": 2})
+        print("success")
 
     def test_seconds(self):
         from random import random
@@ -71,127 +71,133 @@ class TestInterval:
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
-        print('checking cached')
+        print("checking cached")
         assert x == foo()
 
         # expire
         self._delay = datetime.timedelta(seconds=2)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_minutes(self):
         from random import random
         import temporalcache
+
         self._delay = datetime.timedelta(seconds=0)
 
         @temporalcache.interval(minutes=1)
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
-        print('checking cached')
+        print("checking cached")
         assert x == foo()
 
         self._delay = datetime.timedelta(minutes=1, seconds=1)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_minutely(self):
         from random import random
         import temporalcache
+
         self._delay = datetime.timedelta(seconds=0)
 
         @temporalcache.minutely()
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
-        print('checking cached')
+        print("checking cached")
         assert x == foo()
 
         self._delay = datetime.timedelta(minutes=1, seconds=1)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_hours(self):
         from random import random
         import temporalcache
+
         self._delay = datetime.timedelta(seconds=0)
 
         @temporalcache.interval(hours=1)
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
-        print('checking cached')
+        print("checking cached")
         assert x == foo()
 
         self._delay = datetime.timedelta(minutes=60, seconds=1)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_hourly(self):
         from random import random
         import temporalcache
+
         self._delay = datetime.timedelta(seconds=0)
 
         @temporalcache.hourly()
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
-        print('checking cached')
+        print("checking cached")
         assert x == foo()
 
         self._delay = datetime.timedelta(minutes=60, seconds=1)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_daily(self):
         from random import random
         import temporalcache
+
         self._delay = datetime.timedelta(seconds=0)
 
         @temporalcache.daily()
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
-        print('checking cached')
+        print("checking cached")
         assert x == foo()
 
         self._delay = datetime.timedelta(hours=24, seconds=1)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
 
     def test_monthly(self):
         from random import random
         import temporalcache
+
         self._delay = datetime.timedelta(seconds=0)
 
         @temporalcache.daily()
         def foo():
             return random()
 
-        print('running first')
+        print("running first")
         x = foo()
-        print('checking cached')
+        print("checking cached")
         assert x == foo()
 
         self._delay = datetime.timedelta(days=31, seconds=1)
-        print('checking cache expired')
+        print("checking cache expired")
         assert x != foo()
-        print('success')
+        print("success")
diff --git a/temporalcache/tests/test_persistent.py b/temporalcache/tests/test_persistent.py
index d47ab36..3ce7b87 100644
--- a/temporalcache/tests/test_persistent.py
+++ b/temporalcache/tests/test_persistent.py
@@ -4,6 +4,7 @@ from tempfile import NamedTemporaryFile
 
 
 if os.name != "nt":
+
     class TestExpire:
         def setup(self):
             self._olddatetime = datetime.datetime
@@ -29,20 +30,21 @@ if os.name != "nt":
             self._delay = datetime.timedelta(seconds=0)
 
             with NamedTemporaryFile() as f:
+
                 @expire(1, persistent=f.name, maxsize=2)
                 def foo(test):
                     return random()
 
-                print('running first')
-                x = foo('a')
-                print('checking cached')
-                assert x == foo('a')
-                foo('b')
-                foo('c')
-                x = foo('d')
+                print("running first")
+                x = foo("a")
+                print("checking cached")
+                assert x == foo("a")
+                foo("b")
+                foo("c")
+                x = foo("d")
 
                 # expire
                 self._delay = datetime.timedelta(seconds=2)
-                print('checking cache expired')
-                assert x != foo('d')
-                print('success')
+                print("checking cache expired")
+                assert x != foo("d")
+                print("success")
diff --git a/temporalcache/tests/test_utils.py b/temporalcache/tests/test_utils.py
index 09054f0..dfcb5b8 100644
--- a/temporalcache/tests/test_utils.py
+++ b/temporalcache/tests/test_utils.py
@@ -4,6 +4,7 @@ from datetime import timedelta, datetime
 class TestUtils:
     def test_calc(self):
         from temporalcache.utils import calc
+
         assert calc(7, 6, 5, 4, 3, 2, 1) == 70002367
 
     def test_should_expire_seconds(self):
@@ -75,6 +76,7 @@ class TestUtils:
 
     def test_should_expire_boundary(self):
         from temporalcache.utils import should_expire
+
         now = datetime(1999, 12, 31, 23, 59, 58)
         next_second = now + timedelta(seconds=1)
         next_secondp = now + timedelta(seconds=2)