Skip to content
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

replacing pkg_resources with importlib #3749

Merged
merged 12 commits into from
Feb 1, 2024
Merged

Conversation

fondbcn
Copy link
Contributor

@fondbcn fondbcn commented Jan 24, 2024

Pull Request Checklist

  • I’ve read the guidelines for contributing.
  • I updated AUTHORS.txt and CHANGES.txt (if the change is non-trivial) and documentation (if applicable).
  • I tested my changes.

Description

Sorry for the old error.
I updated the file with this PR instead.

@Kwpolska
Copy link
Member

There are some more places where pkg_resources is used, could you fix them all?

nikola/nikola.py Outdated
@@ -1031,7 +1031,7 @@ def init_plugins(self, commands_only=False, load_all=False):
extra_plugins_dirs = self.config['EXTRA_PLUGINS_DIRS']
self._loading_commands_only = commands_only
self._plugin_places = [
resource_filename('nikola', 'plugins'),
resources.files('nikola').joinpath('plugins'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resources.files() has been added in Python 3.9 (https://docs.python.org/3/library/importlib.resources.html#importlib.resources.files), while this repo still supports Python 3.8 (https://github.com/getnikola/nikola/blob/master/setup.py#L142).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resources.files() has been added in Python 3.9 (https://docs.python.org/3/library/importlib.resources.html#importlib.resources.files), while this repo still supports Python 3.8 (https://github.com/getnikola/nikola/blob/master/setup.py#L142).

should we use importlib_resources instead of importlib.resources ?

Copy link
Member

@Kwpolska Kwpolska Jan 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Please use the built-in importlib.resources, but only the functions available in Python 3.7 3.8: https://docs.python.org/3.8/library/importlib.html#module-importlib.resources

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Please use the built-in importlib.resources, but only the functions available in Python 3.7 3.8: https://docs.python.org/3.8/library/importlib.html#module-importlib.resources

I can't, with importlib.resources you can choose only between deprecated or newer methods! (all the available methods in 3.8 are not working with newer python releases)

Copy link
Contributor

@felixfontein felixfontein Jan 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can always make code depend on sys.version_info.

@fondbcn
Copy link
Contributor Author

fondbcn commented Jan 24, 2024

There are some more places where pkg_resources is used, could you fix them all?

not in nikola.py ?

@Kwpolska
Copy link
Member

There are some more places where pkg_resources is used, could you fix them all?
not in nikola.py ?

Yes, there are 6 other files.

@fondbcn
Copy link
Contributor Author

fondbcn commented Jan 24, 2024

There are some more places where pkg_resources is used, could you fix them all?
not in nikola.py ?

Yes, there are 6 other files.

how to deal with python 3.8 as felixfontein said ?

@felixfontein
Copy link
Contributor

I would probably create a helper function (in utils.py maybe?) which uses the functions available in Python 3.8. The next step would be to make this function depend on the Python version, since Python 3.11 basically deprecated everything in importlib.resources that was available in Python 3.8...

@felixfontein
Copy link
Contributor

Another alternative might be using https://docs.python.org/3/library/pkgutil.html#pkgutil.get_data instead.

@fondbcn
Copy link
Contributor Author

fondbcn commented Jan 25, 2024

Another alternative might be using https://docs.python.org/3/library/pkgutil.html#pkgutil.get_data instead.

will "pkgutil" be widely compatible ?

@felixfontein
Copy link
Contributor

According to the docs it's been available since at least Python 2.6.

@fondbcn
Copy link
Contributor Author

fondbcn commented Jan 26, 2024

hoping this works.
strangely some files require str() !

nikola/nikola.py Outdated
@@ -1031,7 +1031,7 @@ def init_plugins(self, commands_only=False, load_all=False):
extra_plugins_dirs = self.config['EXTRA_PLUGINS_DIRS']
self._loading_commands_only = commands_only
self._plugin_places = [
resource_filename('nikola', 'plugins'),
str(resources.path('nikola', 'plugins')) if sys.version_info.minor == 8 else str(resources.files('nikola').joinpath('plugins')),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Instead of repeating the same version check everywhere, please instead make a helper function in utils.py.
  2. Please make it so your version check won’t break for Python 4.8, and consider making it <= instead of == while doing that.
  3. What do the functions return so that they need str? If it’s a pathlib.Path, it would be desirable to switch other things to Paths instead of working with strings.

nikola/nikola.py Outdated
builtin_sc_dir = resource_filename(
'nikola',
os.path.join('data', 'shortcodes', utils.get_template_engine(self.THEMES)))
builtin_sc_dir = str(resources.path('nikola')) if sys.version_info.minor == 8 else str(resources.files('nikola').joinpath(os.path.join('data', 'shortcodes', utils.get_template_engine(self.THEMES))))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two things are not equivalent, this is why a function in utils would be a better choice.

@Kwpolska
Copy link
Member

Please fix the failing tests and linting errors.

@fondbcn
Copy link
Contributor Author

fondbcn commented Jan 27, 2024

Please fix the failing tests and linting errors.

I have no idea why resources.path() is not working!

Copy link
Contributor

@felixfontein felixfontein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like I forgot to send this review. Here it is.

nikola/utils.py Outdated Show resolved Hide resolved
nikola/utils.py Outdated Show resolved Hide resolved
@Kwpolska
Copy link
Member

To understand the 3.8 test failures, you can try running the tests locally, but first changing the code so that the 3.8 version runs on all Python versions (or you could install 3.8, but it’s probably not worth it).
The test failures in 3.9+ are unrelated to your code (#3753).

@fondbcn
Copy link
Contributor Author

fondbcn commented Jan 29, 2024

To understand the 3.8 test failures, you can try running the tests locally, but first changing the code so that the 3.8 version runs on all Python versions (or you could install 3.8, but it’s probably not worth it). The test failures in 3.9+ are unrelated to your code (#3753).

I tried every method in https://docs.python.org/3.8/library/importlib.html#module-importlib.resources , but nothing is working on 3.8 !
how newer files().joinpath() avoid this issue ???

@felixfontein
Copy link
Contributor

The documentation of importlib.resources.path() says:

Return the path to the resource as an actual file system path. This function returns a context manager for use in a with statement. The context manager provides a pathlib.Path object.

(Emphasis is mine.)

So it returns a context manager, not directly a path. Your code is treating it as a function which returns a path. That doesn't work. Instead of return str(resources.path(package, resource)), you have to do

        with resources.path(package, resource) as path:
            return str(path)

This only works for resources that are not part of an archive. For this to work with resources in an archive, you need to implement a caching solution. Which might be easier if not all uses of resource_filename would be routed through the same utils function call.

I guess one question is how much complexity we want to add for Python 3.8. @Kwpolska what do you think?

@Kwpolska
Copy link
Member

This only works for resources that are not part of an archive. For this to work with resources in an archive, you need to implement a caching solution. Which might be easier if not all uses of resource_filename would be routed through the same utils function call.

What’s an archive? We don’t support .egg or zipfile.

If the with statement is enough to fix 3.8, we should do that. If it isn’t, we can use pkg_resources or a backport of importlib_resources on 3.8 (but only 3.8, with a conditional requirement)

@felixfontein
Copy link
Contributor

If we don't support zipfiles or directly running from eggs, then yeah, just doing a return inside the with should be fine.

@fondbcn
Copy link
Contributor Author

fondbcn commented Jan 29, 2024

If we don't support zipfiles or directly running from eggs, then yeah, just doing a return inside the with should be fine.

I tried the "with" on path() but the test is still failing.
The documentation of importlib.resources (3.9+) says that path() is equivalent to as_file(files().joinpath()), however read() also didn't work.

@fondbcn
Copy link
Contributor Author

fondbcn commented Jan 30, 2024

I found a solution that works for all 3.8 and 3.9+ (at least for me), just adding some init.py in data/ and removing os.path.join .
However the test time is longer.

nikola/data/__init__.py Outdated Show resolved Hide resolved
nikola/data/samplesite/files/__init__.py Outdated Show resolved Hide resolved
nikola/utils.py Outdated Show resolved Hide resolved
nikola/utils.py Outdated Show resolved Hide resolved
nikola/nikola.py Outdated Show resolved Hide resolved
@Kwpolska
Copy link
Member

Kwpolska commented Feb 1, 2024

Please fix the test failures.

@Kwpolska Kwpolska linked an issue Feb 1, 2024 that may be closed by this pull request
3 tasks
@Kwpolska Kwpolska enabled auto-merge (squash) February 1, 2024 22:12
@Kwpolska Kwpolska merged commit 4541149 into getnikola:master Feb 1, 2024
11 checks passed
@Kwpolska
Copy link
Member

Kwpolska commented Feb 1, 2024

Thanks for your contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Replace use of pkg_resources with importlib.resources
3 participants