Compare commits

...

10 Commits
v1.1 ... master

Author SHA1 Message Date
39f55c1b37 Fix for logging 2022-10-02 01:53:32 +03:00
8cd4e59918 Add asyncio support 2022-10-01 13:41:08 +03:00
069a7d9356 Minor fixes 2022-10-01 13:40:54 +03:00
santaspeen
56c4212391 del sonar files 2022-02-27 21:07:16 +03:00
santaspeen
156fba7a88 Add preview 2022-02-27 21:05:46 +03:00
santaspeen
3892657558 Ignore Sonar 2022-02-27 18:51:00 +03:00
santaspeen
12408f841b Update README 2022-02-24 16:07:35 +03:00
santaspeen
3533c7ebbf Update README 2022-02-24 16:02:11 +03:00
SantaSpeen
88138b6cb5 Update README 2022-02-23 00:46:09 +03:00
SantaSpeen
575879459d Update README 2022-02-23 00:41:32 +03:00
7 changed files with 161 additions and 56 deletions

6
.gitignore vendored
View File

@ -128,4 +128,10 @@ dmypy.json
# Pyre type checker # Pyre type checker
.pyre/ .pyre/
# Ignore .idea
.idea/ .idea/
# ignore Sonar
codecov
.scannerwork/

View File

@ -1,4 +1,11 @@
# CLI in Python # CLI in Python
<p align="center">
<img src="https://img.shields.io/github/license/SantaSpeen/CLI-in-Python?style=for-the-badge" alt="license" title="license: MIT">
<img src="https://img.shields.io/github/issues/SantaSpeen/CLI-in-Python?style=for-the-badge" alt="issues">
<img src="./assets/magic_logo.svg" alt="magic">
<br/>
<img src="./assets/preview.png" alt="preview">
</p>
##### Версия для русских: [здесь](./README_RU.md) ##### Версия для русских: [здесь](./README_RU.md)
@ -52,7 +59,7 @@ cli.write("cli.write")
# ]: cli.write # ]: cli.write
``` ```
* With logging output usage * With `logging` output usage
```python ```python
from console import Console from console import Console
@ -75,7 +82,7 @@ logging.info("Info log")
# ]: 2022-02-20 23:22:49,731 - root - INFO - Info log # ]: 2022-02-20 23:22:49,731 - root - INFO - Info log
``` ```
* with `print()` and `console.log` output usage * With `print()` and `console.log` output usage
```python ```python
from console import Console from console import Console
@ -113,3 +120,4 @@ Copy all from `builtins_fix.pyi` and insert into `builtins.pyi` at line `131` be
Used in: Used in:
* [Python-CLI-Game-Engine](https://github.com/SantaSpeen/Python-CLI-Game-Engine) * [Python-CLI-Game-Engine](https://github.com/SantaSpeen/Python-CLI-Game-Engine)
* [CLI-Remote-in-Python](https://github.com/SantaSpeen/CLI-Remote-in-Python)

View File

@ -1,4 +1,11 @@
# CLI in Python # CLI in Python
<p align="center">
<img src="https://img.shields.io/github/license/SantaSpeen/CLI-in-Python?style=for-the-badge" alt="license" title="license: MIT">
<img src="https://img.shields.io/github/issues/SantaSpeen/CLI-in-Python?style=for-the-badge" alt="issues">
<img src="./assets/magic_logo.svg" alt="magic">
<br/>
<img src="./assets/preview.png" alt="preview">
</p>
## Консольная оболочка для программ на Python3 ## Консольная оболочка для программ на Python3
@ -50,7 +57,7 @@ cli.write("cli.write")
# ]: cli.write # ]: cli.write
``` ```
* Использование вывода с logging * Использование вывода с `logging`
```python ```python
from console import Console from console import Console
@ -73,7 +80,7 @@ logging.info("Info log")
# ]: 2022-02-20 23:22:49,731 - root - INFO - Info log # ]: 2022-02-20 23:22:49,731 - root - INFO - Info log
``` ```
* Использование вывода с`print()` и `console.log` * Использование вывода с `print()` и `console.log`
```python ```python
from console import Console from console import Console
@ -101,13 +108,14 @@ console << "<< log"
# ]: << log # ]: << log
``` ```
Если вы используете IDE, можно обновить `builtins.pyi` используя `scr/builtins_fix.pyi`. <br/> Если вы используете IDE, можно обновить `builtins.pyi`, что бы она не ругалась на отсутствие `console.*` используя `scr/builtins_fix.pyi`. <br/>
Скопируйте всё из `builtins_fix.pyi` и вставте в `builtins.pyi` на `131` линию, до `class type(object)`. Скопируйте всё из `builtins_fix.pyi` и вставте в `builtins.pyi` на `131` линию, перед `class type(object)`.
## Ссылки ## Ссылки
* [Мой Telegram](https://t.me/SantaSpeen "SantaSpeen"): https://t.me/SantaSpeen * [Мой Telegram](https://t.me/SantaSpeen "SantaSpeen"): https://t.me/SantaSpeen
Используемые в поектах: Используемые в проектах:
* [Python-CLI-Game-Engine](https://github.com/SantaSpeen/Python-CLI-Game-Engine) * [Python-CLI-Game-Engine](https://github.com/SantaSpeen/Python-CLI-Game-Engine)
* [CLI-Remote-in-Python](https://github.com/SantaSpeen/CLI-Remote-in-Python)

40
assets/magic_logo.svg Normal file
View File

@ -0,0 +1,40 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="180.5" height="28" role="img" aria-label="MADE WITH: MAGIC">
<title>MADE WITH: MAGIC</title>
<g shape-rendering="crispEdges">
<rect width="100.25" height="28" fill="#555"/>
<rect x="100.25" width="80.25" height="28" fill="#fe7d37"/>
</g>
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="100">
<svg x="3"
y="4"
id="Capa_1"
height="20"
viewBox="0 0 512 512"
width="20"
xmlns="http://www.w3.org/2000/svg">
<g>
<path d="m395.82 182.616-188.72 188.72-12.91 1.72-9.35 20.54-34.31 34.31-11.01-.73-11.25 22.99-56.48 56.48c-2.93 2.93-6.77 4.39-10.61 4.39s-7.68-1.46-10.61-4.39l-22.62-22.62h-.01l-22.62-22.63c-5.86-5.86-5.86-15.36 0-21.22l77.63-77.63 16.6-7.03 5.66-15.23 34.31-34.31 14.84-4.92 7.42-17.34 167.57-167.57 33.24 33.24z" fill="#f66"/>
<path d="m395.82 116.146v66.47l-188.72 188.72-12.91 1.72-9.35 20.54-34.31 34.31-11.01-.73-11.25 22.99-56.48 56.48c-2.93 2.93-6.77 4.39-10.61 4.39s-7.68-1.46-10.61-4.39l-22.62-22.62 334.64-334.64z" fill="#e62e6b"/>
<path d="m506.61 209.006-69.14-69.13 43.05-88.38c2.8-5.75 1.65-12.65-2.88-17.17-4.52-4.53-11.42-5.68-17.17-2.88l-88.38 43.05-69.13-69.14c-4.35-4.35-10.92-5.6-16.56-3.16-5.65 2.45-9.23 8.09-9.04 14.24l2.86 90.45-85.37 57.83c-4.91 3.32-7.4 9.22-6.36 15.04 1.04 5.83 5.4 10.51 11.15 11.94l96.62 24.01 24.01 96.62c1.43 5.75 6.11 10.11 11.94 11.15.87.16 1.75.23 2.62.23 4.92 0 9.6-2.42 12.42-6.59l57.83-85.37 90.45 2.86c6.14.19 11.79-3.39 14.24-9.04 2.44-5.64 1.19-12.21-3.16-16.56z" fill="#fabe2c"/>
<path d="m296.26 215.706 24.01 96.62c1.43 5.75 6.11 10.11 11.94 11.15.87.16 1.75.23 2.62.23 4.92 0 9.6-2.42 12.42-6.59l57.83-85.37 90.45 2.86c6.14.19 11.79-3.39 14.24-9.04 2.44-5.64 1.19-12.21-3.16-16.56l-69.14-69.13 43.05-88.38c2.8-5.75 1.65-12.65-2.88-17.17z" fill="#fd9025"/>
<path d="m465 416.966c-25.92 0-47 21.08-47 47s21.08 47 47 47 47-21.08 47-47-21.08-47-47-47z" fill="#fabe2c"/>
<path d="m104 28.966h-13v-13c0-8.284-6.716-15-15-15s-15 6.716-15 15v13h-13c-8.284 0-15 6.716-15 15s6.716 15 15 15h13v13c0 8.284 6.716 15 15 15s15-6.716 15-15v-13h13c8.284 0 15-6.716 15-15s-6.716-15-15-15z" fill="#fed843"/>
<path d="m207.1 371.336-22.26 22.26-45.32-87.62 22.26-22.26z" fill="#fed843"/>
<path d="m184.84 393.596 22.26-22.26-22.66-43.81-22.265 22.265z" fill="#fabe2c"/>
<path d="m150.53 427.906-22.26 22.26-45.32-87.62 22.26-22.26z" fill="#fed843"/>
<path d="m128.27 450.166 22.26-22.26-22.655-43.815-22.26 22.26z" fill="#fabe2c"/>
<circle cx="15" cy="119.969" fill="#5ed8d3" r="15"/>
<circle cx="128" cy="199.969" fill="#d599ed" r="15"/>
<circle cx="192" cy="63.964" fill="#f66" r="15"/>
<circle cx="328" cy="415.967" fill="#31bebe" r="15"/>
<circle cx="440" cy="327.967" fill="#ad77e3" r="14.999"/>
</g>
</svg>
<text transform="scale(.1)" x="600.25" y="175" textLength="590.5" fill="#fff">
MAGIC BY
</text>
<text transform="scale(.1)" x="1400.75" y="175" textLength="700.5" fill="#fff" font-weight="bold">
SantaSpeen
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
assets/preview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@ -2,17 +2,23 @@
# Developed by Ahegao Devs # Developed by Ahegao Devs
# Written by: SantaSpeen # Written by: SantaSpeen
# Version 1.1 # Version 2.1
# Licence: MIT # Licence: MIT
# (c) ahegao.ovh 2022 # (c) ahegao.su 2022
import builtins import builtins
import logging import logging
import sys import sys
import traceback import traceback
import asyncio
from builtins import RecursionError from builtins import RecursionError
from typing import AnyStr from typing import AnyStr
try:
from aioconsole import ainput
except ImportError:
ainput = None
class ConsoleIO: class ConsoleIO:
@ -33,11 +39,12 @@ class ConsoleIO:
class Console: class Console:
def __init__(self, def __init__(self,
prompt_in: str = ">", prompt_in=">",
prompt_out: str = "]:", prompt_out="]:",
not_found: str = "Command \"%s\" not found in alias.", not_found="Command \"%s\" not found in alias.",
file: str or None = ConsoleIO, file=ConsoleIO,
debug: bool = False) -> None: debug=False,
async_loop=None) -> None:
""" """
def __init__(self, def __init__(self,
prompt_in: str = ">", prompt_in: str = ">",
@ -66,6 +73,8 @@ class Console:
self.is_run = False self.is_run = False
self.async_loop = async_loop
self.get_IO = ConsoleIO self.get_IO = ConsoleIO
def __debug(self, *x): def __debug(self, *x):
@ -78,13 +87,14 @@ class Console:
print(item) print(item)
def __get_max_len(self, arg) -> int: @staticmethod
def __get_max_len(arg) -> int:
i = 0 i = 0
arg = list(arg) arg = list(arg)
for a in arg: for a in arg:
l = len(str(a)) ln = len(str(a))
if l > i: if ln > i:
i = l i = ln
return i return i
def __create_man_message(self, argv: list) -> AnyStr: def __create_man_message(self, argv: list) -> AnyStr:
@ -101,6 +111,7 @@ class Console:
""" Print help message and alias of console commands""" """ Print help message and alias of console commands"""
self.__debug("creating help message") self.__debug("creating help message")
raw = False raw = False
max_len_v = 0
if "--raw" in argv: if "--raw" in argv:
max_len_v = self.__get_max_len(self.__alias.values()) max_len_v = self.__get_max_len(self.__alias.values())
print() print()
@ -114,17 +125,15 @@ class Console:
if not raw: if not raw:
message += f"%{max_len}s : Help message\n" % "Command" message += f"%{max_len}s : Help message\n" % "Command"
else: else:
message += f"%-{max_len - len(self.__prompt_out)-1}s; %-{max_len_v}s; __doc__\n" % ("Key", "Object") message += f"%-{max_len - len(self.__prompt_out) - 1}s; %-{max_len_v}s; __doc__\n" % ("Key", "Object")
for k, v in self.__alias.items(): for k, v in self.__alias.items():
doc = v['f'].__doc__ doc = v['f'].__doc__
if raw: if raw:
message += f"%-{max_len}s; %-{max_len_v}s; %s\n" % (k, v, doc)
message += f"%-{max_len}s; %-{max_len_v}s; %s\n" % (k, v, doc)
else: else:
if doc is None: if doc is None:
doc = " No help message found" doc = " No help message found"
message += f" %{max_len}s :%s\n" % (k, doc) message += f" %{max_len}s :%s\n" % (k, doc)
@ -206,11 +215,14 @@ class Console:
def emit(cls, record): def emit(cls, record):
try: try:
msg = cls.format(record) msg = cls.format(record)
ConsoleIO.write(self.__create_message(msg)) if cls.stream.name == "<stderr>":
ConsoleIO.write(self.__create_message(msg))
else:
cls.stream.write(msg + cls.terminator)
cls.flush() cls.flush()
except RecursionError: except RecursionError:
raise raise
except Exception: except Exception as e:
cls.handleError(record) cls.handleError(record)
logging.StreamHandler.emit = emit logging.StreamHandler.emit = emit
@ -227,6 +239,29 @@ class Console:
builtins.print = self.__builtins_print builtins.print = self.__builtins_print
def _cli_logic(self, cmd_in):
try:
cmd = cmd_in.split(" ")[0]
if cmd == "":
pass
else:
command_object = self.__alias.get(cmd)
if command_object:
command = command_object['f']
if command_object['e']:
argv = cmd_in[len(cmd) + 1:].split(" ")
output = command(argv)
else:
output = command()
self.log(str(output))
else:
self.log(self.__not_found % cmd)
except Exception as e:
ConsoleIO.write_err("\rDuring the execution of the command, an error occurred:\n\n" +
str(traceback.format_exc()) +
"\nType Enter to continue.")
def run(self) -> None: def run(self) -> None:
""" """
def run(self) -> None: def run(self) -> None:
@ -243,26 +278,31 @@ class Console:
""" """
self.__debug(f"run while {whl}") self.__debug(f"run while {whl}")
while whl: while whl:
try: ConsoleIO.write("\r" + self.__prompt_in + " ")
ConsoleIO.write("\r" + self.__prompt_in + " ") self._cli_logic(ConsoleIO.read())
cmd_in = ConsoleIO.read()
cmd = cmd_in.split(" ")[0]
if cmd == "":
pass
else:
command_object = self.__alias.get(cmd)
if command_object:
command = command_object['f']
if command_object['e']:
argv = cmd_in[len(cmd) + 1:].split(" ")
output = command(argv)
else:
output = command()
self.log(str(output))
else: async def async_run(self) -> None:
self.log(self.__not_found % cmd) """
except Exception as e: def async_run(self) -> None:
ConsoleIO.write_err("\rDuring the execution of the command, an error occurred:\n\n" + :return: None
str(traceback.format_exc()) + """
"\nType Enter to continue.") self.is_run = True
await self.async_run_while(True)
async def async_run_while(self, whl) -> None:
"""
async def async_run_while(self, whl) -> None:
:param whl: run while what?
:return: None
"""
if ainput is None:
print("Install aioconsole for async! pip install aioconsole")
exit(1)
if self.async_loop is None:
self.async_loop = asyncio.get_event_loop()
self.__debug(f"async run while {whl}")
reader = asyncio.StreamReader()
while whl:
ConsoleIO.write("\r" + self.__prompt_in + " ")
res = await ainput()
self._cli_logic(res)

View File

@ -6,8 +6,8 @@
# (c) ahegao.ovh 2022 # (c) ahegao.ovh 2022
from _typeshed import SupportsWrite from _typeshed import SupportsWrite
from builtins import function from asyncio import AbstractEventLoop
from typing import AnyStr from typing import AnyStr, NoReturn
class ConsoleIO: class ConsoleIO:
@ -29,7 +29,8 @@ class Console(object):
prompt_out: str = "]:", prompt_out: str = "]:",
not_found: str = "Command \"%s\" not found in alias.", not_found: str = "Command \"%s\" not found in alias.",
file: SupportsWrite[str] or None = Console, file: SupportsWrite[str] or None = Console,
debug: bool = False) -> None: debug: bool = False,
async_loop: AbstractEventLoop = None) -> NoReturn:
self.get_IO: ConsoleIO = ConsoleIO self.get_IO: ConsoleIO = ConsoleIO
self.is_run: bool = False self.is_run: bool = False
@ -38,11 +39,13 @@ class Console(object):
@property @property
def alias(self) -> dict: ... def alias(self) -> dict: ...
def add(self, key: str, func, argv: bool = False, man: str = "No have manual message") -> dict:... def add(self, key: str, func, argv: bool = False, man: str = "No have manual message") -> dict:...
def log(self, s: AnyStr, r='\r') -> None: ... def log(self, s: AnyStr, r='\r') -> NoReturn: ...
def __lshift__(self, s: AnyStr) -> None: def __lshift__(self, s: AnyStr) -> NoReturn:
self.write(s) self.write(s)
def write(self, s: AnyStr, r='\r') -> None: ... def write(self, s: AnyStr, r='\r') -> NoReturn: ...
def logger_hook(self) -> None: ... def logger_hook(self) -> NoReturn: ...
def builtins_hook(self) -> None: ... def builtins_hook(self) -> NoReturn: ...
def run(self) -> None: ... def run(self) -> NoReturn: ...
def run_while(self, whl) -> None:... def run_while(self, whl) -> NoReturn:...
async def async_run(self) -> NoReturn: ...
async def async_run_while(self, whl) -> NoReturn: ...