8000 Improve CSV output (#44) · python/pymanager@e3b6475 · GitHub
[go: up one dir, main page]

Skip to content

Commit e3b6475

Browse files
AA-Turnerzooba
andauthored
Improve CSV output (#44)
Co-authored-by: Steve Dower <steve.dower@python.org>
1 parent ffcd936 commit e3b6475

File tree

2 files changed

+96
-14
lines changed

2 files changed

+96
-14
lines changed

src/manage/list_command.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -105,34 +105,56 @@ def format_table(cmd, installs):
105105
" for alternative ways to display this information.!W!")
106106

107107

108-
CSV_EXCLUDE = {
108+
CSV_EXCLUDE = frozenset([
109109
"schema", "unmanaged",
110110
# Complex columns of limited value
111111
"install-for", "shortcuts", "__original-shortcuts",
112112
"executable", "executable_args",
113-
}
113+
])
114114

115-
CSV_EXPAND = ["run-for", "alias"]
115+
CSV_EXPAND = frozenset(["run-for", "alias"])
116116

117-
def _csv_filter_and_expand(installs):
117+
def _csv_filter_and_expand(installs, *, exclude=CSV_EXCLUDE, expand=CSV_EXPAND):
118118
for i in installs:
119-
i = {k: v for k, v in i.items() if k not in CSV_EXCLUDE}
120-
to_expand = {k: i.pop(k, ()) for k in CSV_EXPAND}
121-
yield i
122-
for k2, vlist in to_expand.items():
123-
for vv in vlist:
124-
yield {f"{k2}.{k}": v for k, v in vv.items()}
119+
filtered = {}
120+
to_expand = {k: [] for k in expand}
121+
for k, v in i.items():
122+
if k in exclude:
123+
continue
124+
elif k in to_expand and isinstance(v, (list, tuple)):
125+
for vv in v:
126+
try:
127+
items = vv.items
128+
except AttributeError:
129+
expanded = {f"{k}": vv}
130+
else:
131+
expanded = {f"{k}.{k2}": vvv for k2, vvv in items()}
132+
to_expand[k].append(expanded)
133+
else:
134+
filtered[k] = v
135+
136+
any_yielded = False
137+
for k in expand:
138+
for expanded in to_expand[k]:
139+
yield filtered | expanded
140+
any_yielded = True
141+
if not any_yielded:
142+
yield filtered
125143

126144

127145
def format_csv(cmd, installs):
128146
import csv
129147
installs = list(_csv_filter_and_expand(installs))
130148
if not installs:
131149
return
132-
s = set()
133-
columns = [c for i in installs for c in i
134-
if c not in s and (s.add(c) or True)]
135-
writer = csv.DictWriter(sys.stdout, columns)
150+
columns = list(dict.fromkeys(col for i in installs for col in i))
151+
152+
class LoggingIOWrapper:
153+
@staticmethod
154+
def write(s):
155+
LOGGER.print_raw(s, end="")
156+
157+
writer = csv.DictWriter(LoggingIOWrapper, columns)
136158
writer.writeheader()
137159
writer.writerows(installs)
138160

tests/test_list.py

Lines changed: 60 additions & 0 deletions
8000
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,63 @@ def test_format_table_empty(assert_log):
163163
(r"!B!Tag\s+Name\s+Managed By\s+Version\s+Alias\s*!W!", ()),
164164
(r".+No runtimes.+", ()),
165165
)
166+
167+
168+
def test_format_csv(assert_log):
169+
list_command.format_csv(None, FAKE_INSTALLS)
170+
# CSV format only contains columns that are present, so this doesn't look
171+
# as complete as for normal installs, but it's fine for the test.
172+
assert_log(
173+
"company,tag,sort-version,default",
174+
"Company2,1.0,1.0,",
175+
"Company1,2.0,2.0,",
176+
"Company1,1.0,1.0,True",
177+
)
178+
179+
180+
def test_format_csv_complex(assert_log):
181+
data = [
182+
{
183+
**d,
184+
"alias": [dict(name=f"n{i}.{j}", target=f"t{i}.{j}") for j in range(i + 1)]
185+
}
186+
for i, d in enumerate(FAKE_INSTALLS)
187+
]
188+
list_command.format_csv(None, data)
189+
assert_log(
190+
"company,tag,sort-version,alias.name,alias.target.default",
191+
"Company2,1.0,1.0,n0.0,t0.0,",
192+
"Company1,2.0,2.0,n1.0,t1.0,",
193+
"Company1,2.0,2.0,n1.1,t1.1,",
194+
"Company1,1.0,1.0,n2.0,t2.0,True",
195+
"Company1,1.0,1.0,n2.1,t2.1,True",
196+
"Company1,1.0,1.0,n2.2,t2.2,True",
197+
)
198+
199+
200+
def test_format_csv_empty(assert_log):
201+
list_command.format_csv(None, [])
202+
assert_log(assert_log.end_of_log())
203+
204+
205+
def test_csv_exclude():
206+
result = list(list_command._csv_filter_and_expand([
207+
dict(a=1, b=2),
208+
dict(a=3, c=4),
209+
dict(a=5, b=6, c=7),
210+
], exclude={"b"}))
211+
assert result == [dict(a=1), dict(a=3, c=4), dict(a=5, c=7)]
212+
213+
214+
def test_csv_expand():
215+
result = list(list_command._csv_filter_and_expand([
216+
dict(a=[1, 2], b=[3, 4]),
217+
dict(a=[5], b=[6]),
218+
dict(a=7, b=8),
219+
], expand={"a"}))
220+
assert result == [
221+
dict(a=1, b=[3, 4]),
222+
dict(a=2, b=[3, 4]),
223+
dict(a=5, b=[6]),
224+
dict(a=7, b=8),
225+
]

0 commit comments

Comments
 (0)
0