-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
use the init_app style for use with app factory pattern #8
Conversation
Hi @hoopes ! Thanks for the contribution, sounds like a good idea! Also, can you please look at Python 3.x compatibility? Thank you! |
Yeah, I will be glad to. Also, proving my theory that every time i do something public on the internet, I look like an idiot, I didn't even test thoroughly enough "by hand" - it's not working properly. I will add some automated tests as well. |
Oh no, you're all right, and I'm thankful for your interest in the project! :) Thanks again! |
Am I right or wrong in assuming the Also - the test I added just checks that calling |
I can imagine that is the reason, yes. I wouldn't worry about it too much. Let me try it in the evening, then I'll merge it in. Thanks again! |
Sorry for the delay @hoopes , I added some comments now. The main thing is about not attaching the Also, could you potentially squash this down to a single commit when you're done? Thanks a lot! |
'registry' : registry, | ||
} | ||
|
||
if app: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rycus86 This will call init_app
if the app is passed into the constructor. Is that what you meant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, no, sorry if I wasn't clear. We used to assign self.app
as the app
passed in to the constructor. With your changes, we don't anymore. This is a problem in the register_endpoint
and export_defaults
functions, when we use the original logic, as it now doesn't have that reference - which is why the extra app_context().push()
was necessary in the test setup.
If we hold the reference to the app
passed in to the constructor, we can restore the original logic by using this in those functions:
if app is None:
app = self.app or current_app
maybe i should have tested more thoroughly added a test showing that the app factory pattern also works reducing my cognitive complexity, maybe added small readme blurb about the app factory pattern
b6efa2a
to
183368f
Compare
Commit has been squashed. Not sure if you wanted me to bump the version number as well, but I thought you could handle that with however you do your releases. |
Thanks for the changes @hoopes ! I'll take care of the version numbers, don't worry about that bit. Thanks! |
Hey, I must be missing something obvious, but I don't see any comments - just my one comment about the |
@@ -66,7 +66,7 @@ def echo_status(status): | |||
- Without an argument, possibly to use with the Flask `request` object | |||
""" | |||
|
|||
def __init__(self, app, path='/metrics', | |||
def __init__(self, app=None, path='/metrics', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder whether it would be more sensible to leave app
as a required parameter, and having to pass in None
when you want to do the app factory pattern, so that the common (?) way of doing this is more relevant - if that makes sense.
@@ -82,16 +82,35 @@ def __init__(self, app, path='/metrics', | |||
(will use the default when `None`) | |||
:param registry: the Prometheus Registry to use | |||
""" | |||
self._options = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I see the benefit of doing it this way, we could just pass the necessary parameters to init_app
, which I would also change from **kwargs
parameters to explicit parameters.
tests/test_app_factory.py
Outdated
|
||
class AppFactoryTest(BaseTestCase): | ||
|
||
def metrics_init(self, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd probably rename this to setUp
, and just not use the BaseTestCase
. We could just duplicate the (minimal) required test setup here.
tests/unittest_helper.py
Outdated
@@ -17,6 +17,7 @@ def __init__(self, *args, **kwargs): | |||
def setUp(self): | |||
self.app = Flask(__name__) | |||
self.app.testing = True | |||
self.app.app_context().push() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be necessary for the existing tests. I'll add some comments on how I managed to solve this locally.
@@ -105,8 +124,7 @@ def register_endpoint(self, path, app=None): | |||
if is_running_from_reloader(): | |||
return | |||
|
|||
if app is None: | |||
app = self.app | |||
app = app or current_app |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To keep the previous logic too, we should keep a reference to the app
passed in the constructor (but not in the init_app
function, then this block should change to:
if app is None:
app = self.app or current_app
@@ -162,6 +180,9 @@ def export_defaults(self, buckets=None, group_by_endpoint=False): | |||
by the endpoints' function name instead of the URI path | |||
""" | |||
|
|||
if not app: | |||
app = current_app |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like I mentioned above, this block should change to:
if app is None:
app = self.app or current_app
|
||
def init_app(self, app, **kwargs): | ||
""" | ||
See the arguments for __init__ for more info. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll probably need more explanation on what is this function for, and how to use it, plus perhaps some changes to the comments in __init__
. Although I'm happy to change these and the README after this PR is merged if you prefer.
'registry' : registry, | ||
} | ||
|
||
if app: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, no, sorry if I wasn't clear. We used to assign self.app
as the app
passed in to the constructor. With your changes, we don't anymore. This is a problem in the register_endpoint
and export_defaults
functions, when we use the original logic, as it now doesn't have that reference - which is why the extra app_context().push()
was necessary in the test setup.
If we hold the reference to the app
passed in to the constructor, we can restore the original logic by using this in those functions:
if app is None:
app = self.app or current_app
🤦♂️ sorry, first time requesting changes here... Apparently I need to press a button, not just leave comments. Sorry again, hopefully you should see them now? |
Got it, ok, i'll try to handle this weekend. Thanks! |
Hey, let me know if you're more into this style. I tried to steal the app factory details from flask-sqlalchemy. https://github.com/mitsuhiko/flask-sqlalchemy/blob/master/flask_sqlalchemy/__init__.py#L675 Note that i needed to use |
Hi @hoopes , Sorry, I was unavailable for a few days. Thanks for the changes! Thanks for you work on this! |
And |
Thanks man, this was fun. Appreciate all your help. |
Hey,
I'd love to use this in my flask app, but we use the "app factory" pattern. http://flask.pocoo.org/docs/0.12/extensiondev/#the-extension-code shows an example of this. I tried to do two things here:
app
object to be passed to the constructor.current_app
instead ofself.app
(See the "Note on init_app" near the bottom of that linked section)The
**kwargs
basically copying the constructor args might be a little awkward, but is there for backwards compatibility? Maybe? You could also scrap that, and just leave the constructor args, andinit_app
just take theapp
object.In any case, if you're into this, or would like some changes, please let me know.