Repository: sloria/environs

Issue:
Add log_level handler
Support

```
LEVEL=DEBUG
```

```python
log_level = env.log_level('LEVEL') # => logging.DEBUG
```  

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 85902be..169340c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,10 @@
 
 ### 5.1.0 (unreleased)
 
+Features:
+
+- Add `env.log_level` ([#7](https://github.com/sloria/environs/issues/7)).
+
 Other changes:
 
 - Improve typings.
diff --git a/README.md b/README.md
index bca1ed1..95b41eb 100644
--- a/README.md
+++ b/README.md
@@ -54,6 +54,7 @@ export TTL=42
 export ENABLE_LOGIN=true
 export GITHUB_REPOS=webargs,konch,ped
 export COORDINATES=23.3,50.0
+export LOG_LEVEL=DEBUG
 ```
 
 Parse them with environs...
@@ -71,6 +72,7 @@ secret = env("SECRET")  # => raises error if not set
 max_connections = env.int("MAX_CONNECTIONS")  # => 100
 ship_date = env.date("SHIP_DATE")  # => datetime.date(1984, 6, 25)
 ttl = env.timedelta("TTL")  # => datetime.timedelta(0, 42)
+log_level = env.log_level("LOG_LEVEL")  # => logging.DEBUG
 
 # providing a default value
 enable_login = env.bool("ENABLE_LOGIN", False)  # => True
@@ -98,6 +100,7 @@ The following are all type-casting methods of `Env`:
 - `env.timedelta` (assumes value is an integer in seconds)
 - `env.url`
 - `env.uuid`
+- `env.log_level`
 - `env.path` (casts to a [`pathlib.Path`](https://docs.python.org/3/library/pathlib.html))
 
 ## Reading `.env` files
diff --git a/environs.py b/environs.py
index ff4af70..91206b9 100644
--- a/environs.py
+++ b/environs.py
@@ -2,6 +2,7 @@ import contextlib
 import inspect
 import functools
 import json as pyjson
+import logging
 import os
 import re
 import typing
@@ -156,6 +157,17 @@ class PathField(ma.fields.Str):
         return Path(ret)
 
 
+class LogLevelField(ma.fields.Int):
+    def _format_num(self, value):
+        try:
+            return super()._format_num(value)
+        except (TypeError, ValueError) as error:
+            if hasattr(logging, value):
+                return getattr(logging, value)
+            else:
+                raise ma.ValidationError("Not a valid log level.") from error
+
+
 class Env:
     """An environment variable reader."""
 
@@ -173,6 +185,7 @@ class Env:
         datetime=_field2method(ma.fields.DateTime, "datetime"),
         date=_field2method(ma.fields.Date, "date"),
         path=_field2method(PathField, "path"),
+        log_level=_field2method(LogLevelField, "log_level"),
         timedelta=_field2method(ma.fields.TimeDelta, "timedelta"),
         uuid=_field2method(ma.fields.UUID, "uuid"),
         url=_field2method(URLField, "url"),


Test patch:
diff --git a/tests/test_environs.py b/tests/test_environs.py
index 6b67a65..eaa6956 100644
--- a/tests/test_environs.py
+++ b/tests/test_environs.py
@@ -1,5 +1,4 @@
-from __future__ import unicode_literals
-
+import logging
 import uuid
 import datetime as dt
 import urllib.parse
@@ -106,7 +105,7 @@ class TestCasting:
     def test_dict_with_default_from_dict(self, set_env, env):
         assert env.dict("DICT", {"key1": "1"}) == {"key1": "1"}
 
-    def test_decimat_cast(self, set_env, env):
+    def test_decimal_cast(self, set_env, env):
         set_env({"DECIMAL": "12.34"})
         assert env.decimal("DECIMAL") == Decimal("12.34")
 
@@ -157,6 +156,17 @@ class TestCasting:
         res = env.path("PTH")
         assert isinstance(res, pathlib.Path)
 
+    def test_log_level_cast(self, set_env, env):
+        set_env({"LOG_LEVEL": "WARNING", "LOG_LEVEL_INT": str(logging.WARNING)})
+        assert env.log_level("LOG_LEVEL_INT") == logging.WARNING
+        assert env.log_level("LOG_LEVEL") == logging.WARNING
+
+    def test_invalid_log_level(self, set_env, env):
+        set_env({"LOG_LEVEL": "INVALID"})
+        with pytest.raises(environs.EnvError) as excinfo:
+            env.log_level("LOG_LEVEL")
+        assert "Not a valid log level" in excinfo.value.args[0]
+
     @pytest.mark.parametrize("url", ["foo", "42", "foo@bar"])
     def test_invalid_url(self, url, set_env, env):
         set_env({"URL": url})
@@ -320,6 +330,7 @@ class TestDumping:
                 "DTIME": dtime.isoformat(),
                 "URLPARSE": "http://stevenloria.com/projects/?foo=42",
                 "PTH": "/home/sloria",
+                "LOG_LEVEL": "WARNING",
             }
         )
 
@@ -328,6 +339,7 @@ class TestDumping:
         env.datetime("DTIME")
         env.url("URLPARSE")
         env.path("PTH")
+        env.log_level("LOG_LEVEL")
 
         result = env.dump()
         assert result["STR"] == "foo"
@@ -338,6 +350,7 @@ class TestDumping:
         assert result["URLPARSE"] == "http://stevenloria.com/projects/?foo=42"
         assert isinstance(result["PTH"], str)
         assert result["PTH"] == str(pathlib.Path("/home/sloria"))
+        assert result["LOG_LEVEL"] == logging.WARNING
 
     def test_env_with_custom_parser(self, set_env, env):
         @env.parser_for("url")