pylitematic 0.0.2__py3-none-any.whl → 0.0.3__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.
pylitematic/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
- __version__ = "0.0.2"
1
+ __version__ = "0.0.3"
2
2
 
3
3
  from .block_state import BlockState
4
4
  from .geometry import BlockPosition, Size3D
5
5
  from .region import Region
6
- from .resource_location import ResourceLocation
6
+ from .resource_location import BlockId
7
7
  from .schematic import Schematic
@@ -14,72 +14,6 @@ ENUM_VALUE_REGEX: str = r"[a-z]+(_[a-z]+)*" # snake case
14
14
  ENUM_VALUE_PATTERN: re.Pattern = re.compile(ENUM_VALUE_REGEX)
15
15
 
16
16
 
17
- class Property():
18
-
19
- __slots__ = ("_name", "_value")
20
-
21
- def __init__(self, name: str, value: Any | PropertyValue) -> None:
22
- if not PROPERTY_NAME_PATTERN.fullmatch(name):
23
- raise ValueError(f"Invalid property name {name!r}")
24
- self._name = name
25
-
26
- if not isinstance(value, PropertyValue):
27
- value = PropertyValue.value_factory(value=value)
28
- self._value = value
29
-
30
- def __str__(self) -> str:
31
- return f"{self._name}={self._value}"
32
-
33
- def __repr__(self) -> str:
34
- return (
35
- f"{type(self).__name__}("
36
- f"name: {self._name}, value: {self._value!r})")
37
-
38
- def __eq__(self, other: Any) -> bool:
39
- if not isinstance(other, Property):
40
- return NotImplemented
41
- return (self.name, self.value) == (other.name, other.value)
42
-
43
- def __lt__(self, other: Any) -> bool:
44
- if not isinstance(other, Property):
45
- return NotImplemented
46
- return (self.name, self.value) < (other.name, other.value)
47
-
48
- @property
49
- def name(self) -> str:
50
- return self._name
51
-
52
- @property
53
- def value(self) -> Any:
54
- return self._value.get()
55
-
56
- @value.setter
57
- def value(self, value: Any) -> None:
58
- self._value.set(value)
59
-
60
- def to_string(self) -> str:
61
- return str(self)
62
-
63
- @staticmethod
64
- def from_string(string: str, value: str | None = None) -> Property:
65
- if value is None:
66
- # tread string as "name=value"
67
- try:
68
- string, value = string.split("=")
69
- except ValueError as exc:
70
- raise ValueError(f"Invalid property string {string!r}") from exc
71
- return Property(name=string, value=PropertyValue.from_string(value))
72
-
73
- def to_nbt(self) -> tuple[str, nbtlib.String]:
74
- # return nbtlib.Compound(Name=nbtlib.String(self._name), Value=self._value.to_nbt()})
75
- return self._name, self._value.to_nbt()
76
-
77
- @staticmethod
78
- def from_nbt(name: str, nbt: nbtlib.String) -> Property:
79
- # return Property.from_string(name=nbt["Name"], value=str(nbt["Value"]))
80
- return Property.from_string(string=name, value=str(nbt))
81
-
82
-
83
17
  class Properties(dict):
84
18
 
85
19
  def __init__(self, *args, **kwargs):
@@ -4,7 +4,7 @@ from copy import deepcopy
4
4
  from nbtlib import Compound
5
5
  from typing import Any, Iterator
6
6
 
7
- from .resource_location import ResourceLocation
7
+ from .resource_location import BlockId
8
8
  from .block_property import Properties
9
9
 
10
10
 
@@ -12,8 +12,15 @@ class BlockState:
12
12
 
13
13
  __slots__ = ("_id", "_props")
14
14
 
15
- def __init__(self, _id: str, **props: Any) -> None:
16
- self._id: ResourceLocation = ResourceLocation.from_string(_id)
15
+ def __init__(self, _id: str | BlockId, **props: Any) -> None:
16
+ if isinstance(_id, str):
17
+ _id = BlockId.from_string(_id)
18
+ elif not isinstance(_id, BlockId):
19
+ raise TypeError(
20
+ f"'_id' has to be str or {BlockId.__name__}, got"
21
+ f" {type(_id).__name__}")
22
+ self._id: BlockId = _id
23
+
17
24
  self._props: Properties = Properties(**props)
18
25
 
19
26
  def __getitem__(self, name: str) -> Any:
@@ -58,8 +65,8 @@ class BlockState:
58
65
  f"id: {self._id!r}, props: {self._props!r})")
59
66
 
60
67
  @property
61
- def id(self) -> str:
62
- return str(self._id)
68
+ def id(self) -> BlockId:
69
+ return self._id
63
70
 
64
71
  def props(self) -> Iterator[tuple[str, Any]]:
65
72
  return self._props.items()
pylitematic/geometry.py CHANGED
@@ -191,3 +191,17 @@ class Size3D(Vec3i):
191
191
  return (
192
192
  f"{type(self).__name__}("
193
193
  f"width={self.width}, height={self.height}, length={self.length})")
194
+
195
+ def end(self, axis: tuple[int,...] | int | None = None) -> BlockPosition:
196
+ limit = self - np.sign(self)
197
+
198
+ if axis is None:
199
+ return BlockPosition(*limit)
200
+
201
+ if not isinstance(axis, tuple):
202
+ axis = (axis, )
203
+
204
+ ret = np.zeros_like(limit, dtype=int)
205
+ for ax in axis:
206
+ ret[ax] = limit[ax]
207
+ return BlockPosition(*ret)
pylitematic/region.py CHANGED
@@ -9,7 +9,7 @@ from typing import Iterator
9
9
 
10
10
  from .block_state import BlockState
11
11
  from .geometry import BlockPosition, Size3D
12
- from .resource_location import ResourceLocation
12
+ from .resource_location import BlockId
13
13
 
14
14
 
15
15
  AIR = BlockState("air")
@@ -28,10 +28,11 @@ class Region:
28
28
  self._palette_map: dict[BlockState, int] = {AIR: 0}
29
29
  self._blocks = np.zeros(abs(self._size), dtype=int)
30
30
 
31
- self._entities: list[nbtlib.Compound] = []
32
- self._tile_entities: list[nbtlib.Compound] = []
33
- self._block_ticks: list[nbtlib.Compound] = []
34
- self._fluid_ticks: list[nbtlib.Compound] = []
31
+ # TODO: Add support
32
+ self._entities = nbtlib.List[nbtlib.Compound]()
33
+ self._tile_entities = nbtlib.List[nbtlib.Compound]()
34
+ self._block_ticks = nbtlib.List[nbtlib.Compound]()
35
+ self._fluid_ticks = nbtlib.List[nbtlib.Compound]()
35
36
 
36
37
  def __contains__(self, item) -> bool:
37
38
  if isinstance(item, BlockPosition):
@@ -41,50 +42,26 @@ class Region:
41
42
  if index is None:
42
43
  return False
43
44
  return np.any(self._blocks == index)
44
- elif isinstance(item, ResourceLocation):
45
+ elif isinstance(item, BlockId):
45
46
  return any(
46
47
  (bs.id == item and np.any(self._blocks == idx))
47
48
  for bs, idx in self._palette_map.items())
48
49
  else:
49
50
  return False
50
51
 
51
- def _expand_index(self, index):
52
- if not isinstance(index, tuple):
53
- index = (index,)
54
- ndim = self._blocks.ndim
55
- result = []
56
- for item in index:
57
- if item is Ellipsis:
58
- result.extend([slice(None)] * (ndim - len(index) + 1))
59
- else:
60
- result.append(item)
61
- while len(result) < ndim:
62
- result.append(slice(None))
63
- return tuple(result)
52
+ def __eq__(self, other) -> bool:
53
+ palette = np.array(self._palette, dtype=object)
64
54
 
65
- def _to_internal(self, pos):
66
- index = []
67
- for i, item in enumerate(pos):
68
- offset = self.lower[i]
69
- if isinstance(item, int):
70
- index.append(item - offset)
71
- elif isinstance(item, slice):
72
- start = item.start - offset if item.start is not None else None
73
- stop = item.stop - offset if item.stop is not None else None
74
- index.append(slice(start, stop, item.step))
75
- else:
76
- index.append(item)
77
- return tuple(index)
55
+ if isinstance(other, BlockState):
56
+ matches = np.array([state == other for state in palette])
57
+ return matches[self._blocks]
78
58
 
79
- def _from_internal(self, index: tuple[int, int, int]) -> BlockPosition:
80
- return self.lower + index
59
+ elif isinstance(other, BlockId):
60
+ matches = np.array([state.id == other for state in palette])
61
+ return matches[self._blocks]
81
62
 
82
- def _key_to_index(self, key):
83
- if isinstance(key, BlockPosition):
84
- index = tuple(key)
85
63
  else:
86
- index = self._expand_index(key)
87
- return self._to_internal(index)
64
+ return NotImplemented
88
65
 
89
66
  def __getitem__(self, key):
90
67
  index = self._key_to_index(key)
@@ -126,6 +103,44 @@ class Region:
126
103
  raise TypeError(
127
104
  "Value must be a BlockState or a list of BlockStates")
128
105
 
106
+ def _expand_index(self, index):
107
+ if not isinstance(index, tuple):
108
+ index = (index,)
109
+ ndim = self._blocks.ndim
110
+ result = []
111
+ for item in index:
112
+ if item is Ellipsis:
113
+ result.extend([slice(None)] * (ndim - len(index) + 1))
114
+ else:
115
+ result.append(item)
116
+ while len(result) < ndim:
117
+ result.append(slice(None))
118
+ return tuple(result)
119
+
120
+ def _to_internal(self, pos):
121
+ index = []
122
+ for i, item in enumerate(pos):
123
+ offset = self.lower[i]
124
+ if isinstance(item, int):
125
+ index.append(item - offset)
126
+ elif isinstance(item, slice):
127
+ start = item.start - offset if item.start is not None else None
128
+ stop = item.stop - offset if item.stop is not None else None
129
+ index.append(slice(start, stop, item.step))
130
+ else:
131
+ index.append(item)
132
+ return tuple(index)
133
+
134
+ def _from_internal(self, index: tuple[int, int, int]) -> BlockPosition:
135
+ return self.lower + index
136
+
137
+ def _key_to_index(self, key):
138
+ if isinstance(key, BlockPosition):
139
+ index = tuple(key)
140
+ else:
141
+ index = self._expand_index(key)
142
+ return self._to_internal(index)
143
+
129
144
  def compact_palette(self) -> None:
130
145
  idx = np.unique(self._blocks)
131
146
  # always include minecraft:air in a palette
@@ -171,14 +186,6 @@ class Region:
171
186
  )
172
187
  return nbtlib.LongArray([twos.to_signed(x, 64) for x in chunks])
173
188
 
174
- @staticmethod
175
- def inclusive_end(
176
- size: Size3D,
177
- pos: BlockPosition = BlockPosition(0, 0, 0),
178
- ) -> BlockPosition:
179
- return pos + (size - np.sign(size))
180
- # return pos + np.where(size > 0, size - 1, size + 1)
181
-
182
189
  @property
183
190
  def size(self) -> Size3D:
184
191
  return self._size
@@ -193,7 +200,7 @@ class Region:
193
200
 
194
201
  @cached_property
195
202
  def limit(self) -> BlockPosition:
196
- return self.inclusive_end(pos=self._origin, size=self._size)
203
+ return self._origin + self._size.end()
197
204
 
198
205
  @cached_property
199
206
  def start(self) -> BlockPosition:
@@ -201,7 +208,7 @@ class Region:
201
208
 
202
209
  @cached_property
203
210
  def end(self) -> BlockPosition:
204
- return self.inclusive_end(pos=self.start, size=self._size)
211
+ return self._size.end()
205
212
 
206
213
  @property
207
214
  def width(self) -> int:
@@ -67,3 +67,7 @@ class ResourceLocation:
67
67
  @staticmethod
68
68
  def from_nbt(nbt: nbtlib.String) -> ResourceLocation:
69
69
  return ResourceLocation.from_string(str(nbt))
70
+
71
+
72
+ class BlockId(ResourceLocation):
73
+ ...
pylitematic/schematic.py CHANGED
@@ -8,8 +8,8 @@ import time
8
8
  import twos
9
9
  from typing import Iterator
10
10
 
11
- from .geometry import BlockPosition, Size3D
12
- from .region import Region
11
+ from pylitematic.geometry import BlockPosition, Size3D
12
+ from pylitematic.region import Region
13
13
 
14
14
 
15
15
  DEFAULT_VERSION_MAJOR: int = 7
@@ -142,7 +142,6 @@ class Schematic:
142
142
 
143
143
  def add_region(self, name: str, region: Region) -> None:
144
144
  self._regions[name] = region
145
- self._update()
146
145
 
147
146
  def remove_region(self, name: str) -> Region:
148
147
  return self._regions.pop(name)
@@ -214,7 +213,10 @@ class Schematic:
214
213
 
215
214
  name = meta["Name"].unpack()
216
215
  author = meta["Author"].unpack()
217
- description = meta["Description"].unpack()
216
+ try:
217
+ desc = meta["Description"].unpack()
218
+ except KeyError:
219
+ desc = ""
218
220
 
219
221
  preview = meta.get("PreviewImageData")
220
222
  if preview is not None:
@@ -248,7 +250,7 @@ class Schematic:
248
250
  schem = Schematic(
249
251
  name=name,
250
252
  author=author,
251
- description=description,
253
+ description=desc,
252
254
  regions=regions,
253
255
  preview=preview,
254
256
  version_major=major,
pylitematic/test.py CHANGED
@@ -1,39 +1,71 @@
1
1
  import numpy as np
2
2
  import pathlib
3
- from pylitematic import BlockPosition, BlockState, ResourceLocation, Schematic
3
+ from pylitematic import BlockPosition, BlockId, BlockState, Region, Schematic, Size3D
4
4
 
5
- path = pathlib.Path("/mnt/d/minecraft/schematics/Litematica/test/subs.litematic")
6
- path = pathlib.Path("/mnt/d/minecraft/schematics/Litematica/test/creeper_test.litematic")
7
- path = pathlib.Path("/mnt/d/minecraft/schematics/Litematica/test/regions.litematic")
8
- stone = BlockState.from_string("minecraft:stone")
9
- dirt = BlockState.from_string("minecraft:dirt")
10
- s = Schematic.load(path)
11
- print(f"{s.volume=} {s.size=} {s.bounds=}")
12
- for name, reg in s.regions():
13
- print(name)
14
- print(f"\t{reg.shape=} {reg.volume=} {reg.block_count=}")
15
- print(f"\t{reg.origin=!s} {reg.limit=!s}")
16
- print(f"\t{reg.start=!s} {reg.end=!s}")
17
- print(f"\t{reg.lower=!s} {reg.upper=!s} {reg.size=}")
18
- # print(f"\t{reg[..., 1, 0]}")
19
- # print(f"\t{reg[:][1][0]}")
20
- # print(f"\t{reg[BlockPosition(0, 1, 0)]}")
21
- # reg[1,1,1] = BlockState.from_string("minecraft:stone")
22
- # print("lol: ", reg[reg.end])
23
- reg[0,:,0] = BlockState("minecraft:obsidian")
24
- reg[0,:,0] = [dirt, stone, dirt]
25
- # print(reg[...,0])
26
- # print(reg[np.array([BlockPosition(0, 0, 0), BlockPosition(1, 1, 1)])])
27
- # print(f"\t{reg[:]}")
28
- # for pos, state in reg.blocks(exclude_air=True):
29
- # print(pos, state)
30
- # for pos, state in reg.blocks((BlockState("oak_log", axis="x"), BlockState("spruce_log", axis="z")), ignore_props=True):
31
- for pos, state in reg.blocks(exclude=BlockState("air")):
32
- print(pos, reg._to_internal(pos), state)
33
- for pos, state in reg.blocks(include=BlockState("air")):
34
- reg[pos] = BlockState("minecraft:netherrack")
35
- print(BlockState("oak_log", axis="x") in reg)
36
- print(BlockPosition(1, 1, 0) in reg)
37
- print(ResourceLocation("birch_log") in reg)
38
- # print(reg[0,:,2])
39
- s.save("/mnt/d/minecraft/schematics/Litematica/test/aaa.litematic")
5
+ # path = pathlib.Path("/mnt/d/minecraft/schematics/Litematica/test/subs.litematic")
6
+ # path = pathlib.Path("/mnt/d/minecraft/schematics/Litematica/test/regions.litematic")
7
+ # path = pathlib.Path("/mnt/d/minecraft/schematics/Litematica/test/creeper_test.litematic")
8
+ # stone = BlockState.from_string("minecraft:stone")
9
+ # dirt = BlockState.from_string("minecraft:dirt")
10
+ # s = Schematic.load(path)
11
+ # print(f"{s.volume=} {s.size=} {s.bounds=}")
12
+ # for name, reg in s.regions():
13
+ # print(name)
14
+ # print(f"\t{reg.shape=} {reg.volume=} {reg.block_count=}")
15
+ # print(f"\t{reg.origin=!s} {reg.limit=!s}")
16
+ # print(f"\t{reg.start=!s} {reg.end=!s}")
17
+ # print(f"\t{reg.lower=!s} {reg.upper=!s} {reg.size=}")
18
+ # # print(f"\t{reg[..., 1, 0]}")
19
+ # # print(f"\t{reg[:][1][0]}")
20
+ # # print(f"\t{reg[BlockPosition(0, 1, 0)]}")
21
+ # # reg[1,1,1] = BlockState.from_string("minecraft:stone")
22
+ # # print("lol: ", reg[reg.end])
23
+ # # reg[0,:,0] = BlockState("minecraft:obsidian")
24
+ # # reg[0,:,0] = [dirt, stone, dirt]
25
+ # # print(reg[...,0])
26
+ # # print(reg[np.array([BlockPosition(0, 0, 0), BlockPosition(1, 1, 1)])])
27
+ # # print(f"\t{reg[:]}")
28
+ # # for pos, state in reg.blocks(exclude_air=True):
29
+ # # print(pos, state)
30
+ # # for pos, state in reg.blocks((BlockState("oak_log", axis="x"), BlockState("spruce_log", axis="z")), ignore_props=True):
31
+ # # reg[...,-1] = stone
32
+ # for pos, state in reg.blocks(exclude=BlockState("air")):
33
+ # print(f"\t{pos} {reg._to_internal(pos)}: {state}")
34
+ # for pos, state in reg.blocks(include=BlockState("lime_wool")):
35
+ # reg[pos] = BlockState("minecraft:blue_wool")
36
+ # for pos, state in reg.blocks(include=BlockState("tripwire"), ignore_props=True):
37
+ # reg[pos] = BlockState("minecraft:glass")
38
+ # # print(BlockState("oak_log", axis="x") in reg)
39
+ # # print(BlockPosition(1, 1, 0) in reg)
40
+ # # print(ResourceLocation("birch_log") in reg)
41
+ # # print(reg[0,:,2])
42
+ # s.save("/mnt/d/minecraft/schematics/Litematica/test/aaa.litematic")
43
+
44
+ air = BlockState("air")
45
+ stone = BlockState("stone")
46
+ dirt = BlockState("dirt")
47
+ grass = BlockState("grass_block")
48
+ cobble = BlockState("mossy_cobblestone")
49
+ snow = BlockState("snow_block")
50
+ pumpkin = BlockState("carved_pumpkin", facing="west")
51
+
52
+ ground = Region(size=Size3D(16, 9, 16), origin=BlockPosition(0, 0, 0))
53
+ ground[:,:5,:] = stone
54
+ ground[:,5:8,:] = dirt
55
+ ground[:,8:,:] = grass
56
+
57
+ boulder = Region(size=(4, 4, 4), origin=ground.origin+[6, ground.height, 6])
58
+ boulder[:] = cobble
59
+
60
+ # snow_man = Region(size=(1, 3, 1), origin=boulder.origin+[1, boulder.height, 1])
61
+ snow_man = Region(size=(-1, -3, -1), origin=boulder.origin+[1, boulder.height+2, 1])
62
+ snow_man[:] = snow
63
+ snow_man[0,snow_man.upper.y,0] = pumpkin
64
+
65
+ schem = Schematic(name="scene", author="Boscawinks", description="A simple scene")
66
+ schem.add_region("ground", ground)
67
+ schem.add_region("boulder", boulder)
68
+ schem.add_region("snow_man", snow_man)
69
+ schem.save(f"/mnt/d/minecraft/schematics/Litematica/test/{schem.name}.litematic")
70
+
71
+ print(snow_man == snow)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pylitematic
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: Load, modify, and save Litematica schematics
5
5
  Author-email: Boscawinks <bosca.winks@gmx.de>
6
6
  License: GPL-3.0-only
@@ -13,6 +13,9 @@ Description-Content-Type: text/markdown
13
13
  Requires-Dist: bitpacking>=0.1.0
14
14
  Requires-Dist: nbtlib>=2.0.4
15
15
  Requires-Dist: numpy>=2.2.6
16
+ Requires-Dist: twos>=0.0.1
17
+ Provides-Extra: dev
18
+ Requires-Dist: pytest; extra == "dev"
16
19
 
17
20
  # pylitematic
18
21
 
@@ -0,0 +1,12 @@
1
+ pylitematic/__init__.py,sha256=-yLTtTzD7kRpeKMbUTYNy67zkFkxUP8V1DnPXhS3ZFY,202
2
+ pylitematic/block_property.py,sha256=4wwsQrxyNGDcrktpd4tD0Vzv-a1OxWYMj0H05GDiT-I,7739
3
+ pylitematic/block_state.py,sha256=tMRoY6jPtt2M85DR9U9dnQh2Ukp6pP_65xXzMIFeUEo,3546
4
+ pylitematic/geometry.py,sha256=kt2buIJovAymAtaGQYmmWj7ypOt1xI8s--LHkbTPUlM,5399
5
+ pylitematic/region.py,sha256=0bUcK9oVyhNDzfxTjZmVLwMddrIdxvJX-cXkWL8BRSE,11097
6
+ pylitematic/resource_location.py,sha256=gHVE1RTRHtc8DWSlXa0WUom68tRlJy8LU5dOzuONV98,2186
7
+ pylitematic/schematic.py,sha256=SLz4NQNBJkLXV9Oj0fVOE-daP4MRsdYAnnl1vKzJv_Q,7928
8
+ pylitematic/test.py,sha256=9uch5L58o9QVJI50jUcbuulEswYzDgtYnRiIP991jFo,3162
9
+ pylitematic-0.0.3.dist-info/METADATA,sha256=ES-4UDWi6DQU6fCSNrgf5FLMDX_jh1g7k6kx9fmiX70,1033
10
+ pylitematic-0.0.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
+ pylitematic-0.0.3.dist-info/top_level.txt,sha256=sYUxm6O7Dh5TzuP-kPFe2FHJWUuwHFO69vN2VBiEG4A,12
12
+ pylitematic-0.0.3.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- pylitematic/__init__.py,sha256=ycco-z7gJlUnBUJuJRo9qzu5pSzXSZLPkqOVLy8OsEI,211
2
- pylitematic/block_property.py,sha256=eV9YbMcuttX-WPdbqN6dMmhb4jK_8_zRv33wNaVd8_o,9887
3
- pylitematic/block_state.py,sha256=hC8ptOTR6XKokn-m2Nlxpi44AvL-vwlgive3KQ4VtUg,3328
4
- pylitematic/geometry.py,sha256=n4Kk413FFhWHFgRRRQCYB2UdDBnbUMqwCEBP85YK1vI,5009
5
- pylitematic/region.py,sha256=15elHo9Li_nw7_VeM9GP92mcK0cYuJtONKnDyj_SnxY,10918
6
- pylitematic/resource_location.py,sha256=kVv9-4WVu_Ak24Um05bucKG-mcXymnylwHMha-ORLoo,2143
7
- pylitematic/schematic.py,sha256=Zc85oT6jdHVdQtAgcZbj9qFXXXWow1GfKXc1TV10CqQ,7879
8
- pylitematic/test.py,sha256=6IrD4t3f7puWIkgsZVfy-epDgKWFQIOGMizQFF7O7u0,1886
9
- pylitematic-0.0.2.dist-info/METADATA,sha256=f0AzgTmhaCPTVVjpnoovf_q_2vG9x_KToOT4kh7bQDM,948
10
- pylitematic-0.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
- pylitematic-0.0.2.dist-info/top_level.txt,sha256=sYUxm6O7Dh5TzuP-kPFe2FHJWUuwHFO69vN2VBiEG4A,12
12
- pylitematic-0.0.2.dist-info/RECORD,,