From a376acc62e9808bf1973f20c8df2c1dede183443 Mon Sep 17 00:00:00 2001 From: nitinl Date: Sat, 20 Oct 2018 19:22:38 +0530 Subject: [PATCH 1/2] Added project to PyPi and configured upload with twine --- CONTRIBUTING.md | 27 ++++++ README.md | 29 ++----- cache4py/storage/redis.py | 10 +-- cache4py/utils.py | 2 +- setup.py | 169 ++++++++++++++++++++++++++++++++++++++ tests/test_basic.py | 2 +- 6 files changed, 209 insertions(+), 30 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 setup.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..11d53eb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,27 @@ +## Contributing to cache4py + + +### Prerequisites + +Install the python package requirements using the following command: + +``` +pipenv install +``` + +### Running the tests + +Run unit tests using the command: + +``` +pytest --cov=cache4py --cov-report html tests/ +``` + +## Issue tracking + +Create issues at [cache4py/issues](https://github.com/nitinl/cache4py/issues). + +## Authors + +* **Nitin Labhishetty ([lnitin94@gmail.com](mailto:lnitin94@gmail.com))** +* **Vaibhav Tulsyan ([vstulsyan@gmail.com](mailto:vstulsyan@gmail.com))** diff --git a/README.md b/README.md index 4329929..0b20b66 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -# cache4py -Caching simplified. +# cache4py: Caching simplified. ## Getting started @@ -9,7 +8,7 @@ Install using pip: `$ pip install cache4py` ### Usage ```python from cache4py.decorators import cache -from cache4py.storage.backends import RedisBackend +from cache4py.storage.redis import RedisBackend # You can choose memcached, redis or default (python's dict) as a backend. redis_backend = RedisBackend(url='localhost', port='6379') @@ -22,32 +21,16 @@ def my_function_one(*args, **kwargs): ### Options 1. Keys -2. Eviction policies +2. Eviction policies (coming soon) 3. Backend -4. Max memory limit -5. Key expiry time +4. Max memory limit (coming soon) +5. Key expiry time (coming soon) ## Contributing to cache4py -These instructions will get you a copy of the project up and running on your local machine for development and testing. - TODO - -### Prerequisites - -Install the python package requirements using the following command: - -``` -pip install -r requirements.txt -``` -### Running the tests - -Run unit tests using the command: - -``` -pytest --cov=cache4py --cov-report html tests/ -``` +Refer CONTRIBUTING.md ## Issue tracking diff --git a/cache4py/storage/redis.py b/cache4py/storage/redis.py index 04a3b01..308a903 100644 --- a/cache4py/storage/redis.py +++ b/cache4py/storage/redis.py @@ -17,19 +17,19 @@ class RedisBackend(BaseBackend): Wrapper over redis client object provided by python redis library. Supports storing objects in redis. """ - def __init__(self, server, port=6379): + def __init__(self, url, port=6379): """ Initialize redis client as a cache backend. - :param server: URL of redis service. + :param url: URL of redis service. :param port: Port number at which redis service is exposed. If not specified, uses port 6379 by default. """ - self.__server = server + self.__server = url self.__port = port - self.__client = redis.StrictRedis(host=server, port=port) + self.__client = redis.StrictRedis(host=url, port=port) try: self.__client.ping() except redis.ConnectionError as connection_error: - warnings.warn('Failed to connect to redis server: {0} at port: {1}'.format(server, port)) + warnings.warn('Failed to connect to redis server: {0} at port: {1}'.format(url, port)) raise RedisBackendException(connection_error) def is_client_valid(self): diff --git a/cache4py/utils.py b/cache4py/utils.py index 2c7e509..38c6787 100644 --- a/cache4py/utils.py +++ b/cache4py/utils.py @@ -29,6 +29,6 @@ def hash_key(python_object): :param python_object: A python object. :return: Consistent sha224 hash for the key_object. """ - serialized_key = pickle.dumps(python_object) + serialized_key = pickle.dumps(python_object, protocol=pickle.HIGHEST_PROTOCOL) hashed_key = sha224(serialized_key).hexdigest() return hashed_key diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..22d5128 --- /dev/null +++ b/setup.py @@ -0,0 +1,169 @@ +""" +Author: nitin +Date: 19/10/18 +Description: setup.py +""" + +# !/usr/bin/env python +# -*- coding: utf-8 -*- + +# Note: To use the 'upload' functionality of this file, you must: +# $ pip install twine + +import io +import os +import sys +from shutil import rmtree + +from setuptools import find_packages, setup, Command + +# Package meta-data. +NAME = 'cache4py' +DESCRIPTION = 'Caching simplified.' +URL = 'https://github.com/nitinl/cache4py' +EMAIL = 'nitinlabhishetty@gmail.com' +AUTHOR = 'Nitin Labhishetty' +REQUIRES_PYTHON = '>=3.6.0' +VERSION = '0.0.1' + +# What packages are required for this module to be executed? +REQUIRED = [ + 'redis', 'pymemcache', +] + +# What packages are optional? +EXTRAS = { + 'test': ['pytest', 'pytest-cov'], +} + +# The rest you shouldn't have to touch too much :) +# ------------------------------------------------ +# Except, perhaps the License and Trove Classifiers! +# If you do change the License, remember to change the Trove Classifier for that! + +here = os.path.abspath(os.path.dirname(__file__)) + +# Import the README and use it as the long-description. +# Note: this will only work if 'README.md' is present in your MANIFEST.in file! +try: + with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = '\n' + f.read() +except FileNotFoundError: + long_description = DESCRIPTION + +# Load the package's __version__.py module as a dictionary. +about = {} +if not VERSION: + with open(os.path.join(here, NAME, '__version__.py')) as f: + exec(f.read(), about) +else: + about['__version__'] = VERSION + + +class UploadCommand(Command): + """Support setup.py upload.""" + + description = 'Build and publish the package.' + user_options = [] + + @staticmethod + def status(s): + """Prints things in bold.""" + print('\033[1m{0}\033[0m'.format(s)) + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + try: + self.status('Removing previous builds…') + rmtree(os.path.join(here, 'dist')) + except OSError: + pass + + self.status('Building Source and Wheel (universal) distribution…') + os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) + + self.status('Uploading the package to PyPI via Twine…') + os.system('twine upload dist/*') + + self.status('Pushing git tags…') + os.system('git tag v{0}'.format(about['__version__'])) + os.system('git push --tags') + + sys.exit() + +class TestUploadCommand(Command): + """Support setup.py upload.""" + + description = 'Build and publish the package to test pypi.' + user_options = [] + + @staticmethod + def status(s): + """Prints things in bold.""" + print('\033[1m{0}\033[0m'.format(s)) + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + try: + self.status('Removing previous builds…') + rmtree(os.path.join(here, 'dist')) + except OSError: + pass + + self.status('Building Source and Wheel (universal) distribution…') + os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) + + self.status('Uploading the package to PyPI via Twine…') + os.system('twine upload --repository-url https://test.pypi.org/legacy/ dist/*') + + sys.exit() + + +# Where the magic happens: +setup( + name=NAME, + version=about['__version__'], + description=DESCRIPTION, + long_description=long_description, + long_description_content_type='text/markdown', + author=AUTHOR, + author_email=EMAIL, + python_requires=REQUIRES_PYTHON, + url=URL, + packages=find_packages(exclude=('tests',)), + # If your package is a single module, use this instead of 'packages': + # py_modules=['mypackage'], + + # entry_points={ + # 'console_scripts': ['mycli=mymodule:cli'], + # }, + install_requires=REQUIRED, + extras_require=EXTRAS, + include_package_data=True, + license='MIT', + classifiers=[ + # Trove classifiers + # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy' + ], + # $ setup.py publish support. + cmdclass={ + 'upload': UploadCommand, + 'test_upload': TestUploadCommand, + }, +) \ No newline at end of file diff --git a/tests/test_basic.py b/tests/test_basic.py index 6141a87..f620ad9 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -37,7 +37,7 @@ def test_redis(): start_time = time.time() for i in range(5): - _ = redis_target_function(75000) + _ = redis_target_function(75000) cached_time = time.time() - start_time print("Time difference: before: {0}, after: {1}".format(uncached_time, cached_time)) From a3ddb1e40a882860a1089b21e0d831784775bda3 Mon Sep 17 00:00:00 2001 From: nitinl Date: Sat, 20 Oct 2018 19:40:10 +0530 Subject: [PATCH 2/2] Added badges to README :) --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0b20b66..ac010ab 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # cache4py: Caching simplified. +[![PyPI version shields.io](https://img.shields.io/pypi/v/cache4py.svg)](https://pypi.python.org/pypi/cache4py/) +[![PyPI pyversions](https://img.shields.io/pypi/pyversions/cache4py.svg)](https://pypi.python.org/pypi/cache4py/) +[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/) + ## Getting started ### Installation