"ImportError: module 'xxxxxxxx' has no attribute 'main'" when porting project to Heroku
<p>I'm attempting to port a Python pyramid app to Heroku.</p>

<p>I must admit that I do not understand the file structure of a Python app, even after reading this very informative thread which seems like it contains all the answers:  <a href="https://what.thedailywtf.com/topic/18922/python-project-structure/27" rel="nofollow">https://what.thedailywtf.com/topic/18922/python-project-structure/27</a></p>

<p>I've got everything set up, so that I can push source updates to Heroku and try to get a build.  The whole process is crashing because of apparently a missing 'main' attribute.  I don't know where to start on this problem, as I don't know what 'main' is, what its structure should be, or what file it should reside in.</p>

<p>I've pasted what I think are the relevant bits below, but please tell me if I've left something out that could be helpful. </p>

<p>I'm attempting to follow the instructions here:  <a href="http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/deployment/heroku.html" rel="nofollow">http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/deployment/heroku.html</a></p>

<p>File structure:</p>

<pre><code>Procfile
run
runapp.py
wsgi.py
---&gt;/corefinance/
----setup.py
----production.ini
-------&gt;/corefinance/
--------__init__.py
</code></pre>

<p>Heroku build errors:</p>

<pre><code>2016-10-10T04:44:45.496214+00:00 app[web.1]: 
2016-10-10T04:44:45.496215+00:00 app[web.1]: Using /app/.heroku/python/lib/python3.5/site-packages
2016-10-10T04:44:45.497067+00:00 app[web.1]: Searching for zope.deprecation==4.1.1
2016-10-10T04:44:45.497245+00:00 app[web.1]: Best match: zope.deprecation 4.1.1
2016-10-10T04:44:45.497356+00:00 app[web.1]: Adding zope.deprecation 4.1.1 to easy-install.pth file
2016-10-10T04:44:45.497742+00:00 app[web.1]: 
2016-10-10T04:44:45.497745+00:00 app[web.1]: Using /app/.heroku/python/lib/python3.5/site-packages
2016-10-10T04:44:45.498530+00:00 app[web.1]: Searching for Mako==1.0.0
2016-10-10T04:44:45.498709+00:00 app[web.1]: Best match: Mako 1.0.0
2016-10-10T04:44:45.498818+00:00 app[web.1]: Adding Mako 1.0.0 to easy-install.pth file
2016-10-10T04:44:45.503267+00:00 app[web.1]: Installing mako-render script to /app/.heroku/python/bin
2016-10-10T04:44:45.503522+00:00 app[web.1]: 
2016-10-10T04:44:45.503524+00:00 app[web.1]: Using /app/.heroku/python/lib/python3.5/site-packages
2016-10-10T04:44:45.503725+00:00 app[web.1]: Finished processing dependencies for corefinance==0.0
2016-10-10T04:44:46.082134+00:00 app[web.1]: Traceback (most recent call last):
2016-10-10T04:44:46.082145+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/setuptools-25.2.0-py3.5.egg/pkg_resources/__init__.py", line 2238, in resolve
2016-10-10T04:44:46.082291+00:00 app[web.1]: AttributeError: module 'corefinance' has no attribute 'main'
2016-10-10T04:44:46.082295+00:00 app[web.1]: 
2016-10-10T04:44:46.082296+00:00 app[web.1]: During handling of the above exception, another exception occurred:
2016-10-10T04:44:46.082297+00:00 app[web.1]: 
2016-10-10T04:44:46.082299+00:00 app[web.1]: Traceback (most recent call last):
2016-10-10T04:44:46.082334+00:00 app[web.1]:   File "runapp.py", line 8, in &lt;module&gt;
2016-10-10T04:44:46.082511+00:00 app[web.1]:     app = loadapp('config:production.ini', relative_to='./corefinance/')
2016-10-10T04:44:46.082519+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/paste/deploy/loadwsgi.py", line 247, in loadapp
2016-10-10T04:44:46.082666+00:00 app[web.1]:     return loadobj(APP, uri, name=name, **kw)
2016-10-10T04:44:46.082668+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/paste/deploy/loadwsgi.py", line 271, in loadobj
2016-10-10T04:44:46.082894+00:00 app[web.1]:     global_conf=global_conf)
2016-10-10T04:44:46.082898+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/paste/deploy/loadwsgi.py", line 296, in loadcontext
2016-10-10T04:44:46.083142+00:00 app[web.1]:     global_conf=global_conf)
2016-10-10T04:44:46.083165+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/paste/deploy/loadwsgi.py", line 320, in _loadconfig
2016-10-10T04:44:46.083511+00:00 app[web.1]:     return loader.get_context(object_type, name, global_conf)
2016-10-10T04:44:46.083514+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/paste/deploy/loadwsgi.py", line 454, in get_context
2016-10-10T04:44:46.083857+00:00 app[web.1]:     section)
2016-10-10T04:44:46.083862+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/paste/deploy/loadwsgi.py", line 476, in _context_from_use
2016-10-10T04:44:46.084217+00:00 app[web.1]:     object_type, name=use, global_conf=global_conf)
2016-10-10T04:44:46.084221+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/paste/deploy/loadwsgi.py", line 406, in get_context
2016-10-10T04:44:46.084536+00:00 app[web.1]:     global_conf=global_conf)
2016-10-10T04:44:46.084539+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/paste/deploy/loadwsgi.py", line 296, in loadcontext
2016-10-10T04:44:46.084822+00:00 app[web.1]:     global_conf=global_conf)
2016-10-10T04:44:46.084826+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/paste/deploy/loadwsgi.py", line 328, in _loadegg
2016-10-10T04:44:46.085119+00:00 app[web.1]:     return loader.get_context(object_type, name, global_conf)
2016-10-10T04:44:46.085123+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/paste/deploy/loadwsgi.py", line 620, in get_context
2016-10-10T04:44:46.085560+00:00 app[web.1]:     object_type, name=name)
2016-10-10T04:44:46.085561+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/paste/deploy/loadwsgi.py", line 646, in find_egg_entry_point
2016-10-10T04:44:46.086013+00:00 app[web.1]:     possible.append((entry.load(), protocol, entry.name))
2016-10-10T04:44:46.086015+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/setuptools-25.2.0-py3.5.egg/pkg_resources/__init__.py", line 2230, in load
2016-10-10T04:44:46.086217+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.5/site-packages/setuptools-25.2.0-py3.5.egg/pkg_resources/__init__.py", line 2240, in resolve
2016-10-10T04:44:46.086408+00:00 app[web.1]: ImportError: module 'corefinance' has no attribute 'main'
</code></pre>

<p>run</p>

<pre><code>#!/bin/bash
set -e
python ./corefinance/setup.py develop
python runapp.py
</code></pre>

<p>runapp.py</p>

<pre><code>import os

from paste.deploy import loadapp
from waitress import serve

if __name__ == "__main__":
    port = int(os.environ.get("PORT", 5000))
    app = loadapp('config:production.ini', relative_to='./corefinance/')

    serve(app, host='0.0.0.0', port=port)
</code></pre>

<p>./corefinance/setup.py</p>

<pre><code>import os

from setuptools import setup, find_packages

here = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(here, 'README.txt')) as f:
    README = f.read()
with open(os.path.join(here, 'CHANGES.txt')) as f:
    CHANGES = f.read()

requires = [
    'setuptools',
    'markupsafe',
    'pyramid',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
    'zope.sqlalchemy',
    'waitress',
    'docutils',
    'pyramid_exclog',
    'cryptacular',
    'pycrypto',
    'webtest',
    ]


setup(name='corefinance',
      version='0.0',
      description='corefinance',
      long_description=README + '\n\n' + CHANGES,
      classifiers=[
        "Programming Language :: Python",
        "Framework :: Pyramid",
        "Topic :: Internet :: WWW/HTTP",
        "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
        ],
      author='',
      author_email='',
      url='',
      keywords='web wsgi bfg pylons pyramid',
      packages=find_packages(),
      include_package_data=True,
      zip_safe=False,
      test_suite='corefinance',
      install_requires=requires,
      entry_points="""\
      [paste.app_factory]
      main = corefinance:main
      [console_scripts]
      initialize_corefinance_db = corefinance.scripts.initializedb:main
      """,
      )
</code></pre>

<p>./corefinance/corefinance/<strong>init</strong>.py</p>

<pre><code>from pyramid.config import Configurator
from sqlalchemy import engine_from_config
from configparser import SafeConfigParser

import os

from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
from pyramid.session import SignedCookieSessionFactory
from .security import groupfinder

from sqlalchemy import engine_from_config

from corefinance.models.meta import DBSession
from corefinance.models.utilities import RootFactory
from corefinance.models.meta import Base


def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """ 

    parser = SafeConfigParser()
    db_ini_file = settings['db_ini_file']
    iniloc = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', db_ini_file))
    read_list = parser.read(iniloc)
    connstring = parser.get('postgres', 'connstring')
    settings['sqlalchemy.url'] = connstring

    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)

    session_factory = SignedCookieSessionFactory(
        settings['session.secret']
        )

    authn_policy = AuthTktAuthenticationPolicy(
        settings['session.secret'], callback=groupfinder, hashalg='sha512')
    authz_policy = ACLAuthorizationPolicy()

    config = Configurator(
        settings=settings,
        root_factory=RootFactory,
        authentication_policy=authn_policy,
        authorization_policy=authz_policy,
        session_factory=session_factory
        )    

    Base.metadata.bind = engine
    config.include('pyramid_chameleon')
    config.include(addroutes)
    config.scan()
    return config.make_wsgi_app()
</code></pre>

<p>I don't think there is a clear reason this isn't working. There's a few things you could improve though.</p>

<p>1) Most <code>setup.py</code> files expect to be executed from their own directory. When you run <code>python some_folder/setup.py develop</code> you are asking for a bad time. <code>pip</code> solves this for you, and you should switch to it by doing <code>pip install -e some_folder</code>.</p>

<p>2) Make sure there isn't an <code>__init.py__</code> in the same folder as the <code>setup.py</code> as that could confuse things for your <code>runapp.py</code> script which is relying on the <code>PYTHONPATH</code> to discover the code, and the current folder is usually on the path meaning the folder with your <code>setup.py</code> could be considered a package (and no <code>main</code> is found in that <code>__init__.py</code>.</p>

<p>The big test to figure this stuff out is just to try and run <code>python</code> in the same environment that's failing and try to <code>import corefinance</code> and see what you get. This should give you some clues as to why it's not working.</p>

python heroku pyramid