Refactor requirementslib for categories and remove unused code.

This commit is contained in:
Matt Davis
2022-09-19 18:03:16 -04:00
parent 91b5160331
commit 7754e6633f
3 changed files with 17 additions and 200 deletions
+9 -9
View File
@@ -35,12 +35,6 @@ class _LockFileEncoder(json.JSONEncoder):
yield "\n"
LOCKFILE_SECTIONS = {
"_meta": Meta,
"default": PackageCollection,
"develop": PackageCollection,
}
PIPFILE_SPEC_CURRENT = 6
@@ -70,8 +64,11 @@ class Lockfile(DataView):
@classmethod
def validate(cls, data):
super(Lockfile, cls).validate(data)
for key, klass in LOCKFILE_SECTIONS.items():
klass.validate(data[key])
for key, value in data.items():
if key == "_meta":
Meta.validate(value)
else:
PackageCollection.validate(value)
@classmethod
def load(cls, f, encoding=None):
@@ -98,7 +95,10 @@ class Lockfile(DataView):
def __getitem__(self, key):
value = self._data[key]
try:
return LOCKFILE_SECTIONS[key](value)
if key == "_meta":
return Meta(value)
else:
return PackageCollection(value)
except KeyError:
return value
+8 -35
View File
@@ -53,7 +53,7 @@ class Lockfile(object):
@property
def section_keys(self):
return ["default", "develop"]
return set(self.lockfile.keys()) - {"_meta"}
@property
def extended_keys(self):
@@ -75,8 +75,6 @@ class Lockfile(object):
def __getitem__(self, k, *args, **kwargs):
retval = None
lockfile = self._lockfile
section = None
pkg_type = None
try:
retval = lockfile[k]
except KeyError:
@@ -94,7 +92,6 @@ class Lockfile(object):
return retval
def __getattr__(self, k, *args, **kwargs):
retval = None
lockfile = super(Lockfile, self).__getattribute__("_lockfile")
try:
return super(Lockfile, self).__getattribute__(k)
@@ -122,7 +119,6 @@ class Lockfile(object):
:return: A project file with the model and location for interaction
:rtype: :class:`~requirementslib.models.project.ProjectFile`
"""
pf = ProjectFile.read(path, lockfiles.Lockfile, invalid_ok=True)
return pf
@@ -250,6 +246,9 @@ class Lockfile(object):
def create(cls, path, create=True):
return cls.load(path, create=create)
def get_section(self, name):
return self._lockfile.get(name)
@property
def develop(self):
return self._lockfile.develop
@@ -280,38 +279,12 @@ class Lockfile(object):
for k, v in deps.items():
yield Requirement.from_pipfile(k, v)
@property
def dev_requirements(self):
if not self._dev_requirements:
self._dev_requirements = list(self.get_requirements(dev=True, only=True))
return self._dev_requirements
@property
def requirements(self):
if not self._requirements:
self._requirements = list(self.get_requirements(dev=False, only=True))
return self._requirements
@property
def dev_requirements_list(self):
return [{name: entry._data} for name, entry in self._lockfile.develop.items()]
@property
def requirements_list(self):
return [{name: entry._data} for name, entry in self._lockfile.default.items()]
def requirements_list(self, category):
if self._lockfile.get(category):
return [{name: entry._data} for name, entry in self._lockfile[category].items()]
return []
def write(self):
self.projectfile.model = copy.deepcopy(self._lockfile)
self.projectfile.write()
def as_requirements(self, include_hashes=False, dev=False):
"""Returns a list of requirements in pip-style format."""
lines = []
section = self.dev_requirements if dev else self.requirements
for req in section:
kwargs = {"include_hashes": include_hashes}
if req.editable:
kwargs["include_markers"] = False
r = req.as_line(**kwargs)
lines.append(r.strip())
return lines
-156
View File
@@ -3,11 +3,7 @@ import io
import os
import pipenv.vendor.attr as attr
import pipenv.vendor.plette as plette
import pipenv.vendor.plette.models as models
import pipenv.vendor.tomlkit as tomlkit
from pipenv.patched.pip._vendor.packaging.markers import Marker
from pipenv.patched.pip._vendor.packaging.utils import canonicalize_name
SectionDifference = collections.namedtuple("SectionDifference", ["inthis", "inthat"])
FileDifference = collections.namedtuple("FileDifference", ["default", "develop"])
@@ -70,155 +66,3 @@ class ProjectFile(object):
strio = io.StringIO()
self.model.dump(strio)
return strio.getvalue()
@attr.s
class Project(object):
root = attr.ib()
_p = attr.ib(init=False)
_l = attr.ib(init=False)
def __attrs_post_init__(self):
self.root = root = os.path.abspath(self.root)
self._p = ProjectFile.read(os.path.join(root, "Pipfile"), plette.Pipfile)
self._l = ProjectFile.read(
os.path.join(root, "Pipfile.lock"), plette.Lockfile, invalid_ok=True
)
@property
def pipfile(self):
return self._p.model
@property
def pipfile_location(self):
return self._p.location
@property
def lockfile(self):
return self._l.model
@property
def lockfile_location(self):
return self._l.location
@lockfile.setter
def lockfile(self, new):
self._l.model = new
def is_synced(self):
return self.lockfile and self.lockfile.is_up_to_date(self.pipfile)
def _get_pipfile_section(self, develop, insert=True):
name = "dev-packages" if develop else "packages"
try:
section = self.pipfile[name]
except KeyError:
section = models.PackageCollection(tomlkit.table())
if insert:
self.pipfile[name] = section
return section
def contains_key_in_pipfile(self, key):
sections = [
self._get_pipfile_section(develop=False, insert=False),
self._get_pipfile_section(develop=True, insert=False),
]
return any(
(canonicalize_name(name) == canonicalize_name(key))
for section in sections
for name in section
)
def add_line_to_pipfile(self, line, develop):
from pipenv.vendor.requirementslib import Requirement
requirement = Requirement.from_line(line)
section = self._get_pipfile_section(develop=develop)
key = requirement.normalized_name
entry = next(iter(requirement.as_pipfile().values()))
if isinstance(entry, dict):
# HACK: TOMLKit prefers to expand tables by default, but we
# always want inline tables here. Also tomlkit.inline_table
# does not have `update()`.
table = tomlkit.inline_table()
for k, v in entry.items():
table[k] = v
entry = table
section[key] = entry
def remove_keys_from_pipfile(self, keys, default, develop):
keys = {canonicalize_name(key) for key in keys}
sections = []
if default:
sections.append(self._get_pipfile_section(develop=False, insert=False))
if develop:
sections.append(self._get_pipfile_section(develop=True, insert=False))
for section in sections:
removals = set()
for name in section:
if canonicalize_name(name) in keys:
removals.add(name)
for key in removals:
del section._data[key]
def remove_keys_from_lockfile(self, keys):
keys = {canonicalize_name(key) for key in keys}
removed = False
for section_name in ("default", "develop"):
try:
section = self.lockfile[section_name]
except KeyError:
continue
removals = set()
for name in section:
if canonicalize_name(name) in keys:
removals.add(name)
removed = removed or bool(removals)
for key in removals:
del section._data[key]
if removed:
# HACK: The lock file no longer represents the Pipfile at this
# point. Set the hash to an arbitrary invalid value.
self.lockfile.meta.hash = models.Hash({"__invalid__": ""})
def difference_lockfile(self, lockfile):
"""Generate a difference between the current and given lockfiles.
Returns a 2-tuple containing differences in default in develop
sections.
Each element is a 2-tuple of dicts. The first, `inthis`, contains
entries only present in the current lockfile; the second, `inthat`,
contains entries only present in the given one.
If a key exists in both this and that, but the values differ, the key
is present in both dicts, pointing to values from each file.
"""
diff_data = {
"default": SectionDifference({}, {}),
"develop": SectionDifference({}, {}),
}
for section_name, section_diff in diff_data.items():
try:
this = self.lockfile[section_name]._data
except (KeyError, TypeError):
this = {}
try:
that = lockfile[section_name]._data
except (KeyError, TypeError):
that = {}
for key, this_value in this.items():
try:
that_value = that[key]
except KeyError:
section_diff.inthis[key] = this_value
continue
if not _are_pipfile_entries_equal(this_value, that_value):
section_diff.inthis[key] = this_value
section_diff.inthat[key] = that_value
for key, that_value in that.items():
if key not in this:
section_diff.inthat[key] = that_value
return FileDifference(**diff_data)