wemake-python-styleguide icon indicating copy to clipboard operation
wemake-python-styleguide copied to clipboard

Possible use for `pass`

Open Day0Dreamer opened this issue 2 years ago • 7 comments

From: WPS420 — Forbid some python keywords.

pass keyword is just useless by design. There’s no use-case for it. Because it does literally nothing.

This is a snippet from a selector. In short, we need at the end a copy of render_data. We can get render_data out of doc, but sometimes we have only the data and no doc in sight.

class RenderSettings(object):

    def __init__(
        self,
        doc: Optional[c4d.documents.BaseDocument] | None = None,
        render_data: Optional[RenderData] | None = None,
    ):
        match (doc, render_data):
            case (None, None):
                doc = c4d.documents.GetActiveDocument()
                render_data = doc.GetActiveRenderData()
            case (None, _):
                pass
            case (_, None):
                render_data = doc.GetActiveRenderData()
            case (_, _):
                raise ValueError("doc and render_data are mutually exclusive.")

        if render_data is None:
            raise RuntimeError("No render data found.")

        self.rd: RenderData = render_data.GetClone()

It would seem, I literally want to just exit the match-case in a case where we have only render_data at the input.

Am I missing something?

Day0Dreamer avatar May 04 '23 22:05 Day0Dreamer

Hm, interesting.

The other way would be:

>>> match (None, 2):
...    case (x, _) if x is not None:
...        raise ValueError
... 

But, I agree that pass seems like the clearest solution here.

sobolevn avatar May 04 '23 22:05 sobolevn

Do we really have to make our match statements inclusive? Is there a need for case (None, _): pass at all?

It wouldn't match - the code wouldn't execute - basically the pass statement. Am I wrong here?

kehrazy avatar May 05 '23 12:05 kehrazy

@kehrazy I'd spend more time remembering and concluding why are there 3 cases for a problem with 2^2=4 possible solutions, than reading the pass case.

This feels like the case about declaring bit masks for filters alike firewall works

class PluginsFilterBits(object):
    """A class for filter bits."""

    known_to_renderfarm = FilterBit(bit=0b0100, name="known_to_renderfarm")             # noqa: WPS339
    built_in = FilterBit(bit=0b0010, name="built_in")                                   # noqa: WPS339
    is_script = FilterBit(bit=0b0001, name="is_script")                                 # noqa: WPS339
    weird = FilterBit(bit=0b1000, name="weird")                                         # noqa: WPS339

It is useful for when debugging and mentally reiterating "This case works, this case works,, this case works,, this case works,, this case works, how many cases were there? Eight? Okay, I've checked all eight"

Or with the bitmask - having it always in full length, with trailing zeroes, is in terms of Chat GPT, tokenizible. Meaning I can have for each bitmask remember it's feeling and operate with it, rather than pure logic.

Day0Dreamer avatar May 05 '23 22:05 Day0Dreamer

@Day0Dreamer hey, yeah, I can see the problem here, thanks for pointing this out. However, personally, when looking at this particular function, my brain goes "Yeah, this function handles these particular cases this way" - not "So, 2^2 - 4 cases... Huh, yeah, there's one that's not covered/handled here - should it be?"

You can add a comment, after all.

And yeah, I know about the "explicit is better than implicit" thing - does this apply here?

kehrazy avatar May 07 '23 06:05 kehrazy

pass here means exactly what it should do in the first place: nothing. So, providing pass in a case statement means that this case does not do anything.

As far as I know, there's no other way to describe the same thing without pass and using ... here is not correct.

sobolevn avatar May 07 '23 09:05 sobolevn

Why would we even declare a pass?

def verify_some_things(value_to_verify: int) -> bool:
    """
    This function verifies a lot of cool data.

    .. code:: python

        >>> verify_some_things(2)
        this is a two!
        True

    :param value_to_verify: an integer, the data to be verified.
    :return: bool - True if successful, False if not.
    """
    
    match value_to_verify:
        case 1:
            print("this is a one!")
            return True
        case 2:
            print("this is a two!")
            return True

    return False


if __name__ == "__main__":
    verify_some_things(1)  # this is a two!
    verify_some_things(2)  # this is a two!
    verify_some_things(3)  # prints nothing, there's no values matching.

kehrazy avatar May 07 '23 13:05 kehrazy

@kehrazy this comes from a habit of making a truth tables, where each state is accounted for. From the field of general computer science and electronics.

It's quite common while designing a logic machine, to start with a truth table, that describes all possible states.

Overall, it's a human construct to help humans not forget stuff and make debugging more structured.

What I think is actionable about this thread – documentation update. I really use a lot of the sections "This is a wrong way, this is a right way, this is the exception to the rule" inside the docs.

p.s. — Already added a noqa comment and forgot about the problem :D

Day0Dreamer avatar May 09 '23 10:05 Day0Dreamer