Skip to content

Commit

Permalink
Merge pull request #45 from joke2k/develop
Browse files Browse the repository at this point in the history
Merge all new features into master for version 0.4
  • Loading branch information
joke2k committed Sep 23, 2015
2 parents 6a8c6cf + 97fa7a1 commit 9fe8c39
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 16 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
language: python
sudo: false
python:
- "2.6"
- "2.7"
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2013 Daniele Faraglia
Copyright (c) 2013-2015, Daniele Faraglia

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
26 changes: 17 additions & 9 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ How to install
How to use
==========

There are only classes, Env and Path
There are only two classes, `environ.Env` and `environ.Path`

::

Expand Down Expand Up @@ -166,6 +166,7 @@ Supported Types
- float
- json
- list (FOO=a,b,c)
- tuple (FOO=(a,b,c))
- dict (BAR=key=val,foo=bar)
- url
- path (environ.Path)
Expand All @@ -189,6 +190,7 @@ Supported Types
- ElasticSearch: elasticsearch://
- Solr: solr://
- Whoosh: whoosh://
- Xapian: xapian://
- Simple cache: simple://
- email_url
- SMTP: smtp://
Expand All @@ -212,35 +214,39 @@ Tests
License
=======

Django-environ is licensed under the MIT License - see the LICENSE.rst file for details
Django-environ is licensed under the MIT License - see the `LICENSE`_ file for details

Changelog
=========

**0.4.0 (2015-09-19)**
`0.4.0 - 23-September-2015 <http://github.com/joke2k/django-environ/compare/v0.3...v0.4>`__
-------------------------------------------------------------------------------------------
- Fix non-ascii values (broken in Python 2.x)
- New email schemes - smtp+ssl and smtp+tls (smtps would be deprecated)
- redis_cache replaced by django_redis

**0.3.1 (2014-09-03)**
- Add tuple support. Thanks to @anonymouzz
- Add LDAP url support for database (django-ldapdb)
- Fix psql/pgsql url

**0.3 (2014-06-03)**
`0.3 - 03-June-2014 <http://github.com/joke2k/django-environ/compare/v0.2.1...v0.3>`__
--------------------------------------------------------------------------------------
- Add cache url support
- Add email url support
- Add search url support
- Rewriting README.rst

**0.2.1 (2013-04-19)**
0.2.1 19-April-2013
-------------------
- environ/environ.py: Env.__call__ now uses Env.get_value instance method

**0.2 (2013-04-16)**
0.2 16-April-2013
-----------------
- environ/environ.py, environ/test.py, environ/test_env.txt: add advanced
float parsing (comma and dot symbols to separate thousands and decimals)
- README.rst, docs/index.rst: fix TYPO in documentation

**0.1 (2013-04-02)**
0.1 02-April-2013
-----------------
- initial release

Credits
Expand Down Expand Up @@ -311,3 +317,5 @@ Credits
.. |license| image:: https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square
:target: https://raw.githubusercontent.com/joke2k/django-environ/master/LICENSE.txt
:alt: Package license

.. _LICENSE: https://github.com/joke2k/django-environ/blob/master/LICENSE.txt
40 changes: 34 additions & 6 deletions environ/environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@ def list(self, var, cast=None, default=NOTSET):
"""
return self.get_value(var, cast=list if not cast else [cast], default=default)

def tuple(self, var, cast=None, default=NOTSET):
"""
:rtype: tuple
"""
return self.get_value(var, cast=tuple if not cast else (cast,), default=default)

def dict(self, var, cast=dict, default=NOTSET):
"""
:rtype: dict
Expand Down Expand Up @@ -214,7 +220,9 @@ def get_value(self, var, cast=None, default=NOTSET, parse_default=False):
:returns: Value from environment or default (if set)
"""

logger.debug("get '{0}' casted as '{1}' with default '{2}'".format(var, cast, default))
logger.debug("get '{0}' casted as '{1}' with default '{2}'".format(
var, cast, default
))

if var in self.scheme:
var_info = self.scheme[var]
Expand Down Expand Up @@ -251,7 +259,7 @@ def get_value(self, var, cast=None, default=NOTSET, parse_default=False):
value = value.lstrip('$')
value = self.get_value(value, cast=cast, default=default)

if value != default or parse_default:
if value != default or (parse_default and value):
value = self.parse_value(value, cast)

return value
Expand All @@ -276,18 +284,27 @@ def parse_value(cls, value, cast):
value = value.lower() in cls.BOOLEAN_TRUE_STRINGS
elif isinstance(cast, list):
value = list(map(cast[0], [x for x in value.split(',') if x]))
elif isinstance(cast, tuple):
val = value.strip('(').strip(')').split(',')
value = tuple(map(cast[0], [x for x in val if x]))
elif isinstance(cast, dict):
key_cast = cast.get('key', str)
value_cast = cast.get('value', str)
value_cast_by_key = cast.get('cast', dict())
value = dict(map(
lambda kv: (key_cast(kv[0]), cls.parse_value(kv[1], value_cast_by_key.get(kv[0], value_cast))),
lambda kv: (
key_cast(kv[0]),
cls.parse_value(kv[1], value_cast_by_key.get(kv[0], value_cast))
),
[val.split('=') for val in value.split(';') if val]
))
elif cast is dict:
value = dict([val.split('=') for val in value.split(',') if val])
elif cast is list:
value = [x for x in value.split(',') if x]
elif cast is tuple:
val = value.strip('(').strip(')').split(',')
value = tuple([x for x in val if x])
elif cast is float:
# clean string
float_str = re.sub(r'[^\d,\.]', '', value)
Expand Down Expand Up @@ -379,7 +396,7 @@ def cache_url_config(cls, url, backend=None):
"""Pulled from DJ-Cache-URL, parse an arbitrary Cache URL.
:param url:
:param overrides:
:param backend:
:return:
"""
url = urlparse.urlparse(url) if not isinstance(url, cls.URL_CLASS) else url
Expand Down Expand Up @@ -663,7 +680,8 @@ def __sub__(self, other):
return self.path('../' * other)
elif isinstance(other, string_types):
return Path(self.__root__.rstrip(other))
raise TypeError("unsupported operand type(s) for -: '{0}' and '{1}'".format(self, type(other)))
raise TypeError(
"unsupported operand type(s) for -: '{0}' and '{1}'".format(self, type(other)))

def __invert__(self):
return self.path('..')
Expand All @@ -683,11 +701,21 @@ def __str__(self):
def __unicode__(self):
return self.__str__()

def __getitem__(self, *args, **kwargs):
return self.__str__().__getitem__(*args, **kwargs)

def rfind(self, *args, **kwargs):
return self.__str__().rfind(*args, **kwargs)

def find(self, *args, **kwargs):
return self.__str__().find(*args, **kwargs)

@staticmethod
def _absolute_join(base, *paths, **kwargs):
absolute_path = os.path.abspath(os.path.join(base, *paths))
if kwargs.get('required', False) and not os.path.exists(absolute_path):
raise ImproperlyConfigured("Create required path: {0}".format(absolute_path))
raise ImproperlyConfigured(
"Create required path: {0}".format(absolute_path))
return absolute_path


Expand Down
11 changes: 11 additions & 0 deletions environ/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def generateData(cls):
BOOL_FALSE_VAR2='False',
PROXIED_VAR='$STR_VAR',
INT_LIST='42,33',
INT_TUPLE='(42,33)',
STR_LIST_WITH_SPACES=' foo, bar',
EMPTY_LIST='',
DICT_VAR='foo=bar,test=on',
Expand Down Expand Up @@ -109,6 +110,11 @@ def test_int_list(self):
self.assertTypeAndValue(list, [42, 33], self.env('INT_LIST', cast=[int]))
self.assertTypeAndValue(list, [42, 33], self.env.list('INT_LIST', int))

def test_int_tuple(self):
self.assertTypeAndValue(tuple, (42, 33), self.env('INT_LIST', cast=(int,)))
self.assertTypeAndValue(tuple, (42, 33), self.env.tuple('INT_LIST', int))
self.assertTypeAndValue(tuple, ('42', '33'), self.env.tuple('INT_LIST'))

def test_str_list_with_spaces(self):
self.assertTypeAndValue(list, [' foo', ' bar'],
self.env('STR_LIST_WITH_SPACES', cast=[str]))
Expand All @@ -134,6 +140,7 @@ def test_url_value(self):
url = self.env.url('URL_VAR')
self.assertEqual(url.__class__, self.env.URL_CLASS)
self.assertEqual(url.geturl(), self.URL)
self.assertEqual(None, self.env.url('OTHER_URL', default=None))

def test_db_url_value(self):
pg_config = self.env.db()
Expand Down Expand Up @@ -562,6 +569,10 @@ def test_comparison(self):
self.assertTrue(Path('/home') == Path('/home'))
self.assertTrue(Path('/home') != Path('/home/dev'))

self.assertEqual(Path('/home/foo/').rfind('/'), str(Path('/home/foo')).rfind('/'))
self.assertEqual(Path('/home/foo/').find('/home'), str(Path('/home/foo/')).find('/home'))
self.assertEqual(Path('/home/foo/')[1], str(Path('/home/foo/'))[1])

self.assertEqual(~Path('/home'), Path('/'))
self.assertEqual(Path('/') + 'home', Path('/home'))
self.assertEqual(Path('/') + '/home/public', Path('/home/public'))
Expand Down
1 change: 1 addition & 0 deletions environ/test_env.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ STR_LIST_WITH_SPACES= foo, bar
STR_VAR=bar
INT_LIST=42,33
CYRILLIC_VAR=фуубар
INT_TUPLE=(42,33)

0 comments on commit 9fe8c39

Please sign in to comment.