10
10
The following checkers are intended to make users are aware of these issues.
11
11
"""
12
12
13
- import re
14
13
import sys
15
14
from typing import Optional , Union
16
15
17
16
from astroid import nodes
18
17
19
- import pylint .checkers .base
20
- import pylint .checkers .utils
21
- from pylint import interfaces
22
- from pylint .constants import HUMAN_READABLE_TYPES
23
- from pylint .lint import PyLinter
24
-
25
- if sys .version_info >= (3 , 8 ):
26
- from typing import Protocol
27
- else :
28
- from typing_extensions import Protocol
29
-
18
+ from pylint import constants , interfaces , lint
19
+ from pylint .checkers import base_checker , utils
30
20
31
21
if sys .version_info [:2 ] >= (3 , 7 ):
32
22
# pylint: disable-next=fixme
@@ -40,13 +30,7 @@ def isascii(self: str) -> bool:
40
30
return all ("\u0000 " <= x <= "\u007F " for x in self )
41
31
42
32
43
- class _AsciiOnlyCheckedNode (Protocol ):
44
- _is_ascii_only : bool
45
-
46
-
47
- class NonAsciiNamesChecker (
48
- pylint .checkers .BaseChecker , pylint .checkers .base .NameCheckerHelper
49
- ):
33
+ class NonAsciiNameChecker (base_checker ._NameCheckerBase ):
50
34
"""A strict name checker only allowing ASCII
51
35
52
36
If your programming guideline defines that you are programming in English,
@@ -101,36 +85,12 @@ class NonAsciiNamesChecker(
101
85
102
86
name = "NonASCII-Checker"
103
87
104
- def __init__ (self , linter : PyLinter ) -> None :
105
- super ().__init__ (linter )
106
- self ._non_ascii_rgx_compiled = re .compile ("[^A-Za-z0-9_]" )
107
-
108
- def _raise_name_warning (
109
- self ,
110
- node : nodes .NodeNG ,
111
- node_type : str ,
112
- name : str ,
113
- ) -> None :
114
- type_label = HUMAN_READABLE_TYPES .get (node_type , node_type )
115
- args = (type_label .capitalize (), name )
116
-
117
- msg = "non-ascii-name"
118
-
119
- # Some node types have customized messages
120
- if node_type == "file" :
121
- msg = "non-ascii-file-name"
122
- elif node_type == "module" :
123
- msg = "non-ascii-module-import"
124
-
125
- self .add_message (msg , node = node , args = args , confidence = interfaces .HIGH )
126
-
127
- # pylint: disable-next=arguments-renamed
128
88
def _check_name (
129
89
self ,
130
90
node_type : str ,
131
- name : str ,
132
- node : Union [ nodes .NodeNG , _AsciiOnlyCheckedNode ] ,
133
- check_string : Optional [ str ] = None ,
91
+ name : Optional [ str ] ,
92
+ node : nodes .NodeNG ,
93
+ confidence = interfaces . HIGH ,
134
94
) -> None :
135
95
"""Check whether a name is using non-ASCII characters.
136
96
@@ -139,31 +99,29 @@ def _check_name(
139
99
too many edge cases.
140
100
"""
141
101
142
- current_state = getattr (node , "_is_ascii_only" , True )
143
-
144
102
if name is None :
145
103
# For some nodes i.e. *kwargs from a dict, the name will be empty
146
104
return
147
105
148
- if check_string is None :
149
- check_string = name
106
+ if not (Py37Str (name ).isascii ()):
107
+ type_label = constants .HUMAN_READABLE_TYPES .get (node_type , node_type )
108
+ args = (type_label .capitalize (), name )
109
+
110
+ msg = "non-ascii-name"
150
111
151
- if not (
152
- Py37Str (check_string ).isascii ()
153
- and self ._non_ascii_rgx_compiled .match (check_string ) is None
154
- ):
155
- # Note that we require the `.isascii` method as it is fast and
156
- # handles the complexities of unicode, so we can use simple regex.
157
- self ._raise_name_warning (node , node_type , name )
158
- current_state = False
112
+ # Some node types have customized messages
113
+ if node_type == "file" :
114
+ msg = "non-ascii-file-name"
115
+ elif node_type == "module" :
116
+ msg = "non-ascii-module-import"
159
117
160
- node . _is_ascii_only = current_state # pylint: disable=protected-access
118
+ self . add_message ( msg , node = node , args = args , confidence = confidence )
161
119
162
- @pylint . checkers . utils .check_messages ("non-ascii-name" )
120
+ @utils .check_messages ("non-ascii-name" )
163
121
def visit_module (self , node : nodes .Module ) -> None :
164
122
self ._check_name ("file" , node .name .split ("." )[- 1 ], node )
165
123
166
- @pylint . checkers . utils .check_messages ("non-ascii-name" )
124
+ @utils .check_messages ("non-ascii-name" )
167
125
def visit_functiondef (
168
126
self , node : Union [nodes .FunctionDef , nodes .AsyncFunctionDef ]
169
127
) -> None :
@@ -189,76 +147,62 @@ def visit_functiondef(
189
147
190
148
visit_asyncfunctiondef = visit_functiondef
191
149
192
- @pylint . checkers . utils .check_messages ("non-ascii-name" )
150
+ @utils .check_messages ("non-ascii-name" )
193
151
def visit_global (self , node : nodes .Global ) -> None :
194
152
for name in node .names :
195
153
self ._check_name ("const" , name , node )
196
154
197
- @pylint . checkers . utils .check_messages ("non-ascii-name" )
155
+ @utils .check_messages ("non-ascii-name" )
198
156
def visit_assignname (self , node : nodes .AssignName ) -> None :
199
157
"""check module level assigned names"""
200
158
# The NameChecker from which this Checker originates knows a lot of different
201
159
# versions of variables, i.e. constants, inline variables etc.
202
160
# To simplify we use only `variable` here, as we don't need to apply different
203
161
# rules to different types of variables.
204
162
frame = node .frame ()
205
- assign_type = node .assign_type ()
206
- if isinstance (assign_type , nodes .Comprehension ):
207
- # called inlinevar in NamesChecker
208
- self ._check_name ("variable" , node .name , node )
209
- elif isinstance (frame , nodes .Module ):
210
- self ._check_name ("variable" , node .name , node )
211
- elif isinstance (frame , nodes .FunctionDef ):
212
- if not hasattr (node , "_is_ascii_only" ):
213
- # only check if not already done
163
+
164
+ if isinstance (frame , nodes .FunctionDef ):
165
+ if node .parent in frame .body :
166
+ # Only perform the check if the assigment was done in within the body
167
+ # of the function (and not the function parameter definition
168
+ # (will be handled in visit_functiondef)
169
+ # or within a decorator (handled in visit_call)
214
170
self ._check_name ("variable" , node .name , node )
215
171
elif isinstance (frame , nodes .ClassDef ):
216
172
self ._check_name ("attr" , node .name , node )
217
173
else :
218
- # Just to make sure we check EVERYTHING (!)
174
+ # Possibilities here:
175
+ # - isinstance(node.assign_type(), nodes.Comprehension) == inlinevar
176
+ # - isinstance(frame, nodes.Module) == variable (constant?)
177
+ # - some other kind of assigment missed but still most likely a variable
219
178
self ._check_name ("variable" , node .name , node )
220
179
221
- @pylint . checkers . utils .check_messages ("non-ascii-name" )
180
+ @utils .check_messages ("non-ascii-name" )
222
181
def visit_classdef (self , node : nodes .ClassDef ) -> None :
223
182
self ._check_name ("class" , node .name , node )
224
183
for attr , anodes in node .instance_attrs .items ():
225
184
if not any (node .instance_attr_ancestors (attr )):
226
185
self ._check_name ("attr" , attr , anodes [0 ])
227
186
228
- def _check_module_import (
229
- self , node : Union [nodes .ImportFrom , nodes .Import ], is_import_from : bool = False
230
- ):
187
+ def _check_module_import (self , node : Union [nodes .ImportFrom , nodes .Import ]):
231
188
for module_name , alias in node .names :
232
- if alias :
233
- name = alias
234
- else :
235
- if is_import_from and module_name == "*" :
236
- # Ignore ``from xyz import *``
237
- continue
238
- name = module_name
239
-
240
- if is_import_from or alias :
241
- self ._check_name ("module" , name , node )
242
- else :
243
- # Normal module import can contain "." for which we don't want to check
244
- self ._check_name (
245
- "module" , name , node , check_string = name .replace ("." , "" )
246
- )
247
-
248
- @pylint .checkers .utils .check_messages ("non-ascii-name" )
189
+ name = alias or module_name
190
+ self ._check_name ("module" , name , node )
191
+
192
+ @utils .check_messages ("non-ascii-name" )
249
193
def visit_import (self , node : nodes .Import ) -> None :
250
194
self ._check_module_import (node )
251
195
252
- @pylint . checkers . utils .check_messages ("non-ascii-name" )
196
+ @utils .check_messages ("non-ascii-name" )
253
197
def visit_importfrom (self , node : nodes .ImportFrom ) -> None :
254
- self ._check_module_import (node , is_import_from = True )
198
+ self ._check_module_import (node )
255
199
256
- @pylint . checkers . utils .check_messages ("non-ascii-name" )
200
+ @utils .check_messages ("non-ascii-name" )
257
201
def visit_call (self , node : nodes .Call ) -> None :
258
202
# lets check if the used keyword args are correct
259
203
for keyword in node .keywords :
260
204
self ._check_name ("argument" , keyword .arg , keyword )
261
205
262
206
263
- def register (linter : PyLinter ) -> None :
264
- linter .register_checker (NonAsciiNamesChecker (linter ))
207
+ def register (linter : lint . PyLinter ) -> None :
208
+ linter .register_checker (NonAsciiNameChecker (linter ))
0 commit comments