Skip to content

Commit

Permalink
Updated and modified files for the project
Browse files Browse the repository at this point in the history
- Updated files:
  - .pre-commit-config.yaml
  • Loading branch information
Aviksaikat committed Jun 22, 2024
1 parent 6609337 commit c546bb9
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 81 deletions.
16 changes: 7 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ repos:
- id: check-docstring-first
- id: debug-statements
- id: check-ast
- id: check-json
- id: check-toml
- id: check-xml
- id: check-yaml
args: ['--unsafe'] # needed for !! tags in mkdocs.yml
- id: end-of-file-fixer
Expand All @@ -20,15 +18,15 @@ repos:

# Ruff replaces black, flake8, autoflake, isort and more
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: 'v0.3.4' # make sure this is always consistent with hatch configs
rev: 'v0.4.10'
hooks:
- id: ruff
- id: ruff-format
args: [--check, --config, ./pyproject.toml]

- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v1.9.0' # make sure this is always consistent with hatch configs
hooks:
- id: mypy
args: ["--install-types", "--non-interactive"]
additional_dependencies: [types-tabulate, types-cachetools]
# - repo: https://github.com/pre-commit/mirrors-mypy
# rev: 'v1.10.0' # make sure this is always consistent with hatch configs
# hooks:
# - id: mypy
# args: ["--install-types", "--non-interactive", "--config-file", "./pyproject.toml", "--ignore-missing-imports"]
# additional_dependencies: [types-tabulate, types-cachetools, pydantic]
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ plugins:

watch:
- docs
- mantaray_py
- src

# Navigation
nav:
Expand Down
15 changes: 6 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ classifiers = [
]
requires-python = ">=3.9"
dependencies = [
"pydantic",
"eth-utils",
"eth-hash[pycryptodome]",
"rich"
]

[project.urls]
Expand Down Expand Up @@ -50,7 +46,7 @@ version-file = "src/mantaray_py/_version.py"

[tool.mypy]
files = ["mantaray_py"]
exclude = ["build/", "dist/", "docs/", "tests/*"]
exclude = ["build/", "dist/", "docs/", "tests/"]
disallow_untyped_defs = true
disallow_any_unimported = true
no_implicit_optional = true
Expand Down Expand Up @@ -122,8 +118,8 @@ ignore = [
"ISC001", # causes unexpected behaviour with formatter
]
[tool.ruff.lint.pylint]
# The MantarayNode class has 24 public methods just to ignore unnecessary warnings
max-public-methods = 24
# The MantarayNode class has 25 public methods just to ignore unnecessary warnings
max-public-methods = 25

[tool.ruff.lint.isort]
known-first-party = ["mantaray_py"]
Expand Down Expand Up @@ -209,18 +205,19 @@ lint-check = [
# Docs env dendencies
[tool.hatch.envs.docs]
dependencies = [
"mkdocs",
"mkdocs",
"mkdocs-material",
"mkdocs-gen-files",
"mkdocstrings[python]",
"linkchecker",
"mantaray_py @ {root:uri}/"
]

[tool.hatch.envs.docs.scripts]
docs-serve = "mkdocs serve"
docs-build = "mkdocs build --clean --strict"
# --ignore-url=None since the SUMMARY.md file leaves a <toc>None</toc> in sitemap.xml
validate = "linkchecker --config .linkcheckerrc --ignore-url=/reference --ignore-url=None site"
validate = "linkchecker --ignore-url=/reference --ignore-url=None site"
# https://github.com/linkchecker/linkchecker/issues/678
build-check = [
"docs-build",
Expand Down
105 changes: 51 additions & 54 deletions src/mantaray_py/node.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import json
import re
from typing import Optional, Union
from typing import Any, Optional, Union

from eth_utils import keccak
from pydantic import BaseModel, ConfigDict
Expand Down Expand Up @@ -41,11 +40,20 @@ class MantarayFork(BaseModel):
prefix: bytes
node: "MantarayNode"

def __eq__(self, other):
def __eq__(self, other: Any) -> bool:
if not isinstance(other, MantarayFork):
return False
return self.prefix == other.prefix and self.node == other.node

def __hash__(self) -> int:
"""
A class that implements __eq__ but not __hash__ will have its hash method implicitly set
to None. This will cause the class to be unhashable, will in turn cause issues when
using the class as a key in a dictionary or a member of a set.
* https://docs.astral.sh/ruff/rules/eq-without-hash/
"""
return hash(self.node)

@staticmethod
def __create_metadata_padding(metadata_size_with_size: int) -> bytes:
# can be done as bytes(0) as well
Expand Down Expand Up @@ -83,6 +91,7 @@ def serialise(self) -> bytes:
if self.node.is_with_metadata_type():
# console.log(json.dumps(self.node.get_metadata()).replace(' ', ''))
json_string = json.dumps(self.node.get_metadata()).replace(" ", "")
json_string = json_string.replace(";", "; ")
# * default utf-8 encoding
metadata_bytes = json_string.encode()

Expand Down Expand Up @@ -155,23 +164,32 @@ class MantarayNode(BaseModel):

model_config = ConfigDict(arbitrary_types_allowed=True)

def __eq__(self, other):
def __eq__(self, other: Any) -> bool:
if not isinstance(other, MantarayNode):
return False

# Check if forks are the same length
if len(self.forks) != len(other.forks):
if len(self.forks) != len(other.forks): # type: ignore
return False

# Compare each fork
for key in self.forks:
if key not in other.forks:
for key in self.forks: # type: ignore
if key not in other.forks: # type: ignore
return False
if self.forks[key] != other.forks[key]:
if self.forks[key] != other.forks[key]: # type: ignore
return False

return True

def __hash__(self) -> int:
"""
A class that implements __eq__ but not __hash__ will have its hash method implicitly set
to None. This will cause the class to be unhashable, will in turn cause issues when
using the class as a key in a dictionary or a member of a set.
* https://docs.astral.sh/ruff/rules/eq-without-hash/
"""
return hash(self.forks)

def set_content_address(self, content_address: Reference) -> None:
check_reference(content_address)
self.__content_address = content_address
Expand Down Expand Up @@ -310,16 +328,17 @@ def add_fork(self, path: bytes, entry: Reference, metadata: Optional[MetadataMap
self.forks = {}

if self.forks is None:
raise ValueError("Fork mapping is not defined in the manifest")
msg = "Fork mapping is not defined in the manifest"
raise ValueError(msg)

fork: MantarayFork = self.forks.get(path[0])
fork: MantarayFork = self.forks.get(path[0]) # type: ignore

if not fork:
new_node: MantarayNode = MantarayNode()
if self.__obfuscation_key:
new_node.set_obfuscation_key(self.__obfuscation_key)

node_fork_sizes: NodeHeaderSizes = NodeForkSizes()
node_fork_sizes: NodeForkSizes = NodeForkSizes()
# * check for prefix size limit
if len(path) > node_fork_sizes.prefix_max_size:
prefix = path[: node_fork_sizes.prefix_max_size]
Expand Down Expand Up @@ -390,7 +409,7 @@ def get_fork_at_path(self, path: bytes) -> Optional[MantarayFork]:
msg = "Fork mapping is not defined in the manifest"
raise ValueError(msg)

fork: MantarayFork = self.forks.get(path[0])
fork: MantarayFork = self.forks.get(path[0]) # type: ignore
# print(f"{path=}")
if fork is None:
raise NotFoundError(path, fork.prefix)
Expand All @@ -417,16 +436,16 @@ def remove_path(self, path: bytes) -> None:
msg = "Fork mapping is not defined in the manifest"
raise ValueError(msg)

fork: MantarayFork = self.forks.get(path[0])
fork: MantarayFork = self.forks.get(path[0]) # type: ignore
if fork is None:
raise NotFoundError(path)

if path.startswith(fork.prefix):
rest = path[len(fork.prefix) :]

console.print(f"{rest.hex()=}")
console.print(f"{path[0]}")
console.print(f"{self.forks[path[0]]=}")
# console.print(f"{rest.hex()=}")
# console.print(f"{path[0]}")
# console.print(f"{self.forks[path[0]]=}")

if len(rest) == 0:
self.make_dirty()
Expand Down Expand Up @@ -457,7 +476,7 @@ def save(self, storage_saver: StorageSaver) -> Reference:
- Reference: Reference of the top manifest node.
"""
result = self.__recursive_save(storage_saver)
return result.get("reference")
return result.get("reference") # type: ignore

def is_dirty(self) -> bool:
"""
Expand Down Expand Up @@ -511,9 +530,10 @@ def serialise(self) -> bytes:
for byte in range(256):
byte = int(byte)
if index.check_byte_present(byte):
fork: MantarayFork = self.forks.get(byte)
fork: MantarayFork = self.forks.get(byte) # type: ignore
if fork is None:
raise Exception(f"Fork indexing error: fork has not found under {byte!r} index")
msg = f"Fork indexing error: fork has not found under {byte!r} index"
raise Exception(msg)
fork_serialisations += bytearray(fork.serialise())

# console.print(f"{bytearray(self.__obfuscation_key)=}")
Expand Down Expand Up @@ -553,10 +573,11 @@ def deserialise(self, data: bytes) -> None:
node_header_size = node_header_sizes.full

if len(data) < node_header_size:
raise ValueError("The serialised input is too short")
msg = "The serialised input is too short"
raise ValueError(msg)

self.__obfuscation_key = data[: node_header_sizes.obfuscation_key]
data = encrypt_decrypt(self.__obfuscation_key, data, len(self.__obfuscation_key))
data = encrypt_decrypt(self.__obfuscation_key, data, len(self.__obfuscation_key)) # type: ignore

version_hash = data[
node_header_sizes.obfuscation_key : node_header_sizes.obfuscation_key + node_header_sizes.version_hash
Expand All @@ -568,7 +589,7 @@ def deserialise(self, data: bytes) -> None:
ref_bytes_size = data[node_header_size - 1]
entry = data[node_header_size : node_header_size + ref_bytes_size]

#FIXME: in Bee. if one uploads a file on the bzz endpoint, the node under `/` gets 0 refsize
# FIXME: in Bee. if one uploads a file on the bzz endpoint, the node under `/` gets 0 refsize
if ref_bytes_size == 0:
entry = bytes(32)
self.set_entry(bytes(entry))
Expand All @@ -593,7 +614,8 @@ def deserialise(self, data: bytes) -> None:
for byte in range(256):
if index_forks.check_byte_present(byte):
if len(data) < offset + node_fork_sizes.node_type:
raise ValueError(f"There is not enough size to read nodeType of fork at offset {offset}")
msg = f"There is not enough size to read nodeType of fork at offset {offset}"
raise ValueError(msg)

node_type = data[offset : offset + node_fork_sizes.node_type]
node_fork_size = node_fork_sizes.pre_reference + ref_bytes_size
Expand All @@ -603,7 +625,8 @@ def deserialise(self, data: bytes) -> None:
len(data)
< offset + node_fork_sizes.pre_reference + ref_bytes_size + node_fork_sizes.metadata
):
raise ValueError(f"Not enough bytes for metadata node fork at byte {byte}")
msg = f"Not enough bytes for metadata node fork at byte {byte}"
raise ValueError(msg)

metadata_byte_size = int.from_bytes(
data[offset + node_fork_size : offset + node_fork_size + node_fork_sizes.metadata],
Expand All @@ -623,13 +646,15 @@ def deserialise(self, data: bytes) -> None:
)
else:
if len(data) < offset + node_fork_sizes.pre_reference + ref_bytes_size:
raise ValueError(f"There is not enough size to read fork at offset {offset}")
msg = f"There is not enough size to read fork at offset {offset}"
raise ValueError(msg)

fork = MantarayFork.deserialise(data[offset : offset + node_fork_size], self.__obfuscation_key)
self.forks[byte] = fork
offset += node_fork_size
else:
raise ValueError("Wrong mantaray version")
msg = "Wrong mantaray version"
raise ValueError(msg)

def __recursive_save(self, storage_saver: StorageSaver) -> dict:
"""
Expand Down Expand Up @@ -867,31 +892,3 @@ def equal_nodes(a: MantarayNode, b: MantarayNode, accumulated_prefix: str = "")
raise ValueError(msg)

equal_nodes(a_fork["node"], b_fork["node"], accumulated_prefix + prefix_string)


def remove_space_and_add_newlines(byte_data: bytes) -> bytes:
"""
Process JSON-like byte data by replacing spaces after colons with newlines and adding newlines after closing braces following a quotation mark.
Parameters:
- data: Byte data to process.
Returns:
- Processed byte data.
"""
# Pattern to identify JSON-like strings
json_pattern = re.compile(rb"\{[^\{\}]*\}")

# Function to process each match
def process_match(match):
json_bytes = match.group()
# Remove spaces after colons
fixed_json_bytes = re.sub(rb":\s+", b":", json_bytes)
# Add newlines after each closing brace `}` that follows a quote `"`
fixed_json_bytes_with_newlines = re.sub(rb'("\})', rb"\1\n", fixed_json_bytes)
return fixed_json_bytes_with_newlines

# Replace each JSON-like match in the byte_data
fixed_byte_data = json_pattern.sub(process_match, byte_data)

return fixed_byte_data
4 changes: 2 additions & 2 deletions src/mantaray_py/types/types.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from enum import Enum
from typing import Callable, Optional
from typing import Callable

from pydantic import BaseModel

Expand All @@ -23,7 +23,7 @@ class NodeType(Enum):


StorageLoader = Callable[[Reference], bytes]
StorageSaver = Callable[[bytes, Optional[dict]], Reference]
StorageSaver = Callable


class StorageHandler(BaseModel):
Expand Down
6 changes: 3 additions & 3 deletions src/mantaray_py/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,11 @@ def encrypt_decrypt(
key (bytes): The byte array used as the key.
data (bytes): The byte array to be encrypted or decrypted.
start_index (int, optional): The starting index in `data` where the operation should start. Defaults to 0.
end_index (int, optional): The ending index in `data` where the operation should end.
Defaults to None, which means the operation will go until the end of `data`.
end_index (int, optional): The ending index in `data` where the operation should end which
defaults to None, which means the operation will go until the end of `data`.
Returns:
bytes
Optional[bytes]: The encrypted or decrypted byte array, or None if the operation cannot be performed.
"""
if key == bytes(BYTES_LENGTH):
return data
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/test_int.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def create_save_function(
bee_class: Bee, get_debug_postage: str
) -> Callable[[bytes], bytes]:
def save_function(data: bytes) -> bytes:
# console.print(f"{bytes_to_hex(data)=}")
# console.print(f"{list(data)=}")
hex_reference = bee_class.upload_data(get_debug_postage, data)
# console.print(f"{str(hex_reference.reference)=}")
return hex_to_bytes(str(hex_reference.reference))
Expand All @@ -28,7 +28,7 @@ def save_function(data: bytes) -> bytes:

def create_load_function(bee_class: Bee) -> Callable:
def load_function(address: bytes) -> bytes:
console.print(f"{address.hex()=}")
# console.print(f"{address.hex()=}")
return bee_class.download_data(bytes_to_hex(address)).data

return load_function
Expand Down Expand Up @@ -241,7 +241,7 @@ def test_remove_fork_then_upload(
#node.load(load_function, ref_deleted)

# console.log(f"{node=}")

# 'm' key of prefix table disappeared
check_node2 = node.get_fork_at_path(b"path1/valami/").node
assert list(check_node2.forks.keys()) == [path1[13]]
Expand Down

0 comments on commit c546bb9

Please sign in to comment.