Commit e5f3c4dd authored by Vincent Texier's avatar Vincent Texier

issue #52 Fix circular import migrating BlockUID class in new module (break BC)

Fix mypy check
Fix tests
parent bb07b1f7
......@@ -33,3 +33,4 @@ WS2PID_REGEX = "[0-9a-f]{8}"
WS2P_PRIVATE_PREFIX_REGEX = "O[CT][SAM]"
WS2P_PUBLIC_PREFIX_REGEX = "I[CT]"
WS2P_HEAD_REGEX = "HEAD:?(?:[0-9]+)?"
EMPTY_HASH = "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"
from .block import Block, BlockUID, block_uid
from .block import Block
from .block_uid import BlockUID, block_uid
from .certification import Identity, Certification, Revocation
from .membership import Membership
from .transaction import SimpleTransaction, Transaction, InputSource, OutputSource, \
SIGParameter, Unlock, UnlockParameter
SIGParameter, Unlock, UnlockParameter
from .document import Document, MalformedDocumentError
from .crc_pubkey import CRCPubkey
import base64
import hashlib
import re
from typing import Union, TypeVar, Type, Optional, List, Sequence
from typing import TypeVar, Type, Optional, List, Sequence
from .block_uid import BlockUID
from .certification import Identity, Certification, Revocation
from .document import Document, MalformedDocumentError
from .membership import Membership
from .transaction import Transaction
from ..constants import PUBKEY_REGEX, BLOCK_ID_REGEX, BLOCK_HASH_REGEX
# required to type hint cls in classmethod
BlockUIDType = TypeVar('BlockUIDType', bound='BlockUID')
class BlockUID:
"""
A simple block id
"""
re_block_uid = re.compile("({block_id_regex})-({block_hash_regex})".format(block_id_regex=BLOCK_ID_REGEX,
block_hash_regex=BLOCK_HASH_REGEX))
re_hash = re.compile("({block_hash_regex})".format(block_hash_regex=BLOCK_HASH_REGEX))
def __init__(self, number: int, sha_hash: str) -> None:
assert (type(number) is int)
assert (BlockUID.re_hash.match(sha_hash) is not None)
self.number = number
self.sha_hash = sha_hash
@classmethod
def empty(cls: Type[BlockUIDType]) -> BlockUIDType:
return cls(0, Block.Empty_Hash)
@classmethod
def from_str(cls: Type[BlockUIDType], blockid: str) -> BlockUIDType:
"""
:param blockid: The block id
"""
data = BlockUID.re_block_uid.match(blockid)
if data is None:
raise MalformedDocumentError("BlockUID")
try:
number = int(data.group(1))
except AttributeError:
raise MalformedDocumentError("BlockUID")
try:
sha_hash = data.group(2)
except AttributeError:
raise MalformedDocumentError("BlockHash")
return cls(number, sha_hash)
def __str__(self) -> str:
return "{0}-{1}".format(self.number, self.sha_hash)
def __eq__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return self.number == other.number and self.sha_hash == other.sha_hash
def __lt__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return self.number < other.number
def __gt__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return self.number > other.number
def __le__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return self.number <= other.number
def __ge__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return self.number >= other.number
def __hash__(self) -> int:
return hash((self.number, self.sha_hash))
def __bool__(self) -> bool:
return self != BlockUID.empty()
def block_uid(value: Union[str, BlockUID, None]) -> BlockUID:
"""
Convert value to BlockUID instance
:param value: Value to convert
:return:
"""
if isinstance(value, BlockUID):
return value
elif isinstance(value, str):
return BlockUID.from_str(value)
elif value is None:
return BlockUID.empty()
else:
raise TypeError("Cannot convert {0} to BlockUID".format(type(value)))
from ..constants import PUBKEY_REGEX, BLOCK_HASH_REGEX
# required to type hint cls in classmethod
......@@ -212,8 +119,6 @@ The class Block handles Block documents.
}
}
Empty_Hash = "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"
def __init__(self,
version: int,
currency: str,
......
import re
from typing import Union, TypeVar, Type
from .document import MalformedDocumentError
from ..constants import EMPTY_HASH, BLOCK_ID_REGEX, BLOCK_HASH_REGEX
# required to type hint cls in classmethod
BlockUIDType = TypeVar('BlockUIDType', bound='BlockUID')
class BlockUID:
"""
A simple block id
"""
re_block_uid = re.compile("({block_id_regex})-({block_hash_regex})".format(block_id_regex=BLOCK_ID_REGEX,
block_hash_regex=BLOCK_HASH_REGEX))
re_hash = re.compile("({block_hash_regex})".format(block_hash_regex=BLOCK_HASH_REGEX))
def __init__(self, number: int, sha_hash: str) -> None:
assert (type(number) is int)
assert (BlockUID.re_hash.match(sha_hash) is not None)
self.number = number
self.sha_hash = sha_hash
@classmethod
def empty(cls: Type[BlockUIDType]) -> BlockUIDType:
return cls(0, EMPTY_HASH)
@classmethod
def from_str(cls: Type[BlockUIDType], blockid: str) -> BlockUIDType:
"""
:param blockid: The block id
"""
data = BlockUID.re_block_uid.match(blockid)
if data is None:
raise MalformedDocumentError("BlockUID")
try:
number = int(data.group(1))
except AttributeError:
raise MalformedDocumentError("BlockUID")
try:
sha_hash = data.group(2)
except AttributeError:
raise MalformedDocumentError("BlockHash")
return cls(number, sha_hash)
def __str__(self) -> str:
return "{0}-{1}".format(self.number, self.sha_hash)
def __eq__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return self.number == other.number and self.sha_hash == other.sha_hash
def __lt__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return self.number < other.number
def __gt__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return self.number > other.number
def __le__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return self.number <= other.number
def __ge__(self, other: object) -> bool:
if not isinstance(other, BlockUID):
return False
return self.number >= other.number
def __hash__(self) -> int:
return hash((self.number, self.sha_hash))
def __bool__(self) -> bool:
return self != BlockUID.empty()
def block_uid(value: Union[str, BlockUID, None]) -> BlockUID:
"""
Convert value to BlockUID instance
:param value: Value to convert
:return:
"""
if isinstance(value, BlockUID):
return value
elif isinstance(value, str):
return BlockUID.from_str(value)
elif value is None:
return BlockUID.empty()
else:
raise TypeError("Cannot convert {0} to BlockUID".format(type(value)))
import base64
import logging
import re
from typing import Optional, TypeVar, Type, List
from duniterpy.documents import BlockUID
from typing import Optional, TypeVar, Type
from .block_uid import BlockUID
from ..constants import PUBKEY_REGEX, SIGNATURE_REGEX, BLOCK_ID_REGEX, BLOCK_UID_REGEX, UID_REGEX
from .document import Document, MalformedDocumentError
......@@ -63,8 +62,6 @@ class Identity(Document):
:param inline: Inline string of the Identity
:return:
"""
from .block import BlockUID
selfcert_data = Identity.re_inline.match(inline)
if selfcert_data is None:
raise MalformedDocumentError("Inline self certification")
......@@ -82,8 +79,6 @@ class Identity(Document):
:param signed_raw: Signed raw document
:return:
"""
from .block import BlockUID
n = 0
lines = signed_raw.splitlines(True)
......@@ -141,6 +136,8 @@ Timestamp: {timestamp}
# required to type hint cls in classmethod
CertificationType = TypeVar('CertificationType', bound='Certification')
# todo: certification document should be created with the certified Identity document in arguments
class Certification(Document):
"""
......@@ -197,8 +194,6 @@ class Certification(Document):
:param signed_raw: Signed raw document
:return:
"""
from .block import BlockUID
n = 0
lines = signed_raw.splitlines(True)
......@@ -245,7 +240,6 @@ class Certification(Document):
:param inline: Inline document
:return:
"""
from .block import BlockUID
cert_data = Certification.re_inline.match(inline)
if cert_data is None:
raise MalformedDocumentError("Certification ({0})".format(inline))
......@@ -325,6 +319,8 @@ CertTimestamp: {timestamp}
# required to type hint cls in classmethod
RevocationType = TypeVar('RevocationType', bound='Revocation')
# todo: Revocation document should be created with the revoked Identity document in arguments
class Revocation(Document):
"""
......
......@@ -4,7 +4,7 @@ Created on 2 déc. 2014
@author: inso
"""
import re
from .block_uid import BlockUID
from .document import Document, MalformedDocumentError
from ..constants import BLOCK_UID_REGEX, SIGNATURE_REGEX, PUBKEY_REGEX
......@@ -69,7 +69,6 @@ class Membership(Document):
@classmethod
def from_inline(cls, version, currency, membership_type, inline):
from .block import BlockUID
data = Membership.re_inline.match(inline)
if data is None:
raise MalformedDocumentError("Inline membership ({0})".format(inline))
......@@ -82,7 +81,6 @@ class Membership(Document):
@classmethod
def from_signed_raw(cls, signed_raw):
from .block import BlockUID
lines = signed_raw.splitlines(True)
n = 0
......
......@@ -2,7 +2,7 @@ import re
from duniterpy.api.endpoint import endpoint
from .document import Document
from . import BlockUID
from .block_uid import BlockUID
from ..constants import BLOCK_HASH_REGEX, PUBKEY_REGEX
......
import re
import pypeg2
from .block_uid import BlockUID
from .document import Document, MalformedDocumentError
from ..constants import PUBKEY_REGEX, TRANSACTION_HASH_REGEX, BLOCK_ID_REGEX, BLOCK_UID_REGEX
from ..grammars import output
......@@ -165,7 +165,6 @@ Comment: {comment}
@classmethod
def from_compact(cls, currency, compact):
from .block import BlockUID
lines = compact.splitlines(True)
n = 0
......@@ -231,7 +230,6 @@ Comment: {comment}
@classmethod
def from_signed_raw(cls, raw):
from .block import BlockUID
lines = raw.splitlines(True)
n = 0
......
......@@ -2,7 +2,7 @@ import re
import attr
from ..block import BlockUID
from ..block_uid import BlockUID
from ..document import MalformedDocumentError
from ...constants import WS2P_PUBLIC_PREFIX_REGEX, WS2P_PRIVATE_PREFIX_REGEX, WS2P_HEAD_REGEX, \
PUBKEY_REGEX, SIGNATURE_REGEX, WS2PID_REGEX, BLOCK_UID_REGEX
......
......@@ -5,7 +5,8 @@ Created on 12 déc. 2014
"""
import unittest
from duniterpy.documents.block import Block, BlockUID, block_uid
from duniterpy.documents.block import Block
from duniterpy.documents.block_uid import BlockUID, block_uid
raw_block = """Version: 2
Type: Block
......
......@@ -6,7 +6,8 @@ Created on 6 déc. 2014
import unittest
from duniterpy.documents.certification import Identity, Certification, Revocation
from duniterpy.documents import Block, BlockUID
from duniterpy.documents.block import Block, BlockUID
from duniterpy.constants import EMPTY_HASH
selfcert_inlines = ["HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:\
h/H8tDIEbfA4yxMQcvfOXVDQhi1sUa9qYtPKrM59Bulv97ouwbAvAsEkC1Uyit1IOpeAV+CQQs4IaAyjE8F1Cw==:\
......@@ -73,7 +74,7 @@ J3G9oM5AKYZNLAB5Wx499w61NuUoS57JVccTShUbGpCMjCqj9yXXqNq7dyZpDWA6BxipsiaMZhujMeBf
self.assertEqual(cert.pubkey_from, "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU")
self.assertEqual(cert.pubkey_to, "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk")
self.assertEqual(cert.timestamp.number, 0)
self.assertEqual(cert.timestamp.sha_hash, Block.Empty_Hash)
self.assertEqual(cert.timestamp.sha_hash, EMPTY_HASH)
self.assertEqual(cert.signatures[0], "TgmDuMxZdyutroj9jiLJA8tQp/389JIzDKuxW5+h7GIfjDu1ZbwI7HNm5rlUDhR2KreaV/QJjEaItT4Cf75rCQ==")
cert = Certification.from_inline(version, currency, "DB30D958EE5CB75186972286ED3F4686B8A1C2CD", cert_inlines[1])
......
......@@ -47,7 +47,7 @@ class Test_Membership(unittest.TestCase):
def test_fromraw_toraw(self):
membership = Membership.from_signed_raw(membership_raw)
rendered_membership = membership.signed_raw_for_certified()
rendered_membership = membership.signed_raw()
from_rendered_membership = Membership.from_signed_raw(rendered_membership)
self.assertEqual(from_rendered_membership.issuer, "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk")
self.assertEqual(from_rendered_membership.membership_ts.number, 0)
......
......@@ -59,7 +59,7 @@ class TestPeer(unittest.TestCase):
def test_fromraw_toraw(self):
peer = Peer.from_signed_raw(rawpeer)
rendered_peer = peer.signed_raw_for_certified()
rendered_peer = peer.signed_raw()
from_rendered_peer = Peer.from_signed_raw(rendered_peer)
self.assertEqual(from_rendered_peer.currency, "beta_brousouf")
......@@ -87,9 +87,9 @@ class TestPeer(unittest.TestCase):
self.assertEqual(from_rendered_peer.signatures[0],
"dkaXIiCYUJtCg8Feh/BKvPYf4uFH9CJ/zY6J4MlA9BsjmcMe4YAblvNt/gJy31b1aGq3ue3h14mLMCu84rraDg==")
self.assertEqual(rawpeer, from_rendered_peer.signed_raw_for_certified())
self.assertEqual(rawpeer, from_rendered_peer.signed_raw())
def test_incorrect(self):
peer = Peer.from_signed_raw(test_weird_ipv6_peer)
rendered_peer = peer.signed_raw_for_certified()
rendered_peer = peer.signed_raw()
Peer.from_signed_raw(rendered_peer)
......@@ -299,7 +299,7 @@ class Test_Transaction(unittest.TestCase):
def test_fromraw_toraw(self):
tx = Transaction.from_signed_raw(tx_raw)
rendered_tx = tx.signed_raw_for_certified()
rendered_tx = tx.signed_raw()
from_rendered_tx = Transaction.from_signed_raw(rendered_tx)
self.assertEqual(tx.version, 2)
......@@ -366,7 +366,7 @@ class Test_Transaction(unittest.TestCase):
def test_fromraw_toraw_v3(self):
tx = Transaction.from_signed_raw(tx_raw_v3)
rendered_tx = tx.signed_raw_for_certified()
rendered_tx = tx.signed_raw()
from_rendered_tx = Transaction.from_signed_raw(rendered_tx)
self.assertEqual(tx.version, 3)
......@@ -435,7 +435,7 @@ class Test_Transaction(unittest.TestCase):
def test_compact_change(self):
tx = Transaction.from_compact("gtest", compact_change)
rendered_tx = tx.signed_raw_for_certified()
rendered_tx = tx.signed_raw()
from_rendered_tx = Transaction.from_signed_raw(rendered_tx)
def test_reduce_base(self):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment