Hello community, here is the log from the commit of package python-pep8-naming for openSUSE:Factory checked in at 2019-02-02 22:24:46 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pep8-naming (Old) and /work/SRC/openSUSE:Factory/.python-pep8-naming.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pep8-naming" Sat Feb 2 22:24:46 2019 rev:4 rq:670749 version:0.8.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pep8-naming/python-pep8-naming.changes 2018-12-24 11:47:41.817117762 +0100 +++ /work/SRC/openSUSE:Factory/.python-pep8-naming.new.28833/python-pep8-naming.changes 2019-02-02 22:24:55.242092197 +0100 @@ -1,0 +2,19 @@ +Sat Feb 2 17:04:38 UTC 2019 - Arun Persaud <a...@gmx.de> + +- specfile: + * update copyright year + +- update to version 0.8.0: + * Detect N806 errors within for loops and exception handlers. + * Improve support for non-ASCII characters. + * Detect mixedCased variable names at class (N815) and global (N816) + scope. + * Ignore Django's setUpTestData method by default. + * Fix column offsets for N803, N804, and N805 under Python 3. + * Detect underscores within class names as N801 errors. + * Don't flag __getattr__ and __dir__ as N807 errors. (See PEP 562). + * async function and method names are now checked. + * Detect N806 errors in generator expressions and comprehensions. + * Detect N81x errors in import x as y statements. + +------------------------------------------------------------------- Old: ---- pep8-naming-0.7.0.tar.gz New: ---- pep8-naming-0.8.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pep8-naming.spec ++++++ --- /var/tmp/diff_new_pack.5IFOVN/_old 2019-02-02 22:24:55.758091739 +0100 +++ /var/tmp/diff_new_pack.5IFOVN/_new 2019-02-02 22:24:55.770091728 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-pep8-naming # -# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,25 +18,24 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-pep8-naming -Version: 0.7.0 +Version: 0.8.0 Release: 0 Summary: Flake8 plugin for checking PEP-8 naming conventions License: MIT Group: Development/Languages/Python -Url: https://github.com/flintwork/pep8-naming +URL: https://github.com/flintwork/pep8-naming Source: https://files.pythonhosted.org/packages/source/p/pep8-naming/pep8-naming-%{version}.tar.gz BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros -# SECTION test requirements -BuildRequires: %{python_module flake8-polyfill >= 1.0.2} -BuildRequires: %{python_module flake8} -# /SECTION Requires: python-flake8 Requires: python-flake8-polyfill >= 1.0.2 Requires: python-setuptools BuildArch: noarch - +# SECTION test requirements +BuildRequires: %{python_module flake8-polyfill >= 1.0.2} +BuildRequires: %{python_module flake8} +# /SECTION %python_subpackages %description ++++++ pep8-naming-0.7.0.tar.gz -> pep8-naming-0.8.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/CHANGELOG.rst new/pep8-naming-0.8.0/CHANGELOG.rst --- old/pep8-naming-0.7.0/CHANGELOG.rst 2018-05-17 17:30:20.000000000 +0200 +++ new/pep8-naming-0.8.0/CHANGELOG.rst 2019-01-28 16:46:14.000000000 +0100 @@ -1,6 +1,30 @@ Changes ======= +0.8.0 - 2019-01-28 +------------------ + +* Detect N806 errors within ``for`` loops and exception handlers. + +* Improve support for non-ASCII characters. + +* Detect mixedCased variable names at class (N815) and global (N816) scope. + +* Ignore Django's ``setUpTestData`` method by default. + +* Fix column offsets for N803, N804, and N805 under Python 3. + +* Detect underscores within class names as N801 errors. + +* Don't flag ``__getattr__`` and ``__dir__`` as N807 errors. (See + `PEP 562 <https://www.python.org/dev/peps/pep-0562/>`_). + +* ``async`` function and method names are now checked. + +* Detect N806 errors in generator expressions and comprehensions. + +* Detect N81x errors in ``import x as y`` statements. + 0.7.0 - 2018-05-17 ------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/PKG-INFO new/pep8-naming-0.8.0/PKG-INFO --- old/pep8-naming-0.7.0/PKG-INFO 2018-05-17 17:31:23.000000000 +0200 +++ new/pep8-naming-0.8.0/PKG-INFO 2019-01-28 16:49:34.000000000 +0100 @@ -1,13 +1,15 @@ Metadata-Version: 1.1 Name: pep8-naming -Version: 0.7.0 +Version: 0.8.0 Summary: Check PEP-8 naming conventions, plugin for flake8 Home-page: https://github.com/PyCQA/pep8-naming Author: Florent Xicluna Author-email: florent.xicl...@gmail.com License: Expat license -Description-Content-Type: UNKNOWN -Description: PEP-8 Naming Conventions +Description: .. image:: https://travis-ci.org/PyCQA/pep8-naming.svg?branch=master + :target: https://travis-ci.org/PyCQA/pep8-naming + + PEP-8 Naming Conventions ======================== Check the PEP-8 naming conventions. @@ -66,6 +68,33 @@ +------+-------------------------------------------------------+ | N814 | camelcase imported as constant | +------+-------------------------------------------------------+ + | N815 | mixedCase variable in class scope | + +------+-------------------------------------------------------+ + | N816 | mixedCase variable in global scope | + +------+-------------------------------------------------------+ + + Options + ------- + + The following flake8 options are added: + + --ignore-names Ignore errors for specific variable names. + + Currently, this option can only be used for N802 errors (`#43 <https://github.com/PyCQA/pep8-naming/issues/43>`_). + + Default: ``setUp,tearDown,setUpClass,tearDownClass,setUpTestData``. + + --classmethod-decorators List of method decorators pep8-naming plugin should consider class method. + + Used to prevent false N804 errors. + + Default: ``classmethod``. + + --staticmethod-decorators List of method decorators pep8-naming plugin should consider static method. + + Used to prevent false N805 errors. + + Default: ``staticmethod``. Keywords: flake8 pep8 naming Platform: UNKNOWN diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/README.rst new/pep8-naming-0.8.0/README.rst --- old/pep8-naming-0.7.0/README.rst 2018-05-05 01:12:53.000000000 +0200 +++ new/pep8-naming-0.8.0/README.rst 2018-08-14 17:57:14.000000000 +0200 @@ -1,3 +1,6 @@ +.. image:: https://travis-ci.org/PyCQA/pep8-naming.svg?branch=master + :target: https://travis-ci.org/PyCQA/pep8-naming + PEP-8 Naming Conventions ======================== @@ -57,3 +60,30 @@ +------+-------------------------------------------------------+ | N814 | camelcase imported as constant | +------+-------------------------------------------------------+ +| N815 | mixedCase variable in class scope | ++------+-------------------------------------------------------+ +| N816 | mixedCase variable in global scope | ++------+-------------------------------------------------------+ + +Options +------- + +The following flake8 options are added: + +--ignore-names Ignore errors for specific variable names. + + Currently, this option can only be used for N802 errors (`#43 <https://github.com/PyCQA/pep8-naming/issues/43>`_). + + Default: ``setUp,tearDown,setUpClass,tearDownClass,setUpTestData``. + +--classmethod-decorators List of method decorators pep8-naming plugin should consider class method. + + Used to prevent false N804 errors. + + Default: ``classmethod``. + +--staticmethod-decorators List of method decorators pep8-naming plugin should consider static method. + + Used to prevent false N805 errors. + + Default: ``staticmethod``. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/run_tests.py new/pep8-naming-0.8.0/run_tests.py --- old/pep8-naming-0.7.0/run_tests.py 2018-05-05 01:34:19.000000000 +0200 +++ new/pep8-naming-0.8.0/run_tests.py 2019-01-24 19:23:43.000000000 +0100 @@ -1,5 +1,7 @@ +import io import optparse import os +import platform import re import sys @@ -8,11 +10,13 @@ PyCF_ONLY_AST = 1024 -IS_PY3 = sys.version_info[0] == 3 -IS_PY3_TEST = re.compile(r"^#\s*python3\s*only") -IS_PY2_TEST = re.compile(r"^#\s*python2\s*only") - -TESTCASE_RE = re.compile("^#: (?P<code>\w+)(\((?P<options>.+)\))?$") +TESTCASE_RE = re.compile( + r'#: ' + r'(?P<code>\w+:?\d*:?\d*)' + r'(\((?P<options>.+)\))?' + r'$' +) +EVAL_LOCALS = {'python_version': platform.python_version()[:3]} def main(): @@ -20,7 +24,8 @@ test_count = 0 errors = 0 for filename in os.listdir('testsuite'): - with open(os.path.join('testsuite', filename)) as fd: + filepath = os.path.join('testsuite', filename) + with io.open(filepath, encoding='utf8') as fd: lines = list(fd) if not is_test_allowed(lines): continue @@ -37,12 +42,9 @@ def is_test_allowed(lines): - if IS_PY3 and any(IS_PY2_TEST.search(line) for line in lines[:3]): - return False - - if not IS_PY3 and any(IS_PY3_TEST.search(line) for line in lines[:3]): - return False - + for line in lines[:3]: + if 'python_version' in line: + return eval(line[1:], {}, EVAL_LOCALS) return True @@ -84,21 +86,25 @@ def test_file(filename, lines, code, options): - tree = compile(''.join(lines), '', 'exec', PyCF_ONLY_AST) + if code is None: # Invalid test case + return 0 + source = ''.join(lines) + tree = compile(source, '', 'exec', PyCF_ONLY_AST) checker = pep8ext_naming.NamingChecker(tree, filename) parse_options(checker, options) + error_format = ( + '{0}:{lineno}:{col_offset}' if ':' in code else '{0}').format - found_errors = [] + found_errors = set() for lineno, col_offset, msg, instance in checker.run(): - found_errors.append(msg.split()[0]) + found_errors.add(error_format(msg.split()[0], **locals())) - if code is None: # Invalid test case - return 0 if not found_errors and code == 'Okay': # Expected PASS return 0 if code in found_errors: # Expected FAIL return 0 - print("ERROR: %s not in %s" % (code, filename)) + print("ERROR: %s not in %s. found_errors: %s. Source:\n%s" + % (code, filename, found_errors, source)) return 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/src/pep8_naming.egg-info/PKG-INFO new/pep8-naming-0.8.0/src/pep8_naming.egg-info/PKG-INFO --- old/pep8-naming-0.7.0/src/pep8_naming.egg-info/PKG-INFO 2018-05-17 17:31:23.000000000 +0200 +++ new/pep8-naming-0.8.0/src/pep8_naming.egg-info/PKG-INFO 2019-01-28 16:49:34.000000000 +0100 @@ -1,13 +1,15 @@ Metadata-Version: 1.1 Name: pep8-naming -Version: 0.7.0 +Version: 0.8.0 Summary: Check PEP-8 naming conventions, plugin for flake8 Home-page: https://github.com/PyCQA/pep8-naming Author: Florent Xicluna Author-email: florent.xicl...@gmail.com License: Expat license -Description-Content-Type: UNKNOWN -Description: PEP-8 Naming Conventions +Description: .. image:: https://travis-ci.org/PyCQA/pep8-naming.svg?branch=master + :target: https://travis-ci.org/PyCQA/pep8-naming + + PEP-8 Naming Conventions ======================== Check the PEP-8 naming conventions. @@ -66,6 +68,33 @@ +------+-------------------------------------------------------+ | N814 | camelcase imported as constant | +------+-------------------------------------------------------+ + | N815 | mixedCase variable in class scope | + +------+-------------------------------------------------------+ + | N816 | mixedCase variable in global scope | + +------+-------------------------------------------------------+ + + Options + ------- + + The following flake8 options are added: + + --ignore-names Ignore errors for specific variable names. + + Currently, this option can only be used for N802 errors (`#43 <https://github.com/PyCQA/pep8-naming/issues/43>`_). + + Default: ``setUp,tearDown,setUpClass,tearDownClass,setUpTestData``. + + --classmethod-decorators List of method decorators pep8-naming plugin should consider class method. + + Used to prevent false N804 errors. + + Default: ``classmethod``. + + --staticmethod-decorators List of method decorators pep8-naming plugin should consider static method. + + Used to prevent false N805 errors. + + Default: ``staticmethod``. Keywords: flake8 pep8 naming Platform: UNKNOWN diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/src/pep8_naming.egg-info/SOURCES.txt new/pep8-naming-0.8.0/src/pep8_naming.egg-info/SOURCES.txt --- old/pep8-naming-0.7.0/src/pep8_naming.egg-info/SOURCES.txt 2018-05-17 17:31:23.000000000 +0200 +++ new/pep8-naming-0.8.0/src/pep8_naming.egg-info/SOURCES.txt 2019-01-28 16:49:34.000000000 +0100 @@ -14,13 +14,27 @@ src/pep8_naming.egg-info/requires.txt src/pep8_naming.egg-info/top_level.txt testsuite/N801.py +testsuite/N801_py3.py testsuite/N802.py +testsuite/N802_py3.py +testsuite/N802_py35.py testsuite/N803.py testsuite/N803_py2.py testsuite/N803_py3.py +testsuite/N803_py35.py testsuite/N804.py +testsuite/N804_py35.py testsuite/N805.py +testsuite/N805_py35.py testsuite/N806.py testsuite/N806_py3.py +testsuite/N806_py35.py testsuite/N807.py -testsuite/N81x.py \ No newline at end of file +testsuite/N807_py3.py +testsuite/N807_py35.py +testsuite/N815.py +testsuite/N816.py +testsuite/N816_py3.py +testsuite/N816_py37.py +testsuite/N81x.py +testsuite/N81x_py3.py \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/src/pep8ext_naming.py new/pep8-naming-0.8.0/src/pep8ext_naming.py --- old/pep8-naming-0.7.0/src/pep8ext_naming.py 2018-05-17 17:29:59.000000000 +0200 +++ new/pep8-naming-0.8.0/src/pep8ext_naming.py 2019-01-28 16:46:14.000000000 +0100 @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- """Checker of PEP-8 Naming Conventions.""" -import re import sys from collections import deque +from functools import partial from flake8_polyfill import options @@ -12,18 +12,23 @@ except ImportError: from flake8.util import ast, iter_child_nodes -__version__ = '0.7.0' +__version__ = '0.8.0' -LOWERCASE_REGEX = re.compile(r'[_a-z][_a-z0-9]*$') -UPPERCASE_REGEX = re.compile(r'[_A-Z][_A-Z0-9]*$') -MIXEDCASE_REGEX = re.compile(r'_?[A-Z][a-zA-Z0-9]*$') - -PY2 = sys.version_info[0] == 2 +PYTHON_VERSION = sys.version_info[:3] +PY2 = PYTHON_VERSION[0] == 2 # Node types which may contain class methods -METHOD_CONTAINER_NODES = {ast.If, ast.While, ast.For, ast.With} | ( - {ast.TryExcept, ast.TryFinally} if PY2 else {ast.Try}) +METHOD_CONTAINER_NODES = {ast.If, ast.While, ast.For, ast.With} +FUNC_NODES = (ast.FunctionDef,) +if PY2: + METHOD_CONTAINER_NODES |= {ast.TryExcept, ast.TryFinally} +else: + METHOD_CONTAINER_NODES |= {ast.Try} + +if PYTHON_VERSION > (3, 5): + FUNC_NODES += (ast.AsyncFunctionDef,) + METHOD_CONTAINER_NODES |= {ast.AsyncWith, ast.AsyncFor} if PY2: def _unpack_args(args): @@ -32,15 +37,16 @@ if isinstance(arg, ast.Tuple): ret.extend(_unpack_args(arg.elts)) else: - ret.append(arg.id) + ret.append((arg, arg.id)) return ret - def get_arg_names(node): + def get_arg_name_tuples(node): return _unpack_args(node.args.args) else: - def get_arg_names(node): - pos_args = [arg.arg for arg in node.args.args] - kw_only = [arg.arg for arg in node.args.kwonlyargs] + def get_arg_name_tuples(node): + args = node.args + pos_args = [(arg, arg.arg) for arg in args.args] + kw_only = [(arg, arg.arg) for arg in args.kwonlyargs] return pos_args + kw_only @@ -52,18 +58,18 @@ cls._checks = [] -def _err(self, node, code, name=None): +def _err(self, node, code, **kwargs): lineno, col_offset = node.lineno, node.col_offset if isinstance(node, ast.ClassDef): lineno += len(node.decorator_list) col_offset += 6 - elif isinstance(node, ast.FunctionDef): + elif isinstance(node, FUNC_NODES): lineno += len(node.decorator_list) col_offset += 4 code_str = getattr(self, code) - if name is not None: - code_str = code_str.format(name=name) - return (lineno, col_offset, '%s %s' % (code, code_str), self) + if kwargs: + code_str = code_str.format(**kwargs) + return lineno, col_offset + 1, '%s %s' % (code, code_str), self BaseASTCheck = _ASTCheckMeta('BaseASTCheck', (object,), @@ -94,7 +100,7 @@ """Checker of PEP-8 Naming Conventions.""" name = 'naming' version = __version__ - ignore_names = ['setUp', 'tearDown', 'setUpClass', 'tearDownClass'] + ignore_names = ['setUp', 'tearDown', 'setUpClass', 'tearDownClass', 'setUpTestData'] decorator_to_type = _build_decorator_to_type( _default_classmethod_decorators, _default_staticmethod_decorators) @@ -156,7 +162,7 @@ def visit_node(self, node): if isinstance(node, ast.ClassDef): self.tag_class_functions(node) - elif isinstance(node, ast.FunctionDef): + elif isinstance(node, FUNC_NODES): self.find_global_defs(node) method = 'visit_' + node.__class__.__name__.lower() @@ -199,7 +205,7 @@ if type(node) in METHOD_CONTAINER_NODES: self.set_function_nodes_types( iter_child_nodes(node), ismetaclass, late_decoration) - if not isinstance(node, ast.FunctionDef): + if not isinstance(node, FUNC_NODES): continue node.function_type = _FunctionType.METHOD if node.name in ('__new__', '__init_subclass__') or ismetaclass: @@ -214,7 +220,8 @@ if names: node.function_type = names[0] - def find_global_defs(self, func_def_node): + @staticmethod + def find_global_defs(func_def_node): global_names = set() nodes_to_check = deque(iter_child_nodes(func_def_node)) while nodes_to_check: @@ -222,7 +229,7 @@ if isinstance(node, ast.Global): global_names.update(node.names) - if not isinstance(node, (ast.FunctionDef, ast.ClassDef)): + if not isinstance(node, (ast.ClassDef,) + FUNC_NODES): nodes_to_check.extend(iter_child_nodes(node)) func_def_node.global_names = global_names @@ -233,14 +240,15 @@ Classes for internal use have a leading underscore in addition. """ - check = MIXEDCASE_REGEX.match N801 = "class name '{name}' should use CapWords convention" def visit_classdef(self, node, parents, ignore=None): - if ignore and node.name in ignore: + name = node.name + if ignore and name in ignore: return - if not self.check(node.name): - yield self.err(node, 'N801', node.name) + name = name.strip('_') + if not name[:1].isupper() or '_' in name: + yield self.err(node, 'N801', name=name) class FunctionNameCheck(BaseASTCheck): @@ -253,7 +261,6 @@ mixedCase is allowed only in contexts where that's already the prevailing style (e.g. threading.py), to retain backwards compatibility. """ - check = LOWERCASE_REGEX.match N802 = "function name '{name}' should be lowercase" N807 = "function name '{name}' should not start or end with '__'" @@ -262,10 +269,14 @@ name = node.name if ignore and name in ignore: return - if not self.check(name): - yield self.err(node, 'N802', name) + if name in ('__dir__', '__getattr__'): + return + if not name.islower() and name != '_': + yield self.err(node, 'N802', name=name) if function_type == 'function' and '__' in (name[:2], name[-2:]): - yield self.err(node, 'N807', name) + yield self.err(node, 'N807', name=name) + + visit_asyncfunctiondef = visit_functiondef class FunctionArgNamesCheck(BaseASTCheck): @@ -276,7 +287,6 @@ A classmethod should have 'cls' as first argument. A method should have 'self' as first argument. """ - check = LOWERCASE_REGEX.match N803 = "argument name '{name}' should be lowercase" N804 = "first argument of a classmethod should be named 'cls'" N805 = "first argument of a method should be named 'self'" @@ -284,85 +294,90 @@ def visit_functiondef(self, node, parents, ignore=None): def arg_name(arg): - return getattr(arg, 'arg', arg) - - kwarg = arg_name(node.args.kwarg) - if kwarg is not None: - if not self.check(kwarg): - yield self.err(node, 'N803', kwarg) - return + try: + return arg, arg.arg + except AttributeError: # PY2 + return node, arg + + for arg, name in arg_name(node.args.vararg), arg_name(node.args.kwarg): + if name is not None: + if not name.islower(): + yield self.err(arg, 'N803', name=name) + return - vararg = arg_name(node.args.vararg) - if vararg is not None: - if not self.check(vararg): - yield self.err(node, 'N803', vararg) - return - arg_names = get_arg_names(node) - if not arg_names: + arg_name_tuples = get_arg_name_tuples(node) + if not arg_name_tuples: return + arg0, name0 = arg_name_tuples[0] function_type = getattr(node, 'function_type', 'function') if function_type == _FunctionType.METHOD: - if arg_names[0] != 'self': - yield self.err(node, 'N805') + if name0 != 'self': + yield self.err(arg0, 'N805') elif function_type == _FunctionType.CLASSMETHOD: - if arg_names[0] != 'cls': - yield self.err(node, 'N804') - for arg in arg_names: - if not self.check(arg): - yield self.err(node, 'N803', arg) + if name0 != 'cls': + yield self.err(arg0, 'N804') + for arg, name in arg_name_tuples: + if not name.islower(): + yield self.err(arg, 'N803', name=name) return + visit_asyncfunctiondef = visit_functiondef + class ImportAsCheck(BaseASTCheck): """ Don't change the naming convention via an import """ - check_lower = LOWERCASE_REGEX.match - check_upper = UPPERCASE_REGEX.match - N811 = "constant '{name}' imported as non constant" - N812 = "lowercase '{name}' imported as non lowercase" - N813 = "camelcase '{name}' imported as lowercase" - N814 = "camelcase '{name}' imported as constant" + N811 = "constant '{name}' imported as non constant '{asname}'" + N812 = "lowercase '{name}' imported as non lowercase '{asname}'" + N813 = "camelcase '{name}' imported as lowercase '{asname}'" + N814 = "camelcase '{name}' imported as constant '{asname}'" def visit_importfrom(self, node, parents, ignore=None): for name in node.names: - if not name.asname: + asname = name.asname + if not asname: continue - if self.check_upper(name.name): - if not self.check_upper(name.asname): - yield self.err(node, 'N811', name.asname) - elif self.check_lower(name.name): - if not self.check_lower(name.asname): - yield self.err(node, 'N812', name.asname) - elif self.check_lower(name.asname): - yield self.err(node, 'N813', name.asname) - elif self.check_upper(name.asname): - yield self.err(node, 'N814', name.asname) + original_name = name.name + err_kwargs = {'name': original_name, 'asname': asname} + if original_name.isupper(): + if not asname.isupper(): + yield self.err(node, 'N811', **err_kwargs) + elif original_name.islower(): + if not asname.islower(): + yield self.err(node, 'N812', **err_kwargs) + elif asname.islower(): + yield self.err(node, 'N813', **err_kwargs) + elif asname.isupper(): + yield self.err(node, 'N814', **err_kwargs) + + visit_import = visit_importfrom -class VariablesInFunctionCheck(BaseASTCheck): +class VariablesCheck(BaseASTCheck): """ Local variables in functions should be lowercase """ - check = LOWERCASE_REGEX.match N806 = "variable '{name}' in function should be lowercase" + N815 = "variable '{name}' in class scope should not be mixedCase" + N816 = "variable '{name}' in global scope should not be mixedCase" def _find_errors(self, assignment_target, parents): for parent_func in reversed(parents): if isinstance(parent_func, ast.ClassDef): - return - if isinstance(parent_func, ast.FunctionDef): + checker = self.class_variable_check + break + if isinstance(parent_func, FUNC_NODES): + checker = partial(self.function_variable_check, parent_func) break else: - return + checker = self.global_variable_check for name in _extract_names(assignment_target): - if name in parent_func.global_names: - continue - if self.check(name) or name[:1] == '_': - continue - yield self.err(assignment_target, 'N806', name) + error_code = checker(name) + if error_code: + yield self.err(assignment_target, error_code, name=name) def visit_assign(self, node, parents, ignore=None): if isinstance(node.value, ast.Call): @@ -385,6 +400,44 @@ for error in self._find_errors(item.optional_vars, parents): yield error + visit_asyncwith = visit_with + + def visit_for(self, node, parents, ignore): + for error in self._find_errors(node.target, parents): + yield error + + visit_asyncfor = visit_for + + def visit_excepthandler(self, node, parents, ignore): + if node.name: + for error in self._find_errors(node, parents): + yield error + + def visit_generatorexp(self, node, parents, ignore): + for gen in node.generators: + for error in self._find_errors(gen.target, parents): + yield error + + visit_listcomp = visit_dictcomp = visit_setcomp = visit_generatorexp + + @staticmethod + def global_variable_check(name): + if is_mixed_case(name): + return 'N816' + + @staticmethod + def class_variable_check(name): + if is_mixed_case(name): + return 'N815' + + @staticmethod + def function_variable_check(func, var_name): + if var_name in func.global_names: + return None + if var_name.islower() or var_name == '_': + return None + return 'N806' + def _extract_names(assignment_target): """Yield assignment_target ids.""" @@ -403,3 +456,14 @@ elif not PY2 and element_type is ast.Starred: # PEP 3132 for n in _extract_names(element.value): yield n + return + if target_type is ast.ExceptHandler: + if PY2: + yield assignment_target.name.id + else: + yield assignment_target.name + return + + +def is_mixed_case(name): + return name.lower() != name and name.lstrip('_')[:1].islower() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N801.py new/pep8-naming-0.8.0/testsuite/N801.py --- old/pep8-naming-0.7.0/testsuite/N801.py 2017-01-19 15:23:08.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N801.py 2018-08-14 17:57:14.000000000 +0200 @@ -9,3 +9,40 @@ #: Okay class VeryGood(object): pass +#: N801:1:7 +class _: + pass +#: N801:1:7 +class BAD_NAME: + pass +#: Okay +class Fine_: + pass +#: Okay +class Fine__: + pass +#: Okay +class G_: + pass +#: N801:1:7 +class Not_Good: + pass +#: Okay +class __Fine: + pass +# The following cases are currently OK, but perhaps could be errors. +#: Okay +class MEHHHH: + pass +#: Okay +class __Meh__: + pass +#: Okay +class __MEH: + pass +#: Okay +class MEH__: + pass +#: Okay +class __MEH__: + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N801_py3.py new/pep8-naming-0.8.0/testsuite/N801_py3.py --- old/pep8-naming-0.7.0/testsuite/N801_py3.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N801_py3.py 2019-01-24 19:23:43.000000000 +0100 @@ -0,0 +1,19 @@ +# python_version >= '3' +#: Okay +class Γ: + pass +#: Okay +class ΓγΓγ: + pass +#: Okay +class ΓγΓ6: + pass +#: Okay +class _Γ: + pass +#: N801:1:7 +class γ: + pass +#: N801 +class _γ: + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N802.py new/pep8-naming-0.8.0/testsuite/N802.py --- old/pep8-naming-0.7.0/testsuite/N802.py 2018-05-05 01:12:53.000000000 +0200 +++ new/pep8-naming-0.8.0/testsuite/N802.py 2018-08-14 17:57:14.000000000 +0200 @@ -16,7 +16,7 @@ #: Okay def _go_od_(): pass -#: N802 +#: N802:1:5 def NotOK(): pass #: Okay @@ -56,3 +56,5 @@ pass def tearDownClass(self): pass + def setUpTestData(self): + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N802_py3.py new/pep8-naming-0.8.0/testsuite/N802_py3.py --- old/pep8-naming-0.7.0/testsuite/N802_py3.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N802_py3.py 2019-01-24 19:23:43.000000000 +0100 @@ -0,0 +1,7 @@ +# python_version >= '3' +#: Okay +def γ(x): + pass +#: Okay +def γ6(x): + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N802_py35.py new/pep8-naming-0.8.0/testsuite/N802_py35.py --- old/pep8-naming-0.7.0/testsuite/N802_py35.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N802_py35.py 2019-01-24 19:23:43.000000000 +0100 @@ -0,0 +1,9 @@ +# python_version >= '3.5' +#: Okay +async def func(param1, param2): + do_stuff() + await some_coroutine() +#: N802 +async def Func(param1, param2): + do_stuff() + await some_coroutine() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N803.py new/pep8-naming-0.8.0/testsuite/N803.py --- old/pep8-naming-0.7.0/testsuite/N803.py 2017-01-19 15:23:08.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N803.py 2018-08-14 17:57:14.000000000 +0200 @@ -37,10 +37,10 @@ #: N803 def b13(BAD, *VERYBAD, **EXTRABAD): pass -#: N803 +#: N803:1:9 def b14(BAD): pass -#: N803 +#: N803:2:24 class Test(object): def __init__(self, BAD): pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N803_py2.py new/pep8-naming-0.8.0/testsuite/N803_py2.py --- old/pep8-naming-0.7.0/testsuite/N803_py2.py 2017-01-19 15:23:08.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N803_py2.py 2019-01-24 19:23:43.000000000 +0100 @@ -1,4 +1,4 @@ -# python2 only +# python_version < '3' #: Okay def test(a, b, (good, verygood)): pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N803_py3.py new/pep8-naming-0.8.0/testsuite/N803_py3.py --- old/pep8-naming-0.7.0/testsuite/N803_py3.py 2017-01-19 15:23:08.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N803_py3.py 2019-01-24 19:23:43.000000000 +0100 @@ -1,4 +1,4 @@ -# python3 only +# python_version >= '3' #: Okay def compare(a, b, *, key=None): pass @@ -11,3 +11,21 @@ #: N803 def compare(a, b, *ok, fine=None, **BAD): pass +#: Okay +def foo(α, ß, γ): + pass +#: Okay +def foo(α, ß=''): + pass +#: Okay +def foo(**κ): + pass +#: Okay +def foo(*α): + pass +#: Okay +def foo(**κ2): + pass +#: Okay +def foo(*α2): + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N803_py35.py new/pep8-naming-0.8.0/testsuite/N803_py35.py --- old/pep8-naming-0.7.0/testsuite/N803_py35.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N803_py35.py 2019-01-24 19:23:43.000000000 +0100 @@ -0,0 +1,7 @@ +# python_version >= '3.5' +#: Okay +async def compare(a, b, *, key=None): + pass +#: N803 +async def compare(a, b, *, BAD=None): + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N804.py new/pep8-naming-0.8.0/testsuite/N804.py --- old/pep8-naming-0.7.0/testsuite/N804.py 2018-05-06 13:50:37.000000000 +0200 +++ new/pep8-naming-0.8.0/testsuite/N804.py 2018-08-14 17:57:14.000000000 +0200 @@ -1,4 +1,4 @@ -#: N804 +#: N804:7:13 class Foo(object): @classmethod def mmm(cls, ads): @@ -14,7 +14,7 @@ def __init_subclass(self, ads): pass -#: N804(--classmethod-decorators=clazzy,cool) +#: N804:3:14(--classmethod-decorators=clazzy,cool) class NewClassIsRequired(object): @cool def test(self, sy): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N804_py35.py new/pep8-naming-0.8.0/testsuite/N804_py35.py --- old/pep8-naming-0.7.0/testsuite/N804_py35.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N804_py35.py 2019-01-24 19:23:43.000000000 +0100 @@ -0,0 +1,37 @@ +# python_version >= '3.5' +#: N804:7:19 +class Foo(object): + @classmethod + async def mmm(cls, ads): + pass + + @classmethod + async def bad(self, ads): + pass + + @calling() + async def test(self, ads): + pass + + async def __init_subclass(self, ads): + pass +#: N804:3:20(--classmethod-decorators=clazzy,cool) +class NewClassIsRequired(object): + @cool + async def test(self, sy): + pass +#: N804 +class Meta(type): + async def __new__(self, name, bases, attrs): + pass +#: Okay +class MetaMethod(type): + async def test(cls): + pass +#: Okay +class NotMeta(object): + otherclass = Foo +class AttributeParent(NotMeta.otherclass): + pass +class CallParent(type('_tmp', (), {})): + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N805.py new/pep8-naming-0.8.0/testsuite/N805.py --- old/pep8-naming-0.7.0/testsuite/N805.py 2018-05-05 01:12:53.000000000 +0200 +++ new/pep8-naming-0.8.0/testsuite/N805.py 2018-08-14 17:57:14.000000000 +0200 @@ -1,3 +1,13 @@ +#: Okay +class C: + def __init__(*args, **kwargs): + pass +#: N805:4:11 +class C: + @decorator( + 'a') + def m(cls, k='w'): # noqa: N805 + pass #: N805 class Foo(object): def good(self, ads): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N805_py35.py new/pep8-naming-0.8.0/testsuite/N805_py35.py --- old/pep8-naming-0.7.0/testsuite/N805_py35.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N805_py35.py 2019-01-24 19:23:43.000000000 +0100 @@ -0,0 +1,16 @@ +# python_version >= '3.5' +#: Okay +class C: + async def __init__(*args, **kwargs): + pass +#: N805:4:17 +class C: + @decorator( + 'a') + async def m(cls, k='w'): # noqa: N805 + pass +#: N805(--staticmethod-decorators=exstatik,stcmthd) +class ButWeLostTheOriginalStaticMethodLateDecorator(object): + async def test(so, exciting): + pass + test = staticmethod(test) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N806.py new/pep8-naming-0.8.0/testsuite/N806.py --- old/pep8-naming-0.7.0/testsuite/N806.py 2018-05-17 17:27:10.000000000 +0200 +++ new/pep8-naming-0.8.0/testsuite/N806.py 2019-01-24 19:23:43.000000000 +0100 @@ -100,3 +100,69 @@ def f(): with C() as (a, b, baD): pass +#: Okay +def f(): + for i in iterator: + pass +#: N806:2:9 +def f(): + for Bad in iterator: + pass +#: Okay +def f(): + for a, b in enumerate(iterator): + pass +#: N806 +def f(): + for index, ITEM in enumerate(iterator): + pass +#: N806 +def f(): + try: + f() + except Exception as Bad: + pass +#: Okay +def f(): + try: + f() + except Exception as good: + pass +#: Okay +def f(): + try: + f() + except: + pass +#: Okay +def f(): + try: + f() + except good: + pass +#: N806 +def f(): + try: + f() + except RuntimeError as good: + pass + except IndexError as BAD: + pass +#: Okay +def f(): + return [i for i in range(3)] +#: N806:2:22 +def t(): + return [ITEM for ITEM in range(3)] +#: N806:2:24 +def d(): + return {AA: BB for AA, BB in {}} +#: N806:2:22 +def s(): + return {Item for Item in range(3)} +#: N806:2:57 +def n(): + return (good + BAD for good in range(3) if good for BAD in range(3) if BAD) +#: N806:2:26 +def e(): + return tuple(BaD for BaD in range(2)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N806_py3.py new/pep8-naming-0.8.0/testsuite/N806_py3.py --- old/pep8-naming-0.7.0/testsuite/N806_py3.py 2018-05-17 17:27:10.000000000 +0200 +++ new/pep8-naming-0.8.0/testsuite/N806_py3.py 2019-01-24 19:23:43.000000000 +0100 @@ -1,7 +1,9 @@ -# python3 only +# python_version >= '3' #: Okay VAR1, *VAR2, VAR3 = 1, 2, 3 #: Okay +Α, *Β, Γ = 1, 2, 3 +#: Okay [VAR1, *VAR2, VAR3] = (1, 2, 3) #: N806 def extended_unpacking_not_ok(): @@ -15,3 +17,20 @@ #: N806 def assing_to_unpack_not_ok(): a, *[bB] = 1, 2 +#: Okay +Γ = 1 +#: N806 +def f(): + Δ = 1 +#: N806 +def f(): + _Δ = 1 +#: Okay +def f(): + γ = 1 +#: Okay +def f(): + _γ = 1 +#: Okay +def f(): + h, _, γ = s.partition('sep') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N806_py35.py new/pep8-naming-0.8.0/testsuite/N806_py35.py --- old/pep8-naming-0.7.0/testsuite/N806_py35.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N806_py35.py 2019-01-24 19:23:43.000000000 +0100 @@ -0,0 +1,8 @@ +# python_version >= '3.5' +#: Okay +async def test(): + good = 1 +#: N806 +async def f(): + async with expr as ASYNC_VAR: + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N807.py new/pep8-naming-0.8.0/testsuite/N807.py --- old/pep8-naming-0.7.0/testsuite/N807.py 2018-05-14 15:32:13.000000000 +0200 +++ new/pep8-naming-0.8.0/testsuite/N807.py 2018-09-07 17:05:25.000000000 +0200 @@ -24,7 +24,7 @@ #: N807 def __bad(): pass -#: N807 +#: N807:1:5 def bad__(): pass #: N807 @@ -35,3 +35,9 @@ def method(self): def __bad(): pass +#: Okay +def __dir__(): + pass +#: Okay +def __getattr__(name): + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N807_py3.py new/pep8-naming-0.8.0/testsuite/N807_py3.py --- old/pep8-naming-0.7.0/testsuite/N807_py3.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N807_py3.py 2019-01-24 19:23:43.000000000 +0100 @@ -0,0 +1,15 @@ +# python_version >= '3' +#: Okay +class C: + def γ(self): + pass +#: N807 +def __β(self): + pass +#: N807 +def __β6(self): + pass +#: Okay +class C: + def γ1(self): + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N807_py35.py new/pep8-naming-0.8.0/testsuite/N807_py35.py --- old/pep8-naming-0.7.0/testsuite/N807_py35.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N807_py35.py 2019-01-24 19:23:43.000000000 +0100 @@ -0,0 +1,8 @@ +# python_version >= '3.5' +#: Okay +class C: + async def γ(self): + pass +#: N807 +async def __β(self): + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N815.py new/pep8-naming-0.8.0/testsuite/N815.py --- old/pep8-naming-0.7.0/testsuite/N815.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N815.py 2018-08-14 17:57:14.000000000 +0200 @@ -0,0 +1,18 @@ +#: Okay +class C: + a = 0 +#: Okay +class C: + lowercase = 0 +#: Okay +class C: + v1 = 0 +#: Okay +class C: + _1 = 0 +#: N815:2:5 +class C: + mixedCase = 0 +#: N815 +class C: + mixed_Case = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N816.py new/pep8-naming-0.8.0/testsuite/N816.py --- old/pep8-naming-0.7.0/testsuite/N816.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N816.py 2018-08-14 17:57:14.000000000 +0200 @@ -0,0 +1,20 @@ +#: Okay +GLOBAL_UPPER_CASE = 0 +#: N816 +mixedCase = 0 +#: N816:1:1 +mixed_Case = 0 +#: Okay +_C = 0 +#: Okay +__D = 0 +#: N816 +__mC = 0 +#: N816 +__mC__ = 0 +#: Okay +__C6__ = 0 +#: Okay +C6 = 0 +#: Okay +C_6 = 0. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N816_py3.py new/pep8-naming-0.8.0/testsuite/N816_py3.py --- old/pep8-naming-0.7.0/testsuite/N816_py3.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N816_py3.py 2019-01-24 19:23:43.000000000 +0100 @@ -0,0 +1,17 @@ +# python_version >= '3' +#: Okay +Γ = 1 +#: N816 +γΓ = 1 +#: Okay +Γ1 = 1 +#: Okay +Γ_ = 1 +#: Okay +Γ_1 = 1 +#: Okay +Γ1_ = 1 +#: N816 +γΓ1 = 1 +#: N816 +_γ1Γ = 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N816_py37.py new/pep8-naming-0.8.0/testsuite/N816_py37.py --- old/pep8-naming-0.7.0/testsuite/N816_py37.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N816_py37.py 2019-01-24 19:23:43.000000000 +0100 @@ -0,0 +1,13 @@ +# python_version >= '3.7' +#: Okay +async with expr as Γ: + pass +#: N816 +async with expr as γΓ: + pass +#: Okay +async for Γ1 in iterator: + pass +#: N816 +async for γΓ1 in iterator: + pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N81x.py new/pep8-naming-0.8.0/testsuite/N81x.py --- old/pep8-naming-0.7.0/testsuite/N81x.py 2017-01-19 15:23:08.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N81x.py 2019-01-24 19:23:43.000000000 +0100 @@ -1,12 +1,16 @@ +#: N812:1:1 +import os as OS +#: Okay +import os as myos #: Okay import good as good #: Okay from mod import good as nice, NICE as GOOD, Camel as Memel -#: N811 +#: N811:1:1 from mod import GOOD as bad -#: N812 +#: N812:1:1 from mod import good as Bad -#: N813 +#: N813:1:1 from mod import CamelCase as noncamle -#: N814 +#: N814:1:1 from mod import CamelCase as CONSTANT diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pep8-naming-0.7.0/testsuite/N81x_py3.py new/pep8-naming-0.8.0/testsuite/N81x_py3.py --- old/pep8-naming-0.7.0/testsuite/N81x_py3.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pep8-naming-0.8.0/testsuite/N81x_py3.py 2019-01-24 19:23:43.000000000 +0100 @@ -0,0 +1,11 @@ +# python_version >= '3' +#: Okay +import good as γ +#: Okay +from mod import good as γ +#: Okay +import GOOD as Γ +#: Okay +from mod import GOOD as Γ +#: Okay +from mod import GOOD as Γ1