lockss-turtles 0.6.0.dev17__py3-none-any.whl → 0.6.0.dev18__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@ Library and command line tool to manage LOCKSS plugin sets and LOCKSS plugin
5
5
  registries.
6
6
  """
7
7
 
8
- __version__ = '0.6.0-dev17'
8
+ __version__ = '0.6.0-dev18'
9
9
 
10
10
  __copyright__ = '''
11
11
  Copyright (c) 2000-2025, Board of Trustees of Leland Stanford Jr. University
@@ -28,6 +28,10 @@
28
28
  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
29
  # POSSIBILITY OF SUCH DAMAGE.
30
30
 
31
+ """
32
+ Entry point for the ``lockss.turtles`` module.
33
+ """
34
+
31
35
  from lockss.turtles.cli import main
32
36
 
33
37
  main()
lockss/turtles/cli.py CHANGED
@@ -51,7 +51,7 @@ from .util import file_or
51
51
 
52
52
 
53
53
  class PluginBuildingOptions(BaseModel):
54
- plugin_set: Optional[list[FilePath]] = Field(aliases=['-s'], description=f'(plugin sets) add one or more plugin sets to the loaded plugin sets')
54
+ plugin_set: Optional[list[FilePath]] = Field(aliases=['-s'], description=f'(plugin sets) add one or more plugin set definition files to the loaded plugin sets')
55
55
  plugin_set_catalog: Optional[list[FilePath]] = Field(aliases=['-S'], description=f'(plugin sets) add one or more plugin set catalogs to the loaded plugin set catalogs; if no plugin set catalogs or plugin sets are specified, load {file_or(TurtlesApp.default_plugin_set_catalog_choices())}')
56
56
  plugin_signing_credentials: Optional[FilePath] = Field(aliases=['-c'], description=f'(plugin signing credentials) load the plugin signing credentials from the given file, or if none, from {file_or(TurtlesApp.default_plugin_signing_credentials_choices())}')
57
57
  plugin_signing_password: Optional[str] = Field(description='(plugin signing credentials) set the plugin signing password, or if none, prompt interactively')
@@ -87,7 +87,7 @@ class BasePluginRegistryLayout(BaseModel, ABC):
87
87
 
88
88
  def get_plugin_registry(self) -> PluginRegistry:
89
89
  if self._plugin_registry is None:
90
- raise RuntimeError('Uninitialized plugin registry')
90
+ raise ValueError('Uninitialized plugin registry')
91
91
  return self._plugin_registry
92
92
 
93
93
  def get_type(self) -> PluginRegistryLayoutType:
@@ -194,7 +194,7 @@ class PluginRegistryLayer(BaseModel, ABC):
194
194
 
195
195
  def get_plugin_registry(self) -> PluginRegistry:
196
196
  if self._plugin_registry is None:
197
- raise RuntimeError('Uninitialized plugin registry')
197
+ raise ValueError('Uninitialized plugin registry')
198
198
  return self._plugin_registry
199
199
 
200
200
  def initialize(self, plugin_registry: PluginRegistry) -> PluginRegistryLayer:
@@ -28,6 +28,10 @@
28
28
  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
29
  # POSSIBILITY OF SUCH DAMAGE.
30
30
 
31
+ """
32
+ Representations of plugin sets.
33
+ """
34
+
31
35
  # Remove in Python 3.14
32
36
  # See https://stackoverflow.com/questions/33533148/how-do-i-type-hint-a-method-with-the-type-of-the-enclosing-class/33533514#33533514
33
37
  from __future__ import annotations
@@ -45,52 +49,149 @@ from pydantic import BaseModel, Field
45
49
  from .plugin import Plugin, PluginIdentifier
46
50
  from .util import BaseModelWithRoot
47
51
 
48
-
52
+ #: A type alias for the plugin set catalog kind.
49
53
  PluginSetCatalogKind = Literal['PluginSetCatalog']
50
54
 
51
55
 
52
56
  class PluginSetCatalog(BaseModelWithRoot):
57
+ """
58
+ A Pydantic model (``lockss.turtles.util.BaseModelWithRoot``) to represent a
59
+ plugin set catalog.
60
+ """
61
+ #: This object's kind.
53
62
  kind: PluginSetCatalogKind = Field(description="This object's kind")
63
+ #: A non-empty list of plugin set files.
54
64
  plugin_set_files: list[str] = Field(min_length=1, description="A non-empty list of plugin set files", title='Plugin Set Files', alias='plugin-set-files')
55
65
 
56
66
  def get_plugin_set_files(self) -> list[Path]:
67
+ """
68
+ Return this plugin set catalog's list of plugin set definition file
69
+ paths (relative to the root if not absolute).
70
+ :return: A list of plugin set definition file paths.
71
+ :rtype: list[Path]
72
+ """
57
73
  return [self.get_root().joinpath(p) for p in self.plugin_set_files]
58
74
 
59
75
 
76
+ #: A type alias for the plugin set builder type.
60
77
  PluginSetBuilderType = Literal['ant', 'maven']
61
78
 
62
79
 
63
80
  class BasePluginSetBuilder(BaseModelWithRoot, ABC):
81
+ """
82
+ An abstract Pydantic model (``lockss.turtles.util.BaseModelWithRoot``) to
83
+ represent a plugin set builder.
84
+ """
85
+
86
+ #: Pydantic definition of the ``type`` field.
64
87
  TYPE_FIELD: ClassVar[dict[str, str]] = dict(description='A plugin builder type', title='Plugin Builder Type')
88
+ #: Pydantic definition of the ``main`` field.
65
89
  MAIN_FIELD: ClassVar[dict[str, str]] = dict(description="The path to the plugins' source code, relative to the root of the project", title='Main Code Path')
90
+ #: Pydantic definition of the ``test`` field.
66
91
  TEST_FIELD: ClassVar[dict[str, str]] = dict(description="The path to the plugins' unit tests, relative to the root of the project", title='Test Code Path')
67
92
 
68
93
  @abstractmethod
69
94
  def build_plugin(self, plugin_id: PluginIdentifier, keystore_path: Path, keystore_alias: str, keystore_password=None) -> tuple[Path, Plugin]:
70
- pass
95
+ """
96
+ Builds the given plugin, using the given plugin signing credentials.
97
+
98
+ :param plugin_id: A plugin identifier.
99
+ :type plugin_id: PluginIdentifier
100
+ :param keystore_path: The path to the plugin signing keystore.
101
+ :type keystore_path: Path
102
+ :param keystore_alias: The signing alias to use from the plugin signing
103
+ keystore.
104
+ :type keystore_alias: str
105
+ :param keystore_password: The signing password.
106
+ :type keystore_password: Any
107
+ :return: A tuple of the plugin JAR path and the corresponding ``Plugin``
108
+ object.
109
+ :rtype: tuple[Path, Plugin]
110
+ """
111
+ pass # FIXME: typing of keystore_password
71
112
 
72
113
  def get_main(self) -> Path:
114
+ """
115
+ Returns the plugin set's main code path (relative to the root if not
116
+ absolute).
117
+
118
+ :return: The plugin set's main code path.
119
+ :rtype: Path
120
+ :raises ValueError: If this object is not properly initialized.
121
+ """
73
122
  return self.get_root().joinpath(self._get_main())
74
123
 
75
124
  def get_test(self) -> Path:
125
+ """
126
+ Returns the plugin set's unit test path (relative to the root if not
127
+ absolute).
128
+
129
+ :return: The plugin set's unit test path.
130
+ :rtype: Path
131
+ :raises ValueError: If this object is not properly initialized.
132
+ """
76
133
  return self.get_root().joinpath(self._get_test())
77
134
 
78
135
  def get_type(self) -> PluginSetBuilderType:
136
+ """
137
+ Returns this plugin set builder's type.
138
+
139
+ :return: This plugin set builder's type.
140
+ :rtype: PluginSetBuilderType
141
+ """
79
142
  return getattr(self, 'type')
80
143
 
81
144
  def has_plugin(self, plugin_id: PluginIdentifier) -> bool:
145
+ """
146
+ Determines if the given plugin identifier represents a plugin that is
147
+ present in the plugin set.
148
+
149
+ :param plugin_id: A plugin identifier.
150
+ :type plugin_id: PluginIdentifier
151
+ :return: Whether the plugin is present in the plugin set.
152
+ :rtype: bool
153
+ """
82
154
  return self._plugin_path(plugin_id).is_file()
83
155
 
84
156
  def make_plugin(self, plugin_id: PluginIdentifier) -> Plugin:
157
+ """
158
+ Makes a ``Plugin`` object from the given plugin identifier.
159
+
160
+ :param plugin_id: A plugin identifier.
161
+ :type plugin_id: PluginIdentifier
162
+ :return: The corresponding ``Plugin`` object.
163
+ :rtype: Plugin
164
+ """
85
165
  return Plugin.from_path(self._plugin_path(plugin_id))
86
166
 
87
167
  def _get_main(self) -> str:
168
+ """
169
+ Return the concrete implementation's ``main`` field.
170
+
171
+ :return: The ``main`` field.
172
+ :rtype: str
173
+ """
88
174
  return getattr(self, 'main')
89
175
 
90
176
  def _get_test(self) -> str:
177
+ """
178
+ Return the concrete implementation's ``test`` field.
179
+
180
+ :return: The ``test`` field.
181
+ :rtype: str
182
+ """
91
183
  return getattr(self, 'test')
92
184
 
93
185
  def _plugin_path(self, plugin_id: PluginIdentifier) -> Path:
186
+ """
187
+ Returns the path of the plugin file for the given plugin identifier
188
+ relative to the plugin set's main code path.
189
+
190
+ :param plugin_id: A plugin identifier.
191
+ :type plugin_id: PluginIdentifier
192
+ :return: The plugin file.
193
+ :rtype: Path
194
+ """
94
195
  return self.get_main().joinpath(Plugin.id_to_file(plugin_id))
95
196
 
96
197
 
lockss/turtles/util.py CHANGED
@@ -52,7 +52,7 @@ class BaseModelWithRoot(BaseModel):
52
52
 
53
53
  def get_root(self) -> Path:
54
54
  if self._root is None:
55
- raise RuntimeError('Uninitialized root')
55
+ raise ValueError('Uninitialized root')
56
56
  return self._root
57
57
 
58
58
  def initialize(self, root: PathOrStr) -> BaseModelWithRoot:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: lockss-turtles
3
- Version: 0.6.0.dev17
3
+ Version: 0.6.0.dev18
4
4
  Summary: Library and command line tool to manage LOCKSS plugin sets and LOCKSS plugin registries
5
5
  License: BSD-3-Clause
6
6
  Author: Thib Guicherd-Callin
@@ -34,7 +34,7 @@ Description-Content-Type: text/x-rst
34
34
  Turtles
35
35
  =======
36
36
 
37
- .. |RELEASE| replace:: 0.6.0-dev1
37
+ .. |RELEASE| replace:: 0.6.0-dev18
38
38
  .. |RELEASE_DATE| replace:: ?
39
39
 
40
40
  .. |HELP| replace:: ``--help/-h``
@@ -54,7 +54,7 @@ Turtles
54
54
  :alt: Turtles logo
55
55
  :align: right
56
56
 
57
- Turtles is a tool to manage LOCKSS plugin sets and LOCKSS plugin registries.
57
+ Turtles is a command line tool and Python library to manage LOCKSS plugin sets and LOCKSS plugin registries.
58
58
 
59
59
  **Latest release:** |RELEASE| (|RELEASE_DATE|)
60
60
 
@@ -0,0 +1,15 @@
1
+ lockss/turtles/__init__.py,sha256=l85NQRMGYRq2ptQpR3ssp7sKSXMW-vfL_EZI-mZbjl4,1744
2
+ lockss/turtles/__main__.py,sha256=BqRTG3dejCgLh87UJ1Os9DD9unxnQkOdUQM6eqWS3Sg,1680
3
+ lockss/turtles/app.py,sha256=SAmd_k_2viX_SY2aiXNgQq0k1oPYMUwNBicsnzAo9e4,16689
4
+ lockss/turtles/cli.py,sha256=ZB1H7egHWjG2IkPxwW0NvlLTBQ99bpN5wuzOO7_xa30,20681
5
+ lockss/turtles/plugin.py,sha256=re44YVlzXVU8azDshxn7oHw1GdTQLLQgYwkvZlur-60,5384
6
+ lockss/turtles/plugin_registry.py,sha256=G_CwTFgDV4om1W0-QY7Ww_7mneCbckXuEWMk7ZFOPW4,11916
7
+ lockss/turtles/plugin_set.py,sha256=OCQjRnb4FeIRsuwJpJ63UoXYNeENm39V-iQL47xXZ0M,14711
8
+ lockss/turtles/util.py,sha256=8EyWvzTLNycQM_ZKCtWm8FpKJSrwaCSWh8006UYq6vU,2498
9
+ unittest/lockss/turtles/__init__.py,sha256=hrgWx4GaP-hhPBuRlbLndJnOQmZicKCLaP-dQTCu1sQ,3162
10
+ unittest/lockss/turtles/test_plugin_set.py,sha256=q6JmooDR-wijAQ8x9DWKTNB6Of4EOr3Dgq8oaX0LTpQ,4179
11
+ lockss_turtles-0.6.0.dev18.dist-info/LICENSE,sha256=O9ONND4uDxY_jucI4jZDf2liAk05ScEJaYu-Al7EOdQ,1506
12
+ lockss_turtles-0.6.0.dev18.dist-info/METADATA,sha256=iyywFL8UvcuqBz6M-T3Vv4AVn8FhtO81nOJCw9biIYU,39692
13
+ lockss_turtles-0.6.0.dev18.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
14
+ lockss_turtles-0.6.0.dev18.dist-info/entry_points.txt,sha256=25BAVFSBRKWAWiXIGZgcr1ypt2mV7nj31Jl8WcNZZOk,51
15
+ lockss_turtles-0.6.0.dev18.dist-info/RECORD,,
@@ -28,8 +28,13 @@
28
28
  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
29
  # POSSIBILITY OF SUCH DAMAGE.
30
30
 
31
+ from pathlib import Path
32
+
31
33
  from . import PydanticTestCase
32
- from lockss.turtles.plugin_set import AntPluginSetBuilder, MavenPluginSetBuilder, PluginSet, PluginSetBuilder
34
+ from lockss.turtles.plugin_set import AntPluginSetBuilder, MavenPluginSetBuilder, PluginSet, PluginSetBuilder, PluginSetBuilderType
35
+
36
+
37
+ ROOT: Path = Path('.').absolute()
33
38
 
34
39
 
35
40
  class TestPluginSet(PydanticTestCase):
@@ -46,17 +51,27 @@ class TestPluginSet(PydanticTestCase):
46
51
  PluginSet(kind='PluginSet', id='myset', name='My Set', builder=AntPluginSetBuilder(type='ant'))
47
52
  PluginSet(kind='PluginSet', id='myset', name='My Set', builder=MavenPluginSetBuilder(type='maven'))
48
53
 
54
+
49
55
  class TestPluginSetBuilder(PydanticTestCase):
50
56
 
51
- def doTestPluginSetBuilder(self, Pbsc: type(PluginSetBuilder), typ: str, def_main: str, def_test: str) -> None:
57
+ def doTestPluginSetBuilder(self, Pbsc: type(PluginSetBuilder), typ: PluginSetBuilderType, def_main: Path, def_test: Path) -> None:
52
58
  self.assertPydanticMissing(lambda: Pbsc(), 'type')
53
59
  self.assertPydanticLiteralError(lambda: Pbsc(type='BADTYPE'), 'type', typ)
54
60
  self.assertIsNone(Pbsc(type=typ)._root)
55
- self.assertEqual(Pbsc(type=typ)._get_main(), def_main)
56
- self.assertEqual(Pbsc(type=typ, main='mymain')._get_main(), 'mymain')
57
- self.assertEqual(Pbsc(type=typ)._get_test(), def_test)
58
- self.assertEqual(Pbsc(type=typ, test='mytest')._get_test(), 'mytest')
61
+ with self.assertRaises(ValueError):
62
+ Pbsc(type=typ).get_root()
63
+ self.assertEqual(Pbsc(type=typ).initialize(ROOT).get_root(), ROOT)
64
+ with self.assertRaises(ValueError):
65
+ Pbsc(type=typ, main='anything').get_main()
66
+ self.assertEqual(Pbsc(type=typ).initialize(ROOT).get_main(), def_main)
67
+ self.assertEqual(Pbsc(type=typ, main='mymain').initialize(ROOT).get_main(), ROOT.joinpath('mymain'))
68
+ self.assertEqual(Pbsc(type=typ, main='/opt/main').initialize(ROOT).get_main(), Path('/opt/main'))
69
+ with self.assertRaises(ValueError):
70
+ Pbsc(type=typ, test='anything').get_test()
71
+ self.assertEqual(Pbsc(type=typ).initialize(ROOT).get_test(), def_test)
72
+ self.assertEqual(Pbsc(type=typ, test='mytest').initialize(ROOT).get_test(), ROOT.joinpath('mytest'))
73
+ self.assertEqual(Pbsc(type=typ, test='/opt/test').initialize(ROOT).get_test(), Path('/opt/test'))
59
74
 
60
75
  def testPluginSetBuilder(self):
61
- self.doTestPluginSetBuilder(AntPluginSetBuilder, 'ant', 'plugins/src', 'plugins/test/src')
62
- self.doTestPluginSetBuilder(MavenPluginSetBuilder, 'maven', 'src/main/java', 'src/test/java')
76
+ self.doTestPluginSetBuilder(AntPluginSetBuilder, 'ant', ROOT.joinpath('plugins/src'), ROOT.joinpath('plugins/test/src'))
77
+ self.doTestPluginSetBuilder(MavenPluginSetBuilder, 'maven', ROOT.joinpath('src/main/java'), ROOT.joinpath('src/test/java'))
@@ -1,15 +0,0 @@
1
- lockss/turtles/__init__.py,sha256=DHr6P3wE_eSUSkgtca783Sm1ppF269jpwUNuxTcaOx4,1744
2
- lockss/turtles/__main__.py,sha256=825geLIwXS0LKRqxifJXlLaAZrY8nllXfHzw5ch5ysM,1624
3
- lockss/turtles/app.py,sha256=SAmd_k_2viX_SY2aiXNgQq0k1oPYMUwNBicsnzAo9e4,16689
4
- lockss/turtles/cli.py,sha256=jKghKNTHmxs0ZKy_R_VVujL6X7Ka1qpC1SmOhObDEfM,20665
5
- lockss/turtles/plugin.py,sha256=re44YVlzXVU8azDshxn7oHw1GdTQLLQgYwkvZlur-60,5384
6
- lockss/turtles/plugin_registry.py,sha256=VmvUI6Mx6Jk7fr1L3RfJ4jB6lppCHUm-2PjzwoqxBFk,11920
7
- lockss/turtles/plugin_set.py,sha256=hKUXOSRyhHxxcMWE3I69Wykod32Ig871oeJsMTvbXfU,11291
8
- lockss/turtles/util.py,sha256=wGCrw_YySvyqaCzT0PItzXpkLHOCMMC_DQHhGU7zudI,2500
9
- unittest/lockss/turtles/__init__.py,sha256=hrgWx4GaP-hhPBuRlbLndJnOQmZicKCLaP-dQTCu1sQ,3162
10
- unittest/lockss/turtles/test_plugin_set.py,sha256=i-VM8mvrPuW2KqUlh2HPVRtgh3-F7RhmRAwcvhwpoDA,3354
11
- lockss_turtles-0.6.0.dev17.dist-info/LICENSE,sha256=O9ONND4uDxY_jucI4jZDf2liAk05ScEJaYu-Al7EOdQ,1506
12
- lockss_turtles-0.6.0.dev17.dist-info/METADATA,sha256=RjDZ6rwBmkfoK-d3bsP9LQXsdmd0ZfJhXFmYQRK5nPE,39659
13
- lockss_turtles-0.6.0.dev17.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
14
- lockss_turtles-0.6.0.dev17.dist-info/entry_points.txt,sha256=25BAVFSBRKWAWiXIGZgcr1ypt2mV7nj31Jl8WcNZZOk,51
15
- lockss_turtles-0.6.0.dev17.dist-info/RECORD,,