{ "info": { "author": "Hunter Richards", "author_email": "opensource@counsyl.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Framework :: Django", "Intended Audience :: Developers", "Intended Audience :: Financial and Insurance Industry", "Intended Audience :: Healthcare Industry", "Intended Audience :: Legal Industry", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Topic :: Office/Business :: Financial :: Accounting" ], "description": "# Capone\n\n_Never let your books land you in the pen._\n\n![Al Capone's Miami Mugshot](Al_Capone_in_Florida.jpg)\n\n`Capone` is a library that provides double-entry bookkeeping (the foundation of\nall modern accounting) for Django with the ability to link each recorded\ntransaction to zero or more other Django models as evidence for that\ntransaction.\n\n## Introduction\n\nIn double-entry bookkeeping (DEB), all recordable events (purchases, sales,\nequipment depreciation, bad debt markdowns, etc.) are tracked as \"ledger\nentries\" or \"transactions\" in \"ledgers\". Each ledger entry is made up of one\nor more \"credit\" and one or more \"debit\" entries. For the sake of this brief\nexample, you can think of credits as increasing the amount of money recorded in\na ledger and a debit decreasing it. With that assumption, the central idea behind\ndouble-entry bookkeeping is that the sum of every ledger entry's debits must\nequal the sum of its credits. `capone` implements a double-entry bookkeeping\nsystem by providing an API for checking that all created entries satisfy this\ncondition or rolling back the transaction if not.\n\nIn addition to this standard bookkeeping functionality, `capone` also allows\nany number of arbitrary objects to be attached, via generic foreign keys, to\na ledger entry as \"evidence\" for that transaction's having happened. For\ninstance, a transaction recording a bank deposit paying for several medical\ntests at a time from an insurance company to your medical testing company could\nbe linked to the original `Order` objects that recorded the test. `capone`\nalso provides an API for the efficient querying of ledger entries by evidence.\n\nFor more information on the concept of double-entry bookkeeping itself, we\nrecommend the Wikipedia article:\nhttps://en.wikipedia.org/wiki/Double-entry_bookkeeping_system.\n\n\n## Local Development\n\n### Setup:\n\nFirst, you must set up your working environment:\n\n make setup\n\nThis will build a local virtualenv and all other requirements for local\ndevelopment.\n\n\n### Running Commands:\n\nThe following commands are available for interacting with the app:\n\nTo start a shell instance so that you can interact with the app via the ORM:\n\n make shell\n\nNote: before any of the following instructions, you may have to run `make\ndevelop` to set up a postgres database for this app.\n\nFirst, activate a virtualenv so that your commands have access to the\nenvironment built by `make setup`:\n\nFrom the repository root, run:\n\n source .venv/bin/activate\n\nThen you should be free to run\n\n ./manage.py makemigrations --settings=capone.tests.settings\n\nor any other `manage.py` command, even those in the Makefile.\n\nTo run individual tests, use the following:\n\n ./manage.py test --settings=capone.tests.settings capone.tests\n\nNotice the `--settings=capone.tests.settings` argument: because this repository\nis a django sub-module, it wouldn't make sense for it to come with its own\ndefault `settings.py` file. Instead, it ships with one used to run its tests.\nTo use `manage.py`, we have to pass an import path to the settings file\nexplicitly.\n\n\n## Models\n\nLet's introduce the models provided by `capone` and how they relate to one\nanother.\n\nNote that all objects in this library have `created_at` and `modified_at`\nfields that are `auto_now_add` and `auto_now`, respectively.\n\n### Accounting Models\n\nThe models in this section are those that correspond most to well known\naccounting concepts, i.e. those involved in keeping accounts using the\nprinciples of double-entry bookkeeping. They model ledgers, journal entries,\ncredits and debits, and any metadata one wishes to store with these objects.\n\n\n#### Ledger\n\nA `Ledger` is the top-most level of organization of information in double-entry\nbookkeeping as well as the `capone` app. Most ledgers have names familiar to\nthose with any knowledge of accounting, such as \"revenue\" or \"accounts\nreceivable\".\n\n`Ledgers` are synonymous with the accounting concept of an \"account\", so you\nmay see references to accounts in this documentation or elsewhere in the\naccounting literature.\n\nAs a data structure, a `Ledger` in this library is little more than a name,\ndescription, and unique number: `LedgerEntries` (see below) point to a `Ledger`\nto represent their being \"in\" a `Ledger`. `Transactions` (see below also) that\nare \"between\" two `Ledgers` have a `LedgerEntry` pointing to one `Ledger` and\nanother `LedgerEntry` pointing to the other `Ledger`.\n\n##### `increased_by_debits`\n\n`Ledger` also has the sometimes confusing field `increased_by_debits`. All\n`Ledgers` are of one of two types: either debits increase the \"value\" of an\naccount or credits do. By convention, asset and expense accounts are of the\nformer type, while liabilities, equity, and revenue are of the latter: in\nshort, an increase to an \"asset\"-type account is a debit, and an increase to\na \"liability\" or \"equity\"-type account is a credit.\n\nHere's a handy mnemonic for the two types of accounts: The accounting equation\nsays (by definition) that:\n\n assets == liabilities + owner equity\n\nThe terms on the right of the equals sign are increased by debits, and terms on\nthe left of the equals sign are decreased by debits. We can therefore use the\naccounting equation to know whether to use debits or credits to model an\nincrease in a ledger.\n\n**So because debits and credits mean different things in different types of\naccounts, we can have a transaction with an \"equal and opposite\" credit and\ndebit pair of the same currency amount, but that still represents a net\nincrease in the value of a company: a debit in Accounts Receivable and a credit\nin Revenue increases both accounts while satisfying the accounting equation.**\n\nCurrently, field `increased_by_debits` is not used by the code in `capone` but\nis provided as a convenience to users who might wish to incorporate this\ninformation into an external report or calculation.\n\n\n#### Transaction\n\nA `Transaction` is a record of a discrete financial action, represented by\na collection of debits and credits whose sums equal one another. Practically\nall models in `capone` link to or through `Transaction`: in a sense you could\nsay it's the main model provided by `capone`. A `Transaction` can sometimes be\nreferred to as a \"journal entry\".\n\nThe `Transaction` model records debits and credits by linking to\n`LedgerEntries`, which include currency amounts of the proper sign, and those\n`LedgerEntries` themselves point to `Ledger`. In other words, `Transaction`\nand `Ledger` are linked in a many-to-many fashion by going through\n`LedgerEntry` as a custom through model. The \"proper sign\" part is taken care\nof by the `credit` and `debit` convenience methods (see examples below).\n\n`Transactions` should never be deleted. Instead, a new `Transaction` with\ndebits and credits swapped should be created using\n`capone.api.actions.void_transaction` to negate the effect of the `Transaction`\nyou'd like to remove. The `voids` field on the new `Transaction` will\nautomatically be filled in with the old `Transaction` you wish to remove. By\nthis method, you'll never have to delete data from your system as a part of\nnormal operation, which mimics one of the many benefits of traditional,\nnon-computerized double-entry bookkeeping.\n\n`Transaction` also has the following fields to provide metadata for each transaction:\n\n- `created_by`: The user who created this `Transaction`.\n- `notes`: A free-form text field for adding to a `Transaction` any\n information not expressed in the numerous metadata fields.\n- `posted_timestamp`: The time a `Transaction` should be considered valid\n from. `capone.api.actions.create_transaction` automatically deals with\n filling in this value with the current time. You can change this value to\n post-date or back-date `Transactions` because `created_at` will always\n represent the true object creation time.\n- `transaction_id`: A Universally Unique Identifier (UUID) for the\n `Transaction`, useful for unambiguously referring to a `Transaction`\n without using primary keys or other database internals.\n- `type`: A user-defined type for the `Transaction` (see the `TransactionType`\n model below).\n\n\n#### TransactionType\n\nA `TransactionType` is a user-defined, human-readable \"type\" for\na `Transaction`, useful for sorting, aggregating, or annotating `Transactions`.\nThe default `TransactionType` is `MANUAL`, which is created automatically by\nthe library, but you can define others, say for bots or certain classes of\nusers.\n\nCurrently, `TransactionType` is not used by the code in `capone` but is\nprovided as a convenience to users who might wish to incorporate this\ninformation into an external report or calculation.\n\n\n#### LedgerEntry\n\n`LedgerEntries` represent single debit or credit entries in a single `Ledger`.\n`LedgerEntries` are grouped together into `Transactions` (see above) with the\nconstraint that the sum of all credit and debit `LedgerEntries` for a given\n`Transaction` must equal zero.\n\n`LedgerEntries` have a field `entry_id`, which is a UUID for unambiguously\nreferring to a single `LedgerEntry`.\n\n\n### Evidence Models\n\nThe models in this section deal with adding evidence to `Transactions` and\nsearching over that evidence.\n\n\n#### TransactionRelatedObject\n\nA `TransactionRelatedObject` (`TRO`) represents the \"evidence\" relationship that\nmakes the `capone` library more useful. A `TRO` links a `Transaction` to an arbitrary\nobject in the larger app that this library is used in using a generic foreign\nkey. One `TRO` links one `Transaction` and one arbitrary object, so we make as\nmany `TROs` as we want pieces of evidence. There are several convenience\nmethods in `capone.api.queries` for efficiently querying over `Transactions`\nbased on evidence and evidence objects based on their `Transactions` (see\nexamples below).\n\n\n#### LedgerBalance\n\nA `LedgerBalance` is similar to a `TRO` in that it allows linking `ledger`\nobjects with objects from the wider app that the library is used in via generic\nforeign keys. The purpose of `LedgerBalance` is to denormalize for more\nefficient querying the current sum of debits and credits for an object in\na specific Ledger. Therefore, there is only one `LedgerBalance` for each\n`(ledger, related_object)` tuple.\n\nYou should never have to manually create or edit a `LedgerBalance`: doing so,\nas well as keeping them up-to-date, is handled by `capone` internals. For the\nsame reasons, deleting them is not necessary or a good idea.\n\nThe purpose of `LedgerBalance` can best be demonstrated by considering the\ndeceptively simple query, \"how many Orders (a non-`capone` model we presumably\ncreated in the app where we include `capone` as a library) have an Accounts\nReceivable balance greater than zero?\" One would have to calculate the ledger\nbalance over literally the product of all ledgers and all non-`capone` objects\nin the database, and then filter them for all those with balances above zero,\nto answer this question, which is obviously too expensive. By keeping track of\nthe per-`Ledger` balance for each object used as evidence in a `Transaction`,\nwe can much more easily make these queries with reasonable overhead.\n\n\n## Usage\n\n### Creating Ledgers\n\nLet's start by creating two common ledger types, \"Accounts Receivable\" and\n\"Revenue\", which usually have transactions between themselves:\n\n```\n>>> from capone.models import Ledger\n>>> ar = Ledger.objects.create(name='Accounts Receivable', number=1, increased_by_debits=True)\n\n>>> revenue = Ledger.objects.create(name='Revenue', number=2, increased_by_debits=True)\n\n```\n\nBoth of these accounts are asset accounts, so they're both increased by debits.\nPlease consult the double-entry bookkeeping Wikipedia article or the\nexplanation for `increased_by_debits` above for a more in-depth explanation of\nthe \"accounting equation\" and whether debits increase or decrease an account.\n\nAlso, note that the default convention in `capone` is to store debits as\npositive numbers and credits as negative numbers. This convention is common\nbut completely arbitrary. If you want to switch the convention around, you can\nset `DEBITS_ARE_NEGATIVE` to `True` in your settings.py file. By default, that\nconstant doesn't need to be defined, and if it remains undefined, `capone` will\ninterpret its value as `False`.\n\n\n### Faking Evidence Models\n\nNow let's create a fake Order, so that we have some evidence for these ledger\nentries, and a fake User, so we'll have someone to blame for these transactions:\n\n```\n>>> from capone.tests.factories import OrderFactory\n>>> order = OrderFactory()\n>>> from capone.tests.factories import UserFactory\n>>> user = UserFactory()\n```\n\n\n### Creating Transactions\n\nWe're now ready to create a simple transaction:\n\n```\n>>> from capone.api.actions import create_transaction\n>>> from capone.api.actions import credit\n>>> from capone.api.actions import debit\n>>> from decimal import Decimal\n>>> from capone.models import LedgerEntry\n>>> txn = create_transaction(user, evidence=[order], ledger_entries=[LedgerEntry(amount=debit(Decimal(100)), ledger=ar), LedgerEntry(amount=credit(Decimal(100)), ledger=revenue)])\n>>> txn.summary()\n{\n u'entries': [\n 'LedgerEntry: $100.0000 in Accounts Receivable',\n 'LedgerEntry: $-100.0000 in Revenue',\n ],\n u'related_objects': [\n 'TransactionRelatedObject: Order(id=1)',\n ]\n}\n```\n\nNote that we use the helper functions `credit` and `debit` with positive\nnumbers to keep the signs consistent in our code. There should be no reason to\nuse negative numbers with `capone`.\n\nNote also that the value for the credit and debit is the same: $100. If we\ntried to create a transaction with mismatching amounts, we would get an error:\n\n```\n>>> create_transaction(user, evidence=[order], ledger_entries=[LedgerEntry(amount=debit(Decimal(100)), ledger=ar), LedgerEntry(amount=credit(Decimal(101)), ledger=revenue)])\n---------------------------------------------------------------------------\nTransactionBalanceException Traceback (most recent call last)\n\n[...]\n\nTransactionBalanceException: Credits do not equal debits. Mis-match of -1.\n```\n\nSo the consistency required of double-entry bookkeeping is automatically kept.\n\nThere are many other options for `create_transaction`: see below or its\ndocstring for details.\n\n\n### Ledger Balances\n\n`capone` keeps track of the balance in each ledger for each evidence object in\na denormalized and efficient way. Let's use this behavior to get the balances\nof our ledgers as well as the balances in each ledger for our `order` object:\n\n\n```\n>>> from capone.api.queries import get_balances_for_object\n\n>>> get_balances_for_object(order)\ndefaultdict( at 0x7fd7ecfa96e0>, {: Decimal('100.0000'), : Decimal('-100.0000')})\n\n>>> ar.get_balance()\nDecimal('100.0000')\n\n>>> revenue.get_balance()\nDecimal('-100.0000')\n```\n\n\n### Voiding Transactions\n\nWe can also void that transaction, which enters a transaction with the same\nevidence but with all values of the opposite sign:\n\n```\n>>> from capone.api.actions import void_transaction\n>>> void = void_transaction(txn, user)\n\n\n>>> void_transaction(txn, user)\n---------------------------------------------------------------------------\nUnvoidableTransactionException Traceback (most recent call last)\n\n[...]\n\nUnvoidableTransactionException: Cannot void the same Transaction #(e0842107-3a5b-4487-9b86-d1a5d7ab77b4) more than once.\n\n>>> void.summary()\n{u'entries': ['LedgerEntry: $-100.0000 in Accounts Receivable',\n 'LedgerEntry: $100.0000 in Revenue'],\n u'related_objects': ['TransactionRelatedObject: Order(id=1)']}\n\n>>> txn.voids\n\n>>> void.voids\n\n```\n\nNote the new balances for evidence objects and `Ledgers`:\n\n```\n>>> get_balances_for_object(order)\ndefaultdict( at 0x7fd7ecfa9758>, {: Decimal('0.0000'), : Decimal('0.0000')})\n\n>>> ar.get_balance()\nDecimal('0.0000')\n\n>>> revenue.get_balance()\nDecimal('0.0000')\n```\n\n\n### Transaction Types\n\nYou can label a `Transaction` using a foreign key to the `TransactionType` to,\nsay, distinguish between manually made `Transactions` and those made by a bot,\nor between `Transactions` that represent two different types of financial\ntransaction, such as \"Reconciliation\" and \"Revenue Recognition\".\n\nBy default, `Transactions` are of a special, auto-generated \"manual\" type:\n\n```\n>>> txn.type\n\n```\n\nbut you can create and assign `TransactionTypes` when creating `Transactions`:\n\n```\n>>> from capone.models import TransactionType\n>>> new_type = TransactionType.objects.create(name='New type')\n>>> txn = create_transaction(user, evidence=[order], ledger_entries=[LedgerEntry(amount=debit(Decimal(100)), ledger=ar), LedgerEntry(amount=credit(Decimal(100)), ledger=revenue)], type=new_type)\n>>> txn.type\n\n```\n\n\n### Querying Transactions\n\n#### Getting Balances\n\n`Transaction` has a `summary` method to summarize the data on the many models\nthat can link to it:\n\n```\n>>> txn.summary()\n{u'entries': ['LedgerEntry: $100.0000 in Accounts Receivable',\n 'LedgerEntry: $-100.0000 in Revenue'],\n u'related_objects': ['TransactionRelatedObject: Order(id=1)']}\n```\n\nTo get the balance for a `Ledger`, use its `get_balance` method:\n\n```\n>>> ar.get_balance()\nDecimal('100.0000')\n```\n\nTo efficiently get the balance of all transactions with a particular object as\nevidence, use `get_balances_for_objects`:\n\n```\n>>> get_balances_for_object(order)\ndefaultdict( at 0x7fd7ecfa9230>, {: Decimal('100.0000'), : Decimal('-100.0000')})\n```\n\n`Transactions` are validated before they are created, but if you need to do\nthis manually for some reason, use the `validate_transaction` function, which\nhas the same prototype as `create_transaction`:\n\n```\n>>> validate_transaction(user, evidence=[order], ledger_entries=[LedgerEntry(amount=debit(Decimal(100)), ledger=ar), LedgerEntry(amount=credit(Decimal(100)), ledger=revenue)], type=new_type)\n>>> validate_transaction(user, evidence=[order], ledger_entries=[LedgerEntry(amount=debit(Decimal(100)), ledger=ar), LedgerEntry(amount=credit(Decimal(101)), ledger=revenue)], type=new_type)\n---------------------------------------------------------------------------\nTransactionBalanceException Traceback (most recent call last)\n in ()\n----> 1 validate_transaction(user, evidence=[order], ledger_entries=[LedgerEntry(amount=debit(Decimal(100)), ledger=ar), LedgerEntry(amount=credit(Decimal(101)), ledger=revenue)], type=new_type)\n\n/home/hunter/capone/capone/api/queries.pyc in validate_transaction(user, evidence, ledger_entries, notes, type, posted_timestamp)\n 67 if total != Decimal(0):\n 68 raise TransactionBalanceException(\n---> 69 \"Credits do not equal debits. Mis-match of %s.\" % total)\n 70\n 71 if not ledger_entries:\n\nTransactionBalanceException: Credits do not equal debits. Mis-match of -1.\n```\n\n### Queries\n\nAlong with the query possibilities from the Django ORM, `capone` provides\n`Transaction.filter_by_related_objects` for finding `Transactions` that are\nrelated to certain models as evidence.\n\n```\n>>> Transaction.objects.count()\n5\n\n>>> Transaction.objects.filter_by_related_objects([order]).count()\n5\n\n>>> order2 = OrderFactory()\n\n>>> create_transaction(user, evidence=[order2], ledger_entries=[LedgerEntry(amount=debit(Decimal(100)), ledger=ar), LedgerEntry(amount=credit(Decimal(100)), ledger=revenue)])\n\n\n>>> Transaction.objects.filter_by_related_objects([order2]).count()\n1\n```\n\n`filter_by_related_objects` is defined on a custom `QuerySet` provided for\n`Transaction`, so calls to it can be chained like ordinary `QuerySet` function\ncalls:\n\n```\n>>> create_transaction(user, evidence=[order2], ledger_entries=[LedgerEntry(amount=debit(Decimal(100)), ledger=ar), LedgerEntry(amount=credit(Decimal(100)), ledger=revenue)])\n\n\n>>> Transaction.objects.filter_by_related_objects([order2]).count()\n2\n\n>>> Transaction.objects.filter_by_related_objects([order2]).filter(transaction_id='92049712-4982-4718-bc71-a405b0d762ac').count()\n1\n```\n\n`filter_by_related_objects` takes an optional `match_type` argument, which is\nof type `MatchType(Enum)` that allows one to filter in different ways, namely\nwhether the matching transactions may have \"any\", \"all\", \"none\", or \"exactly\"\nthe evidence provided, determined by `MatchTypes` `ANY`, `ALL`, `NONE`, and\n`EXACT`, respectively.\n\n\n### Asserting over Transactions\n\nFor writing tests, the method\n`assert_transaction_in_ledgers_for_amounts_with_evidence` is provided for\nconvenience. As its name implies, it allows asserting the existence of exactly\none `Transaction` with the ledger amounts, evidence, and other fields on Ledger\nprovided to the method.\n\n```\n>>> create_transaction(user, evidence=[order], ledger_entries=[LedgerEntry(amount=debit(Decimal(100)), ledger=ar), LedgerEntry(amount=credit(Decimal(100)), ledger=revenue)])\n\n>>> with assert_raises(Transaction.DoesNotExist):\n... assert_transaction_in_ledgers_for_amounts_with_evidence(ledger_amount_pairs=[(revenue.name, credit(Decimal(100))), (ar.name, debit(Decimal(100)))], evidence=[])\n...\n>>> assert_transaction_in_ledgers_for_amounts_with_evidence(ledger_amount_pairs=[(revenue.name, credit(Decimal(100))), (ar.name, debit(Decimal(100)))], evidence=[order])\n>>> with assert_raises(Transaction.DoesNotExist):\n... assert_transaction_in_ledgers_for_amounts_with_evidence(ledger_amount_pairs=[(revenue.name, credit(Decimal(100))), (ar.name, debit(Decimal(100)))], evidence=[order])\n...\nTraceback (most recent call last):\n File \"\", line 2, in \n File \"/usr/lib/python2.7/unittest/case.py\", line 116, in __exit__\n \"{0} not raised\".format(exc_name))\n AssertionError: DoesNotExist not raised\n```\n\nYou can see\n`capone.tests.test_assert_transaction_in_ledgers_for_amounts_with_evidence` for\nmore examples!\n\n\n## Image Credits\n\nImage courtesy [Officer](https://commons.wikimedia.org/wiki/User:Officer) on [Wikipedia](https://commons.wikimedia.org/wiki/File:Al_Capone_in_Florida.jpg).\nThis work was created by a government unit (including state, county, and municipal government agencies) of the U.S. state of Florida. It is a public record that was not created by an agency which state law has allowed to claim copyright and is therefore in the public domain in the United States.\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/counsyl/capone", "keywords": "", "license": "Copyright Counsyl, Inc.", "maintainer": "", "maintainer_email": "", "name": "capone", "package_url": "https://pypi.org/project/capone/", "platform": "", "project_url": "https://pypi.org/project/capone/", "project_urls": { "Homepage": "https://github.com/counsyl/capone" }, "release_url": "https://pypi.org/project/capone/1.0.7/", "requires_dist": null, "requires_python": "", "summary": "Django app representing a double-entry accounting ledger.", "version": "1.0.7" }, "last_serial": 3697740, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "298b2206c490b51c5f31c7e05af4f7aa", "sha256": "5994017ed015b4067ab08619b6b53dede1f61d7935554a6f81a5678cd31e0ef6" }, "downloads": -1, "filename": "capone-1.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "298b2206c490b51c5f31c7e05af4f7aa", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 41573, "upload_time": "2017-08-17T20:49:46", "url": "https://files.pythonhosted.org/packages/7a/2b/febaf72f96e446ca4c376ef584a45b3edbb4dd703f49a7989d77311779a8/capone-1.0.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "07a4e6e50bc4bb43fd3451c4095723b9", "sha256": "fbfb068ea3510682ef26eb4fedbbfe2783367a910b3ca7719986713d2fdbca30" }, "downloads": -1, "filename": "capone-1.0.0.tar.gz", "has_sig": false, "md5_digest": "07a4e6e50bc4bb43fd3451c4095723b9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 107461, "upload_time": "2017-08-17T20:49:48", "url": "https://files.pythonhosted.org/packages/1a/f5/52172ba0cee432faf82668a1e06b337ddfd3d29156fbe46bf19984f6c3c9/capone-1.0.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "63aca0e322c9a7fc53d98323ae354afb", "sha256": "ff863cc7a21dcc9b42be41ca7c041b375ba709e8f6b38f5e635e71c8ab6e73e8" }, "downloads": -1, "filename": "capone-1.0.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "63aca0e322c9a7fc53d98323ae354afb", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 41625, "upload_time": "2017-08-18T17:24:11", "url": "https://files.pythonhosted.org/packages/be/4a/d06fa4e14663430c352806a65aa3255085ebc965cf17092688797f23521d/capone-1.0.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5f9da1e93bd314e111eaa1886fd2f774", "sha256": "88a76ec46c4213ceeaa23a339be5fa1e3db201c6acd0e8c2dbd88a17f0035fb5" }, "downloads": -1, "filename": "capone-1.0.1.tar.gz", "has_sig": false, "md5_digest": "5f9da1e93bd314e111eaa1886fd2f774", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 107535, "upload_time": "2017-08-18T17:24:13", "url": "https://files.pythonhosted.org/packages/92/76/c9082f28ca0180bb70e2a2fbf436e0d476baaa0d8205353169cd56b40f56/capone-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "baaf35969f98cc81be5df688be0ae8c1", "sha256": "622f213560e963042143063d6b85d3a5393aec97942fe3ff213145575ee98f7b" }, "downloads": -1, "filename": "capone-1.0.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "baaf35969f98cc81be5df688be0ae8c1", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 41630, "upload_time": "2017-10-28T00:02:31", "url": "https://files.pythonhosted.org/packages/95/8b/d19125986980d5e96dfcb99668d8ba7b471b115922035d9a1cad90473aed/capone-1.0.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8009816100abb5a4b500772d2423a7e2", "sha256": "7e5ae7d1d9b44623b103c65ee60856d8ff76d33ac2f67a6d5c5e1ac9e7ad79ee" }, "downloads": -1, "filename": "capone-1.0.2.tar.gz", "has_sig": false, "md5_digest": "8009816100abb5a4b500772d2423a7e2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 107533, "upload_time": "2017-10-28T00:02:33", "url": "https://files.pythonhosted.org/packages/15/18/d08cd5a659ebc374a1d711cea37472ca3137e0a182293754e3ce93cf2cd8/capone-1.0.2.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "8ace8a567d354fce80e1e57c3c89cf7e", "sha256": "9eb308ff18508bab6291e4fc1ea15e7f62d7b1ba866fc0f3e4c38b39d673e1d1" }, "downloads": -1, "filename": "capone-1.0.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "8ace8a567d354fce80e1e57c3c89cf7e", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 41630, "upload_time": "2017-10-28T20:30:28", "url": "https://files.pythonhosted.org/packages/d5/7a/b2f20f0226afe053068a40045be5bb0b6bc91835deb745dec57167854171/capone-1.0.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "98d7014300fe2262d43d7f25058da479", "sha256": "af99f569833f90da2dbe67529a3c341d2c5c4ba1b604f81ce34d39fa10c7c4be" }, "downloads": -1, "filename": "capone-1.0.3.tar.gz", "has_sig": false, "md5_digest": "98d7014300fe2262d43d7f25058da479", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 107541, "upload_time": "2017-10-28T20:30:30", "url": "https://files.pythonhosted.org/packages/13/99/ff528827bf86e2e535d71c1e13e8db62c0ceee2897faa0f6d067e1e76172/capone-1.0.3.tar.gz" } ], "1.0.4": [ { "comment_text": "", "digests": { "md5": "9a50394a1a4eb308761e1d45b758785e", "sha256": "01e30613f3caa6e8a8247ab39d264b61965f94abc0184c963b7feadcd8f950fa" }, "downloads": -1, "filename": "capone-1.0.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "9a50394a1a4eb308761e1d45b758785e", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 41627, "upload_time": "2017-11-11T18:12:45", "url": "https://files.pythonhosted.org/packages/ca/5c/c3992df75ff3109cdf4a01a718133b27348bd4fba2d073532d4805183f21/capone-1.0.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b38f9cc0e290caeb1ac41fdf64ad5772", "sha256": "87602d6b40cada67c692e6cf51bbce2776086d6241da4a14c958db420202e430" }, "downloads": -1, "filename": "capone-1.0.4.tar.gz", "has_sig": false, "md5_digest": "b38f9cc0e290caeb1ac41fdf64ad5772", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 107539, "upload_time": "2017-11-11T18:12:47", "url": "https://files.pythonhosted.org/packages/13/ae/46e48c7e00283360b7e96dab5fc3149b87addd8cda824ac3218c256faffd/capone-1.0.4.tar.gz" } ], "1.0.5": [ { "comment_text": "", "digests": { "md5": "9e8183e64c98ffaab6b31c2898f9eeab", "sha256": "b9862f067c5743a5594225e440ef41da2fcd64ead3bed1f35d3700c8abed4592" }, "downloads": -1, "filename": "capone-1.0.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "9e8183e64c98ffaab6b31c2898f9eeab", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 41667, "upload_time": "2018-01-08T20:38:59", "url": "https://files.pythonhosted.org/packages/c5/30/ab010a0b1fdfe2317eac689fedbab8b438dbea29e657c033aca3fb6680c5/capone-1.0.5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "018c49474544c45ad3d8fc691e9fea8e", "sha256": "101583019cf50c50dba17358f1b89a79107d025a85ae917d7abf92fc3f717bce" }, "downloads": -1, "filename": "capone-1.0.5.tar.gz", "has_sig": false, "md5_digest": "018c49474544c45ad3d8fc691e9fea8e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 107171, "upload_time": "2018-01-08T20:39:02", "url": "https://files.pythonhosted.org/packages/f4/c6/635b9bc0bf1298c152e98a82e9af5e542f3374179111b59ae9dc26094524/capone-1.0.5.tar.gz" } ], "1.0.6": [ { "comment_text": "", "digests": { "md5": "a1df9d48ac3783ff146427b5935002be", "sha256": "c731978030ee3fd7b299ec4b2e9bd801c3989ba05f77735a8dec4f82a40d4aa7" }, "downloads": -1, "filename": "capone-1.0.6-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a1df9d48ac3783ff146427b5935002be", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 41676, "upload_time": "2018-03-18T00:27:22", "url": "https://files.pythonhosted.org/packages/b6/eb/9e336b2694a16c1d43166ec3b90f415a7d62ed9a076b9f4491d92ecbeb3c/capone-1.0.6-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "150cfd5b40012a047467ee223d804520", "sha256": "bfe10bbcc3a48045b004a998897dcdf29d3df8a456c1b93ef568b3b2b6f085be" }, "downloads": -1, "filename": "capone-1.0.6.tar.gz", "has_sig": false, "md5_digest": "150cfd5b40012a047467ee223d804520", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 107183, "upload_time": "2018-03-18T00:27:25", "url": "https://files.pythonhosted.org/packages/b8/27/93a9afabe89a34ad71c2707fdc546ba2bbe99365727370d98047398bcce6/capone-1.0.6.tar.gz" } ], "1.0.7": [ { "comment_text": "", "digests": { "md5": "458aac6dad81cfdcc1c246810d55304a", "sha256": "b6d93afc4c20d2bc0f857252afc5c3a2b7f365dac3f99eaa1ba50e32c03a363f" }, "downloads": -1, "filename": "capone-1.0.7-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "458aac6dad81cfdcc1c246810d55304a", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 41626, "upload_time": "2018-03-23T06:34:06", "url": "https://files.pythonhosted.org/packages/7e/1b/53d780d13793880bc87dcd0a6eb69023f85539d6c8fb1ffae5a24f5696da/capone-1.0.7-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "896bc39eef0456ff120fffb51099d967", "sha256": "4cbb16fd0bc34c2db85a112b8171bdc215e69fc5b5232be163f17e394d4e7986" }, "downloads": -1, "filename": "capone-1.0.7.tar.gz", "has_sig": false, "md5_digest": "896bc39eef0456ff120fffb51099d967", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 107154, "upload_time": "2018-03-23T06:34:08", "url": "https://files.pythonhosted.org/packages/69/76/074a8ce3ed3c035e00997af47a56959f1854087fbb5d529c432336b28214/capone-1.0.7.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "458aac6dad81cfdcc1c246810d55304a", "sha256": "b6d93afc4c20d2bc0f857252afc5c3a2b7f365dac3f99eaa1ba50e32c03a363f" }, "downloads": -1, "filename": "capone-1.0.7-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "458aac6dad81cfdcc1c246810d55304a", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 41626, "upload_time": "2018-03-23T06:34:06", "url": "https://files.pythonhosted.org/packages/7e/1b/53d780d13793880bc87dcd0a6eb69023f85539d6c8fb1ffae5a24f5696da/capone-1.0.7-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "896bc39eef0456ff120fffb51099d967", "sha256": "4cbb16fd0bc34c2db85a112b8171bdc215e69fc5b5232be163f17e394d4e7986" }, "downloads": -1, "filename": "capone-1.0.7.tar.gz", "has_sig": false, "md5_digest": "896bc39eef0456ff120fffb51099d967", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 107154, "upload_time": "2018-03-23T06:34:08", "url": "https://files.pythonhosted.org/packages/69/76/074a8ce3ed3c035e00997af47a56959f1854087fbb5d529c432336b28214/capone-1.0.7.tar.gz" } ] }