Skip to content

Commit 3f718c5

Browse files
0xDEC0DEnisimond
andauthored
Simplify/improve Package.clone() (#159)
Downstream clients (e.g., poetry) appear to assume that the result of a Package.clone() will be a full-fidelity copy of the original. Use `copy.deepcopy` to clone the object, and ensure that this is the case. Resolves Issue #2422 Co-authored-by: Nicolas Simonds <[email protected]>
1 parent fe476e0 commit 3f718c5

File tree

2 files changed

+31
-27
lines changed

2 files changed

+31
-27
lines changed

poetry/core/packages/package.py

+2-27
Original file line numberDiff line numberDiff line change
@@ -428,33 +428,8 @@ def without_features(self) -> "Package":
428428
return self.with_features([])
429429

430430
def clone(self) -> "Package":
431-
if self.is_root():
432-
clone = self.__class__(self.pretty_name, self.version)
433-
else:
434-
clone = self.__class__(
435-
self.pretty_name,
436-
self.version,
437-
source_type=self._source_type,
438-
source_url=self._source_url,
439-
source_reference=self._source_reference,
440-
features=list(self.features),
441-
)
442-
443-
clone.description = self.description
444-
clone.category = self.category
445-
clone.optional = self.optional
446-
clone.python_versions = self.python_versions
447-
clone.marker = self.marker
448-
clone.extras = self.extras
449-
clone.root_dir = self.root_dir
450-
clone.develop = self.develop
451-
452-
for dep in self.requires:
453-
clone.requires.append(dep)
454-
455-
for dep in self.dev_requires:
456-
clone.dev_requires.append(dep)
457-
431+
clone = self.__class__(self.pretty_name, self.version)
432+
clone.__dict__ = copy.deepcopy(self.__dict__)
458433
return clone
459434

460435
def __hash__(self) -> int:

tests/packages/test_package.py

+29
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import unicode_literals
22

3+
import random
4+
35
from pathlib import Path
46

57
import pytest
@@ -280,3 +282,30 @@ def test_to_dependency_for_url():
280282
assert "https://example.com/path.tar.gz" == dep.url
281283
assert "url" == dep.source_type
282284
assert "https://example.com/path.tar.gz" == dep.source_url
285+
286+
287+
def test_package_clone(f):
288+
# TODO(nic): this test is not future-proof, in that any attributes added
289+
# to the Package object and not filled out in this test setup might
290+
# cause comparisons to match that otherwise should not. A factory method
291+
# to create a Package object with all fields fully randomized would be the
292+
# most rigorous test for this, but that's likely overkill.
293+
p = Package(
294+
"lol_wut",
295+
"3.141.5926535",
296+
pretty_version="③.⑭.⑮",
297+
source_type="git",
298+
source_url="http://some.url",
299+
source_reference="fe4d2adabf3feb5d32b70ab5c105285fa713b10c",
300+
source_resolved_reference="fe4d2adabf3feb5d32b70ab5c105285fa713b10c",
301+
features=["abc", "def"],
302+
develop=random.choice((True, False)),
303+
)
304+
p.files = (["file1", "file2", "file3"],)
305+
p.homepage = "https://some.other.url"
306+
p.repository_url = "http://bug.farm"
307+
p.documentation_url = "http://lorem.ipsum/dolor/sit.amet"
308+
p2 = p.clone()
309+
310+
assert p == p2
311+
assert p.__dict__ == p2.__dict__

0 commit comments

Comments
 (0)