Exemple #1
0
def assert_message_fixer(old_expr, new_expr, method, is_absl=False):
  """Fixer for assertTrue()/assertFalse()/etc.

  related error fixes.

  assertTrue(...) often produces less readable error information than
  alternative methods like assertEqual etc.

  Args:
    old_expr: a ExprPattern string for the expr to match
    new_expr: a template string for the replacement
    method: the method to link to in the docs.
    is_absl: Whether this is an absl method with absl docs.

  Returns:
    A fixer that replaces old_expr with new_expr.
  """
  if is_absl:
    # absl doesn't have docs per se.
    url = f'https://github.com/abseil/abseil-py/search?q=%22def+{method}%22'
  else:
    url = f'https://docs.python.org/3/library/unittest.html#unittest.TestCase.{method}'
  dotdotdot = fixer.ImmutableDefaultDict(lambda _: '...')
  return fixer.SimplePythonFixer(
      message=(
          '%s is a more specific assertion, and may give more detailed error information than %s.'
          % (string.Template(new_expr).substitute(dotdotdot),
             string.Template(old_expr).substitute(dotdotdot))),
      matcher=syntax_matchers.ExprPattern(old_expr),
      replacement=syntactic_template.PythonExprTemplate(new_expr),
      url=url,
      category='pylint.g-generic-assert',
  )
Exemple #2
0
def assert_alias_fixer(
    old_expr,
    new_expr,
    url='https://docs.python.org/3/library/unittest.html#deprecated-aliases'):
  """Fixer for deprecated unittest aliases.

  Args:
    old_expr: A string for an ExprPattern matching the target expr.
    new_expr: A string for a PythonExprTemplate to replace it with.
    url: The URL documenting the deprecation.

  Returns:
    A fixer that replaces old_expr with new_expr.
  """
  dotdotdot = fixer.ImmutableDefaultDict(lambda _: '...')
  return fixer.SimplePythonFixer(
      message=('{old} is a deprecated alias for {new} in the unittest module.'
               .format(
                   old=string.Template(old_expr).substitute(dotdotdot),
                   new=string.Template(new_expr).substitute(dotdotdot))),
      matcher=syntax_matchers.ExprPattern(old_expr),
      replacement=syntactic_template.PythonExprTemplate(new_expr),
      url=url,
      significant=False,
      category='pylint.g-deprecated-assert',
  )
Exemple #3
0
def idiom_fixer(
    old_expr,
    new_expr,
    category,
    url='https://refex.readthedocs.io/en/latest/guide/fixers/idiom.html',
):
    """Fixer for making expressions "clearer" / less convoluted.

  This also helps normalize them for other fixers to apply.

  Args:
    old_expr: An ExprPattern string for the expr to match.
    new_expr: A string.Template string for the replacement.
    category: A category for the fix.
    url: An URL describing the fix.

  Returns:
    A fixer that replaces old_expr with new_expr.
  """
    dotdotdot = fixer.ImmutableDefaultDict(lambda _: '...')
    return fixer.SimplePythonFixer(
        message=('This could be more Pythonic: %s -> %s.' %
                 ((string.Template(old_expr).substitute(dotdotdot),
                   string.Template(new_expr).substitute(dotdotdot)))),
        matcher=syntax_matchers.ExprPattern(old_expr),
        replacement=syntactic_template.PythonExprTemplate(new_expr),
        url=url,
        significant=False,
        category=category,
    )
Exemple #4
0
 def test_labeled_replacements_example_fragment(self):
     fx = fixer.SimplePythonFixer(
         message='',
         matcher=syntax_matchers.ExprPattern('$y'),
         replacement={'y': syntactic_template.PythonExprTemplate('$y')},
     )
     with self.assertRaises(TypeError):
         fx.example_replacement()
Exemple #5
0
    def test_replace(self):
        fix = fixer.SimplePythonFixer(
            matcher=syntax_matchers.ExprPattern('$obj.attr'),
            replacement=syntactic_template.PythonTemplate(u'$obj.other'),
        )
        searcher = fixer.CombiningPythonFixer([fix])

        source = 'my_obj.attr + other_obj.attr'
        self.assertEqual('my_obj.other + other_obj.other',
                         search.rewrite_string(searcher, source, 'example.py'))
Exemple #6
0
 def test_doesnt_discard_unparseable_compound_stmt(self):
     fx = fixer.CombiningPythonFixer([
         fixer.SimplePythonFixer(message='ouch',
                                 matcher=ast_matchers.For(),
                                 replacement=formatting.ShTemplate('x x x'),
                                 url='')
     ])
     self.assertEqual(
         list(search.find_iter(fx, 'for x in y: pass', 'foo.py')),
         [_substitution(message='ouch')])
Exemple #7
0
def _mutable_constant_fixer(matcher, replacement, **kwargs):
    return fixer.SimplePythonFixer(
        message=
        'For constants, prefer immutable collections (like frozensets or tuples) to mutable collections (like sets or lists).',
        url=
        'https://refex.readthedocs.io/en/latest/guide/fixers/mutable_constants.html',
        significant=False,
        category=_MUTABLE_CONSTANT_CATEGORY,
        matcher=matcher,
        replacement=replacement,
        **kwargs)
Exemple #8
0
def _search_replace_fixer(search_expr,
                          replace,
                          message=None,
                          url='',
                          **kwargs):
    return fixer.SimplePythonFixer(
        message=message if message is not None else search_expr,
        matcher=syntax_matchers.ExprPattern(search_expr),
        replacement=syntactic_template.PythonExprTemplate(replace),
        url=url,
        category='TESTONLY',
        **kwargs)
Exemple #9
0
    def test_discards_unparseable_expr(self):
        """Searching discards unparseable substitutions for expressions.

    (Note: this only happens during fixedpoint computation.)
    """
        fx = fixer.CombiningPythonFixer([
            fixer.SimplePythonFixer(message='',
                                    matcher=syntax_matchers.ExprPattern('a'),
                                    replacement=formatting.ShTemplate('x x x'),
                                    url='')
        ])
        self.assertEqual(
            list(search.find_iter(fx, 'a', 'foo.py', max_iterations=10)), [])
Exemple #10
0
def _dict_iter_fixer(method_name):
    return fixer.SimplePythonFixer(
        message=('dict.{method} is deprecated and does not exist in Python 3. '
                 'Instead, import six and use six.{method}').format(
                     method=method_name),
        matcher=with_six(
            syntax_matchers.ExprPattern('$x.{}()'.format(method_name), {
                'x':
                base_matchers.Unless(syntax_matchers.ExprPattern('six'))
            }), ),
        replacement=syntactic_template.PythonExprTemplate(
            'six.{}($x)'.format(method_name)),
        url='https://www.python.org/doc/sunset-python-2/',
        category='pylint.dict-iter-method',
        # Must define manually due to the extra restrictions on the pattern.
        example_fragment='import six; x.{}()'.format(method_name),
        example_replacement='import six; six.{}(x)'.format(method_name),
    )
Exemple #11
0
from refex.python import syntactic_template
from refex.python.matchers import ast_matchers
from refex.python.matchers import base_matchers
from refex.python.matchers import syntax_matchers

SIMPLE_PYTHON_FIXERS = []  # Disabled except when running in Python 2.


def with_six(m):
    return syntax_matchers.WithTopLevelImport(m, 'six')


_HAS_KEY_FIXER = fixer.SimplePythonFixer(
    message='dict.has_key() was removed in Python 3.',
    matcher=syntax_matchers.ExprPattern('$a.has_key($b)'),
    replacement=syntactic_template.PythonExprTemplate('$b in $a'),
    url='https://docs.python.org/3.1/whatsnew/3.0.html#builtins',
    significant=True,
    category='refex.modernize.dict_has_key',
)


def _dict_iter_fixer(method_name):
    return fixer.SimplePythonFixer(
        message=('dict.{method} is deprecated and does not exist in Python 3. '
                 'Instead, import six and use six.{method}').format(
                     method=method_name),
        matcher=with_six(
            syntax_matchers.ExprPattern('$x.{}()'.format(method_name), {
                'x':
                base_matchers.Unless(syntax_matchers.ExprPattern('six'))
            }), ),
Exemple #12
0
 fixer.SimplePythonFixer(
     message=
     'If a function ever returns a value, all the code paths should have a return statement with a return value.',
     url=
     'https://refex.readthedocs.io/en/latest/guide/fixers/return_none.html',
     significant=False,
     category=_NONE_RETURNS_CATEGORY,
     matcher=base_matchers.AllOf(
         syntax_matchers.StmtPattern('return'),
         syntax_matchers.InNamedFunction(
             _function_containing(_NON_NONE_RETURN)),
         # Nested functions are too weird to consider right now.
         # TODO: Add matchers to match only the first ancestor
         # function and a way to use IsOrHasDescendant that doesn't recurse
         # into nested functions.
         base_matchers.Unless(
             syntax_matchers.InNamedFunction(
                 _function_containing(
                     syntax_matchers.NamedFunctionDefinition())))),
     replacement=syntactic_template.PythonStmtTemplate('return None'),
     example_fragment=textwrap.dedent("""
         def f(x):
           if x:
             return
           return -1
         """),
     example_replacement=textwrap.dedent("""
         def f(x):
           if x:
             return None
           return -1
         """),
 ),