Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    regarding the import is not unorthodox per se, it just that usually scoped imports are used in case of circular references or to import a rarely used part of the application/library. Another use case if for cli application where startup time is important (so cli_tool --help does not take 2s )
    Alan Orth
    @alanorth

    OK so let's say I keep the imports in the method, then how do I reference it for patching?

    As a global import it is: patch('package.app.method')

    As a method-scoped import in on_post it should be: patch('package.app.class.on_post.method') ... but that returns an AttributeError.

    Vytautas Liuolia
    @vytas7
    In all fairness, better don't :slight_smile:
    That being said, if you really insist, importing from inside a method should not be different from a global import. You could either prewarm the machinery by calling the method once before all tests, or try passing create=True to mock.patch.
    Alan Orth
    @alanorth
    OK I think I'll move them to global imports. I have more interesting/fun things to do (writing tests!). :P
    Ian Beck
    @onecrayon
    Hey Falcon folks; I setup a cookiecutter template for bootstrapping a basic Falcon 3 WSGI (or FastAPI, another framework we're evaluating) project using the 3 Musketeers setup (basically: docker + make for absurdly easy local development regardless of host OS). I whipped this up for internal use at my company, but if anyone has suggestions for how to improve it, I'd love feedback: https://github.com/onecrayon/cookiecutter-musketeers-python-api In particular, I haven't had a chance to make sure the testing logic actually works for Falcon. (Next up I need to mix Falcon 3 ASGI into things, but that's going to need a lot more testing on my end since it will also require asyncpg and SQLAlchemy 1.4 pre-release.)
    Zoltan Fedor
    @zoltan-fedor
    Hi all, I am hoping to get a confirmation regarding the order of the relative order of hooks and middlewares. Do I see it right the before hooks are always executed AFTER the process_request of all middlewares. So basically there is no way to execute a middleware between a before hook and the resource itself. If that it in fact that case, then unfortunately hooks and middlewares cannot be mixed in all scenarios - not when you would need them to execute in the order of first the hook and then the middleware.
    Zackary Walker
    @zqwalker_gitlab
    I believe that is correct. The only work around I have found is to move the hook to a middleware and have a function check the route and/or the resource class attributes.
    Zoltan Fedor
    @zoltan-fedor
    Thanks @zqwalker_gitlab. I was thinking the same - turning my hooks into middlewares. The documentation of hook seems to suggest that the only difference between hooks and middlewares is that the middleware is globally applied. It should mention somewhere that all middlewares are applied before hooks, so if you want a hook which only applies to certain endpoints only, but you have a middleware following it, then you can't do that with a hook, but must use a middleware and make that hook-like (execute on marked endpoints only). I used to write middlewares that required decorating the methods (just like hooks). It seems there is no point using hooks then, as at any point there might be a need to place a middleware behind it, when the hook would need to be rewritten into a middleware.
    Zackary Walker
    @zqwalker_gitlab
    True, that could be more clear in the docs. For me personally, I've used hooks for route authorization. After authenticating in a middleware, I pass the method name to the hook decorator, where I then check the resouces (where I store permissions) to see if the user has the required permissions. This solves my pain point of not knowing the method that will be exicuted in a middleware, although I could back my way into it through the http method and the route.
    Zoltan Fedor
    @zoltan-fedor
    Unfortunately I have used hooks for authentication (only some endpoints needed authentication, so hooked seemed fine). But now I am trying to add rate limiting - which I wrote as a middleware and as it would need to know the user name, it needs to be past authentication, and now realized that this won't work because of the middleware-hook order. :-) As long as people would be aware that middlewares always come first and hooks can come only after, it would be fine. I feel that the documentation doesn't make this very important point today. Maybe I should do a PR for the documentation to point this out.
    Zackary Walker
    @zqwalker_gitlab
    Could you add the rate limiting to the process_response? This will exicuted after the resource, even if you the user isn't authenticated.
    It should mention somewhere that all middlewares are applied before hooks
    is only true for the process_request and process_resource
    I guess then the issue is checking the limit on the request : (
    Zoltan Fedor
    @zoltan-fedor
    Thanks. Yes, in this specific case it really needs to be before the request gets executed. Rate limiting is being a security feature preventing DOS attacks and such. So yes, while theoretically I could have it after the processing of the resource, it really shouldn't be. But yes, in same cases that might be the solution for mixing middlewares and hooks.
    Yes, I meant the "It should mention somewhere that all middlewares are applied before hooks" for the process_request and process_response and the 'before' hooks. I assume the 'after' hooks and the 'process_response' of the middlewares have a similar relationship - there is a set order and you can't mix- and match the order of hooks and middlewares there either.
    Zackary Walker
    @zqwalker_gitlab
    So move your auth to middleware, and then just store the results in the context and have the hook reject unauthenticated users to auth required routes would be a solution.
    Zoltan Fedor
    @zoltan-fedor
    Yes, that's pretty much the plan now. Turn the auth hook into an auth middleware, so it can run before the rate limit middleware.
    Tim Brown
    @tim-clipchamp

    Hi all. I'm migrating an app over to falcon 2.0.0 (this is part of our wider migration from Python 2 to 3) and I'm having an issue with routing that I would appreciate input on. Specifically, we have:

    api = falcon.API()
    api.add_route('/upload/{service}/auth/token', TokenHandler())
    api.add_route('/upload/youtube/{project_id}/share', ShareHandler())

    When a request to /upload/youtube/auth/token comes in, a project_id (with value auth) is passed to the TokenHandler(). Looking at the default CompiledRouter, I think this is happening due to the tree of nodes type system that it creates. So rather than matching the entire URL, it matches section by section.

    Given this is an existing app and so it's not ideal to be changing paths at this point, is there a reasonable way that I can have project_id not be set for the above URL?

    Zackary Walker
    @zqwalker_gitlab
    Create another route, then reroute request from a middleware when services == youtube.
    1 reply
    Federico Caselli
    @CaselIT
    That seems strange. @tim-clipchamp was that with falcon 2 or 3?
    Federico Caselli
    @CaselIT

    @tim-clipchamp I cannot reproduce it. My test is:

    import falcon
    import falcon.testing
    
    class Resource:
        def __init__(self, name):
            self.name = name
    
        def on_get(self, req, res, **kw):
            print(self.name, kw)
    
    api = falcon.API()
    api.add_route("/upload/{service}/auth/token", Resource('service'))
    api.add_route("/upload/youtube/{project_id}/share", Resource('project'))
    
    client = falcon.testing.TestClient(api)
    client.simulate_get('/upload/foo-bar/auth/token')
    client.simulate_get('/upload/youtube/auth/share')
    client.simulate_get('/upload/youtube/foo-bar/share')

    In all versions I get as output the expected

    service {'service': 'foo-bar'}
    project {'project_id': 'auth'}
    project {'project_id': 'foo-bar'}
    JaivyDaam
    @JaivyDaam

    Hi Everyone, apart from sending/creating middleware between local environment and a cloud service. How would one be able to create Falconista class to request oAuth tokens with proper flow?

    Can't seem to find any resources on that and I would love to use Falcon as a Middleware solution

    Kurt Griffiths
    @kgriffs
    Hi @JaivyDaam, OAuth is a common request and we definitely need to add a recipe for that to our docs... In the meantime I believe @CaselIT or @vytas7 can point you to a couple of projects you can use as a reference. Did you have a specific provider/flow in mind? (e.g., https://developer.okta.com/docs/concepts/oauth-openid/)
    Federico Caselli
    @CaselIT
    Hi. I've started a falcon extension to manage authentication, here https://github.com/CaselIT/falcon-auth2, but as of yet it does not support oauth. You can also look at https://github.com/loanzen/falcon-auth but I don't think it also supports it.
    Neil du Toit
    @NeilduToit13
    Hi I'm looking for input on using multiprocessing.Pool in a Falcon endpoint. Hope this is the right place to ask? I will be deploying with Nginx & UWSGI. I want process-parallelism in computing response. Will it work? How will it interact with uWSGI? Do I need to set any config to allow this? Thanks.
    Vytautas Liuolia
    @vytas7
    Hi @NeilduToit13 !
    That shouldn't generally be a problem, although multiprocessing, itself, can be subject to somewhat tricky edge cases. Furthermore, IIRC multiprocessing.Pool doesn't mix well with Gevent, so make sure you're not mixing and matching them. Are you targeting Linux?
    @NeilduToit13 I remember I was looking into this report: falconry/falcon#1742 , but couldn't reproduce any problems... Which is, OTOH, a positive answer to your question :slight_smile:
    Vytautas Liuolia
    @vytas7
    @NeilduToit13 Check if my attempts to dig into that question could be of any use for you (at least as a starting point): https://github.com/falconry/falcon/issues/1742#issuecomment-660185035 https://github.com/falconry/falcon/issues/1742#issuecomment-660198081
    Vytautas Liuolia
    @vytas7
    Right, so looking into what I did there, one potential pitfall is that you should take care not to fork multiprocessing.Pool instances, otherwise things can get really messed up. If possible, it is best to initialize any multiprocessing.Pools after your worker process has been forked (particularly if you are using more than one worker process in your application server).
    Neil du Toit
    @NeilduToit13
    Thank you for the help @vytas7 ! I am targeting Linux. Going through links now.
    Aah okay that makes sense
    Neil du Toit
    @NeilduToit13
    I'll feedback how it goes. Thanks for help.
    Vytautas Liuolia
    @vytas7
    Just one semi-obvious addition to the above. Needless to say, it is problematic to fork() processes with threads. So, if possible, try to avoid starting any threads in your worker processes, and do not configure uWSGI to use multiple threads per worker. (You can still scale by multiple worker processes if it makes sense for your use case, as in my uWSGI example linked above).
    Neil du Toit
    @NeilduToit13
    Got it, thank you
    Federico Caselli
    @CaselIT
    You can also use spawn to create multiple processes as an alternative
    Tim Brown
    @tim-clipchamp

    @CaselIT thanks for the investigation above about my routing issue. Your test paths are slightly off though. Here's code that reproduces the issue

    import falcon
    import falcon.testing
    
    class Resource:
        def __init__(self, name):
            self.name = name
    
        def on_get(self, req, res, **kw):
            print(self.name, kw)
    
    api = falcon.API()
    api.add_route("/upload/{service}/auth/token", Resource('service'))
    api.add_route("/upload/youtube/{project_id}/share", Resource('project'))
    
    client = falcon.testing.TestClient(api)
    client.simulate_get('/upload/youtube/auth/token')

    The project resource shouldn't be matching (due to the final section of the path being token) and so project_id should not be populated.

    This is with falcon 2.

    1 reply
    Vytautas Liuolia
    @vytas7
    Interesting catch @tim-clipchamp ! I can indeed reproduce what you mean. I'll file an issue (reproducible with both Falcon 2.0 and 3.0 development version).
    Vytautas Liuolia
    @vytas7
    @tim-clipchamp Filed as falconry/falcon#1779
    Federico Caselli
    @CaselIT
    @tim-clipchamp The same test fails all the way back to falcon 1.1, but you mentioned it was working for you on 1.4? If you could try to update the test so that falcon 2 fails and falcon 1.4 does not it would greatly help us. Thanks!
    Vytautas Liuolia
    @vytas7
    I have already tested this on 1.4.1, 2.0 and 3.0.0a2 @CaselIT :arrow_up: Sorry I forgot to add 1.4.1 to the issue.
    Federico Caselli
    @CaselIT

    @tim-clipchamp The same test fails all the way back to falcon 1.1, but you mentioned it was working for you on 1.4? If you could try to update the test so that falcon 2 fails and falcon 1.4 does not it would greatly help us. Thanks!

    nevermind, I was convinced you were updating from falcon 1.4 -> 2, but you do not mention from where you are upgrading. Sorry

    3 replies

    I have already tested this on 1.4.1, 2.0 and 3.0.0a2 @CaselIT :arrow_up: Sorry I forgot to add 1.4.1 to the issue.

    yes, it happens also on 1.3,1.2,1.1 (and probably also 1.0, but it does not have a test client)

    Vytautas Liuolia
    @vytas7
    We probably don't need to dig that deep anyway :slight_smile:

    @CaselIT commented 7 minutes ago
    I've traced this issue since at least falcon 1.1 (and is probably even older, but falcon 1.0 does not have a test client)

    Indeed, I don't think that part has been changed at all since the advent of CompiledRouter.

    Federico Caselli
    @CaselIT
    yes, I was writing the same
    I guess we need to add a dict.pop or something similar
    Vytautas Liuolia
    @vytas7
    Interesting to find it only now :slight_smile:
    Federico Caselli
    @CaselIT
    I guess many use **kw, so it gets ingnored