text:
pipenv uninstall transitive dependencies

Is your feature request related to a problem? Please describe.
We want to be able to remove a package from our Pipfile, and have it and its transitive dependencies removed from Pipfile.lock, without other dependencies getting automatically upgraded.

pipenv uninstall will upgrade anything that isn't pinned, which is very surprising behavior
pipenv uninstall --keep-outdated does not modify the Pipfile.lock at all, so it is kind of useless, and it is unclear what behavior it is supposed to have anyway (#4390)

Describe the solution you'd like
Some way to remove a package and its dependencies (assume they are otherwise unused), without effectively recalculating the Pipfile.lock from scratch. Alternatively, a command like pipenv prune that just removes unused dependencies from the Pipfile.lock.
Describe alternatives you've considered
We can hand-edit the Pipfile.lock, but this is rather cumbersome.

This is a great proposal and description +you did link to the other discussion about it so that is good.  We may ultimately want to close one or the other issue to help track as a single issue, but I will comment on some thoughts on implementation details:
The challenge I see here is with respect to the transitive dependencies because the Pipfile.lock file is a flat structure where all dependencies are at equal level--imagine the case where two different projects require some transitive dependency-b so pipenv could calculate because we are requesting to remove package-A1 which requires dependency-b to remove it, but in order to be correct, pipenv would also have to calculate and verify that dependency-b is not a required dependency for any other package remaining in the Pipfile.  To that end, this uninstall option would become as expensive as locking, I think.
Since the outcome is an expensive operation, to avoid having to repeat it I like the idea of pipenv uninstall --keep-outdated because the Pipfile should get updated to prevent a future pipenv lock from bringing back in the undesired dependency.
The case of a command like pipenv prune -- I think it is ultimately similar to my thoughts above, it would have to re-compute the new lock file in memory based on the current Pipfile and compare the set of package names with the existing lock file -- anything in the existing lock file not in the re-computed version would get pruned out of the lock file.

Since --keep-outdated is no longer supported and issue #4390 has been closed, is there a chance of prioritizing this issue?

I could not reproduce this in latest pipenv -- I had done some work on improving the uninstall command earlier this year -- perhaps this can be closed or a better reproduction example provided?
matte@matteius-proart MINGW64 ~/projects/pipenv-triage/issue-4924
$ pipenv install requests
Creating a virtualenv for this project
Pipfile: C:\Users\matte\projects\pipenv-triage\issue-4924\Pipfile
Using default python from C:\Users\matte\AppData\Local\Programs\Python\Python313\python.exe3.13.0 to create virtualenv...
[==  ] Creating virtual environment...created virtual environment CPython3.13.0.final.0-64 in 266ms
  creator CPython3Windows(dest=C:\Users\matte\.virtualenvs\issue-4924-Ea2dyS44, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, via=copy, app_data_dir=C:\Users\matte\AppData\Local\pypa\virtualenv)
    added seed packages: pip==24.2
  activators BashActivator,BatchActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator

Successfully created virtual environment!
Virtualenv location: C:\Users\matte\.virtualenvs\issue-4924-Ea2dyS44
Creating a Pipfile for this project...
Pipfile.lock not found, creating...
Locking [packages] dependencies...
Locking [dev-packages] dependencies...
Updated Pipfile.lock (494d5b4f482f0ef471f49afe28f00ec1a2ff75da2ce65060d8cabaeb3da2f100)!
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
Installing requests...
Installation Succeeded
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
Installing dependencies from Pipfile.lock (a2f100)...
All dependencies are now up-to-date!
Upgrading requests in  dependencies.
Building requirements...
Resolving dependencies...
Success!
Building requirements...
Resolving dependencies...
Success!
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
Installing dependencies from Pipfile.lock (7c77c5)...
All dependencies are now up-to-date!
Installing dependencies from Pipfile.lock (7c77c5)...

matte@matteius-proart MINGW64 ~/projects/pipenv-triage/issue-4924
$ pipenv install numpy
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
Installing numpy...
Installation Succeeded
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
Installing dependencies from Pipfile.lock (7c77c5)...
All dependencies are now up-to-date!
Upgrading numpy in  dependencies.
Building requirements...
Resolving dependencies...
Success!
Building requirements...
Resolving dependencies...
Success!
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
Installing dependencies from Pipfile.lock (1df1c4)...
All dependencies are now up-to-date!
Installing dependencies from Pipfile.lock (1df1c4)...

matte@matteius-proart MINGW64 ~/projects/pipenv-triage/issue-4924
(reverse-i-search)`': ^C

matte@matteius-proart MINGW64 ~/projects/pipenv-triage/issue-4924
$ cat Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
requests = "*"
numpy = "*"

[dev-packages]

[requires]
python_version = "3.13"

matte@matteius-proart MINGW64 ~/projects/pipenv-triage/issue-4924
$ cat Pipfile.lock
{
    "_meta": {
        "hash": {
            "sha256": "99dab2961e0d2c6ed96a40d04995f23a98b41e981d97aacd6f3dd63a2f1df1c4"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3.13"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "certifi": {
            "hashes": [
                "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8",
                "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"
            ],
            "markers": "python_version >= '3.6'",
            "version": "==2024.8.30"
        },
        "charset-normalizer": {
            "hashes": [
                "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621",
                "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6",
                "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8",
                "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912",
                "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c",
                "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b",
                "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d",
                "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d",
                "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95",
                "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e",
                "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565",
                "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64",
                "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab",
                "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be",
                "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e",
                "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907",
                "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0",
                "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2",
                "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62",
                "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62",
                "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23",
                "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc",
                "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284",
                "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca",
                "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455",
                "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858",
                "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b",
                "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594",
                "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc",
                "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db",
                "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b",
                "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea",
                "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6",
                "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920",
                "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749",
                "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7",
                "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd",
                "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99",
                "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242",
                "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee",
                "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129",
                "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2",
                "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51",
                "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee",
                "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8",
                "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b",
                "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613",
                "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742",
                "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe",
                "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3",
                "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5",
                "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631",
                "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7",
                "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15",
                "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c",
                "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea",
                "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417",
                "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250",
                "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88",
                "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca",
                "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa",
                "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99",
                "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149",
                "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41",
                "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574",
                "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0",
                "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f",
                "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d",
                "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654",
                "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3",
                "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19",
                "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90",
                "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578",
                "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9",
                "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1",
                "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51",
                "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719",
                "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236",
                "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a",
                "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c",
                "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade",
                "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944",
                "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc",
                "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6",
                "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6",
                "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27",
                "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6",
                "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2",
                "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12",
                "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf",
                "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114",
                "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7",
                "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf",
                "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d",
                "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b",
                "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed",
                "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03",
                "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4",
                "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67",
                "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365",
                "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a",
                "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748",
                "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b",
                "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079",
                "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"
            ],
            "markers": "python_full_version >= '3.7.0'",
            "version": "==3.4.0"
        },
        "idna": {
            "hashes": [
                "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9",
                "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"
            ],
            "markers": "python_version >= '3.6'",
            "version": "==3.10"
        },
        "numpy": {
            "hashes": [
                "sha256:05b2d4e667895cc55e3ff2b56077e4c8a5604361fc21a042845ea3ad67465aa8",
                "sha256:12edb90831ff481f7ef5f6bc6431a9d74dc0e5ff401559a71e5e4611d4f2d466",
                "sha256:13311c2db4c5f7609b462bc0f43d3c465424d25c626d95040f073e30f7570e35",
                "sha256:13532a088217fa624c99b843eeb54640de23b3414b14aa66d023805eb731066c",
                "sha256:13602b3174432a35b16c4cfb5de9a12d229727c3dd47a6ce35111f2ebdf66ff4",
                "sha256:1600068c262af1ca9580a527d43dc9d959b0b1d8e56f8a05d830eea39b7c8af6",
                "sha256:1b8cde4f11f0a975d1fd59373b32e2f5a562ade7cde4f85b7137f3de8fbb29a0",
                "sha256:1c193d0b0238638e6fc5f10f1b074a6993cb13b0b431f64079a509d63d3aa8b7",
                "sha256:1ebec5fd716c5a5b3d8dfcc439be82a8407b7b24b230d0ad28a81b61c2f4659a",
                "sha256:242b39d00e4944431a3cd2db2f5377e15b5785920421993770cddb89992c3f3a",
                "sha256:259ec80d54999cc34cd1eb8ded513cb053c3bf4829152a2e00de2371bd406f5e",
                "sha256:2abbf905a0b568706391ec6fa15161fad0fb5d8b68d73c461b3c1bab6064dd62",
                "sha256:2cbba4b30bf31ddbe97f1c7205ef976909a93a66bb1583e983adbd155ba72ac2",
                "sha256:2ffef621c14ebb0188a8633348504a35c13680d6da93ab5cb86f4e54b7e922b5",
                "sha256:30d53720b726ec36a7f88dc873f0eec8447fbc93d93a8f079dfac2629598d6ee",
                "sha256:32e16a03138cabe0cb28e1007ee82264296ac0983714094380b408097a418cfe",
                "sha256:43cca367bf94a14aca50b89e9bc2061683116cfe864e56740e083392f533ce7a",
                "sha256:456e3b11cb79ac9946c822a56346ec80275eaf2950314b249b512896c0d2505e",
                "sha256:4d6ec0d4222e8ffdab1744da2560f07856421b367928026fb540e1945f2eeeaf",
                "sha256:5006b13a06e0b38d561fab5ccc37581f23c9511879be7693bd33c7cd15ca227c",
                "sha256:675c741d4739af2dc20cd6c6a5c4b7355c728167845e3c6b0e824e4e5d36a6c3",
                "sha256:6cdb606a7478f9ad91c6283e238544451e3a95f30fb5467fbf715964341a8a86",
                "sha256:6d95f286b8244b3649b477ac066c6906fbb2905f8ac19b170e2175d3d799f4df",
                "sha256:76322dcdb16fccf2ac56f99048af32259dcc488d9b7e25b51e5eca5147a3fb98",
                "sha256:7c1c60328bd964b53f8b835df69ae8198659e2b9302ff9ebb7de4e5a5994db3d",
                "sha256:860ec6e63e2c5c2ee5e9121808145c7bf86c96cca9ad396c0bd3e0f2798ccbe2",
                "sha256:8e00ea6fc82e8a804433d3e9cedaa1051a1422cb6e443011590c14d2dea59146",
                "sha256:9c6c754df29ce6a89ed23afb25550d1c2d5fdb9901d9c67a16e0b16eaf7e2550",
                "sha256:a26ae94658d3ba3781d5e103ac07a876b3e9b29db53f68ed7df432fd033358a8",
                "sha256:a65acfdb9c6ebb8368490dbafe83c03c7e277b37e6857f0caeadbbc56e12f4fb",
                "sha256:a7d80b2e904faa63068ead63107189164ca443b42dd1930299e0d1cb041cec2e",
                "sha256:a84498e0d0a1174f2b3ed769b67b656aa5460c92c9554039e11f20a05650f00d",
                "sha256:ab4754d432e3ac42d33a269c8567413bdb541689b02d93788af4131018cbf366",
                "sha256:ad369ed238b1959dfbade9018a740fb9392c5ac4f9b5173f420bd4f37ba1f7a0",
                "sha256:b1d0fcae4f0949f215d4632be684a539859b295e2d0cb14f78ec231915d644db",
                "sha256:b42a1a511c81cc78cbc4539675713bbcf9d9c3913386243ceff0e9429ca892fe",
                "sha256:bd33f82e95ba7ad632bc57837ee99dba3d7e006536200c4e9124089e1bf42426",
                "sha256:bdd407c40483463898b84490770199d5714dcc9dd9b792f6c6caccc523c00952",
                "sha256:c6eef7a2dbd0abfb0d9eaf78b73017dbfd0b54051102ff4e6a7b2980d5ac1a03",
                "sha256:c82af4b2ddd2ee72d1fc0c6695048d457e00b3582ccde72d8a1c991b808bb20f",
                "sha256:d666cb72687559689e9906197e3bec7b736764df6a2e58ee265e360663e9baf7",
                "sha256:d7bf0a4f9f15b32b5ba53147369e94296f5fffb783db5aacc1be15b4bf72f43b",
                "sha256:d82075752f40c0ddf57e6e02673a17f6cb0f8eb3f587f63ca1eaab5594da5b17",
                "sha256:da65fb46d4cbb75cb417cddf6ba5e7582eb7bb0b47db4b99c9fe5787ce5d91f5",
                "sha256:e2b49c3c0804e8ecb05d59af8386ec2f74877f7ca8fd9c1e00be2672e4d399b1",
                "sha256:e585c8ae871fd38ac50598f4763d73ec5497b0de9a0ab4ef5b69f01c6a046142",
                "sha256:e8d3ca0a72dd8846eb6f7dfe8f19088060fcb76931ed592d29128e0219652884",
                "sha256:ef444c57d664d35cac4e18c298c47d7b504c66b17c2ea91312e979fcfbdfb08a",
                "sha256:f1eb068ead09f4994dec71c24b2844f1e4e4e013b9629f812f292f04bd1510d9",
                "sha256:f2ded8d9b6f68cc26f8425eda5d3877b47343e68ca23d0d0846f4d312ecaa445",
                "sha256:f751ed0a2f250541e19dfca9f1eafa31a392c71c832b6bb9e113b10d050cb0f1",
                "sha256:faa88bc527d0f097abdc2c663cddf37c05a1c2f113716601555249805cf573f1",
                "sha256:fc44e3c68ff00fd991b59092a54350e6e4911152682b4782f68070985aa9e648"
            ],
            "index": "pypi",
            "markers": "python_version >= '3.10'",
            "version": "==2.1.2"
        },
        "requests": {
            "hashes": [
                "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760",
                "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"
            ],
            "index": "pypi",
            "markers": "python_version >= '3.8'",
            "version": "==2.32.3"
        },
        "urllib3": {
            "hashes": [
                "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac",
                "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"
            ],
            "markers": "python_version >= '3.8'",
            "version": "==2.2.3"
        }
    },
    "develop": {}
}

matte@matteius-proart MINGW64 ~/projects/pipenv-triage/issue-4924
$ pipenv uninstall requests
Removed requests from Pipfile.
Building requirements...
Resolving dependencies...
Success!
Uninstalling requests...
Found existing installation: requests 2.32.3
Uninstalling requests-2.32.3:
  Successfully uninstalled requests-2.32.3

matte@matteius-proart MINGW64 ~/projects/pipenv-triage/issue-4924
$ cat Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
numpy = "*"

[dev-packages]

[requires]
python_version = "3.13"

matte@matteius-proart MINGW64 ~/projects/pipenv-triage/issue-4924
$ cat Pipfile.lock
{
    "_meta": {
        "hash": {
            "sha256": "93f8cacebadda837ec66e7db191de584c30f89b70a00041f134add39db647f23"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3.13"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "numpy": {
            "hashes": [
                "sha256:05b2d4e667895cc55e3ff2b56077e4c8a5604361fc21a042845ea3ad67465aa8",
                "sha256:12edb90831ff481f7ef5f6bc6431a9d74dc0e5ff401559a71e5e4611d4f2d466",
                "sha256:13311c2db4c5f7609b462bc0f43d3c465424d25c626d95040f073e30f7570e35",
                "sha256:13532a088217fa624c99b843eeb54640de23b3414b14aa66d023805eb731066c",
                "sha256:13602b3174432a35b16c4cfb5de9a12d229727c3dd47a6ce35111f2ebdf66ff4",
                "sha256:1600068c262af1ca9580a527d43dc9d959b0b1d8e56f8a05d830eea39b7c8af6",
                "sha256:1b8cde4f11f0a975d1fd59373b32e2f5a562ade7cde4f85b7137f3de8fbb29a0",
                "sha256:1c193d0b0238638e6fc5f10f1b074a6993cb13b0b431f64079a509d63d3aa8b7",
                "sha256:1ebec5fd716c5a5b3d8dfcc439be82a8407b7b24b230d0ad28a81b61c2f4659a",
                "sha256:242b39d00e4944431a3cd2db2f5377e15b5785920421993770cddb89992c3f3a",
                "sha256:259ec80d54999cc34cd1eb8ded513cb053c3bf4829152a2e00de2371bd406f5e",
                "sha256:2abbf905a0b568706391ec6fa15161fad0fb5d8b68d73c461b3c1bab6064dd62",
                "sha256:2cbba4b30bf31ddbe97f1c7205ef976909a93a66bb1583e983adbd155ba72ac2",
                "sha256:2ffef621c14ebb0188a8633348504a35c13680d6da93ab5cb86f4e54b7e922b5",
                "sha256:30d53720b726ec36a7f88dc873f0eec8447fbc93d93a8f079dfac2629598d6ee",
                "sha256:32e16a03138cabe0cb28e1007ee82264296ac0983714094380b408097a418cfe",
                "sha256:43cca367bf94a14aca50b89e9bc2061683116cfe864e56740e083392f533ce7a",
                "sha256:456e3b11cb79ac9946c822a56346ec80275eaf2950314b249b512896c0d2505e",
                "sha256:4d6ec0d4222e8ffdab1744da2560f07856421b367928026fb540e1945f2eeeaf",
                "sha256:5006b13a06e0b38d561fab5ccc37581f23c9511879be7693bd33c7cd15ca227c",
                "sha256:675c741d4739af2dc20cd6c6a5c4b7355c728167845e3c6b0e824e4e5d36a6c3",
                "sha256:6cdb606a7478f9ad91c6283e238544451e3a95f30fb5467fbf715964341a8a86",
                "sha256:6d95f286b8244b3649b477ac066c6906fbb2905f8ac19b170e2175d3d799f4df",
                "sha256:76322dcdb16fccf2ac56f99048af32259dcc488d9b7e25b51e5eca5147a3fb98",
                "sha256:7c1c60328bd964b53f8b835df69ae8198659e2b9302ff9ebb7de4e5a5994db3d",
                "sha256:860ec6e63e2c5c2ee5e9121808145c7bf86c96cca9ad396c0bd3e0f2798ccbe2",
                "sha256:8e00ea6fc82e8a804433d3e9cedaa1051a1422cb6e443011590c14d2dea59146",
                "sha256:9c6c754df29ce6a89ed23afb25550d1c2d5fdb9901d9c67a16e0b16eaf7e2550",
                "sha256:a26ae94658d3ba3781d5e103ac07a876b3e9b29db53f68ed7df432fd033358a8",
                "sha256:a65acfdb9c6ebb8368490dbafe83c03c7e277b37e6857f0caeadbbc56e12f4fb",
                "sha256:a7d80b2e904faa63068ead63107189164ca443b42dd1930299e0d1cb041cec2e",
                "sha256:a84498e0d0a1174f2b3ed769b67b656aa5460c92c9554039e11f20a05650f00d",
                "sha256:ab4754d432e3ac42d33a269c8567413bdb541689b02d93788af4131018cbf366",
                "sha256:ad369ed238b1959dfbade9018a740fb9392c5ac4f9b5173f420bd4f37ba1f7a0",
                "sha256:b1d0fcae4f0949f215d4632be684a539859b295e2d0cb14f78ec231915d644db",
                "sha256:b42a1a511c81cc78cbc4539675713bbcf9d9c3913386243ceff0e9429ca892fe",
                "sha256:bd33f82e95ba7ad632bc57837ee99dba3d7e006536200c4e9124089e1bf42426",
                "sha256:bdd407c40483463898b84490770199d5714dcc9dd9b792f6c6caccc523c00952",
                "sha256:c6eef7a2dbd0abfb0d9eaf78b73017dbfd0b54051102ff4e6a7b2980d5ac1a03",
                "sha256:c82af4b2ddd2ee72d1fc0c6695048d457e00b3582ccde72d8a1c991b808bb20f",
                "sha256:d666cb72687559689e9906197e3bec7b736764df6a2e58ee265e360663e9baf7",
                "sha256:d7bf0a4f9f15b32b5ba53147369e94296f5fffb783db5aacc1be15b4bf72f43b",
                "sha256:d82075752f40c0ddf57e6e02673a17f6cb0f8eb3f587f63ca1eaab5594da5b17",
                "sha256:da65fb46d4cbb75cb417cddf6ba5e7582eb7bb0b47db4b99c9fe5787ce5d91f5",
                "sha256:e2b49c3c0804e8ecb05d59af8386ec2f74877f7ca8fd9c1e00be2672e4d399b1",
                "sha256:e585c8ae871fd38ac50598f4763d73ec5497b0de9a0ab4ef5b69f01c6a046142",
                "sha256:e8d3ca0a72dd8846eb6f7dfe8f19088060fcb76931ed592d29128e0219652884",
                "sha256:ef444c57d664d35cac4e18c298c47d7b504c66b17c2ea91312e979fcfbdfb08a",
                "sha256:f1eb068ead09f4994dec71c24b2844f1e4e4e013b9629f812f292f04bd1510d9",
                "sha256:f2ded8d9b6f68cc26f8425eda5d3877b47343e68ca23d0d0846f4d312ecaa445",
                "sha256:f751ed0a2f250541e19dfca9f1eafa31a392c71c832b6bb9e113b10d050cb0f1",
                "sha256:faa88bc527d0f097abdc2c663cddf37c05a1c2f113716601555249805cf573f1",
                "sha256:fc44e3c68ff00fd991b59092a54350e6e4911152682b4782f68070985aa9e648"
            ],
            "index": "pypi",
            "markers": "python_version >= '3.10'",
            "version": "==2.1.2"
        }
    },
    "develop": {}
}

authors: matteius rittneje ryerson


text:
Newlines in the description field produce a malformed PKG-INFO

We discovered this accidentally by way of https://github.com/zopefoundation/zc.relation/issues/4#issuecomment-397532224: if you pass a string containing newlines to the description argument of setup(), setuptools will generate a malformed PKG-INFO.
To reproduce:
# setup.py
from setuptools import setup
setup(
    name='test-package',
    version='0.1',
    author='Blah Blah',
    author_email='blah@example.com',
    description='description\n\n',
    py_modules=['blah'],
)

(The contents of blah.py do not matter, but the file should exist.)
Run python setup.py sdist and the inspect test_package.egg-info/PKG-INFO.  For me, with setuptools 39.1.0, it looks like this:
Metadata-Version: 1.0
Name: test-package
Version: 0.1
Summary: description

Home-page: UNKNOWN
Author: Blah Blah
Author-email: blah@example.com
License: UNKNOWN
Description: UNKNOWN
Platform: UNKNOWN

The extra newlines lead tools to treat the rest of the PKG-INFO as a long_description.
I would expect setuptools to complain about the newlines in the description field, or at least escape them properly (i.e. prepend whitespace, like it does for the long_description field).

I looked at this for about 10 minutes, and I'm still not sure where validation should happen for these options/metadata fields. From what I can tell, only a few of the options do any sort of validation, and even then only in distutils.
So while I agree it would be nice for Setuptools to reject invalid metadata fields, it may not even have a good hook point to do so. Perhaps a hook could be added in Distribution.finalize_options.

Do you think this would be best fixed in distutils?  Such a fix would take (much) longer to reach users, but I don't think this foot-gun is very dangerous.

@mgedmin I think at this point things are not really being fixed much in distutils. Some time soon we'll be removing setuptools' dependency on distutils and distutils will be deprecated entirely.

Just wanted to point out that this is not limited to just the Summary field -- any field with a double newline will cause the rest of the PKG-INFO file after those newlines to be interpreted as the "message body" and thus become the Long-Description.

@di That's not great. I think we could reasonably add strip('\n') to all fields, but that wouldn't stop anyone from doing something like A\n\nB. Is there any way to escape double-newlines so they aren't interpreted this way?
I see the options as:

Escape newlines in the text so they aren't interpreted as delimiters.
Raise an error whenever double newlines are found outside of long_description.
Silently s/\n+/\n/g for everything except long_description.

I think I prefer 1 as least disruptive, but I'm ambivalent between 2 and 3. 2 is more explicit, but 3 creates less "churn" (since this will just be auto-magically fixed).

I think #1 is probably not the right thing to do here, as the resulting field would still contain the extra (albeit escaped) newline characters, which would not be what the user wants.
I think if we could do #2, it would be easy enough to just do #3 and avoid a possibly-confusing error message.

@mgedmin @di Even a single newline at the end of the description parameter of the setup function seems break PKG-INFO. (The second newline is added when writing PKG-INFO to separate the parameters in the file.)
See https://pypi.org/project/zc.relation/1.1.post1/#files for such a malformed PKG-INFO and https://pypi.org/project/zc.relation/1.1.post1/#description for the PyPI parsing result.

#262 was another case where a single newline at the end breaks description.
I tend to think that "newlines are not allowed in that field" would be a clear enough error message to support option (2) for that case.
However, if you go for the explicit options (1 or 3), note that setup.py upload (as opposed to twine) does NOT fail in that case (not sure what/how it does exactly, but data is shown correctly in testpypi).
Hence - having a look at what the raw upload command does might provide more objective feedback re: "what the user expects" in this case.

I see the options as:

Escape newlines in the text so they aren't interpreted as delimiters.
Raise an error whenever double newlines are found outside of long_description.
Silently s/\n+/\n/g for everything except long_description.

I think I prefer 1 as least disruptive, but I'm ambivalent between 2 and 3. 2 is more explicit, but 3 creates less "churn" (since this will just be auto-magically fixed).

We should fail hard for configurations that are invalid. There should be an error message that gives a clear indication on how to fix the problem. This is a developer API, and developers should deal with their broken code. We shouldn't try to guess-fix broken stuff.
Do the fields/kwargs have an explicit specification of the data they expect? This should be enforced. The fields description and license obviously expect single-line data. Hence, when a newline is submitted in the data for those fields the generation of PKG-INFO should be aborted with a clear error message, e.g.
$ python3 setup.py sdist
ERROR: The "description" field requires a single line of text. Multi-line text was supplied.
Aborting.

OK, anyone who wants to submit a PR, let's go with a hard-failure if newlines are found in fields other than long_description.
I think the easiest way to do this is to implement the check right before PKG-INFO is actually written out. Hopefully that doesn't disconnect the error message too much from the location where these inputs are actually being generated.

I can do this -- if no-one else has already started.
IIUC, I have to adapt the write_pkg_file pseudo-method, which is used to monkey patch the distutils implementation from the Python standard library.
I'd really prefer to introduce a class for this that can encapsulate the validation logic for all values. It feels too much like spaghetti code, otherwise. I hope that's fine.

I'd really prefer to introduce a class for this that can encapsulate the validation logic for all values. It feels too much like spaghetti code, otherwise. I hope that's fine.

One of my top priorities for this weekend's sprint is to move metadata validation logic out of Warehouse and into pypa/packaging for reuse elsewhere, and this would be a good example of "elsewhere".
The API will likely behave a lot like how it's currently being used in Warehouse: there will be a class which is initialized with a dict adhering to JSON-compatible metadata, and an instance of that class will have a .validate() function and a .errors attribute.
If you want to move ahead with that assumption, we can probably just connect the dots later.

@di I have some difficulties with the idea of passing in only a (flat) dict with JSON-compatible Metadata to the constructor. Currently, the resulting code would look something like below. But this way we'd have to somehow stick the validation logic into the validate method:
def write_pkg_file(self, file):
    """Write the PKG-INFO format data to a file object."""
    metadata = Metadata(dict(
        name=self.get_name(),
        version=self.get_version(),
        description=self.get_description(),
        # ...
    ))
    metadata.validate(throw_exception=True)

    version = get_metadata_version(self)
    file.write('Metadata-Version: %s\n' % version)
    file.write('Name: %s\n' % metadata.name)
    file.write('Version: %s\n' % metadata.version)
    file.write('Summary: %s\n' % metadata.description)
    # ...

To avoid setting a validator for every single value we may set a "default" validator, and set individual validators with method calls, e.g.
        # ...
    ))
    metadata.add_validator('default', single_line)
    metadata.add_validator('long_description', multi_line)
    metadata.add_validator('requires', check_requirements)
    metadata.validate(throw_exception=True)

Note that this splits up the value and its validation specification, and duplicates the metadata key.
Instead, I'd rather specify the validator together with with the metadata item, e.g.
    metadata = Metadata(dict(
        name=Value(self.get_name(), validator=single_line),
        version=Value(self.get_version(), validator=single_line),
        description=Value(self.get_description(), validator=multi_line),
        # ...
    ))

Obviously, this is not particularly beautiful, but value and validation would be visible next to each other. Maybe there is a similar but better way. Any ideas?
I've also noticed that there are quite a few check_* functions the the dist module. Would it be okay to move them to a separate validation module together with the Metadata class?

@bittner Not sure I follow... The validator(s) would be part of the packaging library, which would understand how to validate a field based on the field name. You shouldn't have to do an add_validator here at all.

@di Please see PR #1562 and let me know if this is roughly what you envisioned. Thanks!

I'd like to point out, the error message given when this issue occurs is somewhat confusing from an end user perspective, since description could actually be a text issue with the license param of the setup.
https://github.com/pypa/warehouse/blob/44fed4afb2cac5da56a3e0f9d9d73872e4e6d0ec/warehouse/forklift/legacy.py#L1012
I was scratching my head on this trying to figure out why description wasn't working, when it was actually the license text that wasn't being parsed - https://github.com/pypa/warehouse/issues/3664#issuecomment-552218625

Thanks to https://github.com/pypa/warehouse/pull/7582 , https://github.com/pypa/packaging/issues/147 is now resolved, which may unblock progress on this per https://github.com/pypa/setuptools/issues/1390#issuecomment-432411556 .

@di  Has there been any progress on this one?
I observed a similar problem if settings in setup.cfg span more than one line.
For example:
# setup.cfg
[metadata]
name = cyminiball
version = file: VERSION
url = https://github.com/hirsch-lab/cyminiball
license = LGPLv3
license_file = LICENSE
description =
    Compute the smallest bounding ball of a point cloud.
    Cython binding of the popular miniball utility. Fast!
long_description = file: README.md
long_description_content_type = text/markdown
author = Boris Leberhard
keywords = miniball, geometry, fast
classifiers =
    Programming Language :: Python :: 3
    Programming Language :: Python :: 3.6
    Programming Language :: Python :: 3.7
    Programming Language :: Python :: 3.8
    Programming Language :: Python :: 3.9
    Programming Language :: Python :: Implementation :: CPython
    License :: OSI Approved :: GNU General Public License v3 (GPLv3)
    Operating System :: OS Independent
    Topic :: Scientific/Engineering :: Mathematics
    Topic :: Software Development :: Libraries
    Topic :: Utilities
    Intended Audience :: Developers
    Intended Audience :: Science/Research

Reading the meta-data for this package results in incomplete information:
try:
    from importlib.metadata import metadata
except ModuleNotFoundError:
    from importlib_metadata import metadata

print(dict(metadata("cyminiball")))

# {'Metadata-Version': '2.1',
#  'Name': 'cyminiball',
#  'Version': '1.1.10',
#  'Summary': '',
#  'Requires-Dist': 'numpy'}

Note the empty Summary. Author, URL and other keys are missing. The same applies for other multi-line values, e.g. "classifiers", breaking the meta-data readout.
What to do about this?

@normanius: The project cyminiball needs to fix their use of the description field not to include a newline. In 904f4a1, I'm adding a crash when newlines are present, which addresses the reported issue, but will cause cyminiball and similar packages not to build.

@jaraco Thanks for the quick response. I also found the summary of @di's recent activities in this area.
Just out of curiosity: Why are newlines not possible? What breaks with newlines? When using a setup.cfg, such restrictions are not evident because configparser is able to handle newlines. Breaking long lines is a natural reflex. Plus, I cannot read any notes about this anywhere. For example, this setuptools userguide article was the source I used as a template for my setup.cfg files.
This is probably unrelated, but it's unexpected that
from importlib.metadata import metadata
metadata("cyminiball")["classifier"]

returns only the first entry in the list of specified classifiers. Is this behavior intended or should it be reported somewhere?
Update: I just found the (undocumented) feature `metadata("cyminiball").get_all("classifier"), which returns the complete list of classifiers.

Just out of curiosity: Why are newlines not possible? What breaks with newlines?

In its final form, the PKG-INFO metadata file is an RFC 822 document. Double newlines at any point in this document indicate a switch from the message headers to the message body. This causes everything after a double newline to be interpreted as part of the message body, including important metadata fields.

@jaraco with the latest update it's likely that more people will encounter pip install failures due to dependencies having newlines in the descriptions. It's causing my CI/CD pipelines to fail. I'm using Docker so I had to do a pip install setuptools==51.2.0 before pip install to work around this, which isn't ideal.

@jaraco with the latest update it's likely that more people will encounter pip install failures due to dependencies having newlines in the descriptions. It's causing my CI/CD pipelines to fail. I'm using Docker so I had to do a pip install setuptools==51.2.0 before pip install to work around this, which isn't ideal.

That’s unfortunate. I wonder how widespread these issues are. What packages are affected? How much control do you have to either install from wheel or fix/patch the affected packages?

That’s unfortunate. I wonder how widespread these issues are. What packages are affected? How much control do you have to either install from wheel or fix/patch the affected packages?

For me, it was spleeter==2.0.2, which doesn't seem to have wheel. But they recently migrated over to using Poetry in 2.1 which conveniently does have it. So it's no longer an issue in the latest version. I'll have to make some changes to my project regardless.

For me, it was spleeter==2.0.2, which doesn't seem to have wheel. But they recently migrated over to using Poetry in 2.1 which conveniently does have it. So it's no longer an issue in the latest version. I'll have to make some changes to my project regardless.

Hello,
is this problem in the process of being fixed. I have just rum some of my azure pipelines and got a similar error https://dev.azure.com/matteoravasi/PyLops/_build/results?buildId=221&view=logs&j=011e1ec8-6569-5e69-4f06-baf193d1351e&t=fe9cbe73-a432-5abe-f444-5cc590841043&l=229
It is not fully clear to me if this is one of the dependencies or my description file? But I do not have any explicit \n myself https://github.com/PyLops/pyproximal/blob/main/setup.py. Could the fact I go to the new line be a problem, even though being the text between triple quotes that should not be really a new line. Thanks!

Hello,
is this problem in the process of being fixed. I have just rum some of my azure pipelines and got a similar error https://dev.azure.com/matteoravasi/PyLops/_build/results?buildId=221&view=logs&j=011e1ec8-6569-5e69-4f06-baf193d1351e&t=fe9cbe73-a432-5abe-f444-5cc590841043&l=229
It is not fully clear to me if this is one of the dependencies or my description file? But I do not have any explicit \n myself https://github.com/PyLops/pyproximal/blob/main/setup.py. Could the fact I go to the new line be a problem, even though being the text between triple quotes that should not be really a new line. Thanks!

@mrava87 Yes, AFAIU your code (before the fix) was buggy. The problem here is not that setuptools doesn’t accept newlines in the description field — it’s not supposed to, the (short) description must fit on a single line — but that in this case it produces corrupt output instead of halting and catching fire immediately.
That is to say, yes, there’s a bug in setuptools, even if there weren’t, what you just fixed in your code was a real mistake as well. (Your Travis pipeline is still failing, but for a different reason, as far as I can see.)

@mrava87 Yes, AFAIU your code (before the fix) was buggy. The problem here is not that setuptools doesn’t accept newlines in the description field — it’s not supposed to, the (short) description must fit on a single line — but that in this case it produces corrupt output instead of halting and catching fire immediately.
That is to say, yes, there’s a bug in setuptools, even if there weren’t, what you just fixed in your code was a real mistake as well. (Your Travis pipeline is still failing, but for a different reason, as far as I can see.)

Thanks! My travis pipeline is back on track, but yes that was another mistake.
Strange as I had two lines for long time and it always worked fine. But I have no problem to make it one line :)

Thanks! My travis pipeline is back on track, but yes that was another mistake.
Strange as I had two lines for long time and it always worked fine. But I have no problem to make it one line :)

In retrospect, the change introduced was probably too aggressive, especially because it affects third-party packages and older releases. I'll back off the change to emit a warning and remove the newlines with the intention of making the behavior invalid in the future.

In retrospect, the change introduced was probably too aggressive, especially because it affects third-party packages and older releases. I'll back off the change to emit a warning and remove the newlines with the intention of making the behavior invalid in the future.

@mrava87 wrote:

Strange as I had two lines for long time and it always worked fine.

That’s the problem with broken output, yes: whatever fields happened to come after the description in the PKG-INFO just got silently reinterpreted as a part of the text of the long description. In my case, for example, the package was almost correct, except that the Requires-Python aka python_requires field was silently discarded (and that the package description on PyPI was broken, of course). I never even recognized this before somebody using an old and unsupported Python complained. (Yes, I could and should have, but the point is that it’s not obvious.)

@mrava87 wrote:

Strange as I had two lines for long time and it always worked fine.

That’s the problem with broken output, yes: whatever fields happened to come after the description in the PKG-INFO just got silently reinterpreted as a part of the text of the long description. In my case, for example, the package was almost correct, except that the Requires-Python aka python_requires field was silently discarded (and that the package description on PyPI was broken, of course). I never even recognized this before somebody using an old and unsupported Python complained. (Yes, I could and should have, but the point is that it’s not obvious.)

setuptools 51.3.0 landed and I immediately got some error report about broken (internal) builds.
Reporting error here is not a good idea, really.
Please, don't go that way. Drop description altogether if you don't like it and can't fix it, but don't break installations. Ecosystem is huge, libraries are plenty, automated builds are numerous…

setuptools 51.3.0 landed and I immediately got some error report about broken (internal) builds.
Reporting error here is not a good idea, really.
Please, don't go that way. Drop description altogether if you don't like it and can't fix it, but don't break installations. Ecosystem is huge, libraries are plenty, automated builds are numerous…

@Mekk Immediately issuing a fatal error here is perhaps not a good idea (if you are affected, fetch 51.3.3 and get a warning instead), but please do recognize that if these errors break your build, your build was already subtly broken. It’s not that setuptools dropped support for newlines in the description field, it’s that it never supported them properly in the first place and produced bad and wrong output when they were encountered, only that bad and wrong output was still good enough that it still worked in most cases (though see my comment above re python_requires). Again, this is not about dropping something that used to be supported, this is turning silent breakage into loud breakage. Which I think we can all agree is a good thing.

@Mekk Immediately issuing a fatal error here is perhaps not a good idea (if you are affected, fetch 51.3.3 and get a warning instead), but please do recognize that if these errors break your build, your build was already subtly broken. It’s not that setuptools dropped support for newlines in the description field, it’s that it never supported them properly in the first place and produced bad and wrong output when they were encountered, only that bad and wrong output was still good enough that it still worked in most cases (though see my comment above re python_requires). Again, this is not about dropping something that used to be supported, this is turning silent breakage into loud breakage. Which I think we can all agree is a good thing.

I am not even trying to comprehend all possible setuptools use cases. I understand that probably there are some. But my builds worked happily, then they stopped to. And I strongly bet I am not the only one.
I understand, that the problem discussed here in some cases caused misinterpretation of some metadata field(s). Well, looks like this is more difficult to face and only rarely causes problems.
BTW: as I look at some random PKG-INFO files around, looks like Description field (mapped from long_description if I understand correclty) happily handles newlines by simply indenting whole field content. Couldn't the same technique be used for Summary in case it contains newlines?

I am not even trying to comprehend all possible setuptools use cases. I understand that probably there are some. But my builds worked happily, then they stopped to. And I strongly bet I am not the only one.
I understand, that the problem discussed here in some cases caused misinterpretation of some metadata field(s). Well, looks like this is more difficult to face and only rarely causes problems.
BTW: as I look at some random PKG-INFO files around, looks like Description field (mapped from long_description if I understand correclty) happily handles newlines by simply indenting whole field content. Couldn't the same technique be used for Summary in case it contains newlines?

For example, here is some random package I wrote on PyPi: https://pypi.org/project/mercurial_path_pattern/  Note that keywords and classifiers are correct (that's important as they are below long description in my PKG INFO).
And here is it's PKG-INFO (cut a bit to make it shorter:
Metadata-Version: 1.1
Name: mercurial_path_pattern
Version: 1.4.2
Summary: Mercurial Path Pattern Extension
Home-page: https://foss.heptapod.net/mercurial/mercurial-path_pattern
Author: Marcin Kasperski
Author-email: Marcin.Kasperski@mekk.waw.pl
License: BSD
Description: .. -*- mode: rst; compile-command: "rst2html README.rst README.html" -*-

        =======================================================
        Mercurial Path Pattern
        =======================================================

        Don't repeat yourself defining ``[paths]`` over many repositories,
        specify the general rule once in ``~/.hgrc``.

        Path Pattern is a Mercurial_ extension used to define default
        remote path aliases. You may find it helpful if you maintain
        consistently layed out repository trees on a few machines.

        … and so on and so on ending in empty line …

Keywords: mercurial hg path alias
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
…and remaining classifiers…

At least pypi parses that properly.

For example, here is some random package I wrote on PyPi: https://pypi.org/project/mercurial_path_pattern/  Note that keywords and classifiers are correct (that's important as they are below long description in my PKG INFO).
And here is it's PKG-INFO (cut a bit to make it shorter:
Metadata-Version: 1.1
Name: mercurial_path_pattern
Version: 1.4.2
Summary: Mercurial Path Pattern Extension
Home-page: https://foss.heptapod.net/mercurial/mercurial-path_pattern
Author: Marcin Kasperski
Author-email: Marcin.Kasperski@mekk.waw.pl
License: BSD
Description: .. -*- mode: rst; compile-command: "rst2html README.rst README.html" -*-

        =======================================================
        Mercurial Path Pattern
        =======================================================

        Don't repeat yourself defining ``[paths]`` over many repositories,
        specify the general rule once in ``~/.hgrc``.

        Path Pattern is a Mercurial_ extension used to define default
        remote path aliases. You may find it helpful if you maintain
        consistently layed out repository trees on a few machines.

        … and so on and so on ending in empty line …

Keywords: mercurial hg path alias
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
…and remaining classifiers…

At least pypi parses that properly.

So: is there any fundamental reason why the same method (indenting) which nicely works for Description, couldn't work for Summary?

So: is there any fundamental reason why the same method (indenting) which nicely works for Description, couldn't work for Summary?

Probably the strongest argument is that the field is specified to be one line. I do see that the "email headers" format does appear to support multiline values in any field, although the indentation semantics are not elegant:
draft $ cat > METADATA
Summary: foo
        bar
draft $ import importlib.metadata
draft $ dist = importlib.metadata.Distribution.at('.')
draft $ dist.metadata['Summary']
'foo\n        bar'

That is, the indents get included when the value is loaded. The same happens when there's a leading bar:
draft $ cat > METADATA
Summary: foo
       |bar
draft $ dist.metadata['Summary']
'foo\n       |bar'

The spec additionally indicates that for description (and only for description), seven spaces plus a pipe character should be used to indicate a continuation following a newline.
The spec is very imprecise about what characters are allowed. Most indicate "a string" and some examples do appear to have newlines and not the pipe characters. Even PEP 566 JSON conversion has the metadata converted without any indication of how to deal with multiline strings (all of the padding and pipes in continuation lines would be included).
Probably the PEPs need a refresh or new PEP to specify how multi-line fields should be serialized and deserialized to remove extraneous content.
Until someone takes up that mantle, Setuptools will do its best to honor and enforce the specified format as best as possible.

Probably the strongest argument is that the field is specified to be one line. I do see that the "email headers" format does appear to support multiline values in any field, although the indentation semantics are not elegant:
draft $ cat > METADATA
Summary: foo
        bar
draft $ import importlib.metadata
draft $ dist = importlib.metadata.Distribution.at('.')
draft $ dist.metadata['Summary']
'foo\n        bar'

That is, the indents get included when the value is loaded. The same happens when there's a leading bar:
draft $ cat > METADATA
Summary: foo
       |bar
draft $ dist.metadata['Summary']
'foo\n       |bar'

The spec additionally indicates that for description (and only for description), seven spaces plus a pipe character should be used to indicate a continuation following a newline.
The spec is very imprecise about what characters are allowed. Most indicate "a string" and some examples do appear to have newlines and not the pipe characters. Even PEP 566 JSON conversion has the metadata converted without any indication of how to deal with multiline strings (all of the padding and pipes in continuation lines would be included).
Probably the PEPs need a refresh or new PEP to specify how multi-line fields should be serialized and deserialized to remove extraneous content.
Until someone takes up that mantle, Setuptools will do its best to honor and enforce the specified format as best as possible.

@mrava87 wrote:

Strange as I had two lines for long time and it always worked fine.

That’s the problem with broken output, yes: whatever fields happened to come after the description in the PKG-INFO just got silently reinterpreted as a part of the text of the long description. In my case, for example, the package was almost correct, except that the Requires-Python aka python_requires field was silently discarded (and that the package description on PyPI was broken, of course). I never even recognized this before somebody using an old and unsupported Python complained. (Yes, I could and should have, but the point is that it’s not obvious.)

Thanks for the explanation. Makes sense and good that things get fixed and users can't follow bad practices anymore. No problem with things breaking as long as it is clear why and we can change, its all good :D

@mrava87 wrote:

Strange as I had two lines for long time and it always worked fine.

That’s the problem with broken output, yes: whatever fields happened to come after the description in the PKG-INFO just got silently reinterpreted as a part of the text of the long description. In my case, for example, the package was almost correct, except that the Requires-Python aka python_requires field was silently discarded (and that the package description on PyPI was broken, of course). I never even recognized this before somebody using an old and unsupported Python complained. (Yes, I could and should have, but the point is that it’s not obvious.)

Thanks for the explanation. Makes sense and good that things get fixed and users can't follow bad practices anymore. No problem with things breaking as long as it is clear why and we can change, its all good :D

According to the TODO comment in the source, it's time to turn the warning into an exception.

Lots of our builds are AGAIN broken since this release, for various dependencies.
I would have expect that setuptools does not hardly break for a simple escape all \n workaround.

I would have expect that setuptools does not hardly break for a simple escape all \n workaround.

It seems like an unfortunate wart to carry to support transforming \n to   forever. Is that what you're proposing, that Setuptools should allow invalid inputs and maintain responsibility for making them valid?
To be sure, Setuptools is not happy about breaking the builds. It's conceivable we could back out the removal and restore the Deprecation warning for an extended period. Would that help?

IMHO, no need to act. Package maintainer should be able to fix it, is not that we didn't see this coming.

It's not true, maintainers of those package can fix current code, but that will be only for "future" releases of one package, and not the already released one.
It means that every other stack that relies on that package needs to be also upgrade their versions pinning to fix their own build pipelines.
Indeed, as of today, builds are broken for nothing but a little metadata violation, i agree.
But this violation can still easily reworked (stripping \n is not a big deal) to be acceptable and then conserve retrocompatiblity which has no prize.
So, yes, the best option indeed is a forever(and not an extent of the deprecation period) warning, i would be really fine with that.

To make things clear, maybe a solution would be that what is not already uploaded to pypi can not be accepted, but what's already released should continue to be installable as it is already used in the wild.

source: gharchive/issue

authors: AmitAronovitch JeffreyCA Mekk alexshpilkin bittner brainwane di icemac jaraco kiorky mgedmin mrava87 normanius pganssle ssbarnea webknjaz wesinator

repo: pypa/setuptools

license: mit

license_type: permissive

license_source: bigquery


text:
database "warehouse" does not exist (while bootstrapping tutorial)

I was interested in testing a PR I was reviewing, so I followed the getting started guide. I checked out the repo, then ran the steps make build, make serve, then make initdb. The build seemed to go fine, but the make serve didn't seem to serve and instead there were lots of errors about database "warehouse" does not exist and DatabaseNotAvailableError. So I stopped the serve and ran make initdb, but that failed with:
docker-compose run --rm web psql -h db -d postgres -U postgres -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname ='warehouse';"
psql: could not translate host name "db" to address: Name or service not known
make: *** [initdb] Error 2

I see some other errors in the transcript as well.
I saved a full transcript of the session.
I'm using macOS 12 with Docker 20.10.10 and docker-compose 2.1.1. I set docker to have 4GB of memory.
Any suggestions?

Aha. It looks like make initdb needs to be run in a separate session while make serve is active.

Still, running make initdb is failing with this error (also visible in the transcript above):
docker-compose run --rm web python -m warehouse db upgrade head
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/runpy.py", line 193, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/local/lib/python3.8/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/opt/warehouse/src/warehouse/__main__.py", line 18, in <module>
    sys.exit(warehouse())
  File "/opt/warehouse/lib/python3.8/site-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "/opt/warehouse/lib/python3.8/site-packages/click/core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "/opt/warehouse/lib/python3.8/site-packages/click/core.py", line 1659, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/opt/warehouse/lib/python3.8/site-packages/click/core.py", line 1659, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/opt/warehouse/lib/python3.8/site-packages/click/core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/opt/warehouse/lib/python3.8/site-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "/opt/warehouse/lib/python3.8/site-packages/click/decorators.py", line 38, in new_func
    return f(get_current_context().obj, *args, **kwargs)
  File "/opt/warehouse/src/warehouse/cli/db/upgrade.py", line 27, in upgrade
    config.registry["sqlalchemy.engine"], config.alembic_config()
  File "/opt/warehouse/src/warehouse/cli/__init__.py", line 34, in __getattr__
    self.__config = configure(*self.__args, **self.__kwargs)
  File "/opt/warehouse/src/warehouse/config.py", line 475, in configure
    config.include(".routes")
  File "/opt/warehouse/lib/python3.8/site-packages/pyramid/config/__init__.py", line 666, in include
    c(configurator)
  File "/opt/warehouse/src/warehouse/routes.py", line 19, in includeme
    files_url = config.get_settings()["files.url"]
KeyError: 'files.url'
make: *** [initdb] Error 1

@jaraco I can't reproduce, is it possible you've changed/removed this line or this file? https://github.com/pypa/warehouse/blob/1bdbd65e66c71503dd7eedc48760807cc545ad45/dev/environment#L21
Or this line? https://github.com/pypa/warehouse/blob/1bdbd65e66c71503dd7eedc48760807cc545ad45/docker-compose.yml#L71

I hadn't changed anything. There was one file that was modified by make build, but it was just a comment in requirements/deploy.txt. Otherwise, I was on main at f84d7c5f.

That env var is getting set in the container:
warehouse main $ docker-compose run web env | grep FILES
Creating warehouse_web_run ... done
FILES_BACKEND=warehouse.packaging.services.LocalFileStorage path=/var/opt/warehouse/packages/ url=http://localhost:9001/packages/{path}

I just ran make build and make serve and I saw the same error in the web process.
I then updated the repo to edd39ff9, and the problem has gone away.
Maybe the issue was that when I first bootstrapped the environments, I was on a branch (standard-dist-name-check).

To try to recreate the issue, I updated to the branch, ran make purge, make build, make serve and (in a separate terminal) make initdb, and it all seems to be working. So whatever was going on seems to have corrected itself. My workstation did crash when I connected it up today, so maybe something was glitched on the host.

Since I can no longer recreate the issue, I'll close this. Thanks for the advice.

@jaraco https://github.com/pypa/warehouse/pull/9993 is the proper way to fix this. The reason for the error is that currently db service is started by make serve without finishing DB initialization. The PR makes sure the service is started after DB bootstrapping is complete.

authors: abitrolly di jaraco

repo: pypa/warehouse

license_source: github-api


text:
Add pointer to pypi-support on faq page

Added a pointer to the pypi-support repo in case someone loses access to their authenticator app and don't have recovery codes.

Hi @vinayak-mehta thank you for your pull request, I've addressed this separately in #7441

:+1:

source: gharchive/pull-request

authors: ewdurbin vinayak-mehta


text:
import pyroscope crash on arm64 platform!

WARNING: The requested image's platform (linux/arm64) does not match the detected host platform (linux/amd64) and no specific platform was requested
root@05f75e64e7d6:/home/app/webapp# uname -a
Linux 05f75e64e7d6 5.10.102.1-microsoft-standard-WSL2 #1 SMP Wed Mar 2 00:30:59 UTC 2022 aarch64 GNU/Linux
root@05f75e64e7d6:/home/app/webapp# python
iPython 3.7.5 (default, Nov 23 2019, 08:56:26)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyroscope
>>> python: malloc.c:2385: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
qemu: uncaught target signal 6 (Aborted) - core dumped
Aborted

pyroscope-io==0.6.0

# pypi index-url
https://mirrors.huaweicloud.com/repository/pypi/packages/b5/5c/d2215d263c638bdc8aa2b3530554b28b5694790aefa3ae25d1cbc2c27acf/pyroscope_io-0.6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#sha256=a437f9ec181cdac8b31041ff2a6a9f7330203304ef2841393428669d4931312c

@Panlq we recently changed the way we build the pip package — it should be more stable on arm64. Can you test to see if you can still reproduce this problem?

authors: Panlq petethepig

repo: pyroscope-io/pyroscope-python


text:
🛑 Pysio Home Files is down

In 93aafba, Pysio Home Files (https://files.pysio.online/dashboard) was down:

HTTP code: 0
Response time: 0 ms

Resolved: Pysio Home Files is back up in 52e5522 after 22 minutes.

license: MIT


text:
pyarrow.lib.ArrowKeyError: A type extension with name pandas.period already defined

As far as I can tell, I cannot use twice pd.read_parquet when mocking the filesystem.
How To Reproduce
% venv/bin/pytest tests/test_pyfakefs.py
=============================================================================== test session starts ===============================================================================
platform linux -- Python 3.11.7, pytest-8.0.0, pluggy-1.4.0
rootdir: /home/jbb/sandbox/pyfakefs_x_pandas
plugins: pyfakefs-5.3.5
collected 2 items

tests/test_pyfakefs.py .F                                                                                [100%]

==================================================================================== FAILURES =====================================================================================
_____________________________________________________________________________________ test_2 ______________________________________________________________________________________

    def test_2() -> None:
        dir_ = Path(Path(__file__).parent, "data")

>       df = pd.read_parquet(Path(dir_, "test.parquet"))

tests/test_pyfakefs.py:17:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
venv/lib/python3.11/site-packages/pandas/io/parquet.py:651: in read_parquet
    impl = get_engine(engine)
venv/lib/python3.11/site-packages/pandas/io/parquet.py:63: in get_engine
    return engine_class()
venv/lib/python3.11/site-packages/pandas/io/parquet.py:169: in __init__
    import pandas.core.arrays.arrow.extension_types  # pyright: ignore[reportUnusedImport] # noqa: F401
venv/lib/python3.11/site-packages/pandas/core/arrays/arrow/extension_types.py:59: in <module>
    pyarrow.register_extension_type(_period_type)
pyarrow/types.pxi:1842: in pyarrow.lib.register_extension_type
    ???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

>   ???
E   pyarrow.lib.ArrowKeyError: A type extension with name pandas.period already defined

pyarrow/error.pxi:91: ArrowKeyError
============================================================================= short test summary info =============================================================================
FAILED tests/test_pyfakefs.py::test_2 - pyarrow.lib.ArrowKeyError: A type extension with name pandas.period already defined
=========================================================================== 1 failed, 1 passed in 0.26s ===========================================================================

Your environment
% tree tests
tests
├── data
│   └── test.parquet
└── test_pyfakefs.py

% cat tests/test_pyfakefs.py
from pyfakefs.fake_filesystem import FakeFilesystem
from pathlib import Path
import pandas as pd

def test_1(fs: FakeFilesystem) -> None:
    dir_ = Path(Path(__file__).parent, "data")
    fs.add_real_directory(dir_)

    df = pd.read_parquet(Path(dir_, "test.parquet"))

# def test_2(fs: FakeFilesystem) -> None:
def test_2() -> None:
    dir_ = Path(Path(__file__).parent, "data")

    df = pd.read_parquet(Path(dir_, "test.parquet"))

python3.11 -m venv venv
source venv/bin/activate
pip install pandas pytest pyfakefs pyarrow
venv/bin/pytest tests/test_pyfakefs.py

% pip freeze
iniconfig==2.0.0
numpy==1.26.4
packaging==23.2
pandas==2.2.0
pluggy==1.4.0
pyarrow==15.0.0
pyfakefs==5.3.5
pytest==8.0.0
python-dateutil==2.8.2
pytz==2024.1
six==1.16.0
tzdata==2024.1

This is how I generated the parquet file:
python
>>> import pandas as pd
>>> pd.DataFrame({"a": [1], "b": 2}).to_parquet("data/test.parquet")

Thanks! Looks like the patching is not correctly reverted in this case for some reason.

@mrbean-bremen thank you for the quick response. How often do you perform maintenance tasks on this lib?
I'm looking for visibility on this issue to understand if I need to look for another solution.
I am aware you're probably maintaining this repo on your personal time.

I try to fix issues as soon as possible, but that depends on the kind of issue, and on other things I have to do. I had some shot at that one last weekend, but didn't get anywhere, and haven't since worked on it. I will see what I can do, but probably not before the weekend. I will let you know if I find something, or if this may take longer.
And yes, I'm doing this in my free time. I'm always happy about other contributors, of course...

The problem has to do with the dynamic patcher, but I didn't find the root cause yet. Switching off the dynamic patcher fixes the example, but depending on your use case, it may be needed (it patches modules loaded dynamically during the test).
If you want to try this, you can replace fs with a customized fixture, e.g.:
@pytest.fixture
def fs_no_dyn_patch():
    with Patcher(use_dynamic_patch=False) as p:
        yield p.fs

@jbbqqf - should be fixed on the main branch. Can you please test if this works for you?

Hi @mrbean-bremen .
I deeply apologize for asking for feedback and not replying until now. I had my test suite broken and ran out of time to fix it.
It is now fixed and I didn't experience the issue described above with the main branch of this repo installed (pip install git+https://github.com/pytest-dev/pyfakefs.git@582abdf44b5ee11f84215d7a638224ce67e122e9) instead of pyfakefs==5.3.5.
Thank you!

Thank you @jbbqqf - I'm waiting for feedback for another issue, and if nothing comes up, I will make a new release sometime next week (traveling right now).

FYI: A new release is out.

authors: jbbqqf mrbean-bremen

repo: pytest-dev/pyfakefs


text:
auto_detect in mypy

Opening here for discussion, before moving into mypy's bug tracker.
It just painfully occurred to me that mypy doesn't support auto_detect=True which is True by default in NG.
E.g. in
@attr.define
class SortableTableHeaders:
    headers: dict[str, str]
    default: str

    def __init__(self, names: tuple[str, ...]) -> None:
        def normalize(s: str) -> str:
            return s.replace(" ", "-").lower()

        self.default = normalize(names[0])
        self.headers = {normalize(n): n for n in names}

it forces you to pass init=False to define. Has that been raise to mypy? Would it be hard to implement? I think that's a really nice feature and am surprised myself, I didn't notice it before. @euresti any ideas?

I implemented the auto_detecting of attribs.  But nothing else.  You can file it there, but they'll probably just ping me about fixing it.  Unless someone else is excited about learning the mypy plugin code.  :)

authors: euresti hynek

repo: python-attrs/attrs


text:
Support for coroutines (asyncio)

Hello,
I was trying to use cachier for caching the result of functions, in particular, HTTP requests.
I am using asyncio throughout my code. I noticed that cachier is fully synchronous, as seen here when calling _calc_entry.
It would be great to have support for caching result of coroutines, using await.
Maybe an async PickeCore / decorator? I am not clear on the best way to accomplish this with minimal code duplication, though.

Hey,
That's an interesting use case. Yeah, I'm not sure myself. I think duplicating the decorator in a way that is agnostic to the core being used would be best, but this might also require rewriting the cores themselves to some extent. Also, it might simply be too complicated or plain impossible to have cores support this agnostically, and so each core would perhaps have to have a separate async implementation. But the pickle one is the important one anyway, I think.
I guess you'd have to figure things out a bit more before I can help you with this, as I really don't have the time to dive into this problem myself.

This would be amazing

Bump on that one.

authors: Paillat-dev bswck dekked shaypal5

repo: python-cachier/cachier


text:
Fix pzmap grid (matplotlib angle_helper)

CI runs started to fail today with:
Traceback (most recent call last):
959  File "pvtol-nested.py", line 169, in <module>
960    P, Z = pzmap(T, plot=True, grid=True)
961  File "/home/travis/build/python-control/python-control/control/pzmap.py", line 106, in pzmap
962    ax, fig = sgrid()
963  File "/home/travis/build/python-control/python-control/control/grid.py", line 82, in sgrid
964    ax.axis["wnxneg"] = axis = ax.new_floating_axis(0, 180)
965  File "/home/travis/miniconda/envs/test-environment/lib/python3.6/site-packages/mpl_toolkits/axisartist/axislines.py", line 575, in new_floating_axis
966    axes=self)
967  File "/home/travis/miniconda/envs/test-environment/lib/python3.6/site-packages/mpl_toolkits/axisartist/grid_helper_curvelinear.py", line 350, in new_floating_axis
968    axisline = AxisArtist(axes, _helper)
969  File "/home/travis/miniconda/envs/test-environment/lib/python3.6/site-packages/mpl_toolkits/axisartist/axis_artist.py", line 746, in __init__
970    self._init_line()
971  File "/home/travis/miniconda/envs/test-environment/lib/python3.6/site-packages/mpl_toolkits/axisartist/axis_artist.py", line 887, in _init_line
972    self._axis_artist_helper.get_line(self.axes),
973  File "/home/travis/miniconda/envs/test-environment/lib/python3.6/site-packages/mpl_toolkits/axisartist/grid_helper_curvelinear.py", line 270, in get_line
974    self.update_lim(axes)
975  File "/home/travis/miniconda/envs/test-environment/lib/python3.6/site-packages/mpl_toolkits/axisartist/grid_helper_curvelinear.py", line 101, in update_lim
976    self.grid_helper.update_lim(axes)
977  File "/home/travis/miniconda/envs/test-environment/lib/python3.6/site-packages/mpl_toolkits/axisartist/axislines.py", line 327, in update_lim
978    self._update(x1, x2, y1, y2)
979  File "/home/travis/miniconda/envs/test-environment/lib/python3.6/site-packages/mpl_toolkits/axisartist/grid_helper_curvelinear.py", line 319, in _update
980    self._update_grid(x1, y1, x2, y2)
981  File "/home/travis/miniconda/envs/test-environment/lib/python3.6/site-packages/mpl_toolkits/axisartist/grid_helper_curvelinear.py", line 367, in _update_grid
982    self.grid_info = self.grid_finder.get_grid_info(x1, y1, x2, y2)
983  File "/home/travis/miniconda/envs/test-environment/lib/python3.6/site-packages/mpl_toolkits/axisartist/grid_finder.py", line 104, in get_grid_info
984    extremes = self.extreme_finder(self.inv_transform_xy, x1, y1, x2, y2)
985  File "/home/travis/build/python-control/python-control/control/grid.py", line 44, in __call__
986    self._adjust_extremes(lon_min, lon_max, lat_min, lat_max)
987AttributeError: 'ModifiedExtremeFinderCycle' object has no attribute '_adjust_extremes'

Apparently Matplotlib removed the private function _adjust_extremes between 3.2 and 3.3 (I could not find the commit yet. Clicking blame on github doesn't work. Their git history is weird).
The specific branch of pzmap and this portion of grid.py are not covered by the unit tests. Hence it was not discovered until now, when conda updated matplotlib and it fails in the pvtol-nested.pyexample.

Coverage decreased (-10.7%) to 73.487% when pulling df0051c2849bc7accf772ee80faeb752b0478002 on bnavigator:fix-mpl-grid into 08d5e6ce2dfb99aee9d3d51d5689fac24cca7baa on python-control:master.

Added unit tests. Two fixtures editsdefaults and mplcleanup written for #438 are made especially for the use case here, so I pulled them from there. That should be relative benign when merging.
Found a copy and paste error in the pzmap defaults handling

Look at that increased coverage :)
Found another config/"defaults" handling bug in pzmap through the tests.

authors: bnavigator coveralls

repo: python-control/python-control


text:
Execute commands on netcup nodes.

What should the command do?
The idea is us being able to execute specific actions on one of our NetCup boxes.
For this to happen, a King-Arthur user needs to be created on all of our boxes.
Then, using its own private key, KA can SSH into a particular box and execute a command from there.
I am not sure how to scope this in terms of commands/cogs, but i thought we could have a NetCup cog which contains 2 commands

a raw command, to allow flexibility of using any command we want, and this needs to be granted to only a set of particular people. Ideally this command will prompt user for confirmation before using it.
A fail2ban group/command that will mostly just allow unbanning IPs from a particular host.

All these commands will need to take the box name in param obviously.
APIs

[ ] CloudFlare
[ ] Kubernetes
[ ] Discord
[X] Other

Who should be authorized to use this command?
DevOps

Fail2ban is the only thing that comes to mind right now also.
Potentially fetching info like things from "doveadm who" could be nice but isn't
a big deal.
I think it's fine to keep open but not prioritize implementation, it doesn't
hurt us.

repo: python-discord/king-arthur


text:
Threads archive state is not synchronized after start

Currently the thread archive state is only synchronized on startup. This means
that the archived flag on threads in the database slowly runs out of sync.
We should probably listen for
on_thread_update
or
on_raw_thread_update
here and update the database accordingly.

We listen to the former of the two events here https://github.com/python-discord/metricity/blob/main/metricity/exts/event_listeners/guild_listeners.py#L56-L62
Have you seen an example a thread's archive state not being updated? we might need to start listening to the second if so.
I didn't bother listening to the second event originally as my understanding was an active thread should always be in the bot's cache, so archiving a thread should mean that it always triggers the first event.

Just spotted why, https://github.com/python-discord/metricity/pull/156 should fix this

currently we will synchronize each of the current threads on the guild on any thread update
Yeah just spotted this too, seems quite heavy handed, but as you say it's still a small number of queries as far as postgers is concerned

authors: ChrisLovering jchristgit

repo: python-discord/metricity


text:
[Feature Request] April Fool's video

In the spirit of April Fool's, many companies have created ads that are less on the serious, and more on the fun side. Some of these can be quite believable.
So, for this particular issue, we would like to fetch a random April Fool's video from YouTube  from a pre-compiled list of these videos that we can watch for our entertainment.
Implementation details
List the changes required for the implementation here.

[ ] Write the bot command .foolme
[ ] Create a list of youtube April Fools video link
[ ] commands loads random video

Additional information
some examples:
https://www.youtube.com/watch?time_continue=1&v=KfWx2-QkEdI
https://www.youtube.com/watch?v=OYcv406J_J4&list=PLAD8wFTLnQKeDsINWn8WjXT1WIN8yDivO
https://www.youtube.com/watch?v=XQQuOICUylQ

I'll take this

repo: python-discord/seasonalbot


text:
Eigen values calculator for 3x3 matrix

Eigen Values calculator (for 3x3 matrix)
Brief - This script will find 3 eigen values of a given 3x3 matrix if they exist. The program will take the 9 values of a 3x3 matrix line by line and will generate the output showing the characteristic equation and a list of 3 eigen values.
Instructions

Create a new folder for your script and file/folder name should be appropriate.
Create a README.md (using this template) in your folder for program Instructions
add requirements.txt if needed

Programming Language

[x] Python

Happy Coding

@pawangeek Can you please assign this issue to me?

@pawangeek Can you please assign this issue to me?

This is not any general propose automation script

repo: python-geeks/Automation-scripts


text:
Snap Restart

Snap Restart
Sometimes, snap on linux (mostly Ubuntu distros) start background upgrades without notification or authorization. This may seems as trivial but it's very bothering for people with limited bandwidth and internet data.
So this script is used to easily stop and/or restart snap service.
Instructions

Create a new folder for your script and file/folder name should be appropriate.
Create a README.md (using this template) in your folder for program Instructions
add requirements.txt if needed

Programming Language

[x] Python

Target plateform

Linux

Happy Coding

Hi please assign this issue to me.

hye, if no one is working then please assign this to me

authors: ShlokJswl ptiwari6239 tbgracy