falconry / falcon

The no-magic web data plane API and microservices framework for Python developers, with a focus on reliability, correctness, and performance at scale.
https://falcon.readthedocs.io/en/stable/
Apache License 2.0
9.53k stars 945 forks source link

fix: implement `close()` method for asgi static files #1985

Closed Contessina closed 3 years ago

Contessina commented 3 years ago

Summary of Changes

Implement close() method for _AsyncFileReader

Related Issues

Fixes #1963

Pull Request Checklist

This is just a reminder about the most common mistakes. Please make sure that you tick all appropriate boxes. But please read our contribution guide at least once; it will save you a few review cycles!

If an item doesn't apply to your pull request, check it anyway to make it apparent that there's nothing to do.

If you have any questions to any of the points above, just submit and ask! This checklist is here to help you, not to deter you from contributing!

PR template inspired by the attrs project.

codecov[bot] commented 3 years ago

Codecov Report

Merging #1985 (ebca9f9) into master (663417c) will not change coverage. The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff            @@
##            master     #1985   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           63        63           
  Lines         6674      6676    +2     
  Branches      1079      1079           
=========================================
+ Hits          6674      6676    +2     
Impacted Files Coverage Δ
falcon/routing/static.py 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update 663417c...ebca9f9. Read the comment docs.

vytas7 commented 3 years ago

Hi again @Contessina! Just checking if you are planning to work on adding tests for the bug that you fixed? (You could probably adapt my snippet from the issue's description to get started: https://github.com/falconry/falcon/issues/1963#issue-1021755137.)

Contessina commented 3 years ago

Hi again @Contessina! Just checking if you are planning to work on adding tests for the bug that you fixed? (You could probably adapt my snippet from the issue's description to get started: #1963 (comment).)

Hi there. I included the suggestions for the news fragment and also implemented test for this scenario.

As expected, the test fails before my code changes and passes afterwards (tested on python3.8 and pypy3). The test uses a custom exception somewhat counter-intuitively, but I could not find a better way to test the side effect. I am open to suggestions if you think of a better way to implement this.

vytas7 commented 3 years ago

Just using a custom exception that way is fine per se for implementing tests, however it's potentially an issue if we ever decide to address https://github.com/falconry/falcon/issues/1865.

You could instead just monkeypatch that method to a custom function, that would register the call in a local variable/closure, or use unittest.mock, and inspect if the patched object was called.

Moreover, we have recently refactored these tests somewhat, so you may need to check the latest changes coming from the master branch.

wsz commented 3 years ago

Hi! I was researching how to approach the issue, just before @Contessina created the PR. I would recommend moving stream.read() and stream.close() inside a try: ... finally: ... block here in asgi/app.py. This way, we can ensure the stream is always closed at the end, even if read() or any other call raises an exception.

vytas7 commented 3 years ago

Hi @wsz! Spot on regarding restructuring how .close() ought to be ensured in a finally block.

In fact, there is a separate issue tracking this bug (https://github.com/falconry/falcon/issues/1943) with a lingering PR (https://github.com/falconry/falcon/pull/1949), maybe you would like to take over that one?

vytas7 commented 3 years ago

Hi again @Contessina -- I took the liberty of tweaking the proposed news fragment somewhat, check if I haven't distorted it too much.

Edit: I'll finish reviewing the test later today; it was behaving a bit strange when I was digging a bit more in depth, but that could have well been my fault. It was a misunderstanding on my end; both your code and tests worked fine.

Nevertheless, I went on to refactor slightly in favour of the existing fixture leveraging monkeypatch for two reasons: better reuse of existing test code, and to cleaner handle os.fstat() on the mocked file; your code was working as-is, but it was effectively setting Content-Length: 0, which could have made this test somewhat fragile wrt future refactoring.