Repository: sanic-org/sanic

Issue:
Trouble with import conflict in request.py
```
Traceback (most recent call last):
  File "/env/lib/python3.6/site-packages/sanic/__main__.py", line 4, in <module>
    from sanic.log import logger
  File "/env/lib/python3.6/site-packages/sanic/__init__.py", line 1, in <module>
    from sanic.app import Sanic
  File "/env/lib/python3.6/site-packages/sanic/app.py", line 21, in <module>
    from sanic.server import serve, serve_multiple, HttpProtocol, Signal
  File "/env/lib/python3.6/site-packages/sanic/server.py", line 31, in <module>
    from sanic.request import Request
  File "/env/lib/python3.6/site-packages/sanic/request.py", line 6, in <module>
    from http.cookies import SimpleCookie
ModuleNotFoundError: No module named 'http.cookies'; 'http' is not a package
```

It seems it tries to use sanic's `http.py` instead of the builtin Python library. The `http.py` itself is used only twice, in the `response.py` & `exceptions.py`.
Am I missing something and/or have something misconfigured? 



Discussion:
@hatarist coincidently enough, I had almost the same problem yesterday. In my case, I was from invoking `ipython` from the `sanic` source code directory, resulting on this error:

```
$ pwd
/home/richard/work/sanic/sanic

$ ipython
Traceback (most recent call last):
  File "/home/richard/.pyenv/versions/sanic-boom-3.7.0/bin/ipython", line 7, in <module>
    from IPython import start_ipython
  File "/home/richard/.pyenv/versions/sanic-boom-3.7.0/lib/python3.7/site-packages/IPython/__init__.py", line 55, in <module>
    from .terminal.embed import embed
  File "/home/richard/.pyenv/versions/sanic-boom-3.7.0/lib/python3.7/site-packages/IPython/terminal/embed.py", line 17, in <module>
    from IPython.terminal.ipapp import load_default_config
  File "/home/richard/.pyenv/versions/sanic-boom-3.7.0/lib/python3.7/site-packages/IPython/terminal/ipapp.py", line 28, in <module>
    from IPython.core.magics import (
  File "/home/richard/.pyenv/versions/sanic-boom-3.7.0/lib/python3.7/site-packages/IPython/core/magics/__init__.py", line 18, in <module>
    from .code import CodeMagics, MacroToEdit
  File "/home/richard/.pyenv/versions/sanic-boom-3.7.0/lib/python3.7/site-packages/IPython/core/magics/code.py", line 23, in <module>
    from urllib.request import urlopen
  File "/usr/lib/python3.7/urllib/request.py", line 88, in <module>
    import http.client
ModuleNotFoundError: No module named 'http.client'; 'http' is not a package
```

How is your environment? Can you provide the result of your Python call using the `-v` flag? Example from what I did with IPython:

```
$ python -v -m IPython
```

Cheers!
Sorry for the late reply. Seems like I found the issue.

The problem seems to be the `python -msanic` command. It runs the `__main__.py`, which is located in the sanic's directory.

So if I run `python -msanic microservice.app.app`, it forks using `/bin/sh -c /env/bin/python /env/lib/python3.6/site-packages/sanic/__main__.py microservice.app.app`. Then, if I print out the `sys.path` right in the `__main__.py` (say, third line), it will show the sanic's directory in the first item.

I run the `python -msanic app` from my project's directory (not the `/env/` and obviously not `/env/../site-packages/sanic`, either)
(sorry, `python -v` is way too bloated)

The issue is reproducible using 3.6.5 on both Linux and OS X with such commands:
```
cd /tmp
python3.6 -mvenv testenv
source testenv/bin/activate
pip install sanic==0.8.3
echo 'import sanic\napp = sanic.Sanic()' > test.py
python -msanic test.app --debug
```

with such an output:
```
Traceback (most recent call last):
  File "/private/tmp/testenv/lib/python3.6/site-packages/sanic/__main__.py", line 4, in <module>
    from sanic.log import logger
  File "/private/tmp/testenv/lib/python3.6/site-packages/sanic/__init__.py", line 1, in <module>
    from sanic.app import Sanic
  File "/private/tmp/testenv/lib/python3.6/site-packages/sanic/app.py", line 21, in <module>
    from sanic.server import serve, serve_multiple, HttpProtocol, Signal
  File "/private/tmp/testenv/lib/python3.6/site-packages/sanic/server.py", line 31, in <module>
    from sanic.request import Request
  File "/private/tmp/testenv/lib/python3.6/site-packages/sanic/request.py", line 6, in <module>
    from http.cookies import SimpleCookie
ModuleNotFoundError: No module named 'http.cookies'; 'http' is not a package
```
@hatarist thanks for pointing this out. I think @ahopkins already pointed me out what may be the root cause of this and probably is by the fact we have a file inside the Sanic source code called `http.py`, that also happens to be the name of a builtin Python module. This needs to be changed to avoid these kind of problems. We'll see what we can do :wink:
Yeah, I know. Thanks, I appreciate it.
@vltr @ahopkins do we have an issue to track the http.py rename?
@sjsadowski no, it was on a chat some days ago (referencing this issue). Perhaps we need to re-open it or create a new one referencing this one.
Pardon me. If you guys need a pull request from me with the name change, could do, just not so sure about the name. `helpers.py`, perhaps?
@hatarist that would be awesome. I just added #1326 to reference this. `helpers.py` makes sense.

Resolving patch:
diff --git a/sanic/exceptions.py b/sanic/exceptions.py
--- a/sanic/exceptions.py
+++ b/sanic/exceptions.py
@@ -1,4 +1,4 @@
-from sanic.http import STATUS_CODES
+from sanic.helpers import STATUS_CODES
 
 TRACEBACK_STYLE = '''
     <style>
diff --git a/sanic/http.py b/sanic/helpers.py
similarity index 100%
rename from sanic/http.py
rename to sanic/helpers.py
diff --git a/sanic/response.py b/sanic/response.py
--- a/sanic/response.py
+++ b/sanic/response.py
@@ -10,7 +10,7 @@
 from aiofiles import open as open_async
 from multidict import CIMultiDict
 
-from sanic import http
+from sanic.helpers import STATUS_CODES, has_message_body, remove_entity_headers
 from sanic.cookies import CookieJar
 
 
@@ -103,7 +103,7 @@ def get_headers(
         if self.status is 200:
             status = b'OK'
         else:
-            status = http.STATUS_CODES.get(self.status)
+            status = STATUS_CODES.get(self.status)
 
         return (b'HTTP/%b %d %b\r\n'
                 b'%b'
@@ -141,7 +141,7 @@ def output(
             timeout_header = b'Keep-Alive: %d\r\n' % keep_alive_timeout
 
         body = b''
-        if http.has_message_body(self.status):
+        if has_message_body(self.status):
             body = self.body
             self.headers['Content-Length'] = self.headers.get(
                 'Content-Length', len(self.body))
@@ -150,14 +150,14 @@ def output(
                                        'Content-Type', self.content_type)
 
         if self.status in (304, 412):
-            self.headers = http.remove_entity_headers(self.headers)
+            self.headers = remove_entity_headers(self.headers)
 
         headers = self._parse_headers()
 
         if self.status is 200:
             status = b'OK'
         else:
-            status = http.STATUS_CODES.get(self.status, b'UNKNOWN RESPONSE')
+            status = STATUS_CODES.get(self.status, b'UNKNOWN RESPONSE')
 
         return (b'HTTP/%b %d %b\r\n'
                 b'Connection: %b\r\n'


Test patch: