fallback to importlib.resources when __file__ is undefined
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
0
yamllint/conf/__init__.py
Normal file
0
yamllint/conf/__init__.py
Normal file
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user