• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

liqd / roots / 22995037636

12 Mar 2026 09:24AM UTC coverage: 81.129% (-0.4%) from 81.522%
22995037636

push

github

web-flow
apps/summarization: refactor export (#88)

74 of 360 new or added lines in 16 files covered. (20.56%)

7386 of 9104 relevant lines covered (81.13%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

5.97
/apps/summarization/export_utils/processing/cleaning.py
1
def clean_dict(data):
1✔
2
    """Remove empty/null values from a dictionary recursively."""
NEW
3
    if not isinstance(data, dict):
×
NEW
4
        return data
×
5

NEW
6
    cleaned = {}
×
NEW
7
    for key, value in data.items():
×
8
        # Skip None values
NEW
9
        if value is None:
×
NEW
10
            continue
×
11

12
        # Skip empty lists
NEW
13
        if isinstance(value, list) and len(value) == 0:
×
NEW
14
            continue
×
15

16
        # Skip empty strings
NEW
17
        if isinstance(value, str) and value == "":
×
NEW
18
            continue
×
19

20
        # Recursively clean nested dicts
NEW
21
        if isinstance(value, dict):
×
NEW
22
            cleaned_value = clean_dict(value)
×
NEW
23
            if cleaned_value:  # Only include non-empty dicts
×
NEW
24
                cleaned[key] = cleaned_value
×
25
        else:
NEW
26
            cleaned[key] = value
×
27

NEW
28
    return cleaned
×
29

30

31
def clean_comment(comment):
1✔
32
    """Clean a comment by removing redundant fields."""
NEW
33
    cleaned = {
×
34
        "id": comment["id"],
35
        "text": comment["text"],
36
        "created": comment["created"],
37
    }
38

39
    # Only include replies if they exist
NEW
40
    if comment.get("replies"):
×
NEW
41
        cleaned["replies"] = [clean_comment(r) for r in comment["replies"]]
×
NEW
42
        cleaned["reply_count"] = len(cleaned["replies"])
×
43

44
    # Only include ratings if they exist
NEW
45
    if comment.get("ratings"):
×
NEW
46
        cleaned["ratings"] = comment["ratings"]
×
47

NEW
48
    return cleaned
×
49

50

51
def clean_content_item(item):  # noqa: C901
1✔
52
    """Clean a content item (idea, poll, etc.) by removing empty fields."""
NEW
53
    cleaned = {}
×
54

55
    # Always include essential fields
NEW
56
    for field in ["id", "name", "description", "created", "reference_number"]:
×
NEW
57
        if field in item:
×
NEW
58
            cleaned[field] = item[field]
×
59

60
    # Optional fields only if they have values
NEW
61
    if item.get("category"):
×
NEW
62
        cleaned["category"] = item["category"]
×
63

NEW
64
    if item.get("labels"):
×
NEW
65
        cleaned["labels"] = item["labels"]
×
66

NEW
67
    if item.get("attachments"):
×
NEW
68
        cleaned["attachments"] = item["attachments"]
×
69

NEW
70
    if item.get("images") and item["images"] != [""]:
×
NEW
71
        cleaned["images"] = item["images"]
×
72

73
    # Clean comments
NEW
74
    if item.get("comments"):
×
NEW
75
        cleaned["comments"] = [clean_comment(c) for c in item["comments"]]
×
76

77
    # Clean ratings
NEW
78
    if item.get("ratings"):
×
NEW
79
        cleaned["ratings"] = item["ratings"]
×
80

81
    # Poll-specific fields
NEW
82
    if item.get("choices"):
×
NEW
83
        cleaned["choices"] = item["choices"]
×
NEW
84
    if item.get("answers"):
×
NEW
85
        cleaned["answers"] = item["answers"]
×
NEW
86
    if item.get("other_answers"):
×
NEW
87
        cleaned["other_answers"] = item["other_answers"]
×
88

89
    # Map-specific fields
NEW
90
    if item.get("point") and (item["point"].get("lat") or item["point"].get("lng")):
×
NEW
91
        cleaned["point"] = item["point"]
×
NEW
92
    if item.get("point_label"):
×
NEW
93
        cleaned["point_label"] = item["point_label"]
×
94

NEW
95
    return cleaned
×
96

97

98
def clean_export(export_data):
1✔
99
    """Clean the entire export by removing empty/null values."""
NEW
100
    cleaned = {
×
101
        "project": clean_dict(export_data["project"]),  # Keep this for project
102
        "phases": {},
103
        "offline_events": export_data.get("offline_events", []),
104
    }
105

106
    # Clean each phase
NEW
107
    for phase_name, phase_data in export_data["phases"].items():
×
NEW
108
        cleaned_phase = {"phase_status": phase_data["phase_status"], "modules": []}
×
109

NEW
110
        for module in phase_data["modules"]:
×
NEW
111
            cleaned_module = {
×
112
                "module_id": module["module_id"],
113
                "module_name": module["module_name"],
114
                "module_type": module["module_type"],
115
                "module_start": module["module_start"],
116
                "module_end": module["module_end"],
117
                "url": module["url"],
118
                "content": {},
119
            }
120

121
            # Only include description if it exists
NEW
122
            if module.get("description"):
×
NEW
123
                cleaned_module["description"] = module["description"]
×
124

125
            # Clean each content type
NEW
126
            for content_type, items in module["content"].items():
×
NEW
127
                if items:
×
NEW
128
                    cleaned_module["content"][content_type] = [
×
129
                        clean_content_item(item) for item in items
130
                    ]
131

NEW
132
            cleaned_phase["modules"].append(cleaned_module)  # Remove clean_dict
×
133

NEW
134
        cleaned["phases"][phase_name] = cleaned_phase
×
135

NEW
136
    return cleaned  # Remove final clean_dict
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc