Skip to content

Instantly share code, notes, and snippets.

@qexat
Last active April 17, 2026 16:14
Show Gist options
  • Select an option

  • Save qexat/3b6dbb57edc68973f3432f6eb79c5be7 to your computer and use it in GitHub Desktop.

Select an option

Save qexat/3b6dbb57edc68973f3432f6eb79c5be7 to your computer and use it in GitHub Desktop.
my .pythonrc (2026.04.17)
#!/usr/bin/env python3
# pyright: reportUnusedCallResult = false, reportUnusedImport = false
# ruff: noqa: DTZ005, T201
"""
.pythonrc is a file which is executed when the Python interactive shell is
started if $PYTHONSTARTUP is in your environment and points to this file.
It's just regular Python code, so do what you will. Your ~/.inputrc file
can greatly complement this file.
Modified from sontek's dotfiles repo on github:
https://github.com/sontek/dotfiles
"""
from __future__ import annotations
import abc
import ast
import atexit
import builtins
import calendar as _calendar
import collections.abc
import contextlib
import copy
import ctypes # noqa: F401
import dataclasses
import datetime
import decimal
import faulthandler
import functools
import importlib.util
import inspect
import io
import math # noqa: F401
import operator # noqa: F401
import os
import platform
import random
import re
import shutil
import subprocess
import sys
import textwrap
import traceback
import typing
if typing.TYPE_CHECKING:
import types
_PRIDE_MONTH_NUMBER = 6
__MIN_RECURSION_LIMIT = 0x800
__MAX_RECURSION_LIMIT = 0x8000
__MIN_INT_MAX_STR_DIGITS = 100_000
__MAX_INT_MAX_STR_DIGITS = 2_000_000
#############
# LAUNCHING #
#############
LAUNCHING_MESSAGE = (
"\x1b[35m◉ \x1b[1mLaunching the custom REPL...\x1b[22;39m"
)
VIRTUAL_ENV = os.environ.get("VIRTUAL_ENV", None)
HOME = (
VIRTUAL_ENV
or os.environ.get("WORKON_HOME", None)
or os.environ["HOME"]
)
#############
# TYPE VARS #
#############
AnyCallable: typing.TypeAlias = collections.abc.Callable[..., typing.Any]
AnyCallableT = typing.TypeVar("AnyCallableT", bound=AnyCallable)
_T = typing.TypeVar("_T")
_T0 = typing.TypeVar("_T0")
_T1 = typing.TypeVar("_T1")
_T2 = typing.TypeVar("_T2")
_P = typing.ParamSpec("_P")
_R = typing.TypeVar("_R")
#############
# CONSTANTS #
#############
DECIMAL_CONTEXT = decimal.getcontext()
_FIVE_SQRT = decimal.Decimal(5.0**0.5)
phi: typing.Final[float] = (1.0 + 5.0**0.5) / 2.0
psi: typing.Final = 1.0 - phi
phi_decimal: typing.Final = decimal.Decimal(phi)
psi_decimal: typing.Final = decimal.Decimal(psi)
python: typing.Final = builtins
#################################
# SAVE & RESTORE HISTORY STATES #
#################################
try:
import readline
except ImportError:
pass
else:
##################
# TAB COMPLETION #
##################
try:
import rlcompleter # noqa: F401
except ImportError:
pass
else:
if sys.platform == "darwin":
# Work around a bug in Mac OS X's readline module.
readline.parse_and_bind("bind ^I rl_complete")
else:
readline.parse_and_bind("tab: complete")
######################
# PERSISTENT HISTORY #
######################
# Use separate history files for each virtual environment.
HISTORY_FILE = os.path.join(HOME, ".pyhistory")
# Read the existing history if there is one.
if os.path.exists(HISTORY_FILE):
try:
readline.read_history_file(HISTORY_FILE)
except Exception: # noqa: BLE001
# If there was a problem reading the history file then it may
# have become corrupted, so we just delete it.
os.remove(HISTORY_FILE)
# Set maximum number of commands written to the history file.
readline.set_history_length(256)
@atexit.register
def savehist() -> None:
"""
Save the history of the shell into a `.pyhistory` file.
Automatically runs when the user exists the shell.
"""
try:
readline.write_history_file(HISTORY_FILE)
except NameError:
pass
except Exception as err: # noqa: BLE001
message = (
f"Unable to save history file due to the following "
f"error: {err}"
)
print(message, file=sys.stderr)
#################
# COLOR SUPPORT #
#################
class TermColors(dict[str, str]):
"""
Gives easy access to ANSI color codes.
Attempts to fall back to no color for certain TERM values.
Mostly taken from IPython.
"""
COLOR_TEMPLATES = (
("Black", "30"),
("Red", "31"),
("Green", "32"),
("Brown", "33"),
("Blue", "34"),
("Purple", "35"),
("Cyan", "36"),
("LightGray", "37"),
("DarkGray", "90"),
("LightRed", "91"),
("LightGreen", "92"),
("Yellow", "93"),
("LightBlue", "94"),
("LightPurple", "95"),
("LightCyan", "96"),
("White", "97"),
("Normal", "39"),
)
NoColor = ""
_base = "\033[%sm"
def __init__(self) -> None:
if os.environ.get("TERM") in {
"xterm-color",
"xterm-256color",
"linux",
"screen",
"screen-256color",
"screen-bce",
}:
self.update(
(k, self._base % v) for k, v in self.COLOR_TEMPLATES
)
else:
self.update((k, self.NoColor) for k, _ in self.COLOR_TEMPLATES)
_c: typing.Final = TermColors()
##############################
# BETTER SYNTAX HIGHLIGHTING #
##############################
with contextlib.suppress(ImportError, ModuleNotFoundError):
import _colorize
_theme = _colorize.get_theme()
_colorize.set_theme(
_theme.copy_with(
syntax=_colorize.Syntax(
comment=_colorize.ANSIColors.INTENSE_BLACK,
keyword=_colorize.ANSIColors.BOLD_MAGENTA,
keyword_constant=_colorize.ANSIColors.MAGENTA,
soft_keyword=_colorize.ANSIColors.INTENSE_MAGENTA,
builtin=_colorize.ANSIColors.BLUE,
number=_colorize.ANSIColors.CYAN,
op=_colorize.ANSIColors.WHITE,
definition=_colorize.ANSIColors.BLUE,
),
),
)
#################
# FAKE COMMANDS #
#################
class FakeCommand(abc.ABC):
"""Class to inherit to create your own "fake" command."""
def __repr__(self) -> str:
self()
return "\u200b" # zero-width space
@abc.abstractmethod
def __call__(self) -> typing.Any: # noqa: D102
pass
class _ExitConsole(FakeCommand):
"""Exit command (no parentheses needed!)."""
def __call__(self, code: int = 0) -> typing.Never:
raise SystemExit(code)
class _CalendarCommand(FakeCommand):
"""Command to display the calendar."""
def __call__(self) -> None:
print(_calendar.calendar(datetime.date.today().year, m=4)) # noqa: DTZ011
@dataclasses.dataclass(repr=False, frozen=True)
class ShellCommand(FakeCommand):
"""Run shell commands directly in your Python REPL. Do NOT abuse."""
cmd: str
def __call__(self) -> None: # noqa: D102
STATE.status = subprocess.call([self.cmd]) # noqa: S603
#########
# UTILS #
#########
class _UtilsList(FakeCommand, list[AnyCallable]):
"""Utilitary to list and provide info on REPL utils."""
__name__ = "utils"
def __call__(self, function: AnyCallable | None = None) -> None:
buffer = io.StringIO()
if function is None:
for element in self:
buffer.write(f"\x1b[1;37m{element.__name__}\x1b[22;39m")
if element.__doc__:
doc = textwrap.dedent(element.__doc__)
first_line = doc.strip().splitlines()[0]
if not first_line.endswith("."):
first_line += "..."
function_comment = (
f" \x1b[2m·\x1b[22m \x1b[3;92m"
f"{first_line}\x1b[23;39m"
)
buffer.write(f"{function_comment:>48}")
buffer.write("\n")
else:
buffer.write(
f"def {function.__name__}"
f"{inspect.signature(function, eval_str=True)}"
)
if function.__doc__:
doc = textwrap.indent(
f"\"\"\"\n{function.__doc__.strip('\n')}\n\"\"\"",
" " * 4,
)
buffer.write(f"\n\x1b[92m{doc}\x1b[39m")
builtins.print(buffer.getvalue())
__annotations__ = __call__.__annotations__
def register(
self,
function: AnyCallableT,
*,
with_name: str | None = None,
) -> AnyCallableT:
_function = copy.copy(function)
self.append(_function)
if with_name:
_function.__name__ = with_name
self.sort(key=lambda function: function.__name__)
return _function
utils: typing.Final = _UtilsList()
utils.append(utils)
literal: typing.Final = utils.register(
ast.literal_eval,
with_name="literal",
)
@utils.register
def concat(*strings: str, sep: str = " ") -> str:
"""
Concatenate strings together giving a separator `sep` (default: " ").
"""
return sep.join(strings)
@utils.register
def clamp(number: int, _min: int = 0, _max: int = sys.maxsize) -> int:
"""
Minmax an integer to a `min` (default: 0) and a `max`
(default: sys.maxsize).
"""
return max(_min, min(_max, number))
@utils.register
def clear() -> None:
"""
Clear the terminal.
"""
is_pride_month = datetime.datetime.now().month == _PRIDE_MONTH_NUMBER
sys.stdout.write("\x1b[H\x1b[J")
sys.stdout.write(
make_pill(
get_pretty_python_version(),
get_pretty_date(),
*(
(
"\x1b[1m"
"\x1b[38;5;9mH"
"\x1b[38;5;1ma"
"\x1b[38;5;3mp"
"\x1b[38;5;11mp"
"\x1b[38;5;10my "
"\x1b[38;5;2mP"
"\x1b[38;5;14mr"
"\x1b[38;5;6mi"
"\x1b[38;5;12md"
"\x1b[38;5;4me "
"\x1b[38;5;5mM"
"\x1b[38;5;13mo"
"\x1b[38;5;15mn"
"\x1b[38;5;7mt"
"\x1b[38;5;8mh"
"\x1b[38;5;0m!"
"\x1b[22;39m",
)
if is_pride_month
else ()
),
get_pretty_time(),
),
)
sys.stdout.write("\n")
@utils.register
def choose(*values: object) -> object:
"""
Pick a random element among the values.
Variadic equivalent of `random.choice()`.
"""
return random.choice(values)
@utils.register
def compose(
func1: collections.abc.Callable[[_T0], _T1],
func2: collections.abc.Callable[[_T1], _T2],
) -> collections.abc.Callable[[_T0], _T2]:
"""
Compose two functions together from left to right.
>>> compose(str, len)(36)
2
"""
return lambda arg: func2(func1(arg))
@utils.register
def flipped(
func: collections.abc.Callable[[_T0, _T1], _T2],
) -> collections.abc.Callable[[_T1, _T0], _T2]:
"""
Return a version of the function with its arguments flipped.
>>> flipped(operator.sub)(3, 5)
2
"""
return lambda arg1, arg2: func(arg2, arg1)
@utils.register
def raw_length(value: str) -> int:
"""
Calculate the raw length of the string, i.e. its "displayed" length.
"""
return compose(esclean, len)(value)
@utils.register
def float_equal(f1: float, f2: float) -> bool:
"""
Estimate if two floats are equal using the machine's epsilon.
>>> float_equal(0.1 + 0.2, 0.3)
True
"""
return 0 <= abs(f2 - f1) <= sys.float_info.epsilon
@utils.register
def irange(start: int, stop: int) -> range:
"""
`range`, but with inclusive stop.
>>> irange(0, 10)
range(0, 11)
"""
return range(start, stop + 1)
@utils.register
def magic(string: str) -> list[str]:
"""
Convert a string into a list of the hexadecimal values of its
characters.
>>> magic("hello")
['0x68', '0x65', '0x6c', '0x6c', '0x6f']
"""
return list(map(hex, string.encode("utf-8")))
@utils.register
def unpack[T, U](
fn: collections.abc.Callable[[collections.abc.Iterable[T]], U],
) -> collections.abc.Callable[[*tuple[T, ...]], U]:
"""
Unpack the parameters of the provided function.
>>> unpack(list)(3, 5, 2)
[3, 5, 2]
"""
def f(*args: *tuple[T, ...]) -> U:
return fn(args)
return f
s = unpack(" ".join)
_map_curried = lambda fn: lambda xs: map(fn, xs)
fmap = lambda fn: unpack(_map_curried(fn))
@utils.register
def zeros_iter(
n: int = -1, /
) -> collections.abc.Generator[int, None, None]:
"""
Return an iterator of `n` zeros.
"""
i = 0
while i < n or n < 0:
yield 0
i += 1
@utils.register
def zeros(n: int, /) -> list[int]:
"""
Return a list of `n` zeros.
Raises
------
ValueError
If `n` is less than 0.
Examples
--------
>>> zeros(5)
[0, 0, 0, 0, 0]
>>> zeros(0)
[]
>>> zeros(-2)
*- ValueError: n must be non-negative -*
"""
if n < 0:
message = "n must be non-negative"
raise ValueError(message)
return list(zeros_iter(n))
@utils.register
def bool_to_sign(value: bool, /) -> typing.Literal[1, -1]: # noqa: FBT001
"""
Return 1 if value is `True`, else -1.
>>> bool_to_sign(True)
1
>>> bool_to_sign(False)
-1
"""
return 1 if value else -1
@utils.register
def parity_to_sign(
value: int,
/,
*,
inverted: bool = False,
) -> typing.Literal[1, -1]:
"""
Return 1 if value is even, else -1. For consistency, 0 is considered
even.
If `inverted` is set to `True`, the result is negated.
>>> parity_to_sign(2)
1
>>> parity_to_sign(-3)
-1
>>> parity_to_sign(0)
1
>>> parity_to_sign(40, inverted=True)
-1
"""
return bool_to_sign(value % 2 == inverted)
@utils.register
def fib(n: int) -> int:
"""The Fibonacci sequence over the integers."""
if n < 0:
return parity_to_sign(n, inverted=True) * fib(abs(n))
if n <= 1:
return n
return fib(n - 2) + fib(n - 1)
@utils.register
def fib_fast(n: int) -> int:
"""
A fast implementation of the Fibonacci sequence.
"""
_n = decimal.Decimal(n)
return int(
(
DECIMAL_CONTEXT.power(phi_decimal, _n)
- DECIMAL_CONTEXT.power(psi_decimal, _n)
)
/ _FIVE_SQRT,
)
@utils.register
def os_colorify(string: str) -> str:
"""
Stylize the `string` with the color of the OS.
Raises
------
OSError
If the operating system is not Linux or the distribution does not
have a color.
"""
if sys.platform != "linux":
message = "this function can only run on Linux"
raise OSError(message)
info = platform.freedesktop_os_release()
if "ANSI_COLOR" not in info:
message = "operating system does not have a color"
raise OSError(message)
return f"\x1b[{info['ANSI_COLOR']}m{string}\x1b[39m"
@typing.final
class Canvas(list[list[bool]]):
@staticmethod
def new(width: int, height: int) -> Canvas:
return Canvas(
([False for _ in range(width + 1)]) for _ in range(height + 1)
)
def set_point(self, *, x: int, y: int) -> None:
if y >= len(self):
self.extend([] for _ in range(y - len(self) + 1))
xs = self[y]
if x >= len(xs):
xs.extend(False for _ in range(x - len(xs) + 1))
xs[x] = True
def _uniformize_lengths(self) -> None:
max_length = max(map(len, self))
for xs in self:
if len(xs) < max_length:
xs.extend(False for _ in range(max_length - len(xs)))
def render(self, *, symbol: str = "*") -> str:
lines = ["".join(symbol if x else " " for x in xs) for xs in self]
return "\n".join(reversed(lines))
def print(self, *, symbol: str = "*") -> None:
print(self.render(symbol=symbol))
class Plot:
def __init__(
self,
*,
x: range | None = None,
y: range | None = None,
) -> None:
columns, lines = shutil.get_terminal_size()
self.canvas: typing.Final = Canvas()
self.x: typing.Final = range(0, columns, 1) if x is None else x
self.y: typing.Final = range(0, lines - 5, 1) if y is None else y
def __contains__(self, position: tuple[int, int]) -> bool:
(x, y) = position
return x in self.x and y in self.y
def add_function(
self,
function: typing.Callable[[int], int],
) -> typing.Self:
for xi in self.x:
yi = function(xi)
if (xi, yi) in self:
self.canvas.set_point(x=xi, y=yi)
return self
def print(self, *, symbol: str = "*") -> None:
self.canvas.print(symbol=symbol)
@utils.register
def display_function(
function: typing.Callable[[int], int],
*,
symbol: str = "*",
x: range | None = None,
y: range | None = None,
) -> None:
plot = Plot(x=x, y=y)
plot.add_function(function)
plot.print(symbol=symbol)
################################
# PRETTY PRINT OUTPUT & ERRORS #
################################
def get_pretty_python_version() -> str:
"""Render a colorful piece of text of the current Python version."""
string = "\x1b[1mPython\x1b[0m \x1b[91m{}.{}.{}\x1b[39m"
return string.format(*sys.version_info[:3])
def get_pretty_date() -> str:
"""Render a colorful piece of text of the current date."""
return datetime.datetime.now().strftime(
"\x1b[1;35m%A %d %B %Y\x1b[22;39m"
)
def get_pretty_time() -> str:
"""Render a colorful piece of text of the current time."""
return datetime.datetime.now().strftime("\x1b[1;34m%H:%M\x1b[22;39m")
@utils.register
def esclean(string: str) -> str:
"""
Clean the string from escape sequences.
Regex shamelessly stolen from a tutorialspoint post:
https://www.tutorialspoint.com/How-can-I-remove-the-ANSI-escape-sequences-from-a-string-in-python
"""
return re.compile(r"(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]").sub("", string)
@utils.register
def make_pill(main: str, *others: str) -> str:
"""
Render a contiguous array of blocks containing text.
TODO: fix the case where the pill ends up being bigger than the
available terminal width.
>>> make_pill("hello", "world")
╭───────┬───────╮
│ hello │ world │
╰───────┴───────╯
"""
buffer = io.StringIO()
main_len = raw_length(main)
others_len = [raw_length(other) for other in others]
buffer.write("╭" + "─" * (main_len + 2))
for length in others_len:
buffer.write("┬" + "─" * (length + 2))
buffer.write("╮\n")
buffer.write("│ " + " │ ".join((main, *others)) + " │\n")
buffer.write("╰" + "─" * (main_len + 2))
for length in others_len:
buffer.write("┴" + "─" * (length + 2))
buffer.write("╯")
return buffer.getvalue()
exit = utils.register(_ExitConsole(), with_name="exit") # noqa: A001
fastfetch = ShellCommand("fastfetch")
calendar = _CalendarCommand()
class ReplState:
"""
The state of the REPL (mainly, its status code).
"""
def __init__(self) -> None:
self.status = 0
def mutator(
self, *, status: int | None = None
) -> collections.abc.Callable[
[collections.abc.Callable[_P, _R]],
collections.abc.Callable[_P, _R],
]:
"""
Set a function `func` to be a REPL state mutator.
When the function `func` is called, set the state provided as
keyword arguments to this decorator.
Returns
-------
The decorator that takes the function as argument.
"""
def decorator(
func: collections.abc.Callable[_P, _R], /
) -> collections.abc.Callable[_P, _R]:
"""
Decorator returned by `mutator`.
Returns
-------
The transformed function that mutates the state.
"""
@functools.wraps(func)
def inner(*args: _P.args, **kwargs: _P.kwargs) -> _R:
result = func(*args, **kwargs)
if status is not None:
self.status = status
return result
return inner
return decorator
STATE = ReplState()
class DynamicPrompt(abc.ABC):
"""
Prompt that dynamically adapts according to the state of the REPL.
"""
def __init__(self, state: ReplState) -> None:
self._state = state
def __repr__(self) -> str:
return self.prompt()
@abc.abstractmethod
def prompt(self) -> str:
"""Return the dynamic prompt."""
class DynamicPS1(DynamicPrompt):
"""
Main prompt that dynamically adapts according to the state of the REPL.
"""
def prompt(self) -> str: # noqa: D102
color = _c["LightRed"] if self._state.status else _c["LightGreen"]
return " %sλ%s " % (color, _c["Normal"]) # noqa: UP031
class DynamicPS2(DynamicPrompt):
"""
Secondary prompt string that dynamically adapts according to what is
happening in the REPL.
"""
def prompt(self) -> str: # noqa: D102
color = _c["LightRed"] if self._state.status else _c["LightGreen"]
return f"\x1b[m{' ' * (raw_length(repr(sys.ps1)) - 2)}%s┊%s " % (
color,
_c["Normal"],
)
# Make the prompts colorful.
sys.ps1 = DynamicPS1(STATE)
sys.ps2 = DynamicPS2(STATE)
# Enable pretty printing for STDOUT
@STATE.mutator(status=0)
def pretty_display_hook(value: object) -> None:
"""Custom display hook to make printed values colorful and pretty."""
if value is not None:
__builtins__._ = value
builtins.print(repr(value))
sys.displayhook = pretty_display_hook
# Make errors and tracebacks stand out a bit more.
def pretty_except_hook(
exc_type: type[BaseException],
exc_value: BaseException,
exc_tb: types.TracebackType | None,
) -> None:
"""
Custom exception hook to make them look colorful and pretty.
"""
sys.stderr.write(_c["Yellow"])
traceback.print_exception(exc_type, exc_value, exc_tb)
sys.stderr.write(_c["Normal"])
# NOTE: There is a bug (?) in Python 3, where a trailing color marker
# that's written to STDERR or STDOUT by itself does not color the
# subsequent lines.
# We work around this by manually calling ``flush`` afterwards.
sys.stderr.flush()
# Python 3.13 introduces pretty exceptions
if sys.version_info < (3, 13):
sys.excepthook = pretty_except_hook
sys.excepthook = STATE.mutator(status=1)(sys.excepthook)
_setrecursionlimit: typing.Final = sys.setrecursionlimit
_set_int_max_str_digits: typing.Final = sys.set_int_max_str_digits
def recursion_limit_setter_safe(limit: int, /) -> None:
"""\
Set the recursion limit of the Python interpreter.
This function overrides the built-in to prevent basic footguns.
Raises
------
ValueError
When `limit` is lower than 2048 or higher than 32768.
"""
if limit > __MAX_RECURSION_LIMIT:
message = (
"cannot set recursion limit to higher than 32768 "
"\x1b[35m[prevent-large-recursion]\x1b[39m",
)
raise ValueError(message)
if limit < __MIN_RECURSION_LIMIT:
message = (
"cannot set recursion limit to lower than 2048 "
"\x1b[35m[prevent-small-recursion]\x1b[39m",
)
raise ValueError(message)
_setrecursionlimit(limit)
def int_max_str_digits_setter_safe(limit: int, /) -> None:
"""
Set the max count of digits for integers to be converted to a string.
This function overrides the built-in to prevent basic footguns.
Raises
------
ValueError
When `limit` is lower than 10'000 or higher than 200'000.
"""
if limit > __MAX_INT_MAX_STR_DIGITS:
message = "cannot set int max str digit limit to higher than 200'000"
raise ValueError(message)
if limit < __MIN_INT_MAX_STR_DIGITS:
message = "cannot set int max str digit limit to lower than 10'000"
raise ValueError(message)
_set_int_max_str_digits(limit)
# Prevents a footgun ^^
sys.setrecursionlimit = recursion_limit_setter_safe
sys.set_int_max_str_digits = _set_int_max_str_digits
# Funny things happen here vvv
@utils.register
def hex_encode(string: str) -> str:
"""
Encode the string as the hexadecimal representation of its bytes.
>>> hex_encode("hello")
68656C6C6F
"""
return f"{int.from_bytes(string.encode()):X}"
@utils.register
def hex_decode(encoded: str, length: int) -> str:
"""Decode the hexadecimal representation of a string's bytes into the \
original object.
>>> hex_decode("68656C6C6F", 5)
hello
"""
return int(encoded, 16).to_bytes(length).replace(b"\x00", b"").decode()
@utils.register
def encode_funcname(
function: collections.abc.Callable[..., typing.Any],
) -> str:
"""
Encode a function as an unique identifier that can be used to
retrieve the function object later.
>>> encode_funcname(abs)
_6275696C74696E73_616273
"""
return (
"_"
+ hex_encode(function.__module__)
+ "_"
+ hex_encode(function.__name__)
)
@utils.register
def decode_funcname(
byteid: str,
) -> collections.abc.Callable[..., typing.Any]:
"""
Decode the identifier generated by `encode_funcname` and retreive, if
it exists, the original function object.
Raises
------
ValueError
When `byteid` is invalid.
Examples
--------
>>> decode_funcname("_6275696C74696E73_616273")
<built-in function abs>
"""
_, module_id, func_id = byteid.split("_")
module_name = hex_decode(module_id, 64)
func_name = hex_decode(func_id, 64)
try:
return getattr(importlib.import_module(module_name), func_name)
except Exception: # noqa: BLE001
message = "invalid func byte id"
raise ValueError(message) from None
@utils.register
def identity(value: _T) -> _T:
"""
Implementation of the I combinator (λa.a).
"""
return value
@utils.register
def kestrel(first: _T, _: object) -> _T:
"""
Implementation of the K combinator (λab.a).
"""
return first
@utils.register
def kite(_: object, second: _T) -> _T:
"""
Implementation of the KI combinator (λab.b).
"""
return second
@utils.register
def starling(
func1: collections.abc.Callable[[_T0, _T1], _T2],
func2: collections.abc.Callable[[_T0], _T1],
value: _T0,
/,
) -> _T2:
"""
Implementation of the S combinator (λa.λb.λc.ac(bc)).
"""
return func1(value, func2(value))
@utils.register
def thrush(value: _T0, func: collections.abc.Callable[[_T0], _T1]) -> _T1:
"""
Implementation of the T combinator (λa.λb.ba).
"""
return func(value)
@utils.register
def inductive(
operation: collections.abc.Callable[[_T0, _T1], _T1],
fixpoint_predicate: collections.abc.Callable[[_T0], bool],
fixpoint_value: _T1,
decreasing: collections.abc.Callable[[_T0], _T0],
) -> collections.abc.Callable[[_T0], _T1]:
"""
Produce an inductive function given an operation, a fixpoint and a
decreasing function.
Parameters
----------
operation : (T, U) -> U
A binary function that takes the current argument and the value of
the previous iteration and returns a new value.
For example, for the factorial, it would be the multiplication.
fixpoint_predicate : (T) -> bool
A predicate that determines whether the current iteration's
argument has reached the base case where the induction should stop.
fixpoint_value : U
The value that is returned when the base case is reached, on top of
all the results of the previous iterations.
decreasing : (T) -> T
A unary function that minimally decreases the current iteration
argument's value. The result is used as the argument of the next
iteration, so make sure it can actually reached the fixpoint
predicate.
For example, in the case where `T` is `int`, it should be
`n -> n - 1`.
Examples
--------
>>> fact = inductive(
lambda a, b: a * b, # a = n, b = fact(n - 1)
lambda a: a <= 1, # base case
1, # for n <= 1, fact(n) = 1
lambda a: a - 1,
)
>>> fact(10)
3628800
"""
def function(value: _T0) -> _T1:
def function_auxiliary(current: _T0, previous: _T1) -> _T1:
if fixpoint_predicate(current):
return previous
return function_auxiliary(
decreasing(current),
operation(current, previous),
)
return function_auxiliary(value, fixpoint_value)
return function
src: typing.Final = utils.register(inspect.getsource, with_name="src")
def help(request: object = None, /) -> None: # noqa: A001, D103
builtins.help(request)
sys.stdout.write("\x1b[?1049h")
clear()
def __disable_if_not_tty(
func: collections.abc.Callable[[], None],
) -> collections.abc.Callable[[], None]:
if sys.stdout.isatty():
return func
return lambda: None
@atexit.register
@__disable_if_not_tty
def _exit_alt_buffer() -> None: # pyright: ignore[reportUnusedFunction]
"""\
Disable the alternative screen buffer at exit.
"""
import sys # for IPython
sys.stdout.write("\x1b[?1049l")
sys.stdout.flush()
print("\x1b[32m♡ \x1b[1mThank you for using qexat's .pythonrc\x1b[22;39m")
__has_initialized = False
def init(_: list[str]) -> None:
"""
The default init function of the REPL.
Tasks
-----
* Print a launching message
* Enable the fault handler
* Set the recursion limit to a higher, but safe limit
* Switch to the alternative screen buffer
* Clear the screen
If the REPL is already initialized, do nothing.
"""
if __has_initialized:
return
print(LAUNCHING_MESSAGE)
# Sometimes I do some fuckery in the REPL so we should get ourselves
# covered
faulthandler.enable()
# 1000 is too low...
sys.setrecursionlimit(__MAX_RECURSION_LIMIT)
DECIMAL_CONTEXT.prec = 10_000
sys.set_int_max_str_digits(100_000)
# Enter the alternative screen buffer
# We do NOT use `print` because `rich` strips the escape sequence
# somehow
sys.stdout.write("\x1b[?1049h")
sys.stdout.flush()
# We clear the buffer so it looks like a new window
clear()
def main(
init_func: collections.abc.Callable[[list[str]], None],
*,
args: list[str],
) -> None:
"""
Entry point of the REPL.
Parameters
----------
init_func : (list[str]) -> None
A function run at the initialization of the REPL.
args : list[str]
The CLI arguments passed to the REPL.
"""
global __has_initialized # noqa: PLW0603
if not sys.stdout.isatty():
print("\x1b[1;31mError:\x1b[22;39m piping output is not supported\n")
raise SystemExit(1)
if __has_initialized:
builtins.print(
"\x1b[1;93mWARNING: "
"\x1b[39mREPL is already initialized\x1b[22m",
file=sys.stderr,
)
init_func(args)
__has_initialized = True
if __name__ == "__main__":
main(init, args=sys.argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment