-
Notifications
You must be signed in to change notification settings - Fork 1k
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
RFC: Dependency conflict: fastapi-utils prevents upgrade to sqlachemy 2.0 #17185
Comments
Try the fork, I don't think the rest is really an option. |
Unfortunately that doesn't work. The implementation of cbv in the fork is significantly different from the original (fastapi-utils). Switching to the fork will raise this error on startup: https://github.com/yuval9313/FastApi-RESTful/blob/master/fastapi_restful/cbv.py#L119. Here's why: the fork checks whether the routes belonging to the router are all unique (see line 118); however it uses only the router path and the http method to disambiguate between the routes. But there're many more route attributes, and among them - In my opinion, given our very heavy use of FastAPI, we should stick to the core library. Furthermore, given that the cbv feature is really non-essential (whereas its implementation adds quite a bit of complexity and increases the chance of more bugs), I suggest we go with option 4: just specify the common dependencies for each route. It's clean, it's straightforward, and it's trivial to fix. To update a module with cbv, we simply add the dependency as an argument to the methods that actually use it, remove the class and convert its methods to functions (kill the |
As per our discussion on the backend channel, I've looked at how class-based views are implemented. I've found that there's no performance gain by using class-based views: the number of calls to |
Thanks for checking, this however was a minute detail of the discussion and does not change my view that we should not make these sweeping changes to cut down on one tiny dependency. |
Summarizing my point here.
Or we can just drop the dependency. Here's why I think it's a good solution:
Dependency management is a hard problem and there's been a ton written on it. Of course we should rely on external software, and of course such reliance comes with risks. What's clear to me (from both literature and experience) is that a decision on including a dependency should not be made lightly. In this case, there is no good reason to rely on fastapi-utils other than "[removing it is] a can of worms where we'll likely break things" (as per channel discussion). But I don't think removing it will break things: it is a lengthy but straightforward modification that is not at all complex compared to lots of other changes we make all the time. |
I really don't think of Galaxy as a FastAPI app - Galaxy has its own opinion about what the structure of web controllers looks like and we've sculpted it and documented it and refined it over many years. Dropping an external dependency and structuring the code more tightly toward FastAPI dependency management... actual ties us to FastAPI more strongly. External dependencies aren't just about the things you import - it is also about structuring your code to shield yourself from the external dependencies. When Marius took the big swing of bringing in FastAPI he was very cognizant of my concerns about the existing structure of the code and brought in class based views to make it feel more Galaxy and in addition to that kindness was kind and let me replace the dependency management features with a standalone library that was more shielded from FastAPI internals and was useful throughout the application and in non-FastAPI contexts. He used FastAPI to implement a Galaxy web framework - he did not make Galaxy a FastAPI application. We moved the code in direction I thought there was full consensus around and balanced everyone's concerns. This feels like another big shift but we're letting our dependencies dictate our code structure and move it in directions there isn't consensus around. I understand the performance might be better as the result of this change, but it isn't in a portion of code we know to be critical and I do not think it is wise to take such a big swing on changes that your peers aren't a fan of. |
I know that you're tasked with replacing SQLAlchemy and this is an approach to accomplish a piece of that task - if Marius and I think it is not the right approach I think it is fair to say... "I've done what I think is the right approach" and put the ball in our courts to find some replacement for CBV. I don't mind doing the work to support the structure that I think is important - if you don't agree it is important. The people doing the work should have a dispropionate say in how it is done - but I think you should give us sometime to propose a less drastic alternative code structure. |
@jmchilton thank you for taking the time to read into the issue. I do appreciate the very detailed and constructive points that you've made. If we want to structure our endpoints in classes with dependencies defined at the method level factored out, #17205 is one way to do that: we only take the one module+test that we're actually using from the original external library and maintain it from now on. That way we don't have to rely on an incompatible external dependency most of which we don't need. |
@jmchilton On a related topic, the only other dependency conflict is graphene-sqlalchemy which is part of the new TS code, added in #15639. We are using version "3.0.0b3", which is pre-SQLAlchemy 2.0. So is "3.0.0b4". The current version is "3.0.0rc1", which is compatible with SQLAlchemy 2.0, however, it appears to come with breaking changes, so the previous beta releases don't work (e.g. |
☝️ I'm working on it. Breaking changes affecting conversion of hybrid properties introduced in graphql-python/graphene-sqlalchemy#371. @jmchilton |
We need to upgrade to SQLAlchemy 2.0 (#12541). However, there is a dependency conflict: Galaxy uses fastapi-utils, which requires SQLAlchemy < 2 (
sqlalchemy = "^1.4,<2.0"
).The only functionality that we use from fastapi-utils is class-based views. This is a small but useful convenience feature which reduces duplication by organizing related route operation functions into classes (which can be done in fastapi) and defining common dependencies on that class (which cannot be done in fastapi) instead of specifying them for each route. Usually there are 1-2 common dependencies per class (service, manager, config, serializer, etc.), although usually it's only the manager or the service that are utilized in every route function.
It is unlikely that the fastapi-utls project will add support for SQLAlchemy 2.0 in the near future. There is an issue and a PR; however, the project appears to be inactive (see this discussion in a fork: yuval9313/FastApi-RESTful#227).
The class-based-views feature has a relatively straightforward implementation, but it's not a one-liner. Its test support is minimal.
I've double-checked FastAPI; there's nothing that can substitute class-based views, I think.
I see the following options:
Simplest option. Switch to an existing fork: FastApi-RESTful. It has a minimal install which does not include SQLAlchemy, so it will give us only 2 additional dependencies: annotated-types and pydantic-core (fastapi-utils doesn't require anything that's not installed for fastapi).
Painful option. Fork fastapi-utils and drop all but the feature(s) we need or might need. And maintain it.
Dependency-free option. Reimplement the feature as a our own native module (crediting the author, of course). This is not ideal, since this would be a fastapi utility with no Galaxy-specific functionality, and as such it really doesn't belong in our core code base.
Most lightweight/nuclear option. Forget about convenience and just specify the common dependencies for each route. There are not a lot, so that might be not that bad.
Unless there are other/better options, and given that cbv is a relatively minor improvement and has to do with code readability, but not performance or added functionality, I'm leaning towards option 4 as the most practical.
What do others think?
The text was updated successfully, but these errors were encountered: