Cyclic dependencies when using AuthorizationServer(Client, app) #8
Comments
@moritz89 I can't understand your question. There is a demo: https://github.com/authlib/playground which is working right now. |
That is true. I'll give it a bit more context. In the server documentation you mention that to create the server:
This code would then be placed in Now we are back to my first comment, that this creates a cyclic include. The documentation for Flask-oauthlib does not have this "limitation". |
@moritz89 I still can't get your point.
I mean "Client is defined in the above section of the documentation". Check https://github.com/authlib/playground/blob/master/website/services/oauth2.py for a real example. Do you mean I should improve the documentation? There is no cyclic dependency problem, it there is, you are doing it wrong. |
Sorry for the misunderstanding. The code you are referring to is 100% correct and works, hats off to you. What I am meaning to say is, instead of defining the client above, is there a work-around, so that it is possible to place it in the As a reference, when I write Flask applications I structure them as follows:
Now my question is, is |
@moritz89 Please check the example I provided above.
It can also be initialized lazily with init_app: https://docs.authlib.org/en/latest/flask/oauth2.html#define-server server = AuthorizationServer(Client)
server.init_app(app) Please check out the playground code. https://github.com/authlib/playground/blob/master/website/services/oauth2.py |
@moritz89 Does this fix your problem? |
Hi, thanks for your patience first of all. It is interesting that the structure, where the db object is created, is different from all other Flask projects that I know. You actually create a base class, in the model folder, from which all other models derive themselves. What effects on the rest of the project does it have, that the db object is created in the models class? Thanks for writing all that code the last few days. I was always referring to the locally cloned repo, where only the client, not the server was implemented. |
The issue is closed but just sharing how I got it working. Might be helpful for others who are looking for a similar solution.
Snippet A: (goes in from authlib.flask.oauth2 import AuthorizationServer
from .models import Client
oauthserver = AuthorizationServer(Client) Snippet B: (goes in app = Flask(__name__)
db = SQLAlchemy(app)
from app.oauth_module import oauthserver
oauthserver.init_app(app)
# register all blueprints
from app.oauth_module.controllers import oauth_blueprint
app.register_blueprint(oauth_blueprint)
# ....
db.create_all() The from app.oauth_module import oauthserver
from flask import Blueprint
# ..
# Define the grant classes
# ..
oauthserver.register_grant_endpoint(PasswordGrant)
# ..
oauth_blueprint = Blueprint('oauth_blueprint', __name__)
@oauth_blueprint.route('/oauth/token', methods=['POST'])
def issue_token():
return oauthserver.create_token_response() |
I finally got it. You are putting
Here is how it looks in # models/base.py
db = SQLAlchemy()
# models/__init__.py
from .base import db And then importing it to the root: # my_project/__init__.py
from my_project.models import db
db.init_app(app) I'm wondering where did you learnt your Flask directory structure. Flask is very flexible, there is no certain folder structure for it. But putting your |
Not everyone has a good folder structure, there are chances that people don't know how to prevent a cyclic dependency. With this change, people don't need to init Client directly, they can initilize it in `init_app`. Inspired by the issue: #8
@lepture Completely agree on Flask being very flexible. Its flexibility makes it very powerful in the hands of experienced. But people new to Flask or, as in my case, new to Python Web ecosystem, need some structure to begin with. So, I followed this article https://www.digitalocean.com/community/tutorials/how-to-structure-large-flask-applications Thanks for the commit. And thanks for the sample structure, will try to use it in my application. |
Damn. That tutorial is a really bad example. For large application, we are using the factory pattern: |
Will definitely have a look at the best practices. I used the user management scaffolding provided by https://github.com/hack4impact/flask-base. What is your impression of their structure and have you come across any other project that does it better? |
@moritz89 that’s why you have a cyclic dependency issue. It is a bad practice to put those things in the root init file then importing them backwards. Instead, the root init should be a holy place to import other things. This is not just a tip for Flask, but for every language. Keep the root as root. |
As I mentioned above, if you read the official guide on the factory guide, there is an example: def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
from yourapplication.model import db
db.init_app(app) |
Actually authlib playground has a better folder structure, you can learn something from it. |
@moritz89 @iabtyagi I've written a post on folder structure: https://lepture.com/en/2018/structure-of-a-flask-project |
At least in my case, when creating an AuthorizationServer, it requires the Client model. This has the requirement that the models be imported. However, since the models themselves also import
__init__.py
throughfrom .. import db, login_manager
, it creates a cyclic include.Due to this constraint, the next best option is to use flask-oauthlib library. It might make sense to address this issue, either in the documentation or in the code architecturally.
The text was updated successfully, but these errors were encountered: