Repository: benoitc/gunicorn

Issue:
Configs now have to be named as proper Python modules
Traditionally, I name my Gunicorn configuration files for the environment that they run in, such as _gunicorn.conf.dev_ or _gunicorn.conf.prod_. However, as of several hours ago, I started running into this:

```
Failed to read config file: deploy_ui/resources/data/gunicorn.conf.dev
Traceback (most recent call last):
  File "/Users/dustin/development/python/deployment/deploy_ui/lib/python2.7/site-packages/gunicorn/app/base.py", line 94, in load_config_from_file
    execfile_(filename, cfg, cfg)
  File "/Users/dustin/development/python/deployment/deploy_ui/lib/python2.7/site-packages/gunicorn/six.py", line 390, in execfile_
    return exec_(_get_codeobj(fname), *args)
  File "/Users/dustin/development/python/deployment/deploy_ui/lib/python2.7/site-packages/gunicorn/six.py", line 318, in _get_codeobj
    result, fileobj, fullpath = _check_if_pyc(pyfile)
  File "/Users/dustin/development/python/deployment/deploy_ui/lib/python2.7/site-packages/gunicorn/six.py", line 309, in _check_if_pyc
    raise IOError("Cannot find config file. Path maybe incorrect! : {0}".format(filepath))
IOError: Cannot find config file. Path maybe incorrect! : /Users/dustin/development/python/deployment/deploy_ui/deploy_ui/resources/data/gunicorn.conf.dev
Traceback (most recent call last):
  File "./dui_start_gunicorn_dev", line 20, in <module>
    raise EnvironmentError("Gunicorn launch failed.")
EnvironmentError: Gunicorn launch failed.
```

I could only fix it by renaming the configuration file to gunicorn_conf_dev.py .

It looks like your change from:

https://github.com/benoitc/gunicorn/blob/2e84d68edbabbefa4be4d9b3812239b6050ef5d9/gunicorn/six.py#L289

to:

https://github.com/benoitc/gunicorn/blob/e1e5d3638fa25be1eba013783e4940f35846abe2/gunicorn/six.py#L289

is what broke it.

Man. I just lost several hours debugging several applications and several combinations of dependency versions trying to figure out why projects worked and then didn't work. It turns out that I had a couple of different Gunicorn versions, and that it was Gunicorn's changes that had broken everything. It took me extra long to identify it because I usually exclude Gunicorn as a suspect.. It never is.

I searched the issue on Google, and got zero relevant results. Meanwhile, I had sought to verify if anything had changed with how to name Gunicorn configurations and how to launch with them, but there weren't any examples in the documentation. I guess I must've picked-up my conventions from some other project back when I first started using Gunicorn.

I highly recommend that you add such an example for using a configuration file and how to name it, and put a warning in the documentation that configurations must now be named like proper Python modules, but didn't previously have to be.



Discussion:
There is an example in examples: https://github.com/benoitc/gunicorn/blob/master/examples/example_config.py

To be honnest I didn't expect any breaking change here. Gunicorn should still be able to load any file. 

It has been introduced by  8b49de4ad264d629a8ef6e267fe5588172338dd1 to solve #693 .  We should either fix this change or revert it for the coming release. @jerynmathew  would be cool if you could also have a look. I will work on it later in the day.

It looks like it was a major refactor. That being said, I took a brief glance at the current version of the file to see if there were any quick fixes. _check_if_pyc is being called by _get_codeobj (https://github.com/benoitc/gunicorn/blob/8b49de4ad264d629a8ef6e267fe5588172338dd1/gunicorn/six.py#L306), but _get_codeobj isn't called from within its own module. Is _get_codeobj being called from _another_ module (which would be weird, given the naming convention)?


Resolving patch:
diff --git a/gunicorn/six.py b/gunicorn/six.py
--- a/gunicorn/six.py
+++ b/gunicorn/six.py
@@ -357,7 +357,11 @@ def reraise(tp, value, tb=None):
     print_ = getattr(builtins, "print")
 
     def execfile_(fname, *args):
-        return exec_(_get_codeobj(fname), *args)
+        if fname.endswith(".pyc"):
+            code = _get_codeobj(fname)
+        else:
+            code = compile(open(fname, 'rb').read(), fname, 'exec')
+        return exec_(code, *args)
 
 
     del builtins
@@ -382,7 +386,9 @@ def exec_(code, globs=None, locs=None):
 
     def execfile_(fname, *args):
         """ Overriding PY2 execfile() implementation to support .pyc files """
-        return exec_(_get_codeobj(fname), *args)
+        if fname.endswith(".pyc"):
+            return exec_(_get_codeobj(fname), *args)
+        return execfile(fname, *args)
 
 
     def print_(*args, **kwargs):


Test patch: