Skip to content

Commit

Permalink
Merge pull request #289 from ales-erjavec/remove-pkg-resources
Browse files Browse the repository at this point in the history
[ENH] Remove use of pkg_resources
  • Loading branch information
PrimozGodec committed Dec 8, 2023
2 parents 5f582f7 + 8018377 commit af0fac5
Show file tree
Hide file tree
Showing 22 changed files with 367 additions and 287 deletions.
4 changes: 2 additions & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
import os
import shlex

import pkg_resources
dist = pkg_resources.get_distribution("orange-canvas-core")
import importlib_metadata
dist = importlib_metadata.distribution("orange-canvas-core")

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
Expand Down
21 changes: 10 additions & 11 deletions orangecanvas/application/addons.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from typing import List, Any, Optional, Tuple

import pkg_resources
from packaging.requirements import Requirement

from AnyQt.QtWidgets import (
QDialog, QLineEdit, QTreeView, QHeaderView,
Expand Down Expand Up @@ -52,9 +52,8 @@

from .. import config
from ..config import Config
from ..utils.pkgmeta import Distribution

Requirement = pkg_resources.Requirement
Distribution = pkg_resources.Distribution

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -155,7 +154,7 @@ def createRow(item):
if isinstance(item, Installed):
installed = True
ins, dist = item.installable, item.local
name = prettify_name(dist.project_name)
name = prettify_name(dist.name)
summary = get_dist_meta(dist).get("Summary", "")
version = dist.version
item_is_core = item.required
Expand Down Expand Up @@ -553,14 +552,14 @@ def network_warning(exc):
if ep.dist is not None]
items = installable_items(packages, installed)
core_constraints = {
r.project_name.casefold(): r
for r in (Requirement.parse(r) for r in config.core_packages())
r.name.casefold(): r
for r in map(Requirement, config.core_packages())
}

def constrain(item): # type: (Item) -> Item
"""Include constraint in Installed when in core_constraint"""
if isinstance(item, Installed):
name = item.local.project_name.casefold()
name = item.local.name.casefold()
if name in core_constraints:
return item._replace(
required=True, constraint=core_constraints[name]
Expand Down Expand Up @@ -686,7 +685,7 @@ def match(item):
elif item.installable is not None:
return item.installable.name == installable.name
else:
return item.local.project_name.lower() == installable.name.lower()
return item.local.name.lower() == installable.name.lower()

new = next(filter(match, new_), None)
assert new is not None
Expand Down Expand Up @@ -858,7 +857,7 @@ def __accepted(self):
core_required = {}
for item in self.items():
if isinstance(item, Installed) and item.required:
core_required[item.local.project_name] = item.local.version
core_required[item.local.name] = item.local.version

core_upgrade = set()
for step in steps:
Expand All @@ -867,8 +866,8 @@ def __accepted(self):
if inst.name in core_required: # direct upgrade of a core package
core_upgrade.add(inst.name)
if inst.requirements: # indirect upgrade of a core package as a requirement
for req in pkg_resources.parse_requirements(inst.requirements):
if req.name in core_required and core_required[req.name] not in req:
for req in map(Requirement, inst.requirements):
if req.name in core_required and not req.specifier.contains(core_required[req.name], prereleases=True):
core_upgrade.add(req.name) # current doesn't meet requirements

if core_upgrade:
Expand Down
2 changes: 1 addition & 1 deletion orangecanvas/application/canvasmain.py
Original file line number Diff line number Diff line change
Expand Up @@ -1354,7 +1354,7 @@ def install_requirements(self, requires: Sequence[str]) -> int:
dlg.setStyle(QApplication.style())
dlg.setConfig(config.default)
req = addons.Requirement
names = [req.parse(r).project_name for r in requires]
names = [req(r).name for r in requires]
normalized_names = {normalize_name(r) for r in names}

def set_state(*args):
Expand Down
36 changes: 18 additions & 18 deletions orangecanvas/application/examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
"""
import os
import logging
import pathlib
import types

from typing import List, Optional, IO

import pkg_resources

from orangecanvas import config as _config
from orangecanvas.utils.pkgmeta import Distribution

try:
from importlib.resources import files as _files
except ImportError:
from importlib_resources import files as _files

log = logging.getLogger(__name__)

Expand All @@ -24,8 +29,8 @@ def is_ows(filename):
# type: (str) -> bool
return filename.endswith(".ows")

resources = pkg_resources.resource_listdir(package.__name__, ".")
return sorted(filter(is_ows, resources))
resources = _files(package.__name__).iterdir()
return sorted(filter(is_ows, (r.name for r in resources)))


def workflows(config=None):
Expand All @@ -45,11 +50,7 @@ def workflows(config=None):
examples_entry_points = config.examples_entry_points
for ep in examples_entry_points():
try:
examples = ep.resolve()
except pkg_resources.DistributionNotFound as ex:
log.warning("Could not load examples from %r (%r)",
ep.dist, ex)
continue
examples = ep.load()
except Exception:
log.error("Could not load examples from %r",
ep.dist, exc_info=True)
Expand All @@ -75,34 +76,33 @@ def workflows(config=None):

class ExampleWorkflow:
def __init__(self, resource, package=None, distribution=None):
# type: (str, Optional[types.ModuleType], Optional[pkg_resources.Distribution]) -> None
# type: (str, Optional[types.ModuleType], Optional[Distribution]) -> None
self.resource = resource
self.package = package
self.distribution = distribution

def abspath(self):
# type: () -> str
def abspath(self) -> str:
"""
Return absolute filename for the workflow if possible else
raise an ValueError.
"""
if self.package is not None:
return pkg_resources.resource_filename(self.package.__name__,
self.resource)
item = _files(self.package) / self.resource
if isinstance(item, pathlib.Path):
return str(item)
elif isinstance(self.resource, str):
if os.path.isabs(self.resource):
return self.resource

raise ValueError("cannot resolve resource to an absolute name")

def stream(self):
# type: () -> IO[bytes]
def stream(self) -> IO[bytes]:
"""
Return the example file as an open stream.
"""
if self.package is not None:
return pkg_resources.resource_stream(self.package.__name__,
self.resource)
item = _files(self.package) / self.resource
return item.open('rb')
elif isinstance(self.resource, str):
if os.path.isabs(self.resource) and os.path.exists(self.resource):
return open(self.resource, "rb")
Expand Down
40 changes: 34 additions & 6 deletions orangecanvas/application/tests/test_addons.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from AnyQt.QtGui import QDropEvent
from AnyQt.QtTest import QTest
from AnyQt.QtWidgets import QDialogButtonBox, QMessageBox, QTreeView, QStyle
from pkg_resources import Distribution, EntryPoint

from orangecanvas.application import addons
from orangecanvas.application.addons import AddonManagerDialog
Expand All @@ -26,6 +25,7 @@
)
from orangecanvas.gui.test import QAppTestCase
from orangecanvas.utils.qinvoke import qinvoke
from orangecanvas.utils.pkgmeta import Distribution, EntryPoint


@contextmanager
Expand All @@ -41,19 +41,46 @@ def addon_archive(pkginfo):
os.remove(name)


class FakeDistribution(Distribution):
def locate_file(self, path):
pass

def read_text(self, filename):
pass

def __init__(self, name, version):
super().__init__()
self._name = name
self._version = version

@property
def name(self):
return self._name

@property
def version(self):
return self._version


class FakeEntryPoint(EntryPoint):
def for_(self, dist):
vars(self).update(dist=dist)
return self


class TestAddonManagerDialog(QAppTestCase):
def test_widget(self):
items = [
Installed(
Installable("foo", "1.1", "", "", "", []),
Distribution(project_name="foo", version="1.0"),
FakeDistribution(name="foo", version="1.0"),
),
Available(
Installable("q", "1.2", "", "", "", [])
),
Installed(
None,
Distribution(project_name="a", version="0.0")
FakeDistribution(name="a", version="0.0")
),
]
w = AddonManagerDialog()
Expand Down Expand Up @@ -98,13 +125,14 @@ def check_state_equal(left, right):
check_state_equal(index.data(Qt.CheckStateRole), Qt.Unchecked)

@patch("orangecanvas.config.default.addon_entry_points",
return_value=[EntryPoint(
"a", "b", dist=Distribution(project_name="foo", version="1.0"))])
return_value=[
FakeEntryPoint(
"a", "b", "g").for_(FakeDistribution(name="foo", version="1.0"))])
def test_drop(self, p1):
items = [
Installed(
Installable("foo", "1.1", "", "", "", []),
Distribution(project_name="foo", version="1.0"),
FakeDistribution(name="foo", version="1.0"),
),
]
w = AddonManagerDialog()
Expand Down
20 changes: 13 additions & 7 deletions orangecanvas/application/tests/test_addons_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import unittest
from tempfile import mkdtemp

from pkg_resources import Requirement
from requests import Session
from requests_cache import CachedSession
from packaging.requirements import Requirement

from orangecanvas.application.utils.addons import (
Available,
Expand All @@ -16,20 +16,26 @@
is_updatable,
prettify_name, _session,
)
from orangecanvas.config import Distribution
from orangecanvas.application.tests.test_addons import FakeDistribution


class TestUtils(unittest.TestCase):
def test_items_1(self):
inst = Installable("foo", "1.0", "a foo", "", "", [])
dist = Distribution(project_name="foo", version="1.0")
dist = FakeDistribution(name="foo", version="1.0")
item = Available(inst)
self.assertFalse(is_updatable(item))
self.assertEqual(item.name, "foo")
self.assertEqual(item.normalized_name, "foo")

item = Installed(None, dist)
self.assertFalse(is_updatable(item))
self.assertEqual(item.name, dist.name)
self.assertEqual(item.normalized_name, dist.name)

item = Installed(inst, dist)
self.assertFalse(is_updatable(item))
self.assertEqual(item.name, inst.name)

item = Installed(inst._replace(version="0.9"), dist)
self.assertFalse(is_updatable(item))
Expand All @@ -38,17 +44,17 @@ def test_items_1(self):
self.assertTrue(is_updatable(item))

item = Installed(inst._replace(version="2.0"), dist,
constraint=Requirement.parse("foo<1.99"))
constraint=Requirement("foo<1.99"))
self.assertFalse(is_updatable(item))
item = Installed(inst._replace(version="2.0"), dist,
constraint=Requirement.parse("foo<2.99"))
constraint=Requirement("foo<2.99"))
self.assertTrue(is_updatable(item))

def test_items_2(self):
inst1 = Installable("foo", "1.0", "a foo", "", "", [])
inst2 = Installable("bar", "1.0", "a bar", "", "", [])
dist2 = Distribution(project_name="bar", version="0.9")
dist3 = Distribution(project_name="quack", version="1.0")
dist2 = FakeDistribution(name="bar", version="0.9")
dist3 = FakeDistribution(name="quack", version="1.0")
items = installable_items([inst1, inst2], [dist2, dist3])
self.assertIn(Available(inst1), items)
self.assertIn(Installed(inst2, dist2), items)
Expand Down
10 changes: 7 additions & 3 deletions orangecanvas/application/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@

from orangecanvas import config
from orangecanvas.application.canvasmain import CanvasMainWindow
from orangecanvas.config import Config, EntryPoint
from orangecanvas.config import Config
from orangecanvas.gui.test import QAppTestCase
from orangecanvas.main import Main
from orangecanvas.registry import WidgetDiscovery
from orangecanvas.registry.tests import set_up_modules, tear_down_modules
from orangecanvas.scheme import Scheme
from orangecanvas.utils.shtools import temp_named_file
from orangecanvas.utils.pkgmeta import EntryPoint


class TestMain(unittest.TestCase):
Expand Down Expand Up @@ -76,13 +77,16 @@ def widget_discovery(self, *args, **kwargs):
def widgets_entry_points(self): # type: () -> Iterable[EntryPoint]
pkg = "orangecanvas.registry.tests"
return (
EntryPoint.parse(f"add = {pkg}.operators.add"),
EntryPoint.parse(f"sub = {pkg}.operators.sub")
EntryPoint("add", f"{pkg}.operators.add", "w"),
EntryPoint("sub", f"{pkg}.operators.sub", "w")
)

def workflow_constructor(self, *args, **kwargs):
return Scheme(*args, **kwargs)

def splash_screen(self):
return config.Default.splash_screen()


class TestMainGuiCase(QAppTestCase):
def setUp(self):
Expand Down

0 comments on commit af0fac5

Please sign in to comment.