-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial commit; readme & initial tests
- Loading branch information
0 parents
commit d029937
Showing
8 changed files
with
215 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
Copyright (c) 2012, Ben Davis | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above copyright | ||
notice, this list of conditions and the following disclaimer in the | ||
documentation and/or other materials provided with the distribution. | ||
* Neither the name of python-gitmodel nor the names of its contributors may | ||
be used to endorse or promote products derived from this software without | ||
specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ABOVE BE LIABLE FOR ANY | ||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
=============== | ||
python-gitmodel | ||
=============== | ||
A distributed, versioned data store for Python | ||
---------------------------------------------- | ||
|
||
python-gitmodel is a framework for persisting objects using Git for versioning | ||
and remote syncing. | ||
|
||
Why? | ||
---- | ||
According to Git's README[1], Git is a "stupid content tracker". That means you | ||
aren't limited to storing source code in git. The goal of this project is to | ||
provide an object-level interface to use git as a schema-less data store, as | ||
well as tools that take advantage of gits powerful versioning capabilities. | ||
|
||
python-gitmodel is based on libgit2[2], a pure C implementation of the Git core | ||
methods. This means that instead of calling git commands via shell, we get | ||
to use git at native speed. | ||
|
||
What it's good for | ||
------------------ | ||
* Schema-less data store | ||
* Never lose data. History is kept forever and can be restored using git tools. | ||
* Branch and merge your production data | ||
* python-gitmodel can work with different branches | ||
* branch or tag snapshots of your data | ||
* experiment on production data using branches, for example, to test a migration | ||
|
||
|
||
------------------------------------------------------------------------------- | ||
|
||
python-gitmodel was inspired by Rick Olson's talk, "Git, the Stupid NoSQL | ||
Database"[3] and Paul Downman's GitModel[4] for ruby. | ||
|
||
------------------------------------------------------------------------------- | ||
|
||
.. [1] https://github.com/git/git#readme | ||
.. [2] http://libgit2.github.com | ||
.. [3] http://git-nosql-rubyconf.heroku.com/ | ||
.. [4] https://github.com/pauldowman/gitmodel/ |
Empty file.
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from gitmodel.models import GitModel | ||
from gitmodel import fields | ||
|
||
class Author(GitModel): | ||
email = fields.CharField() | ||
first_name = fields.CharField() | ||
last_name = fields.CharField() | ||
|
||
class Post(GitModel): | ||
slug = fields.SlugField(id=True) | ||
title = fields.CharField() | ||
body = fields.CharField() | ||
author = fields.ToOneField(Author, required=False) | ||
image = fields.ImageField(required=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import os | ||
import shutil | ||
import unittest | ||
import tempfile | ||
import pygit2 | ||
|
||
class GitModelBasicTest(unittest.TestCase): | ||
def setUp(self): | ||
from gitmodel.test.basic import models | ||
from gitmodel import config | ||
from gitmodel.utils import json | ||
from gitmodel import exceptions | ||
|
||
self.models = models | ||
self.config = config | ||
self.json = json | ||
self.exceptions = exceptions | ||
|
||
config.REPOSITORY_PATH = tempfile.mkdtemp() | ||
|
||
# gitmodel does not create your repo for you | ||
self.repo = pygit2.init_repository(config.REPOSITORY_PATH) | ||
self.index = self.repo.index | ||
self.index.read() | ||
|
||
self.author = models.Author( | ||
email='[email protected]', | ||
first_name='John', | ||
last_name='Doe' | ||
) | ||
|
||
self.post = models.Post( | ||
slug='test-post', | ||
title='Test Post', | ||
body='Lorem ipsum dolor sit amet', | ||
) | ||
|
||
def tearDown(self): | ||
# clean up test repo | ||
shutil.rmtree(self.config.REPOSITORY_PATH) | ||
|
||
def test_tree_name(self): | ||
self.assertEqual(self.models.Author._meta.tree_name, 'author') | ||
self.assertEqual(self.models.Post._meta.tree_name, 'post') | ||
|
||
def test_get_path(self): | ||
self.author.save() | ||
# author id should be 1 | ||
path = self.author.get_path() | ||
self.assertEqual(path, 'author/1') | ||
|
||
def test_get_oid(self): | ||
self.author.save() | ||
test_oid = self.author.get_oid() | ||
oid = self.index[self.author.get_path()] | ||
self.assertEqual(oid, test_oid) | ||
|
||
def test_save(self): | ||
# Save is analagous to "git add" | ||
self.author.save() | ||
|
||
# get json using libgit2 | ||
path = os.path.join(self.author._meta.tree_name, self.author.id) | ||
entry = self.index[path] | ||
blob = self.repo[entry.oid] | ||
|
||
# verify data | ||
data = self.json.loads(blob.data) | ||
self.assertEqual(data, { | ||
'first_name': 'John', | ||
'last_name': 'Doe', | ||
'email': '[email protected]' | ||
}) | ||
|
||
def test_get_simple_object(self): | ||
self.author.save() | ||
author = self.models.Author.find(1) | ||
self.assertEqual(author.first_name, 'John') | ||
self.assertEqual(author.last_name, 'Doe') | ||
self.assertEqual(author.email, 'johndoe') | ||
|
||
def test_custom_id_field(self): | ||
# id should resolve to the slug field, since slug is marked as id=True | ||
self.post.save() | ||
self.assertEqual(self.post.id, self.post.slug) | ||
|
||
def test_id_auto_increment(self): | ||
author1 = self.author.save() | ||
author2 = self.models.Author( | ||
email='[email protected]', | ||
first_name='Jane', | ||
last_name='Doe' | ||
) | ||
author2.save() | ||
|
||
self.assertEqual(author1.id, 1) | ||
self.assertEqual(author2.id, 2) | ||
|
||
def test_id_validator(self): | ||
# "/" and "\0" are both invalid characters | ||
with self.assertRaises(ValueError): | ||
self.author.email='foo/bar' | ||
with self.assertRaises(ValueError): | ||
self.author.email='foo\000bar' | ||
|
||
def test_create_object_with_binary(self): | ||
fd = open(os.path.join(self.static_dir, 'git-logo-2color.png')) | ||
self.post.image = fd | ||
self.post.save() | ||
|
||
#make sure stored file and original file are identical | ||
fd.seek(0) | ||
entry = self.repo[self.post.get_path()] | ||
blob = self.repo[entry.oid] | ||
orig_content = fd.read() | ||
self.assertEqual(blob, orig_content) | ||
|
||
def test_require_fields(self): | ||
test_author = self.models.Author(first_name='Jane') | ||
with self.assertRaises(self.exceptions.ValidationError): | ||
test_author.save() | ||
|
||
def test_related(self): | ||
self.author.save() | ||
self.post.author = self.author | ||
self.post.save() | ||
self.assertUnless(False) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/usr/bin/env python | ||
import unittest | ||
|
||
tests = ('basic',) | ||
|
||
if __name__ == "__main__": | ||
for mod in tests: | ||
unittest.main('{}.tests'.format(mod), exit=False) |