arches_extensions.utils
1import uuid 2import textwrap 3from typing import Union 4from argparse import RawTextHelpFormatter 5 6from django.db.models.functions import Lower 7 8from arches.app.models.graph import Graph 9 10class ArchesCLIStyles(): 11 """ 12Styles for Arches CLI output. Borrowed heavily from https://stackoverflow.com/a/26445590/3873885. 13 14Usage:: 15 16 s = ArchesCLIStyles() 17 18Add arbitrary style within strings:: 19 20 print(f"{s.fg.red}Red text{s.reset} not red text") 21 22Some methods transform text in predetermined ways, like 23the following format for an optional CLI argument:: 24 25 print(s.opt("--source")) 26 27Further notes 28 29 - Reset all colors with `s.reset` 30 - Two subclasses `fg` for foreground and `bg` for background. 31 - Use as `s.<subclass>.<colorname>`, e.g., `s.fg.red` or `s.bg.green` 32 - Also, `bold`, `disable`, `underline`, `reverse`, `strikethrough`, 33 and `invisible` work with the main class, e.g., `s.bold` 34""" 35 reset='\033[0m' 36 bold='\033[01m' 37 disable='\033[02m' 38 underline='\033[04m' 39 blink='\33[5m' 40 noblink='\33[25m' 41 reverse='\033[07m' 42 strikethrough='\033[09m' 43 invisible='\033[08m' 44 class fg: 45 black='\033[30m' 46 red='\033[31m' 47 green='\033[32m' 48 orange='\033[33m' 49 blue='\033[34m' 50 purple='\033[35m' 51 cyan='\033[36m' 52 lightgrey='\033[37m' 53 darkgrey='\033[90m' 54 lightred='\033[91m' 55 lightgreen='\033[92m' 56 yellow='\033[93m' 57 lightblue='\033[94m' 58 pink='\033[95m' 59 lightcyan='\033[96m' 60 class bg: 61 black='\033[40m' 62 red='\033[41m' 63 green='\033[42m' 64 orange='\033[43m' 65 blue='\033[44m' 66 purple='\033[45m' 67 cyan='\033[46m' 68 lightgrey='\033[47m' 69 salmon='\033[101m' 70 71 def print_ansi_codes(self): 72 """ 73 This is a helper method that may be useful during style development. 74 75 https://stackoverflow.com/a/39452138/3873885 76 """ 77 x = 0 78 for i in range(24): 79 colors = "" 80 for j in range(5): 81 code = str(x+j) 82 colors += "\33[" + code + "m\\33[" + code + "m\033[0m " 83 print(colors) 84 x += 5 85 86 def req(self, string): 87 return f"{self.fg.lightgreen}{string}{self.reset}" 88 89 def opt(self, string): 90 return f"{self.fg.yellow}{string}{self.reset}" 91 92 def invert(self, string): 93 return f"{self.reverse}{string}{self.reset}" 94 95 def error(self, string): 96 return f"{self.fg.lightred}{self.bold}{self.blink}{string}{self.reset}" 97 98 def warn(self, string): 99 return f"{self.fg.cyan}{self.bold}{string}{self.reset}" 100 101class ArchesHelpTextFormatter(RawTextHelpFormatter): 102 """Help message formatter that applies optional text styling.""" 103 def _split_lines(self, text, width): 104 ret = [] 105 for line in text.splitlines(): 106 ret += [i for i in textwrap.wrap(line.strip(), width)] 107 return ret 108 109def get_graph(name_or_uuid: Union[str, uuid.UUID]) -> Graph: 110 """ Utility function to get a graph by its name or UUID. """ 111 graph = None 112 try: 113 uid = uuid.UUID(str(name_or_uuid)) 114 except ValueError: 115 qs = Graph.objects.annotate(name_lower=Lower('name')) 116 graphs = qs.filter(name_lower=str(name_or_uuid).lower(), isresource=True) 117 if graphs.count() == 1: 118 return graphs[0] 119 elif graphs.count() > 1: 120 msg = "Choose one of the following (by number):" 121 lookup = {} 122 for n, g in enumerate(graphs, start=1): 123 msg += f"\n{n}. {g.name}, {g.uuid}" 124 lookup[n] = g 125 choice = input(msg) 126 if choice in lookup: 127 graph = lookup[choice] 128 129 return graph 130 131def user_confirms(message:str="Continue?", default:bool=True): 132 133 message = f"{message} Y/n " if default is True else f"{message} y/N " 134 response = input(message).lower() 135 if not response: 136 return default 137 elif response.startswith("y"): 138 return True 139 else: 140 return False
class
ArchesCLIStyles:
11class ArchesCLIStyles(): 12 """ 13Styles for Arches CLI output. Borrowed heavily from https://stackoverflow.com/a/26445590/3873885. 14 15Usage:: 16 17 s = ArchesCLIStyles() 18 19Add arbitrary style within strings:: 20 21 print(f"{s.fg.red}Red text{s.reset} not red text") 22 23Some methods transform text in predetermined ways, like 24the following format for an optional CLI argument:: 25 26 print(s.opt("--source")) 27 28Further notes 29 30 - Reset all colors with `s.reset` 31 - Two subclasses `fg` for foreground and `bg` for background. 32 - Use as `s.<subclass>.<colorname>`, e.g., `s.fg.red` or `s.bg.green` 33 - Also, `bold`, `disable`, `underline`, `reverse`, `strikethrough`, 34 and `invisible` work with the main class, e.g., `s.bold` 35""" 36 reset='\033[0m' 37 bold='\033[01m' 38 disable='\033[02m' 39 underline='\033[04m' 40 blink='\33[5m' 41 noblink='\33[25m' 42 reverse='\033[07m' 43 strikethrough='\033[09m' 44 invisible='\033[08m' 45 class fg: 46 black='\033[30m' 47 red='\033[31m' 48 green='\033[32m' 49 orange='\033[33m' 50 blue='\033[34m' 51 purple='\033[35m' 52 cyan='\033[36m' 53 lightgrey='\033[37m' 54 darkgrey='\033[90m' 55 lightred='\033[91m' 56 lightgreen='\033[92m' 57 yellow='\033[93m' 58 lightblue='\033[94m' 59 pink='\033[95m' 60 lightcyan='\033[96m' 61 class bg: 62 black='\033[40m' 63 red='\033[41m' 64 green='\033[42m' 65 orange='\033[43m' 66 blue='\033[44m' 67 purple='\033[45m' 68 cyan='\033[46m' 69 lightgrey='\033[47m' 70 salmon='\033[101m' 71 72 def print_ansi_codes(self): 73 """ 74 This is a helper method that may be useful during style development. 75 76 https://stackoverflow.com/a/39452138/3873885 77 """ 78 x = 0 79 for i in range(24): 80 colors = "" 81 for j in range(5): 82 code = str(x+j) 83 colors += "\33[" + code + "m\\33[" + code + "m\033[0m " 84 print(colors) 85 x += 5 86 87 def req(self, string): 88 return f"{self.fg.lightgreen}{string}{self.reset}" 89 90 def opt(self, string): 91 return f"{self.fg.yellow}{string}{self.reset}" 92 93 def invert(self, string): 94 return f"{self.reverse}{string}{self.reset}" 95 96 def error(self, string): 97 return f"{self.fg.lightred}{self.bold}{self.blink}{string}{self.reset}" 98 99 def warn(self, string): 100 return f"{self.fg.cyan}{self.bold}{string}{self.reset}"
Styles for Arches CLI output. Borrowed heavily from https://stackoverflow.com/a/26445590/3873885.
Usage::
s = ArchesCLIStyles()
Add arbitrary style within strings::
print(f"{s.fg.red}Red text{s.reset} not red text")
Some methods transform text in predetermined ways, like the following format for an optional CLI argument::
print(s.opt("--source"))
Further notes
- Reset all colors with `s.reset`
- Two subclasses `fg` for foreground and `bg` for background.
- Use as `s.<subclass>.<colorname>`, e.g., `s.fg.red` or `s.bg.green`
- Also, `bold`, `disable`, `underline`, `reverse`, `strikethrough`,
and `invisible` work with the main class, e.g., `s.bold`
def
print_ansi_codes(self):
72 def print_ansi_codes(self): 73 """ 74 This is a helper method that may be useful during style development. 75 76 https://stackoverflow.com/a/39452138/3873885 77 """ 78 x = 0 79 for i in range(24): 80 colors = "" 81 for j in range(5): 82 code = str(x+j) 83 colors += "\33[" + code + "m\\33[" + code + "m\033[0m " 84 print(colors) 85 x += 5
This is a helper method that may be useful during style development.
class
ArchesCLIStyles.fg:
45 class fg: 46 black='\033[30m' 47 red='\033[31m' 48 green='\033[32m' 49 orange='\033[33m' 50 blue='\033[34m' 51 purple='\033[35m' 52 cyan='\033[36m' 53 lightgrey='\033[37m' 54 darkgrey='\033[90m' 55 lightred='\033[91m' 56 lightgreen='\033[92m' 57 yellow='\033[93m' 58 lightblue='\033[94m' 59 pink='\033[95m' 60 lightcyan='\033[96m'
class
ArchesCLIStyles.bg:
class
ArchesHelpTextFormatter(argparse.RawTextHelpFormatter):
102class ArchesHelpTextFormatter(RawTextHelpFormatter): 103 """Help message formatter that applies optional text styling.""" 104 def _split_lines(self, text, width): 105 ret = [] 106 for line in text.splitlines(): 107 ret += [i for i in textwrap.wrap(line.strip(), width)] 108 return ret
Help message formatter that applies optional text styling.
def
get_graph(name_or_uuid: Union[str, uuid.UUID]) -> arches.app.models.graph.Graph:
110def get_graph(name_or_uuid: Union[str, uuid.UUID]) -> Graph: 111 """ Utility function to get a graph by its name or UUID. """ 112 graph = None 113 try: 114 uid = uuid.UUID(str(name_or_uuid)) 115 except ValueError: 116 qs = Graph.objects.annotate(name_lower=Lower('name')) 117 graphs = qs.filter(name_lower=str(name_or_uuid).lower(), isresource=True) 118 if graphs.count() == 1: 119 return graphs[0] 120 elif graphs.count() > 1: 121 msg = "Choose one of the following (by number):" 122 lookup = {} 123 for n, g in enumerate(graphs, start=1): 124 msg += f"\n{n}. {g.name}, {g.uuid}" 125 lookup[n] = g 126 choice = input(msg) 127 if choice in lookup: 128 graph = lookup[choice] 129 130 return graph
Utility function to get a graph by its name or UUID.
def
user_confirms(message: str = 'Continue?', default: bool = True):