Skip to content

Commit 1648006

Browse files
authored
Merge pull request #4800 from stsewd/remove-support-for-mult-confs
Remove support for multiple configurations in one file
2 parents 3930383 + 178d744 commit 1648006

File tree

6 files changed

+49
-137
lines changed

6 files changed

+49
-137
lines changed

readthedocs/config/config.py

+16-40
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
'ConfigError',
3737
'ConfigOptionNotSupportedError',
3838
'InvalidConfig',
39-
'ProjectConfig',
4039
)
4140

4241
ALL = 'all'
@@ -110,12 +109,10 @@ class InvalidConfig(ConfigError):
110109

111110
message_template = 'Invalid "{key}": {error}'
112111

113-
def __init__(self, key, code, error_message, source_file=None,
114-
source_position=None):
112+
def __init__(self, key, code, error_message, source_file=None):
115113
self.key = key
116114
self.code = code
117115
self.source_file = source_file
118-
self.source_position = source_position
119116
message = self.message_template.format(
120117
key=key,
121118
code=code,
@@ -149,11 +146,10 @@ class BuildConfigBase(object):
149146
]
150147
version = None
151148

152-
def __init__(self, env_config, raw_config, source_file, source_position):
149+
def __init__(self, env_config, raw_config, source_file):
153150
self.env_config = env_config
154151
self.raw_config = raw_config
155152
self.source_file = source_file
156-
self.source_position = source_position
157153
if os.path.isdir(self.source_file):
158154
self.base_path = self.source_file
159155
else:
@@ -165,10 +161,7 @@ def __init__(self, env_config, raw_config, source_file, source_position):
165161
def error(self, key, message, code):
166162
"""Raise an error related to ``key``."""
167163
if not os.path.isdir(self.source_file):
168-
source = '{file} [{pos}]'.format(
169-
file=os.path.relpath(self.source_file, self.base_path),
170-
pos=self.source_position,
171-
)
164+
source = os.path.relpath(self.source_file, self.base_path)
172165
error_message = '{source}: {message}'.format(
173166
source=source,
174167
message=message,
@@ -180,7 +173,6 @@ def error(self, key, message, code):
180173
code=code,
181174
error_message=error_message,
182175
source_file=self.source_file,
183-
source_position=self.source_position,
184176
)
185177

186178
@contextmanager
@@ -194,7 +186,6 @@ def catch_validation_error(self, key):
194186
code=error.code,
195187
error_message=str(error),
196188
source_file=self.source_file,
197-
source_position=self.source_position,
198189
)
199190

200191
def pop(self, name, container, default, raise_ex):
@@ -1058,16 +1049,6 @@ def submodules(self):
10581049
return Submodules(**self._config['submodules'])
10591050

10601051

1061-
class ProjectConfig(list):
1062-
1063-
"""Wrapper for multiple build configs."""
1064-
1065-
def validate(self):
1066-
"""Validates each configuration build."""
1067-
for build in self:
1068-
build.validate()
1069-
1070-
10711052
def load(path, env_config):
10721053
"""
10731054
Load a project configuration and the top-most build config for a given path.
@@ -1083,10 +1064,9 @@ def load(path, env_config):
10831064
'No configuration file found',
10841065
code=CONFIG_REQUIRED
10851066
)
1086-
build_configs = []
10871067
with open(filename, 'r') as configuration_file:
10881068
try:
1089-
configs = parse(configuration_file.read())
1069+
config = parse(configuration_file.read())
10901070
except ParseError as error:
10911071
raise ConfigError(
10921072
'Parse error in {filename}: {message}'.format(
@@ -1095,23 +1075,19 @@ def load(path, env_config):
10951075
),
10961076
code=CONFIG_SYNTAX_INVALID,
10971077
)
1098-
for i, config in enumerate(configs):
1099-
allow_v2 = env_config.get('allow_v2')
1100-
if allow_v2:
1101-
version = config.get('version', 1)
1102-
else:
1103-
version = 1
1104-
build_config = get_configuration_class(version)(
1105-
env_config,
1106-
config,
1107-
source_file=filename,
1108-
source_position=i,
1109-
)
1110-
build_configs.append(build_config)
1078+
allow_v2 = env_config.get('allow_v2')
1079+
if allow_v2:
1080+
version = config.get('version', 1)
1081+
else:
1082+
version = 1
1083+
build_config = get_configuration_class(version)(
1084+
env_config,
1085+
config,
1086+
source_file=filename,
1087+
)
11111088

1112-
project_config = ProjectConfig(build_configs)
1113-
project_config.validate()
1114-
return project_config
1089+
build_config.validate()
1090+
return build_config
11151091

11161092

11171093
def get_configuration_class(version):

readthedocs/config/parser.py

+7-8
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,17 @@ class ParseError(Exception):
1717

1818
def parse(stream):
1919
"""
20-
Take file-like object and return a list of project configurations.
20+
Take file-like object and return a project configuration.
2121
22-
The files need be valid YAML and only contain mappings as documents.
22+
The file need be valid YAML and only contain mappings as document.
2323
Everything else raises a ``ParseError``.
2424
"""
2525
try:
26-
configs = list(yaml.safe_load_all(stream))
26+
config = yaml.safe_load(stream)
2727
except yaml.YAMLError as error:
2828
raise ParseError('YAML: {message}'.format(message=error))
29-
if not configs:
29+
if not isinstance(config, dict):
30+
raise ParseError('Expected mapping')
31+
if not config:
3032
raise ParseError('Empty config')
31-
for config in configs:
32-
if not isinstance(config, dict):
33-
raise ParseError('Expected mapping')
34-
return configs
33+
return config

readthedocs/config/tests/test_config.py

+9-62
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
ConfigError,
1818
ConfigOptionNotSupportedError,
1919
InvalidConfig,
20-
ProjectConfig,
2120
load,
2221
)
2322
from readthedocs.config.config import (
@@ -81,13 +80,11 @@
8180
}
8281

8382

84-
def get_build_config(config, env_config=None, source_file='readthedocs.yml',
85-
source_position=0):
83+
def get_build_config(config, env_config=None, source_file='readthedocs.yml'):
8684
return BuildConfigV1(
8785
env_config or {},
8886
config,
8987
source_file=source_file,
90-
source_position=source_position,
9188
)
9289

9390

@@ -130,10 +127,7 @@ def test_load_empty_config_file(tmpdir):
130127
def test_minimal_config(tmpdir):
131128
apply_fs(tmpdir, minimal_config_dir)
132129
base = str(tmpdir)
133-
config = load(base, env_config)
134-
assert isinstance(config, ProjectConfig)
135-
assert len(config) == 1
136-
build = config[0]
130+
build = load(base, env_config)
137131
assert isinstance(build, BuildConfigV1)
138132

139133

@@ -144,10 +138,7 @@ def test_load_version1(tmpdir):
144138
''')
145139
})
146140
base = str(tmpdir)
147-
config = load(base, get_env_config({'allow_v2': True}))
148-
assert isinstance(config, ProjectConfig)
149-
assert len(config) == 1
150-
build = config[0]
141+
build = load(base, get_env_config({'allow_v2': True}))
151142
assert isinstance(build, BuildConfigV1)
152143

153144

@@ -158,10 +149,7 @@ def test_load_version2(tmpdir):
158149
''')
159150
})
160151
base = str(tmpdir)
161-
config = load(base, get_env_config({'allow_v2': True}))
162-
assert isinstance(config, ProjectConfig)
163-
assert len(config) == 1
164-
build = config[0]
152+
build = load(base, get_env_config({'allow_v2': True}))
165153
assert isinstance(build, BuildConfigV2)
166154

167155

@@ -182,31 +170,18 @@ def test_yaml_extension(tmpdir):
182170
apply_fs(tmpdir, yaml_extension_config_dir)
183171
base = str(tmpdir)
184172
config = load(base, env_config)
185-
assert len(config) == 1
173+
assert isinstance(config, BuildConfigV1)
186174

187175

188176
def test_build_config_has_source_file(tmpdir):
189177
base = str(apply_fs(tmpdir, minimal_config_dir))
190-
build = load(base, env_config)[0]
178+
build = load(base, env_config)
191179
assert build.source_file == os.path.join(base, 'readthedocs.yml')
192-
assert build.source_position == 0
193-
194-
195-
def test_build_config_has_source_position(tmpdir):
196-
base = str(apply_fs(tmpdir, multiple_config_dir))
197-
builds = load(base, env_config)
198-
assert len(builds) == 2
199-
first, second = filter(
200-
lambda b: not b.source_file.endswith('nested/readthedocs.yml'),
201-
builds,
202-
)
203-
assert first.source_position == 0
204-
assert second.source_position == 1
205180

206181

207182
def test_build_config_has_list_with_single_empty_value(tmpdir):
208183
base = str(apply_fs(tmpdir, config_with_explicit_empty_list))
209-
build = load(base, env_config)[0]
184+
build = load(base, env_config)
210185
assert isinstance(build, BuildConfigV1)
211186
assert build.formats == []
212187

@@ -216,7 +191,6 @@ def test_config_requires_name():
216191
{'output_base': ''},
217192
{},
218193
source_file='readthedocs.yml',
219-
source_position=0,
220194
)
221195
with raises(InvalidConfig) as excinfo:
222196
build.validate()
@@ -229,7 +203,6 @@ def test_build_requires_valid_name():
229203
{'output_base': ''},
230204
{'name': 'with/slashes'},
231205
source_file='readthedocs.yml',
232-
source_position=0,
233206
)
234207
with raises(InvalidConfig) as excinfo:
235208
build.validate()
@@ -553,7 +526,6 @@ def test_valid_build_config():
553526
env_config,
554527
minimal_config,
555528
source_file='readthedocs.yml',
556-
source_position=0,
557529
)
558530
build.validate()
559531
assert build.name == 'docs'
@@ -575,7 +547,6 @@ def test_it_validates_to_abspath(self, tmpdir):
575547
get_env_config(),
576548
{'base': '../docs'},
577549
source_file=source_file,
578-
source_position=0,
579550
)
580551
build.validate()
581552
assert build.base == str(tmpdir.join('docs'))
@@ -596,7 +567,6 @@ def test_it_fails_if_base_is_not_a_string(self, tmpdir):
596567
get_env_config(),
597568
{'base': 1},
598569
source_file=str(tmpdir.join('readthedocs.yml')),
599-
source_position=0,
600570
)
601571
with raises(InvalidConfig) as excinfo:
602572
build.validate()
@@ -609,7 +579,6 @@ def test_it_fails_if_base_does_not_exist(self, tmpdir):
609579
get_env_config(),
610580
{'base': 'docs'},
611581
source_file=str(tmpdir.join('readthedocs.yml')),
612-
source_position=0,
613582
)
614583
with raises(InvalidConfig) as excinfo:
615584
build.validate()
@@ -625,7 +594,6 @@ def test_it_fails_if_build_is_invalid_option(self, tmpdir):
625594
get_env_config(),
626595
{'build': {'image': 3.0}},
627596
source_file=str(tmpdir.join('readthedocs.yml')),
628-
source_position=0,
629597
)
630598
with raises(InvalidConfig) as excinfo:
631599
build.validate()
@@ -641,7 +609,6 @@ def test_it_fails_on_python_validation(self, tmpdir):
641609
'python': {'version': '3.3'},
642610
},
643611
source_file=str(tmpdir.join('readthedocs.yml')),
644-
source_position=0,
645612
)
646613
build.validate_build()
647614
with raises(InvalidConfig) as excinfo:
@@ -658,7 +625,6 @@ def test_it_works_on_python_validation(self, tmpdir):
658625
'python': {'version': '3.3'},
659626
},
660627
source_file=str(tmpdir.join('readthedocs.yml')),
661-
source_position=0,
662628
)
663629
build.validate_build()
664630
build.validate_python()
@@ -669,7 +635,6 @@ def test_it_works(self, tmpdir):
669635
get_env_config(),
670636
{'build': {'image': 'latest'}},
671637
source_file=str(tmpdir.join('readthedocs.yml')),
672-
source_position=0,
673638
)
674639
build.validate()
675640
assert build.build.image == 'readthedocs/build:latest'
@@ -680,7 +645,6 @@ def test_default(self, tmpdir):
680645
get_env_config(),
681646
{},
682647
source_file=str(tmpdir.join('readthedocs.yml')),
683-
source_position=0,
684648
)
685649
build.validate()
686650
assert build.build.image == 'readthedocs/build:2.0'
@@ -696,7 +660,6 @@ def test_it_priorities_image_from_env_config(self, tmpdir, image):
696660
get_env_config({'defaults': defaults}),
697661
{'build': {'image': 'latest'}},
698662
source_file=str(tmpdir.join('readthedocs.yml')),
699-
source_position=0,
700663
)
701664
build.validate()
702665
assert build.build.image == image
@@ -786,7 +749,6 @@ def test_build_validate_calls_all_subvalidators(tmpdir):
786749
{},
787750
{},
788751
source_file=str(tmpdir.join('readthedocs.yml')),
789-
source_position=0,
790752
)
791753
with patch.multiple(
792754
BuildConfigV1,
@@ -802,20 +764,6 @@ def test_build_validate_calls_all_subvalidators(tmpdir):
802764
BuildConfigV1.validate_output_base.assert_called_with()
803765

804766

805-
def test_validate_project_config():
806-
with patch.object(BuildConfigV1, 'validate') as build_validate:
807-
project = ProjectConfig([
808-
BuildConfigV1(
809-
env_config,
810-
minimal_config,
811-
source_file='readthedocs.yml',
812-
source_position=0,
813-
),
814-
])
815-
project.validate()
816-
assert build_validate.call_count == 1
817-
818-
819767
def test_load_calls_validate(tmpdir):
820768
apply_fs(tmpdir, minimal_config_dir)
821769
base = str(tmpdir)
@@ -896,13 +844,12 @@ def test_as_dict(tmpdir):
896844

897845
class TestBuildConfigV2(object):
898846

899-
def get_build_config(self, config, env_config=None,
900-
source_file='readthedocs.yml', source_position=0):
847+
def get_build_config(
848+
self, config, env_config=None, source_file='readthedocs.yml'):
901849
return BuildConfigV2(
902850
env_config or {},
903851
config,
904852
source_file=source_file,
905-
source_position=source_position,
906853
)
907854

908855
def test_version(self):

0 commit comments

Comments
 (0)