Skip to content

Commit

Permalink
chore: Transition from pkg_resources API to importlib-resources API
Browse files Browse the repository at this point in the history
  • Loading branch information
farhan committed May 20, 2024
1 parent 003ae98 commit c6801a6
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 24 deletions.
2 changes: 1 addition & 1 deletion xblock/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
XBlock Courseware Components
"""

__version__ = '4.1.0'
__version__ = '4.1.1'
6 changes: 4 additions & 2 deletions xblock/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import warnings
from collections import OrderedDict, defaultdict

import pkg_resources
import importlib.resources
from lxml import etree
from webob import Response

Expand Down Expand Up @@ -157,7 +157,9 @@ def open_local_resource(cls, uri):
if "/." in uri:
raise DisallowedFileError("Only safe file names are allowed: %r" % uri)

return pkg_resources.resource_stream(cls.__module__, os.path.join(cls.resources_dir, uri))
return importlib.resources.files(cls.__module__).joinpath(
os.path.join(cls.resources_dir, uri)
).open('rb')

@classmethod
def json_handler(cls, func):
Expand Down
10 changes: 7 additions & 3 deletions xblock/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
This code is in the Runtime layer.
"""
import functools
import importlib.metadata
import itertools
import logging
import pkg_resources

from xblock.internal import class_lazy

Expand Down Expand Up @@ -100,7 +100,11 @@ def select(identifier, all_entry_points):
if select is None:
select = default_select

all_entry_points = list(pkg_resources.iter_entry_points(cls.entry_point, name=identifier))
all_entry_points = [
entry_point
for entry_point in importlib.metadata.entry_points().get(cls.entry_point, [])
if entry_point.name == identifier
]
for extra_identifier, extra_entry_point in iter(cls.extra_entry_points):
if identifier == extra_identifier:
all_entry_points.append(extra_entry_point)
Expand Down Expand Up @@ -133,7 +137,7 @@ def load_classes(cls, fail_silently=True):
contexts. Hence, the flag.
"""
all_classes = itertools.chain(
pkg_resources.iter_entry_points(cls.entry_point),
importlib.metadata.entry_points().get(cls.entry_point, []),
(entry_point for identifier, entry_point in iter(cls.extra_entry_points)),
)
for class_ in all_classes:
Expand Down
20 changes: 10 additions & 10 deletions xblock/test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -961,11 +961,6 @@ class UnloadableXBlock(XBlock):
"""Just something to load resources from."""
resources_dir = None

def stub_resource_stream(self, module, name):
"""Act like pkg_resources.resource_stream, for testing."""
assert module == "xblock.test.test_core"
return "!" + name + "!"

@ddt.data(
"public/hey.js",
"public/sub/hey.js",
Expand All @@ -976,7 +971,8 @@ def stub_resource_stream(self, module, name):
)
def test_open_good_local_resource(self, uri):
loadable = self.LoadableXBlock(None, scope_ids=Mock())
with patch('pkg_resources.resource_stream', self.stub_resource_stream):
with patch('importlib.resources.files') as mock_files:
mock_files.return_value.joinpath.return_value.open.return_value = "!" + uri + "!"
assert loadable.open_local_resource(uri) == "!" + uri + "!"
assert loadable.open_local_resource(uri.encode('utf-8')) == "!" + uri + "!"

Expand All @@ -990,7 +986,8 @@ def test_open_good_local_resource(self, uri):
)
def test_open_good_local_resource_binary(self, uri):
loadable = self.LoadableXBlock(None, scope_ids=Mock())
with patch('pkg_resources.resource_stream', self.stub_resource_stream):
with patch('importlib.resources.files') as mock_files:
mock_files.return_value.joinpath.return_value.open.return_value = "!" + uri.decode('utf-8') + "!"
assert loadable.open_local_resource(uri) == "!" + uri.decode('utf-8') + "!"

@ddt.data(
Expand All @@ -1004,7 +1001,8 @@ def test_open_good_local_resource_binary(self, uri):
)
def test_open_bad_local_resource(self, uri):
loadable = self.LoadableXBlock(None, scope_ids=Mock())
with patch('pkg_resources.resource_stream', self.stub_resource_stream):
with patch('importlib.resources.files') as mock_files:
mock_files.return_value.joinpath.return_value.open.return_value = "!" + uri + "!"
msg_pattern = ".*: %s" % re.escape(repr(uri))
with pytest.raises(DisallowedFileError, match=msg_pattern):
loadable.open_local_resource(uri)
Expand All @@ -1020,7 +1018,8 @@ def test_open_bad_local_resource(self, uri):
)
def test_open_bad_local_resource_binary(self, uri):
loadable = self.LoadableXBlock(None, scope_ids=Mock())
with patch('pkg_resources.resource_stream', self.stub_resource_stream):
with patch('importlib.resources.files') as mock_files:
mock_files.return_value.joinpath.return_value.open.return_value = "!" + str(uri) + "!"
msg = ".*: %s" % re.escape(repr(uri.decode('utf-8')))
with pytest.raises(DisallowedFileError, match=msg):
loadable.open_local_resource(uri)
Expand All @@ -1043,7 +1042,8 @@ def test_open_bad_local_resource_binary(self, uri):
def test_open_local_resource_with_no_resources_dir(self, uri):
unloadable = self.UnloadableXBlock(None, scope_ids=Mock())

with patch('pkg_resources.resource_stream', self.stub_resource_stream):
with patch('importlib.resources.files') as mock_files:
mock_files.return_value.joinpath.return_value.open.return_value = "!" + uri + "!"
msg = "not configured to serve local resources"
with pytest.raises(DisallowedFileError, match=msg):
unloadable.open_local_resource(uri)
Expand Down
6 changes: 3 additions & 3 deletions xblock/test/utils/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

import gettext
import unittest
from unittest.mock import patch, DEFAULT
from unittest.mock import DEFAULT, patch

from pkg_resources import resource_filename
import importlib.resources

from xblock.utils.resources import ResourceLoader

Expand Down Expand Up @@ -136,7 +136,7 @@ class MockI18nService:
def __init__(self):

locale_dir = 'data/translations'
locale_path = resource_filename(__name__, locale_dir)
locale_path = str(importlib.resources.files(__name__) / locale_dir)
domain = 'text'
self.mock_translator = gettext.translation(
domain,
Expand Down
10 changes: 5 additions & 5 deletions xblock/utils/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import sys
import warnings

import pkg_resources
from django.template import Context, Template, Engine
import importlib.resources
from django.template import Context, Engine, Template
from django.template.backends.django import get_installed_libraries
from mako.lookup import TemplateLookup as MakoTemplateLookup
from mako.template import Template as MakoTemplate
Expand All @@ -22,8 +22,7 @@ def load_unicode(self, resource_path):
"""
Gets the content of a resource
"""
resource_content = pkg_resources.resource_string(self.module_name, resource_path)
return resource_content.decode('utf-8')
return importlib.resources.files(self.module_name).joinpath(resource_path).read_text()

def render_django_template(self, template_path, context=None, i18n_service=None):
"""
Expand Down Expand Up @@ -57,7 +56,8 @@ def render_mako_template(self, template_path, context=None):
)
context = context or {}
template_str = self.load_unicode(template_path)
lookup = MakoTemplateLookup(directories=[pkg_resources.resource_filename(self.module_name, '')])
directory = str(importlib.resources.as_file(importlib.resources.files(self.module_name) / ''))
lookup = MakoTemplateLookup(directories=[directory])
template = MakoTemplate(template_str, lookup=lookup)
return template.render(**context)

Expand Down

0 comments on commit c6801a6

Please sign in to comment.