Skip to content

Commit

Permalink
initial commit; readme & initial tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bendavis78 committed Jul 28, 2012
0 parents commit d029937
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 0 deletions.
24 changes: 24 additions & 0 deletions LICENSE
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.
41 changes: 41 additions & 0 deletions README.rst
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 added gitmodel/test/__init__.py
Empty file.
Empty file added gitmodel/test/basic/__init__.py
Empty file.
Binary file added gitmodel/test/basic/git-logo-2color.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions gitmodel/test/basic/models.py
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)
128 changes: 128 additions & 0 deletions gitmodel/test/basic/tests.py
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)

8 changes: 8 additions & 0 deletions gitmodel/test/runtests.py
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)

0 comments on commit d029937

Please sign in to comment.