├── test ├── __init__.py ├── unit │ ├── __init__.py │ └── test_client.py └── integration │ ├── __init__.py │ └── test_client.py ├── .github ├── FUNDING.yml └── workflows │ └── semgrep.yml ├── requirements.txt ├── .isort.cfg ├── pyproject.toml ├── .coveragerc ├── MANIFEST.in ├── setup.cfg ├── flask_redis ├── __init__.py └── client.py ├── AUTHORS.md ├── .pre-commit-config.yaml ├── .circleci └── config.yml ├── .bentoignore ├── tox.ini ├── LICENSE.md ├── setup.py ├── CHANGELOG.md ├── .gitignore └── README.md /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/unit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/integration/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: underyx 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask>=0.9 2 | redis>=2.6.2 3 | -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | [settings] 2 | known_third_party = flask,pytest,setuptools 3 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=40.6.0", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | source = 4 | flask_redis 5 | 6 | [paths] 7 | source = 8 | flask_redis 9 | .tox/*/lib/python*/site-packages/flask_redis 10 | 11 | [report] 12 | show_missing = True 13 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.md 2 | include *.toml 3 | include *.txt 4 | include *.yaml 5 | 6 | include .bentoignore 7 | include .coveragerc 8 | include .isort.cfg 9 | include tox.ini 10 | 11 | graft .bento 12 | graft .circleci 13 | -------------------------------------------------------------------------------- /test/unit/test_client.py: -------------------------------------------------------------------------------- 1 | from flask_redis import client as uut 2 | 3 | 4 | def test_constructor_app(mocker): 5 | """Test that the constructor passes the app to FlaskRedis.init_app""" 6 | mocker.patch.object(uut.FlaskRedis, "init_app", autospec=True) 7 | app_stub = mocker.stub(name="app_stub") 8 | 9 | uut.FlaskRedis(app_stub) 10 | 11 | uut.FlaskRedis.init_app.assert_called_once_with(mocker.ANY, app_stub) 12 | -------------------------------------------------------------------------------- /.github/workflows/semgrep.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: {} 3 | push: 4 | branches: 5 | - main 6 | - master 7 | name: Semgrep 8 | jobs: 9 | semgrep: 10 | name: Scan 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: returntocorp/semgrep-action@v1 15 | with: 16 | auditOn: push 17 | publishToken: ${{ secrets.SEMGREP_APP_TOKEN }} 18 | publishDeployment: 28 19 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal = 1 3 | 4 | [metadata] 5 | license_file = LICENSE.md 6 | 7 | [flake8] 8 | max-line-length = 88 9 | 10 | [tool:pytest] 11 | strict = true 12 | testpaths = test 13 | 14 | [isort] 15 | atomic=true 16 | force_grid_wrap=0 17 | include_trailing_comma=true 18 | lines_after_imports=2 19 | lines_between_types=1 20 | multi_line_output=3 21 | not_skip=__init__.py 22 | use_parentheses=true 23 | 24 | known_first_party=flask_redis 25 | -------------------------------------------------------------------------------- /flask_redis/__init__.py: -------------------------------------------------------------------------------- 1 | from .client import FlaskRedis 2 | 3 | 4 | __version__ = "0.5.0.dev0" 5 | 6 | __title__ = "flask-redis" 7 | __description__ = "A nice way to use Redis in your Flask app" 8 | __url__ = "https://github.com/underyx/flask-redis/" 9 | __uri__ = __url__ 10 | 11 | __author__ = "Bence Nagy" 12 | __email__ = "bence@underyx.me" 13 | 14 | __license__ = "Blue Oak License" 15 | __copyright__ = "Copyright (c) 2019 Bence Nagy" 16 | 17 | __all__ = [FlaskRedis] 18 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # Credits 2 | 3 | The `flask-redis` project is written and maintained 4 | by [Bence Nagy (underyx)](https://underyx.me). 5 | 6 | The project was originally created by [Rhys Elsmore](https://rhys.io/), 7 | who maintained it until the 0.0.6 release in 2014. 8 | His work was licensed under the Apache 2 license. 9 | The project has gone through a full rewrite since, 10 | but his work was essential as inspiration. 11 | Thanks, Rhys! 12 | 13 | A full list of contributors can be found on [GitHub's Contributors page](https://github.com/underyx/flask-redis/graphs/contributors) 14 | or you can obtain it on your own by running `git shortlog -sn`. 15 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/ambv/black 3 | rev: 19.3b0 4 | hooks: 5 | - id: black 6 | language_version: python3.7 7 | 8 | - repo: https://gitlab.com/pycqa/flake8 9 | rev: 3.7.7 10 | hooks: 11 | - id: flake8 12 | language_version: python3.7 13 | 14 | - repo: https://github.com/asottile/seed-isort-config 15 | rev: v1.7.0 16 | hooks: 17 | - id: seed-isort-config 18 | 19 | - repo: https://github.com/pre-commit/mirrors-isort 20 | rev: v4.3.16 21 | hooks: 22 | - id: isort 23 | language_version: python3.7 24 | 25 | - repo: https://github.com/pre-commit/pre-commit-hooks 26 | rev: v2.1.0 27 | hooks: 28 | - id: trailing-whitespace 29 | - id: end-of-file-fixer 30 | - id: debug-statements 31 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Docs: https://circleci.com/docs/2.0/language-python/ 2 | version: 2 3 | jobs: 4 | build: 5 | docker: 6 | - image: kiwicom/tox:3.7 7 | 8 | working_directory: ~/repo 9 | 10 | steps: 11 | - checkout 12 | 13 | - restore_cache: 14 | keys: 15 | - v1-dependencies-{{ checksum "requirements.txt" }} 16 | - v1-dependencies- 17 | 18 | - run: 19 | name: Install Alpine dependencies 20 | command: apk add --no-cache curl findutils git 21 | 22 | - run: 23 | name: Install Python dependencies 24 | command: pip install coverage 25 | 26 | - run: 27 | name: Create tox environments 28 | command: tox --notest 29 | 30 | - save_cache: 31 | paths: 32 | - ./.tox 33 | key: v1-dependencies-{{ checksum "requirements.txt" }} 34 | 35 | - run: 36 | name: Run tests with tox 37 | command: tox 38 | 39 | - run: 40 | name: Report coverage to codecov 41 | command: bash <(curl -s https://codecov.io/bash) 42 | -------------------------------------------------------------------------------- /.bentoignore: -------------------------------------------------------------------------------- 1 | # Items added to this file will be ignored by bento. 2 | # 3 | # This file uses .gitignore syntax: 4 | # 5 | # To ignore a file anywhere it occurs in your project, enter a 6 | # glob pattern here. E.g. "*.min.js". 7 | # 8 | # To ignore a directory anywhere it occurs in your project, add 9 | # a trailing slash to the file name. E.g. "dist/". 10 | # 11 | # To ignore a file or directory only relative to the project root, 12 | # include a slash anywhere except the last character. E.g. 13 | # "/dist/", or "src/generated". 14 | # 15 | # Some parts of .gitignore syntax are not supported, and patterns 16 | # using this syntax will be dropped from the ignore list: 17 | # - Explicit "include syntax", e.g. "!kept/". 18 | # - Multi-character expansion syntax, e.g. "*.py[cod]" 19 | # 20 | # To include ignore patterns from another file, start a line 21 | # with ':include', followed by the path of the file. E.g. 22 | # ":include path/to/other/ignore/file". 23 | # 24 | # To ignore a file with a literal ':' character, escape it with 25 | # a backslash, e.g. "\:foo". 26 | 27 | # Ignore Bento environment files 28 | .bento/ 29 | 30 | # Ignore git items 31 | .gitignore 32 | .git/ 33 | :include .gitignore 34 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = 3 | lint 4 | py{27,35,36,37} 5 | py37-oldpy3deps 6 | py27-oldpy2deps 7 | coverage-report 8 | manifest 9 | pypi-description 10 | isolated_build = true 11 | 12 | [testenv] 13 | deps = 14 | oldpy2deps: redis==2.6.2 15 | oldpy2deps: flask==0.8.0 16 | oldpy2deps: werkzeug==0.8.3 17 | oldpy3deps: redis==2.6.2 18 | oldpy3deps: flask==0.11.1 19 | oldpy3deps: werkzeug==0.11.15 20 | extras = tests 21 | commands = coverage run --parallel-mode -m pytest {posargs} 22 | 23 | [testenv:coverage-report] 24 | basepython = python3.7 25 | skip_install = true 26 | deps = coverage 27 | commands = 28 | coverage combine 29 | coverage report 30 | 31 | [testenv:lint] 32 | basepython = python3.7 33 | skip_install = true 34 | deps = pre-commit 35 | passenv = HOMEPATH # needed on Windows 36 | commands = pre-commit run --all-files 37 | 38 | [testenv:manifest] 39 | basepython = python3.7 40 | skip_install = true 41 | deps = check-manifest 42 | commands = check-manifest 43 | 44 | [testenv:pypi-description] 45 | basepython = python3.7 46 | skip_install = true 47 | deps = twine 48 | commands = 49 | pip wheel -w {envtmpdir}/build --no-deps . 50 | twine check {envtmpdir}/build/* 51 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Blue Oak Model License 2 | 3 | Version 1.0.0 4 | 5 | ## Purpose 6 | 7 | This license gives everyone as much permission to work with 8 | this software as possible, while protecting contributors 9 | from liability. 10 | 11 | ## Acceptance 12 | 13 | In order to receive this license, you must agree to its 14 | rules. The rules of this license are both obligations 15 | under that agreement and conditions to your license. 16 | You must not do anything with this software that triggers 17 | a rule that you cannot or will not follow. 18 | 19 | ## Copyright 20 | 21 | Each contributor licenses you to do everything with this 22 | software that would otherwise infringe that contributor's 23 | copyright in it. 24 | 25 | ## Notices 26 | 27 | You must ensure that everyone who gets a copy of 28 | any part of this software from you, with or without 29 | changes, also gets the text of this license or a link to 30 | . 31 | 32 | ## Excuse 33 | 34 | If anyone notifies you in writing that you have not 35 | complied with [Notices](#notices), you can keep your 36 | license by taking all practical steps to comply within 30 37 | days after the notice. If you do not do so, your license 38 | ends immediately. 39 | 40 | ## Patent 41 | 42 | Each contributor licenses you to do everything with this 43 | software that would otherwise infringe any patent claims 44 | they can license or become able to license. 45 | 46 | ## Reliability 47 | 48 | No contributor can revoke this license. 49 | 50 | ## No Liability 51 | 52 | ***As far as the law allows, this software comes as is, 53 | without any warranty or condition, and no contributor 54 | will be liable to anyone for any damages related to this 55 | software or this license, under any kind of legal claim.*** 56 | -------------------------------------------------------------------------------- /flask_redis/client.py: -------------------------------------------------------------------------------- 1 | try: 2 | import redis 3 | except ImportError: 4 | # We can still allow custom provider-only usage without redis-py being installed 5 | redis = None 6 | 7 | 8 | class FlaskRedis(object): 9 | def __init__(self, app=None, strict=True, config_prefix="REDIS", **kwargs): 10 | self._redis_client = None 11 | self.provider_class = redis.StrictRedis if strict else redis.Redis 12 | self.provider_kwargs = kwargs 13 | self.config_prefix = config_prefix 14 | 15 | if app is not None: 16 | self.init_app(app) 17 | 18 | @classmethod 19 | def from_custom_provider(cls, provider, app=None, **kwargs): 20 | assert provider is not None, "your custom provider is None, come on" 21 | 22 | # We never pass the app parameter here, so we can call init_app 23 | # ourselves later, after the provider class has been set 24 | instance = cls(**kwargs) 25 | 26 | instance.provider_class = provider 27 | if app is not None: 28 | instance.init_app(app) 29 | return instance 30 | 31 | def init_app(self, app, **kwargs): 32 | redis_url = app.config.get( 33 | "{0}_URL".format(self.config_prefix), "redis://localhost:6379/0" 34 | ) 35 | 36 | self.provider_kwargs.update(kwargs) 37 | self._redis_client = self.provider_class.from_url( 38 | redis_url, **self.provider_kwargs 39 | ) 40 | 41 | if not hasattr(app, "extensions"): 42 | app.extensions = {} 43 | app.extensions[self.config_prefix.lower()] = self 44 | 45 | def __getattr__(self, name): 46 | return getattr(self._redis_client, name) 47 | 48 | def __getitem__(self, name): 49 | return self._redis_client[name] 50 | 51 | def __setitem__(self, name, value): 52 | self._redis_client[name] = value 53 | 54 | def __delitem__(self, name): 55 | del self._redis_client[name] 56 | -------------------------------------------------------------------------------- /test/integration/test_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """Integration tests for Flask-Redis.""" 4 | 5 | import flask 6 | import pytest 7 | 8 | from flask_redis import client as uut 9 | 10 | 11 | @pytest.fixture 12 | def app(): 13 | return flask.Flask(__name__) 14 | 15 | 16 | def test_constructor(app): 17 | """Test that a constructor with app instance will initialize the 18 | connection""" 19 | redis = uut.FlaskRedis(app) 20 | assert redis._redis_client is not None 21 | assert hasattr(redis._redis_client, "connection_pool") 22 | 23 | 24 | def test_init_app(app): 25 | """Test that a constructor without app instance will not initialize the 26 | connection. 27 | 28 | After FlaskRedis.init_app(app) is called, the connection will be 29 | initialized.""" 30 | redis = uut.FlaskRedis() 31 | assert redis._redis_client is None 32 | redis.init_app(app) 33 | assert redis._redis_client is not None 34 | assert hasattr(redis._redis_client, "connection_pool") 35 | if hasattr(app, "extensions"): 36 | assert "redis" in app.extensions 37 | assert app.extensions["redis"] == redis 38 | 39 | 40 | def test_custom_prefix(app): 41 | """Test that config prefixes enable distinct connections""" 42 | app.config["DBA_URL"] = "redis://localhost:6379/1" 43 | app.config["DBB_URL"] = "redis://localhost:6379/2" 44 | redis_a = uut.FlaskRedis(app, config_prefix="DBA") 45 | redis_b = uut.FlaskRedis(app, config_prefix="DBB") 46 | assert redis_a.connection_pool.connection_kwargs["db"] == 1 47 | assert redis_b.connection_pool.connection_kwargs["db"] == 2 48 | 49 | 50 | @pytest.mark.parametrize( 51 | ["strict_flag", "allowed_names"], 52 | [ 53 | [ 54 | True, 55 | # StrictRedis points to Redis in newer versions 56 | {"Redis", "StrictRedis"}, 57 | ], 58 | [False, {"Redis"}], 59 | ], 60 | ) 61 | def test_strict_parameter(app, strict_flag, allowed_names): 62 | """Test that initializing with the strict parameter set to True will use 63 | StrictRedis, and that False will keep using the old Redis class.""" 64 | 65 | redis = uut.FlaskRedis(app, strict=strict_flag) 66 | assert redis._redis_client is not None 67 | assert type(redis._redis_client).__name__ in allowed_names 68 | 69 | 70 | def test_custom_provider(app): 71 | """Test that FlaskRedis can be instructed to use a different Redis client, 72 | like StrictRedis""" 73 | 74 | class FakeProvider(object): 75 | @classmethod 76 | def from_url(cls, *args, **kwargs): 77 | return cls() 78 | 79 | redis = uut.FlaskRedis.from_custom_provider(FakeProvider) 80 | assert redis._redis_client is None 81 | redis.init_app(app) 82 | assert redis._redis_client is not None 83 | assert isinstance(redis._redis_client, FakeProvider) 84 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | import os 3 | import re 4 | 5 | from setuptools import find_packages, setup 6 | 7 | 8 | NAME = "flask-redis" 9 | KEYWORDS = ["flask", "redis"] 10 | CLASSIFIERS = [ 11 | "Development Status :: 4 - Beta", 12 | "Environment :: Web Environment", 13 | "Framework :: Flask", 14 | "Intended Audience :: Developers", 15 | "Operating System :: OS Independent", 16 | "Programming Language :: Python", 17 | "Programming Language :: Python :: 2", 18 | "Programming Language :: Python :: 2.7", 19 | "Programming Language :: Python :: 3", 20 | "Programming Language :: Python :: 3.5", 21 | "Programming Language :: Python :: 3.6", 22 | "Programming Language :: Python :: 3.7", 23 | "Programming Language :: Python :: Implementation :: CPython", 24 | "Topic :: Internet :: WWW/HTTP :: Dynamic Content", 25 | "Topic :: Software Development :: Libraries :: Python Modules", 26 | ] 27 | 28 | 29 | PROJECT_URLS = { 30 | "Bug Tracker": "https://github.com/underyx/flask-redis/issues", 31 | "Source Code": "https://github.com/underyx/flask-redis", 32 | } 33 | 34 | INSTALL_REQUIRES = ["Flask>=0.8", "redis>=2.7.6"] 35 | EXTRAS_REQUIRE = {"tests": ["coverage", "pytest", "pytest-mock"]} 36 | EXTRAS_REQUIRE["dev"] = EXTRAS_REQUIRE["tests"] + ["pre-commit"] 37 | 38 | 39 | def read(*parts): 40 | """ 41 | Build an absolute path from *parts* and return the contents of the resulting file. 42 | 43 | Assumes UTF-8 encoding. 44 | """ 45 | here = os.path.abspath(os.path.dirname(__file__)) 46 | with codecs.open(os.path.join(here, *parts), "rb", "utf-8") as f: 47 | return f.read() 48 | 49 | 50 | META_FILE = read("flask_redis", "__init__.py") 51 | 52 | 53 | def find_meta(meta): 54 | """Extract __*meta*__ from META_FILE.""" 55 | meta_match = re.search( 56 | r"^__{meta}__ = ['\"]([^'\"]*)['\"]".format(meta=meta), META_FILE, re.M 57 | ) 58 | if meta_match: 59 | return meta_match.group(1) 60 | raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta)) 61 | 62 | 63 | setup( 64 | name=find_meta("title"), 65 | description=find_meta("description"), 66 | version=find_meta("version"), 67 | url=find_meta("url"), 68 | author=find_meta("author"), 69 | author_email=find_meta("email"), 70 | maintainer=find_meta("author"), 71 | maintainer_email=find_meta("email"), 72 | download_url=find_meta("url") + "releases", 73 | keywords=KEYWORDS, 74 | long_description=( 75 | read("README.md") 76 | + "\n\n" 77 | + re.sub("^#", "##", read("CHANGELOG.md")) 78 | + "\n\n" 79 | + re.sub("^#", "##", read("AUTHORS.md")) 80 | ), 81 | long_description_content_type="text/markdown", 82 | packages=find_packages(), 83 | classifiers=CLASSIFIERS, 84 | install_requires=INSTALL_REQUIRES, 85 | extras_require=EXTRAS_REQUIRE, 86 | python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", 87 | include_package_data=True, 88 | ) 89 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.4.0 (2019-05-29) 9 | 10 | - Reorganized the module and rewrote everything other than the library code, mainly packaging and CI. There are no user-facing changes in behavior. 11 | 12 | ## 0.3.0 (2016-07-18) 13 | 14 | - **Backwards incompatible:** The `FlaskRedis.init_app` method no 15 | longer takes a `strict` parameter. Pass this flag when creating your 16 | `FlaskRedis` instance, instead. 17 | - **Backwards incompatible:** The extension will now be registered 18 | under the (lowercased) config prefix of the instance. The default 19 | config prefix is `'REDIS'`, so unless you change that, you can still 20 | access the extension via `app.extensions['redis']` as before. 21 | - **Backwards incompatible:** The default class has been changed to 22 | `redis.StrictRedis`. You can switch back to the old `redis.Redis` 23 | class by specifying `strict=False` in the `FlaskRedis` kwargs. 24 | - You can now pass all supported `Redis` keyword arguments (such as 25 | `decode_responses`) to `FlaskRedis` and they will be correctly 26 | passed over to the `redis-py` instance. Thanks, @giyyapan\! 27 | - Usage like `redis_store['key'] = value`, `redis_store['key']`, and 28 | `del redis_store['key']` is now supported. Thanks, @ariscn\! 29 | 30 | ## 0.2.0 (2015-04-15) 31 | 32 | - Made 0.1.0's deprecation warned changes final 33 | 34 | ## 0.1.0 (2015-04-15) 35 | 36 | - **Deprecation:** Renamed `flask_redis.Redis` to 37 | `flask_redis.FlaskRedis`. Using the old name still works, but emits 38 | a deprecation warning, as it will be removed from the next version 39 | - **Deprecation:** Setting a `REDIS_DATABASE` (or equivalent) now 40 | emits a deprecation warning as it will be removed in the version in 41 | favor of including the database number in `REDIS_URL` (or 42 | equivalent) 43 | - Added a `FlaskRedis.from_custom_provider(provider)` class method for 44 | using any redis provider class that supports instantiation with a 45 | `from_url` class method 46 | - Added a `strict` parameter to `FlaskRedis` which expects a boolean 47 | value and allows choosing between using `redis.StrictRedis` and 48 | `redis.Redis` as the defualt provider. 49 | - Made `FlaskRedis` register as a Flask extension through Flask's 50 | extension API 51 | - Rewrote test suite in py.test 52 | - Got rid of the hacky attribute copying mechanism in favor of using 53 | the `__getattr__` magic method to pass calls to the underlying 54 | client 55 | 56 | ## 0.0.6 (2014-04-09) 57 | 58 | - Improved Python 3 Support (Thanks underyx\!). 59 | - Improved test cases. 60 | - Improved configuration. 61 | - Fixed up documentation. 62 | - Removed un-used imports (Thanks underyx and lyschoening\!). 63 | 64 | ## 0.0.5 (2014-02-17) 65 | 66 | - Improved suppot for the config prefix. 67 | 68 | ## 0.0.4 (2014-02-17) 69 | 70 | - Added support for config_prefix, allowing multiple DBs. 71 | 72 | ## 0.0.3 (2013-07-06) 73 | 74 | - Added TravisCI Testing for Flask 0.9/0.10. 75 | - Added Badges to README. 76 | 77 | ## 0.0.2 (2013-07-06) 78 | 79 | - Implemented a very simple test. 80 | - Fixed some documentation issues. 81 | - Included requirements.txt for testing. 82 | - Included task file including some basic methods for tests. 83 | 84 | ## 0.0.1 (2013-07-05) 85 | 86 | - Conception 87 | - Initial Commit of Package to GitHub. 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #### joe made this: http://goel.io/joe 2 | 3 | #####=== Linux ===##### 4 | *~ 5 | 6 | # KDE directory preferences 7 | .directory 8 | 9 | # Linux trash folder which might appear on any partition or disk 10 | .Trash-* 11 | 12 | #####=== OSX ===##### 13 | .DS_Store 14 | .AppleDouble 15 | .LSOverride 16 | 17 | # Icon must end with two \r 18 | Icon 19 | 20 | 21 | # Thumbnails 22 | ._* 23 | 24 | # Files that might appear in the root of a volume 25 | .DocumentRevisions-V100 26 | .fseventsd 27 | .Spotlight-V100 28 | .TemporaryItems 29 | .Trashes 30 | .VolumeIcon.icns 31 | 32 | # Directories potentially created on remote AFP share 33 | .AppleDB 34 | .AppleDesktop 35 | Network Trash Folder 36 | Temporary Items 37 | .apdisk 38 | 39 | #####=== Windows ===##### 40 | # Windows image file caches 41 | Thumbs.db 42 | ehthumbs.db 43 | 44 | # Folder config file 45 | Desktop.ini 46 | 47 | # Recycle Bin used on file shares 48 | $RECYCLE.BIN/ 49 | 50 | # Windows Installer files 51 | *.cab 52 | *.msi 53 | *.msm 54 | *.msp 55 | 56 | # Windows shortcuts 57 | *.lnk 58 | 59 | #####=== VisualStudioCode ===##### 60 | .settings 61 | 62 | 63 | #####=== Vim ===##### 64 | [._]*.s[a-w][a-z] 65 | [._]s[a-w][a-z] 66 | *.un~ 67 | Session.vim 68 | .netrwhist 69 | *~ 70 | 71 | #####=== JetBrains ===##### 72 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 73 | 74 | *.iml 75 | 76 | ## Directory-based project format: 77 | .idea/ 78 | # if you remove the above rule, at least ignore the following: 79 | 80 | # User-specific stuff: 81 | # .idea/workspace.xml 82 | # .idea/tasks.xml 83 | # .idea/dictionaries 84 | 85 | # Sensitive or high-churn files: 86 | # .idea/dataSources.ids 87 | # .idea/dataSources.xml 88 | # .idea/sqlDataSources.xml 89 | # .idea/dynamic.xml 90 | # .idea/uiDesigner.xml 91 | 92 | # Gradle: 93 | # .idea/gradle.xml 94 | # .idea/libraries 95 | 96 | # Mongo Explorer plugin: 97 | # .idea/mongoSettings.xml 98 | 99 | ## File-based project format: 100 | *.ipr 101 | *.iws 102 | 103 | ## Plugin-specific files: 104 | 105 | # IntelliJ 106 | /out/ 107 | 108 | # mpeltonen/sbt-idea plugin 109 | .idea_modules/ 110 | 111 | # JIRA plugin 112 | atlassian-ide-plugin.xml 113 | 114 | # Crashlytics plugin (for Android Studio and IntelliJ) 115 | com_crashlytics_export_strings.xml 116 | crashlytics.properties 117 | crashlytics-build.properties 118 | 119 | #####=== Python ===##### 120 | 121 | # Byte-compiled / optimized / DLL files 122 | __pycache__/ 123 | *.py[cod] 124 | *$py.class 125 | 126 | # C extensions 127 | *.so 128 | 129 | # Distribution / packaging 130 | .Python 131 | env/ 132 | build/ 133 | develop-eggs/ 134 | dist/ 135 | downloads/ 136 | eggs/ 137 | .eggs/ 138 | lib/ 139 | lib64/ 140 | parts/ 141 | sdist/ 142 | var/ 143 | *.egg-info/ 144 | .installed.cfg 145 | *.egg 146 | 147 | # PyInstaller 148 | # Usually these files are written by a python script from a template 149 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 150 | *.manifest 151 | *.spec 152 | 153 | # Installer logs 154 | pip-log.txt 155 | pip-delete-this-directory.txt 156 | 157 | # Unit test / coverage reports 158 | htmlcov/ 159 | .tox/ 160 | .coverage 161 | .coverage.* 162 | .cache 163 | nosetests.xml 164 | coverage.xml 165 | *,cover 166 | 167 | # Translations 168 | *.mo 169 | *.pot 170 | 171 | # Django stuff: 172 | *.log 173 | 174 | # Sphinx documentation 175 | docs/_build/ 176 | 177 | # PyBuilder 178 | target/ 179 | 180 | #####=== Custom ===##### 181 | 182 | .env 183 | env 184 | .cache 185 | .mypy_cache 186 | .bento/cache 187 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flask-redis 2 | 3 | [![CircleCI](https://circleci.com/gh/underyx/flask-redis.svg?style=svg)](https://circleci.com/gh/underyx/flask-redis) 4 | [![codecov](https://codecov.io/gh/underyx/flask-redis/branch/master/graph/badge.svg)](https://codecov.io/gh/underyx/flask-redis) 5 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/8f8297c1a5f542d49429c4837165984f)](https://www.codacy.com/app/bence/flask-redis?utm_source=github.com&utm_medium=referral&utm_content=underyx/flask-redis&utm_campaign=Badge_Grade) 6 | [![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/underyx/flask-redis.svg)](https://github.com/underyx/flask-redis/tags) 7 | 8 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/flask-redis.svg) 9 | ![Flask version support is 0.9+](https://img.shields.io/badge/flask-0.9%2B-blue.svg) 10 | ![redis-py version support is 2.6+](https://img.shields.io/badge/redis--py-2.6%2B-blue.svg) 11 | [![Code style: black](https://img.shields.io/badge/code%20style-black-black.svg)](https://github.com/ambv/black) 12 | 13 | A nice way to use Redis in your Flask app. 14 | 15 | ## Configuration 16 | 17 | Start by installing the extension with `pip install flask-redis`. 18 | Once that's done, configure it within your Flask config. 19 | Set the URL of your Redis instance like this: 20 | 21 | ```python 22 | REDIS_URL = "redis://:password@localhost:6379/0" 23 | ``` 24 | 25 | If you wanna connect to a Unix socket, 26 | you can specify it like `"unix://:password@/path/to/socket.sock?db=0"`. 27 | 28 | ## Usage 29 | 30 | ### Setup 31 | 32 | To add a Redis client to your application: 33 | 34 | ```python 35 | from flask import Flask 36 | from flask_redis import FlaskRedis 37 | 38 | app = Flask(__name__) 39 | redis_client = FlaskRedis(app) 40 | ``` 41 | 42 | or if you prefer, you can do it the other way around: 43 | 44 | ```python 45 | redis_client = FlaskRedis() 46 | def create_app(): 47 | app = Flask(__name__) 48 | redis_client.init_app(app) 49 | return app 50 | ``` 51 | 52 | The `FlaskRedis` client here will pass its keyword arguments 53 | to the [`Redis` class](https://redis-py.readthedocs.io/en/latest/#redis.Redis) 54 | from the [`redis-py`](https://github.com/andymccurdy/redis-py) library, 55 | so all parameters from the `Redis` documentation page will work here as well 56 | — such as `socket_timeout` and `encoding`. 57 | 58 | ### Accessing Redis 59 | 60 | Access is done by using `FlaskRedis` as if it was a 61 | [`Redis` class](https://redis-py.readthedocs.io/en/latest/#redis.Redis) 62 | as well: 63 | 64 | ```python 65 | from my_app import redis_client 66 | 67 | @app.route('/') 68 | def index(): 69 | return redis_client.get('potato') 70 | ``` 71 | 72 | For detailed instructions on what methods you can use on the client, 73 | as well as how you can use advanced features 74 | such as Lua scripting, pipelines, and callbacks, 75 | please check the 76 | [redis-py documentation](https://redis-py.readthedocs.io/en/latest/). 77 | 78 | **Pro-tip:** The [redis-py](https://github.com/andymccurdy/redis-py) 79 | package uses the `redis` namespace, so it's nicer to name your Redis object something like `redis_client` instead of just `redis`. 80 | 81 | ## Extra features in flask-redis 82 | 83 | ### Custom providers 84 | 85 | Instead of the default `Redis` client from `redis-py`, 86 | you can provide your own. 87 | This can be useful to replace it with [mockredis](https://github.com/locationlabs/mockredis) for testing: 88 | 89 | ```python 90 | from flask import Flask 91 | from flask_redis import FlaskRedis 92 | from mockredis import MockRedis 93 | 94 | 95 | def create_app(): 96 | app = Flask(__name__) 97 | if app.testing: 98 | redis_store = FlaskRedis.from_custom_provider(MockRedis) 99 | else: 100 | redis_store = FlaskRedis() 101 | redis_store.init_app(app) 102 | return app 103 | ``` 104 | 105 | ## Contributing 106 | 107 | 1. Check for open issues or open a fresh issue to start a discussion 108 | 2. Fork [the repository](https://github.com/underyx/flask-redis) on GitHub. 109 | 3. Send a pull request with your code! 110 | 111 | Merging will require a test which shows that the bug was fixed, 112 | or that the feature works as expected. 113 | Feel free to open a draft pull request though without such a test 114 | and ask for help with writing it if you're not sure how to. 115 | 116 | As [Bence](https://underyx.me) (the only maintainer) works full-time, 117 | please allow some time before your issue or pull request is handled. 118 | --------------------------------------------------------------------------------