Skip to content

Commit

Permalink
extended vis aux for nodes names adjustments, added tests for aux
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanovaos committed Sep 12, 2024
1 parent 0854ae2 commit c7bf3f8
Show file tree
Hide file tree
Showing 2 changed files with 194 additions and 8 deletions.
87 changes: 79 additions & 8 deletions networkcommons/visual/_aux.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,83 @@
# https://www.gnu.org/licenses/gpl-3.0.txt
#

from typing import List
from networkcommons._session import _log
import re

def wrap_node_name(node_name):
if ":" in node_name:
node_name = node_name.replace(":", "_")
if node_name.startswith("COMPLEX"):
# remove the word COMPLEX with a separator (:/-, etc)
return node_name[8:]
else:
return node_name

def adjust_node_name(node_name: str,
truncate: bool = False,
wrap: bool = False,
max_length: int = 8,
wrap_length: int = 8,
ensure_unique: bool = False,
ensure_unique_list: List[str] = None,
remove_strings: List[str] = None) -> str:
"""
Adjust the node name by replacing special characters, truncating, wrapping, and ensuring uniqueness.
Parameters
----------
node_name : str
The node name to adjust.
truncate : bool, optional
Whether to truncate the node name, by default False.
wrap : bool, optional
Whether to wrap the node name, by default False.
max_length : int, optional
The maximum length of the node name, by default 8.
wrap_length : int, optional
The length at which to wrap the node name, by default 8.
ensure_unique : bool, optional
Whether to ensure the node name is unique, by default False.
ensure_unique_list : List[str], optional
A list of node names to ensure uniqueness against, by default None.
remove_strings : List[str], optional
A list of substrings to remove from the node name, by default None.
"""

# Replace any ':' with '_'
node_name = node_name.replace(":", "_")

# Remove provided substrings, if any
if remove_strings:
for string in remove_strings:
node_name = node_name.replace(string, "")

# Replace special symbols (anything non-alphanumeric or underscore) with '_'
new_node_name = re.sub(r'[^a-zA-Z0-9_]', '_', node_name)

# Log any replacement of special symbols
if new_node_name != node_name:
_log(f"Replaced special characters in '{node_name}' with underscores.", level=10)

# If the modified node name is longer than the specified maximum length, truncate it
if truncate and len(new_node_name) > max_length:
new_node_name = new_node_name[:max_length] + ".."
_log(f"Truncated node name '{node_name}' to '{new_node_name}'.", level=10)

# If the wrap flag is set to True, wrap the node name
if wrap:
new_node_name = "\n".join([new_node_name[i:i + wrap_length]
for i in range(0, len(new_node_name), wrap_length)])

# If multiple underscores are present, replace them with a single underscore
new_node_name = re.sub(r'_+', '_', new_node_name)

# If the node name is empty, return an empty string and log a warning
if not new_node_name:
_log("Empty node name provided. Returning an empty string.", level=20)
return ""

if ensure_unique and ensure_unique_list:
# Ensure the modified node name is unique by appending a number
if new_node_name in ensure_unique_list:
i = 1
while f"{new_node_name}_{i}" in ensure_unique_list:
i += 1
new_node_name = f"{new_node_name}_{i}"
_log(f"Ensured unique node name by appending a number: '{new_node_name}'.", level=10)

# Return the modified node name, stripped of leading and trailing spaces, and _ characters
return new_node_name.strip("_")
115 changes: 115 additions & 0 deletions tests/test_vis_aux.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import pytest
from networkcommons.visual._aux import adjust_node_name


def test_replace_colon():
assert adjust_node_name(
"node:name"
) == "node_name"


def test_remove_provided_strings():
# Remove 'COMPLEX' and 'ABC'
assert adjust_node_name(
"COMPLEX:ABC:node",
remove_strings=["COMPLEX", "ABC"]
) == "node"


def test_special_character_replacement():
# Replace special characters with '_'
assert adjust_node_name(
"node@name#1!"
) == "node_name_1"


def test_truncate_node_name():
# Truncate node name to max_length
assert adjust_node_name(
"VeryLongNodeName",
truncate=True,
max_length=8
) == "VeryLong.."


def test_wrap_node_name():
# Wrap node name into lines of wrap_length
assert adjust_node_name(
"VeryLongNodeName",
wrap=True,
wrap_length=4
) == "Very\nLong\nNode\nName"


def test_no_truncate_or_wrap():
# Test without truncation or wrapping
assert adjust_node_name(
"node_name",
truncate=False,
wrap=False
) == "node_name"


def test_empty_node_name():
# Handle empty node name
assert adjust_node_name(
"",
remove_strings=["COMPLEX"]
) == ""


def test_strip_whitespace():
# Ensure leading and trailing spaces are stripped
assert adjust_node_name(
" COMPLEX:node ",
remove_strings=["COMPLEX"]
) == "node"


def test_multiple_underscores():
# Test reducing multiple underscores to a single one
assert adjust_node_name(
"node___name"
) == "node_name"


def test_unique_node_name():
# Test ensuring uniqueness by appending a number
assert adjust_node_name(
"node_name",
ensure_unique=True,
ensure_unique_list=["node_name", "node_name_1"]
) == "node_name_2"


def test_ensure_unique_with_empty_list():
# Test ensuring uniqueness when the list is empty
assert adjust_node_name(
"node_name",
ensure_unique=True,
ensure_unique_list=[]
) == "node_name"


def test_empty_name_after_modifications():
# Test if name becomes empty after all modifications
assert adjust_node_name(
"COMPLEX:ABC",
remove_strings=["COMPLEX", "ABC"]
) == ""


def test_trailing_underscores():
# Test if trailing underscores are removed after modifications
assert adjust_node_name(
"node___",
remove_strings=["___"]
) == "node"


def test_leading_trailing_underscores_trimmed():
# Test trimming of leading and trailing underscores
assert adjust_node_name(
"___node___",
remove_strings=[]
) == "node"

0 comments on commit c7bf3f8

Please sign in to comment.