-
-
Notifications
You must be signed in to change notification settings - Fork 182
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
remove 'decorator' dependency #1513
Conversation
69057c6
to
fad3e75
Compare
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.
It looks like you ran poetry lock
after you had removed the decorator
/types-decorator
dependencies from pyproject.toml
, which resulted in a full relock of the entire dependency tree. To avoid mixing concerns, could you please restore the old version of poetry lock
and run poetry lock --no-update
instead? The changes to poetry.lock
should be limited to removing the decorator
-related dependencies then.
@sisp changes to lockfile reverted |
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 have a few inline questions.
Do you happen to know why some tests are failing now? Off the top of my head, I'm not sure why these changes would fail those tests. 🤔
poetry.lock
Outdated
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, | ||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, | ||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, | ||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, | ||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, | ||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, | ||
{file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, |
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.
Which version of Poetry are you using? I wonder why, e.g., these locked versions have been removed. 🤔 Specifically here, all Python 3.12 wheel files have been removed; this can't be good.
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 did think that was a touch odd
poetry --version
Poetry (version 1.7.1)
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.
Odd. Could you try running poetry update pexpect pyyaml
and check whether those deleted lines get re-added? Might be a Poetry bug ...
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.
poetry update pexpect pyyaml
no effect
Ah i think i see it. It seems that Doesn't seem like you get all of this to work at once using I'll spend a tiny bit more time on this and see if i can find a resolution |
Head branch was pushed to by a user without write access
so this turned out to be a bit of a rabbit hole. I can fix the issue with def _handle_exceptions(method: Callable[P, int]) -> Callable[P, int]:
def inner(*args: P.args, **kwargs: P.kwargs) -> int:
try:
try:
return method(*args, **kwargs)
except KeyboardInterrupt:
raise UserMessageError("Execution stopped by user")
except UserMessageError as error:
print(colors.red | "\n".join(error.args), file=sys.stderr)
return 1
except UnsafeTemplateError as error:
print(colors.red | "\n".join(error.args), file=sys.stderr)
# DOCS https://github.com/copier-org/copier/issues/1328#issuecomment-1723214165
return 0b100
# See https://github.com/copier-org/copier/pull/1513
inner.__signature__ = inspect.signature(method) # type: ignore[attr-defined]
return inner that works perfectly until i add Adding that changes the behaviour of the |
Thanks for tracing this problem, @danieleades! 🙇 So IIUC, with and without the So, #1506 is blocked in any case as long as we need to support Python 3.8 & 3.9, which we need to keep supporting until EOL. This means, we can't use a decorator if we want #1506. Right? Perhaps we could replace the decorator by a context manager? def main(self, ...):
with _handle_exceptions():
... It would be less elegant but should solve the problem unless I'm missing something. WDYT? |
091a1c4
to
ad9b33e
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #1513 +/- ##
==========================================
- Coverage 97.33% 97.27% -0.07%
==========================================
Files 48 48
Lines 4537 4543 +6
==========================================
+ Hits 4416 4419 +3
- Misses 121 124 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
i think a context manager would be less 'magic' to be honest, so might be worth considering I think this can be made to work as is, just that it's less clear now that this PR adds value, but i personally would argue its still a marginal improvement |
If an upstream fix in I'm a bit undecided about the best way forward (also regarding unblocking #1506). Any opinions, @copier-org/maintainers?
|
just using a plain method to handle errors seems pretty clean to me. Have updated the PR to use this approach |
i did open an upstream issue, but to be honest i think sidestepping the decorator approach entirely is probably the way forward here. It's easier to reason about, and is actually less lines of code |
I agree with @sisp: the worker context manager will let exceptions bubble up on exit, and the function call approach does not catch those. So I'd recommend using the context manager approach for handling exceptions instead. |
@pawamoy Do you happen to have an idea why some locked |
@sisp I don't! I stopped using Poetry more than a year ago 🙂 If I restore the lock file from master branch into this branch, then run poetry.lock --- 1/3 --- TOML
238 238 [package.extras]
239 239 toml = ["tomli"]
240 ...
241 ... [[package]]
242 ... name = "decorator"
243 ... version = "5.1.1"
244 ... description = "Decorators for Humans"
245 ... optional = false
246 ... python-versions = ">=3.5"
247 ... files = [
248 ... {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
249 ... {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
250 ... ]
251 240
252 241 [[package]]
253 242 name = "distlib"
poetry.lock --- 2/3 --- TOML
1503 1492 {file = "types_backports-0.1.3-py2.py3-none-any.whl", hash = "sha256:dafcd61848081503e738a7768872d1dd6c018401b4d2a1cfb608ea87ec9864b9"},
1504 1493 ]
1505 ....
1506 .... [[package]]
1507 .... name = "types-decorator"
1508 .... version = "5.1.8.20240106"
1509 .... description = "Typing stubs for decorator"
1510 .... optional = false
1511 .... python-versions = ">=3.8"
1512 .... files = [
1513 .... {file = "types-decorator-5.1.8.20240106.tar.gz", hash = "sha256:32ff92b33615060d23b9d3760124bdb3506c4aa8d9eb50963cf1a3c20b9ecbbf"},
1514 .... {file = "types_decorator-5.1.8.20240106-py3-none-any.whl", hash = "sha256:14d21e6a0755dbb8f301f2f532b3eab5148f433c69dad2d98bf5bd2b3a2ef4e7"},
1515 .... ]
1516 1494
1517 1495 [[package]]
1518 1496 name = "types-psutil"
poetry.lock --- 3/3 --- TOML
1652 [metadata] 1630 [metadata]
1653 lock-version = "2.0" 1631 lock-version = "2.0"
1654 python-versions = ">=3.8" 1632 python-versions = ">=3.8"
1655 content-hash = "68ae53c03a93971c92d62fdd18a7635f2b9a7d2a42317b781777412020227e01" 1633 content-hash = "e77e027798e8d257d07fee377fb2581be217bbcd761326d043f3b5006e6e870f" (by the way, not sure where this fancy git diff output comes from 😄 I must have installed something extra. EDIT: I thought it was diff-so-fancy, but it looks like it comes from git itself!) |
Thanks, @pawamoy! 🙏 @danieleades, could you try restoring |
I have tried that, doesn't help. If I get the time tonight I'll have a play around with it |
i've used the function approach to also wrap the context manager. It's starting to get a tiny bit unwieldy. it's not at all clear to me how you'd do this with a context manager, as a context manager doesn't allow you to either return a value or re-raise exceptions. What would a context manager based approach look like? |
Reraising seems to be possible when the I think your current approach works. Just one more idea: Would keeping the original decorator approach by replacing the |
sort of. That doesn't give you the opportunity to change the type of the exception. the current code does this- try:
return method(*args, **kwargs)
except KeyboardInterrupt:
raise UserMessageError("Execution stopped by user") i can't think how you can both re-raise the While i think of it, this code snippet should probably be: try:
return method(*args, **kwargs)
except KeyboardInterrupt as e:
raise UserMessageError("Execution stopped by user") from e |
another approach that would work would be to go back to the decorator approach (without the def handle_exceptions(method: Callable[P, int]) -> Callable[P, int]:
def inner(*args: P.args, **kwargs: P.kwargs) -> int:
try:
try:
return method(*args, **kwargs)
except KeyboardInterrupt:
raise UserMessageError("Execution stopped by user")
except UserMessageError as error:
print(colors.red | "\n".join(error.args), file=sys.stderr)
return 1
except UnsafeTemplateError as error:
print(colors.red | "\n".join(error.args), file=sys.stderr)
# DOCS https://github.com/copier-org/copier/issues/1328#issuecomment-1723214165
return 0b100
return inner
# ...
@handle_exceptions
def _main(self, destination_path: cli.ExistingDirectory = ".") -> int:
with self._worker(
dst_path=destination_path,
defaults=self.force or self.defaults,
overwrite=self.force or self.overwrite,
skip_answered=self.skip_answered,
) as worker:
worker.run_recopy()
return 0
def main(self, destination_path: cli.ExistingDirectory = ".") -> int:
"""Call [run_recopy][copier.main.Worker.run_recopy].
Parameters:
destination_path:
Only the destination path is needed to update, because the
`src_path` comes from [the answers file][the-copier-answersyml-file].
The subproject must exist. If not specified, the currently
working directory is used.
"""
return self._main(destination_path: cli.ExistingDirectory) or, equivalently: def handle_exceptions(method: Callable[P, None]) -> Callable[P, int]:
def inner(*args: P.args, **kwargs: P.kwargs) -> int:
try:
try:
method(*args, **kwargs)
return 0
except KeyboardInterrupt:
raise UserMessageError("Execution stopped by user")
except UserMessageError as error:
print(colors.red | "\n".join(error.args), file=sys.stderr)
return 1
except UnsafeTemplateError as error:
print(colors.red | "\n".join(error.args), file=sys.stderr)
# DOCS https://github.com/copier-org/copier/issues/1328#issuecomment-1723214165
return 0b100
return inner
# ...
def main(self, destination_path: cli.ExistingDirectory = ".") -> int:
"""Call [run_recopy][copier.main.Worker.run_recopy].
Parameters:
destination_path:
Only the destination path is needed to update, because the
`src_path` comes from [the answers file][the-copier-answersyml-file].
The subproject must exist. If not specified, the currently
working directory is used.
"""
@handle_exceptions
def inner() -> int:
with self._worker(
dst_path=destination_path,
defaults=self.force or self.defaults,
overwrite=self.force or self.overwrite,
skip_answered=self.skip_answered,
) as worker:
worker.run_recopy()
return inner() |
Thanks for being persistent in trying to solve this problem, @danieleades! 🙏 This last idea has a bit too much duplicate code for my taste. In comparison, I'd prefer the Have you tried |
I haven't- though it does obviate the benefit of eliminating a dependency by introducing a new one |
But perhaps a new one that works in combination with |
I thought |
it may well work, but it may not be necessary to introduce a dependency at all if it only saves 2-3 lines of code. |
Okay, you convinced me. Let's keep the Could you please try to solve the |
i've updated as best i can, unfortunately i can't get the poetry lock behaviour to match the nix environment, and i'm having trouble setting up the nix environment because Would you kindly update this PR by checking it out, updating the lockfile, and committing the change back to this branch? |
If you look at this comment: #1513 (comment), you'll see that you can simply revert any changes to the lock file, and remove the two blocks marked with |
Are you sure? The lock file contains a hash. Do you know that those items are excluded from the hash? |
Yep it was the right hash. I've pushed a commit anyway 😄 |
Cool, I wasn't sure what was included in that hash and have no way to compare! |
OK done! The diff looks nice. |
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.
Perfect! 👌 Thanks for the detailed investigation and also final polishing! 🙏
besides removing an unneeded dependency (always good), using a 'native' decorator function allows for creating a fully-typed decorator