From 4e3976dfbaa4ea06aa1574a461acf8d592964bcb Mon Sep 17 00:00:00 2001 From: Vishal Kuo Date: Wed, 5 Aug 2020 13:14:35 -0700 Subject: [PATCH 01/10] adds @generated to header of lockfile --- poetry/packages/locker.py | 342 ++++++++++++++++++++++++++++++++++ tests/packages/test_locker.py | 4 + 2 files changed, 346 insertions(+) create mode 100644 poetry/packages/locker.py diff --git a/poetry/packages/locker.py b/poetry/packages/locker.py new file mode 100644 index 00000000000..2222ac12a40 --- /dev/null +++ b/poetry/packages/locker.py @@ -0,0 +1,342 @@ +import json +import logging +import re + +from hashlib import sha256 +from typing import List + +from tomlkit import comment +from tomlkit import document +from tomlkit import inline_table +from tomlkit import item +from tomlkit import nl +from tomlkit import table +from tomlkit.exceptions import TOMLKitError + +import poetry.repositories + +from poetry.core.packages.package import Dependency +from poetry.core.packages.package import Package +from poetry.core.semver import parse_constraint +from poetry.core.semver.version import Version +from poetry.core.version.markers import parse_marker +from poetry.utils._compat import Path +from poetry.utils.toml_file import TomlFile + + +logger = logging.getLogger(__name__) + + +class Locker(object): + + _VERSION = "1.1" + + _relevant_keys = ["dependencies", "dev-dependencies", "source", "extras"] + + def __init__(self, lock, local_config): # type: (Path, dict) -> None + self._lock = TomlFile(lock) + self._local_config = local_config + self._lock_data = None + self._content_hash = self._get_content_hash() + + @property + def lock(self): # type: () -> TomlFile + return self._lock + + @property + def lock_data(self): + if self._lock_data is None: + self._lock_data = self._get_lock_data() + + return self._lock_data + + def is_locked(self): # type: () -> bool + """ + Checks whether the locker has been locked (lockfile found). + """ + if not self._lock.exists(): + return False + + return "package" in self.lock_data + + def is_fresh(self): # type: () -> bool + """ + Checks whether the lock file is still up to date with the current hash. + """ + lock = self._lock.read() + metadata = lock.get("metadata", {}) + + if "content-hash" in metadata: + return self._content_hash == lock["metadata"]["content-hash"] + + return False + + def locked_repository( + self, with_dev_reqs=False + ): # type: (bool) -> poetry.repositories.Repository + """ + Searches and returns a repository of locked packages. + """ + if not self.is_locked(): + return poetry.repositories.Repository() + + lock_data = self.lock_data + packages = poetry.repositories.Repository() + + if with_dev_reqs: + locked_packages = lock_data["package"] + else: + locked_packages = [ + p for p in lock_data["package"] if p["category"] == "main" + ] + + if not locked_packages: + return packages + + for info in locked_packages: + package = Package(info["name"], info["version"], info["version"]) + package.description = info.get("description", "") + package.category = info["category"] + package.optional = info["optional"] + if "hashes" in lock_data["metadata"]: + # Old lock so we create dummy files from the hashes + package.files = [ + {"name": h, "hash": h} + for h in lock_data["metadata"]["hashes"][info["name"]] + ] + else: + package.files = lock_data["metadata"]["files"][info["name"]] + + package.python_versions = info["python-versions"] + extras = info.get("extras", {}) + if extras: + for name, deps in extras.items(): + package.extras[name] = [] + + for dep in deps: + m = re.match(r"^(.+?)(?:\s+\((.+)\))?$", dep) + dep_name = m.group(1) + constraint = m.group(2) or "*" + + package.extras[name].append(Dependency(dep_name, constraint)) + + if "marker" in info: + package.marker = parse_marker(info["marker"]) + else: + # Compatibility for old locks + if "requirements" in info: + dep = Dependency("foo", "0.0.0") + for name, value in info["requirements"].items(): + if name == "python": + dep.python_versions = value + elif name == "platform": + dep.platform = value + + split_dep = dep.to_pep_508(False).split(";") + if len(split_dep) > 1: + package.marker = parse_marker(split_dep[1].strip()) + + for dep_name, constraint in info.get("dependencies", {}).items(): + if isinstance(constraint, list): + for c in constraint: + package.add_dependency(dep_name, c) + + continue + + package.add_dependency(dep_name, constraint) + + if "develop" in info: + package.develop = info["develop"] + + if "source" in info: + package.source_type = info["source"].get("type", "") + package.source_url = info["source"]["url"] + package.source_reference = info["source"]["reference"] + + packages.add_package(package) + + return packages + + def set_lock_data(self, root, packages): # type: (...) -> bool + files = table() + packages = self._lock_packages(packages) + # Retrieving hashes + for package in packages: + if package["name"] not in files: + files[package["name"]] = [] + + for f in package["files"]: + file_metadata = inline_table() + for k, v in sorted(f.items()): + file_metadata[k] = v + + files[package["name"]].append(file_metadata) + + if files[package["name"]]: + files[package["name"]] = item(files[package["name"]]).multiline(True) + + del package["files"] + + lock = document() + lock.add(comment("@generated")) + lock.add(nl()) + lock["package"] = packages + + if root.extras: + lock["extras"] = { + extra: [dep.pretty_name for dep in deps] + for extra, deps in root.extras.items() + } + + lock["metadata"] = { + "lock-version": self._VERSION, + "python-versions": root.python_versions, + "content-hash": self._content_hash, + "files": files, + } + + if not self.is_locked() or lock != self.lock_data: + self._write_lock_data(lock) + + return True + + return False + + def _write_lock_data(self, data): + self.lock.write(data) + + # Checking lock file data consistency + if data != self.lock.read(): + raise RuntimeError("Inconsistent lock file data.") + + self._lock_data = None + + def _get_content_hash(self): # type: () -> str + """ + Returns the sha256 hash of the sorted content of the pyproject file. + """ + content = self._local_config + + relevant_content = {} + for key in self._relevant_keys: + relevant_content[key] = content.get(key) + + content_hash = sha256( + json.dumps(relevant_content, sort_keys=True).encode() + ).hexdigest() + + return content_hash + + def _get_lock_data(self): # type: () -> dict + if not self._lock.exists(): + raise RuntimeError("No lockfile found. Unable to read locked packages") + + try: + lock_data = self._lock.read() + except TOMLKitError as e: + raise RuntimeError("Unable to read the lock file ({}).".format(e)) + + lock_version = Version.parse(lock_data["metadata"].get("lock-version", "1.0")) + current_version = Version.parse(self._VERSION) + # We expect the locker to be able to read lock files + # from the same semantic versioning range + accepted_versions = parse_constraint( + "^{}".format(Version(current_version.major, 0)) + ) + lock_version_allowed = accepted_versions.allows(lock_version) + if lock_version_allowed and current_version < lock_version: + logger.warning( + "The lock file might not be compatible with the current version of Poetry.\n" + "Upgrade Poetry to ensure the lock file is read properly or, alternatively, " + "regenerate the lock file with the `poetry lock` command." + ) + elif not lock_version_allowed: + raise RuntimeError( + "The lock file is not compatible with the current version of Poetry.\n" + "Upgrade Poetry to be able to read the lock file or, alternatively, " + "regenerate the lock file with the `poetry lock` command." + ) + + return lock_data + + def _lock_packages( + self, packages + ): # type: (List['poetry.packages.Package']) -> list + locked = [] + + for package in sorted(packages, key=lambda x: x.name): + spec = self._dump_package(package) + + locked.append(spec) + + return locked + + def _dump_package(self, package): # type: (Package) -> dict + dependencies = {} + for dependency in sorted(package.requires, key=lambda d: d.name): + if dependency.is_optional() and not dependency.is_activated(): + continue + + if dependency.pretty_name not in dependencies: + dependencies[dependency.pretty_name] = [] + + constraint = inline_table() + constraint["version"] = str(dependency.pretty_constraint) + + if dependency.extras: + constraint["extras"] = sorted(dependency.extras) + + if dependency.is_optional(): + constraint["optional"] = True + + if not dependency.marker.is_any(): + constraint["markers"] = str(dependency.marker) + + dependencies[dependency.pretty_name].append(constraint) + + # All the constraints should have the same type, + # but we want to simplify them if it's possible + for dependency, constraints in tuple(dependencies.items()): + if all(len(constraint) == 1 for constraint in constraints): + dependencies[dependency] = [ + constraint["version"] for constraint in constraints + ] + + data = { + "name": package.pretty_name, + "version": package.pretty_version, + "description": package.description or "", + "category": package.category, + "optional": package.optional, + "python-versions": package.python_versions, + "files": sorted(package.files, key=lambda x: x["file"]), + } + + if package.extras: + extras = {} + for name, deps in package.extras.items(): + extras[name] = [ + str(dep) if not dep.constraint.is_any() else dep.name + for dep in deps + ] + + data["extras"] = extras + + if dependencies: + for k, constraints in dependencies.items(): + if len(constraints) == 1: + dependencies[k] = constraints[0] + + data["dependencies"] = dependencies + + if package.source_url: + data["source"] = { + "url": package.source_url, + "reference": package.source_reference, + } + if package.source_type: + data["source"]["type"] = package.source_type + if package.source_type == "directory": + data["develop"] = package.develop + + return data diff --git a/tests/packages/test_locker.py b/tests/packages/test_locker.py index 0e79817d4f3..8f5f332f17a 100644 --- a/tests/packages/test_locker.py +++ b/tests/packages/test_locker.py @@ -169,6 +169,8 @@ def test_lock_file_data_is_ordered(locker: Locker, root: ProjectPackage): def test_locker_properly_loads_extras(locker: Locker): content = """\ +@generated + [[package]] name = "cachecontrol" version = "0.12.5" @@ -523,6 +525,8 @@ def test_locker_should_raise_an_error_if_lock_version_is_newer_and_not_allowed( locker: Locker, caplog: LogCaptureFixture ): content = """\ +# @generated + [metadata] lock-version = "2.0" python-versions = "~2.7 || ^3.4" From 7a9e87477eaf9b2d4fdbc056d8288d77c97ad1da Mon Sep 17 00:00:00 2001 From: Vishal Kuo Date: Wed, 5 Aug 2020 13:29:55 -0700 Subject: [PATCH 02/10] fix test --- poetry/packages/locker.py | 2 -- tests/packages/test_locker.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/poetry/packages/locker.py b/poetry/packages/locker.py index 2222ac12a40..fad5837f062 100644 --- a/poetry/packages/locker.py +++ b/poetry/packages/locker.py @@ -9,7 +9,6 @@ from tomlkit import document from tomlkit import inline_table from tomlkit import item -from tomlkit import nl from tomlkit import table from tomlkit.exceptions import TOMLKitError @@ -179,7 +178,6 @@ def set_lock_data(self, root, packages): # type: (...) -> bool lock = document() lock.add(comment("@generated")) - lock.add(nl()) lock["package"] = packages if root.extras: diff --git a/tests/packages/test_locker.py b/tests/packages/test_locker.py index 8f5f332f17a..5ca411b8b7b 100644 --- a/tests/packages/test_locker.py +++ b/tests/packages/test_locker.py @@ -169,7 +169,7 @@ def test_lock_file_data_is_ordered(locker: Locker, root: ProjectPackage): def test_locker_properly_loads_extras(locker: Locker): content = """\ -@generated +# @generated [[package]] name = "cachecontrol" From 9f1f7e515633db21d9ce708193092e44f9a830a2 Mon Sep 17 00:00:00 2001 From: Vishal Kuo Date: Thu, 6 Aug 2020 21:27:09 -0700 Subject: [PATCH 03/10] switch to @ + generated --- poetry/packages/locker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry/packages/locker.py b/poetry/packages/locker.py index fad5837f062..d1dbc6c5fc7 100644 --- a/poetry/packages/locker.py +++ b/poetry/packages/locker.py @@ -177,7 +177,7 @@ def set_lock_data(self, root, packages): # type: (...) -> bool del package["files"] lock = document() - lock.add(comment("@generated")) + lock.add(comment("@" + "generated")) lock["package"] = packages if root.extras: From ad9bb13e8690b6bfb54c43bcbdb8f4a9ab4c6948 Mon Sep 17 00:00:00 2001 From: Vishal Kuo Date: Sun, 22 May 2022 08:58:14 -0700 Subject: [PATCH 04/10] rebaes --- poetry/packages/locker.py | 340 ---------------------------------- src/poetry/packages/locker.py | 2 + tests/packages/test_locker.py | 37 +++- 3 files changed, 33 insertions(+), 346 deletions(-) delete mode 100644 poetry/packages/locker.py diff --git a/poetry/packages/locker.py b/poetry/packages/locker.py deleted file mode 100644 index d1dbc6c5fc7..00000000000 --- a/poetry/packages/locker.py +++ /dev/null @@ -1,340 +0,0 @@ -import json -import logging -import re - -from hashlib import sha256 -from typing import List - -from tomlkit import comment -from tomlkit import document -from tomlkit import inline_table -from tomlkit import item -from tomlkit import table -from tomlkit.exceptions import TOMLKitError - -import poetry.repositories - -from poetry.core.packages.package import Dependency -from poetry.core.packages.package import Package -from poetry.core.semver import parse_constraint -from poetry.core.semver.version import Version -from poetry.core.version.markers import parse_marker -from poetry.utils._compat import Path -from poetry.utils.toml_file import TomlFile - - -logger = logging.getLogger(__name__) - - -class Locker(object): - - _VERSION = "1.1" - - _relevant_keys = ["dependencies", "dev-dependencies", "source", "extras"] - - def __init__(self, lock, local_config): # type: (Path, dict) -> None - self._lock = TomlFile(lock) - self._local_config = local_config - self._lock_data = None - self._content_hash = self._get_content_hash() - - @property - def lock(self): # type: () -> TomlFile - return self._lock - - @property - def lock_data(self): - if self._lock_data is None: - self._lock_data = self._get_lock_data() - - return self._lock_data - - def is_locked(self): # type: () -> bool - """ - Checks whether the locker has been locked (lockfile found). - """ - if not self._lock.exists(): - return False - - return "package" in self.lock_data - - def is_fresh(self): # type: () -> bool - """ - Checks whether the lock file is still up to date with the current hash. - """ - lock = self._lock.read() - metadata = lock.get("metadata", {}) - - if "content-hash" in metadata: - return self._content_hash == lock["metadata"]["content-hash"] - - return False - - def locked_repository( - self, with_dev_reqs=False - ): # type: (bool) -> poetry.repositories.Repository - """ - Searches and returns a repository of locked packages. - """ - if not self.is_locked(): - return poetry.repositories.Repository() - - lock_data = self.lock_data - packages = poetry.repositories.Repository() - - if with_dev_reqs: - locked_packages = lock_data["package"] - else: - locked_packages = [ - p for p in lock_data["package"] if p["category"] == "main" - ] - - if not locked_packages: - return packages - - for info in locked_packages: - package = Package(info["name"], info["version"], info["version"]) - package.description = info.get("description", "") - package.category = info["category"] - package.optional = info["optional"] - if "hashes" in lock_data["metadata"]: - # Old lock so we create dummy files from the hashes - package.files = [ - {"name": h, "hash": h} - for h in lock_data["metadata"]["hashes"][info["name"]] - ] - else: - package.files = lock_data["metadata"]["files"][info["name"]] - - package.python_versions = info["python-versions"] - extras = info.get("extras", {}) - if extras: - for name, deps in extras.items(): - package.extras[name] = [] - - for dep in deps: - m = re.match(r"^(.+?)(?:\s+\((.+)\))?$", dep) - dep_name = m.group(1) - constraint = m.group(2) or "*" - - package.extras[name].append(Dependency(dep_name, constraint)) - - if "marker" in info: - package.marker = parse_marker(info["marker"]) - else: - # Compatibility for old locks - if "requirements" in info: - dep = Dependency("foo", "0.0.0") - for name, value in info["requirements"].items(): - if name == "python": - dep.python_versions = value - elif name == "platform": - dep.platform = value - - split_dep = dep.to_pep_508(False).split(";") - if len(split_dep) > 1: - package.marker = parse_marker(split_dep[1].strip()) - - for dep_name, constraint in info.get("dependencies", {}).items(): - if isinstance(constraint, list): - for c in constraint: - package.add_dependency(dep_name, c) - - continue - - package.add_dependency(dep_name, constraint) - - if "develop" in info: - package.develop = info["develop"] - - if "source" in info: - package.source_type = info["source"].get("type", "") - package.source_url = info["source"]["url"] - package.source_reference = info["source"]["reference"] - - packages.add_package(package) - - return packages - - def set_lock_data(self, root, packages): # type: (...) -> bool - files = table() - packages = self._lock_packages(packages) - # Retrieving hashes - for package in packages: - if package["name"] not in files: - files[package["name"]] = [] - - for f in package["files"]: - file_metadata = inline_table() - for k, v in sorted(f.items()): - file_metadata[k] = v - - files[package["name"]].append(file_metadata) - - if files[package["name"]]: - files[package["name"]] = item(files[package["name"]]).multiline(True) - - del package["files"] - - lock = document() - lock.add(comment("@" + "generated")) - lock["package"] = packages - - if root.extras: - lock["extras"] = { - extra: [dep.pretty_name for dep in deps] - for extra, deps in root.extras.items() - } - - lock["metadata"] = { - "lock-version": self._VERSION, - "python-versions": root.python_versions, - "content-hash": self._content_hash, - "files": files, - } - - if not self.is_locked() or lock != self.lock_data: - self._write_lock_data(lock) - - return True - - return False - - def _write_lock_data(self, data): - self.lock.write(data) - - # Checking lock file data consistency - if data != self.lock.read(): - raise RuntimeError("Inconsistent lock file data.") - - self._lock_data = None - - def _get_content_hash(self): # type: () -> str - """ - Returns the sha256 hash of the sorted content of the pyproject file. - """ - content = self._local_config - - relevant_content = {} - for key in self._relevant_keys: - relevant_content[key] = content.get(key) - - content_hash = sha256( - json.dumps(relevant_content, sort_keys=True).encode() - ).hexdigest() - - return content_hash - - def _get_lock_data(self): # type: () -> dict - if not self._lock.exists(): - raise RuntimeError("No lockfile found. Unable to read locked packages") - - try: - lock_data = self._lock.read() - except TOMLKitError as e: - raise RuntimeError("Unable to read the lock file ({}).".format(e)) - - lock_version = Version.parse(lock_data["metadata"].get("lock-version", "1.0")) - current_version = Version.parse(self._VERSION) - # We expect the locker to be able to read lock files - # from the same semantic versioning range - accepted_versions = parse_constraint( - "^{}".format(Version(current_version.major, 0)) - ) - lock_version_allowed = accepted_versions.allows(lock_version) - if lock_version_allowed and current_version < lock_version: - logger.warning( - "The lock file might not be compatible with the current version of Poetry.\n" - "Upgrade Poetry to ensure the lock file is read properly or, alternatively, " - "regenerate the lock file with the `poetry lock` command." - ) - elif not lock_version_allowed: - raise RuntimeError( - "The lock file is not compatible with the current version of Poetry.\n" - "Upgrade Poetry to be able to read the lock file or, alternatively, " - "regenerate the lock file with the `poetry lock` command." - ) - - return lock_data - - def _lock_packages( - self, packages - ): # type: (List['poetry.packages.Package']) -> list - locked = [] - - for package in sorted(packages, key=lambda x: x.name): - spec = self._dump_package(package) - - locked.append(spec) - - return locked - - def _dump_package(self, package): # type: (Package) -> dict - dependencies = {} - for dependency in sorted(package.requires, key=lambda d: d.name): - if dependency.is_optional() and not dependency.is_activated(): - continue - - if dependency.pretty_name not in dependencies: - dependencies[dependency.pretty_name] = [] - - constraint = inline_table() - constraint["version"] = str(dependency.pretty_constraint) - - if dependency.extras: - constraint["extras"] = sorted(dependency.extras) - - if dependency.is_optional(): - constraint["optional"] = True - - if not dependency.marker.is_any(): - constraint["markers"] = str(dependency.marker) - - dependencies[dependency.pretty_name].append(constraint) - - # All the constraints should have the same type, - # but we want to simplify them if it's possible - for dependency, constraints in tuple(dependencies.items()): - if all(len(constraint) == 1 for constraint in constraints): - dependencies[dependency] = [ - constraint["version"] for constraint in constraints - ] - - data = { - "name": package.pretty_name, - "version": package.pretty_version, - "description": package.description or "", - "category": package.category, - "optional": package.optional, - "python-versions": package.python_versions, - "files": sorted(package.files, key=lambda x: x["file"]), - } - - if package.extras: - extras = {} - for name, deps in package.extras.items(): - extras[name] = [ - str(dep) if not dep.constraint.is_any() else dep.name - for dep in deps - ] - - data["extras"] = extras - - if dependencies: - for k, constraints in dependencies.items(): - if len(constraints) == 1: - dependencies[k] = constraints[0] - - data["dependencies"] = dependencies - - if package.source_url: - data["source"] = { - "url": package.source_url, - "reference": package.source_reference, - } - if package.source_type: - data["source"]["type"] = package.source_type - if package.source_type == "directory": - data["develop"] = package.develop - - return data diff --git a/src/poetry/packages/locker.py b/src/poetry/packages/locker.py index e57e60b83b7..2dffae41681 100644 --- a/src/poetry/packages/locker.py +++ b/src/poetry/packages/locker.py @@ -24,6 +24,7 @@ from poetry.core.version.markers import parse_marker from poetry.core.version.requirements import InvalidRequirement from tomlkit import array +from tomlkit import comment from tomlkit import document from tomlkit import inline_table from tomlkit import item @@ -398,6 +399,7 @@ def set_lock_data(self, root: Package, packages: list[Package]) -> bool: del package["files"] lock = document() + lock.add(comment("@" + "generated")) lock["package"] = package_specs if root.extras: diff --git a/tests/packages/test_locker.py b/tests/packages/test_locker.py index 5ca411b8b7b..606b0f93cf9 100644 --- a/tests/packages/test_locker.py +++ b/tests/packages/test_locker.py @@ -82,6 +82,8 @@ def test_lock_file_data_is_ordered(locker: Locker, root: ProjectPackage): content = f.read() expected = """\ +# @generated + [[package]] name = "A" version = "1.0.0" @@ -216,6 +218,8 @@ def test_locker_properly_loads_extras(locker: Locker): def test_locker_properly_loads_nested_extras(locker: Locker): content = """\ +# @generated + [[package]] name = "a" version = "1.0" @@ -296,6 +300,8 @@ def test_locker_properly_loads_nested_extras(locker: Locker): def test_locker_properly_loads_extras_legacy(locker: Locker): content = """\ +# @generated + [[package]] name = "a" version = "1.0" @@ -353,7 +359,10 @@ def test_lock_packages_with_null_description(locker: Locker, root: ProjectPackag with locker.lock.open(encoding="utf-8") as f: content = f.read() - expected = """[[package]] + expected = """\ +# @generated + +[[package]] name = "A" version = "1.0.0" description = "" @@ -384,7 +393,10 @@ def test_lock_file_should_not_have_mixed_types(locker: Locker, root: ProjectPack locker.set_lock_data(root, [package_a]) - expected = """[[package]] + expected = """\ +# @generated + +[[package]] name = "A" version = "1.0.0" description = "" @@ -417,7 +429,10 @@ def test_lock_file_should_not_have_mixed_types(locker: Locker, root: ProjectPack def test_reading_lock_file_should_raise_an_error_on_invalid_data(locker: Locker): - content = """[[package]] + content = """\ +# @generated + +[[package]] name = "A" version = "1.0.0" description = "" @@ -465,7 +480,10 @@ def test_locking_legacy_repository_package_should_include_source_section( with locker.lock.open(encoding="utf-8") as f: content = f.read() - expected = """[[package]] + expected = """\ +# @generated + +[[package]] name = "A" version = "1.0.0" description = "" @@ -553,7 +571,10 @@ def test_extras_dependencies_are_ordered(locker: Locker, root: ProjectPackage): locker.set_lock_data(root, [package_a]) - expected = """[[package]] + expected = """\ +# @generated + +[[package]] name = "A" version = "1.0.0" description = "" @@ -643,7 +664,9 @@ def test_locker_dumps_dependency_information_correctly( with locker.lock.open(encoding="utf-8") as f: content = f.read() - expected = """[[package]] + expected = """# @generated + +[[package]] name = "A" version = "1.0.0" description = "" @@ -674,6 +697,8 @@ def test_locked_repository_uses_root_dir_of_package( locker: Locker, mocker: MockerFixture ): content = """\ +# @generated + [[package]] name = "lib-a" version = "0.1.0" From 86525bbcc9fbc5c300b303bcd9af593f130d3b01 Mon Sep 17 00:00:00 2001 From: Vishal Kuo Date: Mon, 13 Jun 2022 09:28:46 -0700 Subject: [PATCH 05/10] code review feedback --- src/poetry/packages/locker.py | 5 +++-- tests/packages/test_locker.py | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/poetry/packages/locker.py b/src/poetry/packages/locker.py index 2dffae41681..156020911a0 100644 --- a/src/poetry/packages/locker.py +++ b/src/poetry/packages/locker.py @@ -48,7 +48,8 @@ from poetry.repositories import Repository logger = logging.getLogger(__name__) - +_GENERATED_IDENTIFIER = "@" + "generated" +GENERATED_COMMENT = f"This file is automatically {_GENERATED_IDENTIFIER} by Poetry and should not be changed by hand." class Locker: @@ -399,7 +400,7 @@ def set_lock_data(self, root: Package, packages: list[Package]) -> bool: del package["files"] lock = document() - lock.add(comment("@" + "generated")) + lock.add(comment(GENERATED_COMMENT)) lock["package"] = package_specs if root.extras: diff --git a/tests/packages/test_locker.py b/tests/packages/test_locker.py index 606b0f93cf9..20834a7b012 100644 --- a/tests/packages/test_locker.py +++ b/tests/packages/test_locker.py @@ -82,7 +82,7 @@ def test_lock_file_data_is_ordered(locker: Locker, root: ProjectPackage): content = f.read() expected = """\ -# @generated +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "A" @@ -171,7 +171,7 @@ def test_lock_file_data_is_ordered(locker: Locker, root: ProjectPackage): def test_locker_properly_loads_extras(locker: Locker): content = """\ -# @generated +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "cachecontrol" @@ -218,7 +218,7 @@ def test_locker_properly_loads_extras(locker: Locker): def test_locker_properly_loads_nested_extras(locker: Locker): content = """\ -# @generated +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "a" @@ -300,7 +300,7 @@ def test_locker_properly_loads_nested_extras(locker: Locker): def test_locker_properly_loads_extras_legacy(locker: Locker): content = """\ -# @generated +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "a" @@ -360,7 +360,7 @@ def test_lock_packages_with_null_description(locker: Locker, root: ProjectPackag content = f.read() expected = """\ -# @generated +# # This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "A" @@ -394,7 +394,7 @@ def test_lock_file_should_not_have_mixed_types(locker: Locker, root: ProjectPack locker.set_lock_data(root, [package_a]) expected = """\ -# @generated +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "A" @@ -430,7 +430,7 @@ def test_lock_file_should_not_have_mixed_types(locker: Locker, root: ProjectPack def test_reading_lock_file_should_raise_an_error_on_invalid_data(locker: Locker): content = """\ -# @generated +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "A" @@ -481,7 +481,7 @@ def test_locking_legacy_repository_package_should_include_source_section( content = f.read() expected = """\ -# @generated +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "A" @@ -543,7 +543,7 @@ def test_locker_should_raise_an_error_if_lock_version_is_newer_and_not_allowed( locker: Locker, caplog: LogCaptureFixture ): content = """\ -# @generated +# This file is automatically @generated by Poetry and should not be changed by hand. [metadata] lock-version = "2.0" @@ -572,7 +572,7 @@ def test_extras_dependencies_are_ordered(locker: Locker, root: ProjectPackage): locker.set_lock_data(root, [package_a]) expected = """\ -# @generated +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "A" @@ -664,7 +664,7 @@ def test_locker_dumps_dependency_information_correctly( with locker.lock.open(encoding="utf-8") as f: content = f.read() - expected = """# @generated + expected = """# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "A" @@ -697,7 +697,7 @@ def test_locked_repository_uses_root_dir_of_package( locker: Locker, mocker: MockerFixture ): content = """\ -# @generated +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "lib-a" From 1e810c7b73016bbec5f35f597ac43d550891c246 Mon Sep 17 00:00:00 2001 From: Vishal Kuo Date: Mon, 13 Jun 2022 09:36:14 -0700 Subject: [PATCH 06/10] fix test --- tests/packages/test_locker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/packages/test_locker.py b/tests/packages/test_locker.py index 20834a7b012..7669c21835d 100644 --- a/tests/packages/test_locker.py +++ b/tests/packages/test_locker.py @@ -360,7 +360,7 @@ def test_lock_packages_with_null_description(locker: Locker, root: ProjectPackag content = f.read() expected = """\ -# # This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "A" From d916cc95753fd1f405a008aaa98e1d5ab5b7e793 Mon Sep 17 00:00:00 2001 From: Vishal Kuo Date: Mon, 13 Jun 2022 09:40:20 -0700 Subject: [PATCH 07/10] format --- src/poetry/packages/locker.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/poetry/packages/locker.py b/src/poetry/packages/locker.py index 156020911a0..6225c17af9a 100644 --- a/src/poetry/packages/locker.py +++ b/src/poetry/packages/locker.py @@ -49,7 +49,11 @@ logger = logging.getLogger(__name__) _GENERATED_IDENTIFIER = "@" + "generated" -GENERATED_COMMENT = f"This file is automatically {_GENERATED_IDENTIFIER} by Poetry and should not be changed by hand." +GENERATED_COMMENT = ( + f"This file is automatically {_GENERATED_IDENTIFIER} by Poetry and should not be" + " changed by hand." +) + class Locker: From 936a0fdc049f6322588aeaafd19fa32d811609f9 Mon Sep 17 00:00:00 2001 From: Vishal Kuo Date: Thu, 16 Jun 2022 11:51:47 -0700 Subject: [PATCH 08/10] code review --- tests/packages/test_locker.py | 78 +++++++++++++++++------------------ 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/tests/packages/test_locker.py b/tests/packages/test_locker.py index 7669c21835d..17f8b8c79dc 100644 --- a/tests/packages/test_locker.py +++ b/tests/packages/test_locker.py @@ -17,7 +17,7 @@ from poetry.core.semver.version import Version from poetry.factory import Factory -from poetry.packages.locker import Locker +from poetry.packages.locker import Locker, GENERATED_COMMENT from tests.helpers import get_dependency from tests.helpers import get_package @@ -81,8 +81,8 @@ def test_lock_file_data_is_ordered(locker: Locker, root: ProjectPackage): with locker.lock.open(encoding="utf-8") as f: content = f.read() - expected = """\ -# This file is automatically @generated by Poetry and should not be changed by hand. + expected = f"""\ +# {GENERATED_COMMENT} [[package]] name = "A" @@ -157,9 +157,9 @@ def test_lock_file_data_is_ordered(locker: Locker, root: ProjectPackage): [metadata.files] A = [ - {file = "bar", hash = "123"}, - {file = "foo", hash = "456"}, - {file = "baz", hash = "345"}, + {{file = "bar", hash = "123"}}, + {{file = "foo", hash = "456"}}, + {{file = "baz", hash = "345"}}, ] B = [] git-package = [] @@ -170,8 +170,8 @@ def test_lock_file_data_is_ordered(locker: Locker, root: ProjectPackage): def test_locker_properly_loads_extras(locker: Locker): - content = """\ -# This file is automatically @generated by Poetry and should not be changed by hand. + content = f"""\ +# {GENERATED_COMMENT} [[package]] name = "cachecontrol" @@ -217,8 +217,8 @@ def test_locker_properly_loads_extras(locker: Locker): def test_locker_properly_loads_nested_extras(locker: Locker): - content = """\ -# This file is automatically @generated by Poetry and should not be changed by hand. + content = f"""\ +# {GENERATED_COMMENT} [[package]] name = "a" @@ -229,7 +229,7 @@ def test_locker_properly_loads_nested_extras(locker: Locker): python-versions = "*" [package.dependencies] -b = {version = "^1.0", optional = true, extras = "c"} +b = {{version = "^1.0", optional = true, extras = "c"}} [package.extras] b = ["b[c] (>=1.0,<2.0)"] @@ -243,7 +243,7 @@ def test_locker_properly_loads_nested_extras(locker: Locker): python-versions = "*" [package.dependencies] -c = {version = "^1.0", optional = true} +c = {{version = "^1.0", optional = true}} [package.extras] c = ["c (>=1.0,<2.0)"] @@ -299,8 +299,8 @@ def test_locker_properly_loads_nested_extras(locker: Locker): def test_locker_properly_loads_extras_legacy(locker: Locker): - content = """\ -# This file is automatically @generated by Poetry and should not be changed by hand. + content = f"""\ +# {GENERATED_COMMENT} [[package]] name = "a" @@ -311,7 +311,7 @@ def test_locker_properly_loads_extras_legacy(locker: Locker): python-versions = "*" [package.dependencies] -b = {version = "^1.0", optional = true} +b = {{version = "^1.0", optional = true}} [package.extras] b = ["b (^1.0)"] @@ -359,8 +359,8 @@ def test_lock_packages_with_null_description(locker: Locker, root: ProjectPackag with locker.lock.open(encoding="utf-8") as f: content = f.read() - expected = """\ -# This file is automatically @generated by Poetry and should not be changed by hand. + expected = f"""\ +# {GENERATED_COMMENT} [[package]] name = "A" @@ -393,8 +393,8 @@ def test_lock_file_should_not_have_mixed_types(locker: Locker, root: ProjectPack locker.set_lock_data(root, [package_a]) - expected = """\ -# This file is automatically @generated by Poetry and should not be changed by hand. + expected = f"""\ +# {GENERATED_COMMENT} [[package]] name = "A" @@ -406,8 +406,8 @@ def test_lock_file_should_not_have_mixed_types(locker: Locker, root: ProjectPack [package.dependencies] B = [ - {version = "^1.0.0"}, - {version = ">=1.0.0", optional = true}, + {{version = "^1.0.0"}}, + {{version = ">=1.0.0", optional = true}}, ] [package.extras] @@ -429,8 +429,8 @@ def test_lock_file_should_not_have_mixed_types(locker: Locker, root: ProjectPack def test_reading_lock_file_should_raise_an_error_on_invalid_data(locker: Locker): - content = """\ -# This file is automatically @generated by Poetry and should not be changed by hand. + content = f"""\ +# {GENERATED_COMMENT} [[package]] name = "A" @@ -480,8 +480,8 @@ def test_locking_legacy_repository_package_should_include_source_section( with locker.lock.open(encoding="utf-8") as f: content = f.read() - expected = """\ -# This file is automatically @generated by Poetry and should not be changed by hand. + expected = f"""\ +# {GENERATED_COMMENT} [[package]] name = "A" @@ -542,8 +542,8 @@ def test_locker_should_emit_warnings_if_lock_version_is_newer_but_allowed( def test_locker_should_raise_an_error_if_lock_version_is_newer_and_not_allowed( locker: Locker, caplog: LogCaptureFixture ): - content = """\ -# This file is automatically @generated by Poetry and should not be changed by hand. + content = f"""\ +# {GENERATED_COMMENT} [metadata] lock-version = "2.0" @@ -571,8 +571,8 @@ def test_extras_dependencies_are_ordered(locker: Locker, root: ProjectPackage): locker.set_lock_data(root, [package_a]) - expected = """\ -# This file is automatically @generated by Poetry and should not be changed by hand. + expected = f"""\ +# {GENERATED_COMMENT} [[package]] name = "A" @@ -583,7 +583,7 @@ def test_extras_dependencies_are_ordered(locker: Locker, root: ProjectPackage): python-versions = "*" [package.dependencies] -B = {version = "^1.0.0", extras = ["a", "b", "c"], optional = true} +B = {{version = "^1.0.0", extras = ["a", "b", "c"], optional = true}} [metadata] lock-version = "1.1" @@ -664,7 +664,7 @@ def test_locker_dumps_dependency_information_correctly( with locker.lock.open(encoding="utf-8") as f: content = f.read() - expected = """# This file is automatically @generated by Poetry and should not be changed by hand. + expected = f"""# {GENERATED_COMMENT} [[package]] name = "A" @@ -675,11 +675,11 @@ def test_locker_dumps_dependency_information_correctly( python-versions = "*" [package.dependencies] -B = {path = "project_with_extras", develop = true} -C = {path = "directory/project_with_transitive_directory_dependencies"} -D = {path = "distributions/demo-0.1.0.tar.gz"} -E = {url = "https://python-poetry.org/poetry-1.2.0.tar.gz"} -F = {git = "https://github.com/python-poetry/poetry.git", branch = "foo"} +B = {{path = "project_with_extras", develop = true}} +C = {{path = "directory/project_with_transitive_directory_dependencies"}} +D = {{path = "distributions/demo-0.1.0.tar.gz"}} +E = {{url = "https://python-poetry.org/poetry-1.2.0.tar.gz"}} +F = {{git = "https://github.com/python-poetry/poetry.git", branch = "foo"}} [metadata] lock-version = "1.1" @@ -696,8 +696,8 @@ def test_locker_dumps_dependency_information_correctly( def test_locked_repository_uses_root_dir_of_package( locker: Locker, mocker: MockerFixture ): - content = """\ -# This file is automatically @generated by Poetry and should not be changed by hand. + content = f"""\ +# {GENERATED_COMMENT} [[package]] name = "lib-a" @@ -709,7 +709,7 @@ def test_locked_repository_uses_root_dir_of_package( develop = true [package.dependencies] -lib-b = {path = "../libB", develop = true} +lib-b = {{path = "../libB", develop = true}} [package.source] type = "directory" From 9b54ad3d75bb2a30ec6016f2bd1c605bfa5a5ed1 Mon Sep 17 00:00:00 2001 From: Vishal Kuo Date: Fri, 24 Jun 2022 09:45:27 -0700 Subject: [PATCH 09/10] lint --- .flake8 | 2 ++ tests/packages/test_locker.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index c2389cff812..159336a2ceb 100644 --- a/.flake8 +++ b/.flake8 @@ -23,6 +23,8 @@ per-file-ignores = # ANN201: Missing return type annotation for public function tests/test_*:ANN201 tests/**/test_*:ANN201 + # E800: Found commented out code + tests/packages/test_locker.py:E800 extend-exclude = # Frozen and not subject to change in this repo: get-poetry.py, diff --git a/tests/packages/test_locker.py b/tests/packages/test_locker.py index 17f8b8c79dc..4f2d6d55a62 100644 --- a/tests/packages/test_locker.py +++ b/tests/packages/test_locker.py @@ -17,7 +17,8 @@ from poetry.core.semver.version import Version from poetry.factory import Factory -from poetry.packages.locker import Locker, GENERATED_COMMENT +from poetry.packages.locker import GENERATED_COMMENT +from poetry.packages.locker import Locker from tests.helpers import get_dependency from tests.helpers import get_package From aa641e64c4c714e36bac4b07c7835c67f641f49a Mon Sep 17 00:00:00 2001 From: Vishal Kuo Date: Fri, 24 Jun 2022 09:53:15 -0700 Subject: [PATCH 10/10] actually fix lint --- .flake8 | 2 -- tests/packages/test_locker.py | 22 +++++++++++----------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/.flake8 b/.flake8 index 159336a2ceb..c2389cff812 100644 --- a/.flake8 +++ b/.flake8 @@ -23,8 +23,6 @@ per-file-ignores = # ANN201: Missing return type annotation for public function tests/test_*:ANN201 tests/**/test_*:ANN201 - # E800: Found commented out code - tests/packages/test_locker.py:E800 extend-exclude = # Frozen and not subject to change in this repo: get-poetry.py, diff --git a/tests/packages/test_locker.py b/tests/packages/test_locker.py index 4f2d6d55a62..0b7233544cf 100644 --- a/tests/packages/test_locker.py +++ b/tests/packages/test_locker.py @@ -165,7 +165,7 @@ def test_lock_file_data_is_ordered(locker: Locker, root: ProjectPackage): B = [] git-package = [] url-package = [] -""" +""" # noqa: E800 assert content == expected @@ -201,7 +201,7 @@ def test_locker_properly_loads_extras(locker: Locker): [metadata.files] cachecontrol = [] -""" +""" # noqa: E800 locker.lock.write(tomlkit.parse(content)) @@ -266,7 +266,7 @@ def test_locker_properly_loads_nested_extras(locker: Locker): "a" = [] "b" = [] "c" = [] -""" +""" # noqa: E800 locker.lock.write(tomlkit.parse(content)) @@ -333,7 +333,7 @@ def test_locker_properly_loads_extras_legacy(locker: Locker): [metadata.files] "a" = [] "b" = [] -""" +""" # noqa: E800 locker.lock.write(tomlkit.parse(content)) @@ -378,7 +378,7 @@ def test_lock_packages_with_null_description(locker: Locker, root: ProjectPackag [metadata.files] A = [] -""" +""" # noqa: E800 assert content == expected @@ -421,7 +421,7 @@ def test_lock_file_should_not_have_mixed_types(locker: Locker, root: ProjectPack [metadata.files] A = [] -""" +""" # noqa: E800 with locker.lock.open(encoding="utf-8") as f: content = f.read() @@ -454,7 +454,7 @@ def test_reading_lock_file_should_raise_an_error_on_invalid_data(locker: Locker) [metadata.files] A = [] -""" +""" # noqa: E800 with locker.lock.open("w", encoding="utf-8") as f: f.write(content) @@ -504,7 +504,7 @@ def test_locking_legacy_repository_package_should_include_source_section( [metadata.files] A = [] -""" +""" # noqa: E800 assert content == expected @@ -552,7 +552,7 @@ def test_locker_should_raise_an_error_if_lock_version_is_newer_and_not_allowed( content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77" [metadata.files] -""" +""" # noqa: E800 caplog.set_level(logging.WARNING, logger="poetry.packages.locker") locker.lock.write(tomlkit.parse(content)) @@ -593,7 +593,7 @@ def test_extras_dependencies_are_ordered(locker: Locker, root: ProjectPackage): [metadata.files] A = [] -""" +""" # noqa: E800 with locker.lock.open(encoding="utf-8") as f: content = f.read() @@ -724,7 +724,7 @@ def test_locked_repository_uses_root_dir_of_package( [metadata.files] lib-a = [] lib-b = [] -""" +""" # noqa: E800 locker.lock.write(tomlkit.parse(content)) create_dependency_patch = mocker.patch(