Skip to content

Commit

Permalink
Merge pull request #811 from neo4j-contrib/native_neo4j_datetime
Browse files Browse the repository at this point in the history
Native neo4j datetime; increase test coverage in properties.py
  • Loading branch information
mariusconjeaud authored Jun 7, 2024
2 parents 7c6662a + 5d11484 commit 0a03833
Show file tree
Hide file tree
Showing 6 changed files with 400 additions and 25 deletions.
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

0 comments on commit 0a03833

Please sign in to comment.