oy3o 命名空间,包含一些子包
Project description
oy3o
A Python library for building Text User Interfaces (TUIs), providing curses-based interactive components (e.g., multi-line text editor, scrollable list view) 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 may need to install the windows-curses package (pip install windows-curses), but compatibility may require further testing.
Features
- Interactive Components:
curses-based editable textbox/editor (oy3o.editor.Editor).- Supports basic text navigation (up, down, left, right, home, end).
- Supports text wrapping and view scrolling.
- Scrollable list view (
oy3o.flow.View).- Displays the content of
oy3o.list.List. - Supports keyboard and mouse wheel scrolling.
- Auto-scrolls to newly added entries.
- Displays the content of
- Advanced Input Handling (
oy3o.input):- Listens and responds to individual key presses, including modifier keys (Ctrl).
- Handles special keys (arrow keys, enter, backspace, etc.).
- Captures mouse events: clicks, scrolling (up/down), and movement (including coordinates and modifier key states, e.g., Ctrl+Alt+Move).
- Binds functions to specific key, mouse, or character events via
onkey,onmouse,onchar. - Provides a main input loop (
listen()) to process the event stream. - Note:
input.ALTis currently primarily for mouse events, as Alt + letter keys are often intercepted by the operating system or terminal.
- Data Structures (
oy3o.list):List: An observable list that can trigger events when its content changes, integrating with components likeFlowandView.
- Wide Character Support: Integrates
wcwidthto correctly handle wide characters (e.g., CJK characters). - Utilities (
oy3o._): Contains several utility tools and decorators such as event subscription (@subscribe), throttling (@throttle), debouncing (@debounce), task management (Task,Timer), metaprogramming helpers (@members,@template,Proxy), etc. (See details below). - Token Counting: Integrates
tiktokenfor token counting. - System Clipboard: Supports copy/paste operations with the system clipboard via
pyperclip.
Installation
You can install oy3o from PyPI using pip:
pip install oy3o
Modular Running (Command-Line Piping)
Some oy3o modules can be run directly from the command line using python -m and support piping content from standard input:
-
Editor (
oy3o.editor):cat some_file.txt | python -m oy3o.editor
This will load the content of
some_file.txtinto the editor. After editing, pressCtrl+Dto save and exit (content will be printed to standard output); pressEscto cancel. -
Flow View (
oy3o.flow):cat some_file.txt | python -m oy3o.flow
This will display each line of
some_file.txtas a list item in a scrollable flow view. Pressqto quit.
Basic Usage - Editor (oy3o.editor)
Here's a simple example demonstrating how to launch a basic oy3o editor in the terminal:
import curses
from oy3o.editor import Editor
def main(stdscr):
# Create an Editor instance
# Editor draws and manages its area within the given window based on top/bottom/left/right
editor = Editor(
window=stdscr, # Specify the parent window as stdscr
top=1, # Top margin of the editor area (starts from stdscr row 1)
bottom=1, # Bottom margin of the editor area (1 row from the bottom of stdscr)
left=1, # Left margin of the editor area (starts from stdscr column 1)
right=1, # Right margin of the editor area (1 column from the right of stdscr)
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 to Save & Exit / Esc to Cancel")
stdscr.refresh() # Refresh the parent window to display the hint
# Start the editor's main loop
# The edit() method will take over input until the user exits (e.g., by pressing Ctrl+D or Esc)
final_text = editor.edit()
# curses.wrapper will automatically handle curses.endwin() to restore the terminal
# Return the result so it can be printed after the curses environment ends
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 the curses environment is closed
print("\n--- Editor session ended ---")
if result is not None:
# Depending on your editor.edit() implementation, confirm if it returns the final text or something else
print("Submitted content:")
print(result)
else:
# This depends on what edit() returns on cancellation, possibly None or the original text
print("Editing was canceled.")
Basic Usage - Flow View (oy3o.flow)
The oy3o.flow.View class can display the content of an oy3o.list.List in a scrollable curses window.
import curses
from oy3o import input
from oy3o.list import List
from oy3o.flow import View
import time # For demonstrating dynamic content addition
def main(stdscr):
curses.curs_set(0) # Hide the cursor
stdscr.nodelay(True) # Non-blocking input
# Create a List instance
data_list = List([f"Initial line {i}" for i in range(20)])
# Create a View in stdscr
# y, x, height, width define the View's area within stdscr
# Use a with statement to ensure resources are properly cleaned up
with View(data_list, stdscr, y=1, x=1, height=curses.LINES - 2, width=curses.COLS - 2) as view:
stdscr.addstr(0, 1, "oy3o Flow View Example - Press 'q' to quit, 'a' to add a line, scroll with wheel")
stdscr.refresh()
# Start input listening
# view.listen() will handle internal events like mouse scrolling
# input.listen() is the external event loop
counter = 20
for wc in input.listen(stdscr, delay=0.05): # delay reduces CPU usage
if wc == 'q':
input.stop() # Stop the input.listen() loop
break
elif wc == 'a':
data_list.append(f"Newly added line {counter}")
counter += 1
# view.render() will be called automatically when data_list is updated (via subscription)
# If manual refresh or other logic is needed, it can be added here
# Simulate external data updates
# if time.time() % 5 < 0.05: # Add approximately every 5 seconds
# data_list.append(f"Periodically added line {counter}")
# counter += 1
# curses.wrapper will handle curses.endwin()
if __name__ == "__main__":
curses.wrapper(main)
print("Flow view closed.")
Advanced Usage - Input Handling (oy3o.input)
The oy3o.input module provides a lower-level interface for handling keyboard and mouse input.
from oy3o import input
input.onkey(input.CTRL + input.A, lambda _:print('CTRL + A'))
input.onkey(input.DOWN, lambda _:print('ARROW DOWN'))
input.onkey(input.UP, lambda _:print('ARROW UP'))
input.onkey(input.LEFT, lambda _:print('ARROW LEFT'))
input.onkey(input.RIGHT, lambda _:print('ARROW RIGHT'))
input.onkey(input.ENTER, lambda _:print('ENTER'))
input.onkey(input.BACKSPACE, lambda _:print('BACKSPACE'))
input.onmouse(input.SCROLL_DOWN, lambda *_:print('SCROLL DOWN'))
input.onmouse(input.SCROLL_UP, lambda *_:print('SCROLL UP'))
input.onchar('😊', lambda _:print(':smile:'))
input.onchar('💕', lambda _:print(':love:'))
for wc in input.listen(move=0): # Set move=0 if you don't need mouse move events with no buttons pressed
if wc == 'q':
input.stop()
print(wc)
input.ALT is mainly for mouse events, as ALT + Key is often intercepted by the OS/terminal.
from oy3o.terminal import curses
import oy3o.input as input
input.init()
screen = curses.stdscr
def pos(y,x,type):
screen.addstr(0, 0, f'({y},{x})')
screen.clrtoeol()
screen.refresh()
input.onmouse(input.ALT + input.MOVE, pos)
for wc in input.listen(screen):
if wc == 'q':
input.stop()
Utilities (oy3o)
The oy3o module (often from oy3o._) provides a collection of reusable utility classes, decorators, and helper functions, used internally within the oy3o library and also available for direct use.
from oy3o import Task, Timer, throttle, debounce, subscribe, members, template # and more
Key components include:
Decorators
@throttle(interval: int, exit: bool = True): Limits function call frequency (rate limiting). Ensures the function is executed at most once perintervalseconds.exit=Truequeues the arguments of the last call to be executed after the interval. See code examples in_.py.@debounce(interval: int, enter: bool = False, exit: bool = True): Delays function execution untilintervalseconds have passed without a new call since the last call. Useful for actions performed after activity has paused (e.g., searching after typing stops).enter=Trueexecutes on the first call,exit=Trueexecutes after the pause. See code examples in_.py.@members(*args): Adds default attributes (e.g.,("name", default_value)) to a class, correctly handling mutable default values viadeepcopy. See code examples in_.py.@subscribe(events: list[str] = [], single: bool = False): Adds a simple publish/subscribe event system (trigger,subscribe,unsubscribemethods) to a class.eventslimits allowed event names.single=Truemakes all instances share the same event hub. See code examples in_.py.@template(declare: T): Implements generic functions (templates) based on signatures and type hints, similar tofunctools.singledispatchbut matches the full signature. Requires registering concrete implementations with@template_instance.register. See code examples in_.py.@commands(commands: list): Wraps a class to restrict external access to methods specified in thecommandslist. See code examples in_.py.
Utility Classes
Task(func: Callable, ...): Wraps a function call to support synchronous (.do()), threaded (.threading()), or exception-handled (.catch()) execution. Handles async functions viaasyncio.runin.do(). See code examples in_.py.Timer(once: bool, interval: int, function: Callable, ...): An enhanced version ofthreading.Timerthat supports repeated execution (once=False) and updating parameters (.update()) without restarting. See code examples in_.py.Proxy(target: T, handler: type): Implements the Proxy pattern, delegating attribute/item access to ahandlerclass. See code examples in_.py.List(list):oy3o.list.Listis an observable list. It triggers an "update" event when its content is changed via methods likeappend,extend,insert,pop,remove,clear,__setitem__,__delitem__, etc.FlowandViewcomponents subscribe to this event to automatically refresh their display.
Helper Functions & Constants
- Includes type checkers (
isIterable,isAsync, etc.), a uniqueundefinedsentinel object, and Numba type aliases.
(For detailed implementations and docstrings, please refer to the source code in src/oy3o/_.py and src/oy3o/list.py.)
License
This project is licensed under the MIT License. See the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to raise Issues or submit Pull Requests.
Acknowledgements
- Thanks to the
curseslibrary for providing powerful terminal control capabilities. - Thanks to the
wcwidthlibrary for helping to correctly handle character widths.
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.2.0.tar.gz.
File metadata
- Download URL: oy3o-0.2.0.tar.gz
- Upload date:
- Size: 32.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
daf6ec5991d13e0b960b93102bf9adc77a6e0385904ee48b740ffd86cb34addb
|
|
| MD5 |
130e8843b842425db6dd6bfe9bb2c555
|
|
| BLAKE2b-256 |
2624642eaef59e7d0ec41065f0fd7ab9dd1f7b717d78aa53ee880a96e9af2840
|
File details
Details for the file oy3o-0.2.0-py3-none-any.whl.
File metadata
- Download URL: oy3o-0.2.0-py3-none-any.whl
- Upload date:
- Size: 29.3 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 |
eb204449b02ea950a3df44edc03f3128ddd966727eccc4841ff87cd9457c8777
|
|
| MD5 |
f0bd866130c8f03f6f6ad6e18529dda9
|
|
| BLAKE2b-256 |
e6e87f2202762efd7a15066bdcd9093adfe5929f24ef6e6c0dd3c4b3c1d65346
|