NOTE: Heavily edited from initial question, minimal example included. Original title was misleading as well.
I've spent a few days refactoring a bunch of separate apps and helper modules into one big package with blueprints. The actual Flask stuff is a couple levels below the package's top-level directory, and I've done all my testing in that directory.
After wrapping up the package and installing it, the url_for() calls don't work any more because the endpoints in the app's rules now include the complete path to the blueprint view functions and not just the last bit.
Here's a minimal example that illustrates the issue (files appended below):
This is what the rules look like when the application is run from within its own directory:
$ python foo/test.py
[<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/bar/' (HEAD, OPTIONS, GET) -> bar.index>,
<Rule '/' (HEAD, OPTIONS, GET) -> index>,
<Rule '/other' (HEAD, OPTIONS, GET) -> other>]
...and this is what it looks like when run from the module's base directory:
$ python test.py
[<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/bar/' (HEAD, OPTIONS, GET) -> foo.bar.index>,
<Rule '/' (HEAD, OPTIONS, GET) -> index>,
<Rule '/other' (HEAD, OPTIONS, GET) -> other>]
Notice how the endpoints for "/" and "/other" (defined in the app) stay the same, whereas the endpoint for "/bar/" (defined in a blueprint) gets the package name "foo" prepended. Currently all my url_for() calls use the "short" endpoint path, and I'd like to keep it that way partly I'd hate to have to add the full package name dozens of times, and also because I'm not sure the directory tree will stay the same forever.
This is what the files look like:
$ tree
.
├── foo
│ ├── app.py
│ ├── bar.py
│ ├── __init__.py
│ └── test.py
└── test.py
$ cat ./foo/app.py
import flask
from bar import blp
app = flask.Flask(__name__)
app.register_blueprint(blp, url_prefix='/bar')
@app.route('/')
def index():
pass
@app.route('/other')
def other():
pass
$ cat ./foo/bar.py
import flask
blp = flask.Blueprint(__name__, __name__)
@blp.route('/')
def index():
pass
$ cat ./foo/__init__.py
$ cat ./foo/test.py
from app import app
import pprint
rules = app.url_map.__dict__['_rules']
pprint.pprint(rules)
$ cat ./test.py
from foo.app import app
import pprint
rules = app.url_map.__dict__['_rules']
pprint.pprint(rules)
The issue is generated by the name you assign to the Blueprint. Every rule in a Blueprint is prefixed by the name.
As you are using __name__
as the name for the Blueprint (First argument of the Blueprint constructor). In the testcase foo/test.py
the Blueprint name is bar
. In the testcase test.py
the name of the Blueprint is foo.bar
.
The solution is to rewrite your bar.py
file as follows:
import flask
blp = flask.Blueprint('bar', __name__)
@blp.route('/')
def index():
pass