16
16
import hashlib
17
17
import json
18
18
import os .path
19
+ import re
19
20
import sys
20
21
import time
21
22
from os .path import dirname , basename
@@ -343,23 +344,29 @@ def load_custom_plugins(default_plugin: Plugin, options: Options, errors: Errors
343
344
back to default_plugin.
344
345
"""
345
346
347
+ if not options .config_file :
348
+ return default_plugin
349
+
350
+ line = find_config_file_line_number (options .config_file , 'mypy' , 'plugins' )
351
+ if line == - 1 :
352
+ line = 1 # We need to pick some line number that doesn't look too confusing
353
+
346
354
def plugin_error (message : str ) -> None :
347
- errors .report (0 , 0 , message )
355
+ errors .report (line , 0 , message )
348
356
errors .raise_error ()
349
357
358
+ errors .set_file (options .config_file , None )
350
359
custom_plugins = []
351
360
for plugin_path in options .plugins :
352
- if options .config_file :
353
- # Plugin paths are relative to the config file location.
354
- plugin_path = os .path .join (os .path .dirname (options .config_file ), plugin_path )
355
- errors .set_file (plugin_path , None )
361
+ # Plugin paths are relative to the config file location.
362
+ plugin_path = os .path .join (os .path .dirname (options .config_file ), plugin_path )
356
363
357
364
if not os .path .isfile (plugin_path ):
358
- plugin_error ("Can't find plugin" )
365
+ plugin_error ("Can't find plugin '{}'" . format ( plugin_path ) )
359
366
plugin_dir = os .path .dirname (plugin_path )
360
367
fnam = os .path .basename (plugin_path )
361
368
if not fnam .endswith ('.py' ):
362
- plugin_error ("Plugin must have .py extension" )
369
+ plugin_error ("Plugin '{}' does not have a .py extension" . format ( fnam ) )
363
370
module_name = fnam [:- 3 ]
364
371
import importlib
365
372
sys .path .insert (0 , plugin_dir )
@@ -372,19 +379,21 @@ def plugin_error(message: str) -> None:
372
379
assert sys .path [0 ] == plugin_dir
373
380
del sys .path [0 ]
374
381
if not hasattr (m , 'plugin' ):
375
- plugin_error ('Plugin does not define entry point function "plugin"' )
382
+ plugin_error ('Plugin \' {}\' does not define entry point function "plugin"' .format (
383
+ plugin_path ))
376
384
try :
377
385
plugin_type = getattr (m , 'plugin' )(__version__ )
378
386
except Exception :
379
387
print ('Error calling the plugin(version) entry point of {}\n ' .format (plugin_path ))
380
388
raise # Propagate to display traceback
381
389
if not isinstance (plugin_type , type ):
382
390
plugin_error (
383
- 'Type object expected as the return value of "plugin" ( got {!r})' .format (
384
- plugin_type ))
391
+ 'Type object expected as the return value of "plugin"; got {!r} (in { })' .format (
392
+ plugin_type , plugin_path ))
385
393
if not issubclass (plugin_type , Plugin ):
386
394
plugin_error (
387
- 'Return value of "plugin" must be a subclass of "mypy.plugin.Plugin"' )
395
+ 'Return value of "plugin" must be a subclass of "mypy.plugin.Plugin" '
396
+ '(in {})' .format (plugin_path ))
388
397
try :
389
398
custom_plugins .append (plugin_type (options .python_version ))
390
399
except Exception :
@@ -397,6 +406,29 @@ def plugin_error(message: str) -> None:
397
406
return ChainedPlugin (options .python_version , custom_plugins + [default_plugin ])
398
407
399
408
409
+ def find_config_file_line_number (path : str , section : str , setting_name : str ) -> int :
410
+ """Return the approximate location of setting_name within mypy config file.
411
+
412
+ Return -1 if can't determine the line unambiguously.
413
+ """
414
+ in_desired_section = False
415
+ try :
416
+ results = []
417
+ with open (path ) as f :
418
+ for i , line in enumerate (f ):
419
+ line = line .strip ()
420
+ if line .startswith ('[' ) and line .endswith (']' ):
421
+ current_section = line [1 :- 1 ].strip ()
422
+ in_desired_section = (current_section == section )
423
+ elif in_desired_section and re .match (r'{}\s*=' .format (setting_name ), line ):
424
+ results .append (i + 1 )
425
+ if len (results ) == 1 :
426
+ return results [0 ]
427
+ except OSError :
428
+ pass
429
+ return - 1
430
+
431
+
400
432
# TODO: Get rid of all_types. It's not used except for one log message.
401
433
# Maybe we could instead publish a map from module ID to its type_map.
402
434
class BuildManager :
0 commit comments