Skip to content

Commit

Permalink
Merge branch 'master' into class-getitem
Browse files Browse the repository at this point in the history
  • Loading branch information
PCManticore authored Feb 4, 2019
2 parents 999d50d + c2af5c7 commit da010b5
Show file tree
Hide file tree
Showing 17 changed files with 107 additions and 33 deletions.
6 changes: 6 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ Release date: TBA

Close #2416

* Support ``Ellipsis`` as a synonym for ``pass`` statements.

Close #2718

* ``fixme`` gets triggered only on comments.

Close #2321
Expand Down Expand Up @@ -94,6 +98,8 @@ Release date: TBA
* Avoid popping __main__ when using multiple jobs

Close #2689

* Add a new option 'check-str-concat-over-line-jumps' to check 'implicit-str-concat-in-sequence'

What's New in Pylint 2.2.2?
===========================
Expand Down
2 changes: 1 addition & 1 deletion pylint/__pkginfo__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
modname = distname = "pylint"

numversion = (2, 3, 0)
dev_version = "0"
dev_version = "1"
string_version = ".".join(str(num) for num in numversion)

if dev_version:
Expand Down
14 changes: 9 additions & 5 deletions pylint/checkers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,12 +369,12 @@ def report_by_type_stats(sect, stats, old_stats):
if total != 0:
try:
documented = total - stats["undocumented_" + node_type]
percent = (documented * 100.) / total
percent = (documented * 100.0) / total
nice_stats[node_type]["percent_documented"] = "%.2f" % percent
except KeyError:
nice_stats[node_type]["percent_documented"] = "NC"
try:
percent = (stats["badname_" + node_type] * 100.) / total
percent = (stats["badname_" + node_type] * 100.0) / total
nice_stats[node_type]["percent_badname"] = "%.2f" % percent
except KeyError:
nice_stats[node_type]["percent_badname"] = "NC"
Expand Down Expand Up @@ -1089,13 +1089,17 @@ def visit_expr(self, node):
return
self.add_message("pointless-string-statement", node=node)
return
# ignore if this is :

# Ignore if this is :
# * a direct function call
# * the unique child of a try/except body
# * a yield (which are wrapped by a discard node in _ast XXX)
# * a yieldd statement
# * an ellipsis (which can be used on Python 3 instead of pass)
# warn W0106 if we have any underlying function call (we can't predict
# side effects), else pointless-statement
if isinstance(expr, (astroid.Yield, astroid.Await, astroid.Call)) or (
if isinstance(
expr, (astroid.Yield, astroid.Await, astroid.Ellipsis, astroid.Call)
) or (
isinstance(node.parent, astroid.TryExcept) and node.parent.body == [node]
):
return
Expand Down
40 changes: 31 additions & 9 deletions pylint/checkers/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,20 @@ class StringConstantChecker(BaseTokenChecker):
"maybe a comma is missing ?",
),
}
options = (
(
"check-str-concat-over-line-jumps",
{
"default": False,
"type": "yn",
"metavar": "<y_or_n>",
"help": "This flag controls whether the "
"implicit-str-concat-in-sequence should generate a warning "
"on implicit string concatenation in sequences defined over "
"several lines.",
},
),
)

# Characters that have a special meaning after a backslash in either
# Unicode or byte strings.
Expand Down Expand Up @@ -601,22 +615,30 @@ def process_tokens(self, tokens):
# 'token' is the whole un-parsed token; we can look at the start
# of it to see whether it's a raw or unicode string etc.
self.process_string_token(token, start[0])
next_token = tokens[i + 1] if i + 1 < len(tokens) else None
# We figure the next token, ignoring comments & newlines:
j = i + 1
while j < len(tokens) and tokens[j].type in (
tokenize.NEWLINE,
tokenize.NL,
tokenize.COMMENT,
):
j += 1
next_token = tokens[j] if j < len(tokens) else None
if encoding != "ascii":
# We convert `tokenize` character count into a byte count,
# to match with astroid `.col_offset`
start = (start[0], len(line[: start[1]].encode(encoding)))
self.string_tokens[start] = (str_eval(token), next_token)

@check_messages(*(MSGS.keys()))
@check_messages(*(msgs.keys()))
def visit_list(self, node):
self.check_for_concatenated_strings(node, "list")

@check_messages(*(MSGS.keys()))
@check_messages(*(msgs.keys()))
def visit_set(self, node):
self.check_for_concatenated_strings(node, "set")

@check_messages(*(MSGS.keys()))
@check_messages(*(msgs.keys()))
def visit_tuple(self, node):
self.check_for_concatenated_strings(node, "tuple")

Expand All @@ -633,12 +655,12 @@ def check_for_concatenated_strings(self, iterable_node, iterable_type):
matching_token, next_token = self.string_tokens[
(elt.lineno, elt.col_offset)
]
# We detect string concatenation: the AST Const is the
# combination of 2 string tokens
if matching_token != elt.value and next_token is not None:
next_token_type, next_token_pos = next_token[0], next_token[2]
# We do not warn if string concatenation happens over a newline
if (
next_token_type == tokenize.STRING
and next_token_pos[0] == elt.lineno
if next_token.type == tokenize.STRING and (
next_token.start[0] == elt.lineno
or self.config.check_str_concat_over_line_jumps
):
self.add_message(
"implicit-str-concat-in-sequence",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pylint: disable=bad-continuation,missing-docstring

TEST_TUPLE = ('a', 'b' # [implicit-str-concat-in-sequence]
'c')
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[STRING_CONSTANT]
check-str-concat-over-line-jumps=yes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
implicit-str-concat-in-sequence:3::Implicit string concatenation found in tuple
5 changes: 3 additions & 2 deletions pylint/test/functional/logging_format_interpolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ class Logger(renamed_logging.Logger):

custom_logger = Logger('three')

custom_logger.info('testing {0}'.format('info')) # [logging-format-interpolation]
custom_logger.info('testing %s' % 'info') # [logging-not-lazy]
# Currently disabled until we get this in https://github.com/PyCQA/astroid/pull/637
# custom_logger.info('testing {0}'.format('info'))
# custom_logger.info('testing %s' % 'info')
2 changes: 0 additions & 2 deletions pylint/test/functional/logging_format_interpolation.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,3 @@ logging-format-interpolation:17::Use % formatting in logging functions and pass
logging-format-interpolation:18::Use % formatting in logging functions and pass the % parameters as arguments
logging-format-interpolation:19::Use % formatting in logging functions and pass the % parameters as arguments
logging-format-interpolation:20::Use % formatting in logging functions and pass the % parameters as arguments
logging-format-interpolation:37::Use % formatting in logging functions and pass the % parameters as arguments
logging-not-lazy:38::Specify string format arguments as logging function parameters
9 changes: 9 additions & 0 deletions pylint/test/functional/recursion_error_2667.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Add regression test for https://github.com/PyCQA/pylint/issues/2667"""
# pylint: disable=missing-docstring, too-few-public-methods

class MyClass:
def __init__(self):
self._slice = slice(0, 10)

def incr(self):
self._slice = slice(0, self._slice.stop + 1)
Empty file.
10 changes: 10 additions & 0 deletions pylint/test/functional/statement_without_effect.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,13 @@ def test(self):
self.val = 42
# +1:[pointless-string-statement]
""" this is an invalid attribute docstring. """


def ellipsis():
"""Test that an Ellipsis as a body does not trigger the error"""
...


class EllipsisBody:
"""Test that an Ellipsis as a body does not trigger the error"""
...
17 changes: 16 additions & 1 deletion pylint/test/functional/too_many_arguments.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# pylint: disable=missing-docstring
# pylint: disable=missing-docstring,wrong-import-position

def stupid_function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9): # [too-many-arguments]
return arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
Expand All @@ -15,3 +15,18 @@ def mymethod2(self):


MyClass().mymethod2()()


# Check a false positive does not occur
from functools import partial


def root_function(first, second, third):
return first + second + third


def func_call():
"""Test we don't emit a FP for https://github.com/PyCQA/pylint/issues/2588"""
partial_func = partial(root_function, 1, 2, 3)
partial_func()
return root_function(1, 2, 3)
13 changes: 0 additions & 13 deletions pylint/test/functional/unused_variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,3 @@ def some_other_scope():
def unused_import_from():
from functools import wraps as abc # [unused-import]
from collections import namedtuple # [unused-import]


def function():
ann: int = 0
assign = 0

def inner():
nonlocal ann, assign
ann += 1
assign += 1
return ann + assign

return inner()
13 changes: 13 additions & 0 deletions pylint/test/functional/unused_variable_py36.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# pylint: disable=missing-docstring

def function():
ann: int = 0
assign = 0

def inner():
nonlocal ann, assign
ann += 1
assign += 1
return ann + assign

return inner()
2 changes: 2 additions & 0 deletions pylint/test/functional/unused_variable_py36.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[testoptions]
min_pyver=3.6
Empty file.

0 comments on commit da010b5

Please sign in to comment.