Fix importlib.metadata.files workaround #702
No reviewers
Labels
No Label
blocked
bug
data loss
design finalized
good first issue
new feature area
question / support
security
waiting for response
No Milestone
No Assignees
2 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: borgmatic-collective/borgmatic#702
Loadingโฆ
Reference in New Issue
Block a user
No description provided.
Delete Branch "kaechele/borgmatic:fix-importlib-files"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Some distributions, such as Fedora, do not install the RECORDS file as
part of a package's dist-info. As a result importlib.metadata.files will
return None.
Use the workaround for these cases as well.
Signed-off-by: Felix Kaechele felix@kaechele.ca
Thanks for taking the time to fix this!
A couple of thoughts:
importlib_metadata
approach, what do you think of ditching that whole code path and doing theos.path.join(os.path.dirname(borgmatic.config.__file__), 'schema.yaml')
thing unconditionally? Does that seem like it'd work in all cases?tests/unit/config/test_validate.py
.Sure thing!
I think it makes sense to just determine the location of the schema based on the
config.__file__
. As long as the Python packaging tooling installs it alongside that file (and so far it does) we should be good.I'll take another look at it and amend the pull request accordingly.
I was hoping to get this fix into the next release. If you won't have a chance to work on this soon, just let me know and I can pick it up from here. Thank you!
b316ccbdc5
to5c6a61fd14
5c6a61fd14
to8d5cc53813
Alright. I've updated my branch. Somehow managed to get it out of sync, hence the force push. Sorry about that. I usually prefer working on branches iteratively and have them squashed into one commit that gets merged at the end.
One thing I was wondering is whether we should validate that a file exists at that path so that we can raise FileNotFoundError from that function if required (which seems to have been the original behaviour in the first place).
No worries! (I'm generally pretty loosey-goosey about my own commits on this project.)
Yes, that seems reasonable. Thank you!
Thanks for doing another round on this! I left some annoying, nit-picky comments on some of the particulars in this PR. If at any point you get tired of the back-and-forth, please let me know and I'd be happy to finish this up.
@ -31,1 +17,3 @@
return os.path.join(os.path.dirname(borgmatic.config.__file__), 'schema.yaml')
schema_path = os.path.join(os.path.dirname(borgmatic.config.__file__), 'schema.yaml')
if os.path.exists(schema_path) and os.path.isfile(schema_path):
Turns out you don't need
exists()
if you've also gotisfile()
!@ -32,0 +19,4 @@
if os.path.exists(schema_path) and os.path.isfile(schema_path):
return schema_path
raise FileNotFoundError
Just raising the exception type like this means that it won't include the filename in the exception, and therefore any error messages won't tell the user what file wasn't found. One way around that is to set the message manually when you raise the error type. But an even easier way might be to actually
open()
the file here. Then you won't need theexists()
/isfile()
checks and it'll conveniently raise aFileNotFoundError
populated with an appropriate filename message.Went with the
open()
approach.@ -23,3 +8,1 @@
)
assert module.schema_filename().endswith('/borgmatic/config/schema.yaml')
module.schema_filename().endswith('/borgmatic/config/schema.yaml')
Now that the unit under test is calling
exists()
/isfile()
(oropen()
as suggested above), those functions need to be mocked out here IMO. Otherwise, you run the risk of the environment in which the tests are running impacting the tests. (I realizeschema.yaml
should always be present.)Additionally, now that you've got an
if
in your unit under test, ideally that code path would be tested as well. Which you could do with a separate test function and judicious use of mocks.I've updated the tests and am getting 100% coverage.
deaa6a9c6f
toc61d63b235
I actually appreciate nitpicky comments about my PRs as an opportunity to learn. Thanks for taking the time.
Awesome, thank you for making these changes!
@ -13,3 +14,1 @@
flexmock(match=lambda path: False, locate=lambda: None),
)
flexmock(os.path).should_receive('dirname').and_return("/var/borgmatic/config")
Another nit: This codebase uses single quotes for strings, but I can make this change after merging.
Ah, yes. I trusted a bit too much in
black
to do its thing ;-)No worries. I do that all the time. ๐