# -*- coding: utf-8 -*-
"""IPFS API Bindings for Python.
Classes:
* Client – a TCP client for interacting with an IPFS daemon
"""
from __future__ import absolute_import
from . import http, multipart, utils, exceptions, encoding
DEFAULT_HOST = 'localhost'
DEFAULT_PORT = 5001
DEFAULT_BASE = 'api/v0'
VERSION_MINIMUM = "0.4.3"
VERSION_MAXIMUM = "0.5.0"
[docs]def assert_version(version, minimum=VERSION_MINIMUM, maximum=VERSION_MAXIMUM):
"""Make sure that the given daemon version is supported by this client
version.
Raises
------
~ipfsapi.exceptions.VersionMismatch
Parameters
----------
version : str
The version of an IPFS daemon.
minimum : str
The minimal IPFS version to allow.
maximum : str
The maximum IPFS version to allow.
"""
# Convert version strings to integer tuples
version = list(map(int, version.split('-', 1)[0].split('.')))
minimum = list(map(int, minimum.split('-', 1)[0].split('.')))
maximum = list(map(int, maximum.split('-', 1)[0].split('.')))
if minimum > version or version >= maximum:
raise exceptions.VersionMismatch(version, minimum, maximum)
[docs]def connect(host=DEFAULT_HOST, port=DEFAULT_PORT, base=DEFAULT_BASE,
chunk_size=multipart.default_chunk_size, **defaults):
"""Create a new :class:`~ipfsapi.Client` instance and connect to the
daemon to validate that its version is supported.
Raises
------
~ipfsapi.exceptions.VersionMismatch
~ipfsapi.exceptions.ErrorResponse
~ipfsapi.exceptions.ConnectionError
~ipfsapi.exceptions.ProtocolError
~ipfsapi.exceptions.StatusError
~ipfsapi.exceptions.TimeoutError
All parameters are identical to those passed to the constructor of the
:class:`~ipfsapi.Client` class.
Returns
-------
~ipfsapi.Client
"""
# Create client instance
client = Client(host, port, base, chunk_size, **defaults)
# Query version number from daemon and validate it
assert_version(client.version()['Version'])
return client
[docs]class Client(object):
"""A TCP client for interacting with an IPFS daemon.
A :class:`~ipfsapi.Client` instance will not actually establish a
connection to the daemon until at least one of it's methods is called.
Parameters
----------
host : str
Hostname or IP address of the computer running the ``ipfs daemon``
node (defaults to the local system)
port : int
The API port of the IPFS deamon (usually 5001)
base : str
Path of the deamon's API (currently always ``api/v0``)
chunk_size : int
The size of the chunks to break uploaded files and text content into
"""
_clientfactory = http.HTTPClient
def __init__(self, host=DEFAULT_HOST, port=DEFAULT_PORT,
base=DEFAULT_BASE, chunk_size=multipart.default_chunk_size,
**defaults):
"""Connects to the API port of an IPFS node."""
self.chunk_size = chunk_size
self._client = self._clientfactory(host, port, base, **defaults)
[docs] def add(self, files, recursive=False, pattern='**', **kwargs):
"""Add a file, or directory of files to IPFS.
.. code-block:: python
>>> with io.open('nurseryrhyme.txt', 'w', encoding='utf-8') as f:
... numbytes = f.write('Mary had a little lamb')
>>> c.add('nurseryrhyme.txt')
{'Hash': 'QmZfF6C9j4VtoCsTp4KSrhYH47QMd3DNXVZBKaxJdhaPab',
'Name': 'nurseryrhyme.txt'}
Parameters
----------
files : str
A filepath to either a file or directory
recursive : bool
Controls if files in subdirectories are added or not
pattern : str | list
Single `*glob* <https://docs.python.org/3/library/glob.html>`_
pattern or list of *glob* patterns and compiled regular expressions
to match the names of the filepaths to keep
Returns
-------
dict: File name and hash of the added file node
"""
body, headers = multipart.stream_filesystem_node(
files, recursive, pattern, self.chunk_size
)
return self._client.request('/add', decoder='json',
data=body, headers=headers, **kwargs)
[docs] def get(self, multihash, **kwargs):
"""Downloads a file, or directory of files from IPFS.
Files are placed in the current working directory.
Parameters
----------
multihash : str
The path to the IPFS object(s) to be outputted
"""
args = (multihash,)
return self._client.download('/get', args, **kwargs)
[docs] def cat(self, multihash, **kwargs):
r"""Retrieves the contents of a file identified by hash.
.. code-block:: python
>>> c.cat('QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D')
Traceback (most recent call last):
...
ipfsapi.exceptions.Error: this dag node is a directory
>>> c.cat('QmeKozNssnkJ4NcyRidYgDY2jfRZqVEoRGfipkgath71bX')
b'<!DOCTYPE html>\n<html>\n\n<head>\n<title>ipfs example viewer</…'
Parameters
----------
multihash : str
The path to the IPFS object(s) to be retrieved
Returns
-------
str : File contents
"""
args = (multihash,)
return self._client.request('/cat', args, **kwargs)
[docs] def ls(self, multihash, **kwargs):
"""Returns a list of objects linked to by the given hash.
.. code-block:: python
>>> c.ls('QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D')
{'Objects': [
{'Hash': 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D',
'Links': [
{'Hash': 'Qmd2xkBfEwEs9oMTk77A6jrsgurpF3ugXSg7dtPNFkcNMV',
'Name': 'Makefile', 'Size': 174, 'Type': 2},
…
{'Hash': 'QmSY8RfVntt3VdxWppv9w5hWgNrE31uctgTiYwKir8eXJY',
'Name': 'published-version', 'Size': 55, 'Type': 2}
]}
]}
Parameters
----------
multihash : str
The path to the IPFS object(s) to list links from
Returns
-------
dict : Directory information and contents
"""
args = (multihash,)
return self._client.request('/ls', args, decoder='json', **kwargs)
[docs] def refs(self, multihash, **kwargs):
"""Returns a list of hashes of objects referenced by the given hash.
.. code-block:: python
>>> c.refs('QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D')
[{'Ref': 'Qmd2xkBfEwEs9oMTk77A6jrsgurpF3ugXSg7 … cNMV', 'Err': ''},
…
{'Ref': 'QmSY8RfVntt3VdxWppv9w5hWgNrE31uctgTi … eXJY', 'Err': ''}]
Parameters
----------
multihash : str
Path to the object(s) to list refs from
Returns
-------
list
"""
args = (multihash,)
return self._client.request('/refs', args, decoder='json', **kwargs)
[docs] def refs_local(self, **kwargs):
"""Displays the hashes of all local objects.
.. code-block:: python
>>> c.refs_local()
[{'Ref': 'Qmd2xkBfEwEs9oMTk77A6jrsgurpF3ugXSg7 … cNMV', 'Err': ''},
…
{'Ref': 'QmSY8RfVntt3VdxWppv9w5hWgNrE31uctgTi … eXJY', 'Err': ''}]
Returns
-------
list
"""
return self._client.request('/refs/local', decoder='json', **kwargs)
[docs] def block_stat(self, multihash, **kwargs):
"""Returns a dict with the size of the block with the given hash.
.. code-block:: python
>>> c.block_stat('QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D')
{'Key': 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D',
'Size': 258}
Parameters
----------
multihash : str
The base58 multihash of an existing block to stat
Returns
-------
dict : Information about the requested block
"""
args = (multihash,)
return self._client.request('/block/stat', args,
decoder='json', **kwargs)
[docs] def block_get(self, multihash, **kwargs):
r"""Returns the raw contents of a block.
.. code-block:: python
>>> c.block_get('QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D')
b'\x121\n"\x12 \xdaW>\x14\xe5\xc1\xf6\xe4\x92\xd1 … \n\x02\x08\x01'
Parameters
----------
multihash : str
The base58 multihash of an existing block to get
Returns
-------
str : Value of the requested block
"""
args = (multihash,)
return self._client.request('/block/get', args, **kwargs)
[docs] def block_put(self, file, **kwargs):
"""Stores the contents of the given file object as an IPFS block.
.. code-block:: python
>>> c.block_put(io.BytesIO(b'Mary had a little lamb'))
{'Key': 'QmeV6C6XVt1wf7V7as7Yak3mxPma8jzpqyhtRtCvpKcfBb',
'Size': 22}
Parameters
----------
file : io.RawIOBase
The data to be stored as an IPFS block
Returns
-------
dict : Information about the new block
See :meth:`~ipfsapi.Client.block_stat`
"""
body, headers = multipart.stream_files(file, self.chunk_size)
return self._client.request('/block/put', decoder='json',
data=body, headers=headers, **kwargs)
[docs] def bitswap_wantlist(self, peer=None, **kwargs):
"""Returns blocks currently on the bitswap wantlist.
.. code-block:: python
>>> c.bitswap_wantlist()
{'Keys': [
'QmeV6C6XVt1wf7V7as7Yak3mxPma8jzpqyhtRtCvpKcfBb',
'QmdCWFLDXqgdWQY9kVubbEHBbkieKd3uo7MtCm7nTZZE9K',
'QmVQ1XvYGF19X4eJqz1s7FJYJqAxFC4oqh3vWJJEXn66cp'
]}
Parameters
----------
peer : str
Peer to show wantlist for.
Returns
-------
dict : List of wanted blocks
"""
args = (peer,)
return self._client.request('/bitswap/wantlist', args,
decoder='json', **kwargs)
[docs] def bitswap_stat(self, **kwargs):
"""Returns some diagnostic information from the bitswap agent.
.. code-block:: python
>>> c.bitswap_stat()
{'BlocksReceived': 96,
'DupBlksReceived': 73,
'DupDataReceived': 2560601,
'ProviderBufLen': 0,
'Peers': [
'QmNZFQRxt9RMNm2VVtuV2Qx7q69bcMWRVXmr5CEkJEgJJP',
'QmNfCubGpwYZAQxX8LQDsYgB48C4GbfZHuYdexpX9mbNyT',
'QmNfnZ8SCs3jAtNPc8kf3WJqJqSoX7wsX7VqkLdEYMao4u',
…
],
'Wantlist': [
'QmeV6C6XVt1wf7V7as7Yak3mxPma8jzpqyhtRtCvpKcfBb',
'QmdCWFLDXqgdWQY9kVubbEHBbkieKd3uo7MtCm7nTZZE9K',
'QmVQ1XvYGF19X4eJqz1s7FJYJqAxFC4oqh3vWJJEXn66cp'
]
}
Returns
-------
dict : Statistics, peers and wanted blocks
"""
return self._client.request('/bitswap/stat', decoder='json', **kwargs)
[docs] def bitswap_unwant(self, key, **kwargs):
"""
Remove a given block from wantlist.
Parameters
----------
key : str
Key to remove from wantlist.
"""
args = (key,)
return self._client.request('/bitswap/unwant', args, **kwargs)
[docs] def object_data(self, multihash, **kwargs):
r"""Returns the raw bytes in an IPFS object.
.. code-block:: python
>>> c.object_data('QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D')
b'\x08\x01'
Parameters
----------
multihash : str
Key of the object to retrieve, in base58-encoded multihash format
Returns
-------
str : Raw object data
"""
args = (multihash,)
return self._client.request('/object/data', args, **kwargs)
[docs] def object_new(self, template=None, **kwargs):
"""Creates a new object from an IPFS template.
By default this creates and returns a new empty merkledag node, but you
may pass an optional template argument to create a preformatted node.
.. code-block:: python
>>> c.object_new()
{'Hash': 'QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n'}
Parameters
----------
template : str
Blueprints from which to construct the new object. Possible values:
* ``"unixfs-dir"``
* ``None``
Returns
-------
dict : Object hash
"""
args = (template,) if template is not None else ()
return self._client.request('/object/new', args,
decoder='json', **kwargs)
[docs] def object_links(self, multihash, **kwargs):
"""Returns the links pointed to by the specified object.
.. code-block:: python
>>> c.object_links('QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDx … ca7D')
{'Hash': 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D',
'Links': [
{'Hash': 'Qmd2xkBfEwEs9oMTk77A6jrsgurpF3ugXSg7dtPNFkcNMV',
'Name': 'Makefile', 'Size': 174},
{'Hash': 'QmeKozNssnkJ4NcyRidYgDY2jfRZqVEoRGfipkgath71bX',
'Name': 'example', 'Size': 1474},
{'Hash': 'QmZAL3oHMQYqsV61tGvoAVtQLs1WzRe1zkkamv9qxqnDuK',
'Name': 'home', 'Size': 3947},
{'Hash': 'QmZNPyKVriMsZwJSNXeQtVQSNU4v4KEKGUQaMT61LPahso',
'Name': 'lib', 'Size': 268261},
{'Hash': 'QmSY8RfVntt3VdxWppv9w5hWgNrE31uctgTiYwKir8eXJY',
'Name': 'published-version', 'Size': 55}]}
Parameters
----------
multihash : str
Key of the object to retrieve, in base58-encoded multihash format
Returns
-------
dict : Object hash and merkedag links
"""
args = (multihash,)
return self._client.request('/object/links', args,
decoder='json', **kwargs)
[docs] def object_get(self, multihash, **kwargs):
"""Get and serialize the DAG node named by multihash.
.. code-block:: python
>>> c.object_get('QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D')
{'Data': '\x08\x01',
'Links': [
{'Hash': 'Qmd2xkBfEwEs9oMTk77A6jrsgurpF3ugXSg7dtPNFkcNMV',
'Name': 'Makefile', 'Size': 174},
{'Hash': 'QmeKozNssnkJ4NcyRidYgDY2jfRZqVEoRGfipkgath71bX',
'Name': 'example', 'Size': 1474},
{'Hash': 'QmZAL3oHMQYqsV61tGvoAVtQLs1WzRe1zkkamv9qxqnDuK',
'Name': 'home', 'Size': 3947},
{'Hash': 'QmZNPyKVriMsZwJSNXeQtVQSNU4v4KEKGUQaMT61LPahso',
'Name': 'lib', 'Size': 268261},
{'Hash': 'QmSY8RfVntt3VdxWppv9w5hWgNrE31uctgTiYwKir8eXJY',
'Name': 'published-version', 'Size': 55}]}
Parameters
----------
multihash : str
Key of the object to retrieve, in base58-encoded multihash format
Returns
-------
dict : Object data and links
"""
args = (multihash,)
return self._client.request('/object/get', args,
decoder='json', **kwargs)
[docs] def object_put(self, file, **kwargs):
"""Stores input as a DAG object and returns its key.
.. code-block:: python
>>> c.object_put(io.BytesIO(b'''
... {
... "Data": "another",
... "Links": [ {
... "Name": "some link",
... "Hash": "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCV … R39V",
... "Size": 8
... } ]
... }'''))
{'Hash': 'QmZZmY4KCu9r3e7M2Pcn46Fc5qbn6NpzaAGaYb22kbfTqm',
'Links': [
{'Hash': 'QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V',
'Size': 8, 'Name': 'some link'}
]
}
Parameters
----------
file : io.RawIOBase
(JSON) object from which the DAG object will be created
Returns
-------
dict : Hash and links of the created DAG object
See :meth:`~ipfsapi.Object.object_links`
"""
body, headers = multipart.stream_files(file, self.chunk_size)
return self._client.request('/object/put', decoder='json',
data=body, headers=headers, **kwargs)
[docs] def object_stat(self, multihash, **kwargs):
"""Get stats for the DAG node named by multihash.
.. code-block:: python
>>> c.object_stat('QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D')
{'LinksSize': 256, 'NumLinks': 5,
'Hash': 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D',
'BlockSize': 258, 'CumulativeSize': 274169, 'DataSize': 2}
Parameters
----------
multihash : str
Key of the object to retrieve, in base58-encoded multihash format
Returns
-------
dict
"""
args = (multihash,)
return self._client.request('/object/stat', args,
decoder='json', **kwargs)
[docs] def object_patch_append_data(self, multihash, new_data, **kwargs):
"""Creates a new merkledag object based on an existing one.
The new object will have the provided data appended to it,
and will thus have a new Hash.
.. code-block:: python
>>> c.object_patch_append_data("QmZZmY … fTqm", io.BytesIO(b"bla"))
{'Hash': 'QmR79zQQj2aDfnrNgczUhvf2qWapEfQ82YQRt3QjrbhSb2'}
Parameters
----------
multihash : str
The hash of an ipfs object to modify
new_data : io.RawIOBase
The data to append to the object's data section
Returns
-------
dict : Hash of new object
"""
args = (multihash,)
body, headers = multipart.stream_files(new_data, self.chunk_size)
return self._client.request('/object/patch/append-data', args,
decoder='json',
data=body, headers=headers, **kwargs)
[docs] def object_patch_add_link(self, root, name, ref, create=False, **kwargs):
"""Creates a new merkledag object based on an existing one.
The new object will have a link to the provided object.
.. code-block:: python
>>> c.object_patch_add_link(
... 'QmR79zQQj2aDfnrNgczUhvf2qWapEfQ82YQRt3QjrbhSb2',
... 'Johnny',
... 'QmR79zQQj2aDfnrNgczUhvf2qWapEfQ82YQRt3QjrbhSb2'
... )
{'Hash': 'QmNtXbF3AjAk59gQKRgEdVabHcSsiPUnJwHnZKyj2x8Z3k'}
Parameters
----------
root : str
IPFS hash for the object being modified
name : str
name for the new link
ref : str
IPFS hash for the object being linked to
create : bool
Create intermediary nodes
Returns
-------
dict : Hash of new object
"""
kwargs.setdefault("opts", {"create": create})
args = ((root, name, ref),)
return self._client.request('/object/patch/add-link', args,
decoder='json', **kwargs)
[docs] def object_patch_rm_link(self, root, link, **kwargs):
"""Creates a new merkledag object based on an existing one.
The new object will lack a link to the specified object.
.. code-block:: python
>>> c.object_patch_rm_link(
... 'QmNtXbF3AjAk59gQKRgEdVabHcSsiPUnJwHnZKyj2x8Z3k',
... 'Johnny'
... )
{'Hash': 'QmR79zQQj2aDfnrNgczUhvf2qWapEfQ82YQRt3QjrbhSb2'}
Parameters
----------
root : str
IPFS hash of the object to modify
link : str
name of the link to remove
Returns
-------
dict : Hash of new object
"""
args = ((root, link),)
return self._client.request('/object/patch/rm-link', args,
decoder='json', **kwargs)
[docs] def object_patch_set_data(self, root, data, **kwargs):
"""Creates a new merkledag object based on an existing one.
The new object will have the same links as the old object but
with the provided data instead of the old object's data contents.
.. code-block:: python
>>> c.object_patch_set_data(
... 'QmNtXbF3AjAk59gQKRgEdVabHcSsiPUnJwHnZKyj2x8Z3k',
... io.BytesIO(b'bla')
... )
{'Hash': 'QmSw3k2qkv4ZPsbu9DVEJaTMszAQWNgM1FTFYpfZeNQWrd'}
Parameters
----------
root : str
IPFS hash of the object to modify
data : io.RawIOBase
The new data to store in root
Returns
-------
dict : Hash of new object
"""
args = (root,)
body, headers = multipart.stream_files(data, self.chunk_size)
return self._client.request('/object/patch/set-data', args,
decoder='json',
data=body, headers=headers, **kwargs)
[docs] def file_ls(self, multihash, **kwargs):
"""Lists directory contents for Unix filesystem objects.
The result contains size information. For files, the child size is the
total size of the file contents. For directories, the child size is the
IPFS link size.
The path can be a prefixless reference; in this case, it is assumed
that it is an ``/ipfs/`` reference and not ``/ipns/``.
.. code-block:: python
>>> c.file_ls('QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D')
{'Arguments': {'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D':
'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D'},
'Objects': {
'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D': {
'Hash': 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D',
'Size': 0, 'Type': 'Directory',
'Links': [
{'Hash': 'Qmd2xkBfEwEs9oMTk77A6jrsgurpF3ugXSg7dtPNFkcNMV',
'Name': 'Makefile', 'Size': 163, 'Type': 'File'},
{'Hash': 'QmeKozNssnkJ4NcyRidYgDY2jfRZqVEoRGfipkgath71bX',
'Name': 'example', 'Size': 1463, 'Type': 'File'},
{'Hash': 'QmZAL3oHMQYqsV61tGvoAVtQLs1WzRe1zkkamv9qxqnDuK',
'Name': 'home', 'Size': 3947, 'Type': 'Directory'},
{'Hash': 'QmZNPyKVriMsZwJSNXeQtVQSNU4v4KEKGUQaMT61LPahso',
'Name': 'lib', 'Size': 268261, 'Type': 'Directory'},
{'Hash': 'QmSY8RfVntt3VdxWppv9w5hWgNrE31uctgTiYwKir8eXJY',
'Name': 'published-version',
'Size': 47, 'Type': 'File'}
]
}
}}
Parameters
----------
multihash : str
The path to the object(s) to list links from
Returns
-------
dict
"""
args = (multihash,)
return self._client.request('/file/ls', args, decoder='json', **kwargs)
[docs] def resolve(self, name, recursive=False, **kwargs):
"""Accepts an identifier and resolves it to the referenced item.
There are a number of mutable name protocols that can link among
themselves and into IPNS. For example IPNS references can (currently)
point at an IPFS object, and DNS links can point at other DNS links,
IPNS entries, or IPFS objects. This command accepts any of these
identifiers.
.. code-block:: python
>>> c.resolve("/ipfs/QmTkzDwWqPbnAh5YiV5VwcTLnGdw … ca7D/Makefile")
{'Path': '/ipfs/Qmd2xkBfEwEs9oMTk77A6jrsgurpF3ugXSg7dtPNFkcNMV'}
>>> c.resolve("/ipns/ipfs.io")
{'Path': '/ipfs/QmTzQ1JRkWErjk39mryYw2WVaphAZNAREyMchXzYQ7c15n'}
Parameters
----------
name : str
The name to resolve
recursive : bool
Resolve until the result is an IPFS name
Returns
-------
dict : IPFS path of resource
"""
kwargs.setdefault("opts", {"recursive": recursive})
args = (name,)
return self._client.request('/resolve', args, decoder='json', **kwargs)
[docs] def key_list(self, **kwargs):
"""Returns a list of generated public keys that can be used with name_publish
.. code-block:: python
>>> c.key_list()
[{'Name': 'self',
'Id': 'QmQf22bZar3WKmojipms22PkXH1MZGmvsqzQtuSvQE3uhm'},
{'Name': 'example_key_name',
'Id': 'QmQLaT5ZrCfSkXTH6rUKtVidcxj8jrW3X2h75Lug1AV7g8'}
]
Returns
-------
list : List of dictionaries with Names and Ids of public keys.
"""
return self._client.request('/key/list', decoder='json')['Keys']
[docs] def key_gen(self, key_name, type, size=2048, **kwargs):
"""Adds a new public key that can be used for name_publish.
.. code-block:: python
>>> c.key_gen('example_key_name')
{'Name': 'example_key_name',
'Id': 'QmQLaT5ZrCfSkXTH6rUKtVidcxj8jrW3X2h75Lug1AV7g8'}
Parameters
----------
key_name : str
Name of the new Key to be generated. Used to reference the Keys.
type : str
Type of key to generate. The current possible keys types are:
* ``"rsa"``
* ``"ed25519"``
size : int
Bitsize of key to generate
Returns
-------
dict : Key name and Key Id
"""
existing_keys = self.key_list()
for key in existing_keys:
if key['Name'] == key_name:
return key
opts = {"type": type, "size": size}
kwargs.setdefault("opts", opts)
args = (key_name,)
return self._client.request('/key/gen', args,
decoder='json', **kwargs)
[docs] def name_publish(self, ipfs_path, resolve=True, lifetime="24h", ttl=None,
key=None, **kwargs):
"""Publishes an object to IPNS.
IPNS is a PKI namespace, where names are the hashes of public keys, and
the private key enables publishing new (signed) values. In publish, the
default value of *name* is your own identity public key.
.. code-block:: python
>>> c.name_publish('/ipfs/QmfZY61ukoQuCX8e5Pt7v8pRfhkyxwZK … GZ5d')
{'Value': '/ipfs/QmfZY61ukoQuCX8e5Pt7v8pRfhkyxwZKZMTodAtmvyGZ5d',
'Name': 'QmVgNoP89mzpgEAAqK8owYoDEyB97MkcGvoWZir8otE9Uc'}
Parameters
----------
ipfs_path : str
IPFS path of the object to be published
resolve : bool
Resolve given path before publishing
lifetime : str
Time duration that the record will be valid for
Accepts durations such as ``"300s"``, ``"1.5h"`` or ``"2h45m"``.
Valid units are:
* ``"ns"``
* ``"us"`` (or ``"µs"``)
* ``"ms"``
* ``"s"``
* ``"m"``
* ``"h"``
ttl : int
Time duration this record should be cached for
key : string
Name of the key to be used, as listed by 'ipfs key list'.
Returns
-------
dict : IPNS hash and the IPFS path it points at
"""
opts = {"lifetime": lifetime, "resolve": resolve}
if ttl:
opts["ttl"] = ttl
if key:
opts["key"] = key
kwargs.setdefault("opts", opts)
args = (ipfs_path,)
return self._client.request('/name/publish', args,
decoder='json', **kwargs)
[docs] def name_resolve(self, name=None, recursive=False,
nocache=False, **kwargs):
"""Gets the value currently published at an IPNS name.
IPNS is a PKI namespace, where names are the hashes of public keys, and
the private key enables publishing new (signed) values. In resolve, the
default value of ``name`` is your own identity public key.
.. code-block:: python
>>> c.name_resolve()
{'Path': '/ipfs/QmfZY61ukoQuCX8e5Pt7v8pRfhkyxwZKZMTodAtmvyGZ5d'}
Parameters
----------
name : str
The IPNS name to resolve (defaults to the connected node)
recursive : bool
Resolve until the result is not an IPFS name (default: false)
nocache : bool
Do not use cached entries (default: false)
Returns
-------
dict : The IPFS path the IPNS hash points at
"""
kwargs.setdefault("opts", {"recursive": recursive,
"nocache": nocache})
args = (name,) if name is not None else ()
return self._client.request('/name/resolve', args,
decoder='json', **kwargs)
[docs] def dns(self, domain_name, recursive=False, **kwargs):
"""Resolves DNS links to the referenced object.
Multihashes are hard to remember, but domain names are usually easy to
remember. To create memorable aliases for multihashes, DNS TXT records
can point to other DNS links, IPFS objects, IPNS keys, etc.
This command resolves those links to the referenced object.
For example, with this DNS TXT record::
>>> import dns.resolver
>>> a = dns.resolver.query("ipfs.io", "TXT")
>>> a.response.answer[0].items[0].to_text()
'"dnslink=/ipfs/QmTzQ1JRkWErjk39mryYw2WVaphAZNAREyMchXzYQ7c15n"'
The resolver will give::
>>> c.dns("ipfs.io")
{'Path': '/ipfs/QmTzQ1JRkWErjk39mryYw2WVaphAZNAREyMchXzYQ7c15n'}
Parameters
----------
domain_name : str
The domain-name name to resolve
recursive : bool
Resolve until the name is not a DNS link
Returns
-------
dict : Resource were a DNS entry points to
"""
kwargs.setdefault("opts", {"recursive": recursive})
args = (domain_name,)
return self._client.request('/dns', args, decoder='json', **kwargs)
[docs] def pin_add(self, path, *paths, **kwargs):
"""Pins objects to local storage.
Stores an IPFS object(s) from a given path locally to disk.
.. code-block:: python
>>> c.pin_add("QmfZY61ukoQuCX8e5Pt7v8pRfhkyxwZKZMTodAtmvyGZ5d")
{'Pins': ['QmfZY61ukoQuCX8e5Pt7v8pRfhkyxwZKZMTodAtmvyGZ5d']}
Parameters
----------
path : str
Path to object(s) to be pinned
recursive : bool
Recursively unpin the object linked to by the specified object(s)
Returns
-------
dict : List of IPFS objects that have been pinned
"""
#PY2: No support for kw-only parameters after glob parameters
if "recursive" in kwargs:
kwargs.setdefault("opts", {"recursive": kwargs.pop("recursive")})
args = (path,) + paths
return self._client.request('/pin/add', args, decoder='json', **kwargs)
[docs] def pin_rm(self, path, *paths, **kwargs):
"""Removes a pinned object from local storage.
Removes the pin from the given object allowing it to be garbage
collected if needed.
.. code-block:: python
>>> c.pin_rm('QmfZY61ukoQuCX8e5Pt7v8pRfhkyxwZKZMTodAtmvyGZ5d')
{'Pins': ['QmfZY61ukoQuCX8e5Pt7v8pRfhkyxwZKZMTodAtmvyGZ5d']}
Parameters
----------
path : str
Path to object(s) to be unpinned
recursive : bool
Recursively unpin the object linked to by the specified object(s)
Returns
-------
dict : List of IPFS objects that have been unpinned
"""
#PY2: No support for kw-only parameters after glob parameters
if "recursive" in kwargs:
kwargs.setdefault("opts", {"recursive": kwargs["recursive"]})
del kwargs["recursive"]
args = (path,) + paths
return self._client.request('/pin/rm', args, decoder='json', **kwargs)
[docs] def pin_ls(self, type="all", **kwargs):
"""Lists objects pinned to local storage.
By default, all pinned objects are returned, but the ``type`` flag or
arguments can restrict that to a specific pin type or to some specific
objects respectively.
.. code-block:: python
>>> c.pin_ls()
{'Keys': {
'QmNNPMA1eGUbKxeph6yqV8ZmRkdVat … YMuz': {'Type': 'recursive'},
'QmNPZUCeSN5458Uwny8mXSWubjjr6J … kP5e': {'Type': 'recursive'},
'QmNg5zWpRMxzRAVg7FTQ3tUxVbKj8E … gHPz': {'Type': 'indirect'},
…
'QmNiuVapnYCrLjxyweHeuk6Xdqfvts … wCCe': {'Type': 'indirect'}}}
Parameters
----------
type : "str"
The type of pinned keys to list. Can be:
* ``"direct"``
* ``"indirect"``
* ``"recursive"``
* ``"all"``
Returns
-------
dict : Hashes of pinned IPFS objects and why they are pinned
"""
kwargs.setdefault("opts", {"type": type})
return self._client.request('/pin/ls', decoder='json', **kwargs)
[docs] def repo_gc(self, **kwargs):
"""Removes stored objects that are not pinned from the repo.
.. code-block:: python
>>> c.repo_gc()
[{'Key': 'QmNPXDC6wTXVmZ9Uoc8X1oqxRRJr4f1sDuyQuwaHG2mpW2'},
{'Key': 'QmNtXbF3AjAk59gQKRgEdVabHcSsiPUnJwHnZKyj2x8Z3k'},
{'Key': 'QmRVBnxUCsD57ic5FksKYadtyUbMsyo9KYQKKELajqAp4q'},
…
{'Key': 'QmYp4TeCurXrhsxnzt5wqLqqUz8ZRg5zsc7GuUrUSDtwzP'}]
Performs a garbage collection sweep of the local set of
stored objects and remove ones that are not pinned in order
to reclaim hard disk space. Returns the hashes of all collected
objects.
Returns
-------
dict : List of IPFS objects that have been removed
"""
return self._client.request('/repo/gc', decoder='json', **kwargs)
[docs] def repo_stat(self, **kwargs):
"""Displays the repo's status.
Returns the number of objects in the repo and the repo's size,
version, and path.
.. code-block:: python
>>> c.repo_stat()
{'NumObjects': 354,
'RepoPath': '…/.local/share/ipfs',
'Version': 'fs-repo@4',
'RepoSize': 13789310}
Returns
-------
dict : General information about the IPFS file repository
+------------+-------------------------------------------------+
| NumObjects | Number of objects in the local repo. |
+------------+-------------------------------------------------+
| RepoPath | The path to the repo being currently used. |
+------------+-------------------------------------------------+
| RepoSize | Size in bytes that the repo is currently using. |
+------------+-------------------------------------------------+
| Version | The repo version. |
+------------+-------------------------------------------------+
"""
return self._client.request('/repo/stat', decoder='json', **kwargs)
[docs] def id(self, peer=None, **kwargs):
"""Shows IPFS Node ID info.
Returns the PublicKey, ProtocolVersion, ID, AgentVersion and
Addresses of the connected daemon or some other node.
.. code-block:: python
>>> c.id()
{'ID': 'QmVgNoP89mzpgEAAqK8owYoDEyB97MkcGvoWZir8otE9Uc',
'PublicKey': 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggE … BAAE=',
'AgentVersion': 'go-libp2p/3.3.4',
'ProtocolVersion': 'ipfs/0.1.0',
'Addresses': [
'/ip4/127.0.0.1/tcp/4001/ipfs/QmVgNoP89mzpgEAAqK8owYo … E9Uc',
'/ip4/10.1.0.172/tcp/4001/ipfs/QmVgNoP89mzpgEAAqK8owY … E9Uc',
'/ip4/172.18.0.1/tcp/4001/ipfs/QmVgNoP89mzpgEAAqK8owY … E9Uc',
'/ip6/::1/tcp/4001/ipfs/QmVgNoP89mzpgEAAqK8owYoDEyB97 … E9Uc',
'/ip6/fccc:7904:b05b:a579:957b:deef:f066:cad9/tcp/400 … E9Uc',
'/ip6/fd56:1966:efd8::212/tcp/4001/ipfs/QmVgNoP89mzpg … E9Uc',
'/ip6/fd56:1966:efd8:0:def1:34d0:773:48f/tcp/4001/ipf … E9Uc',
'/ip6/2001:db8:1::1/tcp/4001/ipfs/QmVgNoP89mzpgEAAqK8 … E9Uc',
'/ip4/77.116.233.54/tcp/4001/ipfs/QmVgNoP89mzpgEAAqK8 … E9Uc',
'/ip4/77.116.233.54/tcp/10842/ipfs/QmVgNoP89mzpgEAAqK … E9Uc']}
Parameters
----------
peer : str
Peer.ID of the node to look up (local node if ``None``)
Returns
-------
dict : Information about the IPFS node
"""
args = (peer,) if peer is not None else ()
return self._client.request('/id', args, decoder='json', **kwargs)
[docs] def bootstrap(self, **kwargs):
"""Compatiblity alias for :meth:`~ipfsapi.Client.bootstrap_list`."""
self.bootstrap_list(**kwargs)
[docs] def bootstrap_list(self, **kwargs):
"""Returns the addresses of peers used during initial discovery of the
IPFS network.
Peers are output in the format ``<multiaddr>/<peerID>``.
.. code-block:: python
>>> c.bootstrap_list()
{'Peers': [
'/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYER … uvuJ',
'/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRa … ca9z',
'/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKD … KrGM',
…
'/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3p … QBU3']}
Returns
-------
dict : List of known bootstrap peers
"""
return self._client.request('/bootstrap', decoder='json', **kwargs)
[docs] def bootstrap_add(self, peer, *peers, **kwargs):
"""Adds peers to the bootstrap list.
Parameters
----------
peer : str
IPFS MultiAddr of a peer to add to the list
Returns
-------
dict
"""
args = (peer,) + peers
return self._client.request('/bootstrap/add', args,
decoder='json', **kwargs)
[docs] def bootstrap_rm(self, peer, *peers, **kwargs):
"""Removes peers from the bootstrap list.
Parameters
----------
peer : str
IPFS MultiAddr of a peer to remove from the list
Returns
-------
dict
"""
args = (peer,) + peers
return self._client.request('/bootstrap/rm', args,
decoder='json', **kwargs)
[docs] def swarm_peers(self, **kwargs):
"""Returns the addresses & IDs of currently connected peers.
.. code-block:: python
>>> c.swarm_peers()
{'Strings': [
'/ip4/101.201.40.124/tcp/40001/ipfs/QmZDYAhmMDtnoC6XZ … kPZc',
'/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYER … uvuJ',
'/ip4/104.223.59.174/tcp/4001/ipfs/QmeWdgoZezpdHz1PX8 … 1jB6',
…
'/ip6/fce3: … :f140/tcp/43901/ipfs/QmSoLnSGccFuZQJzRa … ca9z']}
Returns
-------
dict : List of multiaddrs of currently connected peers
"""
return self._client.request('/swarm/peers', decoder='json', **kwargs)
[docs] def swarm_addrs(self, **kwargs):
"""Returns the addresses of currently connected peers by peer id.
.. code-block:: python
>>> pprint(c.swarm_addrs())
{'Addrs': {
'QmNMVHJTSZHTWMWBbmBrQgkA1hZPWYuVJx2DpSGESWW6Kn': [
'/ip4/10.1.0.1/tcp/4001',
'/ip4/127.0.0.1/tcp/4001',
'/ip4/51.254.25.16/tcp/4001',
'/ip6/2001:41d0:b:587:3cae:6eff:fe40:94d8/tcp/4001',
'/ip6/2001:470:7812:1045::1/tcp/4001',
'/ip6/::1/tcp/4001',
'/ip6/fc02:2735:e595:bb70:8ffc:5293:8af8:c4b7/tcp/4001',
'/ip6/fd00:7374:6172:100::1/tcp/4001',
'/ip6/fd20:f8be:a41:0:c495:aff:fe7e:44ee/tcp/4001',
'/ip6/fd20:f8be:a41::953/tcp/4001'],
'QmNQsK1Tnhe2Uh2t9s49MJjrz7wgPHj4VyrZzjRe8dj7KQ': [
'/ip4/10.16.0.5/tcp/4001',
'/ip4/127.0.0.1/tcp/4001',
'/ip4/172.17.0.1/tcp/4001',
'/ip4/178.62.107.36/tcp/4001',
'/ip6/::1/tcp/4001'],
…
}}
Returns
-------
dict : Multiaddrs of peers by peer id
"""
return self._client.request('/swarm/addrs', decoder='json', **kwargs)
[docs] def swarm_connect(self, address, *addresses, **kwargs):
"""Opens a connection to a given address.
This will open a new direct connection to a peer address. The address
format is an IPFS multiaddr::
/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
.. code-block:: python
>>> c.swarm_connect("/ip4/104.131.131.82/tcp/4001/ipfs/Qma … uvuJ")
{'Strings': ['connect QmaCpDMGvV2BGHeYERUEnRQAwe3 … uvuJ success']}
Parameters
----------
address : str
Address of peer to connect to
Returns
-------
dict : Textual connection status report
"""
args = (address,) + addresses
return self._client.request('/swarm/connect', args,
decoder='json', **kwargs)
[docs] def swarm_disconnect(self, address, *addresses, **kwargs):
"""Closes the connection to a given address.
This will close a connection to a peer address. The address format is
an IPFS multiaddr::
/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
The disconnect is not permanent; if IPFS needs to talk to that address
later, it will reconnect.
.. code-block:: python
>>> c.swarm_disconnect("/ip4/104.131.131.82/tcp/4001/ipfs/Qm … uJ")
{'Strings': ['disconnect QmaCpDMGvV2BGHeYERUEnRQA … uvuJ success']}
Parameters
----------
address : str
Address of peer to disconnect from
Returns
-------
dict : Textual connection status report
"""
args = (address,) + addresses
return self._client.request('/swarm/disconnect', args,
decoder='json', **kwargs)
[docs] def swarm_filters_add(self, address, *addresses, **kwargs):
"""Adds a given multiaddr filter to the filter list.
This will add an address filter to the daemons swarm. Filters applied
this way will not persist daemon reboots, to achieve that, add your
filters to the configuration file.
.. code-block:: python
>>> c.swarm_filters_add("/ip4/192.168.0.0/ipcidr/16")
{'Strings': ['/ip4/192.168.0.0/ipcidr/16']}
Parameters
----------
address : str
Multiaddr to filter
Returns
-------
dict : List of swarm filters added
"""
args = (address,) + addresses
return self._client.request('/swarm/filters/add', args,
decoder='json', **kwargs)
[docs] def swarm_filters_rm(self, address, *addresses, **kwargs):
"""Removes a given multiaddr filter from the filter list.
This will remove an address filter from the daemons swarm. Filters
removed this way will not persist daemon reboots, to achieve that,
remove your filters from the configuration file.
.. code-block:: python
>>> c.swarm_filters_rm("/ip4/192.168.0.0/ipcidr/16")
{'Strings': ['/ip4/192.168.0.0/ipcidr/16']}
Parameters
----------
address : str
Multiaddr filter to remove
Returns
-------
dict : List of swarm filters removed
"""
args = (address,) + addresses
return self._client.request('/swarm/filters/rm', args,
decoder='json', **kwargs)
[docs] def dht_query(self, peer_id, *peer_ids, **kwargs):
"""Finds the closest Peer IDs to a given Peer ID by querying the DHT.
.. code-block:: python
>>> c.dht_query("/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDM … uvuJ")
[{'ID': 'QmPkFbxAQ7DeKD5VGSh9HQrdS574pyNzDmxJeGrRJxoucF',
'Extra': '', 'Type': 2, 'Responses': None},
{'ID': 'QmR1MhHVLJSLt9ZthsNNhudb1ny1WdhY4FPW21ZYFWec4f',
'Extra': '', 'Type': 2, 'Responses': None},
{'ID': 'Qmcwx1K5aVme45ab6NYWb52K2TFBeABgCLccC7ntUeDsAs',
'Extra': '', 'Type': 2, 'Responses': None},
…
{'ID': 'QmYYy8L3YD1nsF4xtt4xmsc14yqvAAnKksjo3F3iZs5jPv',
'Extra': '', 'Type': 1, 'Responses': []}]
Parameters
----------
peer_id : str
The peerID to run the query against
Returns
-------
dict : List of peers IDs
"""
args = (peer_id,) + peer_ids
return self._client.request('/dht/query', args,
decoder='json', **kwargs)
[docs] def dht_findprovs(self, multihash, *multihashes, **kwargs):
"""Finds peers in the DHT that can provide a specific value.
.. code-block:: python
>>> c.dht_findprovs("QmNPXDC6wTXVmZ9Uoc8X1oqxRRJr4f1sDuyQu … mpW2")
[{'ID': 'QmaxqKpiYNr62uSFBhxJAMmEMkT6dvc3oHkrZNpH2VMTLZ',
'Extra': '', 'Type': 6, 'Responses': None},
{'ID': 'QmaK6Aj5WXkfnWGoWq7V8pGUYzcHPZp4jKQ5JtmRvSzQGk',
'Extra': '', 'Type': 6, 'Responses': None},
{'ID': 'QmdUdLu8dNvr4MVW1iWXxKoQrbG6y1vAVWPdkeGK4xppds',
'Extra': '', 'Type': 6, 'Responses': None},
…
{'ID': '', 'Extra': '', 'Type': 4, 'Responses': [
{'ID': 'QmVgNoP89mzpgEAAqK8owYoDEyB97Mk … E9Uc', 'Addrs': None}
]},
{'ID': 'QmaxqKpiYNr62uSFBhxJAMmEMkT6dvc3oHkrZNpH2VMTLZ',
'Extra': '', 'Type': 1, 'Responses': [
{'ID': 'QmSHXfsmN3ZduwFDjeqBn1C8b1tcLkxK6yd … waXw', 'Addrs': [
'/ip4/127.0.0.1/tcp/4001',
'/ip4/172.17.0.8/tcp/4001',
'/ip6/::1/tcp/4001',
'/ip4/52.32.109.74/tcp/1028'
]}
]}]
Parameters
----------
multihash : str
The DHT key to find providers for
Returns
-------
dict : List of provider Peer IDs
"""
args = (multihash,) + multihashes
return self._client.request('/dht/findprovs', args,
decoder='json', **kwargs)
[docs] def dht_findpeer(self, peer_id, *peer_ids, **kwargs):
"""Queries the DHT for all of the associated multiaddresses.
.. code-block:: python
>>> c.dht_findpeer("QmaxqKpiYNr62uSFBhxJAMmEMkT6dvc3oHkrZN … MTLZ")
[{'ID': 'QmfVGMFrwW6AV6fTWmD6eocaTybffqAvkVLXQEFrYdk6yc',
'Extra': '', 'Type': 6, 'Responses': None},
{'ID': 'QmTKiUdjbRjeN9yPhNhG1X38YNuBdjeiV9JXYWzCAJ4mj5',
'Extra': '', 'Type': 6, 'Responses': None},
{'ID': 'QmTGkgHSsULk8p3AKTAqKixxidZQXFyF7mCURcutPqrwjQ',
'Extra': '', 'Type': 6, 'Responses': None},
…
{'ID': '', 'Extra': '', 'Type': 2,
'Responses': [
{'ID': 'QmaxqKpiYNr62uSFBhxJAMmEMkT6dvc3oHkrZNpH2VMTLZ',
'Addrs': [
'/ip4/10.9.8.1/tcp/4001',
'/ip6/::1/tcp/4001',
'/ip4/164.132.197.107/tcp/4001',
'/ip4/127.0.0.1/tcp/4001']}
]}]
Parameters
----------
peer_id : str
The ID of the peer to search for
Returns
-------
dict : List of multiaddrs
"""
args = (peer_id,) + peer_ids
return self._client.request('/dht/findpeer', args,
decoder='json', **kwargs)
[docs] def dht_get(self, key, *keys, **kwargs):
"""Queries the DHT for its best value related to given key.
There may be several different values for a given key stored in the
DHT; in this context *best* means the record that is most desirable.
There is no one metric for *best*: it depends entirely on the key type.
For IPNS, *best* is the record that is both valid and has the highest
sequence number (freshest). Different key types may specify other rules
for they consider to be the *best*.
Parameters
----------
key : str
One or more keys whose values should be looked up
Returns
-------
str
"""
args = (key,) + keys
res = self._client.request('/dht/get', args, decoder='json', **kwargs)
if isinstance(res, dict) and "Extra" in res:
return res["Extra"]
else:
for r in res:
if "Extra" in r and len(r["Extra"]) > 0:
return r["Extra"]
raise exceptions.Error("empty response from DHT")
[docs] def dht_put(self, key, value, **kwargs):
"""Writes a key/value pair to the DHT.
Given a key of the form ``/foo/bar`` and a value of any form, this will
write that value to the DHT with that key.
Keys have two parts: a keytype (foo) and the key name (bar). IPNS uses
the ``/ipns/`` keytype, and expects the key name to be a Peer ID. IPNS
entries are formatted with a special strucutre.
You may only use keytypes that are supported in your ``ipfs`` binary:
``go-ipfs`` currently only supports the ``/ipns/`` keytype. Unless you
have a relatively deep understanding of the key's internal structure,
you likely want to be using the :meth:`~ipfsapi.Client.name_publish`
instead.
Value is arbitrary text.
.. code-block:: python
>>> c.dht_put("QmVgNoP89mzpgEAAqK8owYoDEyB97Mkc … E9Uc", "test123")
[{'ID': 'QmfLy2aqbhU1RqZnGQyqHSovV8tDufLUaPfN1LNtg5CvDZ',
'Extra': '', 'Type': 5, 'Responses': None},
{'ID': 'QmZ5qTkNvvZ5eFq9T4dcCEK7kX8L7iysYEpvQmij9vokGE',
'Extra': '', 'Type': 5, 'Responses': None},
{'ID': 'QmYqa6QHCbe6eKiiW6YoThU5yBy8c3eQzpiuW22SgVWSB8',
'Extra': '', 'Type': 6, 'Responses': None},
…
{'ID': 'QmP6TAKVDCziLmx9NV8QGekwtf7ZMuJnmbeHMjcfoZbRMd',
'Extra': '', 'Type': 1, 'Responses': []}]
Parameters
----------
key : str
A unique identifier
value : str
Abitrary text to associate with the input (2048 bytes or less)
Returns
-------
list
"""
args = (key, value)
return self._client.request('/dht/put', args, decoder='json', **kwargs)
[docs] def ping(self, peer, *peers, **kwargs):
"""Provides round-trip latency information for the routing system.
Finds nodes via the routing system, sends pings, waits for pongs,
and prints out round-trip latency information.
.. code-block:: python
>>> c.ping("QmTzQ1JRkWErjk39mryYw2WVaphAZNAREyMchXzYQ7c15n")
[{'Success': True, 'Time': 0,
'Text': 'Looking up peer QmTzQ1JRkWErjk39mryYw2WVaphAZN … c15n'},
{'Success': False, 'Time': 0,
'Text': 'Peer lookup error: routing: not found'}]
Parameters
----------
peer : str
ID of peer to be pinged
count : int
Number of ping messages to send (Default: ``10``)
Returns
-------
list : Progress reports from the ping
"""
#PY2: No support for kw-only parameters after glob parameters
if "count" in kwargs:
kwargs.setdefault("opts", {"count": kwargs["count"]})
del kwargs["count"]
args = (peer,) + peers
return self._client.request('/ping', args, decoder='json', **kwargs)
[docs] def config(self, key, value=None, **kwargs):
"""Controls configuration variables.
.. code-block:: python
>>> c.config("Addresses.Gateway")
{'Key': 'Addresses.Gateway', 'Value': '/ip4/127.0.0.1/tcp/8080'}
>>> c.config("Addresses.Gateway", "/ip4/127.0.0.1/tcp/8081")
{'Key': 'Addresses.Gateway', 'Value': '/ip4/127.0.0.1/tcp/8081'}
Parameters
----------
key : str
The key of the configuration entry (e.g. "Addresses.API")
value : dict
The value to set the configuration entry to
Returns
-------
dict : Requested/updated key and its (new) value
"""
args = (key, value)
return self._client.request('/config', args, decoder='json', **kwargs)
[docs] def config_show(self, **kwargs):
"""Returns a dict containing the server's configuration.
.. warning::
The configuration file contains private key data that must be
handled with care.
.. code-block:: python
>>> config = c.config_show()
>>> config['Addresses']
{'API': '/ip4/127.0.0.1/tcp/5001',
'Gateway': '/ip4/127.0.0.1/tcp/8080',
'Swarm': ['/ip4/0.0.0.0/tcp/4001', '/ip6/::/tcp/4001']},
>>> config['Discovery']
{'MDNS': {'Enabled': True, 'Interval': 10}}
Returns
-------
dict : The entire IPFS daemon configuration
"""
return self._client.request('/config/show', decoder='json', **kwargs)
[docs] def config_replace(self, *args, **kwargs):
"""Replaces the existing config with a user-defined config.
Make sure to back up the config file first if neccessary, as this
operation can't be undone.
"""
return self._client.request('/config/replace', args,
decoder='json', **kwargs)
[docs] def log_level(self, subsystem, level, **kwargs):
r"""Changes the logging output of a running daemon.
.. code-block:: python
>>> c.log_level("path", "info")
{'Message': "Changed log level of 'path' to 'info'\n"}
Parameters
----------
subsystem : str
The subsystem logging identifier (Use ``"all"`` for all subsystems)
level : str
The desired logging level. Must be one of:
* ``"debug"``
* ``"info"``
* ``"warning"``
* ``"error"``
* ``"fatal"``
* ``"panic"``
Returns
-------
dict : Status message
"""
args = (subsystem, level)
return self._client.request('/log/level', args,
decoder='json', **kwargs)
[docs] def log_ls(self, **kwargs):
"""Lists the logging subsystems of a running daemon.
.. code-block:: python
>>> c.log_ls()
{'Strings': [
'github.com/ipfs/go-libp2p/p2p/host', 'net/identify',
'merkledag', 'providers', 'routing/record', 'chunk', 'mfs',
'ipns-repub', 'flatfs', 'ping', 'mockrouter', 'dagio',
'cmds/files', 'blockset', 'engine', 'mocknet', 'config',
'commands/http', 'cmd/ipfs', 'command', 'conn', 'gc',
'peerstore', 'core', 'coreunix', 'fsrepo', 'core/server',
'boguskey', 'github.com/ipfs/go-libp2p/p2p/host/routed',
'diagnostics', 'namesys', 'fuse/ipfs', 'node', 'secio',
'core/commands', 'supernode', 'mdns', 'path', 'table',
'swarm2', 'peerqueue', 'mount', 'fuse/ipns', 'blockstore',
'github.com/ipfs/go-libp2p/p2p/host/basic', 'lock', 'nat',
'importer', 'corerepo', 'dht.pb', 'pin', 'bitswap_network',
'github.com/ipfs/go-libp2p/p2p/protocol/relay', 'peer',
'transport', 'dht', 'offlinerouting', 'tarfmt', 'eventlog',
'ipfsaddr', 'github.com/ipfs/go-libp2p/p2p/net/swarm/addr',
'bitswap', 'reprovider', 'supernode/proxy', 'crypto', 'tour',
'commands/cli', 'blockservice']}
Returns
-------
dict : List of daemon logging subsystems
"""
return self._client.request('/log/ls', decoder='json', **kwargs)
[docs] def log_tail(self, **kwargs):
r"""Reads log outputs as they are written.
This function returns a reponse object that can be iterated over
by the user. The user should make sure to close the response object
when they are done reading from it.
.. code-block:: python
>>> for item in c.log_tail():
... print(item)
...
{"event":"updatePeer","system":"dht",
"peerID":"QmepsDPxWtLDuKvEoafkpJxGij4kMax11uTH7WnKqD25Dq",
"session":"7770b5e0-25ec-47cd-aa64-f42e65a10023",
"time":"2016-08-22T13:25:27.43353297Z"}
{"event":"handleAddProviderBegin","system":"dht",
"peer":"QmepsDPxWtLDuKvEoafkpJxGij4kMax11uTH7WnKqD25Dq",
"session":"7770b5e0-25ec-47cd-aa64-f42e65a10023",
"time":"2016-08-22T13:25:27.433642581Z"}
{"event":"handleAddProvider","system":"dht","duration":91704,
"key":"QmNT9Tejg6t57Vs8XM2TVJXCwevWiGsZh3kB4HQXUZRK1o",
"peer":"QmepsDPxWtLDuKvEoafkpJxGij4kMax11uTH7WnKqD25Dq",
"session":"7770b5e0-25ec-47cd-aa64-f42e65a10023",
"time":"2016-08-22T13:25:27.433747513Z"}
{"event":"updatePeer","system":"dht",
"peerID":"QmepsDPxWtLDuKvEoafkpJxGij4kMax11uTH7WnKqD25Dq",
"session":"7770b5e0-25ec-47cd-aa64-f42e65a10023",
"time":"2016-08-22T13:25:27.435843012Z"}
…
Returns
-------
iterable
"""
return self._client.request('/log/tail', decoder='json',
stream=True, **kwargs)
[docs] def version(self, **kwargs):
"""Returns the software version of the currently connected node.
.. code-block:: python
>>> c.version()
{'Version': '0.4.3-rc2', 'Repo': '4', 'Commit': '',
'System': 'amd64/linux', 'Golang': 'go1.6.2'}
Returns
-------
dict : Daemon and system version information
"""
return self._client.request('/version', decoder='json', **kwargs)
[docs] def files_cp(self, source, dest, **kwargs):
"""Copies files within the MFS.
Due to the nature of IPFS this will not actually involve any of the
file's content being copied.
.. code-block:: python
>>> c.files_ls("/")
{'Entries': [
{'Size': 0, 'Hash': '', 'Name': 'Software', 'Type': 0},
{'Size': 0, 'Hash': '', 'Name': 'test', 'Type': 0}
]}
>>> c.files_cp("/test", "/bla")
''
>>> c.files_ls("/")
{'Entries': [
{'Size': 0, 'Hash': '', 'Name': 'Software', 'Type': 0},
{'Size': 0, 'Hash': '', 'Name': 'bla', 'Type': 0},
{'Size': 0, 'Hash': '', 'Name': 'test', 'Type': 0}
]}
Parameters
----------
source : str
Filepath within the MFS to copy from
dest : str
Destination filepath with the MFS to which the file will be
copied to
"""
args = (source, dest)
return self._client.request('/files/cp', args, **kwargs)
[docs] def files_ls(self, path, **kwargs):
"""Lists contents of a directory in the MFS.
.. code-block:: python
>>> c.files_ls("/")
{'Entries': [
{'Size': 0, 'Hash': '', 'Name': 'Software', 'Type': 0}
]}
Parameters
----------
path : str
Filepath within the MFS
Returns
-------
dict : Directory entries
"""
args = (path,)
return self._client.request('/files/ls', args,
decoder='json', **kwargs)
[docs] def files_mkdir(self, path, parents=False, **kwargs):
"""Creates a directory within the MFS.
.. code-block:: python
>>> c.files_mkdir("/test")
b''
Parameters
----------
path : str
Filepath within the MFS
parents : bool
Create parent directories as needed and do not raise an exception
if the requested directory already exists
"""
kwargs.setdefault("opts", {"parents": parents})
args = (path,)
return self._client.request('/files/mkdir', args, **kwargs)
[docs] def files_stat(self, path, **kwargs):
"""Returns basic ``stat`` information for an MFS file
(including its hash).
.. code-block:: python
>>> c.files_stat("/test")
{'Hash': 'QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn',
'Size': 0, 'CumulativeSize': 4, 'Type': 'directory', 'Blocks': 0}
Parameters
----------
path : str
Filepath within the MFS
Returns
-------
dict : MFS file information
"""
args = (path,)
return self._client.request('/files/stat', args,
decoder='json', **kwargs)
[docs] def files_rm(self, path, recursive=False, **kwargs):
"""Removes a file from the MFS.
.. code-block:: python
>>> c.files_rm("/bla/file")
b''
Parameters
----------
path : str
Filepath within the MFS
recursive : bool
Recursively remove directories?
"""
kwargs.setdefault("opts", {"recursive": recursive})
args = (path,)
return self._client.request('/files/rm', args, **kwargs)
[docs] def files_read(self, path, offset=0, count=None, **kwargs):
"""Reads a file stored in the MFS.
.. code-block:: python
>>> c.files_read("/bla/file")
b'hi'
Parameters
----------
path : str
Filepath within the MFS
offset : int
Byte offset at which to begin reading at
count : int
Maximum number of bytes to read
Returns
-------
str : MFS file contents
"""
opts = {"offset": offset}
if count is not None:
opts["count"] = count
kwargs.setdefault("opts", opts)
args = (path,)
return self._client.request('/files/read', args, **kwargs)
[docs] def files_write(self, path, file, offset=0, create=False, truncate=False,
count=None, **kwargs):
"""Writes to a mutable file in the MFS.
.. code-block:: python
>>> c.files_write("/test/file", io.BytesIO(b"hi"), create=True)
b''
Parameters
----------
path : str
Filepath within the MFS
file : io.RawIOBase
IO stream object with data that should be written
offset : int
Byte offset at which to begin writing at
create : bool
Create the file if it does not exist
truncate : bool
Truncate the file to size zero before writing
count : int
Maximum number of bytes to read from the source ``file``
"""
opts = {"offset": offset, "create": create, truncate: truncate}
if count is not None:
opts["count"] = count
kwargs.setdefault("opts", opts)
args = (path,)
body, headers = multipart.stream_files(file, self.chunk_size)
return self._client.request('/files/write', args,
data=body, headers=headers, **kwargs)
[docs] def files_mv(self, source, dest, **kwargs):
"""Moves files and directories within the MFS.
.. code-block:: python
>>> c.files_mv("/test/file", "/bla/file")
b''
Parameters
----------
source : str
Existing filepath within the MFS
dest : str
Destination to which the file will be moved in the MFS
"""
args = (source, dest)
return self._client.request('/files/mv', args, **kwargs)
###########
# HELPERS #
###########
@utils.return_field('Hash')
[docs] def add_bytes(self, data, **kwargs):
"""Adds a set of bytes as a file to IPFS.
.. code-block:: python
>>> c.add_bytes(b"Mary had a little lamb")
'QmZfF6C9j4VtoCsTp4KSrhYH47QMd3DNXVZBKaxJdhaPab'
Also accepts and will stream generator objects.
Parameters
----------
data : bytes
Content to be added as a file
Returns
-------
str : Hash of the added IPFS object
"""
body, headers = multipart.stream_bytes(data, self.chunk_size)
return self._client.request('/add', decoder='json',
data=body, headers=headers, **kwargs)
@utils.return_field('Hash')
[docs] def add_str(self, string, **kwargs):
"""Adds a Python string as a file to IPFS.
.. code-block:: python
>>> c.add_str(u"Mary had a little lamb")
'QmZfF6C9j4VtoCsTp4KSrhYH47QMd3DNXVZBKaxJdhaPab'
Also accepts and will stream generator objects.
Parameters
----------
string : str
Content to be added as a file
Returns
-------
str : Hash of the added IPFS object
"""
body, headers = multipart.stream_text(string, self.chunk_size)
return self._client.request('/add', decoder='json',
data=body, headers=headers, **kwargs)
[docs] def add_json(self, json_obj, **kwargs):
"""Adds a json-serializable Python dict as a json file to IPFS.
.. code-block:: python
>>> c.add_json({'one': 1, 'two': 2, 'three': 3})
'QmVz9g7m5u3oHiNKHj2CJX1dbG1gtismRS3g9NaPBBLbob'
Parameters
----------
json_obj : dict
A json-serializable Python dictionary
Returns
-------
str : Hash of the added IPFS object
"""
return self.add_bytes(encoding.Json().encode(json_obj), **kwargs)
[docs] def get_json(self, multihash, **kwargs):
"""Loads a json object from IPFS.
.. code-block:: python
>>> c.get_json('QmVz9g7m5u3oHiNKHj2CJX1dbG1gtismRS3g9NaPBBLbob')
{'one': 1, 'two': 2, 'three': 3}
Parameters
----------
multihash : str
Multihash of the IPFS object to load
Returns
-------
object : Deserialized IPFS JSON object value
"""
return self.cat(multihash, decoder='json', **kwargs)
[docs] def add_pyobj(self, py_obj, **kwargs):
"""Adds a picklable Python object as a file to IPFS.
.. code-block:: python
>>> c.add_pyobj([0, 1.0, 2j, '3', 4e5])
'QmWgXZSUTNNDD8LdkdJ8UXSn55KfFnNvTP1r7SyaQd74Ji'
Parameters
----------
py_obj : object
A picklable Python object
Returns
-------
str : Hash of the added IPFS object
"""
return self.add_bytes(encoding.Pickle().encode(py_obj), **kwargs)
[docs] def get_pyobj(self, multihash, **kwargs):
"""Loads a pickled Python object from IPFS.
.. caution::
The pickle module is not intended to be secure against erroneous or
maliciously constructed data. Never unpickle data received from an
untrusted or unauthenticated source.
See the :mod:`pickle` module documentation for more information.
.. code-block:: python
>>> c.get_pyobj('QmWgXZSUTNNDD8LdkdJ8UXSn55KfFnNvTP1r7SyaQd74Ji')
[0, 1.0, 2j, '3', 400000.0]
Parameters
----------
multihash : str
Multihash of the IPFS object to load
Returns
-------
object : Deserialized IPFS Python object
"""
return self.cat(multihash, decoder='pickle', **kwargs)