-
-
Notifications
You must be signed in to change notification settings - Fork 397
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
Import testing dynamically, install requests as extra dependency #174
Conversation
Have we considered the option of vendoring in this The only people that would break is then anyone relying on requests via our dependency without listing it in their own dependencies, which wouldn't be many as I think most would be using an async client, and not really our problem anyway. |
Starlite has several potentially optional dependencies: |
Thanks @vrslev - makes sense to look at all that together indeed. If you look at #165 I'm considering using package extras for centralizing dev dependency specification across poetry and tox, so at least for the requests one - if we have to keep it (which I'm pretty sure we don't) - there'd be a If you are playing around with the codebase I'd be interested in how you go with the workflow that I'm building there for testing locally across python versions. Do you have a pattern that you use for that sort of thing independent of this project? |
@peterschutt If you want reproducible workflow for testing multiple Python versions, you'd have to use |
Yep, using I'm certainly not running tests across all versions while I'm iterating over code, but I much prefer to find any errors locally before having to wait on CI to find them. Cheers for the input. |
@Bobronium -- very nice PR. Please look into why there is a test failure on v3.10. @peterschutt whats your suggestion regarding vendoring? I don't quite understand. |
|
||
# pylint: disable=import-outside-toplevel | ||
def __getattr__(name: str) -> Any: | ||
"""Provide lazy importing as per https://peps.python.org/pep-0562/""" |
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.
interesting, I have never seen this used before.
So this will prevent a breaking change by keeping the import from starlite. The problem is how to prevent users from continuing to import from starlite in the future - I assume the IDE will not try to import from here by default, correct?
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.
At first, I also raised deprecation warning, as well as removed these names from __all__
. But in c81d99a I thought, why forbid it if we can handle it gracefully anyway?
Currently, IDE will still import it from starlite package, since it's declared in __all__
and imported in if TYPE_CHECKING
block — so from IDE's perspective not much has changed.
If we decide that we want to discourage it though, then removing the names from __all__
and if TYPE_CHECKING
block would be sufficient for redirecting auto-import to starlite.testing
.
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.
Ok, Im not 100% sure I like this, perhaps deprecations and discouragement are better -- @peterschutt whats your opinion here?
@Goldziher, regarding vendoring: as I understood it, @peterschutt proposed copy-pasting needed code from requests lib to starlite source code, since we borrow only small amount from it. I actually think it makes perfect sense, if we're not using 99% of what comes with requests dependency. |
I see. But thats not actually correct - we also build on the Starlette testing package, which relies on requests extensively. So in either case we are going to have requests around. |
@pytest.mark.skipif( | ||
"starlite" not in sys.modules, reason="Was able to run previous test, no need to launch subprocess for that" | ||
) | ||
def test_testing_import_deprecation_in_subprocess() -> None: |
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.
You can set starite
to None
and achieve the same result. Example: https://github.com/vrslev/ikea-api-client/blob/1b9003111ed774751705ed14076dbb0882a24bd0/tests/test_init.py
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.
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.
For some reason, It worked If I ran test separately, but not when they all ran with pytest. I tried importlib.reload()
as well.
Having a clean subprocess is slower, but more right in terms of what we expect to get. Reloading modules when they already were imported somewhere may cause weird bugs when some_module.reloaded_module.Class is not reloaded_module.Class
if some_module
imported reloaded_module
before it was reloaded and check is happening after.
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 be more specific:
reloaded_module.py
class Class:
pass
some_module.py
from reloaded_module import Class
instance = Class()
main.py
import sys
import reloaded_module
import some_module
assert isinstance(some_module.instance, reloaded_module.Class), "Before reload"
del sys.modules["reloaded_module"]
import reloaded_module
assert isinstance(some_module.instance, reloaded_module.Class), 'After reload'
Running main.py will result in
Traceback (most recent call last):
File "main.py", line 10, in <module>
assert isinstance(some_module.instance, reloaded_module.Class), 'After reload'
AssertionError: After reload
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 don’t think it matters because tests are isolated from each other 🤔
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 wouldn't say tests are really isolated. To some degree, maybe. But all modules are still shared.
Tests are collected first, then executed. Almost all of the imports are done during collection phase.
If then one module is reloaded, there still might be a conflict between what's already imported in other tests modules later in execution.
If it's still unclear what I mean, I'm pretty sure I can come up with another example.
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.
No, I get it, thanks :)
@Goldziher, CI is still failing, but I think it's unrelated to the changes:
|
yes, its not because of you. |
please rebase |
This allows to get rid of requests dependency for runtime environments.
Since we can import it dynamically, why forbid it anyway?
Co-authored-by: Na'aman Hirschfeld <[email protected]>
Co-authored-by: Na'aman Hirschfeld <[email protected]>
Shouldn't take this long, but it might help to understand if something goes wrong.
9fc7ace
to
39ed55a
Compare
No, that's not correct. Requests is a dependency of the So, if we are relying on functionality in starlette that requires
We have hundreds of transitive dependencies, that doesn't justify this change IMO. I have utmost respect for the work put in here, but the complexity to payoff ratio of this PR is way off IMO. I'm 100% sure we should be just vendoring that class in, in a private module so that it is obviously not for downstream users, and get rid of requests altogether from our own dependencies. If starlette need it for their testing things, then we rely on their |
Ok, fair enough. Let's switch to this solution in that case. Are you up to it @Bobronium ? |
Sorry, up to what exactly? |
I was wondering if you'd like to implement that. Or not. |
TL;DR: no :) For further details, please see: #179 |
Guys, #179 isn't the right solution. My initial enthusiasm didn't factor in all of the urllib3 deps, I read them as stdlib imports when I looked while first forming my opinion. It wouldn't be so bad if we could depend on urllib3 instead of requests and then just vendor in the requests class, but then that doesn't solve this:
As without requests, that doesn't work anymore and we don't rely on starlette's I think the "right" solution to this is that the testing utilities aren't brought into the top-level namespace at all and then when someone does So lets merge this in, and I hope we can move toward a 2.0 where in the |
Ok, that happened fast. We didn't address #174 (comment) before merging, so please be aware that IDEs still gonna autoimport |
@Bobronium apologies, I missed that - no release has been made so we can always amend/walk back.
It seems like the obvious fix, but what are the implications? E.g., say I have |
So if I have
With
Just to make sure I'm on the same page. I get no errors from mypy or IDE, and that is because we have Also a shame that pytest seems to be stripping out the error message pointing to the extra install requirement. |
If requests are installed, correct.
Exactly. |
Yeh ok, I'm kinda OK with the tests breaking - can just add So if the proposed fix for that is removing Deprecating also makes me feel overall better about this as a solution as at least I know there is a sunset clause on how long we have to keep it. Just a comment: I really don't think there is a net upside with having so much imported in |
@Bobronium FYI I've opened a new issue for this seeing that everything has been closed off already. Thanks for your work on this, up to you or not if you want to pick up this extra stuff. Just LMK either way as I'll work on it otherwise. |
@peterschutt, I think it makes sense to mention this PR in the issue you've created, this will create a backlink that will be visible here. For history and convenience :) |
good point, cheers |
Closes #130