oy3o 命名空间,包含一些子包
Project description
oy3o
A Python library for building Text User Interfaces (TUIs), providing interactive components based on curses, such as a multi-line text editor and flexible input handling.
Note: This library depends on Python's curses module, which is typically part of the standard library on Unix-like systems (Linux, macOS) but is not available by default on Windows. Windows users might need to install the windows-curses package (pip install windows-curses), but compatibility may require further testing.
Features
- Interactive Components:
- A
curses-based editable text box/editor (Editor). - Supports basic text navigation (up/down/left/right, home/end).
- Handles text wrapping and view scrolling.
- A
- Advanced Input Handling (
oy3o.input):- Listens for and responds to individual key presses, including modifier keys (Ctrl).
- Handles special keys (arrow keys, Enter, Backspace, etc.).
- Captures mouse events: clicks, scrolls (up/down), and movement (including coordinates and modifier states like Ctrl+Alt+Move).
- Bind functions to specific key, mouse, or character events using
onkey,onmouse,onchar. - Provides a main input loop (
listen()) to process the event stream. - Note:
input.ALTis currently mainly intended for mouse events, as Alt + letter keys are often intercepted by the OS or terminal.
- Wide Character Support: Integrates
wcwidthfor correct handling of wide characters (e.g., CJK characters). - Utilities (
oy3o._): Includes helpful utilities and decorators like event subscription (@subscribe), throttling (@throttle), debouncing (@debounce), task management (Task,Timer), metaprogramming helpers (@members,@template,Proxy), and more. (See details below). - Token Counting: Integrates
tiktokenfor token counting. - System Clipboard: Supports copy/paste operations via
pyperclip.
Installation
You can install oy3o from PyPI using pip:
pip install oy3o
Basic Usage - Editor (oy3o.editor)
Here's a simple example demonstrating how to start a basic oy3o editor in the terminal:
import curses
from oy3o.editor import Editor # Assuming __init__ exposes Editor
def main(stdscr):
# Basic curses setup
curses.curs_set(1) # Show cursor
stdscr.keypad(True) # Enable special keys (like arrows)
curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION) # Enable mouse events
curses.mouseinterval(0) # Report mouse events immediately
stdscr.clear() # Clear screen
# Get screen dimensions
height, width = stdscr.getmaxyx()
# Create Editor instance
# Editor draws and manages its area within the given window
# based on top/bottom/left/right margins.
editor = Editor(
window=stdscr, # Parent window is stdscr
top=1, # Top margin (starts at row 1 of stdscr)
bottom=1, # Bottom margin (1 row from stdscr bottom)
left=1, # Left margin (starts at col 1 of stdscr)
right=1, # Right margin (1 col from stdscr right)
text="Hello, World!\nThis is the oy3o editor.\nPress Ctrl+D to save and exit.\nPress Esc to cancel.", # Initial text
editable=True # Allow editing
)
# (Optional) Add some hint text outside the editor
stdscr.addstr(0, 1, "oy3o Editor Example - Ctrl+D Exit / Esc Cancel")
stdscr.refresh() # Refresh parent window to show hint
# Start the editor's main loop
# The edit() method takes control of input until the user exits (e.g., Ctrl+D or Esc)
final_text = editor.edit()
# curses.wrapper automatically handles curses.endwin() to restore the terminal
# Return the result to be printed after curses has ended
return final_text
if __name__ == "__main__":
# Use curses.wrapper to safely initialize and clean up the curses environment
result = curses.wrapper(main)
# Print the result after curses environment is closed
print("\n--- Editor session ended ---")
if result is not None:
# Check the return value based on your editor.edit() implementation
print("Submitted content:")
print(result)
else:
# Depends on what edit() returns on cancellation (e.g., None or original text)
print("Editing cancelled.")
Advanced Usage - Input Handling (oy3o.input)
The oy3o.input module provides lower-level access to handle keyboard and mouse input.
import curses
from oy3o import input as oy3o_input # Import the input module
def main(stdscr):
# --- Crucial Curses Setup for input module ---
curses.curs_set(0) # Usually hide cursor unless needed
stdscr.keypad(True) # MUST be enabled for special keys (Arrows, F*, etc.)
curses.noecho() # Prevent keys from echoing automatically
curses.cbreak() # Get keys immediately, without waiting for Enter
# If mouse events are needed:
curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION)
curses.mouseinterval(0) # Report mouse events immediately
# Enable Xterm mouse move reporting (if terminal supports it)
print('\033[?1003h', end='')
stdscr.refresh() # Ensure the escape code is sent
stdscr.clear()
stdscr.addstr(1, 0, "oy3o Input Demo. Press 'q' to quit.")
stdscr.addstr(2, 0, "Try pressing Ctrl+A, Arrow Keys, Enter, Backspace.")
stdscr.addstr(3, 0, "Try scrolling or moving the mouse (with/without Ctrl+Alt).")
stdscr.addstr(4, 0, "Try typing 😊 or 💕.")
stdscr.refresh()
# --- Event Bindings ---
oy3o_input.onkey(oy3o_input.CTRL + 'a', lambda _: stdscr.addstr(6, 0, "Detected: CTRL + A ".ljust(30)))
oy3o_input.onkey(oy3o_input.DOWN, lambda _: stdscr.addstr(7, 0, "Detected: ARROW DOWN ".ljust(30)))
oy3o_input.onkey(oy3o_input.UP, lambda _: stdscr.addstr(8, 0, "Detected: ARROW UP ".ljust(30)))
oy3o_input.onkey(oy3o_input.LEFT, lambda _: stdscr.addstr(9, 0, "Detected: ARROW LEFT ".ljust(30)))
oy3o_input.onkey(oy3o_input.RIGHT, lambda _: stdscr.addstr(10, 0, "Detected: ARROW RIGHT".ljust(30)))
oy3o_input.onkey(oy3o_input.ENTER, lambda _: stdscr.addstr(11, 0, "Detected: ENTER ".ljust(30)))
oy3o_input.onkey(oy3o_input.BACKSPACE, lambda _: stdscr.addstr(12, 0, "Detected: BACKSPACE ".ljust(30)))
oy3o_input.onmouse(oy3o_input.SCROLL_DOWN, lambda *_: stdscr.addstr(13, 0, "Detected: SCROLL DOWN".ljust(30)))
oy3o_input.onmouse(oy3o_input.SCROLL_UP, lambda *_: stdscr.addstr(14, 0, "Detected: SCROLL UP ".ljust(30)))
def show_mouse_pos(y, x, type_key):
type_str = f"Type: {type_key!r}" # Display the internal key representation
stdscr.addstr(15, 0, f"Mouse Move: ({y},{x}) {type_str}".ljust(40))
stdscr.refresh()
# Normal move
oy3o_input.onmouse(oy3o_input.MOVE, show_mouse_pos)
# Move with modifiers (Ctrl+Alt)
oy3o_input.onmouse(oy3o_input.CTRL + oy3o_input.ALT + oy3o_input.MOVE, show_mouse_pos)
# Handle specific characters (like Emoji)
oy3o_input.onchar('😊', lambda _: stdscr.addstr(16, 0, "Detected: :smile: ".ljust(30)))
oy3o_input.onchar('💕', lambda _: stdscr.addstr(17, 0, "Detected: :love: ".ljust(30)))
# --- Main Event Loop ---
# listen() blocks and yields key/mouse events
# `move=1` (default) includes MOVE events. `move=0` excludes them.
# Pass stdscr so `listen` can use its getch method.
for event in oy3o_input.listen(stdscr, move=1):
# You can handle events here not caught by onkey/onmouse/onchar
# event can be a character, special key constant, or mouse tuple/constant
stdscr.addstr(19, 0, f"Raw Event: {event!r}".ljust(40))
stdscr.refresh()
if event == 'q':
oy3o_input.stop() # Stop the listen() loop
# --- Cleanup (before wrapper exits) ---
# Disable Xterm mouse reporting
print('\033[?1003l', end='')
# Optional: short sleep allows terminal to process escape code before restoring
curses.napms(50)
if __name__ == "__main__":
curses.wrapper(main)
print("\nInput demo finished.")
Utilities (oy3o)
The oy3o module provides a collection of reusable utility classes, decorators, and helper functions used throughout the oy3o library or available for direct use.
from oy3o import Task, Timer, throttle, debounce, subscribe, members, template # etc.
Key components include:
Decorators
@throttle(interval: int, exit: bool = True): Limits function call frequency (rate-limiting). Ensures the function runs at most once perinterval.exit=Truequeues the last call to run after the interval. See code example in_.py.@debounce(interval: int, enter: bool = False, exit: bool = True): Delays function execution untilintervalseconds have passed without new calls. Useful for actions after a pause (e.g., search after typing stops).enter=Trueruns on the first call,exit=Trueruns after the pause. See code example in_.py.@members(*args): Adds default attributes (e.g.,("name", default_value)) to a class, handling mutable defaults correctly withdeepcopy. See code example in_.py.@subscribe(events: list[str] = [], single: bool = False): Adds a simple pub/sub event system (trigger,subscribe,unsubscribe) to a class.eventsrestricts allowed event names.single=Trueuses a shared event hub for all instances. See code example in_.py.@template(declare: T): Implements generic functions based on signature and type hints, similar tosingledispatchbut matching the full signature. Requires@template_instance.registerfor implementations. See code example in_.py.@commands(commands: list): Wraps a class to restrict external access to only the methods listed incommands. See code example in_.py.
Utility Classes
Task(func: Callable, ...): Wraps a function call for synchronous (.do()), threaded (.threading()), or exception-handled (.catch()) execution. Handles async functions viaasyncio.runwithin.do(). See code example in_.py.Timer(once: bool, interval: int, function: Callable, ...): An enhancedthreading.Timersupporting repeated execution (once=False) and argument updates (.update()) without restarting. See code example in_.py.Proxy(target: T, handler: type): Implements the Proxy pattern, delegating attribute/item access to ahandlerclass. See code example in_.py.
Helper Functions & Constants
- Includes type checkers (
isIterable,isAsync, etc.),setdefault, a uniqueundefinedsentinel, and Numba type aliases.
(Refer to the source code in src/oy3o/_.py for detailed implementations and docstrings.)
License
This project is licensed under the MIT License. See the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit issues or pull requests.
Acknowledgements
- Thanks to the
curseslibrary for providing powerful terminal control capabilities. - Thanks to the
wcwidthlibrary for helping handle character widths correctly.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file oy3o-0.0.1.tar.gz.
File metadata
- Download URL: oy3o-0.0.1.tar.gz
- Upload date:
- Size: 28.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0f95542d2bf2d659750534b14883ec01942b00b6b7328d87a500bbf4fea9fc5
|
|
| MD5 |
809ebfe7da83e461443eb955a8f04ad9
|
|
| BLAKE2b-256 |
6848571db65622a9904d6185d036fd2fbb88f516874b8d9fa105c3f4a85d426d
|
File details
Details for the file oy3o-0.0.1-py3-none-any.whl.
File metadata
- Download URL: oy3o-0.0.1-py3-none-any.whl
- Upload date:
- Size: 23.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
035c22f03cdd32a99d1d6f488524f6a1c4ea658b6d2dbea77c26af6b6045fe5e
|
|
| MD5 |
d0e01feafda34e8498fafe6298ec5696
|
|
| BLAKE2b-256 |
e005758227dec113b16ab2517b950f45e949c309d22a7a7d097dfb894a23f5ab
|