diff --git a/.travis.yml b/.travis.yml index 2701940..029d833 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ -dist: trusty language: python python: - '2.7' - '3.5' - '3.6' + - '3.7' install: - pip install . - pip install docutils pygments # Used to check package metadata. @@ -12,7 +12,7 @@ script: - nosetests deploy: on: - python: '3.6' + python: '3.7' tags: true provider: pypi distributions: 'bdist_wheel sdist' diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 3570b2d..52b8b9b 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -18,7 +18,7 @@ There are lots of ways to get involved with PyOTA. Many of them don't require w - Improving Documentation - Writing Tutorials - Reporting Bugs -- Helping Users on the ``#iota-libs-pyota`` Channel on `Slack`_ +- Helping Users on the ``#python`` Channel on `Discord`_ - Fixing Bugs and Implementing New Features - Writing Unit and Functional Tests @@ -26,10 +26,10 @@ A Few Things that We Can't Accept --------------------------------- We're pretty open about how people contribute to PyOTA, but there are a few things that we can't accept: -- Please do not post support requests here. Use the ``#iota-libs-pyota`` channel on `Slack`_ or post in the `forum`_ to ask for help. +- Please do not post support requests here. Use the ``#python`` channel on `Discord`_ - Please do not propose new API methods here. There are multiple IOTA API libraries out there, and they must all have the same functionality. - - That said, if you have an idea for a new API method, please share it on the ``#developers`` channel in `Slack`_ so that IOTA Foundation members can evaluate it! + - That said, if you have an idea for a new API method, please share it on the ``#developers`` channel in `Discord`_ so that IOTA Foundation members can evaluate it! Need Some Inspiration? @@ -38,7 +38,7 @@ If you would like to help out but don't know how to get started, here are some places you can look for inspiration: - Look for issues marked `help wanted`_ in the `PyOTA Bug Tracker`_ -- Introduce yourself in the `#iota-libs-pyota` channel in `Slack`_ and watch for questions or issues that you can help with. +- Introduce yourself in the `#python` channel in `Discord`_ and watch for questions or issues that you can help with. - Browse existing `tutorials`_ for other programming languages and create Python versions. Is This Your First Contribution? @@ -57,12 +57,12 @@ Instructions 1. Make sure it really is a PyOTA bug. - Check the traceback, and see if you can narrow down the cause of the bug. - - If the error is not directly caused by PyOTA, or if you are unable to figure out what is causing the problem, we're still here for for you! Post in the ``#iota-libs-pyota`` channel in `Slack`_ for assistance. + - If the error is not directly caused by PyOTA, or if you are unable to figure out what is causing the problem, we're still here for for you! Post in the ``#python`` channel in `Discord`_ for assistance. 2. Is it safe to publish details about this bug publicly? - If the bug is security-related (e.g., could compromise a user's seed if exploited), or if it requires sensitive information in order to reproduce (e.g., the private key for an address), please do not post in in the PyOTA Bug Tracker! - - To report security-related bugs, please contact ``@phx`` directly in `Slack`_. + - To report security-related bugs, please contact ``@phx`` directly in `Discord`_. 3. Is this a known issue? @@ -124,7 +124,7 @@ PyOTA is a critical component for many applications, and as such its code must b This is a big list, but don't let it intimidate you! Many of these are "common sense" things that you probably do already, but we have to list them here anyway, just so that there's no confusion. -If you have any questions, please feel free to post in the ``#iota-libs-pyota`` channel in `Slack`_! +If you have any questions, please feel free to post in the ``#python`` channel in `Discord`_! - Please create Pull Requests against the ``develop`` branch. - Please limit each Pull Request to a single bugfix/enhancement. @@ -158,11 +158,10 @@ When you submit a Pull Request, here is what you can expect from the individual .. _come on over and help us out!: https://github.com/iotaledger/iota.lib.py/issues/145 .. _email you: https://help.github.com/articles/managing-notification-delivery-methods/ -.. _forum: https://forum.iota.org .. _help wanted: https://github.com/iotaledger/iota.lib.py/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22 .. _how to contribute to open source: https://opensource.guide/how-to-contribute/ .. _notifications: https://github.com/notifications .. _pep-8: https://www.python.org/dev/peps/pep-0008/ .. _pyota bug tracker: https://github.com/iotaledger/iota.lib.py/issues -.. _slack: https://slack.iota.org -.. _tutorials: https://learn.iota.org/tutorials +.. _discord: https://discord.iota.org +.. _tutorials: https://docs.iota.org diff --git a/README.rst b/README.rst index a7b8dc0..2cb91ec 100644 --- a/README.rst +++ b/README.rst @@ -26,7 +26,7 @@ If you encounter any issues while using PyOTA, please report them using the ============ Dependencies ============ -PyOTA is compatible with Python 3.6, 3.5 and 2.7. +PyOTA is compatible with Python 3.7, 3.6, 3.5 and 2.7 ============ Installation diff --git a/docs/api.rst b/docs/api.rst index f0af315..1a9c176 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -204,6 +204,34 @@ This method returns a ``dict`` with the following items: - ``bundles: List[Bundle]``: Matching bundles, sorted by tail transaction timestamp. +``is_reattachable`` +------------------- + +This API function helps you to determine whether you should replay a +transaction or make a new one (either with the same input, or a +different one). + +This method takes one or more input addresses (i.e. from spent +transactions) as input and then checks whether any transactions with a +value transferred are confirmed. + +If yes, it means that this input address has already been successfully +used in a different transaction, and as such you should no longer replay +the transaction. + +Parameters +~~~~~~~~~~ + +- ``address: Iterable[Address]``: List of addresses. + +Return +~~~~~~ + +This method returns a ``dict`` with the following items: + +- ``reattachable: List[Bool]``: Always a list, even if only one address + was queried. + ``prepare_transfer`` -------------------- @@ -232,6 +260,24 @@ This method returns a ``dict`` with the following items: - ``trytes: List[TransactionTrytes]``: Raw trytes for the transactions in the bundle, ready to be provided to ``send_trytes``. +``promote_transaction`` +----------------------- + +Promotes a transaction by adding spam on top of it. + +- ``transaction: TransactionHash``: Transaction hash. Must be a tail. +- ``depth: int``: Depth at which to attach the bundle. +- ``min_weight_magnitude: Optional[int]``: Min weight magnitude, used + by the node to calibrate Proof of Work. +- If not provided, a default value will be used. + +Return +~~~~~~ + +This method returns a ``dict`` with the following items: + +- ``bundle: Bundle``: The newly-published bundle. + ``replay_bundle`` ----------------- diff --git a/iota/adapter/__init__.py b/iota/adapter/__init__.py index 13ce691..0259be2 100644 --- a/iota/adapter/__init__.py +++ b/iota/adapter/__init__.py @@ -12,7 +12,7 @@ from requests import Response, auth, codes, request from six import PY2, binary_type, iteritems, moves as compat, text_type, \ - with_metaclass + add_metaclass from iota.exceptions import with_context from iota.json import JsonEncoder @@ -139,7 +139,8 @@ def configure(cls, parsed): return cls(parsed) -class BaseAdapter(with_metaclass(AdapterMeta)): +@add_metaclass(AdapterMeta) +class BaseAdapter(object): """ Interface for IOTA API adapters. diff --git a/iota/adapter/wrappers.py b/iota/adapter/wrappers.py index eba9e63..a717016 100644 --- a/iota/adapter/wrappers.py +++ b/iota/adapter/wrappers.py @@ -5,7 +5,7 @@ from abc import ABCMeta, abstractmethod as abstract_method from typing import Dict, Text -from six import with_metaclass +from six import add_metaclass from iota.adapter import AdapterSpec, BaseAdapter, resolve_adapter @@ -14,7 +14,8 @@ ] -class BaseWrapper(with_metaclass(ABCMeta, BaseAdapter)): +@add_metaclass(ABCMeta) +class BaseWrapper(BaseAdapter): """ Base functionality for "adapter wrappers", used to extend the functionality of IOTA adapters. diff --git a/iota/api.py b/iota/api.py index f6ce7d7..761f50f 100644 --- a/iota/api.py +++ b/iota/api.py @@ -4,7 +4,7 @@ from typing import Dict, Iterable, Optional, Text -from six import with_metaclass +from six import add_metaclass from iota import AdapterSpec, Address, BundleHash, ProposedTransaction, Tag, \ TransactionHash, TransactionTrytes, TryteString, TrytesCompatible @@ -53,7 +53,8 @@ def __init__(cls, name, bases=None, attrs=None): cls.commands = commands -class StrictIota(with_metaclass(ApiMeta)): +@add_metaclass(ApiMeta) +class StrictIota(object): """ API to send HTTP requests for communicating with an IOTA node. @@ -907,6 +908,19 @@ def promote_transaction( """ Promotes a transaction by adding spam on top of it. + :param transaction: + Transaction hash. Must be a tail transaction. + + :param depth: + Depth at which to attach the bundle. + Defaults to 3. + + :param min_weight_magnitude: + Min weight magnitude, used by the node to calibrate Proof of + Work. + + If not provided, a default value will be used. + :return: Dict with the following structure:: diff --git a/iota/bin/__init__.py b/iota/bin/__init__.py index d597daa..eb97e20 100644 --- a/iota/bin/__init__.py +++ b/iota/bin/__init__.py @@ -10,7 +10,7 @@ from sys import exit from typing import Any, Optional, Text -from six import text_type, with_metaclass +from six import text_type, add_metaclass from iota import Iota, __version__ from iota.crypto.types import Seed @@ -20,7 +20,8 @@ ] -class IotaCommandLineApp(with_metaclass(ABCMeta)): +@add_metaclass(ABCMeta) +class IotaCommandLineApp(object): """ Base functionality for a PyOTA-powered command-line application. """ diff --git a/iota/commands/__init__.py b/iota/commands/__init__.py index c8b965b..2379abd 100644 --- a/iota/commands/__init__.py +++ b/iota/commands/__init__.py @@ -11,7 +11,7 @@ from typing import Any, Dict, Mapping, Optional, Text, Union import filters as f -from six import string_types, with_metaclass +import six from iota.adapter import BaseAdapter from iota.exceptions import with_context @@ -48,7 +48,7 @@ def discover_commands(package, recursively=True): command name (note: not class name). """ # http://stackoverflow.com/a/25562415/ - if isinstance(package, string_types): + if isinstance(package, six.string_types): package = import_module(package) # type: ModuleType commands = {} @@ -87,8 +87,8 @@ def __init__(cls, what, bases=None, dict=None): if command: command_registry[command] = cls - -class BaseCommand(with_metaclass(CommandMeta)): +@six.add_metaclass(CommandMeta) +class BaseCommand(object): """ An API command ready to send to the node. """ @@ -260,7 +260,8 @@ def _apply_none(self): return self._apply({}) -class FilterCommand(with_metaclass(ABCMeta, BaseCommand)): +@six.add_metaclass(ABCMeta) +class FilterCommand(BaseCommand): """ Uses filters to manipulate request/response values. """ diff --git a/iota/json.py b/iota/json.py index 61e6c7f..f5ef54d 100644 --- a/iota/json.py +++ b/iota/json.py @@ -6,10 +6,11 @@ from json.encoder import JSONEncoder as BaseJsonEncoder from typing import Iterable, Mapping -from six import with_metaclass +from six import add_metaclass -class JsonSerializable(with_metaclass(ABCMeta)): +@add_metaclass(ABCMeta) +class JsonSerializable(object): """ Interface for classes that can be safely converted to JSON. """ diff --git a/setup.py b/setup.py index 8559bfc..4a0aac6 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ name='PyOTA', description='IOTA API library for Python', url='https://github.com/iotaledger/iota.lib.py', - version='2.0.7', + version='2.0.8', long_description=long_description, @@ -57,8 +57,12 @@ ], }, + # filters is no longer maintained and does not support Python 3.7 + # phx-filters is a fork that supports 3.7 and 3.8 but not 2.7 + install_requires=[ - 'filters', + 'filters; python_version < "3.5"', + 'phx-filters; python_version >= "3.5"', 'pysha3', # ``security`` extra wasn't introduced until 2.4.1 @@ -90,6 +94,7 @@ 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Topic :: Software Development :: Libraries :: Python Modules', ], diff --git a/test/api_test.py b/test/api_test.py index 89c4fba..2da3eab 100644 --- a/test/api_test.py +++ b/test/api_test.py @@ -5,7 +5,7 @@ from abc import ABCMeta from unittest import TestCase -from six import with_metaclass +from six import add_metaclass from iota import InvalidCommand, StrictIota from iota.adapter import MockAdapter @@ -150,5 +150,6 @@ class definition raises an exception. # This statement will raise an exception if the regression is # present; no assertions necessary. # noinspection PyUnusedLocal - class CustomClient(with_metaclass(ABCMeta)): + @add_metaclass(ABCMeta) + class CustomClient(object): client = StrictIota(MockAdapter()) diff --git a/tox.ini b/tox.ini index 2f081ee..080f499 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ # and then run "tox" from this directory. [tox] -envlist = py27, py35, py36 +envlist = py27, py35, py36, py37 [testenv] commands = nosetests