├── .bumpversion.cfg ├── .coveragerc ├── .gitignore ├── .travis.yml ├── AUTHORS.rst ├── CONTRIBUTING.rst ├── Changelog ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── bottle_peewee.py ├── requirements-tests.txt ├── requirements.txt ├── setup.cfg ├── setup.py ├── tests ├── __init__.py └── test_bottle_peewee.py └── tox.ini /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | commit = True 3 | current_version = 0.1.5 4 | files = bottle_peewee.py 5 | tag = True 6 | tag_name = {new_version} 7 | 8 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [report] 2 | source=bottle_peewee 3 | 4 | [run] 5 | source=bottle_peewee 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | 37 | # Complexity 38 | output/*.html 39 | output/*/index.html 40 | 41 | # Sphinx 42 | docs/_build 43 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 2.7 4 | 5 | env: 6 | - TOXENV=py27 7 | - TOXENV=py34 8 | - TOXENV=cov 9 | 10 | branches: 11 | only: 12 | - master 13 | - develop 14 | 15 | install: pip install --quiet --use-mirrors tox 16 | 17 | script: tox 18 | 19 | after_script: 20 | - if [ $TOXENV == "cov" ]; then 21 | pip install --quiet --use-mirrors coveralls; 22 | coveralls; 23 | fi 24 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Credits 3 | ======= 4 | 5 | Development Lead 6 | ---------------- 7 | 8 | * Kirill Klenov 9 | 10 | Contributors 11 | ------------ 12 | 13 | None yet. Why not be the first? -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributing 3 | ============ 4 | 5 | Contributions are welcome, and they are greatly appreciated! Every 6 | little bit helps, and credit will always be given. 7 | 8 | You can contribute in many ways: 9 | 10 | Types of Contributions 11 | ---------------------- 12 | 13 | Report Bugs 14 | ~~~~~~~~~~~ 15 | 16 | Report bugs at https://github.com/klen/bottle-peewee/issues. 17 | 18 | If you are reporting a bug, please include: 19 | 20 | * Your operating system name and version. 21 | * Any details about your local setup that might be helpful in troubleshooting. 22 | * Detailed steps to reproduce the bug. 23 | 24 | Fix Bugs 25 | ~~~~~~~~ 26 | 27 | Look through the GitHub issues for bugs. Anything tagged with "bug" 28 | is open to whoever wants to implement it. 29 | 30 | Implement Features 31 | ~~~~~~~~~~~~~~~~~~ 32 | 33 | Look through the GitHub issues for features. Anything tagged with "feature" 34 | is open to whoever wants to implement it. 35 | 36 | Write Documentation 37 | ~~~~~~~~~~~~~~~~~~~ 38 | 39 | bottle-peewee could always use more documentation, whether as part of the 40 | official bottle-peewee docs, in docstrings, or even on the web in blog posts, 41 | articles, and such. 42 | 43 | Submit Feedback 44 | ~~~~~~~~~~~~~~~ 45 | 46 | The best way to send feedback is to file an issue at https://github.com/klen/bottle-peewee/issues. 47 | 48 | If you are proposing a feature: 49 | 50 | * Explain in detail how it would work. 51 | * Keep the scope as narrow as possible, to make it easier to implement. 52 | * Remember that this is a volunteer-driven project, and that contributions 53 | are welcome :) 54 | 55 | Get Started! 56 | ------------ 57 | 58 | Ready to contribute? Here's how to set up `bottle-peewee` for 59 | local development. 60 | 61 | 1. Fork_ the `bottle-peewee` repo on GitHub. 62 | 2. Clone your fork locally:: 63 | 64 | $ git clone git@github.com:your_name_here/bottle-peewee.git 65 | 66 | 3. Create a branch for local development:: 67 | 68 | $ git checkout -b name-of-your-bugfix-or-feature 69 | 70 | Now you can make your changes locally. 71 | 72 | 4. When you're done making changes, check that your changes pass style and unit 73 | tests, including testing other Python versions with tox:: 74 | 75 | $ tox 76 | 77 | To get tox, just pip install it. 78 | 79 | 5. Commit your changes and push your branch to GitHub:: 80 | 81 | $ git add . 82 | $ git commit -m "Your detailed description of your changes." 83 | $ git push origin name-of-your-bugfix-or-feature 84 | 85 | 6. Submit a pull request through the GitHub website. 86 | 87 | .. _Fork: https://github.com/Nekroze/bottle-peewee/fork 88 | 89 | Pull Request Guidelines 90 | ----------------------- 91 | 92 | Before you submit a pull request, check that it meets these guidelines: 93 | 94 | 1. The pull request should include tests. 95 | 2. If the pull request adds functionality, the docs should be updated. Put 96 | your new functionality into a function with a docstring, and add the 97 | feature to the list in README.rst. 98 | 3. The pull request should work for Python 2.6, 2.7, and 3.3, and for PyPy. 99 | Check https://travis-ci.org/klen/bottle-peewee 100 | under pull requests for active pull requests or run the ``tox`` command and 101 | make sure that the tests pass for all supported Python versions. 102 | 103 | 104 | Tips 105 | ---- 106 | 107 | To run a subset of tests:: 108 | 109 | $ py.test test/test_bottle-peewee.py -------------------------------------------------------------------------------- /Changelog: -------------------------------------------------------------------------------- 1 | 2014-12-20 klen 2 | 3 | * Version 0.1.0 4 | * Initial release -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2014, Kirill Klenov 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include MANIFEST.in 3 | include README.rst 4 | include requirements.txt 5 | include bottle_peewee.py 6 | 7 | recursive-exclude * __pycache__ 8 | recursive-exclude * *.py[co] 9 | recursive-exclude * *.orig 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VIRTUALENV=$(shell echo "$${VDIR:-'.env'}") 2 | 3 | all: $(VIRTUALENV) 4 | 5 | .PHONY: help 6 | # target: help - Display callable targets 7 | help: 8 | @egrep "^# target:" [Mm]akefile 9 | 10 | .PHONY: clean 11 | # target: clean - Display callable targets 12 | clean: 13 | rm -rf build/ dist/ docs/_build *.egg-info 14 | find $(CURDIR) -name "*.py[co]" -delete 15 | find $(CURDIR) -name "*.orig" -delete 16 | find $(CURDIR)/$(MODULE) -name "__pycache__" | xargs rm -rf 17 | 18 | # ============== 19 | # Bump version 20 | # ============== 21 | 22 | .PHONY: release 23 | VERSION?=minor 24 | # target: release - Bump version 25 | release: 26 | @$(VIRTUALENV)/bin/pip install bumpversion 27 | @$(VIRTUALENV)/bin/bumpversion $(VERSION) 28 | @git checkout master 29 | @git merge develop 30 | @git checkout develop 31 | @git push origin develop master 32 | @git push --tags 33 | 34 | .PHONY: minor 35 | minor: release 36 | 37 | .PHONY: patch 38 | patch: 39 | make release VERSION=patch 40 | 41 | .PHONY: major 42 | major: 43 | make release VERSION=major 44 | 45 | # =============== 46 | # Build package 47 | # =============== 48 | 49 | .PHONY: register 50 | # target: register - Register module on PyPi 51 | register: 52 | @$(VIRTUALENV)/bin/python setup.py register 53 | 54 | .PHONY: upload 55 | # target: upload - Upload module on PyPi 56 | upload: clean 57 | @$(VIRTUALENV)/bin/pip install twine wheel 58 | @$(VIRTUALENV)/bin/python setup.py sdist bdist_wheel 59 | @$(VIRTUALENV)/bin/twine upload dist/* 60 | 61 | # ============= 62 | # Development 63 | # ============= 64 | 65 | $(VIRTUALENV): requirements.txt 66 | @[ -d $(VIRTUALENV) ] || virtualenv --no-site-packages $(VIRTUALENV) 67 | @$(VIRTUALENV)/bin/pip install -r requirements.txt 68 | @touch $(VIRTUALENV) 69 | 70 | $(VIRTUALENV)/bin/py.test: $(VIRTUALENV) requirements-tests.txt 71 | @$(VIRTUALENV)/bin/pip install -r requirements-tests.txt 72 | @touch $(VIRTUALENV)/bin/py.test 73 | 74 | .PHONY: test 75 | # target: test - Runs tests 76 | test: $(VIRTUALENV)/bin/py.test 77 | @$(VIRTUALENV)/bin/py.test -xs 78 | 79 | .PHONY: t 80 | t: test 81 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Bottle Peewee 2 | ############# 3 | 4 | .. _description: 5 | 6 | Bottle Peewee -- Provide Peewee ORM integration to Bottle framework. 7 | 8 | .. _badges: 9 | 10 | .. image:: http://img.shields.io/travis/klen/bottle-peewee.svg?style=flat-square 11 | :target: http://travis-ci.org/klen/bottle-peewee 12 | :alt: Build Status 13 | 14 | .. image:: http://img.shields.io/coveralls/klen/bottle-peewee.svg?style=flat-square 15 | :target: https://coveralls.io/r/klen/bottle-peewee 16 | :alt: Coverals 17 | 18 | .. image:: http://img.shields.io/pypi/v/bottle-peewee.svg?style=flat-square 19 | :target: https://pypi.python.org/pypi/bottle-peewee 20 | 21 | .. image:: http://img.shields.io/pypi/dm/bottle-peewee.svg?style=flat-square 22 | :target: https://pypi.python.org/pypi/bottle-peewee 23 | 24 | .. image:: http://img.shields.io/gratipay/klen.svg?style=flat-square 25 | :target: https://www.gratipay.com/klen/ 26 | :alt: Donate 27 | 28 | .. _contents: 29 | 30 | .. contents:: 31 | 32 | .. _requirements: 33 | 34 | Requirements 35 | ============= 36 | 37 | - python >= 2.6 38 | 39 | .. _installation: 40 | 41 | Installation 42 | ============= 43 | 44 | **Bottle Peewee** should be installed using pip: :: 45 | 46 | pip install bottle-peewee 47 | 48 | .. _usage: 49 | 50 | Usage 51 | ===== 52 | 53 | :: 54 | 55 | from bottle import Bottle 56 | from bottle_peewee import PeeweePlugin 57 | from peewee import Model, CharField 58 | 59 | app = Bottle() 60 | db = PeeweePlugin('sqlite:///:memory:') 61 | 62 | class User(Model): 63 | name = CharField() 64 | 65 | class Meta(object): 66 | database = db.proxy 67 | 68 | app.install(db) 69 | 70 | db.database.create_table(User) 71 | User.create(name='test') 72 | assert [user for user in User.select()] 73 | 74 | 75 | Configuration 76 | ------------- 77 | 78 | PEEWEE_CONNECTION -- A connection string to database 79 | 80 | .. _bugtracker: 81 | 82 | Bug tracker 83 | =========== 84 | 85 | If you have any suggestions, bug reports or 86 | annoyances please report them to the issue tracker 87 | at https://github.com/klen/bottle-peewee/issues 88 | 89 | .. _contributing: 90 | 91 | Contributing 92 | ============ 93 | 94 | Development of Bottle Peewee happens at: https://github.com/klen/bottle-peewee 95 | 96 | 97 | Contributors 98 | ============= 99 | 100 | * klen_ (Kirill Klenov) 101 | 102 | .. _license: 103 | 104 | License 105 | ======= 106 | 107 | Licensed under a `BSD license`_. 108 | 109 | .. _links: 110 | 111 | .. _BSD license: http://www.linfo.org/bsdlicense.html 112 | .. _klen: https://github.com/klen 113 | -------------------------------------------------------------------------------- /bottle_peewee.py: -------------------------------------------------------------------------------- 1 | # Package information 2 | # =================== 3 | import datetime 4 | 5 | from peewee import PeeweeException, Proxy, Model 6 | from playhouse.db_url import connect 7 | from playhouse.shortcuts import model_to_dict, dict_to_model 8 | 9 | 10 | __version__ = "0.1.5" 11 | __project__ = "bottle-peewee" 12 | __author__ = "Kirill Klenov " 13 | __license__ = "MIT" 14 | 15 | 16 | class PeeweePlugin(object): 17 | 18 | """ Integrate peewee to bottle. """ 19 | 20 | name = 'peewee' 21 | api = 2 22 | default_connection = 'sqlite:///db.sqlite' 23 | 24 | def __init__(self, connection=None): 25 | self.database = None 26 | self.connection = connection or self.default_connection 27 | self.proxy = Proxy() 28 | self.serializer = Serializer() 29 | 30 | def setup(self, app): 31 | """ Initialize the application. """ 32 | 33 | app.config.setdefault('PEEWEE_CONNECTION', self.connection) 34 | self.connection = app.config.get('PEEWEE_CONNECTION') 35 | self.database = connect(self.connection) 36 | self.proxy.initialize(self.database) 37 | 38 | def apply(self, callback, route): 39 | 40 | def wrapper(*args, **kwargs): 41 | if self.connection.startswith('sqlite'): 42 | return callback(*args, **kwargs) 43 | 44 | self.database.connect() 45 | try: 46 | with self.database.transaction(): 47 | response = callback(*args, **kwargs) 48 | except PeeweeException: 49 | self.database.rollback() 50 | raise 51 | finally: 52 | self.database.commit() 53 | if not self.database.is_closed(): 54 | self.database.close() 55 | 56 | return response 57 | 58 | return wrapper 59 | 60 | def to_dict(self, obj, **kwargs): 61 | return self.serializer.serialize_object(obj, **kwargs) 62 | 63 | 64 | class Serializer(object): 65 | date_format = '%Y-%m-%d' 66 | time_format = '%H:%M:%S' 67 | datetime_format = ' '.join([date_format, time_format]) 68 | 69 | def convert_value(self, value): 70 | if isinstance(value, datetime.datetime): 71 | return value.strftime(self.datetime_format) 72 | 73 | if isinstance(value, datetime.date): 74 | return value.strftime(self.date_format) 75 | 76 | if isinstance(value, datetime.time): 77 | return value.strftime(self.time_format) 78 | 79 | if isinstance(value, Model): 80 | return value.get_id() 81 | 82 | return value 83 | 84 | def clean_data(self, data): 85 | for key, value in data.items(): 86 | if isinstance(value, dict): 87 | self.clean_data(value) 88 | elif isinstance(value, (list, tuple)): 89 | data[key] = map(self.clean_data, value) 90 | else: 91 | data[key] = self.convert_value(value) 92 | return data 93 | 94 | def serialize_object(self, obj, **kwargs): 95 | data = model_to_dict(obj, **kwargs) 96 | return self.clean_data(data) 97 | 98 | 99 | class Deserializer(object): 100 | 101 | @staticmethod 102 | def deserialize_object(model, data): 103 | return dict_to_model(model, data) 104 | -------------------------------------------------------------------------------- /requirements-tests.txt: -------------------------------------------------------------------------------- 1 | -r requirements.txt 2 | 3 | ipdb 4 | pytest 5 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | peewee 2 | bottle 3 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [wheel] 2 | universal = 1 3 | 4 | [pylama:setup.py] 5 | ignore=D 6 | 7 | [pytest] 8 | addopts = -s 9 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import re 3 | from os import path as op 4 | 5 | from setuptools import setup 6 | 7 | 8 | def _read(fname): 9 | try: 10 | return open(op.join(op.dirname(__file__), fname)).read() 11 | except IOError: 12 | return '' 13 | 14 | _meta = _read('bottle_peewee.py') 15 | _license = re.search(r'^__license__\s*=\s*"(.*)"', _meta, re.M).group(1) 16 | _project = re.search(r'^__project__\s*=\s*"(.*)"', _meta, re.M).group(1) 17 | _version = re.search(r'^__version__\s*=\s*"(.*)"', _meta, re.M).group(1) 18 | 19 | install_requires = [ 20 | l for l in _read('requirements.txt').split('\n') 21 | if l and not l.startswith('#')] 22 | 23 | setup( 24 | name=_project, 25 | version=_version, 26 | license=_license, 27 | description=_read('DESCRIPTION'), 28 | long_description=_read('README.rst'), 29 | platforms=('Any'), 30 | keywords = "bottle peewee".split(), # noqa 31 | 32 | author='Kirill Klenov', 33 | author_email='horneds@gmail.com', 34 | url='https://github.com/klen/bottle-peewee', 35 | classifiers=[ 36 | 'Development Status :: 4 - Beta', 37 | 'Intended Audience :: Developers', 38 | 'License :: OSI Approved :: BSD License', 39 | 'Natural Language :: English', 40 | 'Natural Language :: Russian', 41 | 'Operating System :: OS Independent', 42 | 'Programming Language :: Python :: 2', 43 | 'Programming Language :: Python :: 3', 44 | 'Programming Language :: Python', 45 | 'Topic :: Software Development :: Libraries :: Python Modules', 46 | 'Topic :: Software Development :: Testing', 47 | 'Topic :: Utilities', 48 | ], 49 | 50 | py_modules=['bottle_peewee'], 51 | install_requires=install_requires, 52 | ) 53 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klen/bottle-peewee/718e38bb3a39c835ca9b437c2802765c7c563c39/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_bottle_peewee.py: -------------------------------------------------------------------------------- 1 | """ Tests for `bottle-peewee` module. """ 2 | from bottle import Bottle 3 | from bottle_peewee import PeeweePlugin 4 | import datetime as dt 5 | from peewee import Model, CharField, DateTimeField, ForeignKeyField 6 | 7 | 8 | def test_bottle_peewee(): 9 | 10 | app = Bottle() 11 | db = PeeweePlugin('sqlite:///:memory:') 12 | 13 | class Role(Model): 14 | name = CharField() 15 | 16 | class Meta(object): 17 | database = db.proxy 18 | 19 | class User(Model): 20 | name = CharField() 21 | created = DateTimeField(default=dt.datetime.now) 22 | 23 | role = ForeignKeyField(Role) 24 | 25 | class Meta(object): 26 | database = db.proxy 27 | 28 | app.install(db) 29 | 30 | db.database.create_tables([User, Role]) 31 | User.create(name='test', role=Role.create(name='admin')) 32 | assert [user for user in User.select()] 33 | 34 | data = db.to_dict(User.get()) 35 | assert data 36 | assert data['name'] == 'test' 37 | assert data['created'] 38 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist=py27,py34,cov 3 | 4 | [pytest] 5 | addopts = -xs tests 6 | 7 | [pylama] 8 | ignore=D 9 | 10 | [testenv] 11 | commands=py.test 12 | deps = -rrequirements-tests.txt 13 | 14 | [testenv:cov] 15 | deps = 16 | coverage 17 | {[testenv]deps} 18 | 19 | commands = 20 | coverage run -m py.test 21 | coverage report 22 | --------------------------------------------------------------------------------