feat: contains in collection
This commit is contained in:
parent
7725ebc306
commit
a6cea55eb2
@ -1,45 +1,85 @@
|
|||||||
from typing import List, Iterable, Iterator, Optional, TypeVar, Generic
|
from typing import List, Iterable, Iterator, Optional, TypeVar, Generic, Dict, Type
|
||||||
import guppy
|
from collections import defaultdict
|
||||||
from guppy.heapy import Path
|
|
||||||
|
|
||||||
from .parents import DatabaseObject
|
from .parents import DatabaseObject
|
||||||
|
from ..utils.functions import replace_all_refs
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar('T', bound=DatabaseObject)
|
T = TypeVar('T', bound=DatabaseObject)
|
||||||
|
|
||||||
|
|
||||||
hp = guppy.hpy()
|
|
||||||
|
|
||||||
def _replace_all_refs(replace_with, replace):
|
|
||||||
"""
|
|
||||||
NO
|
|
||||||
I have a very good reason to use this here
|
|
||||||
DONT use this anywhere else...
|
|
||||||
|
|
||||||
This replaces **ALL** references to replace with a reference to replace_with.
|
|
||||||
|
|
||||||
https://benkurtovic.com/2015/01/28/python-object-replacement.html
|
|
||||||
"""
|
|
||||||
for path in hp.iso(replace).pathsin:
|
|
||||||
relation = path.path[1]
|
|
||||||
if isinstance(relation, Path.R_INDEXVAL):
|
|
||||||
path.src.theone[relation.r] = replace_with
|
|
||||||
|
|
||||||
|
|
||||||
class Collection(Generic[T]):
|
class Collection(Generic[T]):
|
||||||
_data: List[T]
|
_data: List[T]
|
||||||
|
|
||||||
|
_indexed_values: Dict[str, set]
|
||||||
|
_indexed_to_objects: Dict[any, list]
|
||||||
|
|
||||||
shallow_list = property(fget=lambda self: self.data)
|
shallow_list = property(fget=lambda self: self.data)
|
||||||
|
|
||||||
def __init__(self, data: Optional[Iterable[T]]) -> None:
|
def __init__(self, data: Optional[Iterable[T]]) -> None:
|
||||||
self._data = []
|
self._data = []
|
||||||
self.contained_collections: List[Collection[T]] = []
|
self.contained_collections: List[Collection[T]] = []
|
||||||
|
|
||||||
|
self._indexed_values = defaultdict(set)
|
||||||
|
self._indexed_to_objects = defaultdict(list)
|
||||||
|
|
||||||
self.extend(data)
|
self.extend(data)
|
||||||
|
|
||||||
def append(self, __object: T):
|
def _map_element(self, __object: T):
|
||||||
|
for name, value in __object.indexing_values:
|
||||||
|
if value is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._indexed_values[name].add(value)
|
||||||
|
self._indexed_to_objects[value].append(__object)
|
||||||
|
|
||||||
|
def _unmap_element(self, __object: T):
|
||||||
|
for name, value in __object.indexing_values:
|
||||||
|
if value is None:
|
||||||
|
continue
|
||||||
|
if value not in self._indexed_values[name]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._indexed_to_objects[value].remove(__object)
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not len(self._indexed_to_objects[value]):
|
||||||
|
self._indexed_values[name].remove(value)
|
||||||
|
|
||||||
|
def _contained_in_self(self, __object: T) -> bool:
|
||||||
|
for name, value in __object.indexing_values:
|
||||||
|
if value is None:
|
||||||
|
continue
|
||||||
|
if value in self._indexed_values[name]:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _contained_in(self, __object: T) -> Optional["Collection"]:
|
||||||
|
if self._contained_in_self(__object):
|
||||||
|
return self
|
||||||
|
|
||||||
|
for collection in self.contained_collections:
|
||||||
|
if collection._contained_in_self(__object):
|
||||||
|
return collection
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def contains(self, __object: T) -> bool:
|
||||||
|
return self._contained_in(__object) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def _append(self, __object: T):
|
||||||
|
self._map_element(__object)
|
||||||
self._data.append(__object)
|
self._data.append(__object)
|
||||||
|
|
||||||
|
def append(self, __object: Optional[T]):
|
||||||
|
if __object is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._append(__object)
|
||||||
|
|
||||||
def extend(self, __iterable: Optional[Iterable[T]]):
|
def extend(self, __iterable: Optional[Iterable[T]]):
|
||||||
if __iterable is None:
|
if __iterable is None:
|
||||||
return
|
return
|
||||||
@ -69,7 +109,7 @@ class Collection(Generic[T]):
|
|||||||
|
|
||||||
# now the ugly part
|
# now the ugly part
|
||||||
# replace all refs of the other element with this one
|
# replace all refs of the other element with this one
|
||||||
_replace_all_refs(self, equal_collection)
|
replace_all_refs(self, equal_collection)
|
||||||
|
|
||||||
|
|
||||||
def contain_collection_inside(self, sub_collection: "Collection"):
|
def contain_collection_inside(self, sub_collection: "Collection"):
|
||||||
|
@ -7,6 +7,7 @@ from .metadata import Metadata
|
|||||||
from .option import Options
|
from .option import Options
|
||||||
from ..utils.shared import HIGHEST_ID
|
from ..utils.shared import HIGHEST_ID
|
||||||
from ..utils.config import main_settings, logging_settings
|
from ..utils.config import main_settings, logging_settings
|
||||||
|
from ..utils.functions import replace_all_refs
|
||||||
|
|
||||||
|
|
||||||
LOGGER = logging_settings["object_logger"]
|
LOGGER = logging_settings["object_logger"]
|
||||||
@ -25,9 +26,6 @@ class StaticAttribute(Generic[P]):
|
|||||||
is_upwards_collection: bool = False
|
is_upwards_collection: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Attribute(Generic[P]):
|
class Attribute(Generic[P]):
|
||||||
def __init__(self, database_object: "DatabaseObject", static_attribute: StaticAttribute) -> None:
|
def __init__(self, database_object: "DatabaseObject", static_attribute: StaticAttribute) -> None:
|
||||||
self.database_object: DatabaseObject = database_object
|
self.database_object: DatabaseObject = database_object
|
||||||
@ -148,7 +146,7 @@ class DatabaseObject:
|
|||||||
|
|
||||||
return list()
|
return list()
|
||||||
|
|
||||||
def merge(self, other, override: bool = False):
|
def merge(self, other, override: bool = False, replace_all_refs: bool = False):
|
||||||
if other is None:
|
if other is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -171,6 +169,9 @@ class DatabaseObject:
|
|||||||
if override or getattr(self, simple_attribute) == default_value:
|
if override or getattr(self, simple_attribute) == default_value:
|
||||||
setattr(self, simple_attribute, getattr(other, simple_attribute))
|
setattr(self, simple_attribute, getattr(other, simple_attribute))
|
||||||
|
|
||||||
|
if replace_all_refs:
|
||||||
|
replace_all_refs(self, other)
|
||||||
|
|
||||||
def strip_details(self):
|
def strip_details(self):
|
||||||
for collection in type(self).DOWNWARDS_COLLECTION_STRING_ATTRIBUTES:
|
for collection in type(self).DOWNWARDS_COLLECTION_STRING_ATTRIBUTES:
|
||||||
getattr(self, collection).clear()
|
getattr(self, collection).clear()
|
||||||
|
@ -1,5 +1,25 @@
|
|||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import guppy
|
||||||
|
from guppy.heapy import Path
|
||||||
|
|
||||||
|
|
||||||
|
hp = guppy.hpy()
|
||||||
|
|
||||||
|
def replace_all_refs(replace_with, replace):
|
||||||
|
"""
|
||||||
|
NO
|
||||||
|
I have a very good reason to use this here
|
||||||
|
DONT use this anywhere else...
|
||||||
|
|
||||||
|
This replaces **ALL** references to replace with a reference to replace_with.
|
||||||
|
|
||||||
|
https://benkurtovic.com/2015/01/28/python-object-replacement.html
|
||||||
|
"""
|
||||||
|
for path in hp.iso(replace).pathsin:
|
||||||
|
relation = path.path[1]
|
||||||
|
if isinstance(relation, Path.R_INDEXVAL):
|
||||||
|
path.src.theone[relation.r] = replace_with
|
||||||
|
|
||||||
|
|
||||||
def clear_console():
|
def clear_console():
|
||||||
|
Loading…
Reference in New Issue
Block a user