Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 6 additions & 17 deletions coinaddrvalidator/currency.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@
"""

import attr
from zope.interface import implementer, provider
from typing import Dict, Any, Optional

from .interfaces import ICurrency, INamedInstanceContainer
from .base import NamedInstanceContainerBase


@provider(INamedInstanceContainer)
class Currencies(metaclass=NamedInstanceContainerBase):
"""Container for all currencies."""

@classmethod
def get(cls, name, default=None):
def get(cls, name: str, default: Any = None) -> Any:
"""Return currency object with matching name or ticker."""
for inst in cls.instances.values():
if name in (inst.name, inst.ticker):
Expand All @@ -29,36 +28,26 @@ def get(cls, name, default=None):
class CurrencyMeta(type):
"""Register currency classes on Currencies.currencies."""

def __call__(cls, *args, **kwargs):
def __call__(cls, *args: Any, **kwargs: Any) -> Any:
inst = super(CurrencyMeta, cls).__call__(*args, **kwargs)
Currencies[inst.name] = inst
return inst


@implementer(ICurrency)
@attr.s(frozen=True, slots=True, cmp=False)
class Currency(metaclass=CurrencyMeta):
"""An immutable representation of a cryptocurrency specification."""

name = attr.ib(
type=str,
validator=attr.validators.instance_of(str))
ticker = attr.ib(
type=str,
validator=attr.validators.instance_of(str))
validator = attr.ib(
type='str',
validator=attr.validators.instance_of(str))
name = attr.ib(validator=attr.validators.instance_of(str))
ticker = attr.ib(validator=attr.validators.instance_of(str))
validator = attr.ib(validator=attr.validators.instance_of(str))
networks = attr.ib(
type=dict,
validator=attr.validators.optional(attr.validators.instance_of(dict)),
default=attr.Factory(dict))
address_types = attr.ib(
type=dict,
validator=attr.validators.optional(attr.validators.instance_of(dict)),
default=attr.Factory(dict))
charset = attr.ib(
type=bytes,
validator=attr.validators.optional(attr.validators.instance_of(bytes)),
default=None)

Expand Down
212 changes: 164 additions & 48 deletions coinaddrvalidator/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,101 +5,217 @@
:mod:`coinaddr.interfaces`
~~~~~~~~~~~~~~~~~~~~~~~~

Various zope compatible interfaces for the coinaddr package.
Various interfaces for the coinaddr package.
"""

from zope.interface import Interface, Attribute
from abc import ABC, abstractmethod
from typing import Any, Dict, Iterator, Optional


class INamedInstanceContainer(Interface):
class INamedInstanceContainer(ABC):
"""Contains all currencies instantiated."""

instances = Attribute('Mapping of instance.name -> instance')
@property
@abstractmethod
def instances(self) -> Dict[str, Any]:
"""Mapping of instance.name -> instance"""
pass

def __getitem__(name):
@abstractmethod
def __getitem__(self, name: str) -> Any:
"""Return the named instance"""
pass

def __setitem__(name, obj):
@abstractmethod
def __setitem__(self, name: str, obj: Any) -> None:
"""Add the named instance to the mapping of instances"""
pass

def __delitem__(name, obj):
"""Add the named instance to the mapping of instances"""
@abstractmethod
def __delitem__(self, name: str) -> None:
"""Remove the named instance from the mapping of instances"""
pass

def __contains__(name):
@abstractmethod
def __contains__(self, name: str) -> bool:
"""Return true if we contain the named instance"""
pass

def __iter__():
@abstractmethod
def __iter__(self) -> Iterator[Any]:
"""Return an iterable, iterating all instances"""
pass

def get(name, default=None):
@abstractmethod
def get(self, name: str, default: Any = None) -> Any:
"""Return the named instance if we contain it, else default"""
pass


class INamedSubclassContainer(Interface):
class INamedSubclassContainer(ABC):
"""Contains a weakvaluedict of subclasses."""

subclasses = Attribute('Mapping of subclass.name -> subclass')
@property
@abstractmethod
def subclasses(self) -> Dict[str, Any]:
"""Mapping of subclass.name -> subclass"""
pass

def __getitem__(name):
@abstractmethod
def __getitem__(self, name: str) -> Any:
"""Return the named subclass"""
pass

def __setitem__(name, obj):
@abstractmethod
def __setitem__(self, name: str, obj: Any) -> None:
"""Add the named subclass to the mapping of subclasses"""
pass

def __delitem__(name, obj):
"""Add the named subclass to the mapping of subclasses"""
@abstractmethod
def __delitem__(self, name: str) -> None:
"""Remove the named subclass from the mapping of subclasses"""
pass

def __contains__(name):
@abstractmethod
def __contains__(self, name: str) -> bool:
"""Return true if we contain the named subclass"""
pass

def __iter__():
@abstractmethod
def __iter__(self) -> Iterator[Any]:
"""Return an iterable, iterating all subclasses"""
pass

def get(name, default=None):
@abstractmethod
def get(self, name: str, default: Any = None) -> Any:
"""Return the named subclass if we contain it, else default"""
pass


class ICurrency(Interface):
class ICurrency(ABC):
"""A cryptocurrency address specification."""

name = Attribute('Name of currency')
ticker = Attribute('Ticker symbol for currency')
validator = Attribute('Validator name for validation')
networks = Attribute('The networks and version bytes for those networks')
charset = Attribute('For base58Check based currencies, custom charset.')


class IValidator(Interface):
@property
@abstractmethod
def name(self) -> str:
"""Name of currency"""
pass

@property
@abstractmethod
def ticker(self) -> str:
"""Ticker symbol for currency"""
pass

@property
@abstractmethod
def validator(self) -> str:
"""Validator name for validation"""
pass

@property
@abstractmethod
def networks(self) -> Dict[str, Any]:
"""The networks and version bytes for those networks"""
pass

@property
@abstractmethod
def charset(self) -> Optional[bytes]:
"""For base58Check based currencies, custom charset."""
pass


class IValidator(ABC):
"""A cryptocurrency address validator."""

name = Attribute('Name of validator')
network = Attribute('Network name of address being validated')
@property
@abstractmethod
def name(self) -> str:
"""Name of validator"""
pass

@property
@abstractmethod
def network(self) -> str:
"""Network name of address being validated"""
pass

def validate():
@abstractmethod
def validate(self) -> bool:
"""Validate the address type, True if valid, else False."""
pass


class IValidationRequest(Interface):
class IValidationRequest(ABC):
"""Contains the data and helpers for a given validation request."""

currency = Attribute('The currency name or ticker being validated')
address = Attribute('The address to be validated')
extras = Attribute('Any extra attributes to be passed to decoder, etc')
networks = Attribute(
'Concatenated list of all network versions for currency')

def execute():
@property
@abstractmethod
def currency(self) -> str:
"""The currency name or ticker being validated"""
pass

@property
@abstractmethod
def address(self) -> str:
"""The address to be validated"""
pass

@property
@abstractmethod
def extras(self) -> Dict[str, Any]:
"""Any extra attributes to be passed to decoder, etc"""
pass

@property
@abstractmethod
def networks(self) -> str:
"""Concatenated list of all network versions for currency"""
pass

@abstractmethod
def execute(self) -> 'IValidationResult':
"""Executes the request and returns a ValidationResult object"""
pass


class IValidationResult(Interface):
class IValidationResult(ABC):
"""Represents all data for a validation result."""

name = Attribute('Name of currency for address validated')
ticker = Attribute('Ticker of currency for address validated')
address = Attribute('The address that was validated')
valid = Attribute('Boolean representing whether the address is valid')
network = Attribute(
'Name of network the address belongs to if applicable')
is_extended = Attribute('boolean representing whether the address is extended key or not')
@property
@abstractmethod
def name(self) -> str:
"""Name of currency for address validated"""
pass

@property
@abstractmethod
def ticker(self) -> str:
"""Ticker of currency for address validated"""
pass

@property
@abstractmethod
def address(self) -> str:
"""The address that was validated"""
pass

@property
@abstractmethod
def valid(self) -> bool:
"""Boolean representing whether the address is valid"""
pass

@property
@abstractmethod
def network(self) -> Optional[str]:
"""Name of network the address belongs to if applicable"""
pass

@property
@abstractmethod
def is_extended(self) -> bool:
"""boolean representing whether the address is extended key or not"""
pass

Loading