As far as I can tell, if a directory path contains dots then pkgutil.iter_modules breaks and appears to find modules where none exist.
i.e.
/var/www/www.example.org/src
is treated differently to
/var/www/wwwexampleorg/src
Does this make sense to anyone? I've been debugging a problem around this for 8 hours now and I'm kind of stuck about how to work out what is wrong. Does anyone have any insight into how pkgutil.iter_modules works and if it would break on directory paths which includes dots?
I will admit to being out of my depth on this one so not even sure how to write some sample code to demonstrate the problem. I decided the best way to explain it was briefly and to the point.
I'm using Python 3.4 on Ubuntu.
EDIT:
Apologies this is far from minimal. I'm sorry but the most effective way for me to show this is the sequence of actions that anyone can follow to reproduce:
ubuntu@app:~$ mkdir test
ubuntu@app:~$ cd test
ubuntu@app:~/test$ wget https://github.com/mattupstate/overholt/archive/master.zip
--2014-06-24 08:17:13-- https://github.com/mattupstate/overholt/archive/master.zip
Resolving github.com (github.com)... 192.30.252.128
Connecting to github.com (github.com)|192.30.252.128|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://codeload.github.com/mattupstate/overholt/zip/master [following]
--2014-06-24 08:17:13-- https://codeload.github.com/mattupstate/overholt/zip/master
Resolving codeload.github.com (codeload.github.com)... 192.30.252.144
Connecting to codeload.github.com (codeload.github.com)|192.30.252.144|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [application/zip]
Saving to: ‘master.zip’
[ <=> ] 218,165 386KB/s in 0.6s
2014-06-24 08:17:14 (386 KB/s) - ‘master.zip’ saved [218165]
ubuntu@app:~/test$ unzip master.zip
(output not shown................unzips master.zip)
ubuntu@app:~/test$ ls
master.zip overholt-master
ubuntu@app:~/test$ cd overholt-master/
ubuntu@app:~/test/overholt-master$ source ~/venv2.7/bin/activate
(venv2.7)ubuntu@app:~/test/overholt-master$ ls
alembic alembic.ini Berksfile docs LICENSE manage.py overholt README.md requirements.txt tests Vagrantfile wsgi.py
(venv2.7)ubuntu@app:~/test/overholt-master$ pip install -r requirements.txt
(................installs all requirements)
(venv2.7)ubuntu@app:~/test/overholt-master$ python wsgi.py
* Running on http://0.0.0.0:5000/
* Restarting with reloader
(................YAY WORKS!, NOW TO RENAME ONE OF THE PARENT DIRECTORIES......)
^C(venv2.7)ubuntu@app:~/test/overholt-master$ cd ..
(venv2.7)ubuntu@app:~/test$ cd ..
(venv2.7)ubuntu@app:~$ mv test test.test
(venv2.7)ubuntu@app:~$ cd test.test/
(venv2.7)ubuntu@app:~/test.test$ cd overholt-master/
(venv2.7)ubuntu@app:~/test.test/overholt-master$ python wsgi.py
(................FAILS......)
Traceback (most recent call last):
File "wsgi.py", line 15, in <module>
'/api': api.create_app()
File "/home/ubuntu/test.test/overholt-master/overholt/api/__init__.py", line 23, in create_app
register_security_blueprint=register_security_blueprint)
File "/home/ubuntu/test.test/overholt-master/overholt/factory.py", line 44, in create_app
register_blueprints(app, package_name, package_path)
File "/home/ubuntu/test.test/overholt-master/overholt/helpers.py", line 26, in register_blueprints
m = importlib.import_module('%s.%s' % (package_name, name))
File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
__import__(name)
File "/home/ubuntu/test.test/overholt-master/overholt/api/stores.py", line 13, in <module>
from ..tasks import send_manager_added_email, send_manager_removed_email
File "/home/ubuntu/test.test/overholt-master/overholt/tasks.py", line 12, in <module>
celery = create_celery_app()
File "/home/ubuntu/test.test/overholt-master/overholt/factory.py", line 52, in create_celery_app
app = app or create_app('overholt', os.path.dirname(__file__))
File "/home/ubuntu/test.test/overholt-master/overholt/factory.py", line 44, in create_app
register_blueprints(app, package_name, package_path)
File "/home/ubuntu/test.test/overholt-master/overholt/helpers.py", line 26, in register_blueprints
m = importlib.import_module('%s.%s' % (package_name, name))
File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
__import__(name)
ImportError: No module named overholt
(venv2.7)ubuntu@app:~/test.test/overholt-master$
(................NOW TO IDENTIFY THE CULRPIT??......)
(venv2.7)ubuntu@app:~/test.test$ cd overholt-master/
(venv2.7)ubuntu@app:~/test.test/overholt-master$ ls
alembic alembic.ini Berksfile docs LICENSE manage.py overholt README.md requirements.txt tests Vagrantfile wsgi.py
(venv2.7)ubuntu@app:~/test.test/overholt-master$ cd overholt/
(venv2.7)ubuntu@app:~/test.test/overholt-master/overholt$ ls
api core.pyc factory.pyc forms.pyc helpers.py __init__.py manage middleware.pyc models.pyc services.py settings.py stores tasks.pyc
core.py factory.py forms.py frontend helpers.pyc __init__.pyc middleware.py models.py products services.pyc settings.pyc tasks.py users
(venv2.7)ubuntu@app:~/test.test/overholt-master/overholt$ cat helpers.py
# -*- coding: utf-8 -*-
"""
overholt.helpers
~~~~~~~~~~~~~~~~
overholt helpers module
"""
import pkgutil
import importlib
from flask import Blueprint
from flask.json import JSONEncoder as BaseJSONEncoder
def register_blueprints(app, package_name, package_path):
"""Register all Blueprint instances on the specified Flask application found
in all modules for the specified package.
:param app: the Flask application
:param package_name: the package name
:param package_path: the package path
"""
rv = []
for _, name, _ in pkgutil.iter_modules(package_path):
m = importlib.import_module('%s.%s' % (package_name, name))
for item in dir(m):
item = getattr(m, item)
if isinstance(item, Blueprint):
app.register_blueprint(item)
rv.append(item)
return rv
(venv2.7)ubuntu@app:~$