Skip to content

Commit 8a40096

Browse files
authored
Change-plugins-export-format (#2053)
* New utility functions * Fixes plugins export format * Utility functions update
1 parent 3ce2e7e commit 8a40096

File tree

3 files changed

+83
-62
lines changed

3 files changed

+83
-62
lines changed

cli/config.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,7 @@ def __parse_args(desc: str) -> object:
125125
def __normalize_json(json_data: dict[str, any], remove_empty: bool = True, remove_none: bool = True) -> dict[str, any]:
126126
"""Sorts a JSON file and optionally remove empty and none values"""
127127
log.info("Normalizing JSON - remove empty = %s, remove nones = %s", str(remove_empty), str(remove_none))
128-
if remove_empty:
129-
json_data = utilities.remove_empties(json_data)
130-
if remove_none:
131-
json_data = utilities.remove_nones(json_data)
128+
json_data = utilities.clean_data(json_data, remove_none=remove_none, remove_empty=remove_empty)
132129
json_data = utilities.order_keys(json_data, *_SECTIONS_ORDER)
133130
for key in [k for k in _SECTIONS_TO_SORT if k in json_data]:
134131
json_data[key] = {k: json_data[key][k] for k in sorted(json_data[key])}
@@ -260,7 +257,7 @@ def __prep_json_for_write(json_data: types.ObjectJsonRepr, export_settings: type
260257
json_data = utilities.remove_nones(json_data)
261258
if not export_settings.get(EXPORT_EMPTY, False):
262259
log.debug("Removing empties")
263-
json_data = utilities.remove_empties(json_data)
260+
json_data = utilities.clean_data(json_data, remove_empty=True)
264261
if export_settings.get("INLINE_LISTS", True):
265262
json_data = utilities.inline_lists(json_data, exceptions=("conditions",))
266263
return json_data

sonar/platform.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,12 @@ def basics(self) -> dict[str, str]:
189189
if self.is_sonarcloud():
190190
return {**data, "organization": self.organization}
191191

192-
return {**data, "version": util.version_to_string(self.version()[:3]), "serverId": self.server_id(), "plugins": self.plugins()}
192+
return {
193+
**data,
194+
"version": util.version_to_string(self.version()[:3]),
195+
"serverId": self.server_id(),
196+
"plugins": util.dict_to_list(self.plugins(), "key"),
197+
}
193198

194199
def default_user_group(self) -> str:
195200
"""

sonar/utilities.py

Lines changed: 75 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -172,18 +172,6 @@ def convert_to_type(value: Any) -> Any:
172172
return value
173173

174174

175-
def remove_nones(d: dict[str, any]) -> dict[str, any]:
176-
"""Removes elements of the dict that are None values"""
177-
new_d = d.copy()
178-
for k, v in d.items():
179-
if v is None:
180-
new_d.pop(k)
181-
continue
182-
if isinstance(v, dict):
183-
new_d[k] = remove_nones(v)
184-
return new_d
185-
186-
187175
def none_to_zero(d: dict[str, any], key_match: str = "^.+$") -> dict[str, any]:
188176
"""Replaces None values in a dict with 0"""
189177
new_d = d.copy()
@@ -197,21 +185,36 @@ def none_to_zero(d: dict[str, any], key_match: str = "^.+$") -> dict[str, any]:
197185
return new_d
198186

199187

200-
def remove_empties(d: dict[str, any]) -> dict[str, any]:
188+
def remove_nones(d: Any) -> Any:
189+
"""Removes elements of the data that are None values"""
190+
return clean_data(d, remove_empty=False, remove_none=True)
191+
192+
193+
def clean_data(d: Any, remove_empty: bool = True, remove_none: bool = True) -> Any:
201194
"""Recursively removes empty lists and dicts and none from a dict"""
202195
# log.debug("Cleaning up %s", json_dump(d))
203-
new_d = d.copy()
204-
for k, v in d.items():
205-
if isinstance(v, str) and v == "":
206-
new_d.pop(k)
207-
continue
208-
if not isinstance(v, (list, dict)):
209-
continue
210-
if len(v) == 0:
211-
new_d.pop(k)
212-
elif isinstance(v, dict):
213-
new_d[k] = remove_empties(v)
214-
return new_d
196+
if not isinstance(d, (list, dict)):
197+
return d
198+
199+
if isinstance(d, list):
200+
# Remove empty strings and nones
201+
if remove_empty:
202+
d = [elem for elem in d if not (isinstance(elem, str) and elem == "")]
203+
if remove_none:
204+
d = [elem for elem in d if elem is not None]
205+
return [clean_data(elem, remove_empty, remove_none) for elem in d]
206+
207+
# Remove empty dict string values
208+
if remove_empty:
209+
new_d = {k: v for k, v in d.items() if not isinstance(v, str) or v != ""}
210+
if remove_none:
211+
new_d = {k: v for k, v in d.items() if v is not None}
212+
213+
# Remove empty dict list or dict values
214+
new_d = {k: v for k, v in new_d.items() if not isinstance(v, (list, dict)) or len(v) > 0}
215+
216+
# Recurse
217+
return {k: clean_data(v, remove_empty, remove_none) for k, v in new_d.items()}
215218

216219

217220
def sort_lists(data: Any, redact_tokens: bool = True) -> Any:
@@ -278,23 +281,21 @@ def list_to_regexp(str_list: list[str]) -> str:
278281
return "(" + "|".join(str_list) + ")" if len(str_list) > 0 else ""
279282

280283

281-
def list_to_csv(
282-
array: Union[None, str, int, float, list[str], set[str], tuple[str]], separator: str = ",", check_for_separator: bool = False
283-
) -> Optional[str]:
284+
def list_to_csv(array: Union[None, str, int, float, list[str], set[str], tuple[str]], separator: str = ",", check_for_separator: bool = False) -> Any:
284285
"""Converts a list of strings to CSV"""
285286
if isinstance(array, str):
286287
return csv_normalize(array, separator) if " " in array else array
287288
if array is None:
288289
return None
289-
if isinstance(array, (list, set, tuple)):
290+
if isinstance(array, (list, set, tuple)) and all(isinstance(e, str) for e in array):
290291
if check_for_separator:
291292
# Don't convert to string if one array item contains the string separator
292293
s = separator.strip()
293294
for item in array:
294295
if s in item:
295296
return array
296297
return separator.join([v.strip() for v in array])
297-
return str(array)
298+
return array
298299

299300

300301
def csv_normalize(string: str, separator: str = ",") -> str:
@@ -314,10 +315,10 @@ def union(list1: list[any], list2: list[any]) -> list[any]:
314315
return list1 + [value for value in list2 if value not in list1]
315316

316317

317-
def difference(list1: list[any], list2: list[any]) -> list[any]:
318+
def difference(list1: list[Any], list2: list[Any]) -> list[Any]:
318319
"""Computes difference of 2 lists"""
319320
# FIXME - This should be sets
320-
return [value for value in list1 if value not in list2]
321+
return list(set(list1) - set(list2))
321322

322323

323324
def quote(string: str, sep: str) -> str:
@@ -578,15 +579,11 @@ def __prefix(value: Any) -> Any:
578579
return value
579580

580581

581-
def filter_export(json_data: dict[str, any], key_properties: list[str], full: bool) -> dict[str, any]:
582+
def filter_export(json_data: dict[str, Any], key_properties: list[str], full: bool) -> dict[str, Any]:
582583
"""Filters dict for export removing or prefixing non-key properties"""
583-
new_json_data = json_data.copy()
584-
for k in json_data:
585-
if k not in key_properties:
586-
if full and k != "actions":
587-
new_json_data[f"_{k}"] = __prefix(new_json_data.pop(k))
588-
else:
589-
new_json_data.pop(k)
584+
new_json_data = {k: json_data[k] for k in key_properties if k in json_data}
585+
if full:
586+
new_json_data |= {f"_{k}": __prefix(v) for k, v in json_data.items() if k not in key_properties}
590587
return new_json_data
591588

592589

@@ -726,15 +723,15 @@ def dict_remap_and_stringify(original_dict: dict[str, str], remapping: dict[str,
726723
return dict_stringify(dict_remap(original_dict, remapping))
727724

728725

729-
def list_to_dict(original_list: list[dict[str, any]], key_field: str) -> dict[str, any]:
726+
def list_to_dict(original_list: list[dict[str, Any]], key_field: str) -> dict[str, any]:
730727
"""Converts a list to dict with list key_field as dict key"""
731728
converted_dict = {elem[key_field]: elem for elem in original_list}
732729
for e in converted_dict.values():
733730
e.pop(key_field)
734731
return converted_dict
735732

736733

737-
def dict_to_list(original_dict: dict[str, any], key_field: str, value_field: Optional[str] = "value") -> list[str, any]:
734+
def dict_to_list(original_dict: dict[str, Any], key_field: str, value_field: Optional[str] = "value") -> list[str, any]:
738735
"""Converts a dict to list adding dict key in list key_field"""
739736
if isinstance(original_dict, list):
740737
return original_dict
@@ -794,20 +791,6 @@ def pretty_print_json(file: str) -> bool:
794791
return True
795792

796793

797-
def order_keys(original_dict: dict[str, any], *keys) -> dict[str, any]:
798-
"""Orders a dict keys in a chosen order, existings keys not in *keys are pushed to the end
799-
:param dict[str, any] original_dict: Dict to order
800-
:param str *keys: List of keys in desired order
801-
:return: same dict with keys in desired order
802-
"""
803-
ordered_dict = {}
804-
for key in [k for k in keys if k in original_dict]:
805-
ordered_dict[key] = original_dict[key]
806-
for key in [k for k in original_dict if k not in keys]:
807-
ordered_dict[key] = original_dict[key]
808-
return ordered_dict
809-
810-
811794
def flatten(original_dict: dict[str, any]) -> dict[str, any]:
812795
"""Flattens a recursive dict into a flat one"""
813796
flat_dict = {}
@@ -825,3 +808,39 @@ def similar_strings(key1: str, key2: str, max_distance: int = 5) -> bool:
825808
return False
826809
max_distance = min(len(key1) // 2, len(key2) // 2, max_distance)
827810
return (len(key2) >= 7 and (re.match(key2, key1))) or Levenshtein.distance(key1, key2, score_cutoff=6) <= max_distance
811+
812+
813+
def sort_list_by_key(list_to_sort: list[dict[str, Any]], key: str, priority_field: Optional[str] = None) -> list[dict[str, Any]]:
814+
"""Sorts a lits of dicts by a given key, exception for the priority field that would go first"""
815+
f_elem = None
816+
if priority_field:
817+
f_elem = next((elem for elem in list_to_sort if priority_field in elem), None)
818+
tmp_dict = {elem[key]: elem for elem in list_to_sort if elem != f_elem}
819+
first_elem = [f_elem] if f_elem else []
820+
return first_elem + list(dict(sorted(tmp_dict.items())).values())
821+
822+
823+
def order_keys(original_dict: dict[str, any], *keys) -> dict[str, any]:
824+
"""Orders a dict keys in a chosen order, existings keys not in *keys are pushed to the end
825+
:param dict[str, any] original_dict: Dict to order
826+
:param str *keys: List of keys in desired order
827+
:return: same dict with keys in desired order
828+
"""
829+
ordered_dict = {}
830+
for key in [k for k in keys if k in original_dict]:
831+
ordered_dict[key] = original_dict[key]
832+
for key in [k for k in original_dict if k not in keys]:
833+
ordered_dict[key] = original_dict[key]
834+
return ordered_dict
835+
836+
837+
def order_dict(d: dict[str, Any], key_order: list[str]) -> dict[str, Any]:
838+
"""Orders keys of a dictionary in a given order"""
839+
new_d = {k: d[k] for k in key_order if k in d}
840+
return new_d | {k: v for k, v in d.items() if k not in new_d}
841+
842+
843+
def order_list(l: list[str], *key_order) -> list[str]:
844+
"""Orders elements of a list in a given order"""
845+
new_l = [k for k in key_order if k in l]
846+
return new_l + [k for k in l if k not in new_l]

0 commit comments

Comments
 (0)