Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

poetry install checks README.md, but poetry check does not. #6937

Closed
4 tasks done
YDX-2147483647 opened this issue Nov 2, 2022 · 4 comments · Fixed by #7444
Closed
4 tasks done

poetry install checks README.md, but poetry check does not. #6937

YDX-2147483647 opened this issue Nov 2, 2022 · 4 comments · Fixed by #7444
Labels
kind/bug Something isn't working as expected status/triage This issue needs to be triaged

Comments

@YDX-2147483647
Copy link
Contributor

  • Poetry version: 1.2.2

  • Python version: 3.10.8

  • OS version and name: Windows 10 (21H1) and Raspberry Pi OS (based on Debian 11 Bullseye)

  • pyproject.toml: default – poetry new <package_name> can fire this issue.

  • I am on the latest stable Poetry version, installed using a recommended method.

  • I have searched the issues of this repo and believe that this is not a duplicate.

  • I have consulted the FAQ and blog for any relevant entries or release notes. (Note: I’ve only checked FAQ and blog 1.2.x)

  • If an exception occurs when executing a command, I executed it again in debug mode (-vvv option) and have included the output below.

Issue

poetry install checks README.md, but poetry check does not.

To be rigorous, it checks tool.poetry.readme in pyproject.toml.

Is it an issue?

  • All commands work: poetry install raises a FileNotFoundError, but it works.

  • Doc: The install command reads pyproject.toml, resolves the dependencies, and installs them.

    It should not care about README.

  • Doc: The check command validates the structure of pyproject.toml.

    Although README is absent, the TOML structure is valid. So this might be expected.

To Reproduce

TL; DR:

  1. Create a project.
  2. rm README.md.
  3. poetry install: No such file or directory: README.md.

1. Create a project

$ poetry new why-read-me
$ cd why-read-me

$ cat pyproject.toml
# There's a default `README.md`.
[tool.poetry]
name = "why-read-me"
……
readme = "README.md"
……

2. poetry install checks README.md

$ mv .\README.md read-me-whatever.md
# Let's steal the README.

$ poetry install
# The `install` command checks the README, and raises an error.
# However, it successfully installs packages. (If I add some packages in pyproject.toml, it will be installed here.)
Using virtualenv: ……
Installing dependencies from lock file

Finding the necessary packages for the current system

  FileNotFoundError

  [Errno 2] No such file or directory: '……/why-read-me/README.md'

  at ……\Python310\lib\pathlib.py:1119 in open
      1115│         the built-in open() function does.
      1116│         """
      1117│         if "b" not in mode:
      1118│             encoding = io.text_encoding(encoding)
    → 1119│         return self._accessor.open(self, mode, buffering, encoding, errors,
      1120│                                    newline)
      1121│

3. Other commands work

$ poetry check
# It ignores the absence of README.
All set!

$ poetry add any-package
Using version …… for ……
Updating dependencies
Writing lock file
Package operations: …… installs, ……
  - Installing …… (……)
……
# Nothing broken and No error raised.

4. Updatetool.poetry.readme

$ nano pyproject.toml
# Change `tool.poetry.readme` to `read-me-whatever.md`.

$ poetry install
# Everthing is OK now.
Installing dependencies from lock file
Installing the current project: why-read-me (0.1.0)

Full output with -vv

Output of `poetry install -vv` Using virtualenv: ……\temp\why-read-me\.venv Installing dependencies from lock file

Finding the necessary packages for the current system

Stack trace:

11 ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\application.py:329 in run
exit_code = self._run(io)

10 ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\console\application.py:185 in _run
exit_code: int = super()._run(io)

9 ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\application.py:423 in _run
exit_code = self._run_command(command, io)

8 ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\application.py:465 in _run_command
raise error

7 ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\application.py:449 in _run_command
exit_code = command.run(io)

6 ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\commands\base_command.py:119 in run
status_code = self.execute(io)

5 ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\commands\command.py:83 in execute
return self.handle()

4 ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\console\commands\install.py:155 in handle
builder = EditableBuilder(self.poetry, self.env, self.io)

3 ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\masonry\builders\editable.py:47 in init
super().init(poetry)

2 ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\core\masonry\builders\builder.py:90 in init
self._meta = Metadata.from_package(self._package)

1 ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\core\masonry\metadata.py:60 in from_package
with readme.open(encoding="utf-8") as f:

FileNotFoundError

[Errno 2] No such file or directory: '……\temp\why-read-me\README.md'

at C:\Program Files\Python310\lib\pathlib.py:1119 in open
1115│ the built-in open() function does.
1116│ """
1117│ if "b" not in mode:
1118│ encoding = io.text_encoding(encoding)
→ 1119│ return self._accessor.open(self, mode, buffering, encoding, errors,
1120│ newline)
1121│
1122│ def read_bytes(self):
1123│ """

@YDX-2147483647 YDX-2147483647 added kind/bug Something isn't working as expected status/triage This issue needs to be triaged labels Nov 2, 2022
@ppyrzanowski
Copy link

I thought there was a general problem with my project structure as a newbie to poetry. I wonder how such problem has gone unnoticed till now. Spent way too much time figuring out the problem source.

@YDX-2147483647
Copy link
Contributor Author

YDX-2147483647 commented Jan 12, 2023

Further Details

readmes → metadata.descriptionpoetry install ⇒ FileNotFoundError

poetry install needs metadata, whose description is from readmes. (According to “Full output with -vv”)

# poetry/core/masonry/metadata.py
class Metadata:
    def from_package(cls, package: Package) -> Metadata:
        meta = cls()

        if package.readmes:
            descriptions = []
            for readme in package.readmes:
                with readme.open(encoding="utf-8") as f:  # ⇒ FileNotFoundError
                    descriptions.append(f.read())
            meta.description = "\n".join(descriptions)

https://github.com/python-poetry/poetry-core/blob/978fb55a2f78e1e11cd226722713c70a102dc40d/src/poetry/core/masonry/metadata.py#L48-L62

poetry check also somehow validates readmes

check_result = Factory.validate(config, strict=True)

# poetry/core/factory.py 
class Factory:
    @classmethod
    def validate(
        cls, config: dict[str, Any], strict: bool = False
    ) -> dict[str, list[str]]:
        if strict:
            # Checking types of all readme files (must match)
            if "readme" in config and not isinstance(config["readme"], str):
                readme_types = {readme_content_type(r) for r in config["readme"]}
                if len(readme_types) > 1:
                    result["errors"].append(
                        "Declared README files must be of same type: found"
                        f" {', '.join(sorted(readme_types))}"
                    )

https://github.com/python-poetry/poetry-core/blob/978fb55a2f78e1e11cd226722713c70a102dc40d/src/poetry/core/factory.py#L445-L452

Note: readme_content_type() infers content type from the file extension (aka. suffix), not its real content.

@YDX-2147483647
Copy link
Contributor Author

YDX-2147483647 commented Jan 30, 2023

As discussed in #7424, poetry check should check everything.

if "readme" in config:
    readmes = config["readme"]
    if isinstance(config["readme"], str):
        readmes = (config["readme"],)

    # Checking types of all readme files (must match)
    readme_types = {readme_content_type(r) for r in readmes}
    if len(readme_types) > 1:
        # ……

    # Checking existence of readme files
    missing_readmes = [r for r in readmes if not Path(r).exists()]
    if missing_readmes:
        result["errors"].append(
            "Cannot find declared README file(s):"
            f" {', '.join(missing_readmes)}"
        )

I've tried to modify poetry/core/factory.py (as above), but I find it a bad idea… Factory is used as an abstract factory in test_factory.py, so the following tests will be broken.

YDX-2147483647 added a commit to YDX-2147483647/poetry that referenced this issue Jan 31, 2023
YDX-2147483647 added a commit to YDX-2147483647/poetry that referenced this issue Jan 31, 2023
YDX-2147483647 added a commit to YDX-2147483647/poetry that referenced this issue Jan 31, 2023
YDX-2147483647 added a commit to YDX-2147483647/poetry that referenced this issue Feb 3, 2023
cnshing added a commit to cnshing/SnooSpoof-backend-api that referenced this issue Oct 15, 2023
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 29, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
kind/bug Something isn't working as expected status/triage This issue needs to be triaged
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants