tico 0.1.0.dev250618__py3-none-any.whl → 0.1.0.dev250622__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.
tico/__init__.py CHANGED
@@ -21,7 +21,7 @@ from tico.config import CompileConfigV1, get_default_config
21
21
  from tico.utils.convert import convert, convert_from_exported_program, convert_from_pt2
22
22
 
23
23
  # THIS LINE IS AUTOMATICALLY GENERATED BY setup.py
24
- __version__ = "0.1.0.dev250618"
24
+ __version__ = "0.1.0.dev250622"
25
25
 
26
26
  MINIMUM_SUPPORTED_VERSION = "2.5.0"
27
27
  SECURE_TORCH_VERSION = "2.6.0"
@@ -16,11 +16,14 @@ from typing import TYPE_CHECKING
16
16
 
17
17
  if TYPE_CHECKING:
18
18
  import torch.fx
19
+ import copy
20
+
19
21
  import torch
20
22
  from torch.export import ExportedProgram
21
23
 
22
24
  from tico.serialize.quant_param import QPARAM_KEY, QuantParam, to_qparam_dtype
23
25
  from tico.utils import logging
26
+ from tico.utils.graph import create_node
24
27
  from tico.utils.passes import PassBase, PassResult
25
28
  from tico.utils.trace_decorators import trace_graph_diff_on_pass
26
29
  from tico.utils.utils import get_quant_dtype
@@ -78,6 +81,15 @@ class FoldQuantOps(PassBase):
78
81
  if q_args.dtype != dq_args.dtype:
79
82
  continue
80
83
 
84
+ # Case 1. op is not quantized
85
+ # - Quantize op
86
+ # Case 2. op is quantized
87
+ # 2.1. op_dtype == qdq_dtype
88
+ # - Just skip (NOTE Need requantization?)
89
+ # 2.2. op_dtype != qdq_dtype
90
+ # - Insert Quantize operator
91
+
92
+ # Case 1
81
93
  if QPARAM_KEY not in op.meta:
82
94
  qparam = QuantParam()
83
95
  qparam.scale = [q_args.scale]
@@ -85,9 +97,24 @@ class FoldQuantOps(PassBase):
85
97
  qparam.dtype = get_quant_dtype(q_args.quant_min, q_args.quant_max)
86
98
  op.meta[QPARAM_KEY] = qparam
87
99
 
88
- dq.replace_all_uses_with(op, propagate_meta=False)
89
-
90
- logger.debug(f"{q.name} and {dq.name} are folded to {op.name}.")
100
+ dq.replace_all_uses_with(op, propagate_meta=False)
101
+
102
+ logger.debug(f"{q.name} and {dq.name} are folded to {op.name}.")
103
+ else:
104
+ op_qparam: QuantParam = op.meta[QPARAM_KEY]
105
+ qdq_dtype = get_quant_dtype(q_args.quant_min, q_args.quant_max)
106
+ # Case 2.2
107
+ if op_qparam.dtype != qdq_dtype:
108
+ # If op is already quantized with a dtype different from qdq, leave quantize
109
+ qparam = QuantParam()
110
+ qparam.scale = [q_args.scale]
111
+ qparam.zero_point = [q_args.zero_p]
112
+ qparam.dtype = qdq_dtype
113
+ q.meta[QPARAM_KEY] = qparam
114
+ assert len(q.users) == 1, "Fix me unless"
115
+
116
+ dq.replace_all_uses_with(q, propagate_meta=False)
117
+ logger.debug(f"{dq.name} is folded ({q.name} is left).")
91
118
 
92
119
  graph.eliminate_dead_code()
93
120
  graph.lint()
@@ -60,6 +60,7 @@ class AvgPool2DVisitor(NodeVisitor):
60
60
  input_shape = list(extract_shape(args.input))
61
61
  kernel_size = args.kernel_size
62
62
  stride = args.stride
63
+ assert stride
63
64
  padding = args.padding
64
65
  # TODO Update this function when supporting ceil_mode = True
65
66
  assert args.ceil_mode is False
@@ -0,0 +1,60 @@
1
+ # Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Dict, List, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ import torch._ops
19
+ import torch.fx
20
+ import torch
21
+ from circle_schema import circle
22
+
23
+ from tico.serialize.circle_graph import CircleSubgraph
24
+ from tico.serialize.operators.hashable_opcode import OpCode
25
+ from tico.serialize.operators.node_visitor import NodeVisitor, register_node_visitor
26
+ from tico.serialize.operators.utils import create_builtin_operator, get_op_index
27
+ from tico.utils.validate_args_kwargs import LeakyReluArgs
28
+
29
+
30
+ @register_node_visitor
31
+ class LeakyReluVisitor(NodeVisitor):
32
+ target: List[torch._ops.OpOverload] = [torch.ops.aten.leaky_relu.default]
33
+
34
+ def __init__(self, op_codes: Dict[OpCode, int], graph: CircleSubgraph):
35
+ super().__init__(op_codes, graph)
36
+
37
+ def define_node(
38
+ self,
39
+ node: torch.fx.Node,
40
+ ) -> circle.Operator.OperatorT:
41
+ op_index = get_op_index(
42
+ circle.BuiltinOperator.BuiltinOperator.LEAKY_RELU, self._op_codes
43
+ )
44
+
45
+ args = LeakyReluArgs(*node.args, **node.kwargs) # type: ignore[arg-type]
46
+ input = args.input
47
+ negative_slope = args.negative_slope
48
+
49
+ inputs = [input]
50
+ outputs = [node]
51
+
52
+ operator = create_builtin_operator(self.graph, op_index, inputs, outputs)
53
+ operator.builtinOptionsType = (
54
+ circle.BuiltinOptions.BuiltinOptions.LeakyReluOptions
55
+ )
56
+ option = circle.LeakyReluOptions.LeakyReluOptionsT()
57
+ option.alpha = negative_slope
58
+ operator.builtinOptions = option
59
+
60
+ return operator
@@ -72,6 +72,7 @@ class MaxPool2DWithIndicesVisitor(NodeVisitor):
72
72
  input = args.input
73
73
  kernel_size = args.kernel_size
74
74
  stride = args.stride
75
+ assert stride
75
76
  padding = args.padding
76
77
 
77
78
  maxpool_input: torch.fx.Node | circle.Tensor.TensorT = input
@@ -124,7 +125,8 @@ class MaxPool2DWithIndicesVisitor(NodeVisitor):
124
125
  padding_type = PaddingType.SAME
125
126
  else:
126
127
  padding_type = PaddingType.VALID
127
- maxpool_input = define_padding_node()
128
+ if padding[0] != 0 or padding[1] != 0:
129
+ maxpool_input = define_padding_node()
128
130
 
129
131
  inputs = [maxpool_input]
130
132
  outputs = [node]
@@ -385,7 +385,7 @@ def CircleMaxPool2D():
385
385
  def maxpool2d(
386
386
  input_: torch.Tensor,
387
387
  kernel_size: List[int],
388
- stride: List[int],
388
+ stride: Optional[List[int]] = None,
389
389
  padding: Optional[List[int]] = None,
390
390
  dilation: Optional[List[int]] = None,
391
391
  ceil_mode: Optional[bool] = None,
@@ -397,6 +397,7 @@ def CircleMaxPool2D():
397
397
  So, let's set them by None in input specs, and then, set it by default values.
398
398
  https://github.com/pytorch/pytorch/blob/6b05aafc/torch/_library/infer_schema.py#L131-L144
399
399
  """
400
+ stride = kernel_size if not stride else stride
400
401
  padding = [0, 0] if padding is None else padding
401
402
  dilation = [1, 1] if dilation is None else dilation
402
403
  ceil_mode = False if ceil_mode is None else ceil_mode
@@ -416,7 +417,7 @@ def CircleMaxPool2D():
416
417
  def _(
417
418
  input_: torch.Tensor,
418
419
  kernel_size: List[int],
419
- stride: List[int],
420
+ stride: Optional[List[int]] = None,
420
421
  padding: Optional[List[int]] = None,
421
422
  dilation: Optional[List[int]] = None,
422
423
  ceil_mode: Optional[bool] = None,
@@ -428,6 +429,7 @@ def CircleMaxPool2D():
428
429
  So, let's set them by None in input specs, and then, set it by default values.
429
430
  https://github.com/pytorch/pytorch/blob/6b05aafc/torch/_library/infer_schema.py#L131-L144
430
431
  """
432
+ stride = kernel_size if not stride else stride
431
433
  padding = [0, 0] if padding is None else padding
432
434
  dilation = [1, 1] if dilation is None else dilation
433
435
  ceil_mode = False if ceil_mode is None else ceil_mode
@@ -449,12 +451,13 @@ def CircleAvgPool2D():
449
451
  def avgpool2d(
450
452
  input_: torch.Tensor,
451
453
  kernel_size: List[int],
452
- stride: List[int],
454
+ stride: Optional[List[int]] = None,
453
455
  padding: Optional[List[int]] = None,
454
456
  ceil_mode: Optional[bool] = None,
455
457
  count_include_pad: Optional[bool] = None,
456
458
  divisor_override: Optional[int] = None,
457
459
  ) -> torch.Tensor:
460
+ stride = kernel_size if not stride else stride
458
461
  padding = [0, 0] if padding is None else padding
459
462
  ceil_mode = False if ceil_mode is None else ceil_mode
460
463
  count_include_pad = True if count_include_pad is None else count_include_pad
@@ -482,12 +485,13 @@ def CircleAvgPool2D():
482
485
  def _(
483
486
  input_: torch.Tensor,
484
487
  kernel_size: List[int],
485
- stride: List[int],
488
+ stride: Optional[List[int]] = None,
486
489
  padding: Optional[List[int]] = None,
487
490
  ceil_mode: Optional[bool] = None,
488
491
  count_include_pad: Optional[bool] = None,
489
492
  divisor_override: Optional[int] = None,
490
493
  ):
494
+ stride = kernel_size if not stride else stride
491
495
  padding = [0, 0] if padding is None else padding
492
496
  ceil_mode = False if ceil_mode is None else ceil_mode
493
497
  count_include_pad = True if count_include_pad is None else count_include_pad
@@ -123,7 +123,7 @@ class AvgPool2dArgs:
123
123
 
124
124
  input: torch.fx.Node
125
125
  kernel_size: List[int]
126
- stride: List[int] = field(default_factory=list)
126
+ stride: Optional[List[int]] = None
127
127
  padding: List[int] = field(default_factory=lambda: [0, 0])
128
128
  ceil_mode: bool = field(default=False)
129
129
  count_include_pad: bool = field(default=True)
@@ -131,6 +131,7 @@ class AvgPool2dArgs:
131
131
 
132
132
  def __post_init__(self):
133
133
  assert len(self.kernel_size) == 2, len(self.kernel_size)
134
+ self.stride = self.kernel_size if not self.stride else self.stride
134
135
  assert len(self.stride) == 2, len(self.stride)
135
136
  if self.padding is not None:
136
137
  assert len(self.padding) == 2, len(self.padding)
@@ -513,6 +514,17 @@ class InstanceNormArgs:
513
514
  cudnn_enabled: bool
514
515
 
515
516
 
517
+ @enforce_type
518
+ @dataclass
519
+ class LeakyReluArgs:
520
+ """
521
+ leaky_relu(Tensor self, Scalar negative_slope=0.01) -> Tensor
522
+ """
523
+
524
+ input: torch.fx.Node
525
+ negative_slope: float = 0.01
526
+
527
+
516
528
  @enforce_type
517
529
  @dataclass
518
530
  class LinearArgs:
@@ -598,13 +610,14 @@ class MaxPool2dWithIndicesArgs:
598
610
 
599
611
  input: torch.fx.Node
600
612
  kernel_size: List[int]
601
- stride: List[int] = field(default_factory=list)
613
+ stride: Optional[List[int]] = None
602
614
  padding: List[int] = field(default_factory=lambda: [0, 0])
603
615
  dilation: List[int] = field(default_factory=lambda: [1, 1])
604
616
  ceil_mode: bool = field(default=False)
605
617
 
606
618
  def __post_init__(self):
607
619
  assert len(self.kernel_size) == 2, len(self.kernel_size)
620
+ self.stride = self.kernel_size if not self.stride else self.stride
608
621
  assert len(self.stride) == 2, len(self.stride)
609
622
  if self.padding is not None:
610
623
  assert len(self.padding) == 2, len(self.padding)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tico
3
- Version: 0.1.0.dev250618
3
+ Version: 0.1.0.dev250622
4
4
  Summary: Convert exported Torch module to circle
5
5
  Home-page: UNKNOWN
6
6
  License: UNKNOWN
@@ -1,4 +1,4 @@
1
- tico/__init__.py,sha256=RrIXtcajfToey4BPf7DPtQpe9D5Ds438M8cEHimbNC8,1743
1
+ tico/__init__.py,sha256=U0yTg9CHkHxsRbkNANLYjrQ1kxP3vT3IjjtbLc8Bysk,1743
2
2
  tico/pt2_to_circle.py,sha256=PPmFNw20jw2Z2VyM3ln9pX__jTzBOAZiv0gT5a-p-Y8,2666
3
3
  tico/config/__init__.py,sha256=xZzCXjZ84qE-CsBi-dfaL05bqpQ3stKKfTXhnrJRyVs,142
4
4
  tico/config/base.py,sha256=anwOiJFkUxUi7Cef573JgQcjk6S-FSi6O_TLjYASW-g,1244
@@ -50,7 +50,7 @@ tico/experimental/quantization/evaluation/executor/backend_executor.py,sha256=3k
50
50
  tico/experimental/quantization/evaluation/executor/circle_executor.py,sha256=eCCJ9wTwR0vUJ0oN7jxtQxZ9598GRw6P6KUxiuGsIIM,2685
51
51
  tico/experimental/quantization/evaluation/executor/triv24_executor.py,sha256=sUoXl6oOO2arAKaNjOBg7HiQja145_Jv6qgY7XtR7A8,5159
52
52
  tico/experimental/quantization/passes/__init__.py,sha256=IO6FP_xYbGy0dW0HL26GXD3ouxARaxCK7bz9dn4blPQ,26
53
- tico/experimental/quantization/passes/fold_quant_ops.py,sha256=OYUndHaSL3GiL8koIG9_pqavW-hghrs0kkpvounsh1g,3312
53
+ tico/experimental/quantization/passes/fold_quant_ops.py,sha256=cC5xuvqWqueKzLXUJi0pCk85vryImkhgnx-ee7G-tPI,4463
54
54
  tico/experimental/quantization/passes/insert_quantize_on_dtype_mismatch.py,sha256=AbNcI7rfIwHsQna_rFuwqFdOzFAU2lIB3sMK-vns8Dc,13072
55
55
  tico/experimental/quantization/passes/propagate_qparam_backward.py,sha256=TGtyW0Z2qOTgVIasBdGRgbwH31YYd6ek7OvLTmCV614,3118
56
56
  tico/experimental/quantization/passes/propagate_qparam_forward.py,sha256=RhUHGCR2RpBO5KYkQ7Z8U5u7HEwDq2wdKHLKAJCi-5c,5138
@@ -109,7 +109,7 @@ tico/serialize/operators/op_alias_copy.py,sha256=Xu9OiILbGf8oddh8yTqovvLfgVs8XYV
109
109
  tico/serialize/operators/op_any.py,sha256=QqAYby1WPd4l97vX-tBjAsOb_pVb1wPjj7SbWQNToCQ,5117
110
110
  tico/serialize/operators/op_arange_start_step.py,sha256=0T5lWwh3TfsFStmVv0v5qG03KENRDBmMix08RXQ4D-U,2132
111
111
  tico/serialize/operators/op_argmax.py,sha256=ARyGHlmWVmzwCct93V5x1-VyKqhxMOvV8GuM8yQWXdo,2290
112
- tico/serialize/operators/op_avg_pool2d.py,sha256=eVd5ngFSImAklvJFfBAaEUvAc-I60e43xCdLjd5zwYA,7522
112
+ tico/serialize/operators/op_avg_pool2d.py,sha256=vc7WCakGXtGFPV1ix5EJmboH23tQ-cSI36ePY3PHKI4,7544
113
113
  tico/serialize/operators/op_bmm.py,sha256=AELjHC9ISFPIzEEl5Kr1s4GSNLZElwZmVZJWkEyCEoA,2189
114
114
  tico/serialize/operators/op_cat.py,sha256=XDYOh0XAyrM0TlxVm6Sa0OFFGrKk7aSDcGXC-hYX4gs,2204
115
115
  tico/serialize/operators/op_clamp.py,sha256=ZRAsXLGsZqJEh4wXxESEpRJkRtUuJWTDgAem6lr9_5I,4298
@@ -135,6 +135,7 @@ tico/serialize/operators/op_gt.py,sha256=JAVbtuAUNLYhtJycJJCEkYo9QAvmiK4lTMdw5yH
135
135
  tico/serialize/operators/op_index.py,sha256=iDW2YSeUS_kLiWEaQ_MjrYpxZAFBbm7_GU_2B4SRe6c,3033
136
136
  tico/serialize/operators/op_index_select.py,sha256=cw7IbvixooikGxzbpUmI9tHS4kjl4lXLtO9D-GO8qLQ,2277
137
137
  tico/serialize/operators/op_instance_norm.py,sha256=AhcVm71ChB16BlPNwqBh5tMHCqMShOXHPkE8Ag9jBfQ,3144
138
+ tico/serialize/operators/op_leaky_relu.py,sha256=UJPoL7kAIp6nAjyDdda_afdOcMLHme7NE77b2y76exc,2160
138
139
  tico/serialize/operators/op_linear.py,sha256=bw_mn2CiJy8CbpPevOV0PMPh0ZMWKAybLZ9cnIKJSsk,2527
139
140
  tico/serialize/operators/op_log.py,sha256=1TKvH2lttdAHE0P84vcxmOvGBBRUs6D71Jrei7SdZHE,1827
140
141
  tico/serialize/operators/op_log1p.py,sha256=gG7Fs4UDj_Nnp7U60UtPyz0fLv1lBpJVOGGCMm-42pY,3121
@@ -142,7 +143,7 @@ tico/serialize/operators/op_logical_and.py,sha256=WhQ8knuq32BO-WhAqkOgpcUStPkjoP
142
143
  tico/serialize/operators/op_logical_not.py,sha256=ugrVcRqR3IvUUaiRVW5cArCYJbzmkcXp88QM846jCww,2129
143
144
  tico/serialize/operators/op_lt.py,sha256=_vA7dWpV9wVBxB7JL9pLQT9BsV91NGQBq_0auAtHK5Y,2080
144
145
  tico/serialize/operators/op_max_dim.py,sha256=nS_TZl5uq4uv1LwgBD9Wddyac4atKqBiIWKIyeXse2s,2519
145
- tico/serialize/operators/op_max_pool2d_with_indices.py,sha256=SPXIdlrYgJfR982il_ajokNehFYJWOmccUoksS_0qos,5665
146
+ tico/serialize/operators/op_max_pool2d_with_indices.py,sha256=Vab8KV4w0i70P5XPdqItXEv_hLFjscVngypOltRvBV8,5746
146
147
  tico/serialize/operators/op_maximum.py,sha256=JjBr6gWEnuakLuk1_feotTHfIIm3s5YqWmqhUMpSPI0,1873
147
148
  tico/serialize/operators/op_mean.py,sha256=rVQZOxCJkHFY4kQBAS1HVK0HkcqxgkSy6zvEDLX_WYQ,2267
148
149
  tico/serialize/operators/op_minimum.py,sha256=fASjQVcTPCin02umQwFPdq2ss-Ve7S5A33J3QmmQ_wQ,1873
@@ -188,18 +189,18 @@ tico/utils/logging.py,sha256=IlbBWscsaHidI0dNqro1HEXAbIcbkR3BD5ukLy2m95k,1286
188
189
  tico/utils/model.py,sha256=Uqc92AnJXQ2pbvctS2z2F3Ku3yNrwXZ9O33hZVis7is,1250
189
190
  tico/utils/padding.py,sha256=GGO27VbaOvtaMYLDrSaKv7uxjeet566aMJD0PyYeMvQ,1484
190
191
  tico/utils/passes.py,sha256=kGmDe__5cPaO6i5EDAoXSVe6yXEoX9hAny4ROb3ZEmQ,2409
191
- tico/utils/register_custom_op.py,sha256=iRQvdqlBqrJxq_pNkvJyDIJD_SYtCUl88wwbbuvSwlk,22952
192
+ tico/utils/register_custom_op.py,sha256=qheG1WqtkUaG1SnHrrKQ7-fE4IZRETApCsfMkjDKcfs,23240
192
193
  tico/utils/serialize.py,sha256=AQXMBOLu-Kg2Rn-qbqsAtHndjZAZIavlKA0QFgJREHM,1420
193
194
  tico/utils/trace_decorators.py,sha256=ddLIiKQfSaQrxgF1kNpwjFTQnXENzeSfcr1kuAW4jGI,3221
194
195
  tico/utils/utils.py,sha256=fnbZ2RLH6-J-wqb32O4qsR1ce4BJU0wYNrk84QXa6_E,13158
195
- tico/utils/validate_args_kwargs.py,sha256=ZX820o05hmzg3QmmduAy-rIOrDyPHYe6Uj6Yf6Hoe_c,25055
196
+ tico/utils/validate_args_kwargs.py,sha256=ifzO4ikubDPU2iXRBPF8KeyubW23cjxBThOslLAcTrg,25368
196
197
  tico/utils/mx/__init__.py,sha256=IO6FP_xYbGy0dW0HL26GXD3ouxARaxCK7bz9dn4blPQ,26
197
198
  tico/utils/mx/elemwise_ops.py,sha256=V6glyAHsVR1joqpsgnNytatCD_ew92xNWZ19UFDoMTA,10281
198
199
  tico/utils/mx/formats.py,sha256=uzNWyu-1onUlwQfX5cZ6fZSUfHMRqorper7_T1k3jfk,3404
199
200
  tico/utils/mx/mx_ops.py,sha256=RcfUTYVi-wilGB2sC35OeARdwDqnixv7dG5iyZ-fQT8,8555
200
- tico-0.1.0.dev250618.dist-info/LICENSE,sha256=kp4JLII7bzRhPb0CPD5XTDZMh22BQ7h3k3B7t8TiSbw,12644
201
- tico-0.1.0.dev250618.dist-info/METADATA,sha256=3mRIOovwnOiIsT7YPmmjWd_UPnZYKk08Kz-rvj5E7gE,8846
202
- tico-0.1.0.dev250618.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
203
- tico-0.1.0.dev250618.dist-info/entry_points.txt,sha256=kBKYSS_IYrSXmUYevmmepqIVPScq5vF8ulQRu3I_Zf0,59
204
- tico-0.1.0.dev250618.dist-info/top_level.txt,sha256=oqs7UPoNSKZEwqsX8B-KAWdQwfAa7i60pbxW_Jk7P3w,5
205
- tico-0.1.0.dev250618.dist-info/RECORD,,
201
+ tico-0.1.0.dev250622.dist-info/LICENSE,sha256=kp4JLII7bzRhPb0CPD5XTDZMh22BQ7h3k3B7t8TiSbw,12644
202
+ tico-0.1.0.dev250622.dist-info/METADATA,sha256=PGKSmJTacXjjLvdGaeS4BtgUAEfmMcFQZnFxI5IpoR0,8846
203
+ tico-0.1.0.dev250622.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
204
+ tico-0.1.0.dev250622.dist-info/entry_points.txt,sha256=kBKYSS_IYrSXmUYevmmepqIVPScq5vF8ulQRu3I_Zf0,59
205
+ tico-0.1.0.dev250622.dist-info/top_level.txt,sha256=oqs7UPoNSKZEwqsX8B-KAWdQwfAa7i60pbxW_Jk7P3w,5
206
+ tico-0.1.0.dev250622.dist-info/RECORD,,