Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ repos:
rev: v1.4
hooks:
- id: autoflake
exclude: &fixtures tests/functional/|tests/input|tests/regrtest_data/|tests/data/
exclude: &fixtures tests/functional/|tests/input|tests/regrtest_data/|tests/data/|doc/data/messages
args:
- --in-place
- --remove-all-unused-imports
Expand Down
2 changes: 1 addition & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["_build"]
exclude_patterns = ["_build", "data/**"]

# The reST default role (used for this markup: `text`) to use for all documents.
# default_role = None
Expand Down
2 changes: 2 additions & 0 deletions doc/data/messages/e/empty-docstring/bad.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def foo():
pass # [emtpy-docstring]
Comment on lines +1 to +2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to the actual MR, but I think code example could be 'real' and 'exciting' with animal, vegetal and real concepts or code example to be more rememberable. Also typing by default would influence begginner to use it later.

Suggested change
def foo():
pass # [emtpy-docstring]
def add(a: Any, b: Any) -> Any:
return a + b # [emtpy-docstring]

Foos and bars are traditional and have the benefit of not introducing more concept than the message itself, but also a little boring and I think human learn better with (fun) examples than with generic examples.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, in this case it doesn't really hurt, but I actually think the examples should be as bare bones as possible. That helps to identify the actual issue.
To make a (bad) example from this case: is empty-docstring raise for all functions or only for functions with parameters? In this case it doesn't really matter because that though is nonsensical, but I think there are messages where it actually helps if the example is as simple as possible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right about "any", maybe we could another example ? (def do_nothing() -> None:).

Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas Mar 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're also right about barebone being a good thing, but I dislike foo/bar for documentation. For a beginner the first thing they have to do is to read https://en.wikipedia.org/wiki/Foobar and learn about our little software programmer internal meme. We can probably make barebone examples that school children would understand without prior knowledge.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah shit, I completely forgot about this.

I'll keep it in mind for future PRs 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry we'll have to review hundred of examples that were in pylint-error, there's no use nitpicking about the style right now 😄

2 changes: 2 additions & 0 deletions doc/data/messages/e/empty-docstring/good.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def foo():
"""A dummy description."""
Comment on lines +1 to +2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def foo():
"""A dummy description."""
def add(a: Any, b: Any) -> Any:
"""Add a and b."""
return a + b

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, what does adding Any really provide here? Without any information mypy and others will already infer everything as Any.

2 changes: 2 additions & 0 deletions doc/data/messages/y/yield-inside-async-function/bad.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
async def foo():
yield from [1, 2, 3] # [yield-inside-async-function]
Comment on lines +1 to +2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
async def foo():
yield from [1, 2, 3] # [yield-inside-async-function]
async def count_to_three() -> Iterator[int]:
yield from [1, 2, 3] # [yield-inside-async-function]

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The message can't be emitted when using Python < 3.5.
7 changes: 7 additions & 0 deletions doc/data/messages/y/yield-inside-async-function/good.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
async def foo():
def _inner_foo():
yield from [1, 2, 3]


async def foo():
yield 42
Comment on lines +1 to +7
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
async def foo():
def _inner_foo():
yield from [1, 2, 3]
async def foo():
yield 42
async def count_to_three() -> Iterator[int]:
def _inner_count_to_three() -> Iterator[int]:
yield from [1, 2, 3]
async def the_answer() -> Iterator[int]:
yield 42

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- `PEP 525 <https://peps.python.org/pep-0525/>`_
73 changes: 72 additions & 1 deletion doc/exts/pylint_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
PYLINT_MESSAGES_PATH = PYLINT_BASE_PATH / "doc" / "messages"
"""Path to the messages documentation folder."""

PYLINT_MESSAGES_DATA_PATH = PYLINT_BASE_PATH / "doc" / "data" / "messages"
"""Path to the folder with data for the messages documentation."""

MSG_TYPES_DOC = {k: v if v != "info" else "information" for k, v in MSG_TYPES.items()}

Expand All @@ -32,6 +34,10 @@ class MessageData(NamedTuple):
id: str
name: str
definition: MessageDefinition
good_code: str
bad_code: str
details: str
related_links: str


MessagesDict = Dict[str, List[MessageData]]
Expand All @@ -47,6 +53,54 @@ def _register_all_checkers_and_extensions(linter: PyLinter) -> None:
initialize_extensions(linter)


def _get_message_data(data_path: Path) -> Tuple[str, str, str, str]:
"""Get the message data from the specified path."""
good_code, bad_code, details, related = "", "", "", ""

if not data_path.exists():
return good_code, bad_code, details, related

if (data_path / "good.py").exists():
with open(data_path / "good.py", encoding="utf-8") as file:
file_content = file.readlines()
indented_file_content = "".join(" " + i for i in file_content)
good_code = f"""
**Correct code:**

.. code-block:: python

{indented_file_content}"""

if (data_path / "bad.py").exists():
with open(data_path / "bad.py", encoding="utf-8") as file:
file_content = file.readlines()
indented_file_content = "".join(" " + i for i in file_content)
bad_code = f"""
**Problematic code:**

.. code-block:: python

{indented_file_content}"""

if (data_path / "details.rst").exists():
with open(data_path / "details.rst", encoding="utf-8") as file:
file_content_string = file.read()
details = f"""
**Additional details:**

{file_content_string}"""

if (data_path / "related.rst").exists():
with open(data_path / "related.rst", encoding="utf-8") as file:
file_content_string = file.read()
related = f"""
**Related links:**

{file_content_string}"""

return good_code, bad_code, details, related


def _get_all_messages(
linter: PyLinter,
) -> Tuple[MessagesDict, OldMessagesDict]:
Expand All @@ -72,8 +126,20 @@ def _get_all_messages(
"information": defaultdict(list),
}
for message in linter.msgs_store.messages:
message_data_path = (
PYLINT_MESSAGES_DATA_PATH / message.symbol[0] / message.symbol
)
good_code, bad_code, details, related = _get_message_data(message_data_path)

message_data = MessageData(
message.checker_name, message.msgid, message.symbol, message
message.checker_name,
message.msgid,
message.symbol,
message,
good_code,
bad_code,
details,
related,
)
messages_dict[MSG_TYPES_DOC[message.msgid[0]]].append(message_data)

Expand Down Expand Up @@ -108,6 +174,11 @@ def _write_message_page(messages_dict: MessagesDict) -> None:

*{message.definition.description}*

{message.good_code}
{message.bad_code}
{message.details}
{message.related_links}

Created by ``{message.checker}`` checker
"""
)
Expand Down