decksmith 0.9.1__py3-none-any.whl → 0.9.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.
- decksmith/card_builder.py +66 -35
- decksmith/deck_builder.py +95 -85
- decksmith/export.py +4 -1
- decksmith/gui/app.py +25 -20
- decksmith/gui/static/css/style.css +105 -33
- decksmith/gui/static/img/decksmith.ico +0 -0
- decksmith/gui/static/js/main.js +169 -115
- decksmith/gui/templates/index.html +184 -182
- decksmith/image_ops.py +11 -0
- decksmith/main.py +7 -6
- decksmith/project.py +35 -39
- decksmith/renderers/image.py +4 -6
- decksmith/renderers/text.py +153 -127
- decksmith/validate.py +14 -2
- {decksmith-0.9.1.dist-info → decksmith-0.9.3.dist-info}/METADATA +3 -1
- decksmith-0.9.3.dist-info/RECORD +27 -0
- decksmith-0.9.1.dist-info/RECORD +0 -26
- {decksmith-0.9.1.dist-info → decksmith-0.9.3.dist-info}/WHEEL +0 -0
- {decksmith-0.9.1.dist-info → decksmith-0.9.3.dist-info}/entry_points.txt +0 -0
decksmith/renderers/text.py
CHANGED
|
@@ -1,127 +1,153 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module contains the TextRenderer class for drawing text on cards.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import operator
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from typing import Any, Dict, Optional
|
|
8
|
-
|
|
9
|
-
import pandas as pd
|
|
10
|
-
from PIL import ImageDraw, ImageFont
|
|
11
|
-
|
|
12
|
-
from decksmith.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
1
|
+
"""
|
|
2
|
+
This module contains the TextRenderer class for drawing text on cards.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import operator
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Dict, Optional
|
|
8
|
+
|
|
9
|
+
import pandas as pd
|
|
10
|
+
from PIL import Image, ImageDraw, ImageFont
|
|
11
|
+
|
|
12
|
+
from decksmith.utils import apply_anchor, get_wrapped_text
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TextRenderer:
|
|
16
|
+
"""
|
|
17
|
+
A class to render text elements on a card.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, base_path: Optional[Path] = None):
|
|
21
|
+
self.base_path = base_path
|
|
22
|
+
|
|
23
|
+
def render(
|
|
24
|
+
self,
|
|
25
|
+
card: Image.Image,
|
|
26
|
+
element: Dict[str, Any],
|
|
27
|
+
calculate_pos_func,
|
|
28
|
+
store_pos_func,
|
|
29
|
+
) -> Image.Image:
|
|
30
|
+
"""
|
|
31
|
+
Draws text on the card.
|
|
32
|
+
Args:
|
|
33
|
+
card (Image.Image): The card image object.
|
|
34
|
+
element (Dict[str, Any]): The text element specification.
|
|
35
|
+
calculate_pos_func (callable): Function to calculate absolute position.
|
|
36
|
+
store_pos_func (callable): Function to store element position.
|
|
37
|
+
Returns:
|
|
38
|
+
Image.Image: The updated card image.
|
|
39
|
+
"""
|
|
40
|
+
assert element.pop("type") == "text", "Element type must be 'text'"
|
|
41
|
+
|
|
42
|
+
element = self._prepare_text_element(element)
|
|
43
|
+
|
|
44
|
+
original_pos = calculate_pos_func(element)
|
|
45
|
+
element["position"] = original_pos
|
|
46
|
+
|
|
47
|
+
layer = Image.new("RGBA", card.size, (0, 0, 0, 0))
|
|
48
|
+
draw = ImageDraw.Draw(layer, "RGBA")
|
|
49
|
+
|
|
50
|
+
# Calculate anchor offset if needed
|
|
51
|
+
if "anchor" in element:
|
|
52
|
+
bbox = draw.textbbox(
|
|
53
|
+
xy=(0, 0),
|
|
54
|
+
text=element.get("text"),
|
|
55
|
+
font=element["font"],
|
|
56
|
+
spacing=element.get("line_spacing", 4),
|
|
57
|
+
align=element.get("align", "left"),
|
|
58
|
+
)
|
|
59
|
+
anchor_point = apply_anchor(bbox, element.pop("anchor"))
|
|
60
|
+
element["position"] = tuple(map(operator.sub, original_pos, anchor_point))
|
|
61
|
+
|
|
62
|
+
# Draw text
|
|
63
|
+
draw.text(
|
|
64
|
+
xy=element.get("position"),
|
|
65
|
+
text=element.get("text"),
|
|
66
|
+
fill=element.get("color", None),
|
|
67
|
+
font=element["font"],
|
|
68
|
+
spacing=element.get("line_spacing", 4),
|
|
69
|
+
align=element.get("align", "left"),
|
|
70
|
+
stroke_width=element.get("stroke_width", 0),
|
|
71
|
+
stroke_fill=element.get("stroke_color", None),
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
card = Image.alpha_composite(card, layer)
|
|
75
|
+
|
|
76
|
+
# Store position
|
|
77
|
+
if "id" in element:
|
|
78
|
+
bbox = draw.textbbox(
|
|
79
|
+
xy=element.get("position"),
|
|
80
|
+
text=element.get("text"),
|
|
81
|
+
font=element["font"],
|
|
82
|
+
spacing=element.get("line_spacing", 4),
|
|
83
|
+
align=element.get("align", "left"),
|
|
84
|
+
)
|
|
85
|
+
store_pos_func(element["id"], bbox)
|
|
86
|
+
|
|
87
|
+
return card
|
|
88
|
+
|
|
89
|
+
def _prepare_text_element(self, element: Dict[str, Any]) -> Dict[str, Any]:
|
|
90
|
+
"""Prepares text element properties."""
|
|
91
|
+
if pd.isna(element["text"]):
|
|
92
|
+
element["text"] = " "
|
|
93
|
+
|
|
94
|
+
# Font setup
|
|
95
|
+
font_size = element.pop("font_size", 10)
|
|
96
|
+
if font_path := element.pop("font_path", None):
|
|
97
|
+
# Resolve font path relative to base_path if provided
|
|
98
|
+
if self.base_path and not Path(font_path).is_absolute():
|
|
99
|
+
potential_path = self.base_path / font_path
|
|
100
|
+
if potential_path.exists():
|
|
101
|
+
font_path = str(potential_path)
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
element["font"] = ImageFont.truetype(
|
|
105
|
+
font_path, font_size, encoding="unic"
|
|
106
|
+
)
|
|
107
|
+
except OSError as exc:
|
|
108
|
+
raise OSError(f"Could not load font: {font_path}") from exc
|
|
109
|
+
else:
|
|
110
|
+
element["font"] = ImageFont.load_default(font_size)
|
|
111
|
+
|
|
112
|
+
if font_variant := element.pop("font_variant", None):
|
|
113
|
+
try:
|
|
114
|
+
names = element["font"].get_variation_names()
|
|
115
|
+
except (AttributeError, OSError):
|
|
116
|
+
names = []
|
|
117
|
+
|
|
118
|
+
# Normalize names to strings (some fonts return bytes)
|
|
119
|
+
names = [
|
|
120
|
+
name.decode("utf-8") if isinstance(name, bytes) else name
|
|
121
|
+
for name in names
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
if names:
|
|
125
|
+
if font_variant not in names:
|
|
126
|
+
raise ValueError(
|
|
127
|
+
f"Font variant '{font_variant}' not found. "
|
|
128
|
+
f"Available variants: {', '.join(names)}"
|
|
129
|
+
)
|
|
130
|
+
element["font"].set_variation_by_name(font_variant)
|
|
131
|
+
else:
|
|
132
|
+
try:
|
|
133
|
+
element["font"].set_variation_by_name(font_variant)
|
|
134
|
+
except (AttributeError, OSError) as exc:
|
|
135
|
+
raise ValueError(
|
|
136
|
+
f"Font variant '{font_variant}' not supported for this font."
|
|
137
|
+
) from exc
|
|
138
|
+
|
|
139
|
+
# Text wrapping
|
|
140
|
+
if line_length := element.pop("width", False):
|
|
141
|
+
element["text"] = get_wrapped_text(
|
|
142
|
+
element["text"], element["font"], line_length
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Colors and position
|
|
146
|
+
if position := element.pop("position", [0, 0]):
|
|
147
|
+
element["position"] = tuple(position)
|
|
148
|
+
if color := element.pop("color", [0, 0, 0]):
|
|
149
|
+
element["color"] = tuple(color)
|
|
150
|
+
if stroke_color := element.pop("stroke_color", None):
|
|
151
|
+
element["stroke_color"] = tuple(stroke_color)
|
|
152
|
+
|
|
153
|
+
return element
|
decksmith/validate.py
CHANGED
|
@@ -39,6 +39,7 @@ SPECS_FOR_TYPE: Dict[str, Dict[str, Any]] = {
|
|
|
39
39
|
"?*rotate": "<?int>",
|
|
40
40
|
"?*flip": "<?str>",
|
|
41
41
|
"?*resize": ["<?int>"],
|
|
42
|
+
"?*opacity": "<?int>",
|
|
42
43
|
},
|
|
43
44
|
},
|
|
44
45
|
"circle": {
|
|
@@ -90,10 +91,17 @@ def validate_element(element: Dict[str, Any], element_type: str):
|
|
|
90
91
|
"""
|
|
91
92
|
Validates an element of a card against a spec, raising an exception
|
|
92
93
|
if it does not meet the spec.
|
|
94
|
+
|
|
93
95
|
Args:
|
|
94
96
|
element (dict): The card element.
|
|
95
97
|
element_type (str): The type of the element
|
|
98
|
+
|
|
99
|
+
Raises:
|
|
100
|
+
ValueError: If the element type is unknown.
|
|
101
|
+
jval.exceptions.ValidationException: If the element does not match the spec.
|
|
96
102
|
"""
|
|
103
|
+
if element_type not in SPECS_FOR_TYPE:
|
|
104
|
+
raise ValueError(f"Unknown element type: {element_type}")
|
|
97
105
|
spec = ELEMENT_SPEC | SPECS_FOR_TYPE[element_type]
|
|
98
106
|
validate(element, spec)
|
|
99
107
|
|
|
@@ -102,13 +110,15 @@ def validate_card(card: Dict[str, Any]):
|
|
|
102
110
|
"""
|
|
103
111
|
Validates a card against a spec, raising an exception
|
|
104
112
|
if it does not meet the spec.
|
|
113
|
+
|
|
105
114
|
Args:
|
|
106
115
|
card (Dict[str, Any]): The card.
|
|
116
|
+
|
|
117
|
+
Raises:
|
|
118
|
+
jval.exceptions.ValidationException: If the card does not match the spec.
|
|
107
119
|
"""
|
|
108
|
-
# print(f"DEBUG:\n{card=}")
|
|
109
120
|
validate(card, CARD_SPEC)
|
|
110
121
|
for element in card["elements"]:
|
|
111
|
-
# print(f"DEBUG: {element['type']}")
|
|
112
122
|
validate_element(element, element["type"])
|
|
113
123
|
|
|
114
124
|
|
|
@@ -123,6 +133,8 @@ def transform_card(card: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
123
133
|
Dict[str, Any]: The transformed card with all automatic casts applied.
|
|
124
134
|
"""
|
|
125
135
|
for element in card.get("elements", []):
|
|
136
|
+
if isinstance(element, str):
|
|
137
|
+
raise ValueError(f"Element '{element}' cannot be empty")
|
|
126
138
|
if element.get("type") == "text" and "text" in element:
|
|
127
139
|
if pd.isna(element["text"]):
|
|
128
140
|
element["text"] = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: decksmith
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.3
|
|
4
4
|
Summary: A command-line application to dynamically generate decks of cards from a YAML specification and a CSV data file, inspired by nandeck.
|
|
5
5
|
License-Expression: GPL-2.0-only
|
|
6
6
|
Author: Julio Cabria
|
|
@@ -28,6 +28,8 @@ Description-Content-Type: text/markdown
|
|
|
28
28
|
|
|
29
29
|
# DeckSmith
|
|
30
30
|
|
|
31
|
+
[julynx.github.io/decksmith](https://julynx.github.io/decksmith/)
|
|
32
|
+
|
|
31
33
|
*A powerful application to dynamically generate decks of cards from a YAML specification and a CSV data file.*
|
|
32
34
|
|
|
33
35
|
<br>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
decksmith/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
decksmith/card_builder.py,sha256=vkQDY5hXLrfCxqkjwF6Q87jLxQe4tLmi-ZybFzt_DGw,6213
|
|
3
|
+
decksmith/deck_builder.py,sha256=73p_IxDgH2bbkfow1bTg_eDXhjcALQbVFuudORxZ-E8,3689
|
|
4
|
+
decksmith/export.py,sha256=2dOS59440qwziLG3tvvUzpapAqqHF9TSPqHQHYa_mh0,6057
|
|
5
|
+
decksmith/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
decksmith/gui/app.py,sha256=dDJwMOm6HHTAIewYHcc0zqghxr-k_tXRZmI_44QJ3EM,10707
|
|
7
|
+
decksmith/gui/static/css/style.css,sha256=FMRF5VSGeRGM2CIn2hOe3bnnwNhFq6JRAHTq9wcW0Ak,14172
|
|
8
|
+
decksmith/gui/static/img/decksmith.ico,sha256=bkz7MTDpQELzP2GSvR42Jn7OgIw_j0uBhN4L2i-m1uo,28366
|
|
9
|
+
decksmith/gui/static/js/main.js,sha256=aOwnTIzWvwqBcO9otoB25B43Tbcv_H-JnZ1j8ZvY32s,24125
|
|
10
|
+
decksmith/gui/templates/index.html,sha256=-rZ-eO7O35gh5bJrQrb-5M-tnYEqSVqGWJh5sCe2e5c,9551
|
|
11
|
+
decksmith/image_ops.py,sha256=SU2h_DC2t06adIwFrJdYp9skHSSj8834x8LV9l6z3qE,5073
|
|
12
|
+
decksmith/logger.py,sha256=uSMzIpv7xT7ICMz4a88x_Z9-Izz0WU9MdZ9JEwWnOC4,1020
|
|
13
|
+
decksmith/macro.py,sha256=prHs0fTIqxE5kjT1usqnWg8CNZEoWUVNAezD-qJslRY,1584
|
|
14
|
+
decksmith/main.py,sha256=W5ve6W7D2sFgLRgskuo54H_PDIDMJTcO4JPNgfRCgZI,4681
|
|
15
|
+
decksmith/project.py,sha256=3tp-uWmlVjA1NB-ZElmCK93M3eL-LknbDuZCUqwPVGE,3479
|
|
16
|
+
decksmith/renderers/__init__.py,sha256=xF0SsNJSQEbY-NoSN0N4admLTGc_4JcZumDMpQahWBM,76
|
|
17
|
+
decksmith/renderers/image.py,sha256=5HzKzELhpwN3WMq2Ni7NT-qmTYHuJaBA8jYVAcxioZw,2153
|
|
18
|
+
decksmith/renderers/shapes.py,sha256=iSCCr4hn2lj4EGchq324_eHtuuYAhemYP9PSEUFBkxM,7855
|
|
19
|
+
decksmith/renderers/text.py,sha256=b7NZn5mb8oCg5BzsupH-1-KzveAKCl6YJKcANbzCeRQ,5525
|
|
20
|
+
decksmith/templates/deck.csv,sha256=8P3XknSg6kXulNyAmqFHgJDIzGjMnvdMQ8ctTtUoIzE,782
|
|
21
|
+
decksmith/templates/deck.yaml,sha256=3BMpTUH1It25wrmQXZSrERoPo4-8TBKXKxfaRtYowt8,1034
|
|
22
|
+
decksmith/utils.py,sha256=-QHYbNKQeB1SXB5Ovswn6Yql9sfSb5CmSNVpsw3LiVM,2909
|
|
23
|
+
decksmith/validate.py,sha256=-HNgV1fPhnNUIJK9xI2CBGJwc2HLhChjLEik9cihER4,4245
|
|
24
|
+
decksmith-0.9.3.dist-info/entry_points.txt,sha256=-usRztjj2gnfmPubb8nFYHD22drzThAmSfM6geWI98Y,48
|
|
25
|
+
decksmith-0.9.3.dist-info/METADATA,sha256=g0VD563NLJ0URE68wENn6PSZDWcpy9uPSSWrpgsJL2g,4316
|
|
26
|
+
decksmith-0.9.3.dist-info/WHEEL,sha256=kJCRJT_g0adfAJzTx2GUMmS80rTJIVHRCfG0DQgLq3o,88
|
|
27
|
+
decksmith-0.9.3.dist-info/RECORD,,
|
decksmith-0.9.1.dist-info/RECORD
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
decksmith/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
decksmith/card_builder.py,sha256=hxDVS7-dngCiT392pP2aiWgasfSp1ou3v3lzWmLXxL4,5618
|
|
3
|
-
decksmith/deck_builder.py,sha256=J_Zdj4m-tXPSZh67mEyOCQ_CTphRCsPiyHSh1HcNM0M,3305
|
|
4
|
-
decksmith/export.py,sha256=rzRGdyfK1YXu_k9cpkXvNFZZBkpfXW5zPr_iotlJxcY,5979
|
|
5
|
-
decksmith/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
decksmith/gui/app.py,sha256=NQPR_hfCVvrr0QnEUmJXQv_A4lFXXoF8_OostVLwZkU,10178
|
|
7
|
-
decksmith/gui/static/css/style.css,sha256=djBsKvc7tm7VaK5PWm1vFtan_PyEWESWjckgNSevr2s,13582
|
|
8
|
-
decksmith/gui/static/js/main.js,sha256=A1Vz4kxlokqTadESYT7PlZf4XkVlaT0AXmSNNSrmixw,21680
|
|
9
|
-
decksmith/gui/templates/index.html,sha256=xQhMFPzkCo1F6qR48NHjLkk12wzgn0Hh0LXTA4ShueE,8949
|
|
10
|
-
decksmith/image_ops.py,sha256=8UzibqfoED_Jch-lt--l2LIAoIwdBrXH7so5UqY5pqw,4737
|
|
11
|
-
decksmith/logger.py,sha256=uSMzIpv7xT7ICMz4a88x_Z9-Izz0WU9MdZ9JEwWnOC4,1020
|
|
12
|
-
decksmith/macro.py,sha256=prHs0fTIqxE5kjT1usqnWg8CNZEoWUVNAezD-qJslRY,1584
|
|
13
|
-
decksmith/main.py,sha256=Jm98JBo3a2H_S7mwHEWg8NzyUBXdbFewFxzlpPxjDLI,4653
|
|
14
|
-
decksmith/project.py,sha256=QbhSOAveCuQ05P2Dp-uIc7hkC_o0-NAq3LIWQ4g-FnU,3885
|
|
15
|
-
decksmith/renderers/__init__.py,sha256=xF0SsNJSQEbY-NoSN0N4admLTGc_4JcZumDMpQahWBM,76
|
|
16
|
-
decksmith/renderers/image.py,sha256=SKj_21wlAjHGEG6M0GGu4OkwmJrxf0Nnk9TCu_2BP38,2218
|
|
17
|
-
decksmith/renderers/shapes.py,sha256=iSCCr4hn2lj4EGchq324_eHtuuYAhemYP9PSEUFBkxM,7855
|
|
18
|
-
decksmith/renderers/text.py,sha256=rN3vYUPWy_OpbxiGI5nydOu2V4O1CnoVKaqRIv64waU,4465
|
|
19
|
-
decksmith/templates/deck.csv,sha256=8P3XknSg6kXulNyAmqFHgJDIzGjMnvdMQ8ctTtUoIzE,782
|
|
20
|
-
decksmith/templates/deck.yaml,sha256=3BMpTUH1It25wrmQXZSrERoPo4-8TBKXKxfaRtYowt8,1034
|
|
21
|
-
decksmith/utils.py,sha256=-QHYbNKQeB1SXB5Ovswn6Yql9sfSb5CmSNVpsw3LiVM,2909
|
|
22
|
-
decksmith/validate.py,sha256=uNkBg0ruZp63gOu687Ed2hrtepV9Ez6NwnikKfvexzs,3813
|
|
23
|
-
decksmith-0.9.1.dist-info/entry_points.txt,sha256=-usRztjj2gnfmPubb8nFYHD22drzThAmSfM6geWI98Y,48
|
|
24
|
-
decksmith-0.9.1.dist-info/METADATA,sha256=u3WtryzgPYzisJIQ-gjvL4NaxmeTmM6uUKMeqUx7HZA,4249
|
|
25
|
-
decksmith-0.9.1.dist-info/WHEEL,sha256=kJCRJT_g0adfAJzTx2GUMmS80rTJIVHRCfG0DQgLq3o,88
|
|
26
|
-
decksmith-0.9.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|