amulet-core 1.9.19__py3-none-any.whl → 1.9.20__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.

Potentially problematic release.


This version of amulet-core might be problematic. Click here for more details.

Files changed (198) hide show
  1. amulet/__init__.py +27 -27
  2. amulet/__pyinstaller/__init__.py +2 -2
  3. amulet/__pyinstaller/hook-amulet.py +4 -4
  4. amulet/_version.py +21 -21
  5. amulet/api/__init__.py +2 -2
  6. amulet/api/abstract_base_entity.py +128 -128
  7. amulet/api/block.py +630 -630
  8. amulet/api/block_entity.py +71 -71
  9. amulet/api/cache.py +107 -107
  10. amulet/api/chunk/__init__.py +6 -6
  11. amulet/api/chunk/biomes.py +207 -207
  12. amulet/api/chunk/block_entity_dict.py +175 -175
  13. amulet/api/chunk/blocks.py +46 -46
  14. amulet/api/chunk/chunk.py +389 -389
  15. amulet/api/chunk/entity_list.py +75 -75
  16. amulet/api/chunk/status.py +167 -167
  17. amulet/api/data_types/__init__.py +4 -4
  18. amulet/api/data_types/generic_types.py +4 -4
  19. amulet/api/data_types/operation_types.py +16 -16
  20. amulet/api/data_types/world_types.py +49 -49
  21. amulet/api/data_types/wrapper_types.py +71 -71
  22. amulet/api/entity.py +74 -74
  23. amulet/api/errors.py +119 -119
  24. amulet/api/history/__init__.py +36 -36
  25. amulet/api/history/base/__init__.py +3 -3
  26. amulet/api/history/base/base_history.py +26 -26
  27. amulet/api/history/base/history_manager.py +63 -63
  28. amulet/api/history/base/revision_manager.py +73 -73
  29. amulet/api/history/changeable.py +15 -15
  30. amulet/api/history/data_types.py +7 -7
  31. amulet/api/history/history_manager/__init__.py +3 -3
  32. amulet/api/history/history_manager/container.py +102 -102
  33. amulet/api/history/history_manager/database.py +279 -279
  34. amulet/api/history/history_manager/meta.py +93 -93
  35. amulet/api/history/history_manager/object.py +116 -116
  36. amulet/api/history/revision_manager/__init__.py +2 -2
  37. amulet/api/history/revision_manager/disk.py +33 -33
  38. amulet/api/history/revision_manager/ram.py +12 -12
  39. amulet/api/item.py +75 -75
  40. amulet/api/level/__init__.py +4 -4
  41. amulet/api/level/base_level/__init__.py +1 -1
  42. amulet/api/level/base_level/base_level.py +1035 -1026
  43. amulet/api/level/base_level/chunk_manager.py +227 -227
  44. amulet/api/level/base_level/clone.py +389 -389
  45. amulet/api/level/base_level/player_manager.py +101 -101
  46. amulet/api/level/immutable_structure/__init__.py +1 -1
  47. amulet/api/level/immutable_structure/immutable_structure.py +94 -94
  48. amulet/api/level/immutable_structure/void_format_wrapper.py +117 -117
  49. amulet/api/level/structure.py +22 -22
  50. amulet/api/level/world.py +19 -19
  51. amulet/api/partial_3d_array/__init__.py +2 -2
  52. amulet/api/partial_3d_array/base_partial_3d_array.py +263 -263
  53. amulet/api/partial_3d_array/bounded_partial_3d_array.py +528 -528
  54. amulet/api/partial_3d_array/data_types.py +15 -15
  55. amulet/api/partial_3d_array/unbounded_partial_3d_array.py +229 -229
  56. amulet/api/partial_3d_array/util.py +152 -152
  57. amulet/api/player.py +65 -65
  58. amulet/api/registry/__init__.py +2 -2
  59. amulet/api/registry/base_registry.py +34 -34
  60. amulet/api/registry/biome_manager.py +153 -153
  61. amulet/api/registry/block_manager.py +156 -156
  62. amulet/api/selection/__init__.py +2 -2
  63. amulet/api/selection/abstract_selection.py +315 -315
  64. amulet/api/selection/box.py +805 -805
  65. amulet/api/selection/group.py +488 -488
  66. amulet/api/structure.py +37 -37
  67. amulet/api/wrapper/__init__.py +8 -8
  68. amulet/api/wrapper/chunk/interface.py +441 -441
  69. amulet/api/wrapper/chunk/translator.py +567 -567
  70. amulet/api/wrapper/format_wrapper.py +772 -772
  71. amulet/api/wrapper/structure_format_wrapper.py +116 -116
  72. amulet/api/wrapper/world_format_wrapper.py +63 -63
  73. amulet/level/__init__.py +1 -1
  74. amulet/level/formats/anvil_forge_world.py +40 -40
  75. amulet/level/formats/anvil_world/__init__.py +3 -3
  76. amulet/level/formats/anvil_world/_sector_manager.py +291 -384
  77. amulet/level/formats/anvil_world/data_pack/__init__.py +2 -2
  78. amulet/level/formats/anvil_world/data_pack/data_pack.py +224 -224
  79. amulet/level/formats/anvil_world/data_pack/data_pack_manager.py +77 -77
  80. amulet/level/formats/anvil_world/dimension.py +177 -177
  81. amulet/level/formats/anvil_world/format.py +769 -769
  82. amulet/level/formats/anvil_world/region.py +384 -384
  83. amulet/level/formats/construction/__init__.py +3 -3
  84. amulet/level/formats/construction/format_wrapper.py +515 -515
  85. amulet/level/formats/construction/interface.py +134 -134
  86. amulet/level/formats/construction/section.py +60 -60
  87. amulet/level/formats/construction/util.py +165 -165
  88. amulet/level/formats/leveldb_world/__init__.py +3 -3
  89. amulet/level/formats/leveldb_world/chunk.py +33 -33
  90. amulet/level/formats/leveldb_world/dimension.py +385 -419
  91. amulet/level/formats/leveldb_world/format.py +659 -641
  92. amulet/level/formats/leveldb_world/interface/chunk/__init__.py +36 -36
  93. amulet/level/formats/leveldb_world/interface/chunk/base_leveldb_interface.py +836 -836
  94. amulet/level/formats/leveldb_world/interface/chunk/generate_interface.py +31 -31
  95. amulet/level/formats/leveldb_world/interface/chunk/leveldb_0.py +30 -30
  96. amulet/level/formats/leveldb_world/interface/chunk/leveldb_1.py +12 -12
  97. amulet/level/formats/leveldb_world/interface/chunk/leveldb_10.py +12 -12
  98. amulet/level/formats/leveldb_world/interface/chunk/leveldb_11.py +12 -12
  99. amulet/level/formats/leveldb_world/interface/chunk/leveldb_12.py +12 -12
  100. amulet/level/formats/leveldb_world/interface/chunk/leveldb_13.py +12 -12
  101. amulet/level/formats/leveldb_world/interface/chunk/leveldb_14.py +12 -12
  102. amulet/level/formats/leveldb_world/interface/chunk/leveldb_15.py +12 -12
  103. amulet/level/formats/leveldb_world/interface/chunk/leveldb_16.py +12 -12
  104. amulet/level/formats/leveldb_world/interface/chunk/leveldb_17.py +12 -12
  105. amulet/level/formats/leveldb_world/interface/chunk/leveldb_18.py +12 -12
  106. amulet/level/formats/leveldb_world/interface/chunk/leveldb_19.py +12 -12
  107. amulet/level/formats/leveldb_world/interface/chunk/leveldb_2.py +12 -12
  108. amulet/level/formats/leveldb_world/interface/chunk/leveldb_20.py +12 -12
  109. amulet/level/formats/leveldb_world/interface/chunk/leveldb_21.py +12 -12
  110. amulet/level/formats/leveldb_world/interface/chunk/leveldb_22.py +12 -12
  111. amulet/level/formats/leveldb_world/interface/chunk/leveldb_23.py +10 -10
  112. amulet/level/formats/leveldb_world/interface/chunk/leveldb_24.py +10 -10
  113. amulet/level/formats/leveldb_world/interface/chunk/leveldb_25.py +24 -24
  114. amulet/level/formats/leveldb_world/interface/chunk/leveldb_26.py +10 -10
  115. amulet/level/formats/leveldb_world/interface/chunk/leveldb_27.py +10 -10
  116. amulet/level/formats/leveldb_world/interface/chunk/leveldb_28.py +10 -10
  117. amulet/level/formats/leveldb_world/interface/chunk/leveldb_29.py +33 -33
  118. amulet/level/formats/leveldb_world/interface/chunk/leveldb_3.py +57 -57
  119. amulet/level/formats/leveldb_world/interface/chunk/leveldb_30.py +10 -10
  120. amulet/level/formats/leveldb_world/interface/chunk/leveldb_31.py +10 -10
  121. amulet/level/formats/leveldb_world/interface/chunk/leveldb_32.py +10 -10
  122. amulet/level/formats/leveldb_world/interface/chunk/leveldb_33.py +10 -10
  123. amulet/level/formats/leveldb_world/interface/chunk/leveldb_34.py +10 -10
  124. amulet/level/formats/leveldb_world/interface/chunk/leveldb_35.py +10 -10
  125. amulet/level/formats/leveldb_world/interface/chunk/leveldb_36.py +10 -10
  126. amulet/level/formats/leveldb_world/interface/chunk/leveldb_37.py +10 -10
  127. amulet/level/formats/leveldb_world/interface/chunk/leveldb_38.py +10 -10
  128. amulet/level/formats/leveldb_world/interface/chunk/leveldb_39.py +12 -12
  129. amulet/level/formats/leveldb_world/interface/chunk/leveldb_4.py +12 -12
  130. amulet/level/formats/leveldb_world/interface/chunk/leveldb_40.py +16 -16
  131. amulet/level/formats/leveldb_world/interface/chunk/leveldb_5.py +12 -12
  132. amulet/level/formats/leveldb_world/interface/chunk/leveldb_6.py +12 -12
  133. amulet/level/formats/leveldb_world/interface/chunk/leveldb_7.py +12 -12
  134. amulet/level/formats/leveldb_world/interface/chunk/leveldb_8.py +180 -180
  135. amulet/level/formats/leveldb_world/interface/chunk/leveldb_9.py +18 -18
  136. amulet/level/formats/leveldb_world/interface/chunk/leveldb_chunk_versions.py +79 -79
  137. amulet/level/formats/mcstructure/__init__.py +3 -3
  138. amulet/level/formats/mcstructure/chunk.py +50 -50
  139. amulet/level/formats/mcstructure/format_wrapper.py +408 -408
  140. amulet/level/formats/mcstructure/interface.py +175 -175
  141. amulet/level/formats/schematic/__init__.py +3 -3
  142. amulet/level/formats/schematic/chunk.py +55 -55
  143. amulet/level/formats/schematic/data_types.py +4 -4
  144. amulet/level/formats/schematic/format_wrapper.py +373 -373
  145. amulet/level/formats/schematic/interface.py +142 -142
  146. amulet/level/formats/sponge_schem/__init__.py +4 -4
  147. amulet/level/formats/sponge_schem/chunk.py +62 -62
  148. amulet/level/formats/sponge_schem/format_wrapper.py +463 -463
  149. amulet/level/formats/sponge_schem/interface.py +118 -118
  150. amulet/level/formats/sponge_schem/varint/__init__.py +1 -1
  151. amulet/level/formats/sponge_schem/varint/varint.py +87 -87
  152. amulet/level/interfaces/chunk/anvil/anvil_0.py +72 -72
  153. amulet/level/interfaces/chunk/anvil/anvil_1444.py +336 -336
  154. amulet/level/interfaces/chunk/anvil/anvil_1466.py +94 -94
  155. amulet/level/interfaces/chunk/anvil/anvil_1467.py +37 -37
  156. amulet/level/interfaces/chunk/anvil/anvil_1484.py +20 -20
  157. amulet/level/interfaces/chunk/anvil/anvil_1503.py +20 -20
  158. amulet/level/interfaces/chunk/anvil/anvil_1519.py +34 -34
  159. amulet/level/interfaces/chunk/anvil/anvil_1901.py +20 -20
  160. amulet/level/interfaces/chunk/anvil/anvil_1908.py +20 -20
  161. amulet/level/interfaces/chunk/anvil/anvil_1912.py +21 -21
  162. amulet/level/interfaces/chunk/anvil/anvil_1934.py +20 -20
  163. amulet/level/interfaces/chunk/anvil/anvil_2203.py +69 -69
  164. amulet/level/interfaces/chunk/anvil/anvil_2529.py +19 -19
  165. amulet/level/interfaces/chunk/anvil/anvil_2681.py +76 -76
  166. amulet/level/interfaces/chunk/anvil/anvil_2709.py +19 -19
  167. amulet/level/interfaces/chunk/anvil/anvil_2844.py +267 -267
  168. amulet/level/interfaces/chunk/anvil/anvil_3463.py +19 -19
  169. amulet/level/interfaces/chunk/anvil/anvil_na.py +607 -607
  170. amulet/level/interfaces/chunk/anvil/base_anvil_interface.py +326 -326
  171. amulet/level/load.py +59 -59
  172. amulet/level/loader.py +95 -95
  173. amulet/level/translators/chunk/bedrock/__init__.py +267 -267
  174. amulet/level/translators/chunk/bedrock/bedrock_nbt_blockstate_translator.py +46 -46
  175. amulet/level/translators/chunk/bedrock/bedrock_numerical_translator.py +39 -39
  176. amulet/level/translators/chunk/bedrock/bedrock_psudo_numerical_translator.py +37 -37
  177. amulet/level/translators/chunk/java/java_1_18_translator.py +40 -40
  178. amulet/level/translators/chunk/java/java_blockstate_translator.py +94 -94
  179. amulet/level/translators/chunk/java/java_numerical_translator.py +62 -62
  180. amulet/libs/leveldb/__init__.py +7 -7
  181. amulet/operations/__init__.py +5 -5
  182. amulet/operations/clone.py +18 -18
  183. amulet/operations/delete_chunk.py +32 -32
  184. amulet/operations/fill.py +30 -30
  185. amulet/operations/paste.py +65 -65
  186. amulet/operations/replace.py +58 -58
  187. amulet/utils/__init__.py +14 -14
  188. amulet/utils/format_utils.py +41 -41
  189. amulet/utils/generator.py +15 -15
  190. amulet/utils/matrix.py +243 -243
  191. amulet/utils/numpy_helpers.py +46 -46
  192. amulet/utils/world_utils.py +349 -349
  193. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/METADATA +97 -97
  194. amulet_core-1.9.20.dist-info/RECORD +208 -0
  195. amulet_core-1.9.19.dist-info/RECORD +0 -208
  196. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/WHEEL +0 -0
  197. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/entry_points.txt +0 -0
  198. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/top_level.txt +0 -0
amulet/level/load.py CHANGED
@@ -1,59 +1,59 @@
1
- from __future__ import annotations
2
-
3
- from typing import Union
4
- import logging
5
-
6
- from amulet.api.level import World, Structure
7
-
8
- from amulet.api.wrapper import WorldFormatWrapper, StructureFormatWrapper
9
- from . import loader
10
-
11
- log = logging.getLogger(__name__)
12
-
13
-
14
- def load_level(path: str) -> Union[World, Structure]:
15
- """
16
- Load and return a :class:`World` or :class:`Structure` class exposing the data at ``path``
17
-
18
- Calls :func:`load_format` to try and find a :class:`FormatWrapper` that can open the data.
19
-
20
- If one is found it will wrap it with either a :class:`World` or :class:`Structure` class and return it.
21
-
22
- :param path: The file path to a file or directory for the object to be loaded.
23
- :return: A World or Structure class instance containing the data.
24
- :raises:
25
- LoaderNoneMatched: If no loader could be found that can open the data at path.
26
-
27
- Exception: Other errors.
28
- """
29
- log.info(f"Loading level {path}")
30
- format_wrapper = load_format(path)
31
- if isinstance(format_wrapper, WorldFormatWrapper):
32
- return World(path, format_wrapper)
33
- elif isinstance(format_wrapper, StructureFormatWrapper):
34
- return Structure(path, format_wrapper)
35
- else:
36
- raise Exception(
37
- f"FormatWrapper of type {format_wrapper.__class__.__name__} is not supported. Report this to a developer."
38
- )
39
-
40
-
41
- def load_format(path: str) -> Union[WorldFormatWrapper, StructureFormatWrapper]:
42
- """
43
- Find a valid subclass of :class:`FormatWrapper` and return the data wrapped in the class.
44
- This exposes a low level API to read and write the world data.
45
-
46
- Inspects the data at the given path to find a valid subclass of :class:`FormatWrapper`.
47
-
48
- If a valid wrapper is found it is set up and returned.
49
-
50
- This is not recommended for new users and does not include a history system.
51
-
52
- :param path: The file path to a file or directory for the object to be loaded.
53
- :return: An instance of WorldFormatWrapper or StructureFormatWrapper containing the data at path.
54
- :raises:
55
- LoaderNoneMatched: If no loader could be found that can open the data at path.
56
-
57
- Exception: Other errors.
58
- """
59
- return loader.Formats.get(path)(path)
1
+ from __future__ import annotations
2
+
3
+ from typing import Union
4
+ import logging
5
+
6
+ from amulet.api.level import World, Structure
7
+
8
+ from amulet.api.wrapper import WorldFormatWrapper, StructureFormatWrapper
9
+ from . import loader
10
+
11
+ log = logging.getLogger(__name__)
12
+
13
+
14
+ def load_level(path: str) -> Union[World, Structure]:
15
+ """
16
+ Load and return a :class:`World` or :class:`Structure` class exposing the data at ``path``
17
+
18
+ Calls :func:`load_format` to try and find a :class:`FormatWrapper` that can open the data.
19
+
20
+ If one is found it will wrap it with either a :class:`World` or :class:`Structure` class and return it.
21
+
22
+ :param path: The file path to a file or directory for the object to be loaded.
23
+ :return: A World or Structure class instance containing the data.
24
+ :raises:
25
+ LoaderNoneMatched: If no loader could be found that can open the data at path.
26
+
27
+ Exception: Other errors.
28
+ """
29
+ log.info(f"Loading level {path}")
30
+ format_wrapper = load_format(path)
31
+ if isinstance(format_wrapper, WorldFormatWrapper):
32
+ return World(path, format_wrapper)
33
+ elif isinstance(format_wrapper, StructureFormatWrapper):
34
+ return Structure(path, format_wrapper)
35
+ else:
36
+ raise Exception(
37
+ f"FormatWrapper of type {format_wrapper.__class__.__name__} is not supported. Report this to a developer."
38
+ )
39
+
40
+
41
+ def load_format(path: str) -> Union[WorldFormatWrapper, StructureFormatWrapper]:
42
+ """
43
+ Find a valid subclass of :class:`FormatWrapper` and return the data wrapped in the class.
44
+ This exposes a low level API to read and write the world data.
45
+
46
+ Inspects the data at the given path to find a valid subclass of :class:`FormatWrapper`.
47
+
48
+ If a valid wrapper is found it is set up and returned.
49
+
50
+ This is not recommended for new users and does not include a history system.
51
+
52
+ :param path: The file path to a file or directory for the object to be loaded.
53
+ :return: An instance of WorldFormatWrapper or StructureFormatWrapper containing the data at path.
54
+ :raises:
55
+ LoaderNoneMatched: If no loader could be found that can open the data at path.
56
+
57
+ Exception: Other errors.
58
+ """
59
+ return loader.Formats.get(path)(path)
amulet/level/loader.py CHANGED
@@ -1,95 +1,95 @@
1
- from __future__ import annotations
2
-
3
- import importlib
4
- from typing import AbstractSet, Any, Dict
5
- import pkgutil
6
- import logging
7
- import inspect
8
-
9
- from amulet.api.errors import LoaderNoneMatched
10
- from amulet.api.wrapper import FormatWrapper, Interface, Translator
11
-
12
- log = logging.getLogger(__name__)
13
-
14
- ParentPackage = ".".join(__name__.split(".")[:-1])
15
-
16
-
17
- class Loader:
18
- def __init__(
19
- self,
20
- base_class,
21
- object_type: str,
22
- package_name: str,
23
- create_instance=True,
24
- ):
25
- self._base_class = base_class
26
- self._object_type = object_type
27
- self._objects: Dict[str, Any] = {}
28
- self._create_instance = create_instance
29
- self._recursive_find(package_name)
30
-
31
- def _recursive_find(self, module_name: str):
32
- module = importlib.import_module(module_name)
33
-
34
- c = getattr(module, "export", None)
35
- if inspect.isclass(c) and issubclass(c, self._base_class):
36
- if self._create_instance:
37
- self._objects[module_name] = c()
38
- else:
39
- self._objects[module_name] = c
40
-
41
- log.debug(f'Enabled {self._object_type} "{module_name}"')
42
-
43
- elif hasattr(module, "__path__"):
44
- for _, sub_module_name, ispkg in pkgutil.iter_modules(
45
- module.__path__, module.__name__ + "."
46
- ):
47
- self._recursive_find(sub_module_name)
48
-
49
- def keys(self) -> AbstractSet[str]:
50
- """
51
- :return: The identifiers of all loaded objects
52
- """
53
- return self._objects.keys()
54
-
55
- def get(self, identifier: Any) -> Any:
56
- """
57
- Given an ``identifier`` will find a valid class and return it
58
-
59
- :param identifier: The identifier for the desired loaded object
60
- :return: The class for the object
61
- """
62
- object_id = self.identify(identifier)
63
- return self._objects[object_id]
64
-
65
- def identify(self, identifier: Any) -> str:
66
- if not self._objects:
67
- raise Exception(f"No {self._object_type} loaders found.")
68
- for object_name, obj in self._objects.items():
69
- if obj.is_valid(identifier):
70
- return object_name
71
-
72
- raise LoaderNoneMatched(
73
- f"Could not find a matching {self._object_type} for {identifier}"
74
- )
75
-
76
- def __contains__(self, item: str):
77
- return item in self._objects
78
-
79
- def report(self):
80
- print(f"{self._object_type} objects")
81
- for obj_name, obj in self._objects.items():
82
- print(obj_name, obj)
83
-
84
-
85
- Translators = Loader(Translator, "translator", f"{ParentPackage}.translators")
86
- Interfaces = Loader(Interface, "interface", f"{ParentPackage}.interfaces")
87
- Formats = Loader(
88
- FormatWrapper, "format", f"{ParentPackage}.formats", create_instance=False
89
- )
90
-
91
-
92
- if __name__ == "__main__":
93
- Formats.report()
94
- Interfaces.report()
95
- Translators.report()
1
+ from __future__ import annotations
2
+
3
+ import importlib
4
+ from typing import AbstractSet, Any, Dict
5
+ import pkgutil
6
+ import logging
7
+ import inspect
8
+
9
+ from amulet.api.errors import LoaderNoneMatched
10
+ from amulet.api.wrapper import FormatWrapper, Interface, Translator
11
+
12
+ log = logging.getLogger(__name__)
13
+
14
+ ParentPackage = ".".join(__name__.split(".")[:-1])
15
+
16
+
17
+ class Loader:
18
+ def __init__(
19
+ self,
20
+ base_class,
21
+ object_type: str,
22
+ package_name: str,
23
+ create_instance=True,
24
+ ):
25
+ self._base_class = base_class
26
+ self._object_type = object_type
27
+ self._objects: Dict[str, Any] = {}
28
+ self._create_instance = create_instance
29
+ self._recursive_find(package_name)
30
+
31
+ def _recursive_find(self, module_name: str):
32
+ module = importlib.import_module(module_name)
33
+
34
+ c = getattr(module, "export", None)
35
+ if inspect.isclass(c) and issubclass(c, self._base_class):
36
+ if self._create_instance:
37
+ self._objects[module_name] = c()
38
+ else:
39
+ self._objects[module_name] = c
40
+
41
+ log.debug(f'Enabled {self._object_type} "{module_name}"')
42
+
43
+ elif hasattr(module, "__path__"):
44
+ for _, sub_module_name, ispkg in pkgutil.iter_modules(
45
+ module.__path__, module.__name__ + "."
46
+ ):
47
+ self._recursive_find(sub_module_name)
48
+
49
+ def keys(self) -> AbstractSet[str]:
50
+ """
51
+ :return: The identifiers of all loaded objects
52
+ """
53
+ return self._objects.keys()
54
+
55
+ def get(self, identifier: Any) -> Any:
56
+ """
57
+ Given an ``identifier`` will find a valid class and return it
58
+
59
+ :param identifier: The identifier for the desired loaded object
60
+ :return: The class for the object
61
+ """
62
+ object_id = self.identify(identifier)
63
+ return self._objects[object_id]
64
+
65
+ def identify(self, identifier: Any) -> str:
66
+ if not self._objects:
67
+ raise Exception(f"No {self._object_type} loaders found.")
68
+ for object_name, obj in self._objects.items():
69
+ if obj.is_valid(identifier):
70
+ return object_name
71
+
72
+ raise LoaderNoneMatched(
73
+ f"Could not find a matching {self._object_type} for {identifier}"
74
+ )
75
+
76
+ def __contains__(self, item: str):
77
+ return item in self._objects
78
+
79
+ def report(self):
80
+ print(f"{self._object_type} objects")
81
+ for obj_name, obj in self._objects.items():
82
+ print(obj_name, obj)
83
+
84
+
85
+ Translators = Loader(Translator, "translator", f"{ParentPackage}.translators")
86
+ Interfaces = Loader(Interface, "interface", f"{ParentPackage}.interfaces")
87
+ Formats = Loader(
88
+ FormatWrapper, "format", f"{ParentPackage}.formats", create_instance=False
89
+ )
90
+
91
+
92
+ if __name__ == "__main__":
93
+ Formats.report()
94
+ Interfaces.report()
95
+ Translators.report()