diff options
author | Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com> | 2021-11-20 13:21:28 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-20 13:21:28 +0100 |
commit | bcdb98a68407f57243b509dd35ab24c418485138 (patch) | |
tree | 2efc3ba8e7f34d8e355a7eb679875db1ab47aa69 | |
parent | b7a2ce0e9eb8db7e8ac579a5c16f5e04f87813eb (diff) | |
download | pylint-git-bcdb98a68407f57243b509dd35ab24c418485138.tar.gz |
Fix crash on ``open()`` calls for non-string ``mode`` arguments (#5332)
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | doc/whatsnew/2.12.rst | 4 | ||||
-rw-r--r-- | pylint/checkers/stdlib.py | 7 | ||||
-rw-r--r-- | tests/functional/u/unspecified_encoding_py38.py | 64 | ||||
-rw-r--r-- | tests/functional/u/unspecified_encoding_py38.txt | 32 |
5 files changed, 93 insertions, 18 deletions
@@ -187,6 +187,10 @@ Release date: TBA * Make yn validator case insensitive, to allow for ``True`` and ``False`` in config files. +* Fix crash on ``open()`` calls when the ``mode`` argument is not a simple string. + + Partially closes #5321 + What's New in Pylint 2.11.2? ============================ diff --git a/doc/whatsnew/2.12.rst b/doc/whatsnew/2.12.rst index f39c3f56f..9e8bfbb30 100644 --- a/doc/whatsnew/2.12.rst +++ b/doc/whatsnew/2.12.rst @@ -194,3 +194,7 @@ Other Changes * Added the ``--enable-all-extensions`` command line option. It will load all available extensions which can be listed by running ``--list-extensions`` + +* Fix crash on ``open()`` calls when the ``mode`` argument is not a simple string. + + Partially closes #5321 diff --git a/pylint/checkers/stdlib.py b/pylint/checkers/stdlib.py index 0eb47296e..d1fc49eb7 100644 --- a/pylint/checkers/stdlib.py +++ b/pylint/checkers/stdlib.py @@ -626,7 +626,12 @@ class StdlibChecker(DeprecatedMixin, BaseChecker): if mode_arg: mode_arg = utils.safe_infer(mode_arg) - if not mode_arg or "b" not in mode_arg.value: + + if ( + not mode_arg + or isinstance(mode_arg, nodes.Const) + and "b" not in mode_arg.value + ): encoding_arg = None try: if open_module == "pathlib" and node.func.attrname == "read_text": diff --git a/tests/functional/u/unspecified_encoding_py38.py b/tests/functional/u/unspecified_encoding_py38.py index 79c974bc2..ce5f3e816 100644 --- a/tests/functional/u/unspecified_encoding_py38.py +++ b/tests/functional/u/unspecified_encoding_py38.py @@ -1,8 +1,10 @@ """Warnings for using open() without specifying an encoding""" -# pylint: disable=consider-using-with +# pylint: disable=consider-using-with, too-few-public-methods +import dataclasses import io import locale from pathlib import Path +from typing import Optional FILENAME = "foo.bar" open(FILENAME, "w", encoding="utf-8") @@ -81,3 +83,63 @@ Path(FILENAME).open("wt") # [unspecified-encoding] Path(FILENAME).open("w+") # [unspecified-encoding] Path(FILENAME).open("w", encoding=None) # [unspecified-encoding] Path(FILENAME).open("w", encoding=LOCALE_ENCODING) + + +# Tests for storing data about open calls. +# Most of these are regression tests for a crash +# reported in https://github.com/PyCQA/pylint/issues/5321 + +# -- Constants +MODE = "wb" +open(FILENAME, mode=MODE) + + +# -- Functions +def return_mode_function(): + """Return a mode for open call""" + return "wb" + +open(FILENAME, mode=return_mode_function()) + + +# -- Classes +class IOData: + """Class that returns mode strings""" + + mode = "wb" + + def __init__(self): + self.my_mode = "wb" + + @staticmethod + def my_mode_method(): + """Returns a pre-defined mode""" + return "wb" + + @staticmethod + def my_mode_method_returner(mode: str) -> str: + """Returns the supplied mode""" + return mode + + +open(FILENAME, mode=IOData.mode) +open(FILENAME, mode=IOData().my_mode) +open(FILENAME, mode=IOData().my_mode_method()) +open(FILENAME, mode=IOData().my_mode_method_returner("wb")) +# Invalid value but shouldn't crash, reported in https://github.com/PyCQA/pylint/issues/5321 +open(FILENAME, mode=IOData) + + +# -- Dataclasses +@dataclasses.dataclass +class IOArgs: + """Dataclass storing information about how to open a file""" + + encoding: Optional[str] + mode: str + + +args_good_one = IOArgs(encoding=None, mode="wb") + +# Test for crash reported in https://github.com/PyCQA/pylint/issues/5321 +open(FILENAME, args_good_one.mode, encoding=args_good_one.encoding) diff --git a/tests/functional/u/unspecified_encoding_py38.txt b/tests/functional/u/unspecified_encoding_py38.txt index a83165421..118df7a8b 100644 --- a/tests/functional/u/unspecified_encoding_py38.txt +++ b/tests/functional/u/unspecified_encoding_py38.txt @@ -1,25 +1,25 @@ -unspecified-encoding:11:0::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:12:0::Using open without explicitly specifying an encoding:HIGH unspecified-encoding:13:0::Using open without explicitly specifying an encoding:HIGH unspecified-encoding:14:0::Using open without explicitly specifying an encoding:HIGH unspecified-encoding:15:0::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:24:5::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:27:5::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:31:5::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:36:0::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:37:0::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:16:0::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:17:0::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:26:5::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:29:5::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:33:5::Using open without explicitly specifying an encoding:HIGH unspecified-encoding:38:0::Using open without explicitly specifying an encoding:HIGH unspecified-encoding:39:0::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:48:5::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:51:5::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:55:5::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:64:0::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:65:0::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:40:0::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:41:0::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:50:5::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:53:5::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:57:5::Using open without explicitly specifying an encoding:HIGH unspecified-encoding:66:0::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:73:0::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:74:0::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:67:0::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:68:0::Using open without explicitly specifying an encoding:HIGH unspecified-encoding:75:0::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:79:0::Using open without explicitly specifying an encoding:HIGH -unspecified-encoding:80:0::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:76:0::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:77:0::Using open without explicitly specifying an encoding:HIGH unspecified-encoding:81:0::Using open without explicitly specifying an encoding:HIGH unspecified-encoding:82:0::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:83:0::Using open without explicitly specifying an encoding:HIGH +unspecified-encoding:84:0::Using open without explicitly specifying an encoding:HIGH |