pixee / codemodder-python

Python implementation of the Codemodder framework
GNU Affero General Public License v3.0
38 stars 10 forks source link

Codemod to replace deprecated `pkg_resources` #281

Closed clavedeluna closed 7 months ago

clavedeluna commented 9 months ago

Setuptools now has a deprecation warning for pkg_resources:

Use of pkg_resources is deprecated in favor of importlib.resources, importlib.metadata and their backports (importlib_resources, importlib_metadata). Some useful APIs are also provided by packaging (e.g. requirements and version parsing). Users should refrain from new usage of pkg_resources and should work to port to importlib-based solutions.

We should write a codemod that switches to the new APIs.

drdavella commented 9 months ago

I like this. I'm not sure how tricky it will be to get 💯 right but it's worth doing some investigation.

clavedeluna commented 7 months ago

I've done a bit of research here. I think a starting point here would be to tackle as many fixes for importlib.metadata

  1. To get the distribution

    import pkg_resources
    dist = pkg_resources.get_distribution("package_name")

    becomes

    from importlib.metadata import distribution
    dist = distribution("package_name")
  2. to get version directly

    import pkg_resources
    version = pkg_resources.get_distribution("package_name").version

    to

    from importlib.metadata import version
    version = version("package_name")
  3. also entry points

    import pkg_resources
    for entry_point in pkg_resources.iter_entry_points('my_entry_point_group'):
    ....

    to

from importlib.metadata import entry_points
for entry_point in entry_points(group='my_entry_point_group'):
...

except that in python 3.10 the return value of entry_points is a bit different so it may need to be tweaked starting at this version.

For simplicity I think we can start implementing 1-2 for now and that's a great start.

drdavella commented 7 months ago

@clavedeluna I like the idea of starting with 1. and 2. It seems pretty straightforward to knock out and then we can return focus to remediating SAST findings.

clavedeluna commented 7 months ago

@drdavella I've convinced myself this is not as good a codemod as I thought initially and in fact it could break code. Here's a strong example:

    import pkg_resources

    dist = pkg_resources.get_distribution("Django")
    dist.location
    version = dist.version

would be changed to

    from importlib.metadata import distribution

    dist = distribution("Django")
    dist.location
    version = dist.version

however, as soon as you run the output code you get

>   dist.location
E   AttributeError: 'PathDistribution' object has no attribute 'location'

which clued me in to the fact that the return values of functions pkg_resources.get_distribution and importlib.metadata.distribution are different enough that even basic attrs are different.

I'll save my work to this branch but will close this ticket at this time.