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.
- amulet/__init__.py +27 -27
- amulet/__pyinstaller/__init__.py +2 -2
- amulet/__pyinstaller/hook-amulet.py +4 -4
- amulet/_version.py +21 -21
- amulet/api/__init__.py +2 -2
- amulet/api/abstract_base_entity.py +128 -128
- amulet/api/block.py +630 -630
- amulet/api/block_entity.py +71 -71
- amulet/api/cache.py +107 -107
- amulet/api/chunk/__init__.py +6 -6
- amulet/api/chunk/biomes.py +207 -207
- amulet/api/chunk/block_entity_dict.py +175 -175
- amulet/api/chunk/blocks.py +46 -46
- amulet/api/chunk/chunk.py +389 -389
- amulet/api/chunk/entity_list.py +75 -75
- amulet/api/chunk/status.py +167 -167
- amulet/api/data_types/__init__.py +4 -4
- amulet/api/data_types/generic_types.py +4 -4
- amulet/api/data_types/operation_types.py +16 -16
- amulet/api/data_types/world_types.py +49 -49
- amulet/api/data_types/wrapper_types.py +71 -71
- amulet/api/entity.py +74 -74
- amulet/api/errors.py +119 -119
- amulet/api/history/__init__.py +36 -36
- amulet/api/history/base/__init__.py +3 -3
- amulet/api/history/base/base_history.py +26 -26
- amulet/api/history/base/history_manager.py +63 -63
- amulet/api/history/base/revision_manager.py +73 -73
- amulet/api/history/changeable.py +15 -15
- amulet/api/history/data_types.py +7 -7
- amulet/api/history/history_manager/__init__.py +3 -3
- amulet/api/history/history_manager/container.py +102 -102
- amulet/api/history/history_manager/database.py +279 -279
- amulet/api/history/history_manager/meta.py +93 -93
- amulet/api/history/history_manager/object.py +116 -116
- amulet/api/history/revision_manager/__init__.py +2 -2
- amulet/api/history/revision_manager/disk.py +33 -33
- amulet/api/history/revision_manager/ram.py +12 -12
- amulet/api/item.py +75 -75
- amulet/api/level/__init__.py +4 -4
- amulet/api/level/base_level/__init__.py +1 -1
- amulet/api/level/base_level/base_level.py +1035 -1026
- amulet/api/level/base_level/chunk_manager.py +227 -227
- amulet/api/level/base_level/clone.py +389 -389
- amulet/api/level/base_level/player_manager.py +101 -101
- amulet/api/level/immutable_structure/__init__.py +1 -1
- amulet/api/level/immutable_structure/immutable_structure.py +94 -94
- amulet/api/level/immutable_structure/void_format_wrapper.py +117 -117
- amulet/api/level/structure.py +22 -22
- amulet/api/level/world.py +19 -19
- amulet/api/partial_3d_array/__init__.py +2 -2
- amulet/api/partial_3d_array/base_partial_3d_array.py +263 -263
- amulet/api/partial_3d_array/bounded_partial_3d_array.py +528 -528
- amulet/api/partial_3d_array/data_types.py +15 -15
- amulet/api/partial_3d_array/unbounded_partial_3d_array.py +229 -229
- amulet/api/partial_3d_array/util.py +152 -152
- amulet/api/player.py +65 -65
- amulet/api/registry/__init__.py +2 -2
- amulet/api/registry/base_registry.py +34 -34
- amulet/api/registry/biome_manager.py +153 -153
- amulet/api/registry/block_manager.py +156 -156
- amulet/api/selection/__init__.py +2 -2
- amulet/api/selection/abstract_selection.py +315 -315
- amulet/api/selection/box.py +805 -805
- amulet/api/selection/group.py +488 -488
- amulet/api/structure.py +37 -37
- amulet/api/wrapper/__init__.py +8 -8
- amulet/api/wrapper/chunk/interface.py +441 -441
- amulet/api/wrapper/chunk/translator.py +567 -567
- amulet/api/wrapper/format_wrapper.py +772 -772
- amulet/api/wrapper/structure_format_wrapper.py +116 -116
- amulet/api/wrapper/world_format_wrapper.py +63 -63
- amulet/level/__init__.py +1 -1
- amulet/level/formats/anvil_forge_world.py +40 -40
- amulet/level/formats/anvil_world/__init__.py +3 -3
- amulet/level/formats/anvil_world/_sector_manager.py +291 -384
- amulet/level/formats/anvil_world/data_pack/__init__.py +2 -2
- amulet/level/formats/anvil_world/data_pack/data_pack.py +224 -224
- amulet/level/formats/anvil_world/data_pack/data_pack_manager.py +77 -77
- amulet/level/formats/anvil_world/dimension.py +177 -177
- amulet/level/formats/anvil_world/format.py +769 -769
- amulet/level/formats/anvil_world/region.py +384 -384
- amulet/level/formats/construction/__init__.py +3 -3
- amulet/level/formats/construction/format_wrapper.py +515 -515
- amulet/level/formats/construction/interface.py +134 -134
- amulet/level/formats/construction/section.py +60 -60
- amulet/level/formats/construction/util.py +165 -165
- amulet/level/formats/leveldb_world/__init__.py +3 -3
- amulet/level/formats/leveldb_world/chunk.py +33 -33
- amulet/level/formats/leveldb_world/dimension.py +385 -419
- amulet/level/formats/leveldb_world/format.py +659 -641
- amulet/level/formats/leveldb_world/interface/chunk/__init__.py +36 -36
- amulet/level/formats/leveldb_world/interface/chunk/base_leveldb_interface.py +836 -836
- amulet/level/formats/leveldb_world/interface/chunk/generate_interface.py +31 -31
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_0.py +30 -30
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_1.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_10.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_11.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_12.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_13.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_14.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_15.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_16.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_17.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_18.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_19.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_2.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_20.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_21.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_22.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_23.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_24.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_25.py +24 -24
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_26.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_27.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_28.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_29.py +33 -33
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_3.py +57 -57
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_30.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_31.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_32.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_33.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_34.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_35.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_36.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_37.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_38.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_39.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_4.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_40.py +16 -16
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_5.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_6.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_7.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_8.py +180 -180
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_9.py +18 -18
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_chunk_versions.py +79 -79
- amulet/level/formats/mcstructure/__init__.py +3 -3
- amulet/level/formats/mcstructure/chunk.py +50 -50
- amulet/level/formats/mcstructure/format_wrapper.py +408 -408
- amulet/level/formats/mcstructure/interface.py +175 -175
- amulet/level/formats/schematic/__init__.py +3 -3
- amulet/level/formats/schematic/chunk.py +55 -55
- amulet/level/formats/schematic/data_types.py +4 -4
- amulet/level/formats/schematic/format_wrapper.py +373 -373
- amulet/level/formats/schematic/interface.py +142 -142
- amulet/level/formats/sponge_schem/__init__.py +4 -4
- amulet/level/formats/sponge_schem/chunk.py +62 -62
- amulet/level/formats/sponge_schem/format_wrapper.py +463 -463
- amulet/level/formats/sponge_schem/interface.py +118 -118
- amulet/level/formats/sponge_schem/varint/__init__.py +1 -1
- amulet/level/formats/sponge_schem/varint/varint.py +87 -87
- amulet/level/interfaces/chunk/anvil/anvil_0.py +72 -72
- amulet/level/interfaces/chunk/anvil/anvil_1444.py +336 -336
- amulet/level/interfaces/chunk/anvil/anvil_1466.py +94 -94
- amulet/level/interfaces/chunk/anvil/anvil_1467.py +37 -37
- amulet/level/interfaces/chunk/anvil/anvil_1484.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_1503.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_1519.py +34 -34
- amulet/level/interfaces/chunk/anvil/anvil_1901.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_1908.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_1912.py +21 -21
- amulet/level/interfaces/chunk/anvil/anvil_1934.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_2203.py +69 -69
- amulet/level/interfaces/chunk/anvil/anvil_2529.py +19 -19
- amulet/level/interfaces/chunk/anvil/anvil_2681.py +76 -76
- amulet/level/interfaces/chunk/anvil/anvil_2709.py +19 -19
- amulet/level/interfaces/chunk/anvil/anvil_2844.py +267 -267
- amulet/level/interfaces/chunk/anvil/anvil_3463.py +19 -19
- amulet/level/interfaces/chunk/anvil/anvil_na.py +607 -607
- amulet/level/interfaces/chunk/anvil/base_anvil_interface.py +326 -326
- amulet/level/load.py +59 -59
- amulet/level/loader.py +95 -95
- amulet/level/translators/chunk/bedrock/__init__.py +267 -267
- amulet/level/translators/chunk/bedrock/bedrock_nbt_blockstate_translator.py +46 -46
- amulet/level/translators/chunk/bedrock/bedrock_numerical_translator.py +39 -39
- amulet/level/translators/chunk/bedrock/bedrock_psudo_numerical_translator.py +37 -37
- amulet/level/translators/chunk/java/java_1_18_translator.py +40 -40
- amulet/level/translators/chunk/java/java_blockstate_translator.py +94 -94
- amulet/level/translators/chunk/java/java_numerical_translator.py +62 -62
- amulet/libs/leveldb/__init__.py +7 -7
- amulet/operations/__init__.py +5 -5
- amulet/operations/clone.py +18 -18
- amulet/operations/delete_chunk.py +32 -32
- amulet/operations/fill.py +30 -30
- amulet/operations/paste.py +65 -65
- amulet/operations/replace.py +58 -58
- amulet/utils/__init__.py +14 -14
- amulet/utils/format_utils.py +41 -41
- amulet/utils/generator.py +15 -15
- amulet/utils/matrix.py +243 -243
- amulet/utils/numpy_helpers.py +46 -46
- amulet/utils/world_utils.py +349 -349
- {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/METADATA +97 -97
- amulet_core-1.9.20.dist-info/RECORD +208 -0
- amulet_core-1.9.19.dist-info/RECORD +0 -208
- {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/WHEEL +0 -0
- {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/entry_points.txt +0 -0
- {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/top_level.txt +0 -0
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
from abc import abstractmethod
|
|
2
|
-
from typing import Generator
|
|
3
|
-
|
|
4
|
-
from amulet.utils.generator import generator_unpacker
|
|
5
|
-
|
|
6
|
-
from .base_history import BaseHistory
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class HistoryManager(BaseHistory):
|
|
10
|
-
"""The base class for all active history manager objects.
|
|
11
|
-
The HistoryManager tracks which objects have changed but is not aware of how they have changed.
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
def create_undo_point(self) -> bool:
|
|
15
|
-
"""
|
|
16
|
-
Find what has changed since the last undo point and optionally create a new undo point.
|
|
17
|
-
|
|
18
|
-
:return: Was an undo point created. If there were no changes no snapshot will be created.
|
|
19
|
-
"""
|
|
20
|
-
return generator_unpacker(self.create_undo_point_iter())
|
|
21
|
-
|
|
22
|
-
@abstractmethod
|
|
23
|
-
def create_undo_point_iter(self) -> Generator[float, None, bool]:
|
|
24
|
-
"""
|
|
25
|
-
Find what has changed since the last undo point and optionally create a new undo point.
|
|
26
|
-
|
|
27
|
-
:return: Was an undo point created. If there were no changes no snapshot will be created.
|
|
28
|
-
"""
|
|
29
|
-
raise NotImplementedError
|
|
30
|
-
|
|
31
|
-
@abstractmethod
|
|
32
|
-
def restore_last_undo_point(self):
|
|
33
|
-
"""
|
|
34
|
-
Restore the world to the state it was when self.create_undo_point was called.
|
|
35
|
-
|
|
36
|
-
If an operation errors there may be modifications made that did not get tracked.
|
|
37
|
-
|
|
38
|
-
This will revert those changes.
|
|
39
|
-
"""
|
|
40
|
-
raise NotImplementedError
|
|
41
|
-
|
|
42
|
-
@abstractmethod
|
|
43
|
-
def purge(self):
|
|
44
|
-
"""Unload all cached data. Effectively returns the class to its starting state."""
|
|
45
|
-
raise NotImplementedError
|
|
46
|
-
|
|
47
|
-
@property
|
|
48
|
-
@abstractmethod
|
|
49
|
-
def undo_count(self) -> int:
|
|
50
|
-
"""The number of times the :meth:`undo` method can be run."""
|
|
51
|
-
raise NotImplementedError
|
|
52
|
-
|
|
53
|
-
@property
|
|
54
|
-
@abstractmethod
|
|
55
|
-
def redo_count(self) -> int:
|
|
56
|
-
"""The number of times the :meth:`redo` method can be run."""
|
|
57
|
-
raise NotImplementedError
|
|
58
|
-
|
|
59
|
-
@property
|
|
60
|
-
@abstractmethod
|
|
61
|
-
def unsaved_changes(self) -> int:
|
|
62
|
-
"""The number of changes that have been made since the last save"""
|
|
63
|
-
raise NotImplementedError
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import Generator
|
|
3
|
+
|
|
4
|
+
from amulet.utils.generator import generator_unpacker
|
|
5
|
+
|
|
6
|
+
from .base_history import BaseHistory
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class HistoryManager(BaseHistory):
|
|
10
|
+
"""The base class for all active history manager objects.
|
|
11
|
+
The HistoryManager tracks which objects have changed but is not aware of how they have changed.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def create_undo_point(self) -> bool:
|
|
15
|
+
"""
|
|
16
|
+
Find what has changed since the last undo point and optionally create a new undo point.
|
|
17
|
+
|
|
18
|
+
:return: Was an undo point created. If there were no changes no snapshot will be created.
|
|
19
|
+
"""
|
|
20
|
+
return generator_unpacker(self.create_undo_point_iter())
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def create_undo_point_iter(self) -> Generator[float, None, bool]:
|
|
24
|
+
"""
|
|
25
|
+
Find what has changed since the last undo point and optionally create a new undo point.
|
|
26
|
+
|
|
27
|
+
:return: Was an undo point created. If there were no changes no snapshot will be created.
|
|
28
|
+
"""
|
|
29
|
+
raise NotImplementedError
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
def restore_last_undo_point(self):
|
|
33
|
+
"""
|
|
34
|
+
Restore the world to the state it was when self.create_undo_point was called.
|
|
35
|
+
|
|
36
|
+
If an operation errors there may be modifications made that did not get tracked.
|
|
37
|
+
|
|
38
|
+
This will revert those changes.
|
|
39
|
+
"""
|
|
40
|
+
raise NotImplementedError
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def purge(self):
|
|
44
|
+
"""Unload all cached data. Effectively returns the class to its starting state."""
|
|
45
|
+
raise NotImplementedError
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def undo_count(self) -> int:
|
|
50
|
+
"""The number of times the :meth:`undo` method can be run."""
|
|
51
|
+
raise NotImplementedError
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
@abstractmethod
|
|
55
|
+
def redo_count(self) -> int:
|
|
56
|
+
"""The number of times the :meth:`redo` method can be run."""
|
|
57
|
+
raise NotImplementedError
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
@abstractmethod
|
|
61
|
+
def unsaved_changes(self) -> int:
|
|
62
|
+
"""The number of changes that have been made since the last save"""
|
|
63
|
+
raise NotImplementedError
|
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
from abc import abstractmethod
|
|
2
|
-
from typing import List, Optional, Any
|
|
3
|
-
|
|
4
|
-
from .base_history import BaseHistory
|
|
5
|
-
|
|
6
|
-
StoredEntryType = Optional[Any]
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class RevisionManager(BaseHistory):
|
|
10
|
-
"""The base API for all passive history manager objects.
|
|
11
|
-
The RevisionManager stores the actual versions of the object to revert to."""
|
|
12
|
-
|
|
13
|
-
__slots__ = ("_revisions", "_current_revision_index", "_saved_revision_index")
|
|
14
|
-
|
|
15
|
-
def __init__(self, initial_state: StoredEntryType):
|
|
16
|
-
self._revisions: List[StoredEntryType] = [] # the data for each revision
|
|
17
|
-
self._current_revision_index: int = (
|
|
18
|
-
0 # the index into the above for the current data
|
|
19
|
-
)
|
|
20
|
-
self._saved_revision_index: int = (
|
|
21
|
-
0 # the index into the above for the saved version
|
|
22
|
-
)
|
|
23
|
-
self._store_entry(initial_state)
|
|
24
|
-
|
|
25
|
-
@property
|
|
26
|
-
def changed(self) -> bool:
|
|
27
|
-
"""Have there been modifications since the last save."""
|
|
28
|
-
return self._current_revision_index != self._saved_revision_index
|
|
29
|
-
|
|
30
|
-
def put_new_entry(self, entry: StoredEntryType):
|
|
31
|
-
"""Add a new entry to the database and increment the index."""
|
|
32
|
-
if len(self._revisions) > self._current_revision_index + 1:
|
|
33
|
-
# if there are upstream revisions delete them
|
|
34
|
-
del self._revisions[self._current_revision_index + 1 :]
|
|
35
|
-
if self._saved_revision_index > self._current_revision_index:
|
|
36
|
-
# we are starting a new branch and the save was on the old branch.
|
|
37
|
-
self._saved_revision_index = -1
|
|
38
|
-
self._store_entry(entry)
|
|
39
|
-
self._current_revision_index += 1
|
|
40
|
-
|
|
41
|
-
@abstractmethod
|
|
42
|
-
def _store_entry(self, entry: StoredEntryType):
|
|
43
|
-
"""Store the entry data as required."""
|
|
44
|
-
raise NotImplementedError
|
|
45
|
-
|
|
46
|
-
@abstractmethod
|
|
47
|
-
def get_current_entry(self):
|
|
48
|
-
"""Get the entry at the current revision."""
|
|
49
|
-
raise NotImplementedError
|
|
50
|
-
|
|
51
|
-
def undo(self):
|
|
52
|
-
"""Decrement the state of the entry to the previous revision."""
|
|
53
|
-
if self._current_revision_index <= 0:
|
|
54
|
-
raise Exception(
|
|
55
|
-
"Cannot undo past revision 0"
|
|
56
|
-
) # if run there is a bug in the code
|
|
57
|
-
self._current_revision_index -= 1
|
|
58
|
-
|
|
59
|
-
def redo(self):
|
|
60
|
-
"""Increment the state of the entry to the next revision."""
|
|
61
|
-
if self._current_revision_index >= len(self._revisions):
|
|
62
|
-
raise Exception(
|
|
63
|
-
"Cannot redo past the highest revision"
|
|
64
|
-
) # if run there is a bug in the code
|
|
65
|
-
self._current_revision_index += 1
|
|
66
|
-
|
|
67
|
-
def mark_saved(self):
|
|
68
|
-
"""Let the class know that the current state has been saved."""
|
|
69
|
-
self._saved_revision_index = self._current_revision_index
|
|
70
|
-
|
|
71
|
-
@property
|
|
72
|
-
def is_deleted(self) -> bool:
|
|
73
|
-
return self._revisions[self._current_revision_index] is None
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import List, Optional, Any
|
|
3
|
+
|
|
4
|
+
from .base_history import BaseHistory
|
|
5
|
+
|
|
6
|
+
StoredEntryType = Optional[Any]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RevisionManager(BaseHistory):
|
|
10
|
+
"""The base API for all passive history manager objects.
|
|
11
|
+
The RevisionManager stores the actual versions of the object to revert to."""
|
|
12
|
+
|
|
13
|
+
__slots__ = ("_revisions", "_current_revision_index", "_saved_revision_index")
|
|
14
|
+
|
|
15
|
+
def __init__(self, initial_state: StoredEntryType):
|
|
16
|
+
self._revisions: List[StoredEntryType] = [] # the data for each revision
|
|
17
|
+
self._current_revision_index: int = (
|
|
18
|
+
0 # the index into the above for the current data
|
|
19
|
+
)
|
|
20
|
+
self._saved_revision_index: int = (
|
|
21
|
+
0 # the index into the above for the saved version
|
|
22
|
+
)
|
|
23
|
+
self._store_entry(initial_state)
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def changed(self) -> bool:
|
|
27
|
+
"""Have there been modifications since the last save."""
|
|
28
|
+
return self._current_revision_index != self._saved_revision_index
|
|
29
|
+
|
|
30
|
+
def put_new_entry(self, entry: StoredEntryType):
|
|
31
|
+
"""Add a new entry to the database and increment the index."""
|
|
32
|
+
if len(self._revisions) > self._current_revision_index + 1:
|
|
33
|
+
# if there are upstream revisions delete them
|
|
34
|
+
del self._revisions[self._current_revision_index + 1 :]
|
|
35
|
+
if self._saved_revision_index > self._current_revision_index:
|
|
36
|
+
# we are starting a new branch and the save was on the old branch.
|
|
37
|
+
self._saved_revision_index = -1
|
|
38
|
+
self._store_entry(entry)
|
|
39
|
+
self._current_revision_index += 1
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def _store_entry(self, entry: StoredEntryType):
|
|
43
|
+
"""Store the entry data as required."""
|
|
44
|
+
raise NotImplementedError
|
|
45
|
+
|
|
46
|
+
@abstractmethod
|
|
47
|
+
def get_current_entry(self):
|
|
48
|
+
"""Get the entry at the current revision."""
|
|
49
|
+
raise NotImplementedError
|
|
50
|
+
|
|
51
|
+
def undo(self):
|
|
52
|
+
"""Decrement the state of the entry to the previous revision."""
|
|
53
|
+
if self._current_revision_index <= 0:
|
|
54
|
+
raise Exception(
|
|
55
|
+
"Cannot undo past revision 0"
|
|
56
|
+
) # if run there is a bug in the code
|
|
57
|
+
self._current_revision_index -= 1
|
|
58
|
+
|
|
59
|
+
def redo(self):
|
|
60
|
+
"""Increment the state of the entry to the next revision."""
|
|
61
|
+
if self._current_revision_index >= len(self._revisions):
|
|
62
|
+
raise Exception(
|
|
63
|
+
"Cannot redo past the highest revision"
|
|
64
|
+
) # if run there is a bug in the code
|
|
65
|
+
self._current_revision_index += 1
|
|
66
|
+
|
|
67
|
+
def mark_saved(self):
|
|
68
|
+
"""Let the class know that the current state has been saved."""
|
|
69
|
+
self._saved_revision_index = self._current_revision_index
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def is_deleted(self) -> bool:
|
|
73
|
+
return self._revisions[self._current_revision_index] is None
|
amulet/api/history/changeable.py
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
class Changeable:
|
|
2
|
-
"""A class to track if an object has been changed."""
|
|
3
|
-
|
|
4
|
-
def __init__(self):
|
|
5
|
-
self._changed = False
|
|
6
|
-
|
|
7
|
-
@property
|
|
8
|
-
def changed(self) -> bool:
|
|
9
|
-
"""Has the object been modified since the last revision."""
|
|
10
|
-
return self._changed
|
|
11
|
-
|
|
12
|
-
@changed.setter
|
|
13
|
-
def changed(self, changed: bool):
|
|
14
|
-
assert isinstance(changed, bool), "Changed must be a bool"
|
|
15
|
-
self._changed = changed
|
|
1
|
+
class Changeable:
|
|
2
|
+
"""A class to track if an object has been changed."""
|
|
3
|
+
|
|
4
|
+
def __init__(self):
|
|
5
|
+
self._changed = False
|
|
6
|
+
|
|
7
|
+
@property
|
|
8
|
+
def changed(self) -> bool:
|
|
9
|
+
"""Has the object been modified since the last revision."""
|
|
10
|
+
return self._changed
|
|
11
|
+
|
|
12
|
+
@changed.setter
|
|
13
|
+
def changed(self, changed: bool):
|
|
14
|
+
assert isinstance(changed, bool), "Changed must be a bool"
|
|
15
|
+
self._changed = changed
|
amulet/api/history/data_types.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from typing import Optional, Any
|
|
2
|
-
from .changeable import Changeable
|
|
3
|
-
|
|
4
|
-
EntryKeyType = Any # The key an entry is stored under
|
|
5
|
-
EntryType = Optional[
|
|
6
|
-
Changeable
|
|
7
|
-
] # None is reserved for if the entry was deleted/did not exist
|
|
1
|
+
from typing import Optional, Any
|
|
2
|
+
from .changeable import Changeable
|
|
3
|
+
|
|
4
|
+
EntryKeyType = Any # The key an entry is stored under
|
|
5
|
+
EntryType = Optional[
|
|
6
|
+
Changeable
|
|
7
|
+
] # None is reserved for if the entry was deleted/did not exist
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
from .object import ObjectHistoryManager
|
|
2
|
-
from .database import DatabaseHistoryManager
|
|
3
|
-
from .meta import MetaHistoryManager
|
|
1
|
+
from .object import ObjectHistoryManager
|
|
2
|
+
from .database import DatabaseHistoryManager
|
|
3
|
+
from .meta import MetaHistoryManager
|
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
from abc import abstractmethod
|
|
2
|
-
from typing import List, Any
|
|
3
|
-
|
|
4
|
-
from amulet.api.history.base.history_manager import HistoryManager
|
|
5
|
-
|
|
6
|
-
SnapshotType = Any
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class ContainerHistoryManager(HistoryManager):
|
|
10
|
-
def __init__(self):
|
|
11
|
-
self._snapshots: List[SnapshotType] = []
|
|
12
|
-
self._snapshot_index: int = -1
|
|
13
|
-
|
|
14
|
-
# the snapshot that was saved or the save branches off from
|
|
15
|
-
self._last_save_snapshot = -1
|
|
16
|
-
self._branch_save_count = 0 # if the user saves, undoes and does a new operation a save branch will be lost
|
|
17
|
-
# This is the number of changes on that branch
|
|
18
|
-
|
|
19
|
-
@abstractmethod
|
|
20
|
-
def _check_snapshot(self, snapshot: SnapshotType):
|
|
21
|
-
raise NotImplementedError
|
|
22
|
-
|
|
23
|
-
def _register_snapshot(self, snapshot: SnapshotType) -> bool:
|
|
24
|
-
"""Create a snapshot if it contains data.
|
|
25
|
-
|
|
26
|
-
:param snapshot: The snapshot data to save.
|
|
27
|
-
:return: True if the snapshot was created, false otherwise.
|
|
28
|
-
"""
|
|
29
|
-
self._check_snapshot(snapshot)
|
|
30
|
-
if snapshot:
|
|
31
|
-
if self._last_save_snapshot > self._snapshot_index:
|
|
32
|
-
# if the user has undone changes and made more changes things get a bit messy
|
|
33
|
-
# This fixes the property storing the number of changes since the last save.
|
|
34
|
-
self._branch_save_count += (
|
|
35
|
-
self._last_save_snapshot - self._snapshot_index
|
|
36
|
-
)
|
|
37
|
-
self._last_save_snapshot = self._snapshot_index
|
|
38
|
-
self._snapshot_index += 1
|
|
39
|
-
# delete all upstream snapshots
|
|
40
|
-
del self._snapshots[self._snapshot_index :]
|
|
41
|
-
self._snapshots.append(snapshot)
|
|
42
|
-
return True
|
|
43
|
-
return False
|
|
44
|
-
|
|
45
|
-
def mark_saved(self):
|
|
46
|
-
"""Let the class know that the current state has been saved."""
|
|
47
|
-
self._last_save_snapshot = self._snapshot_index
|
|
48
|
-
self._branch_save_count = 0
|
|
49
|
-
self._mark_saved()
|
|
50
|
-
|
|
51
|
-
@abstractmethod
|
|
52
|
-
def _mark_saved(self):
|
|
53
|
-
raise NotImplementedError
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def undo_count(self) -> int:
|
|
57
|
-
return self._snapshot_index + 1
|
|
58
|
-
|
|
59
|
-
@property
|
|
60
|
-
def redo_count(self) -> int:
|
|
61
|
-
return len(self._snapshots) - (self._snapshot_index + 1)
|
|
62
|
-
|
|
63
|
-
@property
|
|
64
|
-
def unsaved_changes(self) -> int:
|
|
65
|
-
"""The number of changes that have been made since the last save"""
|
|
66
|
-
return (
|
|
67
|
-
abs(self._snapshot_index - self._last_save_snapshot)
|
|
68
|
-
+ self._branch_save_count
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
def undo(self):
|
|
72
|
-
"""Undoes the last set of changes to the database"""
|
|
73
|
-
if self.undo_count > 0:
|
|
74
|
-
snapshot = self._snapshots[self._snapshot_index]
|
|
75
|
-
self._undo(snapshot)
|
|
76
|
-
self._snapshot_index -= 1
|
|
77
|
-
|
|
78
|
-
@abstractmethod
|
|
79
|
-
def _undo(self, snapshot: SnapshotType):
|
|
80
|
-
raise NotImplementedError
|
|
81
|
-
|
|
82
|
-
def redo(self):
|
|
83
|
-
"""Redoes the last set of changes to the database"""
|
|
84
|
-
if self.redo_count > 0:
|
|
85
|
-
self._snapshot_index += 1
|
|
86
|
-
snapshot = self._snapshots[self._snapshot_index]
|
|
87
|
-
self._redo(snapshot)
|
|
88
|
-
|
|
89
|
-
@abstractmethod
|
|
90
|
-
def _redo(self, snapshot: SnapshotType):
|
|
91
|
-
raise NotImplementedError
|
|
92
|
-
|
|
93
|
-
@property
|
|
94
|
-
def changed(self) -> bool:
|
|
95
|
-
return bool(self.unsaved_changes)
|
|
96
|
-
|
|
97
|
-
def purge(self):
|
|
98
|
-
"""Unload all cached data. Effectively returns the class to its starting state."""
|
|
99
|
-
self._snapshots.clear()
|
|
100
|
-
self._snapshot_index: int = -1
|
|
101
|
-
self._last_save_snapshot = -1
|
|
102
|
-
self._branch_save_count = 0
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import List, Any
|
|
3
|
+
|
|
4
|
+
from amulet.api.history.base.history_manager import HistoryManager
|
|
5
|
+
|
|
6
|
+
SnapshotType = Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ContainerHistoryManager(HistoryManager):
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self._snapshots: List[SnapshotType] = []
|
|
12
|
+
self._snapshot_index: int = -1
|
|
13
|
+
|
|
14
|
+
# the snapshot that was saved or the save branches off from
|
|
15
|
+
self._last_save_snapshot = -1
|
|
16
|
+
self._branch_save_count = 0 # if the user saves, undoes and does a new operation a save branch will be lost
|
|
17
|
+
# This is the number of changes on that branch
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def _check_snapshot(self, snapshot: SnapshotType):
|
|
21
|
+
raise NotImplementedError
|
|
22
|
+
|
|
23
|
+
def _register_snapshot(self, snapshot: SnapshotType) -> bool:
|
|
24
|
+
"""Create a snapshot if it contains data.
|
|
25
|
+
|
|
26
|
+
:param snapshot: The snapshot data to save.
|
|
27
|
+
:return: True if the snapshot was created, false otherwise.
|
|
28
|
+
"""
|
|
29
|
+
self._check_snapshot(snapshot)
|
|
30
|
+
if snapshot:
|
|
31
|
+
if self._last_save_snapshot > self._snapshot_index:
|
|
32
|
+
# if the user has undone changes and made more changes things get a bit messy
|
|
33
|
+
# This fixes the property storing the number of changes since the last save.
|
|
34
|
+
self._branch_save_count += (
|
|
35
|
+
self._last_save_snapshot - self._snapshot_index
|
|
36
|
+
)
|
|
37
|
+
self._last_save_snapshot = self._snapshot_index
|
|
38
|
+
self._snapshot_index += 1
|
|
39
|
+
# delete all upstream snapshots
|
|
40
|
+
del self._snapshots[self._snapshot_index :]
|
|
41
|
+
self._snapshots.append(snapshot)
|
|
42
|
+
return True
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
def mark_saved(self):
|
|
46
|
+
"""Let the class know that the current state has been saved."""
|
|
47
|
+
self._last_save_snapshot = self._snapshot_index
|
|
48
|
+
self._branch_save_count = 0
|
|
49
|
+
self._mark_saved()
|
|
50
|
+
|
|
51
|
+
@abstractmethod
|
|
52
|
+
def _mark_saved(self):
|
|
53
|
+
raise NotImplementedError
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def undo_count(self) -> int:
|
|
57
|
+
return self._snapshot_index + 1
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def redo_count(self) -> int:
|
|
61
|
+
return len(self._snapshots) - (self._snapshot_index + 1)
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def unsaved_changes(self) -> int:
|
|
65
|
+
"""The number of changes that have been made since the last save"""
|
|
66
|
+
return (
|
|
67
|
+
abs(self._snapshot_index - self._last_save_snapshot)
|
|
68
|
+
+ self._branch_save_count
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
def undo(self):
|
|
72
|
+
"""Undoes the last set of changes to the database"""
|
|
73
|
+
if self.undo_count > 0:
|
|
74
|
+
snapshot = self._snapshots[self._snapshot_index]
|
|
75
|
+
self._undo(snapshot)
|
|
76
|
+
self._snapshot_index -= 1
|
|
77
|
+
|
|
78
|
+
@abstractmethod
|
|
79
|
+
def _undo(self, snapshot: SnapshotType):
|
|
80
|
+
raise NotImplementedError
|
|
81
|
+
|
|
82
|
+
def redo(self):
|
|
83
|
+
"""Redoes the last set of changes to the database"""
|
|
84
|
+
if self.redo_count > 0:
|
|
85
|
+
self._snapshot_index += 1
|
|
86
|
+
snapshot = self._snapshots[self._snapshot_index]
|
|
87
|
+
self._redo(snapshot)
|
|
88
|
+
|
|
89
|
+
@abstractmethod
|
|
90
|
+
def _redo(self, snapshot: SnapshotType):
|
|
91
|
+
raise NotImplementedError
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def changed(self) -> bool:
|
|
95
|
+
return bool(self.unsaved_changes)
|
|
96
|
+
|
|
97
|
+
def purge(self):
|
|
98
|
+
"""Unload all cached data. Effectively returns the class to its starting state."""
|
|
99
|
+
self._snapshots.clear()
|
|
100
|
+
self._snapshot_index: int = -1
|
|
101
|
+
self._last_save_snapshot = -1
|
|
102
|
+
self._branch_save_count = 0
|