Repository: capless/envs

Issue:
allow_none=True, type "integer" -> error
hi

thank you for your usefull package :)

i think i've found one small bug.

```
>>> from envs import env
>>> PAGE_CACHE=env("PAGE_CACHE", None, "integer", allow_none=True)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/tlb/.cache/pypoetry/virtualenvs/homepage-B7IEgj7y-py3.8/lib/python3.8/site-packages/envs/__init__.py", line 57, in __call__
    return self.validate_type(value, self.valid_types[var_type], key)
  File "/home/tlb/.cache/pypoetry/virtualenvs/homepage-B7IEgj7y-py3.8/lib/python3.8/site-packages/envs/__init__.py", line 66, in validate_type
    return klass(ast.literal_eval(value))
  File "/usr/lib/python3.8/ast.py", line 96, in literal_eval
    return _convert(node_or_string)
  File "/usr/lib/python3.8/ast.py", line 95, in _convert
    return _convert_signed_num(node)
  File "/usr/lib/python3.8/ast.py", line 74, in _convert_signed_num
    return _convert_num(node)
  File "/usr/lib/python3.8/ast.py", line 66, in _convert_num
    raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: None
```

i would expect `None` and not an exception

Discussion:

Patch:
diff --git a/envs/__init__.py b/envs/__init__.py
index 9d6bbce..4a0b860 100644
--- a/envs/__init__.py
+++ b/envs/__init__.py
@@ -48,12 +48,14 @@ class Env(object):
                 json.dump({'key': key, 'var_type': var_type, 'default': default, 'value': os.getenv(key)}, f)
                 f.write(',')
         value = os.getenv(key, default)
-        if not value and not allow_none:
-            raise EnvsValueException('{}: Environment Variable Not Set'.format(key))
         if not var_type in self.valid_types.keys():
             raise ValueError(
                 'The var_type argument should be one of the following {0}'.format(
                     ','.join(self.valid_types.keys())))
+        if value is None:
+            if not allow_none:
+                raise EnvsValueException('{}: Environment Variable Not Set'.format(key))
+            return value
         return self.validate_type(value, self.valid_types[var_type], key)
 
     def validate_type(self, value, klass, key):


Test patch:
diff --git a/envs/tests.py b/envs/tests.py
index 741ad43..1b066df 100644
--- a/envs/tests.py
+++ b/envs/tests.py
@@ -14,6 +14,7 @@ except ImportError:
 import sys
 
 from envs import env
+from envs.exceptions import EnvsValueException
 
 class EnvTestCase(unittest.TestCase):
     def setUp(self):
@@ -113,6 +114,40 @@ class EnvTestCase(unittest.TestCase):
         self.assertEqual(env('HELLO', 'true', var_type='boolean'), True)
         self.assertEqual(env('HELLO', Decimal('3.14'), var_type='decimal'), Decimal('3.14'))
 
+    def test_without_defaults_allow_none(self):
+        self.assertEqual(env('HELLO'), None)
+        self.assertEqual(env('HELLO', var_type='integer'), None)
+        self.assertEqual(env('HELLO', var_type='float'), None)
+        self.assertEqual(env('HELLO', var_type='list'), None)
+
+    def test_without_defaults_disallow_none(self):
+        with self.assertRaises(EnvsValueException):
+            env('HELLO', allow_none=False)
+        with self.assertRaises(EnvsValueException):
+            env('HELLO', var_type='integer', allow_none=False)
+        with self.assertRaises(EnvsValueException):
+            env('HELLO', var_type='float', allow_none=False)
+        with self.assertRaises(EnvsValueException):
+            env('HELLO', var_type='list', allow_none=False)
+
+    def test_empty_values(self):
+        os.environ.setdefault('EMPTY', '')
+        self.assertEqual(env('EMPTY'), '')
+        with self.assertRaises(SyntaxError):
+            env('EMPTY', var_type='integer')
+        with self.assertRaises(SyntaxError):
+            env('EMPTY', var_type='float')
+        with self.assertRaises(SyntaxError):
+            env('EMPTY', var_type='list')
+        with self.assertRaises(SyntaxError):
+            env('EMPTY', var_type='dict')
+        with self.assertRaises(SyntaxError):
+            env('EMPTY', var_type='tuple')
+        with self.assertRaises(ValueError):
+            env('EMPTY', var_type='boolean')
+        with self.assertRaises(ArithmeticError):
+            env('EMPTY', var_type='decimal')
+
 '''
 Each CLI Test must be run outside of test suites in isolation
 since Click CLI Runner alters the global context