Development Artifact Cleanup: ✅ BROTHER_NODE REORGANIZATION: Moved development test node to appropriate location - dev/test-nodes/brother_node/: Moved from root directory for better organization - Contains development configuration, test logs, and test chain data - No impact on production systems - purely development/testing artifact ✅ DEVELOPMENT ARTIFACTS IDENTIFIED: - Chain ID: aitbc-brother-chain (test/development chain) - Ports: 8010 (P2P) and 8011 (RPC) - different from production - Environment: .env file with test configuration - Logs: rpc.log and node.log from development testing session (March 15, 2026) ✅ ROOT DIRECTORY CLEANUP: Removed development clutter from production directory - brother_node/ moved to dev/test-nodes/brother_node/ - Root directory now contains only production-ready components - Development artifacts properly organized in dev/ subdirectory DIRECTORY STRUCTURE IMPROVEMENT: 📁 dev/test-nodes/: Development and testing node configurations 🏗️ Root Directory: Clean production structure with only essential components 🧪 Development Isolation: Test environments separated from production BENEFITS: ✅ Clean Production Directory: No development artifacts in root ✅ Better Organization: Development nodes grouped in dev/ subdirectory ✅ Clear Separation: Production vs development environments clearly distinguished ✅ Maintainability: Easier to identify and manage development components RESULT: Successfully moved brother_node development artifact to dev/test-nodes/ subdirectory, cleaning up the root directory while preserving development testing environment for future use.
142 lines
4.8 KiB
Python
Executable File
142 lines
4.8 KiB
Python
Executable File
from typing import TYPE_CHECKING, List, Optional, Tuple, Union
|
|
|
|
if TYPE_CHECKING:
|
|
from .console import (
|
|
Console,
|
|
ConsoleOptions,
|
|
RenderableType,
|
|
RenderResult,
|
|
)
|
|
|
|
from .jupyter import JupyterMixin
|
|
from .measure import Measurement
|
|
from .segment import Segment
|
|
from .style import Style
|
|
|
|
PaddingDimensions = Union[int, Tuple[int], Tuple[int, int], Tuple[int, int, int, int]]
|
|
|
|
|
|
class Padding(JupyterMixin):
|
|
"""Draw space around content.
|
|
|
|
Example:
|
|
>>> print(Padding("Hello", (2, 4), style="on blue"))
|
|
|
|
Args:
|
|
renderable (RenderableType): String or other renderable.
|
|
pad (Union[int, Tuple[int]]): Padding for top, right, bottom, and left borders.
|
|
May be specified with 1, 2, or 4 integers (CSS style).
|
|
style (Union[str, Style], optional): Style for padding characters. Defaults to "none".
|
|
expand (bool, optional): Expand padding to fit available width. Defaults to True.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
renderable: "RenderableType",
|
|
pad: "PaddingDimensions" = (0, 0, 0, 0),
|
|
*,
|
|
style: Union[str, Style] = "none",
|
|
expand: bool = True,
|
|
):
|
|
self.renderable = renderable
|
|
self.top, self.right, self.bottom, self.left = self.unpack(pad)
|
|
self.style = style
|
|
self.expand = expand
|
|
|
|
@classmethod
|
|
def indent(cls, renderable: "RenderableType", level: int) -> "Padding":
|
|
"""Make padding instance to render an indent.
|
|
|
|
Args:
|
|
renderable (RenderableType): String or other renderable.
|
|
level (int): Number of characters to indent.
|
|
|
|
Returns:
|
|
Padding: A Padding instance.
|
|
"""
|
|
|
|
return Padding(renderable, pad=(0, 0, 0, level), expand=False)
|
|
|
|
@staticmethod
|
|
def unpack(pad: "PaddingDimensions") -> Tuple[int, int, int, int]:
|
|
"""Unpack padding specified in CSS style."""
|
|
if isinstance(pad, int):
|
|
return (pad, pad, pad, pad)
|
|
if len(pad) == 1:
|
|
_pad = pad[0]
|
|
return (_pad, _pad, _pad, _pad)
|
|
if len(pad) == 2:
|
|
pad_top, pad_right = pad
|
|
return (pad_top, pad_right, pad_top, pad_right)
|
|
if len(pad) == 4:
|
|
top, right, bottom, left = pad
|
|
return (top, right, bottom, left)
|
|
raise ValueError(f"1, 2 or 4 integers required for padding; {len(pad)} given")
|
|
|
|
def __repr__(self) -> str:
|
|
return f"Padding({self.renderable!r}, ({self.top},{self.right},{self.bottom},{self.left}))"
|
|
|
|
def __rich_console__(
|
|
self, console: "Console", options: "ConsoleOptions"
|
|
) -> "RenderResult":
|
|
style = console.get_style(self.style)
|
|
if self.expand:
|
|
width = options.max_width
|
|
else:
|
|
width = min(
|
|
Measurement.get(console, options, self.renderable).maximum
|
|
+ self.left
|
|
+ self.right,
|
|
options.max_width,
|
|
)
|
|
render_options = options.update_width(width - self.left - self.right)
|
|
if render_options.height is not None:
|
|
render_options = render_options.update_height(
|
|
height=render_options.height - self.top - self.bottom
|
|
)
|
|
lines = console.render_lines(
|
|
self.renderable, render_options, style=style, pad=True
|
|
)
|
|
_Segment = Segment
|
|
|
|
left = _Segment(" " * self.left, style) if self.left else None
|
|
right = (
|
|
[_Segment(f'{" " * self.right}', style), _Segment.line()]
|
|
if self.right
|
|
else [_Segment.line()]
|
|
)
|
|
blank_line: Optional[List[Segment]] = None
|
|
if self.top:
|
|
blank_line = [_Segment(f'{" " * width}\n', style)]
|
|
yield from blank_line * self.top
|
|
if left:
|
|
for line in lines:
|
|
yield left
|
|
yield from line
|
|
yield from right
|
|
else:
|
|
for line in lines:
|
|
yield from line
|
|
yield from right
|
|
if self.bottom:
|
|
blank_line = blank_line or [_Segment(f'{" " * width}\n', style)]
|
|
yield from blank_line * self.bottom
|
|
|
|
def __rich_measure__(
|
|
self, console: "Console", options: "ConsoleOptions"
|
|
) -> "Measurement":
|
|
max_width = options.max_width
|
|
extra_width = self.left + self.right
|
|
if max_width - extra_width < 1:
|
|
return Measurement(max_width, max_width)
|
|
measure_min, measure_max = Measurement.get(console, options, self.renderable)
|
|
measurement = Measurement(measure_min + extra_width, measure_max + extra_width)
|
|
measurement = measurement.with_maximum(max_width)
|
|
return measurement
|
|
|
|
|
|
if __name__ == "__main__": # pragma: no cover
|
|
from rich import print
|
|
|
|
print(Padding("Hello, World", (2, 4), style="on blue"))
|