A handler can only be registered once
This commit is contained in:
@@ -349,4 +349,5 @@ See LICENSE file for details.
|
|||||||
|
|
||||||
## Version History
|
## Version History
|
||||||
* 0.1.0 - Initial release
|
* 0.1.0 - Initial release
|
||||||
* 0.2.0 - Added custom reference handlers
|
* 0.2.0 - Added custom reference handlers
|
||||||
|
* 0.2.1 - A handler can only be registered once
|
||||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "mydbengine"
|
name = "mydbengine"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
description = "A lightweight, git-inspired database engine that maintains complete history of all modifications"
|
description = "A lightweight, git-inspired database engine that maintains complete history of all modifications"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.8"
|
requires-python = ">=3.8"
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ TAG_SPECIAL = "__special__"
|
|||||||
|
|
||||||
class BaseHandler:
|
class BaseHandler:
|
||||||
"""Base class for all handlers. Subclasses must implement is_eligible_for() and tag()."""
|
"""Base class for all handlers. Subclasses must implement is_eligible_for() and tag()."""
|
||||||
|
|
||||||
def is_eligible_for(self, obj):
|
def is_eligible_for(self, obj):
|
||||||
"""Check if this handler can process the given object."""
|
"""Check if this handler can process the given object."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def tag(self):
|
def tag(self):
|
||||||
"""Return a unique tag identifying this handler type."""
|
"""Return a unique tag identifying this handler type."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@@ -21,11 +21,11 @@ class BaseHandler:
|
|||||||
|
|
||||||
class BaseInlineHandler(BaseHandler):
|
class BaseInlineHandler(BaseHandler):
|
||||||
"""Handler that serializes data directly into the JSON snapshot."""
|
"""Handler that serializes data directly into the JSON snapshot."""
|
||||||
|
|
||||||
def serialize(self, obj) -> dict:
|
def serialize(self, obj) -> dict:
|
||||||
"""Serialize object to dict for inline storage in JSON snapshot."""
|
"""Serialize object to dict for inline storage in JSON snapshot."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def deserialize(self, data: dict) -> object:
|
def deserialize(self, data: dict) -> object:
|
||||||
"""Deserialize object from dict stored in JSON snapshot."""
|
"""Deserialize object from dict stored in JSON snapshot."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@@ -33,15 +33,15 @@ class BaseInlineHandler(BaseHandler):
|
|||||||
|
|
||||||
class BaseRefHandler(BaseHandler):
|
class BaseRefHandler(BaseHandler):
|
||||||
"""Handler that serializes data to refs/ directory using content-addressable storage."""
|
"""Handler that serializes data to refs/ directory using content-addressable storage."""
|
||||||
|
|
||||||
def serialize_to_bytes(self, obj) -> bytes:
|
def serialize_to_bytes(self, obj) -> bytes:
|
||||||
"""Serialize object to bytes for storage in refs/. Must be implemented by subclass."""
|
"""Serialize object to bytes for storage in refs/. Must be implemented by subclass."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def deserialize_from_bytes(self, data: bytes) -> object:
|
def deserialize_from_bytes(self, data: bytes) -> object:
|
||||||
"""Deserialize object from bytes loaded from refs/. Must be implemented by subclass."""
|
"""Deserialize object from bytes loaded from refs/. Must be implemented by subclass."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def serialize(self, obj, ref_helper) -> dict:
|
def serialize(self, obj, ref_helper) -> dict:
|
||||||
"""
|
"""
|
||||||
Default implementation: converts object to bytes, saves to refs/, returns dict with tag and digest.
|
Default implementation: converts object to bytes, saves to refs/, returns dict with tag and digest.
|
||||||
@@ -52,10 +52,10 @@ class BaseRefHandler(BaseHandler):
|
|||||||
from dbengine.serializer import TAG_DIGEST
|
from dbengine.serializer import TAG_DIGEST
|
||||||
TAG_SPECIAL = "__special__"
|
TAG_SPECIAL = "__special__"
|
||||||
return {
|
return {
|
||||||
TAG_SPECIAL: self.tag(),
|
TAG_SPECIAL: self.tag(),
|
||||||
TAG_DIGEST: digest
|
TAG_DIGEST: digest
|
||||||
}
|
}
|
||||||
|
|
||||||
def deserialize(self, data: dict, ref_helper) -> object:
|
def deserialize(self, data: dict, ref_helper) -> object:
|
||||||
"""
|
"""
|
||||||
Default implementation: loads bytes from refs/ using digest, deserializes from bytes.
|
Default implementation: loads bytes from refs/ using digest, deserializes from bytes.
|
||||||
@@ -89,7 +89,7 @@ class DateHandler(BaseInlineHandler):
|
|||||||
class Handlers:
|
class Handlers:
|
||||||
|
|
||||||
def __init__(self, handlers_):
|
def __init__(self, handlers_):
|
||||||
self.handlers = handlers_
|
self.handlers = handlers_ or []
|
||||||
|
|
||||||
def get_handler(self, obj):
|
def get_handler(self, obj):
|
||||||
if has_tag(obj, TAG_SPECIAL):
|
if has_tag(obj, TAG_SPECIAL):
|
||||||
@@ -102,7 +102,14 @@ class Handlers:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def register_handler(self, handler):
|
def register_handler(self, handler):
|
||||||
|
for h in self.handlers:
|
||||||
|
if type(h) == type(handler):
|
||||||
|
return # won't register twice the same handler
|
||||||
|
|
||||||
self.handlers.append(handler)
|
self.handlers.append(handler)
|
||||||
|
|
||||||
|
def unregister_handler(self, handler):
|
||||||
|
self.handlers = [h for h in self.handlers if type(h) != type(handler)]
|
||||||
|
|
||||||
|
|
||||||
handlers = Handlers([DateHandler()])
|
handlers = Handlers([DateHandler()])
|
||||||
|
|||||||
16
tests/test_handlers.py
Normal file
16
tests/test_handlers.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from dbengine.handlers import BaseHandler, handlers
|
||||||
|
|
||||||
|
|
||||||
|
class DummyHandler(BaseHandler):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_i_can_register_only_once():
|
||||||
|
handlers.register_handler(DummyHandler())
|
||||||
|
count = len(handlers.handlers)
|
||||||
|
|
||||||
|
handlers.register_handler(DummyHandler()) # second time is skipped as the class is already registered
|
||||||
|
assert count == len(handlers.handlers)
|
||||||
|
|
||||||
|
handlers.unregister_handler(DummyHandler()) # clean the handlers list
|
||||||
|
assert len(handlers.handlers) == count - 1
|
||||||
Reference in New Issue
Block a user