Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#161] refactoring multiple small files #174

Merged
merged 2 commits into from
Jul 30, 2024
Merged
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
4 changes: 4 additions & 0 deletions hyperon_das_atomdb/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""This module initializes the AtomDB package and imports key components."""

# pylint: disable=wrong-import-position

import sys

if sys.version_info < (3, 10):
Expand Down
2 changes: 2 additions & 0 deletions hyperon_das_atomdb/adapters/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""This module imports the InMemoryDB and RedisMongoDB classes and defines the public API."""

from .ram_only import InMemoryDB
from .redis_mongo_db import RedisMongoDB

Expand Down
6 changes: 3 additions & 3 deletions hyperon_das_atomdb/adapters/ram_only.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from hyperon_das_atomdb.exceptions import AtomDoesNotExist, InvalidOperationException
from hyperon_das_atomdb.logger import logger
from hyperon_das_atomdb.utils.expression_hasher import ExpressionHasher
from hyperon_das_atomdb.utils.patterns import build_patern_keys
from hyperon_das_atomdb.utils.patterns import build_pattern_keys


@dataclass
Expand Down Expand Up @@ -150,7 +150,7 @@ def _delete_templates(self, link_document: dict, targets_hash: List[str]) -> Non
template_named_type.remove((link_document[FieldNames.ID_HASH], tuple(targets_hash)))

def _add_patterns(self, named_type_hash: str, key: str, targets_hash: List[str]) -> None:
pattern_keys = build_patern_keys([named_type_hash, *targets_hash])
pattern_keys = build_pattern_keys([named_type_hash, *targets_hash])

for pattern_key in pattern_keys:
pattern_key_hash = self.db.patterns.get(pattern_key)
Expand All @@ -160,7 +160,7 @@ def _add_patterns(self, named_type_hash: str, key: str, targets_hash: List[str])
self.db.patterns[pattern_key] = {(key, tuple(targets_hash))}

def _delete_patterns(self, link_document: dict, targets_hash: List[str]) -> None:
pattern_keys = build_patern_keys([link_document[FieldNames.TYPE_NAME_HASH], *targets_hash])
pattern_keys = build_pattern_keys([link_document[FieldNames.TYPE_NAME_HASH], *targets_hash])
for pattern_key in pattern_keys:
pattern = self.db.patterns.get(pattern_key, set())
if len(pattern) > 0:
Expand Down
39 changes: 21 additions & 18 deletions hyperon_das_atomdb/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
class BaseException(Exception):
"""Custom exceptions for Atom DB"""


class AtomDbBaseException(Exception):
"""
Base class to exceptions
Base class for Atom DB exceptions
"""

def __init__(self, message: str, details: str = ""):
Expand All @@ -10,33 +13,33 @@ def __init__(self, message: str, details: str = ""):
super().__init__(self.message, self.details)


class ConnectionMongoDBException(BaseException):
... # pragma no cover
class ConnectionMongoDBException(AtomDbBaseException):
"""Exception raised for errors in the connection to MongoDB."""


class AtomDoesNotExist(BaseException):
... # pragma no cover
class AtomDoesNotExist(AtomDbBaseException):
"""Exception raised when an atom does not exist."""


class AddNodeException(BaseException):
... # pragma no cover
class AddNodeException(AtomDbBaseException):
"""Exception raised when adding a node fails."""


class AddLinkException(BaseException):
... # pragma no cover
class AddLinkException(AtomDbBaseException):
"""Exception raised when adding a link fails."""


class InvalidOperationException(BaseException):
... # pragma no cover
class InvalidOperationException(AtomDbBaseException):
"""Exception raised for invalid operations."""


class RetryException(BaseException):
... # pragma no cover
class RetryException(AtomDbBaseException):
"""Exception raised for retryable errors."""


class InvalidAtomDB(BaseException):
... # pragma no cover
class InvalidAtomDB(AtomDbBaseException):
"""Exception raised for invalid Atom DB operations."""


class InvalidSQL(BaseException):
... # pragma no cover
class InvalidSQL(AtomDbBaseException):
"""Exception raised for invalid SQL operations."""
21 changes: 13 additions & 8 deletions hyperon_das_atomdb/index.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,46 @@
"""This module contains the abstract class for index creation and management."""

from abc import ABC, abstractmethod
from typing import Any, Dict, List, Tuple
from typing import Any

from hyperon_das_atomdb.utils.expression_hasher import ExpressionHasher


class Index(ABC):
"""Abstract class for index creation and management."""

@staticmethod
def generate_index_id(field: str, conditionals: Dict[str, Any]) -> str:
def generate_index_id(field: str, conditionals: dict[str, Any]) -> str:
"""Generates an index ID based on the field name.

Args:
field (str): The field name.
conditionals (dict[str, Any]): The conditionals.

Returns:
str: The index ID.
"""
# TODO(angelo,andre): remove '_' from `ExpressionHasher._compute_hash` method?
# pylint: disable=protected-access
return ExpressionHasher._compute_hash(f'{field}{conditionals}')

@abstractmethod
def create(
self,
atom_type: str,
fields: List[str],
fields: list[str],
**kwargs,
) -> Tuple[str, Any]:
) -> tuple[str, Any]:
"""Creates an index on the given field.

Args:
atom_type (str): Atom's type
fields (List[str]): The fields to create the index on.
fields (list[str]): The fields to create the index on.


Returns:
Tuple[str, Any]: Returns the index id and the index properties dict
tuple[str, Any]: Returns the index id and the index properties dict
"""
... # pragma: no cover

@abstractmethod
def index_exists(self, index_id: str) -> bool:
Expand All @@ -46,4 +52,3 @@ def index_exists(self, index_id: str) -> bool:
Returns:
bool: True if the index exists, False otherwise.
"""
... # pragma: no cover
85 changes: 69 additions & 16 deletions hyperon_das_atomdb/logger.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,98 @@
"""
This module provides a singleton Logger class for logging messages to a file with a specific
format and level.

The Logger class ensures that only one instance of the logger is created and provides methods
for logging messages at different levels (debug, info, warning, error). The log messages are
written to a file specified by LOG_FILE_NAME with a logging level defined by LOGGING_LEVEL.
"""

import logging

LOG_FILE_NAME = "/tmp/das.log"
LOGGING_LEVEL = logging.INFO

# pylint: disable=logging-not-lazy


class Logger:
"""Singleton Logger class for logging messages to a file."""

__instance = None

@staticmethod
def get_instance():
def get_instance() -> "Logger":
"""Get the singleton instance of the Logger class."""
if Logger.__instance is None:
return Logger()
return Logger.__instance

def __init__(self):
"""Initializes the Logger instance and sets up the logging configuration.

Raises:
Exception: If an attempt is made to re-instantiate the Logger.
"""

if Logger.__instance is not None:
# TODO(angelo,andre): raise a more specific type of exception?
# pylint: disable=broad-exception-raised
raise Exception("Invalid re-instantiation of Logger")
else:
logging.basicConfig(
filename=LOG_FILE_NAME,
level=LOGGING_LEVEL,
format="%(asctime)s %(levelname)-8s %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
Logger.__instance = self

def _prefix(self):

logging.basicConfig(
filename=LOG_FILE_NAME,
level=LOGGING_LEVEL,
format="%(asctime)s %(levelname)-8s %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
Logger.__instance = self

@staticmethod
def _prefix() -> str:
"""Returns a prefix for log messages.

Returns:
str: The prefix for log messages.
"""
return ""

def debug(self, msg):
def debug(self, msg: str) -> None:
"""Logs a debug message.

Args:
msg (str): The message to log.
"""
logging.debug(self._prefix() + msg)

def info(self, msg):
def info(self, msg: str) -> None:
"""Logs an info message.

Args:
msg (str): The message to log.
"""
logging.info(self._prefix() + msg)

def warning(self, msg):
def warning(self, msg: str) -> None:
"""Logs a warning message.

Args:
msg (str): The message to log.
"""
logging.warning(self._prefix() + msg)

def error(self, msg):
def error(self, msg: str) -> None:
"""Logs an error message.

Args:
msg (str): The message to log.
"""
logging.error(self._prefix() + msg)


def logger():
def logger() -> Logger:
"""Get the singleton instance of the Logger class.

Returns:
Logger: The singleton instance of the Logger class.
"""
return Logger.get_instance()
18 changes: 13 additions & 5 deletions hyperon_das_atomdb/utils/expression_hasher.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
"""
This module provides utility functions for hashing expressions and generating unique identifiers.

It includes classes for computing hashes of various types of expressions, such as named types,
terminals, and composite expressions. The module uses the MD5 hashing algorithm to generate
hashes and provides methods for creating composite hashes from lists of elements.
"""

from hashlib import md5
from typing import Any, List
from typing import Any


class ExpressionHasher:
Expand All @@ -20,7 +28,7 @@ def terminal_hash(named_type: str, terminal_name: str) -> str:
)

@staticmethod
def expression_hash(named_type_hash: str, elements: List[str]) -> str:
def expression_hash(named_type_hash: str, elements: list[str]) -> str:
return ExpressionHasher.composite_hash([named_type_hash, *elements])

@staticmethod
Expand All @@ -43,7 +51,7 @@ def composite_hash(hash_base: Any) -> str:
class StringExpressionHasher:
@staticmethod
def _compute_hash(text: str) -> str:
return str
return str # TODO(angelo,andre): this seems wrong

@staticmethod
def named_type_hash(name: str) -> str:
Expand All @@ -54,11 +62,11 @@ def terminal_hash(named_type: str, terminal_name: str) -> str:
return f"<{named_type}: {terminal_name}>"

@staticmethod
def expression_hash(named_type_hash: str, elements: List[str]) -> str:
def expression_hash(named_type_hash: str, elements: list[str]) -> str:
return f"<{named_type_hash}: {elements}>"

@staticmethod
def composite_hash(hash_list: List[str]) -> str:
def composite_hash(hash_list: list[str]) -> str:
if len(hash_list) == 1:
return hash_list[0]
return f"{hash_list}"
Loading