未验证 提交 ce0478fc 编写于 作者: F frostming

write tests for update and remove

上级 57068eac
......@@ -5,18 +5,6 @@ version = "19.3.1"
marker = "python_version >= \"2.7\" and python_version not in \"3.0, 3.1, 3.2, 3.3, 3.4\""
summary = "The PyPA recommended tool for installing Python packages."
[[package]]
name = "parver"
sections = ["default"]
version = "0.2.1"
marker = "python_version >= \"2.7\" and python_version not in \"3.0, 3.1, 3.2, 3.3\""
summary = "Parse and manipulate version numbers."
[package.dependencies]
arpeggio = "~=1.7"
attrs = ">=17.4.0"
six = "~=1.9"
[[package]]
name = "appdirs"
sections = ["default"]
......@@ -147,13 +135,6 @@ summary = "TextUI colors for Python."
[package.dependencies]
colorama = "*"
[[package]]
name = "arpeggio"
sections = ["default"]
version = "1.9.2"
marker = "python_version >= \"2.7\" and python_version not in \"3.0, 3.1, 3.2, 3.3\""
summary = "Packrat parser interpreter"
[[package]]
name = "attrs"
sections = ["default", "dev"]
......@@ -161,13 +142,6 @@ version = "19.3.0"
marker = "python_version >= \"2.7\""
summary = "Classes Without Boilerplate"
[[package]]
name = "six"
sections = ["default", "dev"]
version = "1.14.0"
marker = "python_version >= \"2.7\" and python_version not in \"3.0, 3.1, 3.2\""
summary = "Python 2 and 3 compatibility utilities"
[[package]]
name = "atomicwrites"
sections = ["dev"]
......@@ -207,12 +181,19 @@ summary = "More routines for operating on iterables, beyond itertools"
name = "importlib-metadata"
sections = ["dev"]
version = "1.4.0"
marker = "python_version >= \"3.5\" and python_version < \"3.8\""
marker = "python_version < \"3.8\" and python_version >= \"3.5\""
summary = "Read metadata from Python packages"
[package.dependencies]
zipp = ">=0.5"
[[package]]
name = "six"
sections = ["default", "dev"]
version = "1.14.0"
marker = "python_version >= \"2.7\" and python_version not in \"3.0, 3.1, 3.2\""
summary = "Python 2 and 3 compatibility utilities"
[[package]]
name = "vistir"
sections = ["default"]
......@@ -267,7 +248,7 @@ summary = "Easily download, build, install, upgrade, and uninstall Python packag
name = "zipp"
sections = ["dev"]
version = "1.0.0"
marker = "python_version >= \"3.5\" and python_version < \"3.8\""
marker = "python_version < \"3.8\" and python_version >= \"3.5\""
summary = "Backport of pathlib-compatible object wrapper for zip files"
[package.dependencies]
......@@ -288,16 +269,152 @@ marker = "python_version >= \"2.7\" and python_version not in \"3.0, 3.1, 3.2\""
summary = "Python parsing module"
[metadata]
"pip 19.3.1" = [
{file = "pip-19.3.1-py2.py3-none-any.whl", hash = "sha256:6917c65fc3769ecdc61405d3dfd97afdedd75808d200b2838d7d961cebc0c2c7"},
{file = "pip-19.3.1.tar.gz", hash = "sha256:21207d76c1031e517668898a6b46a9fb1501c7a4710ef5dfd6a40ad9e6757ea7"},
"appdirs 1.4.3" = [
{file = "appdirs-1.4.3.tar.gz", hash = "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"},
{file = "appdirs-1.4.3-py2.py3-none-any.whl", hash = "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"},
]
"pip-shims 0.4.0" = [
{file = "pip_shims-0.4.0-py2.py3-none-any.whl", hash = "sha256:d4b720d85a8cbd81f72ea22e273ac72415f1e0b49cade597b815c63b351d9637"},
{file = "pip_shims-0.4.0.tar.gz", hash = "sha256:383e054386d15f7a33d619a9fc19d670575cdf88e05a4dab93f0a254696ce836"},
]
"distlib 0.3.0" = [
{file = "distlib-0.3.0.zip", hash = "sha256:2e166e231a26b36d6dfe35a48c4464346620f8645ed0ace01ee31822b288de21"},
]
"tomlkit 0.5.8" = [
{file = "tomlkit-0.5.8-py2.py3-none-any.whl", hash = "sha256:96e6369288571799a3052c1ef93b9de440e1ab751aa045f435b55e9d3bcd0690"},
{file = "tomlkit-0.5.8.tar.gz", hash = "sha256:32c10cc16ded7e4101c79f269910658cc2a0be5913f1252121c3cd603051c269"},
]
"pythonfinder 1.2.1" = [
{file = "pythonfinder-1.2.1-py2.py3-none-any.whl", hash = "sha256:cfbfe61b7bfc3b45b24f156e2bab76621ebc6ba92f69afbc16f76482d69d9802"},
{file = "pythonfinder-1.2.1.tar.gz", hash = "sha256:0a4f585abb76aa2fc97479cd12d10f7644aa1ab42b919747e04d33d7f9379425"},
]
"pytest-cov 2.8.1" = [
{file = "pytest-cov-2.8.1.tar.gz", hash = "sha256:cc6742d8bac45070217169f5f72ceee1e0e55b0221f54bcf24845972d3a47f2b"},
{file = "pytest_cov-2.8.1-py2.py3-none-any.whl", hash = "sha256:cdbdef4f870408ebdbfeb44e63e07eb18bb4619fae852f6e760645fa36172626"},
]
"click 7.0" = [
{file = "Click-7.0-py2.py3-none-any.whl", hash = "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13"},
{file = "Click-7.0.tar.gz", hash = "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"},
]
"pytest-mock 2.0.0" = [
{file = "pytest-mock-2.0.0.tar.gz", hash = "sha256:b35eb281e93aafed138db25c8772b95d3756108b601947f89af503f8c629413f"},
{file = "pytest_mock-2.0.0-py2.py3-none-any.whl", hash = "sha256:cb67402d87d5f53c579263d37971a164743dc33c159dfb4fb4a86f37c5552307"},
]
"pytest 5.3.3" = [
{file = "pytest-5.3.3-py3-none-any.whl", hash = "sha256:9f8d44f4722b3d06b41afaeb8d177cfbe0700f8351b1fc755dd27eedaa3eb9e0"},
{file = "pytest-5.3.3.tar.gz", hash = "sha256:f5d3d0e07333119fe7d4af4ce122362dc4053cdd34a71d2766290cf5369c64ad"},
]
"pluggy 0.13.1" = [
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
]
"vistir[spinner] 0.5.0" = [
{file = "vistir-0.5.0-py2.py3-none-any.whl", hash = "sha256:e47afdec8baf35032a8d17116765f751ecd2f2146d47e5af457c5de1fe5a334e"},
{file = "vistir-0.5.0.tar.gz", hash = "sha256:33f8e905d40a77276b3d5310c8b57c1479a4e46930042b4894fcf7ed60ad76c4"},
]
"crayons 0.3.0" = [
{file = "crayons-0.3.0.tar.gz", hash = "sha256:50e5fa729d313e2c607ae8bf7b53bb487652e10bd8e7a1e08c4bc8bf62755ffc"},
{file = "crayons-0.3.0-py2.py3-none-any.whl", hash = "sha256:8c9e4a3a607bc10e9a9140d496ecd16c6805088dd16c852c378f1f1d5db7aeb6"},
]
"attrs 19.3.0" = [
{file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"},
{file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
]
"atomicwrites 1.3.0" = [
{file = "atomicwrites-1.3.0.tar.gz", hash = "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"},
{file = "atomicwrites-1.3.0-py2.py3-none-any.whl", hash = "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4"},
]
"wcwidth 0.1.8" = [
{file = "wcwidth-0.1.8.tar.gz", hash = "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8"},
{file = "wcwidth-0.1.8-py2.py3-none-any.whl", hash = "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603"},
]
"py 1.8.1" = [
{file = "py-1.8.1-py2.py3-none-any.whl", hash = "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"},
{file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"},
]
"cached-property 1.5.1" = [
{file = "cached-property-1.5.1.tar.gz", hash = "sha256:9217a59f14a5682da7c4b8829deadbfc194ac22e9908ccf7c8820234e80a1504"},
{file = "cached_property-1.5.1-py2.py3-none-any.whl", hash = "sha256:3a026f1a54135677e7da5ce819b0c690f156f37976f3e30c5430740725203d7f"},
]
"more-itertools 8.1.0" = [
{file = "more-itertools-8.1.0.tar.gz", hash = "sha256:c468adec578380b6281a114cb8a5db34eb1116277da92d7c46f904f0b52d3288"},
{file = "more_itertools-8.1.0-py3-none-any.whl", hash = "sha256:1a2a32c72400d365000412fe08eb4a24ebee89997c18d3d147544f70f5403b39"},
]
"importlib-metadata 1.4.0" = [
{file = "importlib_metadata-1.4.0-py2.py3-none-any.whl", hash = "sha256:bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359"},
{file = "importlib_metadata-1.4.0.tar.gz", hash = "sha256:f17c015735e1a88296994c0697ecea7e11db24290941983b08c9feb30921e6d8"},
]
"six 1.14.0" = [
{file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"},
{file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"},
]
"vistir 0.5.0" = [
{file = "vistir-0.5.0-py2.py3-none-any.whl", hash = "sha256:e47afdec8baf35032a8d17116765f751ecd2f2146d47e5af457c5de1fe5a334e"},
{file = "vistir-0.5.0.tar.gz", hash = "sha256:33f8e905d40a77276b3d5310c8b57c1479a4e46930042b4894fcf7ed60ad76c4"},
]
"packaging 20.0" = [
{file = "packaging-20.0-py2.py3-none-any.whl", hash = "sha256:aec3fdbb8bc9e4bb65f0634b9f551ced63983a529d6a8931817d52fdd0816ddb"},
{file = "packaging-20.0.tar.gz", hash = "sha256:fe1d8331dfa7cc0a883b49d75fc76380b2ab2734b220fbb87d774e4fd4b851f8"},
]
"colorama 0.4.3" = [
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
]
"wheel 0.33.6" = [
{file = "wheel-0.33.6-py2.py3-none-any.whl", hash = "sha256:f4da1763d3becf2e2cd92a14a7c920f0f00eca30fdde9ea992c836685b9faf28"},
{file = "wheel-0.33.6.tar.gz", hash = "sha256:10c9da68765315ed98850f8e048347c3eb06dd81822dc2ab1d4fde9dc9702646"},
]
"coverage 4.4.2" = [
{file = "coverage-4.4.2.tar.gz", hash = "sha256:309d91bd7a35063ec7a0e4d75645488bfab3f0b66373e7722f23da7f5b0f34cc"},
{file = "coverage-4.4.2-cp26-cp26m-macosx_10_10_x86_64.whl", hash = "sha256:d1ee76f560c3c3e8faada866a07a32485445e16ed2206ac8378bd90dadffb9f0"},
{file = "coverage-4.4.2-cp26-cp26m-manylinux1_i686.whl", hash = "sha256:007eeef7e23f9473622f7d94a3e029a45d55a92a1f083f0f3512f5ab9a669b05"},
{file = "coverage-4.4.2-cp26-cp26m-manylinux1_x86_64.whl", hash = "sha256:17307429935f96c986a1b1674f78079528833410750321d22b5fb35d1883828e"},
{file = "coverage-4.4.2-cp26-cp26mu-manylinux1_i686.whl", hash = "sha256:845fddf89dca1e94abe168760a38271abfc2e31863fbb4ada7f9a99337d7c3dc"},
{file = "coverage-4.4.2-cp26-cp26mu-manylinux1_x86_64.whl", hash = "sha256:3f4d0b3403d3e110d2588c275540649b1841725f5a11a7162620224155d00ba2"},
{file = "coverage-4.4.2-cp27-cp27m-macosx_10_12_intel.whl", hash = "sha256:4c4f368ffe1c2e7602359c2c50233269f3abe1c48ca6b288dcd0fb1d1c679733"},
{file = "coverage-4.4.2-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:f8c55dd0f56d3d618dfacf129e010cbe5d5f94b6951c1b2f13ab1a2f79c284da"},
{file = "coverage-4.4.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:cdd92dd9471e624cd1d8c1a2703d25f114b59b736b0f1f659a98414e535ffb3d"},
{file = "coverage-4.4.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2ad357d12971e77360034c1596011a03f50c0f9e1ecd12e081342b8d1aee2236"},
{file = "coverage-4.4.2-cp27-cp27m-win32.whl", hash = "sha256:700d7579995044dc724847560b78ac786f0ca292867447afda7727a6fbaa082e"},
{file = "coverage-4.4.2-cp27-cp27m-win_amd64.whl", hash = "sha256:66f393e10dd866be267deb3feca39babba08ae13763e0fc7a1063cbe1f8e49f6"},
{file = "coverage-4.4.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:e9a0e1caed2a52f15c96507ab78a48f346c05681a49c5b003172f8073da6aa6b"},
{file = "coverage-4.4.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:eea9135432428d3ca7ee9be86af27cb8e56243f73764a9b6c3e0bda1394916be"},
{file = "coverage-4.4.2-cp33-cp33m-macosx_10_10_x86_64.whl", hash = "sha256:5ff16548492e8a12e65ff3d55857ccd818584ed587a6c2898a9ebbe09a880674"},
{file = "coverage-4.4.2-cp33-cp33m-manylinux1_i686.whl", hash = "sha256:d00e29b78ff610d300b2c37049a41234d48ea4f2d2581759ebcf67caaf731c31"},
{file = "coverage-4.4.2-cp33-cp33m-manylinux1_x86_64.whl", hash = "sha256:87d942863fe74b1c3be83a045996addf1639218c2cb89c5da18c06c0fe3917ea"},
{file = "coverage-4.4.2-cp34-cp34m-macosx_10_10_x86_64.whl", hash = "sha256:358d635b1fc22a425444d52f26287ae5aea9e96e254ff3c59c407426f44574f4"},
{file = "coverage-4.4.2-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:81912cfe276e0069dca99e1e4e6be7b06b5fc8342641c6b472cb2fed7de7ae18"},
{file = "coverage-4.4.2-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:079248312838c4c8f3494934ab7382a42d42d5f365f0cf7516f938dbb3f53f3f"},
{file = "coverage-4.4.2-cp34-cp34m-win32.whl", hash = "sha256:b0059630ca5c6b297690a6bf57bf2fdac1395c24b7935fd73ee64190276b743b"},
{file = "coverage-4.4.2-cp34-cp34m-win_amd64.whl", hash = "sha256:493082f104b5ca920e97a485913de254cbe351900deed72d4264571c73464cd0"},
{file = "coverage-4.4.2-cp35-cp35m-macosx_10_10_x86_64.whl", hash = "sha256:e3ba9b14607c23623cf38f90b23f5bed4a3be87cbfa96e2e9f4eabb975d1e98b"},
{file = "coverage-4.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:82cbd3317320aa63c65555aa4894bf33a13fb3a77f079059eb5935eea415938d"},
{file = "coverage-4.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9721f1b7275d3112dc7ccf63f0553c769f09b5c25a26ee45872c7f5c09edf6c1"},
{file = "coverage-4.4.2-cp35-cp35m-win32.whl", hash = "sha256:bd4800e32b4c8d99c3a2c943f1ac430cbf80658d884123d19639bcde90dad44a"},
{file = "coverage-4.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:f29841e865590af72c4b90d7b5b8e93fd560f5dea436c1d5ee8053788f9285de"},
{file = "coverage-4.4.2-cp36-cp36m-macosx_10_12_x86_64.whl", hash = "sha256:f3a5c6d054c531536a83521c00e5d4004f1e126e2e2556ce399bef4180fbe540"},
{file = "coverage-4.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:dd707a21332615108b736ef0b8513d3edaf12d2a7d5fc26cd04a169a8ae9b526"},
{file = "coverage-4.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2e1a5c6adebb93c3b175103c2f855eda957283c10cf937d791d81bef8872d6ca"},
{file = "coverage-4.4.2-cp36-cp36m-win32.whl", hash = "sha256:f87f522bde5540d8a4b11df80058281ac38c44b13ce29ced1e294963dd51a8f8"},
{file = "coverage-4.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a7cfaebd8f24c2b537fa6a271229b051cdac9c1734bb6f939ccfc7c055689baa"},
]
"setuptools 45.0.0" = [
{file = "setuptools-45.0.0-py2.py3-none-any.whl", hash = "sha256:001c474c175697a03e2afffd87d92411c89215be5f2cd3e0ab80a67726c0f4c2"},
{file = "setuptools-45.0.0.zip", hash = "sha256:c46d9c8f2289535457d36c676b541ca78f7dcb736b97d02f50d17f7f15b583cc"},
]
"zipp 1.0.0" = [
{file = "zipp-1.0.0-py2.py3-none-any.whl", hash = "sha256:8dda78f06bd1674bd8720df8a50bb47b6e1233c503a4eed8e7810686bde37656"},
{file = "zipp-1.0.0.tar.gz", hash = "sha256:d38fbe01bbf7a3593a32bc35a9c4453c32bc42b98c377f9bff7e9f8da157786c"},
]
"yaspin 0.16.0" = [
{file = "yaspin-0.16.0.tar.gz", hash = "sha256:efca3eb7162e575d3ab2e49743cd9bd1f5ec2adc7d85b9489ab145a3f6460ed4"},
{file = "yaspin-0.16.0-py2.py3-none-any.whl", hash = "sha256:e88bf9c9fe4ac588e3620588aadae655dfc20f1f7460338394ef4693bdc2b800"},
]
"pyparsing 2.4.6" = [
{file = "pyparsing-2.4.6-py2.py3-none-any.whl", hash = "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec"},
{file = "pyparsing-2.4.6.tar.gz", hash = "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f"},
]
[root]
content_hash = "md5:2cb630f9bbca74c542dd5f9af44d03eb"
content_hash = "md5:17695868674c09e56b01814bc5ec0fab"
meta_version = "0.0.1"
import itertools
import time
from typing import Dict, Iterable, Optional, Tuple
from typing import Dict, Iterable, Optional, Sequence
import tomlkit
from pkg_resources import safe_name
from pdm.exceptions import PdmUsageError
from pdm.installers import Synchronizer
from pdm.models.candidates import Candidate, identify
from pdm.models.requirements import parse_requirement
from pdm.models.requirements import parse_requirement, strip_extras
from pdm.models.specifiers import bump_version, get_specifier
from pdm.project import Project
from pdm.resolver import (
......@@ -54,15 +56,13 @@ def format_lockfile(mapping, fetched_dependencies, summary_collection):
def do_lock(
project: Project,
strategy: str = "reuse",
preferred_pins: Optional[Dict[str, Candidate]] = None,
strategy: str = "all",
tracked_names: Optional[Iterable[str]] = None,
) -> Dict[str, Candidate]:
"""Performs the locking process and update lockfile.
:param project: the project instance
:param strategy: update stratege: reuse/eager
:param preferred_pins: pins that will be reused if possible
:param strategy: update stratege: reuse/eager/all
:param tracked_names: required when using eager strategy
"""
# TODO: multiple dependency definitions for the same package.
......@@ -70,12 +70,13 @@ def do_lock(
requirements = project.all_dependencies
allow_prereleases = project.allow_prereleases
requires_python = project.python_requires
if not preferred_pins:
if strategy == "all":
provider = BaseProvider(repository, requires_python, allow_prereleases)
else:
provider_class = (
ReusePinProvider if strategy == "reuse" else EagerUpdateProvider
)
preferred_pins = project.get_locked_candidates("__all__")
provider = provider_class(
preferred_pins,
tracked_names or (),
......@@ -100,7 +101,7 @@ def do_lock(
def do_sync(
project: Project,
sections: Tuple[str, ...] = (),
sections: Sequence[str] = (),
dev: bool = False,
default: bool = True,
dry_run: bool = False,
......@@ -131,7 +132,7 @@ def do_add(
project: Project,
dev: bool = False,
section: Optional[str] = None,
install: bool = True,
sync: bool = True,
save: str = "compatible",
strategy: str = "reuse",
editables: Iterable[str] = (),
......@@ -142,7 +143,7 @@ def do_add(
:param project: the project instance
:param dev: add to dev dependencies seciton
:param section: specify section to be add to
:param install: whether to install added packages
:param sync: whether to install added packages
:param save: save strategy
:param strategy: update strategy
:param editables: editable requirements
......@@ -150,21 +151,18 @@ def do_add(
"""
if not editables and not packages:
raise PdmUsageError("Must specify at least one package or editable package.")
if dev:
section = "dev"
section = "dev" if dev else section or "default"
tracked_names = set()
requirements = {}
for r in [parse_requirement(line, True) for line in editables] + [
parse_requirement(line) for line in packages
]:
key = identify(r)
r.from_section = section or "default"
r.from_section = section
tracked_names.add(key)
requirements[key] = r
project.add_dependencies(requirements)
resolved = do_lock(
project, strategy, project.get_locked_candidates("__all__"), tracked_names
)
resolved = do_lock(project, strategy, tracked_names)
for name in tracked_names:
r = requirements[name]
if r.is_named and not r.specifier:
......@@ -182,7 +180,7 @@ def do_add(
lockfile["root"]["content_hash"] = "md5:" + project.get_content_hash("md5")
project.write_lockfile(lockfile)
if install:
if sync:
do_sync(
project,
sections=(section,),
......@@ -191,3 +189,86 @@ def do_add(
dry_run=False,
clean=False,
)
def do_update(
project: Project,
dev: bool = False,
sections: Sequence[str] = (),
default: bool = True,
strategy: str = "reuse",
packages: Sequence[str] = (),
) -> None:
"""Update specified packages or all packages
:param project: The project instance
:param dev: whether to update dev dependencies
:param sections: update speicified sections
:param default: update default
:param strategy: update strategy (reuse/eager)
:param packages: specified packages to update
:return: None
"""
if len(packages) > 0 and (len(sections) > 1 or not default):
raise PdmUsageError(
"packages argument can't be used together with multple -s or --no-default."
)
if not packages:
# pdm update with no packages given, same as 'lock' + 'sync'
do_lock(project)
do_sync(project, sections, dev, default, clean=False)
return
section = sections[0] if sections else ("dev" if dev else "default")
dependencies = project.get_dependencies(section)
tracked_names = set()
for name in packages:
key = safe_name(name).lower()
matched_name = next(
filter(lambda k: strip_extras(name)[0] == key, dependencies.keys()), None,
)
if not matched_name:
raise PdmUsageError(f"{name} is not found in {section} dependencies")
tracked_names.add(matched_name)
do_lock(project, strategy, tracked_names)
do_sync(project, sections=(section,), default=False, clean=False)
def do_remove(
project: Project,
dev: bool = False,
section: Optional[str] = None,
sync: bool = True,
packages: Sequence[str] = (),
):
"""Remove packages from working set and pyproject.toml
:param project: The project instance
:param dev: Remove package from dev-dependencies
:param section: Remove package from given section
:param sync: Whether perform syncing action
:param packages: Package names to be removed
:return: None
"""
if not packages:
raise PdmUsageError("Must specify at least one package to remove.")
section = "dev" if dev else section or "default"
toml_section = f"{section}-dependencies" if section != "default" else "dependencies"
if toml_section not in project.pyproject:
raise PdmUsageError(f"No such section {toml_section!r} in pyproject.toml.")
deps = project.pyproject[toml_section]
for name in packages:
matched_name = next(
filter(
lambda k: safe_name(k).lower() == safe_name(name).lower(), deps.keys()
),
None,
)
if not matched_name:
raise PdmUsageError(f"{name!r} does not exist under {toml_section!r}.")
del deps[matched_name]
project.write_pyproject()
do_lock(project, "reuse")
if sync:
do_sync(project, sections=(section,), default=False, clean=True)
......@@ -86,29 +86,28 @@ def sync(project, sections, dev, default, dry_run, clean):
)
@click.option("-s", "--section", help="Specify target section to add into.")
@click.option(
"--no-install",
"install",
"--no-sync",
"sync",
flag_value=False,
default=True,
help="Only write pyproject.toml and do not install packages.",
help="Only write pyproject.toml and do not sync the working set.",
)
@save_strategy_option
@update_strategy_option
@click.option("-e", "editables", multiple=True, help="Specify editable packages.")
@click.argument("packages", nargs=-1)
@pass_project
def add(project, dev, section, install, save, strategy, editables, packages):
actions.do_add(project, dev, section, install, save, strategy, editables, packages)
def add(project, dev, section, sync, save, strategy, editables, packages):
actions.do_add(project, dev, section, sync, save, strategy, editables, packages)
@cli.command(help="Update packages in pyproject.toml")
@sections_option
@save_strategy_option
@update_strategy_option
@click.argument("packages", nargs=-1)
@pass_project
def update(project, dev, sections, default, save, strategy, packages):
pass
def update(project, dev, sections, default, strategy, packages):
actions.do_update(project, dev, sections, default, strategy, packages)
@cli.command(help="Remove packages from pyproject.toml")
......@@ -121,13 +120,13 @@ def update(project, dev, sections, default, save, strategy, packages):
)
@click.option("-s", "--section", help="Specify target section the package belongs to")
@click.option(
"--no-install",
"install",
"--no-sync",
"sync",
flag_value=False,
default=True,
help="Only write pyproject.toml and do not uninstall packages.",
)
@click.argument("packages", nargs=-1)
@pass_project
def remove(project, dev, section, install, packages):
pass
def remove(project, dev, section, sync, packages):
actions.do_remove(project, dev, section, sync, packages)
......@@ -26,7 +26,9 @@ def _is_dist_editable(working_set: WorkingSet, dist: Distribution) -> bool:
return False
def _print_list_information(word, items):
def _print_list_information(word, items, dry=False):
if dry:
word = "to be " + word
template = "{count} package{suffix} {word}: {items}"
suffix = "s" if len(items) > 1 else ""
count = len(items)
......@@ -159,8 +161,8 @@ class Synchronizer:
self.remove_distributions(to_remove)
print()
if to_add:
_print_list_information("added", to_add)
_print_list_information("added", to_add, dry_run)
if to_update:
_print_list_information("updated", to_update)
_print_list_information("updated", to_update, dry_run)
if clean and to_remove:
_print_list_information("removed", to_remove)
_print_list_information("removed", to_remove, dry_run)
......@@ -251,7 +251,7 @@ class Project:
data = original
*parts, last = self.PDM_NAMESPACE.split(".")
for part in parts:
data = data.setdefault(part, tomlkit.table())
data = data.setdefault(part, {})
data[last] = self.pyproject
with atomic_open_for_write(
......
......@@ -5,7 +5,6 @@ python_requires = ">=3.7"
appdirs = "*"
click = "*"
distlib = "*"
parver = "<1.0.0,>=0.2.1"
pip = "<20.0.0,>=19.3.1"
pip_shims = "*"
pythonfinder = "*"
......@@ -16,6 +15,7 @@ pytest = "*"
pytest-cov = "*"
pytest-mock = "*"
[tool.isort]
line_length = 88
multi_line_output = 3
......
from pdm.cli.actions import do_add
import pytest
from pdm.cli.actions import do_add, do_update, do_sync, do_remove
from collections import namedtuple
from pdm.exceptions import PdmUsageError
Requirement = namedtuple("Requirement", "key")
Candidate = namedtuple("Candidate", "req,version")
def make_candidate(name, version):
req = Requirement(name)
return Candidate(req=req, version=version)
def test_sync_only_different(project, repository, synchronizer, capsys):
synchronizer.install_candidates(
[
make_candidate("foo", "0.1.0"),
make_candidate("chardet", "3.0.1"),
make_candidate("idna", "2.7"),
]
)
do_add(project, packages=["requests"])
out, _ = capsys.readouterr()
assert "3 packages added" in out
assert "1 package updated" in out
assert "foo" in synchronizer.working_set
assert synchronizer.working_set["chardet"] == "3.0.4"
def test_sync_clean_packages(project, repository, synchronizer):
synchronizer.install_candidates(
[
make_candidate("foo", "0.1.0"),
make_candidate("chardet", "3.0.1"),
make_candidate("idna", "2.7"),
]
)
do_add(project, packages=["requests"], sync=False)
do_sync(project, clean=True)
assert "foo" not in synchronizer.working_set
def test_sync_dry_run(project, repository, synchronizer):
synchronizer.install_candidates(
[
make_candidate("foo", "0.1.0"),
make_candidate("chardet", "3.0.1"),
make_candidate("idna", "2.7"),
]
)
do_add(project, packages=["requests"], sync=False)
do_sync(project, clean=True, dry_run=True)
assert "foo" in synchronizer.working_set
assert "requests" not in synchronizer.working_set
assert synchronizer.working_set["chardet"] == "3.0.1"
def test_add_package(project, repository, synchronizer, is_dev):
......@@ -24,9 +81,9 @@ def test_add_package_to_custom_package(project, repository, synchronizer):
def test_add_editable_package(project, repository, synchronizer, is_dev, vcs):
do_add(
project, is_dev, editables=[
"git+https://github.com/test-root/demo.git#egg=demo"
]
project,
is_dev,
editables=["git+https://github.com/test-root/demo.git#egg=demo"],
)
section = "dev-dependencies" if is_dev else "dependencies"
assert "demo" in project.pyproject[section]
......@@ -36,23 +93,23 @@ def test_add_editable_package(project, repository, synchronizer, is_dev, vcs):
def test_add_no_install(project, repository, synchronizer):
do_add(project, install=False, packages=["requests"])
do_add(project, sync=False, packages=["requests"])
for package in ("requests", "idna", "chardet", "urllib3", "certifi"):
assert package not in synchronizer.working_set
def test_add_package_save_exact(project, repository):
do_add(project, install=False, save="exact", packages=["requests"])
do_add(project, sync=False, save="exact", packages=["requests"])
assert project.pyproject["dependencies"]["requests"] == "==2.19.1"
def test_add_package_save_wildcard(project, repository):
do_add(project, install=False, save="wildcard", packages=["requests"])
do_add(project, sync=False, save="wildcard", packages=["requests"])
assert project.pyproject["dependencies"]["requests"] == "*"
def test_add_package_update_reuse(project, repository):
do_add(project, install=False, save="wildcard", packages=["requests", "pytz"])
do_add(project, sync=False, save="wildcard", packages=["requests", "pytz"])
locked_candidates = project.get_locked_candidates()
assert locked_candidates["requests"].version == "2.19.1"
......@@ -62,14 +119,18 @@ def test_add_package_update_reuse(project, repository):
repository.add_candidate("pytz", "2019.6")
repository.add_candidate("chardet", "3.0.5")
repository.add_candidate("requests", "2.20.0")
repository.add_dependencies("requests", "2.20.0", [
"certifi>=2017.4.17",
"chardet<3.1.0,>=3.0.2",
"idna<2.8,>=2.5",
"urllib3<1.24,>=1.21.1"
])
repository.add_dependencies(
"requests",
"2.20.0",
[
"certifi>=2017.4.17",
"chardet<3.1.0,>=3.0.2",
"idna<2.8,>=2.5",
"urllib3<1.24,>=1.21.1",
],
)
do_add(
project, install=False, save="wildcard", packages=["requests"], strategy="reuse"
project, sync=False, save="wildcard", packages=["requests"], strategy="reuse"
)
locked_candidates = project.get_locked_candidates()
assert locked_candidates["requests"].version == "2.20.0"
......@@ -78,7 +139,7 @@ def test_add_package_update_reuse(project, repository):
def test_add_package_update_eager(project, repository):
do_add(project, install=False, save="wildcard", packages=["requests", "pytz"])
do_add(project, sync=False, save="wildcard", packages=["requests", "pytz"])
locked_candidates = project.get_locked_candidates()
assert locked_candidates["requests"].version == "2.19.1"
......@@ -88,16 +149,130 @@ def test_add_package_update_eager(project, repository):
repository.add_candidate("pytz", "2019.6")
repository.add_candidate("chardet", "3.0.5")
repository.add_candidate("requests", "2.20.0")
repository.add_dependencies("requests", "2.20.0", [
"certifi>=2017.4.17",
"chardet<3.1.0,>=3.0.2",
"idna<2.8,>=2.5",
"urllib3<1.24,>=1.21.1"
])
repository.add_dependencies(
"requests",
"2.20.0",
[
"certifi>=2017.4.17",
"chardet<3.1.0,>=3.0.2",
"idna<2.8,>=2.5",
"urllib3<1.24,>=1.21.1",
],
)
do_add(
project, install=False, save="wildcard", packages=["requests"], strategy="eager"
project, sync=False, save="wildcard", packages=["requests"], strategy="eager"
)
locked_candidates = project.get_locked_candidates()
assert locked_candidates["requests"].version == "2.20.0"
assert locked_candidates["chardet"].version == "3.0.5"
assert locked_candidates["pytz"].version == "2019.3"
def test_update_all_packages(project, repository, synchronizer, capsys):
do_add(project, packages=["requests", "pytz"])
repository.add_candidate("pytz", "2019.6")
repository.add_candidate("chardet", "3.0.5")
repository.add_candidate("requests", "2.20.0")
repository.add_dependencies(
"requests",
"2.20.0",
[
"certifi>=2017.4.17",
"chardet<3.1.0,>=3.0.2",
"idna<2.8,>=2.5",
"urllib3<1.24,>=1.21.1",
],
)
do_update(project)
locked_candidates = project.get_locked_candidates()
assert locked_candidates["requests"].version == "2.20.0"
assert locked_candidates["chardet"].version == "3.0.5"
assert locked_candidates["pytz"].version == "2019.6"
out, _ = capsys.readouterr()
assert "3 packages updated" in out
do_sync(project)
out, _ = capsys.readouterr()
assert "All packages are synced to date" in out
def test_update_specified_packages(project, repository, synchronizer):
do_add(project, sync=False, packages=["requests", "pytz"])
repository.add_candidate("pytz", "2019.6")
repository.add_candidate("chardet", "3.0.5")
repository.add_candidate("requests", "2.20.0")
repository.add_dependencies(
"requests",
"2.20.0",
[
"certifi>=2017.4.17",
"chardet<3.1.0,>=3.0.2",
"idna<2.8,>=2.5",
"urllib3<1.24,>=1.21.1",
],
)
do_update(project, packages=["requests"])
locked_candidates = project.get_locked_candidates()
assert locked_candidates["requests"].version == "2.20.0"
assert locked_candidates["chardet"].version == "3.0.4"
def test_update_specified_packages_eager_mode(project, repository, synchronizer):
do_add(project, sync=False, packages=["requests", "pytz"])
repository.add_candidate("pytz", "2019.6")
repository.add_candidate("chardet", "3.0.5")
repository.add_candidate("requests", "2.20.0")
repository.add_dependencies(
"requests",
"2.20.0",
[
"certifi>=2017.4.17",
"chardet<3.1.0,>=3.0.2",
"idna<2.8,>=2.5",
"urllib3<1.24,>=1.21.1",
],
)
do_update(project, strategy="eager", packages=["requests"])
locked_candidates = project.get_locked_candidates()
assert locked_candidates["requests"].version == "2.20.0"
assert locked_candidates["chardet"].version == "3.0.5"
assert locked_candidates["pytz"].version == "2019.3"
def test_remove_package(project, repository, synchronizer, is_dev):
do_add(project, dev=is_dev, packages=["requests", "pytz"])
do_remove(project, dev=is_dev, packages=["pytz"])
locked_candidates = project.get_locked_candidates()
assert "pytz" not in locked_candidates
assert "pytz" not in synchronizer.working_set
def test_remove_package_no_sync(project, repository, synchronizer):
do_add(project, packages=["requests", "pytz"])
do_remove(project, sync=False, packages=["pytz"])
locked_candidates = project.get_locked_candidates()
assert "pytz" not in locked_candidates
assert "pytz" in synchronizer.working_set
def test_remove_package_not_exist(project, repository, synchronizer):
do_add(project, packages=["requests", "pytz"])
with pytest.raises(PdmUsageError):
do_remove(project, sync=False, packages=["django"])
def test_add_remove_no_package(project, repository):
with pytest.raises(PdmUsageError):
do_add(project, packages=())
with pytest.raises(PdmUsageError):
do_remove(project, packages=())
def test_update_with_package_and_sections_argument(project, repository, synchronizer):
do_add(project, packages=["requests", "pytz"])
with pytest.raises(PdmUsageError):
do_update(project, sections=("default", "dev"), packages=("requests",))
with pytest.raises(PdmUsageError):
do_update(project, default=False, packages=("requests",))
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册