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

Native neo4j datetime; increase test coverage in properties.py #811

Merged
merged 10 commits into from
Jun 7, 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
18 changes: 9 additions & 9 deletions doc/source/properties.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ Property types

The following properties are available on nodes and relationships:

==================================================== ===========================================================
:class:`~neomodel.properties.AliasProperty` :class:`~neomodel.properties.IntegerProperty`
:class:`~neomodel.properties.ArrayProperty` :class:`~neomodel.properties.JSONProperty`
:class:`~neomodel.properties.BooleanProperty` :class:`~neomodel.properties.RegexProperty`
:class:`~neomodel.properties.DateProperty` :class:`~neomodel.properties.StringProperty` (:ref:`Notes <properties_notes>`)
:class:`~neomodel.properties.DateTimeProperty` :class:`~neomodel.properties.UniqueIdProperty`
:class:`~neomodel.properties.DateTimeFormatProperty` :class:`~neomodel.contrib.spatial_properties.PointProperty`
:class:`~neomodel.properties.FloatProperty` \
==================================================== ===========================================================
========================================================= ===========================================================
:class:`~neomodel.properties.AliasProperty` :class:`~neomodel.properties.FloatProperty`
:class:`~neomodel.properties.ArrayProperty` :class:`~neomodel.properties.IntegerProperty`
:class:`~neomodel.properties.BooleanProperty` :class:`~neomodel.properties.JSONProperty`
:class:`~neomodel.properties.DateProperty` :class:`~neomodel.properties.RegexProperty`
:class:`~neomodel.properties.DateTimeProperty` :class:`~neomodel.properties.StringProperty` (:ref:`Notes <properties_notes>`)
:class:`~neomodel.properties.DateTimeFormatProperty` :class:`~neomodel.properties.UniqueIdProperty`
:class:`~neomodel.properties.DateTimeNeo4jFormatProperty` :class:`~neomodel.contrib.spatial_properties.PointProperty`
========================================================= ===========================================================


Naming Convention
Expand Down
1 change: 1 addition & 0 deletions neomodel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
BooleanProperty,
DateProperty,
DateTimeFormatProperty,
DateTimeNeo4jFormatProperty,
DateTimeProperty,
EmailProperty,
FloatProperty,
Expand Down
51 changes: 41 additions & 10 deletions neomodel/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
from neomodel import config
from neomodel.exceptions import DeflateError, InflateError

if sys.version_info >= (3, 0):
Unicode = str
TOO_MANY_DEFAULTS = "too many defaults"


def validator(fn):
Expand Down Expand Up @@ -164,7 +163,7 @@ def __init__(self, expression=None, **kwargs):
self.expression = actual_re

def normalize(self, value):
normal = Unicode(value)
normal = str(value)
if not re.match(self.expression, normal):
raise ValueError(f"{value!r} does not match {self.expression!r}")
return normal
Expand Down Expand Up @@ -226,7 +225,7 @@ def normalize(self, value):
raise ValueError(
f"Property max length exceeded. Expected {self.max_length}, got {len(value)} == len('{value}')"
)
return Unicode(value)
return str(value)

def default_value(self):
return self.normalize(super().default_value())
Expand Down Expand Up @@ -356,7 +355,7 @@ def inflate(self, value):
value = date(value.year, value.month, value.day)
elif isinstance(value, str) and "T" in value:
value = value[: value.find("T")]
return datetime.strptime(Unicode(value), "%Y-%m-%d").date()
return datetime.strptime(str(value), "%Y-%m-%d").date()

@validator
def deflate(self, value):
Expand All @@ -382,15 +381,15 @@ class DateTimeFormatProperty(Property):
def __init__(self, default_now=False, format="%Y-%m-%d", **kwargs):
if default_now:
if "default" in kwargs:
raise ValueError("too many defaults")
raise ValueError(TOO_MANY_DEFAULTS)
kwargs["default"] = datetime.now()

self.format = format
super().__init__(**kwargs)

@validator
def inflate(self, value):
return datetime.strptime(Unicode(value), self.format)
return datetime.strptime(str(value), self.format)

@validator
def deflate(self, value):
Expand All @@ -413,7 +412,7 @@ class DateTimeProperty(Property):
def __init__(self, default_now=False, **kwargs):
if default_now:
if "default" in kwargs:
raise ValueError("too many defaults")
raise ValueError(TOO_MANY_DEFAULTS)
kwargs["default"] = lambda: datetime.utcnow().replace(tzinfo=pytz.utc)

super().__init__(**kwargs)
Expand Down Expand Up @@ -447,6 +446,38 @@ def deflate(self, value):
return float((value - epoch_date).total_seconds())


class DateTimeNeo4jFormatProperty(Property):
"""
Store a datetime by native neo4j format

:param default_now: If ``True``, the creation time (Local) will be used as default.
Defaults to ``False``.

:type default_now: :class:`bool`
"""

form_field_class = "DateTimeNeo4jFormatField"

def __init__(self, default_now=False, **kwargs):
if default_now:
if "default" in kwargs:
raise ValueError(TOO_MANY_DEFAULTS)
kwargs["default"] = datetime.now()

self.format = format
super(DateTimeNeo4jFormatProperty, self).__init__(**kwargs)

@validator
def inflate(self, value):
return value.to_native()

@validator
def deflate(self, value):
if not isinstance(value, datetime):
raise ValueError("datetime object expected, got {0}.".format(type(value)))
return neo4j.time.DateTime.from_native(value)


class JSONProperty(Property):
"""
Store a data structure as a JSON string.
Expand Down Expand Up @@ -518,8 +549,8 @@ def __init__(self, **kwargs):

@validator
def inflate(self, value):
return Unicode(value)
return str(value)

@validator
def deflate(self, value):
return Unicode(value)
return str(value)
7 changes: 5 additions & 2 deletions neomodel/scripts/neomodel_generate_diagram.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
BooleanProperty,
DateProperty,
DateTimeFormatProperty,
DateTimeNeo4jFormatProperty,
DateTimeProperty,
FloatProperty,
IntegerProperty,
Expand Down Expand Up @@ -107,8 +108,10 @@ def transform_property_type(prop_definition):
return "bool"
elif isinstance(prop_definition, DateProperty):
return "date"
elif isinstance(prop_definition, DateTimeProperty) or isinstance(
prop_definition, DateTimeFormatProperty
elif (
isinstance(prop_definition, DateTimeProperty)
or isinstance(prop_definition, DateTimeFormatProperty)
or isinstance(prop_definition, DateTimeNeo4jFormatProperty)
):
return "datetime"
elif isinstance(prop_definition, IntegerProperty):
Expand Down
Loading
Loading