Source code for darc.model.utils
# -*- coding: utf-8 -*-
"""Miscellaneous Utilities
-----------------------------
The :mod:`darc.model.utils` module contains several miscellaneous
utility functions and data fields.
"""
import enum
import ipaddress
import json
import pickle # nosec
import peewee
import playhouse.mysql_ext
import playhouse.shortcuts
import darc.typing as typing
__all__ = ['table_function',
'JSONField', 'IPField',
'IntEnumField', 'PickleField',
'Proxy']
[docs]def table_function(model_class: peewee.Model) -> str:
"""Generate table name dynamically.
The function strips ``Model`` from the class name and
calls :func:`peewee.make_snake_case` to generate a
proper table name.
Args:
model_class: Data model class.
Returns:
Generated table name.
"""
name: str = model_class.__name__
if name.endswith('Model'):
name = name[:-5] # strip ``Model`` suffix
return peewee.make_snake_case(name)
[docs]class JSONField(playhouse.mysql_ext.JSONField):
"""JSON data field."""
[docs] def db_value(self, value: typing.Any) -> typing.Optional[str]: # pylint: disable=inconsistent-return-statements
"""Dump the value for database storage.
Args:
value: Source JSON value.
Returns:
JSON serialised string data.
"""
if value is not None:
return json.dumps(value)
return None
[docs] def python_value(self, value: typing.Optional[str]) -> typing.Any: # pylint: disable=inconsistent-return-statements
"""Load the value from database storage.
Args:
value: Serialised JSON string.
Returns:
Original JSON data.
"""
if value is not None:
return json.loads(value)
return None
[docs]class IPField(peewee.IPField):
"""IP data field."""
[docs] def db_value(self, val: typing.Optional[typing.Union[str, typing.IPAddress]]) -> typing.Optional[int]: # pylint: disable=inconsistent-return-statements
"""Dump the value for database storage.
Args:
value: Source IP address instance.
Returns:
Integral representation of the IP address.
"""
if val is not None:
if isinstance(val, str):
val = ipaddress.ip_address(val)
return int(val) # type: ignore
return None
[docs] def python_value(self, val: typing.Optional[int]) -> typing.Optional[typing.IPAddress]: # pylint: disable=inconsistent-return-statements
"""Load the value from database storage.
Args:
value: Integral representation of the IP address.
Returns:
Original IP address instance.
"""
if val is not None:
return ipaddress.ip_address(val)
return None
[docs]class IntEnumField(peewee.IntegerField):
""":class:`enum.IntEnum` data field."""
#: The original :class:`enum.IntEnum` class.
choices: typing.IntEnum
# def db_value(self, value: typing.Optional[typing.IntEnum]) -> typing.Optional[str]: # pylint: disable=inconsistent-return-statements
# """Dump the value for database storage.
# Args:
# val: Original enumeration object.
# Returns:
# Integral representation of the enumeration.
# """
# if value is not None:
# return value
[docs] def python_value(self, value: typing.Optional[int]) -> typing.Optional[typing.IntEnum]: # pylint: disable=inconsistent-return-statements
"""Load the value from database storage.
Args:
value: Integral representation of the enumeration.
Returns:
Original enumeration object.
"""
if value is not None:
return self.choices(value) # type: ignore
return None
[docs]class PickleField(peewee.BlobField):
"""Pickled data field."""
[docs] def db_value(self, value: typing.Any) -> typing.Optional[bytes]: # pylint: disable=inconsistent-return-statements
"""Dump the value for database storage.
Args:
value: Source value.
Returns:
Picked bytestring data.
"""
if value is not None:
value = pickle.dumps(value)
return super().db_value(value)
[docs] def python_value(self, value: typing.Optional[bytes]) -> typing.Any: # pylint: disable=inconsistent-return-statements
"""Load the value from database storage.
Args:
value: SPicked bytestring data.
Returns:
Original data.
"""
value = super().python_value(value)
if value is not None:
return pickle.loads(value) # nosec
return None
[docs]class Proxy(enum.IntEnum):
"""Proxy types supported by :mod:`darc`."""
#: No proxy.
NULL = enum.auto()
#: Tor proxy.
TOR = enum.auto()
#: I2P proxy.
I2P = enum.auto()
#: ZeroNet proxy.
ZERONET = enum.auto()
#: Freenet proxy.
FREENET = enum.auto()