fallback to importlib.resources when __file__ is undefined

pull/339/head
Jason Mobarak 5 years ago
parent e53ea093e2
commit 7f9a8fe81a

@ -14,12 +14,14 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import importlib
from io import StringIO from io import StringIO
import os import os
import shutil import shutil
import sys import sys
import tempfile import tempfile
import unittest import unittest
import unittest.mock
from tests.common import build_temp_workspace from tests.common import build_temp_workspace
@ -475,3 +477,38 @@ class IgnorePathConfigTestCase(unittest.TestCase):
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:4:17: ' + trailing, './s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen, './s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen,
))) )))
class MissingModulePath(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(MissingModulePath, cls).setUpClass()
cls.mock_module_path = unittest.mock.patch.dict(config.__dict__,
{'_MODULE_PATH': None})
def setUp(self):
if 'importlib.resources' in sys.modules:
del sys.modules['importlib.resources']
@unittest.skipIf(sys.version_info < (3, 7),
'importlib.resources not supported')
def test_missing_module_path(self):
'''When __file__ is undefined, importlib.resources should be used'''
with self.mock_module_path:
importlib.reload(config)
self.assertTrue(config.__dict__['_MODULE_PATH'] is None)
self.assertTrue('importlib.resources' in sys.modules.keys())
self.assertTrue(config.get_extended_config('default') is not None)
@unittest.skipIf(sys.version_info < (3, 7),
'importlib.resources not supported')
def test_missing_importlib_resources(self):
'''When __file__ is undefined and importlib.resources is unavailable,
an ImportError exception is expected.'''
with self.mock_module_path:
sys.modules['importlib.resources'] = None # force an ImportError
error_regex = '.*importlib.resources library is required.*'
with self.assertRaisesRegex(ImportError, error_regex):
importlib.reload(config)
self.assertTrue(config.__dict__['_MODULE_PATH'] is None)

@ -19,8 +19,35 @@ import os.path
import pathspec import pathspec
import yaml import yaml
import yamllint.conf
import yamllint.rules import yamllint.rules
try:
_MODULE_PATH # allows unit tests to patch this
except NameError:
try:
_MODULE_PATH = __file__
except NameError: # pragma: no cover
_MODULE_PATH = None
if _MODULE_PATH is not None:
def _get_config(name):
module_dir = os.path.dirname(os.path.realpath(_MODULE_PATH))
config_path = os.path.join(module_dir, 'conf', name)
with open(config_path) as config:
return config.read()
else:
try:
from importlib.resources import read_text
except ImportError as exc:
_IMPORT_ERR_MESSAGE = (
"The importlib.resources library is required to locate resources "
"when __file__ is not defined")
raise ImportError(_IMPORT_ERR_MESSAGE) from exc
def _get_config(name):
return read_text(yamllint.conf, name)
class YamlLintConfigError(Exception): class YamlLintConfigError(Exception):
pass pass
@ -90,8 +117,8 @@ class YamlLintConfig(object):
# Does this conf override another conf that we need to load? # Does this conf override another conf that we need to load?
if 'extends' in conf: if 'extends' in conf:
path = get_extended_config_file(conf['extends']) config = get_extended_config(conf['extends'])
base = YamlLintConfig(file=path) base = YamlLintConfig(content=config)
try: try:
self.extend(base) self.extend(base)
except Exception as e: except Exception as e:
@ -200,14 +227,11 @@ def validate_rule_conf(rule, conf):
return conf return conf
def get_extended_config_file(name): def get_extended_config(name):
# Is it a standard conf shipped with yamllint... # Is it a standard conf shipped with yamllint...
if '/' not in name: if '/' not in name:
std_conf = os.path.join(os.path.dirname(os.path.realpath(__file__)), resource = name + '.yaml'
'conf', name + '.yaml') return _get_config(resource)
if os.path.isfile(std_conf):
return std_conf
# or a custom conf on filesystem? # or a custom conf on filesystem?
return name with open(name) as config:
return config.read()

Loading…
Cancel
Save