1

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)
musbur
  • 567
  • 4
  • 16
  • Did you read [this question](https://stackoverflow.com/questions/18967441/add-a-prefix-to-all-flask-routes)? – Joost Dec 10 '18 at 14:59
  • I did (before asking my question), but that is about prefixing URLs, not application endpoints (= Python functions) – musbur Dec 10 '18 at 15:35
  • Can you move the WSGI script into the flask_application folder. – rfkortekaas Dec 10 '18 at 16:49
  • Note, I've modified the question to a minimal, self-contained example that illustrates the issue. – musbur Dec 10 '18 at 18:47

1 Answers1

1

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
rfkortekaas
  • 6,049
  • 2
  • 27
  • 34
  • Right on. I knew it had to be something simple. Unfortunately the flask documentation doesn't really explain the purpose and function of the name parameters of the Blueprint constructor. Thanks! – musbur Dec 13 '18 at 14:33