swcgeom 0.4.1__py3-none-any.whl → 0.5.0__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 swcgeom might be problematic. Click here for more details.

swcgeom/core/swc_utils.py CHANGED
@@ -1,8 +1,7 @@
1
- """SWC format."""
1
+ """SWC format utils."""
2
2
 
3
- import warnings
4
3
  from copy import copy
5
- from typing import List, Literal, Tuple
4
+ from typing import Any, List, Literal, Tuple
6
5
 
7
6
  import numpy as np
8
7
  import numpy.typing as npt
@@ -13,6 +12,12 @@ __all__ = [] # do not export anything
13
12
 
14
13
  def mark_roots_as_somas(
15
14
  df: pd.DataFrame, update_type: int | Literal[False] = 1
15
+ ) -> pd.DataFrame:
16
+ return _copy_and_apply(mark_roots_as_somas_, df, update_type=update_type)
17
+
18
+
19
+ def mark_roots_as_somas_(
20
+ df: pd.DataFrame, update_type: int | Literal[False] = 1
16
21
  ) -> None:
17
22
  """Merge multiple roots in swc.
18
23
 
@@ -27,7 +32,11 @@ def mark_roots_as_somas(
27
32
  df.loc[root_loc, "pid"] = -1
28
33
 
29
34
 
30
- def link_roots_to_nearest(df: pd.DataFrame) -> None:
35
+ def link_roots_to_nearest(df: pd.DataFrame) -> pd.DataFrame:
36
+ return _copy_and_apply(link_roots_to_nearest_, df)
37
+
38
+
39
+ def link_roots_to_nearest_(df: pd.DataFrame) -> None:
31
40
  """Merge multiple roots in swc.
32
41
 
33
42
  The first root are reserved, and the others was.
@@ -67,9 +76,11 @@ def assemble_lines(lines: List[pd.DataFrame], **kwargs) -> pd.DataFrame:
67
76
  ~swcgeom.core.swc_utils.try_assemble_lines
68
77
  """
69
78
 
70
- tree, lines = try_assemble_lines(lines, sort=False, **kwargs)
79
+ tree, lines = try_assemble_lines(lines, sort_nodes=False, **kwargs)
71
80
  while len(lines) > 0:
72
- t, lines = try_assemble_lines(lines, id_offset=len(tree), sort=False, **kwargs)
81
+ t, lines = try_assemble_lines(
82
+ lines, id_offset=len(tree), sort_nodes=False, **kwargs
83
+ )
73
84
  tree = pd.concat([tree, t])
74
85
 
75
86
  tree = tree.reset_index()
@@ -83,7 +94,7 @@ def try_assemble_lines(
83
94
  undirected: bool = True,
84
95
  thre: float = 0.2,
85
96
  id_offset: int = 0,
86
- sort: bool = True,
97
+ sort_nodes: bool = True,
87
98
  ) -> Tuple[pd.DataFrame, List[pd.DataFrame]]:
88
99
  """Trying assemble lines to a tree.
89
100
 
@@ -104,7 +115,7 @@ def try_assemble_lines(
104
115
  Connection threshold.
105
116
  id_offset : int, default `0`
106
117
  The offset of the line node id.
107
- sort : bool, default `True`
118
+ sort_nodes : bool, default `True`
108
119
  sort nodes of subtree
109
120
 
110
121
  Returns
@@ -140,33 +151,33 @@ def try_assemble_lines(
140
151
  else:
141
152
  break
142
153
 
143
- if sort:
144
- sort_nodes(tree)
154
+ if sort_nodes:
155
+ sort_nodes_(tree)
145
156
  return tree, lines
146
157
 
147
158
 
148
- def sort_swc(df: pd.DataFrame):
149
- warnings.warn(
150
- "`sort_swc` has been renamed to `sort_nodes`, and will be remove in next version",
151
- DeprecationWarning,
152
- )
153
- return sort_nodes(df)
159
+ def sort_nodes(df: pd.DataFrame) -> pd.DataFrame:
160
+ """Sort the indices of neuron tree.
161
+
162
+ The index for parent are always less than children.
163
+ """
164
+ return _copy_and_apply(sort_nodes_, df)
154
165
 
155
166
 
156
- def sort_nodes(df: pd.DataFrame):
167
+ def sort_nodes_(df: pd.DataFrame) -> None:
157
168
  """Sort the indices of neuron tree.
158
169
 
159
170
  The index for parent are always less than children.
160
171
  """
161
172
  ids, pids = df["id"].to_numpy(), df["pid"].to_numpy()
162
- indices, new_ids, new_pids = sort_swc_impl(ids, pids)
173
+ indices, new_ids, new_pids = sort_nodes_impl(ids, pids)
163
174
  for col in df.columns:
164
175
  df[col] = df[col][indices].to_numpy()
165
176
 
166
177
  df["id"], df["pid"] = new_ids, new_pids
167
178
 
168
179
 
169
- def sort_swc_impl(
180
+ def sort_nodes_impl(
170
181
  old_ids: npt.NDArray[np.int32], old_pids: npt.NDArray[np.int32]
171
182
  ) -> Tuple[npt.NDArray[np.int32], npt.NDArray[np.int32], npt.NDArray[np.int32]]:
172
183
  """Sort the indices of neuron tree."""
@@ -190,8 +201,12 @@ def sort_swc_impl(
190
201
  return indices, new_ids, new_pids
191
202
 
192
203
 
193
- def reset_index(df: pd.DataFrame) -> None:
204
+ def reset_index(df: pd.DataFrame) -> pd.DataFrame:
194
205
  """Reset node index to start with zero."""
206
+ return _copy_and_apply(reset_index_, df)
207
+
208
+
209
+ def reset_index_(df: pd.DataFrame) -> None:
195
210
  roots = df["pid"] == -1
196
211
  root_loc = roots.argmax()
197
212
  root_id = df.loc[root_loc, "id"]
@@ -223,3 +238,9 @@ def _get_dsu(df: pd.DataFrame) -> npt.NDArray[np.int32]:
223
238
  break
224
239
 
225
240
  return dsu
241
+
242
+
243
+ def _copy_and_apply(fn_: Any, df: pd.DataFrame, *args, **kwargs):
244
+ df = df.copy()
245
+ fn_(df, *args, **kwargs)
246
+ return df
swcgeom/core/tree.py CHANGED
@@ -19,6 +19,7 @@ from typing import (
19
19
  import numpy as np
20
20
  import numpy.typing as npt
21
21
  import pandas as pd
22
+ from typing_extensions import Self
22
23
 
23
24
  from ..utils import padding1d
24
25
  from .branch import Branch
@@ -73,12 +74,15 @@ class Tree(SWCLike):
73
74
  return self.distance(self.attach.soma())
74
75
 
75
76
  class Path(Path["Tree"]):
77
+ # TODO: should returns `Tree.Node`
76
78
  """Neural path."""
77
79
 
78
80
  class Segment(Segment["Tree"]):
81
+ # TODO: should returns `Tree.Node`
79
82
  """Neural segment."""
80
83
 
81
84
  class Branch(Branch["Tree"]):
85
+ # TODO: should returns `Tree.Node`
82
86
  """Neural branch."""
83
87
 
84
88
  ndata: dict[str, npt.NDArray]
@@ -174,8 +178,7 @@ class Tree(SWCLike):
174
178
  return [self.node(i) for i in tip_ids]
175
179
 
176
180
  def get_segments(self) -> Segments[Segment]:
177
- # pylint: disable-next=not-an-iterable
178
- return Segments([self.Segment(self, n.pid, n.id) for n in self[1:]])
181
+ return Segments(self.Segment(self, n.pid, n.id) for n in self[1:])
179
182
 
180
183
  def get_branches(self) -> List[Branch]:
181
184
  Info = Tuple[List[Tree.Branch], List[int]]
@@ -292,15 +295,15 @@ class Tree(SWCLike):
292
295
  """Get length of tree."""
293
296
  return sum(s.length() for s in self.get_segments())
294
297
 
295
- @staticmethod
296
- def from_data_frame(df: pd.DataFrame, source: str = "") -> "Tree":
298
+ @classmethod
299
+ def from_data_frame(cls, df: pd.DataFrame, source: str = "") -> "Tree":
297
300
  """Read neuron tree from data frame."""
298
301
  tree = Tree(df.shape[0], **{k: df[k].to_numpy() for k, v in swc_cols})
299
302
  tree.source = source
300
303
  return tree
301
304
 
302
- @staticmethod
303
- def from_swc(swc_file: str, **kwargs) -> "Tree":
305
+ @classmethod
306
+ def from_swc(cls, swc_file: str, **kwargs) -> Self:
304
307
  """Read neuron tree from swc file.
305
308
 
306
309
  See Also
@@ -310,10 +313,10 @@ class Tree(SWCLike):
310
313
 
311
314
  df = read_swc(swc_file, **kwargs)
312
315
  source = os.path.abspath(swc_file)
313
- return Tree.from_data_frame(df, source)
316
+ return cls.from_data_frame(df, source)
314
317
 
315
- @staticmethod
316
- def from_eswc(swc_file: str, extra_cols: List[str] = [], **kwargs) -> "Tree":
318
+ @classmethod
319
+ def from_eswc(cls, swc_file: str, extra_cols: List[str] = [], **kwargs) -> Self:
317
320
  """Read neuron tree from eswc file.
318
321
 
319
322
  See Also
@@ -323,4 +326,4 @@ class Tree(SWCLike):
323
326
  """
324
327
 
325
328
  extra_cols.extend(k for k, t in eswc_cols)
326
- return Tree.from_swc(swc_file, extra_cols=extra_cols, **kwargs)
329
+ return cls.from_swc(swc_file, extra_cols=extra_cols, **kwargs)
@@ -6,7 +6,7 @@ import numpy as np
6
6
  import numpy.typing as npt
7
7
 
8
8
  from .swc import SWCLike
9
- from .swc_utils import sort_swc_impl
9
+ from .swc_utils import sort_nodes_impl
10
10
  from .tree import Tree
11
11
 
12
12
  __all__ = ["REMOVE", "sort_tree", "to_sub_tree", "cut_tree", "propagate_remove"]
@@ -22,7 +22,7 @@ def sort_tree(tree: Tree) -> Tree:
22
22
  --------
23
23
  ~core.swc.swc_sort_tree
24
24
  """
25
- indices, new_ids, new_pids = sort_swc_impl(tree.id(), tree.pid())
25
+ indices, new_ids, new_pids = sort_nodes_impl(tree.id(), tree.pid())
26
26
  new_tree = tree.copy()
27
27
  new_tree.ndata = {k: tree.ndata[k][indices] for k in tree.ndata}
28
28
  new_tree.ndata["id"] = new_ids
swcgeom/utils/numpy.py CHANGED
@@ -1,13 +1,12 @@
1
1
  """Numpy related utils."""
2
2
 
3
- import math
4
3
  from contextlib import contextmanager
5
- from typing import Any, Tuple
4
+ from typing import Any
6
5
 
7
6
  import numpy as np
8
7
  import numpy.typing as npt
9
8
 
10
- __all__ = ["padding1d", "XYPair", "to_distribution", "numpy_printoptions", "numpy_err"]
9
+ __all__ = ["padding1d", "numpy_printoptions", "numpy_err"]
11
10
 
12
11
 
13
12
  def padding1d(
@@ -44,30 +43,6 @@ def padding1d(
44
43
  return np.concatenate([v, padding])
45
44
 
46
45
 
47
- XYPair = Tuple[npt.NDArray[np.float32], npt.NDArray[np.float32]]
48
-
49
-
50
- def to_distribution(
51
- values: npt.NDArray,
52
- step: float,
53
- vmin: float = 0,
54
- vmax: float | None = None,
55
- norm: bool = False,
56
- ) -> XYPair:
57
- indices = np.floor(values / step - vmin).astype(np.int32)
58
- size_min = np.max(indices).item() + 1
59
- size = math.ceil((vmax - vmin) / step) + 1 if vmax is not None else size_min
60
- y = np.zeros(max(size, size_min), dtype=np.float32)
61
- for i in indices:
62
- y[i] = y[i] + 1
63
-
64
- if norm:
65
- y /= values.shape[0]
66
-
67
- x = vmin + step * np.arange(size, dtype=np.float32)
68
- return x, y[:size]
69
-
70
-
71
46
  @contextmanager
72
47
  def numpy_printoptions(*args, **kwargs):
73
48
  original_options = np.get_printoptions()
swcgeom/utils/renderer.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Painter utils."""
2
2
 
3
- from typing import Dict, NamedTuple, Tuple
3
+ from typing import Dict, Literal, NamedTuple, Optional, Tuple
4
4
 
5
5
  import matplotlib.pyplot as plt
6
6
  import numpy as np
@@ -20,17 +20,17 @@ from .transforms import (
20
20
  )
21
21
 
22
22
  __all__ = [
23
- "Vector3D",
23
+ "Vec3f",
24
24
  "Camera",
25
25
  "palette",
26
26
  "draw_lines",
27
- "draw_xyz_axes",
27
+ "draw_direction_indicator",
28
28
  "draw_circles",
29
29
  "get_fig_ax",
30
30
  ]
31
31
 
32
- Vector3D = Tuple[float, float, float]
33
- Camera = NamedTuple("Camera", position=Vector3D, look_at=Vector3D, up=Vector3D)
32
+ Vec3f = Tuple[float, float, float]
33
+ Camera = NamedTuple("Camera", position=Vec3f, look_at=Vec3f, up=Vec3f)
34
34
 
35
35
 
36
36
  class Palette:
@@ -113,17 +113,13 @@ def draw_lines(
113
113
  ends = np.dot(T, ends.T).T[:, 0:2]
114
114
 
115
115
  edges = np.stack([starts, ends], axis=1)
116
- collection = LineCollection(edges, **kwargs) # type: ignore
117
- ax.add_collection(collection) # type: ignore
118
- return collection
116
+ return ax.add_collection(LineCollection(edges, **kwargs)) # type: ignore
119
117
 
120
118
 
121
- def draw_xyz_axes(
122
- ax: Axes, camera: Camera, position: Tuple[float, float] = (0.8, 0.10)
119
+ def draw_direction_indicator(
120
+ ax: Axes, camera: Camera, position: Tuple[float, float]
123
121
  ) -> None:
124
122
  x, y = position
125
- arrow_length = 0.05
126
-
127
123
  direction = np.array(
128
124
  [
129
125
  [1, 0, 0, 1],
@@ -134,29 +130,31 @@ def draw_xyz_axes(
134
130
  )
135
131
  direction = model_view_trasformation(*camera).dot(direction)
136
132
 
137
- for (dx, dy, dz, _), (text, color) in zip(
138
- direction[:3],
139
- [["x", "red"], ["y", "green"], ["z", "blue"]],
140
- ):
133
+ ARROW_LENTH, TEXT_OFFSET = 0.05, 0.05
134
+ text_colors = [["x", "red"], ["y", "green"], ["z", "blue"]]
135
+ for (dx, dy, dz, _), (text, color) in zip(direction, text_colors):
141
136
  if 1 - abs(dz) < 1e-5:
142
137
  continue
143
138
 
144
139
  ax.arrow(
145
140
  x,
146
141
  y,
147
- arrow_length * dx,
148
- arrow_length * dy,
149
- head_length=0.04,
150
- head_width=0.03,
142
+ ARROW_LENTH * dx,
143
+ ARROW_LENTH * dy,
144
+ head_length=0.02,
145
+ head_width=0.01,
151
146
  color=color,
152
147
  transform=ax.transAxes,
153
148
  )
149
+
154
150
  ax.text(
155
- x + (arrow_length + 0.06) * dx,
156
- y + (arrow_length + 0.06) * dy,
151
+ x + (ARROW_LENTH + TEXT_OFFSET) * dx,
152
+ y + (ARROW_LENTH + TEXT_OFFSET) * dy,
157
153
  text,
158
154
  color=color,
159
155
  transform=ax.transAxes,
156
+ horizontalalignment="center",
157
+ verticalalignment="center",
160
158
  )
161
159
 
162
160
 
@@ -166,8 +164,8 @@ def draw_circles(
166
164
  x: npt.NDArray,
167
165
  y: npt.NDArray,
168
166
  /,
169
- y_min: float | None = None,
170
- y_max: float | None = None,
167
+ y_min: Optional[float] = None,
168
+ y_max: Optional[float] = None,
171
169
  cmap: str = "viridis",
172
170
  ) -> None:
173
171
  """Draw a sequential of circles."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: swcgeom
3
- Version: 0.4.1
3
+ Version: 0.5.0
4
4
  Summary: A neuron geometry library for swc format
5
5
  Author-email: yzx9 <yuan.zx@outlook.com>
6
6
  License: CC4.0 BY-NC-SA
@@ -1,23 +1,23 @@
1
1
  swcgeom/__init__.py,sha256=5oZ4DxgA2DHvUiRVqByVLCWkO1RaRyLSzkqYvkkTFyU,122
2
- swcgeom/_version.py,sha256=0_dB-SwRXzCHowA3kD_9MmecjmUqQiIbDwJmtaXjluI,160
2
+ swcgeom/_version.py,sha256=o_9FMpKXs1TaEQNOx-A4tDxKLoFOXZyS8RpLoa-PFCI,160
3
3
  swcgeom/analysis/__init__.py,sha256=6vlB8YVwpW0YGijdFo8WjgZ4TbcGr8kFVLUF1FTGR-Y,206
4
4
  swcgeom/analysis/branch_features.py,sha256=sJPAMTXXId9xyM-s9TmlS24kK65qyZ6Lva4trP816gs,1952
5
- swcgeom/analysis/feature_extractor.py,sha256=L-W4BwzvtWpowoPYuoejchWBo7O2FPuD_ncWmILMp-I,8830
6
- swcgeom/analysis/node_features.py,sha256=hsPJy87IyaVP8h8Fy2BvNeYx5ziYm1Ppcg4omY8Emo8,4324
5
+ swcgeom/analysis/feature_extractor.py,sha256=7GTZ5cfqswc8GzMjhzfNpW7oJ5bB9JBRuMhkgjY5CPA,9232
6
+ swcgeom/analysis/node_features.py,sha256=PQTYMk3VL3_HDjB4E0BcaBRn-_LQXXjHzsbvbUPSUiw,1536
7
7
  swcgeom/analysis/path_features.py,sha256=i9FHZtU98KnCrfpOp4NwVuXeqjzAzLQ9U__Jl5sdIow,883
8
- swcgeom/analysis/sholl.py,sha256=v9wzQ7tnN2syrUyivLlBRiIrfC9YZoEKR8NuhFOAfOg,2336
9
- swcgeom/analysis/visualization.py,sha256=hidgZqKL6DKauBEJ2lJA4KORnCwMhYvuXQbIm-bgfTE,4742
8
+ swcgeom/analysis/sholl.py,sha256=W3B8uuY935DGtnG3G26UFTTXB2cgIBBk5knNygpcq2s,3093
9
+ swcgeom/analysis/visualization.py,sha256=n-zOmHN0y1akQmGPcv-EvCuxlTJAf4HIBXO2vp2kHb4,6046
10
10
  swcgeom/core/__init__.py,sha256=BNdRJEsl_ixpuK-sdBIVxb5ZmBP6vAckQdTVREwDkl0,226
11
11
  swcgeom/core/branch.py,sha256=Rh_yHphV91omYpa0vN0jj-whCQzjhUHK_JHLxS_IQuo,3712
12
- swcgeom/core/branch_tree.py,sha256=8o64y_u2JsryzrC_IqDLYZ9aa-S_JjayfR9LgUtwByA,1648
12
+ swcgeom/core/branch_tree.py,sha256=HIrpo30kb3gG0ljIBbiefZvx3AlQkxrRy8Oa6eU6fp8,1698
13
13
  swcgeom/core/node.py,sha256=nzJjuJ35n9hbRxRICQsUBmJtxKWoyoHvrEoEmuE_JBc,3097
14
14
  swcgeom/core/path.py,sha256=aPebspjzAxC30h7U-ZlOmVKArMj6yeXwtxbgd2OBrRs,3764
15
- swcgeom/core/population.py,sha256=JpDOqr8k3t4GxuMEatte4E6LZfZerM6a6hRBQPdpN5s,2729
15
+ swcgeom/core/population.py,sha256=IqgSs8KvI0rwwX8KmNyDUuma7HiTt6jr_0gV7UC_hVM,5884
16
16
  swcgeom/core/segment.py,sha256=q0qKmVs9K6S5M5KH7TaxM69i_lEOXJwLobd4Bkxubqs,2641
17
- swcgeom/core/swc.py,sha256=5BtVHw3tSgxMc2qDYUx-CkX6aufY2yMu4wCWakxZmHE,7116
18
- swcgeom/core/swc_utils.py,sha256=85rleBf39Sz3GwswE13rcUst4C3pzoJ8F4q9I1tQ9MI,6821
19
- swcgeom/core/tree.py,sha256=7k7BMezwfJZ4BhcxYi1RKwn7Z2xoMPL-Giph2EGRUck,10869
20
- swcgeom/core/tree_utils.py,sha256=zqzNJQsfjCNAgJV4kyVw7PYc38Hvn254aSFyyWu5HsI,3437
17
+ swcgeom/core/swc.py,sha256=WmMego_nskhiYdPOKLCnTnD5UsDPfI0YI2tlcbPF8lM,7106
18
+ swcgeom/core/swc_utils.py,sha256=0zHsbl9Qg6ueI2i8uxijcK1B_J4nk9QMhn-q0fT-Hk0,7412
19
+ swcgeom/core/tree.py,sha256=RxnHlGAuuZ3neGVlumszfF0LpKcpjmywDoxSAeVzffY,10990
20
+ swcgeom/core/tree_utils.py,sha256=QIcxQ-z1uvm2uPG536SYXdh7gwG42DNSoMN1ck7Kd6I,3441
21
21
  swcgeom/datasets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  swcgeom/datasets/pytorch/__init__.py,sha256=gF87h_xfCqpRh9KK3rigeamGI1YzbyE_Kouw9bU69J4,99
23
23
  swcgeom/datasets/pytorch/branch_dataset.py,sha256=BXemD23W9aON_q4W7fU8HlMS6bcH2WmntxO9DI65iSM,2784
@@ -34,12 +34,12 @@ swcgeom/transforms/pytorch/branch.py,sha256=O0b5U3F4opHV6DwmiYKhUR2LDk7BhMUHhyzL
34
34
  swcgeom/utils/__init__.py,sha256=1oqui-U3SNOklQyR9ZpkQrsEnx_vUbuYFByMSJtP0jA,125
35
35
  swcgeom/utils/debug.py,sha256=qay2qJpViLX82mzxdndxQFn-pi1vaEj9CbLGuGt8Y9k,465
36
36
  swcgeom/utils/download.py,sha256=qFWd6IG4_QAs7cGueMvT_EuuzeV_wXeb15O8_cWnt_E,2699
37
- swcgeom/utils/numpy.py,sha256=eOB7BgCc1JEhAe8mRjkbRw3iS2JycXImKcz7FUFIULA,2223
38
- swcgeom/utils/renderer.py,sha256=q6rT0u_t2sjZpFV-ZTpNk-L4rQYbxhw6yia9G2vJiVc,5355
37
+ swcgeom/utils/numpy.py,sha256=A1gwD3GEqNWnbu07gyfJcsE7n_utpLikinjyQrN3U_I,1544
38
+ swcgeom/utils/renderer.py,sha256=5-OSsDmqsE5Uf7kQn6x5RvMAVOgKz8W2mKq1sUc2ESE,5427
39
39
  swcgeom/utils/sdf.py,sha256=GUXmmpGcPCnFMmqWZzK9qJMfGKTgw5awJfJCrvMkPkA,5079
40
40
  swcgeom/utils/transforms.py,sha256=TBcEOojlw60gY0s2B8ywmkf51kzZ52fYan5yXsmIYuI,6349
41
- swcgeom-0.4.1.dist-info/LICENSE,sha256=aiTJ_1to1Xx6PaByy-pSXg42VYzE4FvF6GIt69WSDDI,202
42
- swcgeom-0.4.1.dist-info/METADATA,sha256=LpvkNCD6s-E7h56y5qzeBsWCH2cudEswwu20pWj4-3g,2200
43
- swcgeom-0.4.1.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
44
- swcgeom-0.4.1.dist-info/top_level.txt,sha256=hmLyUXWS61Gxl07haswFEKKefYPBVJYlUlol8ghNkjY,8
45
- swcgeom-0.4.1.dist-info/RECORD,,
41
+ swcgeom-0.5.0.dist-info/LICENSE,sha256=aiTJ_1to1Xx6PaByy-pSXg42VYzE4FvF6GIt69WSDDI,202
42
+ swcgeom-0.5.0.dist-info/METADATA,sha256=geB5_hdoY1edFmYrl5cs85uIyxZ0EgmASIFYEMUnPPg,2200
43
+ swcgeom-0.5.0.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
44
+ swcgeom-0.5.0.dist-info/top_level.txt,sha256=hmLyUXWS61Gxl07haswFEKKefYPBVJYlUlol8ghNkjY,8
45
+ swcgeom-0.5.0.dist-info/RECORD,,