ConseilPy
Python toolkit for Conseil blockchain indexer
Installation
Python 3.6+ required
$ pip install conseil
Usage
ConseilPy is a lot like Sqlalchemy, so if you're familiar with it, you can easily cook queries.
Quickstart
Get top 5 delegators by balance
from conseil import conseil
Account = conseil.tezos.alphanet.accounts
Account.query(Account.acccount_id, Account.balance) \
.filter(Account.script.is_(None),
Account.account_id.startswith('KT1')) \
.order_by(Account.balance.desc()) \
.limit(5) \
.all()
See more examples
Client initialization
If using a default conseil client is not an option you can instantiate it yourself:
from conseil.api import ConseilApi
from conseil.core import Client
conseil = Client(ConseilApi(
api_key='<API_KEY>',
api_host='<API_HOST>',
api_version=2
))
Exploring database schema
Conseil metadata has the following tree structure:
platform / network / entity / attribute / value
So you can simply access any node by name:
>>> from conseil import conseil
>>> print(conseil.tezos.alphanet.operations.kind.transaction)
transaction
Autocompletion Shift + Tab and docstrings are available in Jupyter:
>>> conseil
Path
metadata/platforms
Platforms
.tezos
>>> conseil.tezos.alphanet
Path
metadata/tezos/alphanet/entities
Entities
.accounts
.balance_updates
.ballots
.blocks
.delegates
.fees
.operation_groups
.operations
.proposals
.rolls
Alternatively you can check full SQL schema
Selecting fields
Conseil doesn't support joins at the moment so you can request attributes for a single entity only.
from conseil import conseil
c = conseil.tezos.alphanet
# select all fields
c.query(c.accounts)
c.accounts.query()
# select specific fields
c.query(c.accounts.balance, c.accounts.account_id)
c.accounts.query(c.accounts.balance, c.accounts.account_id)
# select single field
c.accounts.balance.query()
Filtering results
Conseil receives a conjunction of predicates, which can be inverted by one, but not together. Predicate syntax is similar to Sqlalchemy, but has less operations.
from conseil import conseil
from conseil.core import not_
Account = conseil.tezos.alphanet.accounts
Account.query() \
.filter(not_(Account.account_id.startswith('tz')),
Account.script.is_(None),
Account.balance > 0)
Here is a full list of supported operations:
| Conseil operation | Filter | Inversed |
|---|---|---|
| in | x.in_(a, b, ...) |
x.notin_(a, b, ...) |
| between | x.between(a, b) |
not_(x.between(a, b)) |
| like | x.like(a) |
x.notlike(a) |
| lt | x < a |
x >= a |
| gt | x > a |
x <= a |
| eq | x == a |
x != a |
| startsWith | x.startswith(a) |
not_(x.startsWith(a)) |
| endsWith | x.endswith(a) |
not_(x.endswith(a)) |
| isnull | x.is_(None) |
x.isnot(None) |
You can also use filter_by for simple queries:
from conseil import conseil
conseil.tezos.alphanet.accounts.query() \
.filter_by(account_id='tzkt')
Data aggregation
This is an important concept to understand. In Conseil you specify which columns will be aggregated and the rest of them are used in GROUP BY clause. Here is an example:
from conseil import conseil
Block = conseil.tezos.alphanet.blocks
Block.query(Block.baker, Block.level.count(), Block.timestamp.max())
# will be compiled to SELECT baker, COUNT(level), MAX(timestamp) FROM blocks GROUP BY baker
Additionally, you can specify HAVING predicates if you want to filter results by aggregated column:
from conseil import conseil
Block = conseil.tezos.alphanet.blocks
Block.query(Block.baker, Block.level.count()) \
.having(Block.level.count() > 1) # you have to specify aggregation function here as well
Here is the list of supported aggregation functions:
countsumavgminmax
If you want to group by some fields but not include them in the result use group_by method:
from conseil import conseil
Block = conseil.tezos.alphanet.blocks
Block.query(Block.level.count()) \
.group_by(Block.baker)
Sorting and limiting results
This is similar to Sqlalchemy as well, you can specify one or multiple sort columns with optional descending modifier.
from conseil import conseil
Account = conseil.tezos.alphanet.accounts
Account.query() \
.order_by(Account.balance.desc(), Account.account_id) \
.limit(20)
You can sort by aggregated column too:
from conseil import conseil
Operation = conseil.tezos.alphanet.operations
Operation.query(Operation.source, Operation.amount.avg()) \
.order_by(Operation.amount.avg().desc()) \
.limit(50)
Query preview
So you have cooked a simple query and want to see the resulting Conseil request body.
from conseil import conseil
Account = conseil.tezos.alphanet.accounts
query = Account.query() \
.order_by(Account.balance.desc()) \
.limit(1)
Then you can simply:
>>> query
Path
data/tezos/alphanet/accounts
Query
{"aggregation": [],
"fields": [],
"limit": 1,
"orderBy": [{"direction": "desc", "field": "balance"}],
"output": "json",
"predicates": []}
Execution
It's time to submit our query and get some data.
from conseil import conseil
Account = conseil.tezos.alphanet.accounts
Return multiple rows
query = Account.query()
query.all() # will return List[dict] (default output type)
query.all(output='csv') # will return string (csv)
Return single row
query = Account.query() \
.filter_by(account_id='tzkt')
query.one() # will fail if there is no account with such id or there are many
query.one_or_none() # will handle the exception and return None
Return scalar
query = Account.balance.query() \
.order_by(Account.balance.desc()) \
.limit(1)
query.scalar() # will return single numeric value
Return vector
query = Operation.query(Operation.timestamp) \
.filter_by(source='tzkt')
query.vector() # will return flat list of timestamps
Precision
Conseil allows to specify numeric column precision. In order to use this functionality use decimal type. For example:
from conseil import conseil
from decimal import Decimal
Account = conseil.tezos.alphanet.accounts
Account.query(Account.balance) \
.filter(Account.balance > Decimal('0.1'),
Account.balance < Decimal('0.01')) # precision will be 2 (max)
Renaming fields
You can change names of requested fields in the resulting json/csv:
from conseil import conseil
Account = conseil.tezos.alphanet.accounts
Account.query(Account.account_id.label('address'))
Metadata
Release files for conseil 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| conseil-0.1.4.tar.gz | 12.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| conseil-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 23.1 kB
Release files / conseil-0.1.4.tar.gz
| Download URL | conseil-0.1.4.tar.gz |
|---|---|
| Size | 12.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a3b2b6de5003c18c66090bdff2e7f27914e79373df716d2314ab3244623d8333
|
|
BLAKE2b-256 checksum How to use checksums |
3343f5b0746c979748144b9226b6f42bb70e7f3f2f6801744ce8aeb7014d1672
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/0.12.17 CPython/3.7.0 Linux/4.15.0-54-generic
|
Release files / conseil-0.1.4-py3-none-any.whl
| Download URL | conseil-0.1.4-py3-none-any.whl |
|---|---|
| Size | 10.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c87d0cd0104086535d70574ab70acb0a995ddf4889da747b1738e081235f9c0f
|
|
BLAKE2b-256 checksum How to use checksums |
f7767da787c8f2a62a1bde6d06720499c090c5672c6ce39f08c3597dcf5d75c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/0.12.17 CPython/3.7.0 Linux/4.15.0-54-generic
|
Security for conseil 0.1.4
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.