Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9cc4ec0
Minor correction for badness if packaging folder is missing.
amcgregor May 25, 2017
28598e4
Unpacking changes, docstring updates, tweaks to __pk__ usage in Query…
amcgregor May 25, 2017
f8fc45f
WIP heirarchical traits; starting with the ABC, HParent, and HPath.
amcgregor May 25, 2017
27006d3
Docstrings, TODOs.
amcgregor May 25, 2017
c33bc34
Build parallelization and removal of egg legacy.
amcgregor May 29, 2017
c79cd23
Dead import removal.
amcgregor May 29, 2017
659215a
Merge branch 'develop' into feature/heirarchical
amcgregor May 30, 2017
a30b5ef
Updated dependencies to pin tzlocal and add timezone feature.
amcgregor May 31, 2017
95a9758
Adapt to future reserved word use; use wait, not await.
amcgregor May 31, 2017
0733071
Add Bandit exclusions.
amcgregor May 31, 2017
bd1a09a
Correction for filtering with cast None values and minor CPython fiel…
amcgregor May 31, 2017
741e978
Logical order correction accounting for Date changes.
amcgregor May 31, 2017
eed25b4
Utilize pytz.utc if available.
amcgregor May 31, 2017
60b8fdf
Correction for deprecation and future warnings.
amcgregor May 31, 2017
49ebe19
Silly regexen are silly.
amcgregor May 31, 2017
3d4c256
Correction for Pymongo deprecation of insert vs. insert_one.
amcgregor May 31, 2017
c9da243
Addition of timezone handling to Date fields.
amcgregor May 31, 2017
fbf5a55
Remove build parallelism. wry T_T
amcgregor May 31, 2017
145382f
Remove impossible case.
amcgregor May 31, 2017
10c3435
Test on multiple MongoDB versions, with and without timezone support.
amcgregor May 31, 2017
dffe131
Correction for missing inheritance of global environment.
amcgregor May 31, 2017
7114499
Simplification of testing requirement declaration, fix for comparison…
amcgregor May 31, 2017
bbaa06d
Make uninstallation verbose.
amcgregor May 31, 2017
683db05
Pivot now optional test requirements to development requirements.
amcgregor May 31, 2017
00590d0
Armour against missing optional modules.
amcgregor May 31, 2017
a801e15
Hide URI password from repr, tweak compilation/decompilation.
amcgregor Jun 1, 2017
72c89aa
Hide URI password from repr, tweak composition, can resolve relative …
amcgregor Jun 1, 2017
82650aa
Simplification of URIString, consistency cleanup, docstrings.
amcgregor Jun 1, 2017
3b4084c
Correction for import ordering warnings.
amcgregor Jun 1, 2017
f44b553
Added relative resolution tests.
amcgregor Jun 1, 2017
da9f07d
Additional venv ignorance.
amcgregor Jun 20, 2017
5880531
Added docs submodule and tweaked Landscape.io config.
amcgregor Jun 20, 2017
c9ff728
Merge branch 'develop' into feature/heirarchical
amcgregor Sep 5, 2017
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
2 changes: 2 additions & 0 deletions .bandit
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[bandit]
exclude: /env,.eggs,.packaging,.cache
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
.packaging

# Virtual Environment Pseudo-Chroot
.venv
bin
include
lib
Expand All @@ -36,4 +37,3 @@ htmlcov
# Completion Integration
.ropeproject
tags

4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "book"]
path = docs
url = git@github.com:marrow/mongo.git
branch = book
1 change: 1 addition & 0 deletions .landscape.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
max-line-length: 120
ignore-paths:
- docs
- example
python-targets:
- 2
Expand Down
19 changes: 15 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,26 @@ python:
- "3.5"
- "3.6"

env:
- MONGODB_VERSION=3.4.7

matrix:
include:
- python: "3.5"
env: MONGODB_VERSION=3.4.4 NO_PYTZ=1
- python: "3.5"
env: MONGODB_VERSION=3.2.13

before_install:
- wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.4.7.tgz -O /tmp/mongodb.tgz
- wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-${MONGODB_VERSION}.tgz -O /tmp/mongodb.tgz
- tar -xvf /tmp/mongodb.tgz
- mkdir /tmp/data
- ${PWD}/mongodb-linux-x86_64-3.4.7/bin/mongod --dbpath /tmp/data --bind_ip 127.0.0.1 --noauth &> /dev/null &
- ${PWD}/mongodb-linux-x86_64-${MONGODB_VERSION}/bin/mongod --dbpath /tmp/data --bind_ip 127.0.0.1 --noauth &> /dev/null &

install:
- travis_retry pip install --upgrade setuptools pip pytest pytest-cov codecov 'setuptools_scm>=1.9' cffi
- pip install -e '.[development,logger]'
- 'travis_retry pip install --upgrade setuptools pip pytest pytest-cov codecov "setuptools_scm>=1.9" cffi'
- 'pip install -e ".[development]"'
- 'test -n "${NO_PYTZ}" && pip uninstall --yes pytz tzlocal || true'

script:
python setup.py test
Expand Down
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ clean:
rm -rvf build htmlcov

veryclean: clean
rm -rvf *.egg-info .packaging
rm -rvf *.egg-info .packaging/*

test: develop
@clear
Expand All @@ -28,4 +28,3 @@ release:
${PROJECT}.egg-info/PKG-INFO: setup.py setup.cfg marrow/mongo/core/release.py
@mkdir -p ${VIRTUAL_ENV}/lib/pip-cache
pip install --cache-dir "${VIRTUAL_ENV}/lib/pip-cache" -Ue ".[${USE}]"

1 change: 1 addition & 0 deletions docs
Submodule docs added at 9bc522
113 changes: 109 additions & 4 deletions marrow/mongo/core/field/date.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,123 @@
# encoding: utf-8

"""Marrow Mongo Date field specialization.

Commentary on high-level management of timezone casting:

https://groups.google.com/forum/#!topic/mongodb-user/GOMjTJON4cg
"""

from __future__ import unicode_literals

from bson import ObjectId
from datetime import datetime, timedelta, tzinfo
from bson import ObjectId as OID
from collections import MutableMapping
from datetime import datetime, timedelta

from .base import Field
from ...util import utc, utcnow
from ....schema import Attribute

# Conditional dependencies.

try:
from pytz import timezone as get_tz
except ImportError:
get_tz = None

try:
localtz = __import__('tzlocal').get_localzone()
except ImportError:
localtz = None


log = __import__('logging').getLogger(__name__)


class Date(Field):
"""MongoDB date/time storage.

Accepts the following options in addition to the base Field options:

`naive`: The timezone to interpret assigned "naive" datetime objects as.
`timezone`: The timezone to cast objects retrieved from the database to.

Timezone references may be, or may be a callback returning, a `tzinfo`-suitable object, the string name of a
timezone according to `pytz`, the alias 'naive' (strip or ignore the timezone) or 'local' (the local host's)
timezone explicitly. None values imply no conversion.

All dates are converted to and stored in UTC for storage within MongoDB; the original timezone is lost. As a
result if `naive` is `None` then assignment of naive `datetime` objects will fail.
"""

__foreign__ = 'date'
__disallowed_operators__ = {'#array'}

naive = Attribute(default=utc)
tz = Attribute(default=None) # Timezone to cast to when retrieving from the database.

def _process_tz(self, dt, naive, tz):
"""Process timezone casting and conversion."""

def _tz(t):
if t is None:
return

if t == 'local':
if __debug__ and not localtz:
raise ValueError("Requested conversion to local timezone, but `localtz` not installed.")

t = localtz

if not isinstance(t, tzinfo):
if __debug__ and not localtz:
raise ValueError("The `pytz` package must be installed to look up timezone: " + repr(t))

t = get_tz(t)

if not hasattr(t, 'normalize') and get_tz: # Attempt to handle non-pytz tzinfo.
t = get_tz(t.tzname(dt))

return t

naive = _tz(naive)
tz = _tz(tz)

if not dt.tzinfo and naive:
if hasattr(naive, 'localize'):
dt = naive.localize(dt)
elif naive == utc:
dt = dt.replace(tzinfo=naive)
else:
raise ValueError("Must install `pytz` package for timezone support.")

if tz:
if hasattr(tz, 'normalize'):
dt = tz.normalize(dt.astimezone(tz))
else:
dt = dt.astimezone(tz) # Warning: this might not always be entirely correct!

return dt

def to_native(self, obj, name, value):
if not isinstance(value, datetime):
log.warn("Non-date stored in {}.{} field.".format(self.__class__.__name__, ~self),
extra={'document': obj, 'field': ~self, 'value': value})
return value

return self._process_tz(value, self.naive, self.tz)

def to_foreign(self, obj, name, value): # pylint:disable=unused-argument
if isinstance(value, ObjectId):
return value.generation_time
if isinstance(value, MutableMapping) and '_id' in value:
value = value['_id']

if isinstance(value, OID):
value = value.generation_time

elif isinstance(value, timedelta):
value = utcnow() + value

assert isinstance(value, datetime), "Value must be a datetime, ObjectId, or identified document, not: " + \
repr(value)

return value
return self._process_tz(value, self.naive, utc)
18 changes: 8 additions & 10 deletions marrow/mongo/core/field/ttl.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@ class TTL(Date):
__disallowed_operators__ = {'#array'}

def to_foreign(self, obj, name, value):
value = super(TTL, self).to_foreign(obj, name, value)

if isinstance(value, timedelta):
return utcnow() + value

if isinstance(value, datetime):
return value

if isinstance(value, Number):
return utcnow() + timedelta(days=value)
value = utcnow() + value
elif isinstance(value, datetime):
value = value
elif isinstance(value, Number):
value = utcnow() + timedelta(days=value)
else:
raise ValueError("Invalid TTL value: " + repr(value))

raise ValueError("Invalid TTL value: " + repr(value))
return super(TTL, self).to_foreign(obj, name, value)
Empty file.
Loading