|
| 1 | +# python-gitmodel |
| 2 | + |
| 3 | +[](https://badge.fury.io/py/gitarmony-python) |
| 4 | +[](https://gitarmony-python.readthedocs.io/en/latest) |
| 5 | +[](https://codecov.io/gh/bendavis78/python-gitmodel) |
| 6 | + |
| 7 | +## A distributed, versioned data store for Python |
| 8 | + |
| 9 | +python-gitmodel is a framework for persisting objects using Git for |
| 10 | +versioning and remote syncing. |
| 11 | + |
| 12 | +## Why? |
| 13 | + |
| 14 | +According to [Git's README](<https://github.com/git/git#readme>), Git |
| 15 | +is a \"stupid content tracker\". That means you aren\'t limited to |
| 16 | +storing source code in git. The goal of this project is to provide an |
| 17 | +object-level interface to use git as a schema-less data store, as well |
| 18 | +as tools that take advantage of git\'s powerful versioning capabilities. |
| 19 | + |
| 20 | +python-gitmodel allows you to model your data using python, and provides |
| 21 | +an easy-to-use interface for storing that data as git objects. |
| 22 | + |
| 23 | +python-gitmodel is based on [libgit2](<http://libgit2.github.com>), a |
| 24 | +pure C implementation of the Git core methods. This means that instead |
| 25 | +of calling git commands via shell, we get to use git at native speed. |
| 26 | + |
| 27 | +## What\'s so great about it? |
| 28 | + |
| 29 | +* Schema-less data store |
| 30 | +* Never lose data. History is kept forever and can be restored using |
| 31 | +* git tools. |
| 32 | +* Branch and merge your production data |
| 33 | + * gitmodel can work with different branches |
| 34 | + * branch or tag snapshots of your data |
| 35 | + * experiment on production data using branches, for example, to test a migration |
| 36 | +* Ideal for content-driven applications |
| 37 | + |
| 38 | +## Example usage |
| 39 | + |
| 40 | +Below we\'ll cover a use-case for a basic flat-page CMS. |
| 41 | + |
| 42 | +Basic model creation: |
| 43 | +```python |
| 44 | + from gitmodel.workspace import Workspace from gitmodel import fields ws = Workspace('path/to/my-repo/.git') class Page(ws.GitModel): slug = fields.SlugField() title = fields.CharField() content = fields.CharField() published = fields.BooleanField(default=True) |
| 45 | + ``` |
| 46 | + |
| 47 | +The Workspace can be thought of as your git working directory. It also |
| 48 | +acts as the \"porcelain\" layer to pygit2\'s \"plumbing\". In contrast |
| 49 | +to a working directory, the Workspace class does not make use of the |
| 50 | +repository\'s INDEX and HEAD files, and instead keeps track of these in |
| 51 | +memory. |
| 52 | + |
| 53 | +Saving objects: |
| 54 | +```python |
| 55 | + page = Page(slug='example-page', title='Example Page') page.content = '<h2>Here is an Example</h2><p>Lorem Ipsum</p>' page.save() print(page.id) # abc99c394ab546dd9d6e3381f9c0fb4b |
| 56 | + ``` |
| 57 | + |
| 58 | +By default, objects get an auto-ID field which saves as a python UUID |
| 59 | +hex (don\'t confuse these with git hashes). You can easily customize |
| 60 | +which field in your model acts as the ID field, for example: |
| 61 | +```python |
| 62 | + class Page(ws.GitModel): slug = fields.SlugField(id=True) # OR class Page(ws.GitModel): slug = fields.SlugField() class Meta: id_field = 'slug' |
| 63 | + ``` |
| 64 | + |
| 65 | +Objects are not committed to the repository by default. They are, |
| 66 | +however, written into the object database as trees and blobs. The |
| 67 | +[Workspace.index]{.title-ref} object is a [pygit2.Tree]{.title-ref} that |
| 68 | +holds the uncommitted data. It\'s analagous to Git\'s index, except that |
| 69 | +the pointer is stored in memory. |
| 70 | + |
| 71 | +Creating commits is simple: |
| 72 | +```python |
| 73 | + oid = page.save(commit=True, message='Added an example page') commit = ws.repo[oid] # a pygit2.Commit object print(commit.message) |
| 74 | + ``` |
| 75 | + |
| 76 | +You can access previous commits using pygit2, and even view diffs |
| 77 | +between two versions of an object. |
| 78 | +```python |
| 79 | + # walking commits for commit in ws.walk(): print("{}: {}".format(commit.hex, commit.message)) # get a diff between two commits head_commit = ws.branch.commit prev_commit_oid = head_commit.parents[0] print(prev_commit.diff(head_commit)) |
| 80 | + ``` |
| 81 | + |
| 82 | +Objects can be easily retrieved by their id: |
| 83 | +```python |
| 84 | + page = Page.get('example-page') print(page.content) |
| 85 | + ``` |
| 86 | + |
| 87 | +# Caveat Emptor |
| 88 | + |
| 89 | +Git doesn\'t perform very well on its own. If you need your git-backed |
| 90 | +data to perform well in a production environment, you need to get it a |
| 91 | +\"wingman\". Since python-gitmodel can be used in a variety of ways, |
| 92 | +it\'s up to you to decide the best way to optimize it. |
| 93 | + |
| 94 | +# Status |
| 95 | + |
| 96 | +This project is no longer under active development. |
| 97 | + |
| 98 | +# TODO |
| 99 | + |
| 100 | +* Caching? |
| 101 | +* Indexing? |
| 102 | +* Query API? |
| 103 | +* Full documentation |
| 104 | + |
| 105 | +python-gitmodel was inspired by Rick Olson\'s talk, \"[Git, the Stupid |
| 106 | +NoSQL Database](<http://git-nosql-rubyconf.heroku.com/>)\" and Paul |
| 107 | +Downman\'s [GitModel](<https://github.com/pauldowman/gitmodel/>) for |
| 108 | +ruby. |
| 109 | + |
| 110 | +# Development |
| 111 | + |
| 112 | +This projects requires the following: |
| 113 | + |
| 114 | +- [Python >=3.7.9](https://www.python.org/downloads/release/python-379/) |
| 115 | +- [virtualenwrapper](https://pypi.org/project/virtualenvwrapper/) (macOS/Linux) |
| 116 | +- [virtualenwrapper-win](https://pypi.org/project/virtualenvwrapper-win/) (Windows) |
| 117 | + |
| 118 | +Make sure your `WORKON_HOME` environment variable is set on Windows, and create a `gitmodel` virtual environment with `mkvirtualenv`. |
| 119 | +Build systems for installing requirements and running tests are on board of the SublimeText project. |
0 commit comments