diff --git a/.gitignore b/.gitignore
index ad82db58..1a22ad18 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,3 +77,7 @@ benchmarking-tests/ssh_key.py
# Ansible-specific files
ntools/one-m/ansible/hosts
ntools/one-m/ansible/ansible.cfg
+
+# Just in time documentation
+docs/server/source/schema
+docs/server/source/drivers-clients/samples
diff --git a/docs/generate/__init__.py b/docs/generate/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/docs/server/generate_http_server_api_documentation.py b/docs/server/generate_http_server_api_documentation.py
new file mode 100644
index 00000000..d9d86647
--- /dev/null
+++ b/docs/server/generate_http_server_api_documentation.py
@@ -0,0 +1,87 @@
+""" Script to build http examples for http server api docs """
+
+import json
+import os
+import os.path
+
+from bigchaindb.common.transaction import Asset, Transaction
+
+
+TPLS = {}
+
+TPLS['post-tx-request'] = """\
+POST /transactions/ HTTP/1.1
+Host: example.com
+Content-Type: application/json
+
+%(tx)s
+"""
+
+
+TPLS['post-tx-response'] = """\
+HTTP/1.1 201 Created
+Content-Type: application/json
+
+%(tx)s
+"""
+
+
+TPLS['get-tx-status-request'] = """\
+GET /transactions/%(txid)s/status HTTP/1.1
+Host: example.com
+
+"""
+
+
+TPLS['get-tx-status-response'] = """\
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+ "status": "valid"
+}
+"""
+
+
+TPLS['get-tx-request'] = """\
+GET /transactions/%(txid)s HTTP/1.1
+Host: example.com
+
+"""
+
+
+TPLS['get-tx-response'] = """\
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+%(tx)s
+"""
+
+
+def main():
+ """ Main function """
+ pubkey = '9RaWxppkP9UyYWA7NJb5FcgkzfJNPfvPX3FCNw2T5Pwb'
+ asset = Asset(None, 'e6969f87-4fc9-4467-b62a-f0dfa1c85002')
+ tx = Transaction.create([pubkey], [([pubkey], 1)], asset=asset)
+ tx_json = json.dumps(tx.to_dict(), indent=2, sort_keys=True)
+
+ base_path = os.path.join(os.path.dirname(__file__),
+ 'source/drivers-clients/samples')
+
+ if not os.path.exists(base_path):
+ os.makedirs(base_path)
+
+ for name, tpl in TPLS.items():
+ path = os.path.join(base_path, name + '.http')
+ code = tpl % {'tx': tx_json, 'txid': tx.id}
+ with open(path, 'w') as handle:
+ handle.write(code)
+
+
+def setup(*_):
+ """ Fool sphinx into think it's an extension muahaha """
+ main()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/docs/server/generate_schema_documentation.py b/docs/server/generate_schema_documentation.py
index 0e1a626a..8767cabf 100644
--- a/docs/server/generate_schema_documentation.py
+++ b/docs/server/generate_schema_documentation.py
@@ -168,12 +168,20 @@ def main():
'file': os.path.basename(__file__),
}
- path = os.path.join(os.path.dirname(__file__),
- 'source/schema/transaction.rst')
+ base_path = os.path.join(os.path.dirname(__file__), 'source/schema')
+ path = os.path.join(base_path, 'transaction.rst')
+
+ if not os.path.exists(base_path):
+ os.makedirs(base_path)
with open(path, 'w') as handle:
handle.write(doc)
+def setup(*_):
+ """ Fool sphinx into think it's an extension muahaha """
+ main()
+
+
if __name__ == '__main__':
main()
diff --git a/docs/server/source/conf.py b/docs/server/source/conf.py
index c0de76d7..93402f75 100644
--- a/docs/server/source/conf.py
+++ b/docs/server/source/conf.py
@@ -35,6 +35,10 @@ _version = {}
with open('../../../bigchaindb/version.py') as fp:
exec(fp.read(), _version)
+import os.path
+import sys
+
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/..'))
extensions = [
'sphinx.ext.autodoc',
@@ -44,6 +48,10 @@ extensions = [
'sphinx.ext.napoleon',
'sphinxcontrib.httpdomain',
'sphinx.ext.autosectionlabel',
+ # Below are actually build steps made to look like sphinx extensions.
+ # It was the easiest way to get it running with ReadTheDocs.
+ 'generate_schema_documentation',
+ 'generate_http_server_api_documentation',
]
# autodoc settings
diff --git a/docs/server/source/drivers-clients/http-client-server-api.rst b/docs/server/source/drivers-clients/http-client-server-api.rst
index 12f30a79..bb037d15 100644
--- a/docs/server/source/drivers-clients/http-client-server-api.rst
+++ b/docs/server/source/drivers-clients/http-client-server-api.rst
@@ -64,108 +64,13 @@ POST /transactions/
**Example request**:
- .. sourcecode:: http
-
- POST /transactions/ HTTP/1.1
- Host: example.com
- Content-Type: application/json
-
- {
- "transaction": {
- "conditions": [
- {
- "cid": 0,
- "condition": {
- "uri": "cc:4:20:fSlVCKNSzSl0meiwwuUk5JpJ0KLlECTqbd25KyQefFY:96",
- "details": {
- "signature": null,
- "type": "fulfillment",
- "type_id": 4,
- "bitmask": 32,
- "public_key": "9RaWxppkP9UyYWA7NJb5FcgkzfJNPfvPX3FCNw2T5Pwb"
- }
- },
- "amount": 1,
- "owners_after": [
- "9RaWxppkP9UyYWA7NJb5FcgkzfJNPfvPX3FCNw2T5Pwb"
- ]
- }
- ],
- "operation": "CREATE",
- "asset": {
- "divisible": false,
- "updatable": false,
- "data": null,
- "id": "b57801f8-b865-4360-9d1a-3e3009f5ce01",
- "refillable": false
- },
- "metadata": null,
- "fulfillments": [
- {
- "fid": 0,
- "input": null,
- "fulfillment": "cf:4:fSlVCKNSzSl0meiwwuUk5JpJ0KLlECTqbd25KyQefFaf8bQVH1gesZGEGZepCE8_kgo-UfBrCHPlvBsnAsfq56GWjrLTyZ9NXISwcyJ3zmygnVhCMG8xzE6c9fj1-6wK",
- "owners_before": [
- "9RaWxppkP9UyYWA7NJb5FcgkzfJNPfvPX3FCNw2T5Pwb"
- ]
- }
- ]
- },
- "id": "65f1f69b6ebf995a7b2c5ae8a6fb480ce20f0e8f1eb1d77d75f37ab00ccdeec3",
- "version": 1
- }
+ .. literalinclude:: samples/post-tx-request.http
+ :language: http
**Example response**:
- .. sourcecode:: http
-
- HTTP/1.1 201 Created
- Content-Type: application/json
-
- {
- "id": "65f1f69b6ebf995a7b2c5ae8a6fb480ce20f0e8f1eb1d77d75f37ab00ccdeec3",
- "version": 1,
- "transaction": {
- "conditions": [
- {
- "amount": 1,
- "condition": {
- "uri": "cc:4:20:fSlVCKNSzSl0meiwwuUk5JpJ0KLlECTqbd25KyQefFY:96",
- "details": {
- "signature": null,
- "type_id": 4,
- "type": "fulfillment",
- "bitmask": 32,
- "public_key": "9RaWxppkP9UyYWA7NJb5FcgkzfJNPfvPX3FCNw2T5Pwb"
- }
- },
- "owners_after": [
- "9RaWxppkP9UyYWA7NJb5FcgkzfJNPfvPX3FCNw2T5Pwb"
- ],
- "cid": 0
- }
- ],
- "fulfillments": [
- {
- "input": null,
- "fulfillment": "cf:4:fSlVCKNSzSl0meiwwuUk5JpJ0KLlECTqbd25KyQefFaf8bQVH1gesZGEGZepCE8_kgo-UfBrCHPlvBsnAsfq56GWjrLTyZ9NXISwcyJ3zmygnVhCMG8xzE6c9fj1-6wK",
- "fid": 0,
- "owners_before": [
- "9RaWxppkP9UyYWA7NJb5FcgkzfJNPfvPX3FCNw2T5Pwb"
- ]
- }
- ],
- "operation": "CREATE",
- "asset": {
- "updatable": false,
- "refillable": false,
- "divisible": false,
- "data": null,
- "id": "b57801f8-b865-4360-9d1a-3e3009f5ce01"
- },
- "metadata": null
- }
- }
+ .. literalinclude:: samples/post-tx-response.http
+ :language: http
:statuscode 201: A new transaction was created.
:statuscode 400: The transaction was invalid and not created.
@@ -187,21 +92,13 @@ GET /transactions/{tx_id}/status
**Example request**:
- .. sourcecode:: http
-
- GET /transactions/65f1f69b6ebf995a7b2c5ae8a6fb480ce20f0e8f1eb1d77d75f37ab00ccdeec3/status HTTP/1.1
- Host: example.com
+ .. literalinclude:: samples/get-tx-status-request.http
+ :language: http
**Example response**:
- .. sourcecode:: http
-
- HTTP/1.1 200 OK
- Content-Type: application/json
-
- {
- "status": "valid"
- }
+ .. literalinclude:: samples/get-tx-status-response.http
+ :language: http
:statuscode 200: A transaction with that ID was found and the status is returned.
:statuscode 404: A transaction with that ID was not found.
@@ -222,62 +119,13 @@ GET /transactions/{tx_id}
**Example request**:
- .. sourcecode:: http
-
- GET /transactions/65f1f69b6ebf995a7b2c5ae8a6fb480ce20f0e8f1eb1d77d75f37ab00ccdeec3 HTTP/1.1
- Host: example.com
+ .. literalinclude:: samples/get-tx-request.http
+ :language: http
**Example response**:
- .. sourcecode:: http
-
- HTTP/1.1 200 OK
- Content-Type: application/json
-
- {
- "transaction": {
- "conditions": [
- {
- "cid": 0,
- "condition": {
- "uri": "cc:4:20:fSlVCKNSzSl0meiwwuUk5JpJ0KLlECTqbd25KyQefFY:96",
- "details": {
- "signature": null,
- "type": "fulfillment",
- "type_id": 4,
- "bitmask": 32,
- "public_key": "9RaWxppkP9UyYWA7NJb5FcgkzfJNPfvPX3FCNw2T5Pwb"
- }
- },
- "amount": 1,
- "owners_after": [
- "9RaWxppkP9UyYWA7NJb5FcgkzfJNPfvPX3FCNw2T5Pwb"
- ]
- }
- ],
- "operation": "CREATE",
- "asset": {
- "divisible": false,
- "updatable": false,
- "data": null,
- "id": "b57801f8-b865-4360-9d1a-3e3009f5ce01",
- "refillable": false
- },
- "metadata": null,
- "fulfillments": [
- {
- "fid": 0,
- "input": null,
- "fulfillment": "cf:4:fSlVCKNSzSl0meiwwuUk5JpJ0KLlECTqbd25KyQefFaf8bQVH1gesZGEGZepCE8_kgo-UfBrCHPlvBsnAsfq56GWjrLTyZ9NXISwcyJ3zmygnVhCMG8xzE6c9fj1-6wK",
- "owners_before": [
- "9RaWxppkP9UyYWA7NJb5FcgkzfJNPfvPX3FCNw2T5Pwb"
- ]
- }
- ]
- },
- "id": "65f1f69b6ebf995a7b2c5ae8a6fb480ce20f0e8f1eb1d77d75f37ab00ccdeec3",
- "version": 1
- }
+ .. literalinclude:: samples/get-tx-response.http
+ :language: http
:statuscode 200: A transaction with that ID was found.
:statuscode 404: A transaction with that ID was not found.
diff --git a/docs/server/source/schema/transaction.rst b/docs/server/source/schema/transaction.rst
deleted file mode 100644
index 1d2b8f7d..00000000
--- a/docs/server/source/schema/transaction.rst
+++ /dev/null
@@ -1,307 +0,0 @@
-.. This file was auto generated by generate_schema_documentation.py
-
-==================
-Transaction Schema
-==================
-
-* `Transaction`_
-
-* `Transaction Body`_
-
-* Condition_
-
-* Fulfillment_
-
-* Asset_
-
-* Metadata_
-
-.. raw:: html
-
-
-
-Transaction
------------
-
-This is the outer transaction wrapper. It contains the ID, version and the body of the transaction, which is also called ``transaction``.
-
-
-Transaction.id
-^^^^^^^^^^^^^^
-
-**type:** string
-
-A sha3 digest of the transaction. The ID is calculated by removing all
-derived hashes and signatures from the transaction, serializing it to
-JSON with keys in sorted order and then hashing the resulting string
-with sha3.
-
-
-
-Transaction.transaction
-^^^^^^^^^^^^^^^^^^^^^^^
-
-**type:** object
-
-See: `Transaction Body`_.
-
-
-
-Transaction.version
-^^^^^^^^^^^^^^^^^^^
-
-**type:** integer
-
-BigchainDB transaction schema version.
-
-
-
-
-
-Transaction Body
-----------------
-
-See: `Transaction Body`_.
-
-
-Transaction.operation
-^^^^^^^^^^^^^^^^^^^^^
-
-**type:** string
-
-Type of the transaction:
-
-A ``CREATE`` transaction creates an asset in BigchainDB. This
-transaction has outputs (conditions) but no inputs (fulfillments),
-so a dummy fulfillment is used.
-
-A ``TRANSFER`` transaction transfers ownership of an asset, by providing
-fulfillments to conditions of earlier transactions.
-
-A ``GENESIS`` transaction is a special case transaction used as the
-sole member of the first block in a BigchainDB ledger.
-
-
-
-Transaction.asset
-^^^^^^^^^^^^^^^^^
-
-**type:** object
-
-Description of the asset being transacted.
-
-See: `Asset`_.
-
-
-
-Transaction.fulfillments
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-**type:** array (object)
-
-Array of the fulfillments (inputs) of a transaction.
-
-See: Fulfillment_.
-
-
-
-Transaction.conditions
-^^^^^^^^^^^^^^^^^^^^^^
-
-**type:** array (object)
-
-Array of conditions (outputs) provided by this transaction.
-
-See: Condition_.
-
-
-
-Transaction.metadata
-^^^^^^^^^^^^^^^^^^^^
-
-**type:** object or null
-
-User provided transaction metadata. This field may be ``null`` or may
-contain an object with freeform metadata.
-
-See: `Metadata`_.
-
-
-
-
-
-Condition
-----------
-
-An output of a transaction. A condition describes a quantity of an asset
-and what conditions must be met in order for it to be fulfilled. See also:
-fulfillment_.
-
-
-Condition.cid
-^^^^^^^^^^^^^
-
-**type:** integer
-
-Index of this condition's appearance in the `Transaction.conditions`_
-array. In a transaction with 2 conditions, the ``cid``s will be 0 and 1.
-
-
-
-Condition.condition
-^^^^^^^^^^^^^^^^^^^
-
-**type:** object
-
-Body of the condition. Has the properties:
-
-- **details**: Details of the condition.
-- **uri**: Condition encoded as an ASCII string.
-
-
-
-Condition.owners_after
-^^^^^^^^^^^^^^^^^^^^^^
-
-**type:** array (string) or null
-
-List of public keys associated with asset ownership at the time
-of the transaction.
-
-
-
-Condition.amount
-^^^^^^^^^^^^^^^^
-
-**type:** integer
-
-Integral amount of the asset represented by this condition.
-In the case of a non divisible asset, this will always be 1.
-
-
-
-
-
-Fulfillment
------------
-
-A fulfillment is an input to a transaction, named as such because it fulfills a condition of a previous transaction. In the case of a ``CREATE`` transaction, a fulfillment may provide no ``input``.
-
-Fulfillment.fid
-^^^^^^^^^^^^^^^
-
-**type:** integer
-
-The offset of the fulfillment within the fulfillents array.
-
-
-
-Fulfillment.owners_before
-^^^^^^^^^^^^^^^^^^^^^^^^^
-
-**type:** array (string) or null
-
-List of public keys of the previous owners of the asset.
-
-
-
-Fulfillment.fulfillment
-^^^^^^^^^^^^^^^^^^^^^^^
-
-**type:** object or string
-
-Fulfillment of a condition_, or put a different way, this is a
-payload that satisfies a condition in order to spend the associated
-asset.
-
-
-
-Fulfillment.input
-^^^^^^^^^^^^^^^^^
-
-**type:** object or null
-
-Reference to a condition of a previous transaction
-
-
-
-
-
-Asset
------
-
-Description of the asset being transacted. In the case of a ``TRANSFER``
-transaction, this field contains only the ID of asset. In the case
-of a ``CREATE`` transaction, this field may contain properties:
-
-
-Asset.id
-^^^^^^^^
-
-**type:** string
-
-A `UUID `_
-of type 4 (random).
-
-
-
-Asset.divisible
-^^^^^^^^^^^^^^^
-
-**type:** boolean
-
-Whether or not the asset has a quantity that may be partially spent.
-
-
-
-Asset.updatable
-^^^^^^^^^^^^^^^
-
-**type:** boolean
-
-Whether or not the description of the asset may be updated. Defaults to false.
-
-
-
-Asset.refillable
-^^^^^^^^^^^^^^^^
-
-**type:** boolean
-
-Whether the amount of the asset can change after its creation. Defaults to false.
-
-
-
-Asset.data
-^^^^^^^^^^
-
-**type:** object or null
-
-User provided metadata associated with the asset. May also be ``null``.
-
-
-
-
-
-Metadata
---------
-
-User provided transaction metadata. This field may be ``null`` or may
-contain an non empty object with freeform metadata.
-
-
-
diff --git a/setup.py b/setup.py
index 4043c0be..ecb801a3 100644
--- a/setup.py
+++ b/setup.py
@@ -27,18 +27,6 @@ def check_setuptools_features():
check_setuptools_features()
-
-tests_require = [
- 'coverage',
- 'pep8',
- 'flake8',
- 'pylint',
- 'pytest',
- 'pytest-cov>=2.2.1',
- 'pytest-xdist',
- 'pytest-flask',
-]
-
dev_require = [
'ipdb',
'ipython',
@@ -52,6 +40,17 @@ docs_require = [
'sphinxcontrib-napoleon>=0.4.4',
]
+tests_require = [
+ 'coverage',
+ 'pep8',
+ 'flake8',
+ 'pylint',
+ 'pytest',
+ 'pytest-cov>=2.2.1',
+ 'pytest-xdist',
+ 'pytest-flask',
+] + docs_require
+
benchmarks_require = [
'line-profiler==1.0',
]
diff --git a/tests/test_docs.py b/tests/test_docs.py
new file mode 100644
index 00000000..037bf87c
--- /dev/null
+++ b/tests/test_docs.py
@@ -0,0 +1,16 @@
+
+import subprocess
+
+
+def test_build_server_docs():
+ proc = subprocess.Popen(['bash'], stdin=subprocess.PIPE)
+ proc.stdin.write('cd docs/server; make html'.encode())
+ proc.stdin.close()
+ assert proc.wait() == 0
+
+
+def test_build_root_docs():
+ proc = subprocess.Popen(['bash'], stdin=subprocess.PIPE)
+ proc.stdin.write('cd docs/root; make html'.encode())
+ proc.stdin.close()
+ assert proc.wait() == 0