djhtmx 1.3.3__py3-none-any.whl → 1.3.5__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.
- djhtmx/__init__.py +1 -1
- djhtmx/introspection.py +62 -137
- djhtmx/repo.py +13 -2
- djhtmx/templatetags/htmx.py +1 -1
- djhtmx/utils.py +2 -0
- {djhtmx-1.3.3.dist-info → djhtmx-1.3.5.dist-info}/METADATA +1 -1
- {djhtmx-1.3.3.dist-info → djhtmx-1.3.5.dist-info}/RECORD +9 -9
- {djhtmx-1.3.3.dist-info → djhtmx-1.3.5.dist-info}/WHEEL +0 -0
- {djhtmx-1.3.3.dist-info → djhtmx-1.3.5.dist-info}/licenses/LICENSE +0 -0
djhtmx/__init__.py
CHANGED
djhtmx/introspection.py
CHANGED
|
@@ -29,7 +29,6 @@ from django.db import models
|
|
|
29
29
|
from django.db.models import Prefetch
|
|
30
30
|
from django.utils.datastructures import MultiValueDict
|
|
31
31
|
from pydantic import BeforeValidator, PlainSerializer, TypeAdapter
|
|
32
|
-
from pydantic_core import PydanticCustomError
|
|
33
32
|
|
|
34
33
|
M = TypeVar("M", bound=models.Model)
|
|
35
34
|
|
|
@@ -88,6 +87,7 @@ class _LazyModelProxy(Generic[M]): # noqa
|
|
|
88
87
|
allow_none: bool = False,
|
|
89
88
|
):
|
|
90
89
|
self.__model = model
|
|
90
|
+
self.__allow_none = allow_none
|
|
91
91
|
if value is None or isinstance(value, model):
|
|
92
92
|
self.__instance = value
|
|
93
93
|
self.__pk = getattr(value, "pk", None)
|
|
@@ -100,60 +100,31 @@ class _LazyModelProxy(Generic[M]): # noqa
|
|
|
100
100
|
else:
|
|
101
101
|
self.__select_related = None
|
|
102
102
|
self.__prefetch_related = None
|
|
103
|
-
self.__allow_none = allow_none
|
|
104
|
-
|
|
105
|
-
def __bool__(self) -> bool:
|
|
106
|
-
"""Check if the instance exists. Called when proxy is used in boolean context."""
|
|
107
|
-
if self.__instance is None:
|
|
108
|
-
self.__ensure_instance()
|
|
109
|
-
if self.__instance is None:
|
|
110
|
-
# Object doesn't exist
|
|
111
|
-
if not self.__allow_none:
|
|
112
|
-
# Required field - raise exception
|
|
113
|
-
from django.core.exceptions import ObjectDoesNotExist
|
|
114
|
-
|
|
115
|
-
raise ObjectDoesNotExist(
|
|
116
|
-
f"{self.__model.__name__} with pk={self.__pk} does not exist "
|
|
117
|
-
"(object may have been deleted)"
|
|
118
|
-
)
|
|
119
|
-
# Optional field - return False (proxy is falsy)
|
|
120
|
-
return False
|
|
121
|
-
return True
|
|
122
103
|
|
|
123
104
|
def __getattr__(self, name: str) -> Any:
|
|
124
105
|
if name == "pk":
|
|
125
106
|
return self.__pk
|
|
126
107
|
if self.__instance is None:
|
|
127
108
|
self.__ensure_instance()
|
|
128
|
-
if self.__instance is None:
|
|
129
|
-
# Object doesn't exist (was deleted or never existed)
|
|
130
|
-
if self.__allow_none:
|
|
131
|
-
# Optional field (Model | None) - return None gracefully
|
|
132
|
-
return None
|
|
133
|
-
else:
|
|
134
|
-
# Required field (Model) - raise explicit exception
|
|
135
|
-
from django.core.exceptions import ObjectDoesNotExist
|
|
136
|
-
|
|
137
|
-
raise ObjectDoesNotExist(
|
|
138
|
-
f"{self.__model.__name__} with pk={self.__pk} does not exist "
|
|
139
|
-
"(object may have been deleted)"
|
|
140
|
-
)
|
|
141
109
|
return getattr(self.__instance, name)
|
|
142
110
|
|
|
143
111
|
def __ensure_instance(self):
|
|
144
|
-
if self.__instance:
|
|
145
|
-
return self.__instance
|
|
146
|
-
elif self.__pk is None:
|
|
147
|
-
# If pk is None, don't try to load anything
|
|
148
|
-
return None
|
|
149
|
-
else:
|
|
112
|
+
if not self.__instance:
|
|
150
113
|
manager = self.__model.objects
|
|
151
114
|
if select_related := self.__select_related:
|
|
152
115
|
manager = manager.select_related(*select_related)
|
|
153
116
|
if prefetch_related := self.__prefetch_related:
|
|
154
117
|
manager = manager.prefetch_related(*prefetch_related)
|
|
118
|
+
# Use filter().first() instead of get() to avoid exceptions
|
|
155
119
|
self.__instance = manager.filter(pk=self.__pk).first()
|
|
156
|
-
|
|
120
|
+
if self.__instance is None:
|
|
121
|
+
if self.__allow_none:
|
|
122
|
+
# For Model | None, object doesn't exist - proxy becomes None-like
|
|
123
|
+
pass
|
|
124
|
+
else:
|
|
125
|
+
# For required Model fields, raise error
|
|
126
|
+
raise ValueError(f"{self.__model.__name__} with pk={self.__pk} does not exist")
|
|
127
|
+
return self.__instance
|
|
157
128
|
|
|
158
129
|
def __repr__(self) -> str:
|
|
159
130
|
return f"<_LazyModelProxy model={self.__model}, pk={self.__pk}, instance={self.__instance}>"
|
|
@@ -172,18 +143,11 @@ class _ModelBeforeValidator(Generic[M]): # noqa
|
|
|
172
143
|
return self._get_instance(value)
|
|
173
144
|
|
|
174
145
|
def _get_lazy_proxy(self, value):
|
|
175
|
-
if value
|
|
176
|
-
# Don't create a proxy for explicit None
|
|
177
|
-
return None
|
|
178
|
-
elif isinstance(value, _LazyModelProxy):
|
|
146
|
+
if isinstance(value, _LazyModelProxy):
|
|
179
147
|
instance = value._LazyModelProxy__instance or value._LazyModelProxy__pk
|
|
180
|
-
return _LazyModelProxy(
|
|
181
|
-
self.model, instance, model_annotation=self.model_config, allow_none=self.allow_none
|
|
182
|
-
)
|
|
148
|
+
return _LazyModelProxy(self.model, instance, allow_none=self.allow_none)
|
|
183
149
|
else:
|
|
184
|
-
return _LazyModelProxy(
|
|
185
|
-
self.model, value, model_annotation=self.model_config, allow_none=self.allow_none
|
|
186
|
-
)
|
|
150
|
+
return _LazyModelProxy(self.model, value, allow_none=self.allow_none)
|
|
187
151
|
|
|
188
152
|
def _get_instance(self, value):
|
|
189
153
|
if value is None or isinstance(value, self.model):
|
|
@@ -206,11 +170,7 @@ class _ModelBeforeValidator(Generic[M]): # noqa
|
|
|
206
170
|
return None
|
|
207
171
|
else:
|
|
208
172
|
# For required Model fields, raise validation error
|
|
209
|
-
raise
|
|
210
|
-
"model_not_found",
|
|
211
|
-
f"{self.model.__name__} with pk={{pk}} does not exist",
|
|
212
|
-
{"pk": value},
|
|
213
|
-
)
|
|
173
|
+
raise ValueError(f"{self.model.__name__} with pk={value} does not exist")
|
|
214
174
|
return instance
|
|
215
175
|
|
|
216
176
|
@classmethod
|
|
@@ -224,11 +184,7 @@ class _ModelPlainSerializer(Generic[M]): # noqa
|
|
|
224
184
|
model: type[M]
|
|
225
185
|
|
|
226
186
|
def __call__(self, value):
|
|
227
|
-
|
|
228
|
-
if value is None:
|
|
229
|
-
return None
|
|
230
|
-
else:
|
|
231
|
-
return value.pk
|
|
187
|
+
return value.pk
|
|
232
188
|
|
|
233
189
|
@classmethod
|
|
234
190
|
@cache
|
|
@@ -237,16 +193,20 @@ class _ModelPlainSerializer(Generic[M]): # noqa
|
|
|
237
193
|
|
|
238
194
|
|
|
239
195
|
def _Model(
|
|
240
|
-
model: type[models.Model],
|
|
196
|
+
model: type[models.Model],
|
|
197
|
+
model_config: ModelConfig | None = None,
|
|
198
|
+
allow_none: bool = False,
|
|
241
199
|
):
|
|
242
200
|
assert issubclass_safe(model, models.Model)
|
|
243
201
|
model_config = model_config or _DEFAULT_MODEL_CONFIG
|
|
202
|
+
|
|
203
|
+
# Determine the base type
|
|
244
204
|
base_type = model if not model_config.lazy else _LazyModelProxy[model]
|
|
245
|
-
# If allow_none
|
|
246
|
-
if allow_none
|
|
247
|
-
|
|
205
|
+
# If allow_none, make it optional
|
|
206
|
+
annotated_type = base_type | None if allow_none else base_type
|
|
207
|
+
|
|
248
208
|
return Annotated[
|
|
249
|
-
|
|
209
|
+
annotated_type,
|
|
250
210
|
BeforeValidator(_ModelBeforeValidator.from_modelclass(model, model_config, allow_none)),
|
|
251
211
|
PlainSerializer(
|
|
252
212
|
func=_ModelPlainSerializer.from_modelclass(model),
|
|
@@ -285,63 +245,45 @@ def annotate_model(annotation, *, model_config: ModelConfig | None = None):
|
|
|
285
245
|
},
|
|
286
246
|
)
|
|
287
247
|
elif type_ := get_origin(annotation):
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
#
|
|
297
|
-
|
|
298
|
-
(
|
|
248
|
+
if type_ is types.UnionType or type_ is Union:
|
|
249
|
+
type_ = Union
|
|
250
|
+
match get_args(annotation):
|
|
251
|
+
case ():
|
|
252
|
+
return type_
|
|
253
|
+
case (param,):
|
|
254
|
+
return type_[annotate_model(param)] # type: ignore
|
|
255
|
+
case params:
|
|
256
|
+
# Check for ModelConfig in params (for Annotated types)
|
|
257
|
+
param_model_config = next(
|
|
258
|
+
(p for p in params if isinstance(p, ModelConfig)),
|
|
299
259
|
None,
|
|
300
260
|
)
|
|
301
|
-
# Use
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
261
|
+
# Use param ModelConfig if found, otherwise use the passed model_config
|
|
262
|
+
effective_model_config = param_model_config or model_config
|
|
263
|
+
|
|
264
|
+
# Check if this is a Model | None union
|
|
265
|
+
has_none = types.NoneType in params
|
|
266
|
+
model_types = [p for p in params if issubclass_safe(p, models.Model)]
|
|
267
|
+
|
|
268
|
+
# If we have Model | None, annotate the model with allow_none=True
|
|
269
|
+
if has_none and len(model_types) == 1:
|
|
270
|
+
annotated_params = []
|
|
271
|
+
for p in params:
|
|
272
|
+
if issubclass_safe(p, models.Model):
|
|
273
|
+
annotated_params.append(
|
|
274
|
+
_Model(p, effective_model_config, allow_none=True)
|
|
275
|
+
)
|
|
276
|
+
elif p is not types.NoneType:
|
|
277
|
+
annotated_params.append(
|
|
278
|
+
annotate_model(p, model_config=effective_model_config)
|
|
279
|
+
)
|
|
280
|
+
else:
|
|
281
|
+
annotated_params.append(p)
|
|
282
|
+
return type_[*annotated_params] # type: ignore
|
|
313
283
|
else:
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
elif type_ is types.UnionType or type_ is Union:
|
|
318
|
-
type_ = Union
|
|
319
|
-
match get_args(annotation):
|
|
320
|
-
case ():
|
|
321
|
-
return type_
|
|
322
|
-
case (param,):
|
|
323
|
-
return type_[annotate_model(param)] # type: ignore
|
|
324
|
-
case params:
|
|
325
|
-
model_annotation = next(
|
|
326
|
-
(p for p in params if isinstance(p, ModelConfig)),
|
|
327
|
-
None,
|
|
328
|
-
)
|
|
329
|
-
# Check if this is a Model | None union
|
|
330
|
-
has_none = types.NoneType in params
|
|
331
|
-
model_params = [p for p in params if issubclass_safe(p, models.Model)]
|
|
332
|
-
|
|
333
|
-
if has_none and len(model_params) == 1:
|
|
334
|
-
# This is a Model | None union - use allow_none=True
|
|
335
|
-
# Use the model_config parameter passed to annotate_model, not model_annotation from Union params
|
|
336
|
-
model = model_params[0]
|
|
337
|
-
return _Model(model, model_config or model_annotation, allow_none=True)
|
|
338
|
-
else:
|
|
339
|
-
# Regular union - process each param independently
|
|
340
|
-
return type_[
|
|
341
|
-
*(annotate_model(p, model_config=model_annotation) for p in params)
|
|
342
|
-
] # type: ignore
|
|
343
|
-
# Other generic types (list, dict, defaultdict, etc.) - return as-is
|
|
344
|
-
return annotation
|
|
284
|
+
return type_[
|
|
285
|
+
*(annotate_model(p, model_config=effective_model_config) for p in params)
|
|
286
|
+
] # type: ignore
|
|
345
287
|
else:
|
|
346
288
|
return annotation
|
|
347
289
|
|
|
@@ -519,27 +461,10 @@ def is_basic_type(ann):
|
|
|
519
461
|
- Literal types with simple values
|
|
520
462
|
|
|
521
463
|
"""
|
|
522
|
-
# Check if it's a Union (e.g., Item | None)
|
|
523
|
-
origin_type = get_origin(ann)
|
|
524
|
-
if origin_type in (types.UnionType, Union):
|
|
525
|
-
args = get_args(ann)
|
|
526
|
-
# If it's Model | None, consider it a basic type
|
|
527
|
-
model_types = [arg for arg in args if issubclass_safe(arg, models.Model)]
|
|
528
|
-
if model_types and types.NoneType in args:
|
|
529
|
-
return True
|
|
530
|
-
|
|
531
|
-
# Check for Annotated[Model, ...] or Annotated[Model | None, ...] pattern
|
|
532
|
-
origin = getattr(ann, "__origin__", None)
|
|
533
|
-
if origin is not None and get_origin(origin) in (types.UnionType, Union):
|
|
534
|
-
args = get_args(origin)
|
|
535
|
-
model_types = [arg for arg in args if issubclass_safe(arg, models.Model)]
|
|
536
|
-
if model_types and types.NoneType in args:
|
|
537
|
-
return True
|
|
538
|
-
|
|
539
464
|
return (
|
|
540
465
|
ann in _SIMPLE_TYPES
|
|
541
466
|
# __origin__ -> model in 'Annotated[model, BeforeValidator(...), PlainSerializer(...)]'
|
|
542
|
-
or issubclass_safe(
|
|
467
|
+
or issubclass_safe(getattr(ann, "__origin__", None), models.Model)
|
|
543
468
|
or issubclass_safe(ann, (enum.IntEnum, enum.StrEnum))
|
|
544
469
|
or is_collection_annotation(ann)
|
|
545
470
|
or is_literal_annotation(ann)
|
djhtmx/repo.py
CHANGED
|
@@ -240,7 +240,11 @@ class Repository:
|
|
|
240
240
|
Emit(HtmxUnhandledError(error, handler_annotations=annotations))
|
|
241
241
|
]
|
|
242
242
|
yield from self._process_emited_commands(
|
|
243
|
-
component,
|
|
243
|
+
component,
|
|
244
|
+
emited_commands,
|
|
245
|
+
commands,
|
|
246
|
+
during_execute=True,
|
|
247
|
+
method_name=event_handler,
|
|
244
248
|
)
|
|
245
249
|
|
|
246
250
|
case SkipRender(component):
|
|
@@ -286,7 +290,11 @@ class Repository:
|
|
|
286
290
|
else:
|
|
287
291
|
raise
|
|
288
292
|
yield from self._process_emited_commands(
|
|
289
|
-
component,
|
|
293
|
+
component,
|
|
294
|
+
emited_commands,
|
|
295
|
+
commands,
|
|
296
|
+
during_execute=False,
|
|
297
|
+
method_name="_handle_event",
|
|
290
298
|
)
|
|
291
299
|
|
|
292
300
|
case Signal(signals):
|
|
@@ -320,10 +328,13 @@ class Repository:
|
|
|
320
328
|
emmited_commands: Iterable[Command] | None,
|
|
321
329
|
commands: CommandQueue,
|
|
322
330
|
during_execute: bool,
|
|
331
|
+
method_name: str | None = None,
|
|
323
332
|
) -> Iterable[ProcessedCommand]:
|
|
324
333
|
component_was_rendered = False
|
|
325
334
|
commands_to_add: list[Command] = []
|
|
326
335
|
for command in emmited_commands or []:
|
|
336
|
+
if method_name:
|
|
337
|
+
logger.debug("< YIELD: %s.%s -> %s", component.hx_name, method_name, command)
|
|
327
338
|
component_was_rendered = component_was_rendered or (
|
|
328
339
|
isinstance(command, SkipRender | Render) and command.component.id == component.id
|
|
329
340
|
)
|
djhtmx/templatetags/htmx.py
CHANGED
|
@@ -292,4 +292,4 @@ class ClassNode(Node):
|
|
|
292
292
|
for condition, class_name in self.condition_and_classes
|
|
293
293
|
if condition.eval(context) # type: ignore
|
|
294
294
|
]
|
|
295
|
-
return format_html_attrs({"class": " ".join(class_names) or None})
|
|
295
|
+
return format_html_attrs({"class": " ".join(filter(None, class_names)) or None})
|
djhtmx/utils.py
CHANGED
|
@@ -130,6 +130,8 @@ def autodiscover_htmx_modules():
|
|
|
130
130
|
- All Python files under htmx/ directories in apps (recursively)
|
|
131
131
|
"""
|
|
132
132
|
for app_config in apps.get_app_configs():
|
|
133
|
+
if app_config.module is None:
|
|
134
|
+
continue
|
|
133
135
|
module_name = f"{app_config.module.__name__}.htmx"
|
|
134
136
|
spec = importlib.util.find_spec(module_name)
|
|
135
137
|
if spec is None:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
djhtmx/__init__.py,sha256=
|
|
1
|
+
djhtmx/__init__.py,sha256=gh8Y_nLUObBD-XKDjwxAMcHUbqSpiLfbiBgXd3ZEzXk,84
|
|
2
2
|
djhtmx/apps.py,sha256=hAyjzmInEstxLY9k8Qn58LvNlezgQLx5_NqyVL1WwYs,323
|
|
3
3
|
djhtmx/command_queue.py,sha256=LSUkb2YMRt1lDyOg6WP7PoHsObynec0B55JyFtcshT0,5090
|
|
4
4
|
djhtmx/commands.py,sha256=UxXbARd4Teetjh_zjvAWgI2KNbvdETH-WrGf4qD9Xr8,1206
|
|
@@ -7,16 +7,16 @@ djhtmx/consumer.py,sha256=0Yh8urgMH3khA6_pWeY049w3jqHWZL_K9dErOhNctQA,2898
|
|
|
7
7
|
djhtmx/context.py,sha256=cWvz8Z0MC6x_G8sn5mvoH8Hu38qReY21_eNdThuba1A,214
|
|
8
8
|
djhtmx/exceptions.py,sha256=UtyE1N-52OmzwgRM9xFxjUuhHTMDvD7Oy3rNpgthLcs,47
|
|
9
9
|
djhtmx/global_events.py,sha256=bYb8WmQn_WsZ_Dadr0pGiGOPia01K-VanPpM97Lt324,342
|
|
10
|
-
djhtmx/introspection.py,sha256=
|
|
10
|
+
djhtmx/introspection.py,sha256=QZOaX7tWftMZCjRVXYGHxaCxSksoT2wljd3lIMaz9ic,16463
|
|
11
11
|
djhtmx/json.py,sha256=7cjwWIJj7e0dk54INKYZJe6zKkIW7wlsNSlD05cbXfY,1374
|
|
12
12
|
djhtmx/middleware.py,sha256=JuMtv9ZnpungTvQ1qD2Lg6LiFPB3knQlA1ERgH4iGl0,1274
|
|
13
13
|
djhtmx/query.py,sha256=GKubKKZ1Z6krzLjG4GZpcxAyPy-pCMCtyfSVfXrpy90,6855
|
|
14
|
-
djhtmx/repo.py,sha256=
|
|
14
|
+
djhtmx/repo.py,sha256=BZrxLCxcqJudCsHvlL_bmkjhvbsFMAP7sZLCTxTRiCI,22906
|
|
15
15
|
djhtmx/settings.py,sha256=Iti4LkcKBTy-dNyCZxFH_cUp56aTcXjB5ftbssWyDnU,1318
|
|
16
16
|
djhtmx/testing.py,sha256=QmZHrH6Up8uUxkVOHM6CyfocU774GL-lopJvM2X9Mkw,8369
|
|
17
17
|
djhtmx/tracing.py,sha256=xkCXb7t_3yCj1PGzmQfHPu9sYQftDKwtALaEbFVnQ1E,1260
|
|
18
18
|
djhtmx/urls.py,sha256=2LTzmBCd3lBlQcM6WrdQwkITxuL_4ArUHtiYbLk3T1M,4273
|
|
19
|
-
djhtmx/utils.py,sha256=
|
|
19
|
+
djhtmx/utils.py,sha256=XyRF3RD7_wOLIu6dVwxnUm828oGwKcPAbgq8oMd27m8,4708
|
|
20
20
|
djhtmx/management/commands/htmx.py,sha256=tEtiJn_Z6byOFzBNIzTbdluA4T5q21zFwGvJ7yt90bw,3642
|
|
21
21
|
djhtmx/static/htmx/django.js,sha256=QDgkUBiX9PBa_bqfK2k4NwjBAgZlxYEK-JklOgn_IR4,5453
|
|
22
22
|
djhtmx/static/htmx/2.0.4/htmx.amd.js,sha256=Hgmm_X5zw7ek0pjBaxhzH7OHx6Xfce5UYVa9ICWlWR0,165593
|
|
@@ -30,8 +30,8 @@ djhtmx/static/htmx/2.0.4/ext/ws.js,sha256=HwUYFqEZBvs7Tx0_O0Bi-Dcmg5UOMlbMdkJ2FW
|
|
|
30
30
|
djhtmx/templates/htmx/headers.html,sha256=z7r9klwBDXDyjbHrzatZeHDvXB2DaZhgu55CFbbD3d4,159
|
|
31
31
|
djhtmx/templates/htmx/lazy.html,sha256=LfAThtKmFj-lCUZ7JWF_sC1Y6XsIpEz8A3IgWASn-J8,52
|
|
32
32
|
djhtmx/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
|
-
djhtmx/templatetags/htmx.py,sha256
|
|
34
|
-
djhtmx-1.3.
|
|
35
|
-
djhtmx-1.3.
|
|
36
|
-
djhtmx-1.3.
|
|
37
|
-
djhtmx-1.3.
|
|
33
|
+
djhtmx/templatetags/htmx.py,sha256=apZqnFnCYjayj6ZwoQLr6TDgYU0834r3FhPhw3Q-8dU,8411
|
|
34
|
+
djhtmx-1.3.5.dist-info/METADATA,sha256=5VMhn325lefcyL5DDC2CPzLluT74kaPGZqLzsec5fto,33745
|
|
35
|
+
djhtmx-1.3.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
36
|
+
djhtmx-1.3.5.dist-info/licenses/LICENSE,sha256=kCi_iSBUGsRZInQn96w7LXYzjiRjZ8FXl6vP--mFRPk,1085
|
|
37
|
+
djhtmx-1.3.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|