Skip to content

Commit

Permalink
dates and dicts for version 1.2.dev1
Browse files Browse the repository at this point in the history
  • Loading branch information
julienc91 committed Apr 27, 2016
1 parent 7a8f774 commit 89274d6
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 7 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 1.2 - 2016-04-27

New packages `dicts` and `dates`. `dates` provides an easy to use timer class to mesure the execution time
of a block of code. The `dicts` package provides a function to do a safe deep inspection of nested dictionaries.

## 1.1 - 2016-04-17

A new package `file` contains some functions to extract values of any type by reading a file line by line.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ utools
A set of useful functions to use for various purposes in any Python project.

* Author: Julien CHAUMONT (https://julienc.io)
* Version: 1.1
* Date: 2016-04-21
* Version: 1.2.dev1
* Date: 2016-04-27
* Licence: MIT
* Url: http://github.com/julienc91/utools

Expand Down
6 changes: 3 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@
# built documents.
#
# The short X.Y version.
version = '1.1'
version = '1.2'
# The full version, including alpha/beta/rc tags.
release = '1.1'
release = '1.2.dev1'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down Expand Up @@ -121,7 +121,7 @@

# The name for this set of Sphinx documents.
# "<project> v<release> documentation" by default.
#html_title = 'utools v1.1
#html_title = 'utools v1.2.dev1

# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
Expand Down
16 changes: 16 additions & 0 deletions docs/ref_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@
Reference/API
=============

utools.dates module
-------------------

.. automodule:: utools.dates
:members:
:undoc-members:
:show-inheritance:

utools.dicts module
-------------------

.. automodule:: utools.dicts
:members:
:undoc-members:
:show-inheritance:

utools.files module
-------------------

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

setup(
name="utools",
version="1.1",
version="1.2.dev1",
author="Julien Chaumont",
author_email="utools@julienc.io",
description="A set of useful functions to use for various purposes in any Python project",
Expand Down
41 changes: 41 additions & 0 deletions tests/test_dates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-

from utools import dates as udates


def test_timer():

timer = udates.timer()

# no with block, the timer should not have started
assert timer.get() == 0
assert not timer.ongoing()

# a simple with block
with timer:
assert timer.ongoing()
pass
assert not timer.ongoing()
assert timer.get() > 0

# a simple with block with an exception
try:
with timer:
raise SystemError
except SystemError:
pass
assert timer.get() > 0
assert timer.get() == timer.get()

timer.reset()
assert timer.get() == 0
assert not timer.ongoing()

timer.start()
assert timer.ongoing()
assert timer.get() != timer.get()

timer.stop()
assert not timer.ongoing()
assert timer.get() > 0
assert timer.get() == timer.get()
38 changes: 38 additions & 0 deletions tests/test_dicts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-

import pytest
from utools import dicts as udicts


# --- utools.dicts.deep_get ---
def test_deep_get():

d = {"user": {"id": 1, "login": "foo"}, "date": "2016-04-27"}
assert udicts.deep_get(d) == d
assert udicts.deep_get(d, default=3) == d
assert udicts.deep_get(d, "user", "login") == "foo"
assert udicts.deep_get(d, "user") == {"id": 1, "login": "foo"}
assert udicts.deep_get(d, "user", "name") is None
assert udicts.deep_get(d, "user", "name", default="bar") == "bar"
assert udicts.deep_get(d, "user", "login", default="bar") == "foo"

# deep_get should also work with lists
d = [[[3], 4]]
assert udicts.deep_get(d, 0, 0, 0) == 3
assert udicts.deep_get(d, 0, 0) == [3]
assert udicts.deep_get(d, 0, 1) == 4
assert udicts.deep_get(d, 0, 0, 0, 0) is None
assert udicts.deep_get(d, 0, 3, 5, default=17) == 17


# deep_get should be safe and should never raise
@pytest.mark.parametrize("d", [
1,
"foo",
{1, 2, 3},
object(),
int,
None
])
def test_deep_get_with_safety(d):
assert udicts.deep_get(d, "foo", 1, 4) is None
2 changes: 1 addition & 1 deletion utools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-

__version__ = "1.1"
__version__ = "1.2.dev1"
81 changes: 81 additions & 0 deletions utools/dates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-

""" Useful functions to work with dates and durations
"""

from datetime import datetime


class timer:
""" Get the execution time of a block of code.
Example:
The easiest way to use the timer is inside a 'with' statement::
>>> import time
>>> t = timer()
>>> with t:
... time.sleep(1)
>>> t.get()
1.001263
The timer class also provides methods to start and stop the timer when you want::
>>> t = timer()
>>> t.get()
0.
>>> t.start()
>>> t.get()
1.425219
>>> t.stop()
>>> t.get()
2.636786
"""

def __init__(self):
self._start_time = None
self._stop_time = None

def __enter__(self):
self.start()

def __exit__(self, exc_type, exc_value, traceback):
del exc_type, exc_value, traceback
self.stop()

def start(self):
""" Start or restart the timer.
"""
self.reset()
self._start_time = datetime.now()

def stop(self):
""" Stop the timer.
"""
if self.ongoing():
self._stop_time = datetime.now()

def reset(self):
""" Reset the timer.
"""
self._start_time = None
self._stop_time = None

def ongoing(self):
""" Check if the timer is running.
Returns: True if the timer is currently running, False otherwise
"""
return self._start_time is not None and self._stop_time is None

def get(self):
""" Get the current timer value in seconds.
Returns: the elapsed time in seconds since the timer started or until the timer was stopped
"""
now = datetime.now()
if self._start_time:
if self._stop_time:
return (self._stop_time - self._start_time).total_seconds()
return (now - self._start_time).total_seconds()
return 0.
36 changes: 36 additions & 0 deletions utools/dicts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-

""" Useful functions to work with dictionaries.
"""


def deep_get(d, *keys, default=None):
""" Recursive safe search in a dictionary of dictionaries.
Args:
d: the dictionary to work with
*keys: the list of keys to work with
default: the default value to return if the recursive search did not succeed
Returns:
The value wich was found recursively in d, or default if the search did not succeed
Example:
>>> d = {"user": {"id": 1, "login": "foo"}, "date": "2016-04-27"}
>>> deep_get(d, "user", "login")
"foo"
>>> deep_get(d, "user")
{"id": 1, "login": "foo"}
>>> deep_get(d, "user", "name")
None
>>> deep_get(d, "user", "name", default="bar")
"bar"
"""

for key in keys:
try:
d = d[key]
except (KeyError, IndexError, TypeError):
return default
return d

0 comments on commit 89274d6

Please sign in to comment.