pre-commit-crocodile 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. pre_commit_crocodile/__init__.py +5 -0
  2. pre_commit_crocodile/__main__.py +5 -0
  3. pre_commit_crocodile/assets/.cz.yaml +188 -0
  4. pre_commit_crocodile/assets/.pre-commit-config.yaml +68 -0
  5. pre_commit_crocodile/assets/__init__.py +0 -0
  6. pre_commit_crocodile/cli/__init__.py +0 -0
  7. pre_commit_crocodile/cli/entrypoint.py +414 -0
  8. pre_commit_crocodile/cli/main.py +269 -0
  9. pre_commit_crocodile/hooks/__init__.py +0 -0
  10. pre_commit_crocodile/hooks/configurations.py +322 -0
  11. pre_commit_crocodile/hooks/prepare_commit_message.py +258 -0
  12. pre_commit_crocodile/package/__init__.py +0 -0
  13. pre_commit_crocodile/package/bundle.py +34 -0
  14. pre_commit_crocodile/package/settings.py +148 -0
  15. pre_commit_crocodile/package/updates.py +228 -0
  16. pre_commit_crocodile/package/version.py +80 -0
  17. pre_commit_crocodile/prints/__init__.py +0 -0
  18. pre_commit_crocodile/prints/boxes.py +82 -0
  19. pre_commit_crocodile/prints/colors.py +85 -0
  20. pre_commit_crocodile/system/__init__.py +0 -0
  21. pre_commit_crocodile/system/commands.py +90 -0
  22. pre_commit_crocodile/system/platform.py +74 -0
  23. pre_commit_crocodile/types/__init__.py +0 -0
  24. pre_commit_crocodile/types/environments.py +92 -0
  25. pre_commit_crocodile/types/strings.py +152 -0
  26. pre_commit_crocodile-2.0.0.dist-info/LICENSE +201 -0
  27. pre_commit_crocodile-2.0.0.dist-info/METADATA +212 -0
  28. pre_commit_crocodile-2.0.0.dist-info/RECORD +31 -0
  29. pre_commit_crocodile-2.0.0.dist-info/WHEEL +5 -0
  30. pre_commit_crocodile-2.0.0.dist-info/entry_points.txt +3 -0
  31. pre_commit_crocodile-2.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Standard libraries
4
+ from os import environ
5
+ from sys import version_info
6
+
7
+ # Components
8
+ from ..system.platform import Platform
9
+ from .bundle import Bundle
10
+
11
+ # Version class
12
+ class Version:
13
+
14
+ # Getter
15
+ @staticmethod
16
+ def get() -> str:
17
+
18
+ # Fake test version
19
+ if Bundle.ENV_DEBUG_VERSION_FAKE in environ:
20
+ return environ[Bundle.ENV_DEBUG_VERSION_FAKE]
21
+
22
+ # Acquire version from metadata
23
+ try:
24
+ from importlib import metadata # pylint: disable=import-outside-toplevel
25
+ return metadata.version(Bundle.PACKAGE)
26
+ except Exception: # pylint: disable=broad-exception-caught # pragma: no cover
27
+ pass
28
+
29
+ # Acquire version from resources
30
+ try: # pragma: no cover
31
+ from pkg_resources import require # pylint: disable=import-outside-toplevel
32
+ name = __name__.split('.', maxsplit=1)[0]
33
+ return str(require(name)[0].version)
34
+
35
+ # Default fallback
36
+ except Exception: # pylint: disable=broad-exception-caught # pragma: no cover
37
+ return '0.0.0'
38
+
39
+ # Path
40
+ @staticmethod
41
+ def path() -> str:
42
+
43
+ # Acquire path
44
+ path = __file__
45
+
46
+ # Strip package path
47
+ index = path.rfind(Platform.PATH_SEPARATOR)
48
+ index = path.rfind(Platform.PATH_SEPARATOR, 0, index)
49
+ path = path[0:index]
50
+
51
+ # Result
52
+ return path
53
+
54
+ # Python
55
+ @staticmethod
56
+ def python() -> str:
57
+
58
+ # Acquire Python version
59
+ version = f'{version_info.major}.{version_info.minor}'
60
+
61
+ # Result
62
+ return version
63
+
64
+ # Revision
65
+ @staticmethod
66
+ def revision() -> str:
67
+
68
+ # Force package revision
69
+ if Bundle.ENV_DEBUG_REVISION_SHA in environ:
70
+ return environ[Bundle.ENV_DEBUG_REVISION_SHA]
71
+
72
+ # Acquire package version
73
+ version: str = Version.get()
74
+
75
+ # Handle development version
76
+ if '+g' in version:
77
+ return version.split('+g')[1].split('.')[0]
78
+
79
+ # Result
80
+ return version
File without changes
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Standard libraries
4
+ from shutil import get_terminal_size
5
+ from typing import List
6
+
7
+ # Components
8
+ from ..system.platform import Platform
9
+ from ..types.strings import Strings
10
+ from .colors import Colors
11
+
12
+ # Boxes class
13
+ class Boxes:
14
+
15
+ # Constants
16
+ __TOP_LEFT: str = '╭' if Platform.IS_TTY_UTF8 else '-'
17
+ __TOP_LINE: str = '─' if Platform.IS_TTY_UTF8 else '-'
18
+ __TOP_RIGHT: str = '╮' if Platform.IS_TTY_UTF8 else '-'
19
+ __MIDDLE_LEFT: str = '│' if Platform.IS_TTY_UTF8 else '|'
20
+ __MIDDLE_RIGHT: str = '│' if Platform.IS_TTY_UTF8 else '|'
21
+ __BOTTOM_LEFT: str = '╰' if Platform.IS_TTY_UTF8 else '-'
22
+ __BOTTOM_LINE: str = '─' if Platform.IS_TTY_UTF8 else '-'
23
+ __BOTTOM_RIGHT: str = '╯' if Platform.IS_TTY_UTF8 else '-'
24
+ __OFFSET_LINE: int = 2
25
+ __PADDING_LINE: int = 2
26
+
27
+ # Members
28
+ __lines: List[str]
29
+
30
+ # Constructor
31
+ def __init__(self) -> None:
32
+
33
+ # Initialize members
34
+ self.__lines = []
35
+
36
+ # Adder
37
+ def add(self, line: str) -> None:
38
+
39
+ # Add line
40
+ self.__lines += [line]
41
+
42
+ # Printer
43
+ def print(self) -> None:
44
+
45
+ # Evaluate lines length
46
+ length = max(len(Colors.strip(line)) for line in self.__lines)
47
+
48
+ # Acquire terminal width
49
+ columns, _ = get_terminal_size()
50
+
51
+ # Limit line length
52
+ limit = columns - Boxes.__OFFSET_LINE - len(
53
+ Boxes.__MIDDLE_LEFT) - 2 * Boxes.__PADDING_LINE - len(Boxes.__MIDDLE_RIGHT)
54
+ limit = max(limit, 1)
55
+ length = min(length, limit)
56
+
57
+ # Header
58
+ print(' ')
59
+
60
+ # Print header line
61
+ print(f"{' ' * Boxes.__OFFSET_LINE}{Colors.YELLOW}{Boxes.__TOP_LEFT}" \
62
+ f'{Boxes.__TOP_LINE * (length + 2 * Boxes.__PADDING_LINE)}{Boxes.__TOP_RIGHT}')
63
+
64
+ # Print content lines
65
+ for line in self.__lines:
66
+ for part in Strings.wrap(line, length=length):
67
+ print(
68
+ f"{' ' * Boxes.__OFFSET_LINE}{Colors.YELLOW}{Boxes.__MIDDLE_LEFT}" \
69
+ f"{' ' * Boxes.__PADDING_LINE}{Strings.center(part, length)}" \
70
+ f"{' ' * Boxes.__PADDING_LINE}{Colors.YELLOW}{Boxes.__MIDDLE_RIGHT}"
71
+ )
72
+
73
+ # Print bottom line
74
+ print(
75
+ f"{' ' * Boxes.__OFFSET_LINE}{Colors.YELLOW}{Boxes.__BOTTOM_LEFT}" \
76
+ f'{Boxes.__BOTTOM_LINE * (length + 2 * Boxes.__PADDING_LINE)}' \
77
+ f'{Boxes.__BOTTOM_RIGHT}{Colors.RESET}'
78
+ )
79
+
80
+ # Footer
81
+ print(' ')
82
+ Platform.flush()
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Standard libraries
4
+ from typing import List
5
+
6
+ # Modules libraries
7
+ try:
8
+ try: # colored>=2.0.0
9
+ from colored import Colored
10
+ except ImportError: # colored<2.0.0 # pragma: no cover
11
+ from colored import colored as Colored
12
+ except ModuleNotFoundError: # pragma: no cover
13
+ pass
14
+
15
+ # Colors class, pylint: disable=too-few-public-methods
16
+ class Colors:
17
+
18
+ # Attributes
19
+ ALL: List[str] = []
20
+ BOLD = ''
21
+ CYAN = ''
22
+ GREEN = ''
23
+ GREY = ''
24
+ RED = ''
25
+ RESET = ''
26
+ YELLOW = ''
27
+ YELLOW_LIGHT = ''
28
+
29
+ # Enabled
30
+ @staticmethod
31
+ def enabled() -> bool:
32
+
33
+ # Result
34
+ try:
35
+ return bool(Colored('').enabled())
36
+ except (NameError, TypeError): # pragma: no cover
37
+ return False
38
+
39
+ # Prepare
40
+ @staticmethod
41
+ def prepare() -> None:
42
+
43
+ # Colors enabled
44
+ if Colors.enabled():
45
+ Colors.RESET = Colored('reset').attribute()
46
+ Colors.BOLD = Colors.RESET + Colored('bold').attribute()
47
+ Colors.CYAN = Colors.BOLD + Colored('cyan').foreground()
48
+ Colors.GREEN = Colors.BOLD + Colored('green').foreground()
49
+ Colors.GREY = Colors.BOLD + Colored('light_gray').foreground()
50
+ Colors.RED = Colors.BOLD + Colored('red').foreground()
51
+ Colors.YELLOW = Colors.BOLD + Colored('yellow').foreground()
52
+ Colors.YELLOW_LIGHT = Colors.BOLD + Colored('light_yellow').foreground()
53
+ Colors.ALL = [
54
+ Colors.CYAN,
55
+ Colors.GREEN,
56
+ Colors.GREY,
57
+ Colors.RED,
58
+ Colors.YELLOW,
59
+ Colors.YELLOW_LIGHT,
60
+ Colors.BOLD,
61
+ Colors.RESET,
62
+ ]
63
+
64
+ # Colors disabled
65
+ else:
66
+ Colors.BOLD = ''
67
+ Colors.CYAN = ''
68
+ Colors.GREEN = ''
69
+ Colors.GREY = ''
70
+ Colors.RED = ''
71
+ Colors.RESET = ''
72
+ Colors.YELLOW = ''
73
+ Colors.YELLOW_LIGHT = ''
74
+ Colors.ALL = []
75
+
76
+ # Strip
77
+ @staticmethod
78
+ def strip(string: str) -> str:
79
+
80
+ # Strip all colors
81
+ for item in Colors.ALL:
82
+ string = string.replace(item, '')
83
+
84
+ # Result
85
+ return string
File without changes
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Standard libraries
4
+ from pathlib import Path
5
+ from shutil import which
6
+ import subprocess
7
+ from typing import List
8
+
9
+ # Commands
10
+ class Commands:
11
+
12
+ # Exists
13
+ @staticmethod
14
+ def exists(binary: str) -> bool:
15
+
16
+ # Check system binary exists
17
+ return which(binary) is not None
18
+
19
+ # Grep
20
+ @staticmethod
21
+ def grep(file: Path, string: str) -> bool:
22
+
23
+ # Ignore missing file
24
+ if not file.exists():
25
+ return False
26
+
27
+ # Check file contains string
28
+ with open(
29
+ file,
30
+ encoding='utf8',
31
+ mode='r',
32
+ ) as f:
33
+ for line in f.readlines():
34
+
35
+ # Find string in line
36
+ if string in line:
37
+ return True
38
+
39
+ # Fallback
40
+ return False # pragma: no cover
41
+
42
+ # Output
43
+ @staticmethod
44
+ def output(binary: str, arguments: List[str]) -> str:
45
+
46
+ # Get system output
47
+ try:
48
+ return subprocess.check_output(
49
+ args=[binary] + arguments,
50
+ cwd=None,
51
+ shell=False,
52
+ ).strip().decode()
53
+ except subprocess.CalledProcessError as err:
54
+ return str(err.output.decode())
55
+ except FileNotFoundError:
56
+ return ''
57
+
58
+ # Command
59
+ @staticmethod
60
+ def pip(arguments: List[str]) -> bool:
61
+
62
+ # Run with pipx
63
+ if Commands.exists('pipx'):
64
+ return Commands.run(
65
+ 'pipx',
66
+ arguments,
67
+ )
68
+
69
+ # Run with pip # pragma: no cover
70
+ return Commands.run(
71
+ 'sudo',
72
+ ['pip'] + arguments,
73
+ )
74
+
75
+ # Command
76
+ @staticmethod
77
+ def run(binary: str, arguments: List[str]) -> bool:
78
+
79
+ # Run system command
80
+ try:
81
+ process = subprocess.run(
82
+ args=[binary] + arguments,
83
+ cwd=None,
84
+ check=True,
85
+ shell=False,
86
+ )
87
+ return process.returncode == 0
88
+ except subprocess.CalledProcessError as e:
89
+ print(f"Error executing command: {e}")
90
+ return False
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Standard libraries
4
+ from os import access, environ, R_OK, sep
5
+ from os.path import expanduser
6
+ from pathlib import Path
7
+ from sys import platform, stdin, stdout
8
+
9
+ # Platform
10
+ class Platform:
11
+
12
+ # Environment
13
+ ENV_SIMULATE_MAC_OS: str = 'SIMULATE_MAC_OS'
14
+ ENV_SUDO_USER: str = 'SUDO_USER'
15
+
16
+ # Constants
17
+ IS_LINUX: bool = platform in ['linux', 'linux2']
18
+ IS_MAC_OS: bool = platform in ['darwin'] or ENV_SIMULATE_MAC_OS in environ
19
+ IS_SIMULATED: bool = ENV_SIMULATE_MAC_OS in environ
20
+ IS_WINDOWS: bool = platform in ['win32', 'win64']
21
+
22
+ # Separators
23
+ PATH_SEPARATOR: str = sep
24
+
25
+ # TTYs
26
+ IS_TTY_STDIN: bool = stdin.isatty() and stdin.encoding != 'cp1252'
27
+ IS_TTY_STDOUT: bool = stdout.isatty()
28
+ IS_TTY_UTF8: bool = str(stdout.encoding).lower() == 'utf-8'
29
+
30
+ # Outputs
31
+ IS_FLUSH_ENABLED: bool = IS_TTY_STDOUT or IS_WINDOWS
32
+
33
+ # Users
34
+ IS_USER_SUDO: bool = ENV_SUDO_USER in environ
35
+ USER_SUDO: str = environ[ENV_SUDO_USER] if IS_USER_SUDO else ''
36
+
37
+ # Flush
38
+ @staticmethod
39
+ def flush() -> None:
40
+
41
+ # Flush output
42
+ print(
43
+ '',
44
+ end='',
45
+ flush=Platform.IS_FLUSH_ENABLED,
46
+ )
47
+
48
+ # Userspace
49
+ @staticmethod
50
+ def userspace(name: str) -> Path:
51
+
52
+ # Variables
53
+ home: None | Path = None
54
+
55
+ # Elevated home
56
+ if Platform.IS_USER_SUDO:
57
+ home = Path(expanduser(f'~{Platform.USER_SUDO}'))
58
+ if not access(home, R_OK): # pragma: no cover
59
+ home = None
60
+
61
+ # Default home
62
+ if not home or not home.is_dir():
63
+ home = Path.home()
64
+
65
+ # Windows userspace
66
+ if Platform.IS_WINDOWS:
67
+ return home / 'AppData' / 'Local' / name
68
+
69
+ # macOS userspace
70
+ if Platform.IS_MAC_OS:
71
+ return home / 'Library' / 'Preferences' / name
72
+
73
+ # Linux userspace
74
+ return home / '.config' / name
File without changes
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Standard libraries
4
+ from os import environ
5
+ from typing import Dict, List, NamedTuple
6
+
7
+ # Environments class
8
+ class Environments:
9
+
10
+ # Constants
11
+ LINE_EOL: str = '\n'
12
+
13
+ # Variable
14
+ class Variable(NamedTuple):
15
+
16
+ # Variables
17
+ name: str
18
+ description: str
19
+ fallback: str
20
+
21
+ # Value
22
+ @property
23
+ def value(self) -> str:
24
+ if self.fallback:
25
+ return environ.get(self.name, environ.get(self.fallback, ''))
26
+ return environ.get(self.name, '')
27
+
28
+ # Members
29
+ __group: str
30
+ __variables: Dict[str, Variable]
31
+
32
+ # Constructor
33
+ def __init__(self) -> None:
34
+ self.__group = ''
35
+ self.__variables = {}
36
+
37
+ # Group
38
+ @property
39
+ def group(self) -> str:
40
+ return self.__group
41
+
42
+ # Group
43
+ @group.setter
44
+ def group(self, value: str) -> None:
45
+ self.__group = value
46
+
47
+ # Add
48
+ def add(
49
+ self,
50
+ key: str,
51
+ name: str,
52
+ description: str,
53
+ fallback: str = '',
54
+ ) -> None:
55
+
56
+ # Append variable to list
57
+ self.__variables[key] = Environments.Variable(
58
+ name=name,
59
+ description=description,
60
+ fallback=fallback,
61
+ )
62
+
63
+ # Help
64
+ def help(self, help_position: int) -> str:
65
+
66
+ # Variables
67
+ lines: List[str] = []
68
+
69
+ # Append group
70
+ if self.__group:
71
+ lines += [f'{self.__group}:']
72
+
73
+ # Append variables
74
+ for _, variable in self.__variables.items():
75
+ line = f' {variable.name: <{help_position - 2}}'
76
+ line += f'{variable.description}'
77
+ if variable.fallback:
78
+ line += f' (fallback: {variable.fallback})'
79
+ lines += [line]
80
+
81
+ # Result
82
+ return Environments.LINE_EOL.join(lines)
83
+
84
+ # Value
85
+ def value(self, key: str) -> str:
86
+
87
+ # Get value of declared variable
88
+ if key in self.__variables:
89
+ return self.__variables[key].value
90
+
91
+ # Fallback
92
+ return ''
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Standard libraries
4
+ from random import choices
5
+ from string import ascii_letters, digits
6
+ from typing import List
7
+
8
+ # Components
9
+ from ..prints.colors import Colors
10
+
11
+ # Strings class
12
+ class Strings:
13
+
14
+ # Center
15
+ @staticmethod
16
+ def center(string: str, length: int) -> str:
17
+
18
+ # Extract text
19
+ text: str = Colors.strip(string)
20
+
21
+ # Center string
22
+ if len(text) < length:
23
+ paddings = length - len(text)
24
+ left = paddings // 2
25
+ right = -(-paddings // 2)
26
+ return ' ' * left + string + ' ' * right
27
+
28
+ # Default string
29
+ return string
30
+
31
+ # Quote
32
+ @staticmethod
33
+ def quote(string: str) -> str: # pragma: no cover
34
+
35
+ # Single quotes
36
+ if '\'' not in string:
37
+ return '\'' + string + '\''
38
+
39
+ # Double quotes
40
+ if '\"' not in string:
41
+ return '\"' + string + '\"'
42
+
43
+ # Adaptive quotes
44
+ return '\'' + string.replace('\'', '\\\'') + '\''
45
+
46
+ # Random
47
+ @staticmethod
48
+ def random(length: int) -> str: # pragma: no cover
49
+
50
+ # Generate random string
51
+ return ''.join(choices(ascii_letters + digits, k=length))
52
+
53
+ # Wrap
54
+ @staticmethod
55
+ def wrap(string: str, length: int) -> List[str]:
56
+
57
+ # Variables
58
+ color: str = ''
59
+ index: int = 0
60
+ line_data: str = ''
61
+ line_length: int = 0
62
+ lines: List[str] = []
63
+ space: str = ''
64
+ word: str = ''
65
+
66
+ # Length limitations
67
+ length = max(length, 1)
68
+
69
+ # Append line
70
+ def append_line() -> None:
71
+ nonlocal line_data, line_length, lines
72
+ if line_length > 0:
73
+ lines += [line_data]
74
+ line_data = ''
75
+ line_length = 0
76
+
77
+ # Store word
78
+ def store_word() -> None:
79
+ nonlocal color, length, line_data, line_length, space, word
80
+ if len(word) > 0:
81
+
82
+ # Word overflows
83
+ if line_length + len(space) + len(word) > length:
84
+ word_full = word
85
+ if len(word_full) > length:
86
+ while len(word_full) > 0:
87
+ word = word_full[0:length]
88
+ store_word()
89
+ word_full = word_full[length:]
90
+ append_line()
91
+
92
+ # Word spacing
93
+ if line_length > 0 and space:
94
+ line_data += space
95
+ line_length += len(space)
96
+ space = ''
97
+
98
+ # Word appendation
99
+ line_data += color + word
100
+ line_length += len(word)
101
+ word = ''
102
+
103
+ # Line wrapping
104
+ if line_length >= length:
105
+ append_line()
106
+
107
+ # Add char
108
+ def add_char(char: str) -> None:
109
+ nonlocal index, word
110
+ index += 1
111
+ word += char
112
+
113
+ # Iterate through chars
114
+ while index < len(string):
115
+
116
+ # Space separator
117
+ if string[index] == ' ':
118
+
119
+ # Store last word
120
+ store_word()
121
+
122
+ # Reset word data
123
+ space += ' '
124
+ index += 1
125
+ continue
126
+
127
+ # Color marker
128
+ for item in Colors.ALL:
129
+ if item and string[index:].startswith(item):
130
+
131
+ # Store last word
132
+ store_word()
133
+
134
+ # Store new color
135
+ color = item
136
+ index += len(color)
137
+ break
138
+
139
+ # Text content
140
+ else:
141
+
142
+ # Append character
143
+ add_char(string[index])
144
+
145
+ # Store last word
146
+ store_word()
147
+
148
+ # Append last line
149
+ append_line()
150
+
151
+ # Result
152
+ return lines