Skip to content

Commit 3448fb1

Browse files
authored
Update Chore (#99)
1 parent fa0e7dd commit 3448fb1

3 files changed

Lines changed: 165 additions & 112 deletions

File tree

cppython/builder.py

Lines changed: 135 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""Everything needed to build a CPPython project
22
"""
33

4-
from dataclasses import dataclass
54
from importlib import metadata
5+
from inspect import getmodule
66
from logging import Logger
77
from pathlib import Path
88
from typing import Any
@@ -25,19 +25,12 @@
2525
CorePluginData,
2626
CPPythonGlobalConfiguration,
2727
CPPythonLocalConfiguration,
28+
DataPluginT,
2829
PEP621Configuration,
2930
ProjectConfiguration,
3031
)
3132

3233

33-
@dataclass
34-
class GeneratorInformation:
35-
"""Data that the builder outputs about plugins"""
36-
37-
plugin_type: type[Generator]
38-
entry: metadata.EntryPoint
39-
40-
4134
class Builder:
4235
"""Helper class for building CPPython projects"""
4336

@@ -126,11 +119,40 @@ def extract_scm_version(self, path: Path) -> str:
126119

127120
return version
128121

129-
def find_generator(self, core_data: CoreData) -> GeneratorInformation:
122+
def find_generators(self) -> list[type[Generator]]:
130123
"""_summary_
131124
132-
Args:
133-
core_data: _description_
125+
Raises:
126+
PluginError: _description_
127+
128+
Returns:
129+
_description_
130+
"""
131+
132+
group_name = "generator"
133+
plugin_types: list[type[Generator]] = []
134+
135+
# Filter entries by type
136+
for entry_point in list(metadata.entry_points(group=f"cppython.{group_name}")):
137+
loaded_type = entry_point.load()
138+
if not issubclass(loaded_type, Generator):
139+
self.logger.warning(
140+
f"Found incompatible plugin. The '{resolve_name(loaded_type)}' plugin must be an instance of"
141+
f" '{group_name}'"
142+
)
143+
else:
144+
self.logger.warning(
145+
f"{group_name} plugin found: {resolve_name(loaded_type)} from {getmodule(loaded_type)}"
146+
)
147+
plugin_types.append(loaded_type)
148+
149+
if not plugin_types:
150+
raise PluginError(f"No {group_name} plugin was found")
151+
152+
return plugin_types
153+
154+
def find_providers(self) -> list[type[Provider]]:
155+
"""_summary_
134156
135157
Raises:
136158
PluginError: _description_
@@ -139,59 +161,113 @@ def find_generator(self, core_data: CoreData) -> GeneratorInformation:
139161
_description_
140162
"""
141163

142-
group = "Generator"
143-
generator_info: list[tuple[type[Generator], metadata.EntryPoint]] = []
164+
group_name = "provider"
165+
plugin_types: list[type[Provider]] = []
144166

145-
# Filter entries
146-
for entry_point in list(metadata.entry_points(group=f"cppython.{group}")):
147-
plugin_type = entry_point.load()
148-
if not issubclass(plugin_type, Generator):
167+
# Filter entries by type
168+
for entry_point in list(metadata.entry_points(group=f"cppython.{group_name}")):
169+
loaded_type = entry_point.load()
170+
if not issubclass(loaded_type, Provider):
149171
self.logger.warning(
150-
f"Found incompatible plugin. The '{type(plugin_type).__name__}' plugin must be an instance of"
151-
f" '{group}'"
172+
f"Found incompatible plugin. The '{resolve_name(loaded_type)}' plugin must be an instance of"
173+
f" '{group_name}'"
152174
)
153175
else:
154-
self.logger.warning("Generator plugin found: %s", resolve_name(plugin_type))
155-
generator_info.append((plugin_type, entry_point))
156-
157-
if not generator_info:
158-
raise PluginError("No generator plugin was found")
159-
160-
# Lookup the requested generator if given
161-
supported_plugin_info = None
162-
if core_data.cppython_data.generator_name is not None:
163-
for plugin_type, entry in generator_info:
164-
if resolve_name(plugin_type) == core_data.cppython_data.generator_name:
165-
supported_plugin_info = plugin_type, entry
166-
break
167-
168-
# Try and deduce generator
169-
if supported_plugin_info is None:
170-
for plugin_type, entry in generator_info:
171-
if plugin_type.supported(core_data.project_data.pyproject_file.parent):
172-
supported_plugin_info = plugin_type, entry
173-
break
176+
self.logger.warning(
177+
f"{group_name} plugin found: {resolve_name(loaded_type)} from {getmodule(loaded_type)}"
178+
)
179+
plugin_types.append(loaded_type)
180+
181+
if not plugin_types:
182+
raise PluginError(f"No {group_name} plugin was found")
183+
184+
return plugin_types
185+
186+
def filter_plugins(
187+
self, plugin_types: list[type[DataPluginT]], directory: Path, pinned_name: str | None, group_name: str
188+
) -> list[type[DataPluginT]]:
189+
"""Finds and filters data plugins
190+
191+
Args:
192+
plugin_types: The plugin type to lookup
193+
directory: The data to query support for the filtered plugins
194+
pinned_name: The configuration name
195+
group_name: The group name
196+
197+
Raises:
198+
PluginError: Raised if no plugins can be found
199+
200+
Returns:
201+
The list of applicable plugins
202+
"""
203+
204+
# Lookup the requested plugin if given
205+
if pinned_name is not None:
206+
for loaded_type in plugin_types:
207+
if resolve_name(loaded_type) == pinned_name:
208+
self.logger.warning(
209+
f"Using {group_name} plugin: {resolve_name(loaded_type)} from {getmodule(loaded_type)}"
210+
)
211+
return [loaded_type]
212+
213+
self.logger.warning(f"'{group_name}_name' was empty. Trying to deduce {group_name}s")
214+
215+
supported_types: list[type[DataPluginT]] = []
216+
217+
# Deduce types
218+
for loaded_type in plugin_types:
219+
if loaded_type.supported(directory):
220+
self.logger.warning(
221+
f"A {group_name} plugin is supported: {resolve_name(loaded_type)} from {getmodule(loaded_type)}"
222+
)
223+
supported_types.append(loaded_type)
174224

175225
# Fail
176-
if supported_plugin_info is None:
177-
raise PluginError(
178-
"The 'generator_name' was empty and no generator could be deduced from the root directory."
179-
)
226+
if supported_types is None:
227+
raise PluginError(f"No {group_name} could be deduced from the root directory.")
228+
229+
return supported_types
230+
231+
def solve(
232+
self, generator_types: list[type[Generator]], provider_types: list[type[Provider]]
233+
) -> tuple[type[Generator], type[Provider]]:
234+
"""_summary_
235+
236+
Args:
237+
generator_types: _description_
238+
provider_types: _description_
239+
240+
Raises:
241+
PluginError: _description_
242+
243+
Returns:
244+
_description_
245+
"""
246+
247+
combos: list[tuple[type[Generator], type[Provider]]] = []
180248

181-
supported_plugin_type, supported_plugin_entry = supported_plugin_info
182-
self.logger.warning("Using generator plugin: '%s'", resolve_name(supported_plugin_type))
249+
for generator_type in generator_types:
250+
sync_types = generator_type.sync_types()
251+
for provider_type in provider_types:
252+
for sync_type in sync_types:
253+
if provider_type.supported_sync_type(sync_type):
254+
combos.append((generator_type, provider_type))
255+
break
183256

184-
return GeneratorInformation(plugin_type=supported_plugin_type, entry=supported_plugin_entry)
257+
if not combos:
258+
raise PluginError("No provider that supports a given generator could be deduced")
259+
260+
return combos[0]
185261

186262
def create_generator(
187-
self, core_data: CoreData, generator_configuration: dict[str, Any], plugin_info: GeneratorInformation
263+
self, core_data: CoreData, generator_configuration: dict[str, Any], generator_type: type[Generator]
188264
) -> Generator:
189265
"""Creates a generator from input configuration
190266
191267
Args:
192268
core_data: The resolved configuration data
193269
generator_configuration: The generator table of the CPPython configuration data
194-
plugin_info: The plugin information
270+
generator_type: The plugin type
195271
196272
Raises:
197273
PluginError: Raised if no viable generator plugin was found
@@ -201,8 +277,7 @@ def create_generator(
201277
"""
202278

203279
generator_data = resolve_generator(core_data.project_data)
204-
205-
cppython_plugin_data = resolve_cppython_plugin(core_data.cppython_data, plugin_info.plugin_type)
280+
cppython_plugin_data = resolve_cppython_plugin(core_data.cppython_data, generator_type)
206281

207282
core_plugin_data = CorePluginData(
208283
project_data=core_data.project_data,
@@ -215,66 +290,27 @@ def create_generator(
215290
"The pyproject.toml table 'tool.cppython.generator' does not exist. Sending generator empty data",
216291
)
217292

218-
return plugin_info.plugin_type(generator_data, core_plugin_data, generator_configuration)
293+
return generator_type(generator_data, core_plugin_data, generator_configuration)
219294

220-
def create_provider(self, core_data: CoreData, provider_configuration: dict[str, Any]) -> Provider:
295+
def create_provider(
296+
self, core_data: CoreData, provider_configuration: dict[str, Any], provider_type: type[Provider]
297+
) -> Provider:
221298
"""Creates Providers from input data
222299
223300
Args:
224301
core_data: The resolved configuration data
225302
provider_configuration: The provider data table
303+
provider_type: The type to instantiate
226304
227305
Raises:
228-
PluginError: Raised if no viable generator plugin was found
306+
PluginError: Raised if no viable provider plugin was found
229307
230308
Returns:
231309
A constructed provider plugins
232310
"""
233311

234-
group = "Provider"
235-
236-
entries = list(metadata.entry_points(group=f"cppython.{group}"))
237-
provider_info: list[type[Provider]] = []
238-
239-
# Filter entries
240-
for entry_point in entries:
241-
plugin_type = entry_point.load()
242-
if not issubclass(plugin_type, Provider):
243-
self.logger.warning(
244-
f"Found incompatible plugin. The '{resolve_name(plugin_type)}' plugin must be an instance of"
245-
f" '{group}'"
246-
)
247-
else:
248-
self.logger.warning("Provider plugin found: %s", resolve_name(plugin_type))
249-
provider_info.append(plugin_type)
250-
251-
if not provider_info:
252-
raise PluginError("No provider_types plugin was found")
253-
254-
# Lookup the requested provider if given
255-
supported_plugin_type: type[Provider] | None = None
256-
if core_data.cppython_data.provider_name is not None:
257-
for plugin_type in provider_info:
258-
if resolve_name(plugin_type) == core_data.cppython_data.provider_name:
259-
supported_plugin_type = plugin_type
260-
break
261-
262-
# Try and deduce provider
263-
if supported_plugin_type is None:
264-
for plugin_type in provider_info:
265-
if plugin_type.supported(core_data.project_data.pyproject_file.parent):
266-
supported_plugin_type = plugin_type
267-
break
268-
269-
# Fail
270-
if supported_plugin_type is None:
271-
raise PluginError("The 'provider_name' was empty and no provider could be deduced from the root directory.")
272-
273-
self.logger.warning("Using provider plugin: '%s'", resolve_name(supported_plugin_type))
274-
275-
provider_data = resolve_provider(core_data.project_data, core_data.cppython_data)
276-
277-
cppython_plugin_data = resolve_cppython_plugin(core_data.cppython_data, supported_plugin_type)
312+
provider_data = resolve_provider(core_data.project_data)
313+
cppython_plugin_data = resolve_cppython_plugin(core_data.cppython_data, provider_type)
278314

279315
core_plugin_data = CorePluginData(
280316
project_data=core_data.project_data,
@@ -287,4 +323,4 @@ def create_provider(self, core_data: CoreData, provider_configuration: dict[str,
287323
"The pyproject.toml table 'tool.cppython.provider' does not exist. Sending provider empty data",
288324
)
289325

290-
return supported_plugin_type(provider_data, core_plugin_data, provider_configuration)
326+
return provider_type(provider_data, core_plugin_data, provider_configuration)

cppython/project.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,27 @@ def __init__(
4444
builder = Builder(self.logger)
4545

4646
self._core_data = builder.generate_core_data(configuration, pyproject.project, pyproject.tool.cppython)
47-
res = builder.find_generator(self.core_data)
4847

49-
self._generator = builder.create_generator(self.core_data, pyproject.tool.cppython.generator, res)
50-
self._provider = builder.create_provider(self.core_data, pyproject.tool.cppython.provider)
48+
raw_generator_plugins = builder.find_generators()
49+
generator_plugins = builder.filter_plugins(
50+
raw_generator_plugins,
51+
self.core_data.project_data.pyproject_file.parent,
52+
self.core_data.cppython_data.generator_name,
53+
"Generator",
54+
)
55+
56+
raw_provider_plugins = builder.find_providers()
57+
provider_plugins = builder.filter_plugins(
58+
raw_provider_plugins,
59+
self.core_data.project_data.pyproject_file.parent,
60+
self.core_data.cppython_data.provider_name,
61+
"Provider",
62+
)
63+
64+
generator_type, provider_type = builder.solve(generator_plugins, provider_plugins)
65+
66+
self._generator = builder.create_generator(self.core_data, pyproject.tool.cppython.generator, generator_type)
67+
self._provider = builder.create_provider(self.core_data, pyproject.tool.cppython.provider, provider_type)
5168

5269
self._enabled = True
5370

@@ -93,8 +110,8 @@ def sync(self) -> None:
93110
Raises:
94111
PluginError: Plugin error
95112
"""
96-
name = resolve_name(type(self._generator))
97-
if (sync_data := self._provider.sync_data(name)) is None:
113+
114+
if (sync_data := self._provider.sync_data(self._generator)) is None:
98115
raise PluginError("The provider doesn't support the generator")
99116

100117
self._generator.sync(sync_data)

0 commit comments

Comments
 (0)