рдХрдо рд▓реЛрдХрдкреНрд░рд┐рдп рдФрд░ рдмрд╣реБрдд рд╕реАрдПрд▓рдЖрдИ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдирд╣реАрдВ: рдЪрдЯреНрдЯрд╛рди, рдирд╛рд▓, рд╕рд╛рд╣реБрд▓ рдФрд░ рдЕрдиреНрдп (рднрд╛рдЧ 2)

рдкрд╛рдпрдерди рдЗрдХреЛрд╕рд┐рд╕реНрдЯрдо рдореЗрдВ, CLI рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдХрдИ рдкреИрдХреЗрдЬ рд╣реИрдВ, рджреЛрдиреЛрдВ рд▓реЛрдХрдкреНрд░рд┐рдп, рдЬреИрд╕реЗ рдХрд┐ Click, рдФрд░ рдЗрддрдирд╛ рд╣реА рдирд╣реАрдВред рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦ рдореЗрдВ рд╕рдмрд╕реЗ рдЖрдо рд▓реЛрдЧреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ , рд▓реЗрдХрд┐рди рдХрдо-рдЬреНрдЮрд╛рдд, рд▓реЗрдХрд┐рди рдХрдо рджрд┐рд▓рдЪрд╕реНрдк рдирд╣реАрдВ, рдпрд╣рд╛рдВ рджрд┐рдЦрд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред



рдкрд╣рд▓реЗ рднрд╛рдЧ рдХреА рддрд░рд╣, рдЯреЙрдбреЛрд▓рд┐рдм рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рд▓рд┐рдП рдПрдХ рдХрдВрд╕реЛрд▓ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдкрд╛рдпрдерди 3.7 рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рд▓рд┐рдП рд▓рд┐рдЦреА рдЬрд╛рдПрдЧреАред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЗрди рдЬреБрдбрд╝рдирд╛рд░ рдХреЗ рд╕рд╛рде рдПрдХ рддреБрдЪреНрдЫ рдкрд░реАрдХреНрд╖рдг рдкреНрд░рддреНрдпреЗрдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рд▓рд┐рдЦрд╛ рдЬрд╛рдПрдЧрд╛:

@pytest.fixture(autouse=True) def db(monkeypatch): """ monkeypatch         ,         """ value = {"tasks": []} monkeypatch.setattr(todolib.TodoApp, "save", lambda _: ...) monkeypatch.setattr(todolib.TodoApp, "get_db", lambda _: value) return value @pytest.yield_fixture(autouse=True) def check(db): """      """ yield assert db["tasks"] and db["tasks"][0]["title"] == "test" # ,      EXPECTED = "Task 'test' created with number 1.\n" 

рдЗрд╕ рднрдВрдбрд╛рд░ рдореЗрдВ рд╕рднреА рд╕реНрд░реЛрдд рдХреЛрдб рдЙрдкрд▓рдмреНрдз рд╣реИрдВред

рдЪрдЯреНрдЯрд╛рди


GitHub
рдкреНрд░рд▓реЗрдЦрди
рдХрдИ рд▓реЛрдЧреЛрдВ рдиреЗ рдУрдкрдирд╕реНрдЯреИрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реБрдирд╛ рд╣реИ, рдЖрдИрдПрдПрдПрд╕ рдХреЗ рд▓рд┐рдП рдПрдХ рдЦреБрд▓рд╛ рд╕реНрд░реЛрдд рдордВрдЪред рдпрд╣ рдЕрдзрд┐рдХрд╛рдВрд╢ рдкрд╛рдпрдерди рдореЗрдВ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдХрдВрд╕реЛрд▓ рдЙрдкрдпреЛрдЧрд┐рддрд╛рдУрдВ рд╢рд╛рдорд┐рд▓ рд╣реИрдВ рдЬреЛ рд▓рдВрдмреЗ рд╕рдордп рд╕реЗ рд╕реАрдПрд▓рдЖрдИ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рджреЛрд╣рд░рд╛ рд░рд╣реЗ рд╣реИрдВред рдпрд╣ рддрдм рддрдХ рдЬрд╛рд░реА рд░рд╣рд╛, рдЬрдм рддрдХ рдХрд┐ рдХреНрд▓рд┐рдл рдпрд╛ рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рдЗрдВрдЯрд░рдлреЗрд╕ рдлреЙрд░реНрдореВрд▓рд╛ рдлреНрд░реЗрдорд╡рд░реНрдХ, рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдврд╛рдВрдЪреЗ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рдХрдЯ рдирд╣реАрдВ рд╣реБрдЖред рдЗрд╕рдХреЗ рд╕рд╛рде, рдУрдкрдирд╕реНрдЯреИрдХ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдиреЗ рдПрдХ рдУрдкрдирд╕реНрдЯреИрдХ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдореЗрдВ рдЕрдЬрдЧрд░-рдиреЙрд╡рдХреНрд▓рд┐рдПрдВрдЯ, рдкрд╛рдЗрдерди-рд╕реНрд╡рд┐рдлреНрдЯрдХреНрд▓рд┐рдВрдЯ рдФрд░ рдкрд╛рдЗрдерди-рдХреАрд╕реНрдЯреЛрдирдХрд┐рдПрд▓ рдЬреИрд╕реЗ рдкреИрдХреЗрдЬреЛрдВ рдХреЛ рд╕рдВрдпреЛрдЬрд┐рдд рдХрд┐рдпрд╛ред

рдЖрджреЗрд╢реЛрдВ
рдЖрджреЗрд╢реЛрдВ рдХреЛ рдШреЛрд╖рд┐рдд рдХрд░рдиреЗ рдХрд╛ рддрд░реАрдХрд╛ рд╕реАрдореЗрдВрдЯ рдФрд░ рдХреНрд▓рд┐рдпреЛ рд╕реЗ рдорд┐рд▓рддрд╛-рдЬреБрд▓рддрд╛ рд╣реИ: рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдкрд╛рд░реНрд╕рд░ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рд╛рдордиреЗ рдЖрддрд╛ рд╣реИ, рдФрд░ рдХрдорд╛рдВрдб рдХреНрд▓рд╛рд╕ рдХреЗ рдЙрддреНрддрд░рд╛рдзрд┐рдХрд╛рд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕реНрд╡рдпрдВ рдХрдорд╛рдВрдб рдмрдирд╛рдП рдЬрд╛рддреЗ рд╣реИрдВред рдЙрд╕реА рд╕рдордп, рдХрдорд╛рдВрдб рдХреНрд▓рд╛рд╕ рдореЗрдВ рдЫреЛрдЯреЗ рд╡рд┐рд╕реНрддрд╛рд░ рд╣реЛрддреЗ рд╣реИрдВ, рдЬреИрд╕реЗ рд▓рд┐рд╕реНрдЯрд░, рдЬреЛ рд╕реНрд╡рддрдВрддреНрд░ рд░реВрдк рд╕реЗ рдбреЗрдЯрд╛ рдХреЛ рдкреНрд░рд╛рд░реВрдкрд┐рдд рдХрд░рддрд╛ рд╣реИред

рд╕реНрд░реЛрдд рдХреЛрдб
 from cliff import command from cliff.lister import Lister class Command(command.Command): """Command with a parser shortcut.""" def get_parser(self, prog_name): parser = super().get_parser(prog_name) self.extend_parser(parser) return parser def extend_parser(self, parser): ... class Add(Command): """Add new task.""" def extend_parser(self, parser): parser.add_argument("title", help="Task title") def take_action(self, parsed_args): task = self.app.todoapp.add_task(parsed_args.title) print(task, "created with number", task.number, end=".\n") class Show(Lister, Command): """Show current tasks.""" def extend_parser(self, parser): parser.add_argument( "--show-done", action="store_true", help="Include done tasks" ) def take_action(self, parsed_args): tasks = self.app.todoapp.list_tasks(show_done=parsed_args.show_done) #     'there is no todos'   #      return ( ("Number", "Title", "Status"), [[task.number, task.title, "" if task.done else "тЬШ"] for task in tasks], ) class Done(Command): """Mark task as done.""" def extend_parser(self, parser): parser.add_argument("number", type=int, help="Task number") def take_action(self, parsed_args): task = self.app.todoapp.task_done(number=parsed_args.number) print(task, "marked as done.") #   Done    class Remove(Done): """Remove task from the list.""" def take_action(self, parsed_args): task = self.app.todoapp.remove_task(number=parsed_args.number) print(task, "removed from the list.") 


рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдФрд░ рдореБрдЦреНрдп

рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╡рд░реНрдЧ рдореЗрдВ initialize_app рдФрд░ clean_up рд╡рд┐рдзрд┐рдпрд╛рдВ рд╣реИрдВ , рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╡реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдбреЗрдЯрд╛ рдХреЛ рд╕реЗрд╡ рдХрд░рддреЗ рд╣реИрдВред

рд╕реНрд░реЛрдд рдХреЛрдб
 from cliff import app from cliff.commandmanager import CommandManager from todolib import TodoApp, __version__ class App(app.App): def __init__(self): #   add_command, CommandManager  #    setuptools entrypoint manager = CommandManager("todo_cliff") manager.add_command("add", Add) manager.add_command("show", Show) manager.add_command("done", Done) manager.add_command("remove", Remove) super().__init__( description="Todo notes on cliff", version=__version__, command_manager=manager, deferred_help=True, ) self.todoapp = None def initialize_app(self, argv): self.todoapp = TodoApp.fromenv() def clean_up(self, cmd, result, err): self.todoapp.save() def main(args=sys.argv[1:]) -> int: app = App() return app.run(argv=args) 


рдХрд╛рдо рдХреЗ рдЙрджрд╛рд╣рд░рдг

 igor$ ./todo_cliff.py add "sell the old laptop" Using database file /home/igor/.local/share/todoapp/db.json Task 'sell the old laptop' created with number 0. Saving database to a file /home/igor/.local/share/todoapp/db.json 

рдмреЙрдХреНрд╕ рд╕реЗ рд▓реЙрдЧ рдЖрдЙрдЯ! рдФрд░ рдпрджрд┐ рдЖрдк рд╣реБрдб рдХреЗ рдиреАрдЪреЗ рджреЗрдЦрддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдПрдХ рдЪрддреБрд░ рддрд░реАрдХреЗ рд╕реЗ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛: stdout рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА, рдФрд░ stderr рдореЗрдВ рдЪреЗрддрд╛рд╡рдиреА / рддреНрд░реБрдЯрд┐, рдФрд░, рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, - thequiet рдзреНрд╡рдЬ рджреНрд╡рд╛рд░рд╛ рдЕрдХреНрд╖рдо рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

 igor$ ./todo_cliff.py -q show +--------+----------------------+--------+ | Number | Title | Status | +--------+----------------------+--------+ | 1 | sell the old laptop | тЬШ | +--------+----------------------+--------+ 

рдЬреИрд╕рд╛ рдХрд┐ рдкрд╣рд▓реЗ рд╣реА рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд▓рд┐рд╕реНрдЯрд░ рдбреЗрдЯрд╛ рдХреЛ рдкреНрд░рд╛рд░реВрдкрд┐рдд рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рддрд╛рд▓рд┐рдХрд╛ рдЗрд╕рдХреЗ рд▓рд┐рдП рд╕реАрдорд┐рдд рдирд╣реАрдВ рд╣реИ:

 igor$ ./todo_cliff.py -q show -f json --noindent [{"Number": 0, "Title": "sell old laptop", "Status": "\u2718"}] 

Json рдФрд░ table рдХреЗ рдЕрд▓рд╛рд╡рд╛, yaml рдФрд░ csv рдЙрдкрд▓рдмреНрдз рд╣реИрдВред

рдПрдХ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдЫрд┐рдкрд╛ рд╣реБрдЖ рдЯреНрд░реЗрд╕ рднреА рд╣реИ:

 igor$ ./todo_cliff.py -q remove 3 No such task. 

рдПрдХ рдФрд░ рдЙрдкрд▓рдмреНрдз REPL рдФрд░ рдлрдЬреА рдЦреЛрдЬ рдЙрд░реНрдл рдлрдЬреА рдЦреЛрдЬ :

 igor$ ./todo_cliff.py -q (todo_cliff) help Shell commands (type help %topic%): =================================== alias exit history py quit shell unalias edit help load pyscript set shortcuts Application commands (type help %topic%): ========================================= add complete done help remove show (todo_cliff) whow todo_cliff: 'whow' is not a todo_cliff command. See 'todo_cliff --help'. Did you mean one of these? show 

рдкрд░реАрдХреНрд╖рдг

рдпрд╣ рд╕рд░рд▓ рд╣реИ: рдПрдХ рдРрдк рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рд░рди () рднреА рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рдПрдХ рдирд┐рдХрд╛рд╕ рдХреЛрдб рджреЗрддрд╛ рд╣реИред

 def test_cliff(capsys): app = todo_cliff.App() code = app.run(["add", "test"]) assert code == 0 out, _ = capsys.readouterr() assert out == EXPECTED 

рдкреЗрд╢реЗрд╡рд░реЛрдВ рдФрд░ рд╡рд┐рдкрдХреНрд╖

рдкреЗрд╢реЗрд╡рд░реЛрдВ:

  • рдмреЙрдХреНрд╕ рд╕реЗ рдмрд╛рд╣рд░ рд╡рд┐рднрд┐рдиреНрди рд╕реБрд╡рд┐рдзрд╛рдПрдВ;
  • рдУрдкрдирд╕реНрдЯреИрдХ рджреНрд╡рд╛рд░рд╛ рд╡рд┐рдХрд╕рд┐рдд;
  • рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдореЛрдб;
  • рд╕реЗрдкреНрдЯреБрдкреВрд▓рд╕ рдПрдВрдЯреНрд░реА рдкреЙрдЗрдВрдЯ рдФрд░ рдХрдорд╛рдВрдбрд╣реВрдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╡рд┐рд╕реНрддрд╛рд░;
  • рд╕реАрдПрд▓рдЖрдИ рдХреЗ рд▓рд┐рдП рдСрдЯреЛ рдкреНрд░рд▓реЗрдЦрди рдХреЗ рд▓рд┐рдП рд╕реНрдлрд┐рдВрдХреНрд╕ рдкреНрд▓рдЧрдЗрди;
  • рдХрдорд╛рдВрдб рдкреВрд░рд╛ рд╣реЛрдиреЗ (рдХреЗрд╡рд▓ рдмреИрд╢);

рд╡рд┐рдкрдХреНрд╖:

  • рдПрдХ рдЫреЛрдЯрд╛ рджрд╕реНрддрд╛рд╡реЗрдЬ, рдЬрд┐рд╕рдореЗрдВ рдореВрд▓ рд░реВрдк рд╕реЗ рдПрдХ рд╡рд┐рд╕реНрддреГрдд рд▓реЗрдХрд┐рди рдПрдХрд▓ рдЙрджрд╛рд╣рд░рдг рд╢рд╛рдорд┐рд▓ рд╣реИ;

рдПрдХ рдФрд░ рдмрдЧ рджреЗрдЦрд╛ рдЧрдпрд╛ рдерд╛: рд╕реНрдЯреИрдХ рдЯреНрд░реЗрд╕ рдХреЛ рдЫреБрдкрд╛рддреЗ рд╕рдордп рддреНрд░реБрдЯрд┐ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдирд┐рдХрд╛рд╕ рдХреЛрдб рд╣рдореЗрд╢рд╛ рд╢реВрдиреНрдп рд╣реЛрддрд╛ рд╣реИред

рдкреНрд▓реЗрд╕рдореЗрдВрдЯ


GitHub
рдкреНрд░рд▓реЗрдЦрди

рдкрд╣рд▓реА рдирдЬрд╝рд░ рдореЗрдВ, рдкреНрд▓рд╛рдХ рдХреБрдЫ-рдХреБрдЫ рдлрд╛рдпрд░ рдЬреИрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ рдлрд╛рдпрд░ рдХреА рддрд░рд╣ рд╣реИ, рдЬреЛ рдПрдХ рд╣реА рдЖрд░реНрдЧрдкрд░реНрд╕ рдХреЛ рдЫреБрдкрд╛рддрд╛ рд╣реИ рдФрд░ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╣реБрдб рдХреЗ рдиреАрдЪреЗред

рдкреАрдПрд╕реА рдиреЗ рдкреНрд░рд▓реЗрдЦрди рдХрд╛ рд╣рд╡рд╛рд▓рд╛ рджреЗрддреЗ рд╣реБрдП рдХрд╣рд╛, "рдХрдВрдкреНрдпреВрдЯрд░ рдХреА рджреБрдирд┐рдпрд╛ рдХрд╛ рдкреНрд░рд╛рдЪреАрди рд╕рд┐рджреНрдзрд╛рдВрдд: рдХрд╛рд░реНрдпрдХреНрд░рдореЛрдВ рдХреЛ рдХреЗрд╡рд▓ рд╕рд╛рдорд╛рдиреНрдп рдорд╛рдорд▓реЛрдВ рдХреЛ рд╣рд▓ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рд╕рд░рд▓ рдХреЛ рд╕рд░рд▓ рд░рд╣рдирд╛ рдЪрд╛рд╣рд┐рдП, рдФрд░ рдЬрдЯрд┐рд▓ рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП ред" рд░реВрдкрд░реЗрдЦрд╛ рдХрд╛ рд▓реЗрдЦрдХ рдиреМ рд╡рд░реНрд╖реЛрдВ рд╕реЗ рдЕрдзрд┐рдХ рд╕рдордп рд╕реЗ рдкрд╛рдпрдерди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ "99.9% рдХрд╛рд░реНрдпреЛрдВ" рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдХреЗ рд╕рд╛рде рд▓рд┐рдЦрд╛ рд╣реИред

рдХрдорд╛рдВрдб рдФрд░ рдореБрдЦреНрдп

рд╢реЛ рдФрд░ рдХрд┐рдП рдЧрдП рддрд░реАрдХреЛрдВ рдореЗрдВ рдПрдиреЛрдЯреЗрд╢рди рдкрд░ рдзреНрдпрд╛рди рджреЗрдВ: рдпрд╣ рд╣реИ рдХрд┐ рдкреНрд▓рд╛рдХ рдХреНрд░рдорд╢рдГ рдкреИрд░рд╛рдореАрдЯрд░ рдФрд░ рддрд░реНрдХ рд╕рд╣рд╛рдпрддрд╛ рдХреИрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИред

рд╕реНрд░реЛрдд рдХреЛрдб
 import plac import todolib class TodoInterface: commands = "add", "show", "done", "remove" def __init__(self): self.app = todolib.TodoApp.fromenv() def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.app.save() def add(self, task): """ Add new task. """ task = self.app.add_task(title=task) print(task, "created with number", task.number, end=".\n") def show(self, show_done: plac.Annotation("Include done tasks", kind="flag")): """ Show current tasks. """ self.app.print_tasks(show_done=show_done) def done(self, number: "Task number"): """ Mark task as done. """ task = self.app.task_done(number=int(number)) print(task, "marked as done.") def remove(self, number: "Task number"): """ Remove task from the list. """ task = self.app.remove_task(number=int(number)) print(task, "removed from the list.") if __name__ == "__main__": plac.Interpreter.call(TodoInterface) 


рдкрд░реАрдХреНрд╖рдг

рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдкрд░реАрдХреНрд╖рдг рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХрд╛ рдХреЛрдб рдкреНрд▓реЗрд╕ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдЦреБрдж рдХрд╛ рдкрд░реАрдХреНрд╖рдг рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╣реИ:

 def test_plac(capsys): plac.Interpreter.call(todo_plac.TodoInterface, arglist=["add", "test"]) out, _ = capsys.readouterr() assert out == EXPECTED 

рдкреЗрд╢реЗрд╡рд░реЛрдВ рдФрд░ рд╡рд┐рдкрдХреНрд╖

рдкреЗрд╢реЗрд╡рд░реЛрдВ:

  • рд╕рд░рд▓ рдЙрдкрдпреЛрдЧ;
  • рд░реАрдбрд▓рд╛рдЗрди рд╕рдорд░реНрдерди рдХреЗ рд╕рд╛рде рдЗрдВрдЯрд░рдПрдХреНрдЯрд┐рд╡ рдореЛрдб;
  • рд╕реНрдерд┐рд░ рдПрдкреАрдЖрдИ
  • рдЙрддреНрдХреГрд╖реНрдЯ рдкреНрд░рд▓реЗрдЦрди;

рд▓реЗрдХрд┐рди рдкреАрдПрд╕реА рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рдмрд╛рдд рдЙрдиреНрдирдд рдЙрдкрдпреЛрдЧ рдореЗрдВ рдЫрд┐рдкреА рд╣реБрдИ рд╣реИ:

  • рдзрд╛рдЧреЗ рдФрд░ рдЙрдкрдкреНрд░рдХрд╛рд░реЛрдВ рдореЗрдВ рдХрдИ рдЖрджреЗрд╢реЛрдВ рдХрд╛ рдирд┐рд╖реНрдкрд╛рджрди;
  • рд╕рдорд╛рдирд╛рдВрддрд░ рдХрдВрдкреНрдпреВрдЯрд┐рдВрдЧ;
  • рдЯреЗрд▓рдиреЗрдЯ рд╕рд░реНрд╡рд░;

рд╡рд┐рдкрдХреНрд╖:

  • рдЖрдк рдирд┐рдХрд╛рд╕ рдХреЛрдб рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ;
  • рдЧрд░реАрдм рдкрд░рд┐рдпреЛрдЬрдирд╛ рдЬреАрд╡рдиред

рд╕реАрд╕рд╛


GitHub
рдкреНрд░рд▓реЗрдЦрди
рд╕реАрдПрд▓рдЖрдИ рдкреНрд░рд▓реЗрдЦрди
рдкреНрд▓рдВрдмрдо, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдРрд╕рд╛ рдХреЛрдИ рдЬреНрдЮрд╛рдд рдврд╛рдВрдЪрд╛ рдирд╣реАрдВ рд╣реИ - рд▓рдЧрднрдЧ 2000 рд╕рд┐рддрд╛рд░реЗ, рдФрд░ рдЗрд╕рдХреЗ рд▓рд┐рдП рдкреНрдпрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдореЛрдЯреЗ рддреМрд░ рдкрд░, рдпрд╣ рдпреВрдирд┐рдХреНрд╕ рд╢реИрд▓ рд╡рд╛рдХреНрдпрд╡рд┐рдиреНрдпрд╛рд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИред рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ, additives рдХреЗ рд╕рд╛рде:

 >>> from plumbum import local >>> output = local["ls"]() >>> output.split("\n")[:3] ['console_examples.egg-info', '__pycache__', 'readme.md'] #  plumbum     cmd,      >>> from plumbum.cmd import rm, ls, grep, wc >>> rm["-r", "console_examples.egg-info"]() '' >>> chain = ls["-a"] | grep["-v", "\\.py"] | wc["-l"] >>> chain() '11\n' 

рдХрдорд╛рдВрдб рдФрд░ рдореБрдЦреНрдп

рдкреНрд▓рдВрдмрдо рдореЗрдВ рд╕реАрдПрд▓рдЖрдИ рдХреЗ рд▓рд┐рдП рдЙрдкрдХрд░рдг рднреА рд╣реИрдВ, рдФрд░ рдпрд╣ рдХрд╣рдиреЗ рдХреЗ рд▓рд┐рдП рдирд╣реАрдВ рдХрд┐ рд╡реЗ рдХреЗрд╡рд▓ рдПрдХ рдЬреЛрдбрд╝ рд╣реИрдВ: рдЗрд╕рдореЗрдВ рдирд░реНрдЧ, рдХрдорд╛рдВрдб рдФрд░ рд░рдВрдЧ рд╣реИрдВ:

рд╕реНрд░реЛрдд рдХреЛрдб
 from plumbum import cli, colors class App(cli.Application): """Todo notes on plumbum.""" VERSION = todolib.__version__ verbosity = cli.CountOf("-v", help="Increase verbosity") def main(self, *args): if args: print(colors.red | f"Unknown command: {args[0]!r}.") return 1 if not self.nested_command: # will be ``None`` if no sub-command follows print(colors.red | "No command given.") return 1 class Command(cli.Application): """Command with todoapp object""" def __init__(self, executable): super().__init__(executable) self.todoapp = todolib.TodoApp.fromenv() atexit.register(self.todoapp.save) def log_task(self, task, msg): print("Task", colors.green | task.title, msg, end=".\n") @App.subcommand("add") class Add(Command): """Add new task""" def main(self, task): task = self.todoapp.add_task(title=task) self.log_task(task, "added to the list") @App.subcommand("show") class Show(Command): """Show current tasks""" show_done = cli.Flag("--show-done", help="Include done tasks") def main(self): self.todoapp.print_tasks(self.show_done) @App.subcommand("done") class Done(Command): """Mark task as done""" def main(self, number: int): task = self.todoapp.task_done(number) self.log_task(task, "marked as done") @App.subcommand("remove") class Remove(Command): """Remove task from the list""" def main(self, number: int): task = self.todoapp.remove_task(number) self.log_task(task, "removed from the list.") if __name__ == '__main__': App.run() 


рдкрд░реАрдХреНрд╖рдг

рдкреНрд▓рдВрдмрдо рдкрд░ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рджреВрд╕рд░реЛрдВ рд╕реЗ рднрд┐рдиреНрди рд╣реЛрддрд╛ рд╣реИ, рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рдЖрд╡реЗрджрди рдХрд╛ рдирд╛рдо рднреА рдкрд╛рд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЕрд░реНрдерд╛рддреНред рдкрд╣рд▓рд╛ рддрд░реНрдХ:

 def test_plumbum(capsys): _, code = todo_plumbum.App.run(["todo_plumbum", "add", "test"], exit=False) assert code == 0 out, _ = capsys.readouterr() assert out == "Task test created with number 0.\n" 

рдкреЗрд╢реЗрд╡рд░реЛрдВ рдФрд░ рд╡рд┐рдкрдХреНрд╖

рдкреЗрд╢реЗрд╡рд░реЛрдВ:

  • рдмрд╛рд╣рд░реА рдЯреАрдореЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрддреНрдХреГрд╖реНрдЯ рдЯреВрд▓рдХрд┐рдЯ;
  • рд╢реИрд▓рд┐рдпреЛрдВ рдФрд░ рд░рдВрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди;
  • рд╕реНрдерд┐рд░ рдПрдкреАрдЖрдИ
  • рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрд╛ рд╕рдХреНрд░рд┐рдп рдЬреАрд╡рди;

рдХреЛрдИ рдЦрд╛рдореА рдирдЬрд░ рдирд╣реАрдВ рдЖрдИред

CMD2


GitHub
рдкреНрд░рд▓реЗрдЦрди

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, cmd2 рдорд╛рдирдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╕реЗ cmd рдкрд░ рдПрдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╣реИ,
рдпрд╛рдиреА рдпрд╣ рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдХрд░рдирд╛ рд╣реИред рдлрд┐рд░ рднреА, рдпрд╣ рд╕рдореАрдХреНрд╖рд╛ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕реЗ рд╕рд╛рдорд╛рдиреНрдп рд╕реАрдПрд▓рдЖрдИ рдореЛрдб рдХреЗ рд▓рд┐рдП рднреА рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдХрдорд╛рдВрдб рдФрд░ рдореБрдЦреНрдп

cmd2 рдХреЛ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдирд┐рдпрдо рдХреЗ рдЕрдиреБрдкрд╛рд▓рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ: рдХрдорд╛рдВрдб do_ рдЙрдкрд╕рд░реНрдЧ рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП, рд▓реЗрдХрд┐рди рдЕрдиреНрдпрдерд╛ рд╕рдм рдХреБрдЫ рд╕реНрдкрд╖реНрдЯ рд╣реИ:

рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдореЛрдб
 import cmd2 import todolib class App(cmd2.Cmd): def __init__(self, **kwargs): super().__init__(**kwargs) self.todoapp = todolib.TodoApp.fromenv() def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.todoapp.save() def do_add(self, title): """Add new task.""" task = self.todoapp.add_task(str(title)) self.poutput(f"{task} created with number {task.number}.") def do_show(self, show_done): """Show current tasks.""" self.todoapp.print_tasks(bool(show_done)) def do_done(self, number): """Mark task as done.""" task = self.todoapp.task_done(int(number)) self.poutput(f"{task} marked as done.") def do_remove(self, number): """Remove task from the list.""" task = self.todoapp.remove_task(int(number)) self.poutput(f"{task} removed from the list.") def main(**kwargs): with App(**kwargs) as app: app.cmdloop() if __name__ == '__main__': main() 


рдЧреИрд░-рд╕рдВрд╡рд╛рджрд╛рддреНрдордХ рдореЛрдб
рд╕рд╛рдорд╛рдиреНрдп рдореЛрдб рдореЗрдВ рдереЛрдбрд╝рд╛ рдЕрддрд┐рд░рд┐рдХреНрдд рдЖрдВрджреЛрд▓рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЙрд╕ рд╕рдордп рдХреЗ рд▓рд┐рдП рд╡рд╛рдкрд╕ рдЬрд╛рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдЙрд╕ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП рддрд░реНрдХ рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ рдЬрдм рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рдмрд┐рдирд╛ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдФрд░ рдЕрдм рдХрдорд╛рдВрдбреНрд╕ рдХреЛ argparse.Namespace рдорд┐рд▓рддрд╛ рд╣реИред

рдкрд╛рд░реНрд╕рд░ рдХреЛ рдЫреЛрдЯреЗ рдкрд░рд┐рд╡рд░реНрдзрди рдХреЗ рд╕рд╛рде рдЕрд░реНрдЧрдкрд░реНрд╕ рдЙрджрд╛рд╣рд░рдг рд╕реЗ рд▓рд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ - рдЕрдм рдЙрдк-рдкрд╛рд░реНрд╕рд░ рдореБрдЦреНрдп рдЖрд░реНрдЧреНрдпреВрдореЗрдВрдЯрдкреЗрдпрд░ рдХреА рд╡рд┐рд╢реЗрд╖рддрд╛ рд╣реИред

 import cmd2 from todo_argparse import get_parser parser = get_parser(progname="todo_cmd2_cli") class App(cmd2.Cmd): def __init__(self, **kwargs): super().__init__(**kwargs) self.todoapp = todolib.TodoApp.fromenv() def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.todoapp.save() def do_add(self, args): """Add new task.""" task = self.todoapp.add_task(args.title) self.poutput(f"{task} created with number {task.number}.") def do_show(self, args): """Show current tasks.""" self.todoapp.print_tasks(args.show_done) def do_done(self, args): """Mark task as done.""" task = self.todoapp.task_done(args.number) self.poutput(f"{task} marked as done.") def do_remove(self, args): """Remove task from the list.""" task = self.todoapp.remove_task(args.number) self.poutput(f"{task} removed from the list.") parser.add.set_defaults(func=do_add) parser.show.set_defaults(func=do_show) parser.done.set_defaults(func=do_done) parser.remove.set_defaults(func=do_remove) @cmd2.with_argparser(parser) def do_base(self, args): func = getattr(args, "func", None) if func: func(self, args) else: print("No command provided.") print("Call with --help to get available commands.") def main(argv=None): with App() as app: app.do_base(argv or sys.argv[1:]) if __name__ == '__main__': main() 


рдкрд░реАрдХреНрд╖рдг

рдХреЗрд╡рд▓ рдПрдХ рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рдЪреВрдВрдХрд┐ рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдорд╛рдирд╡ рдФрд░ рд╕рдордп рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЗрд╕рд▓рд┐рдП cmd2 рдбреЗрд╡рд▓рдкрд░реНрд╕ рдиреЗ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА - рдЗрдирдкреБрдЯ рдФрд░ рдЕрдкреЗрдХреНрд╖рд┐рдд рдЖрдЙрдЯрдкреБрдЯ рдХреЗ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЗ рд╕рд╛рде рдкрд╛рда рдлрд╛рдЗрд▓реЗрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:

 (Cmd) add test Task 'test' created with number 0. 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╡рд╣ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдЬреЛ рдлрд╛рдЗрд▓реЛрдВ рдХреА рд╕реВрдЪреА рдХреЛ рдРрдк рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ рд╣реИ:

 def test_cmd2(): todo_cmd2.main(transcript_files=["tests/transcript.txt"]) 

рдкреЗрд╢реЗрд╡рд░реЛрдВ рдФрд░ рд╡рд┐рдкрдХреНрд╖

рдкреЗрд╢реЗрд╡рд░реЛрдВ:

  • рд╕рдВрд╡рд╛рджрд╛рддреНрдордХ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдЪреНрдЫрд╛ рдПрдкреАрдЖрдИ;
  • рд╣рд╛рд▓ рдХреЗ рд╡рд░реНрд╖реЛрдВ рдореЗрдВ рд╕рдХреНрд░рд┐рдп рд░реВрдк рд╕реЗ рд╡рд┐рдХрд╕рд┐рдд;
  • рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдореВрд▓ рджреГрд╖реНрдЯрд┐рдХреЛрдг;
  • рдЕрдЪреНрдЫрд╛ рдкреНрд░рд▓реЗрдЦрдиред

рд╡рд┐рдкрдХреНрд╖:

  • рдЧреИрд░-рд╕рдВрд╡рд╛рджрд╛рддреНрдордХ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд▓рд┐рдЦрддреЗ рд╕рдордп рдЖрд░реНрдЧреНрдкреНрд░реЗрд╕ рдФрд░ рдЕрддрд┐рд░рд┐рдХреНрдд рдХреЛрдб рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ;
  • рдЕрд╕реНрдерд┐рд░ рдПрдкреАрдЖрдИ;
  • рдХреБрдЫ рдЬрдЧрд╣реЛрдВ рдкрд░ рдкреНрд░рд▓реЗрдЦрди рдЦрд╛рд▓реА рд╣реИред

рдмреЛрдирд╕: рдЙрд░реНрд╡реА


GitHub
рдкреНрд░рд▓реЗрдЦрди
рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓
рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЗ рдЙрджрд╛рд╣рд░рдг

рдЙрд░реНрд╡рд┐рдб рдПрдХ рдЕрд▓рдЧ рджреБрдирд┐рдпрд╛ рд╕реЗ рдПрдХ рдврд╛рдБрдЪрд╛ рд╣реИ - рд╢рд╛рдк рдФрд░ npyscreen рд╕реЗ, рдпрд╛рдиреА рдХрдВрд╕реЛрд▓ / рдЯрд░реНрдорд┐рдирд▓ UI рд╕реЗред рдлрд┐рд░ рднреА, рдпрд╣ рдПрдХ рдмреЛрдирд╕ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдореАрдХреНрд╖рд╛ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реИ, рдЪреВрдВрдХрд┐, рдореЗрд░реА рд░рд╛рдп рдореЗрдВ, рдпрд╣ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИред

рдРрдк рдФрд░ рдЯреАрдореЗрдВ

рдЙрд░рд╡рд┐рдж рдХреЗ рдкрд╛рд╕ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рд╡рд┐рдЬреЗрдЯ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЗрд╕рдореЗрдВ рдкрдбрд╝реЛрд╕реА рд╡рд┐рдЬреЗрдЯреНрд╕ рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рдВрдбреЛ рдпрд╛ рд╕рд░рд▓ рдЯреВрд▓ рдЬреИрд╕реА рдЕрд╡рдзрд╛рд░рдгрд╛рдПрдВ рдирд╣реАрдВ рд╣реИрдВред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдпрджрд┐ рдЖрдк рдПрдХ рд╕реБрдВрджрд░ рдкрд░рд┐рдгрд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рд╡рд┐рдЪрд╛рд░рд╢реАрд▓ рдбрд┐рдЬрд╛рдЗрди рдФрд░ / рдпрд╛ рдЕрдиреНрдп рдкреИрдХреЗрдЬ рдХреЗ рдЙрдкрдпреЛрдЧ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рдЕрдиреНрдпрдерд╛ рдЖрдкрдХреЛ рдмрдЯрди рдХреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдореЗрдВ рдбреЗрдЯрд╛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдЬреИрд╕рд╛ рдХрд┐ рдпрд╣рд╛рдВ рд╣реИ:

рд╕реНрд░реЛрдд рдХреЛрдб
 import urwid from urwid import Button import todolib class App(urwid.WidgetPlaceholder): max_box_levels = 4 def __init__(self): super().__init__(urwid.SolidFill()) self.todoapp = None self.box_level = 0 def __enter__(self): self.todoapp = todolib.TodoApp.fromenv() self.new_menu( "Todo notes on urwid", #       ,  #      Button("New task", on_press=add), Button("List tasks", on_press=list_tasks), ) return self def __exit__(self, exc_type, exc_val, exc_tb): self.todoapp.save() def new_menu(self, title, *items): self.new_box(menu(title, *items)) def new_box(self, widget): self.box_level += 1 # overlay      , #     LineBox    self.original_widget = urwid.Overlay( # LineBox  unicode-    self.original_widget, align="center", width=30, valign="middle", height=10, ) def popup(self, text): self.new_menu(text, Button("To menu", on_press=lambda _: self.pop(levels=2))) def keypress(self, size, key): if key != "esc": super().keypress(size, key=key) elif self.box_level > 0: self.pop() def pop(self, levels=1): for _ in range(levels): self.original_widget = self.original_widget[0] self.box_level -= levels if self.box_level == 0: raise urwid.ExitMainLoop() 


рдЖрджреЗрд╢реЛрдВ
 app = App() def menu(title, *items) -> urwid.ListBox: body = [urwid.Text(title), urwid.Divider()] body.extend(items) return urwid.ListBox(urwid.SimpleFocusListWalker(body)) def add(button): edit = urwid.Edit("Title: ") def handle(button): text = edit.edit_text app.todoapp.add_task(text) app.popup("Task added") app.new_menu("New task", edit, Button("Add", on_press=handle)) def list_tasks(button): tasks = app.todoapp.list_tasks(show_done=True) buttons = [] for task in tasks: status = "done" if task.done else "not done" text = f"{task.title} [{status}]" #         button = Button(text, on_press=task_actions, user_data=task.number) buttons.append(button) app.new_menu("Task list", *buttons) def task_actions(button, number): def done(button, number): app.todoapp.task_done(number) app.popup("Task marked as done.") def remove(button, number): app.todoapp.remove_task(number) app.popup("Task removed from the list.") btn_done = Button("Mark as done", on_press=done, user_data=number) btn_remove = Button("Remove from the list", on_press=remove, user_data=number) app.new_menu("Actions", btn_done, btn_remove) 


рдореБрдЦреНрдп
 if __name__ == "__main__": try: with app: urwid.MainLoop(app).run() except KeyboardInterrupt: pass 

рдкреЗрд╢реЗрд╡рд░реЛрдВ рдФрд░ рд╡рд┐рдкрдХреНрд╖

рдкреЗрд╢реЗрд╡рд░реЛрдВ:

  • рд╡рд┐рднрд┐рдиреНрди рдЯреАрдпреВрдЖрдИ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдорд╣рд╛рди рдПрдкреАрдЖрдИ;
  • рд▓рдВрдмреЗ рд╡рд┐рдХрд╛рд╕ рдХрд╛ рдЗрддрд┐рд╣рд╛рд╕ (2010 рд╕реЗ) рдФрд░ рд╕реНрдерд┐рд░ рдПрдкреАрдЖрдИ;
  • рд╕рдХреНрд╖рдо рд╡рд╛рд╕реНрддреБрдХрд▓рд╛;
  • рдЕрдЪреНрдЫрд╛ рдкреНрд░рд▓реЗрдЦрди, рдЙрджрд╛рд╣рд░рдг рд╣реИрдВред

рд╡рд┐рдкрдХреНрд╖:

  • рдкрд░реАрдХреНрд╖рдг рдХреИрд╕реЗ рдХрд░реЗрдВ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИред рдХреЗрд╡рд▓ tmux send-keys рдХрд╛ рдЦреНрдпрд╛рд▓ рдЖрддрд╛ рд╣реИ;
  • рдЬрдм рд╡рд┐рдЧреЗрдЯреНрд╕ рдареАрдХ рд╕реЗ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдирд╣реАрдВ рд╣реЛрддреЗ рд╣реИрдВ рддреЛ Uninformative рддреНрд░реБрдЯрд┐рдпрд╛рдБред

* * *


рдХреНрд▓рд┐рдл рдмрд╣реБрдд рдХреБрдЫ рдХреНрд▓рд┐рдпреЛ рдФрд░ рд╕реАрдореЗрдВрдЯ рдХреА рддрд░рд╣ рд╣реИ рдФрд░ рдЖрдорддреМрд░ рдкрд░ рдмрдбрд╝реА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЕрдЪреНрдЫрд╛ рд╣реИред

рдореИрдВ рд╡реНрдпрдХреНрддрд┐рдЧрдд рд░реВрдк рд╕реЗ рдкреНрд▓реЗрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рд╣рд┐рдореНрдордд рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛, рд▓реЗрдХрд┐рди рдореИрдВ рд╕реНрд░реЛрдд рдХреЛрдб рдХреЛ рдкрдврд╝рдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВред

рдкреНрд▓рдВрдмрдо рдореЗрдВ рдЕрдиреНрдп рдХрдорд╛рдВрдбреНрд╕ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЖрд╕рд╛рди рд╕реАрдПрд▓рдЖрдИ рдЯреВрд▓рдХрд┐рдЯ рдФрд░ рдПрдХ рд╢рд╛рдирджрд╛рд░ рдПрдкреАрдЖрдИ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рдЖрдк рдкрд╛рдпрдерди рдореЗрдВ рд╢реЗрд▓ рд╕реНрдХреНрд░рд┐рдкреНрдЯреНрд╕ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рдпрд╣ рд╡рд╣реА рд╣реИ рдЬреЛ рдЖрдкрдХреЛ рдЪрд╛рд╣рд┐рдПред
cmd2 рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдФрд░ рдорд╛рдирдХ cmd рд╕реЗ рдорд╛рдЗрдЧреНрд░реЗрдЯ рдХрд░рдиреЗ рдХреЗ рдЗрдЪреНрдЫреБрдХ рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдЖрдзрд╛рд░ рдХреЗ рд░реВрдк рдореЗрдВ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдЕрдиреБрдХреВрд▓ рд╣реИред

рдФрд░ рдЙрд░реНрд╡реАрдб рдореЗрдВ рд╕реБрдВрджрд░ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдЕрдиреБрдХреВрд▓ рдХрдВрд╕реЛрд▓ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╣реИрдВред

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рдВрдХреБрд▓ рд╕рдореАрдХреНрд╖рд╛ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рдереЗ:

  • aioconsole - рдХреЛрдИ рдЧреИрд░-рдЗрдВрдЯрд░реИрдХреНрдЯрд┐рд╡ рдореЛрдб рдирд╣реАрдВ;
  • pyCLI - рдЙрдк-рдХреНрд╖реЗрддреНрд░ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рд╕рдорд░реНрдерди рдирд╣реАрдВ;
  • рдХреНрд▓рд┐рдВрдЯ - рд╕рдВрдЧреНрд░рд╣ рдореЗрдВ рдЙрдк-рдХреНрд╖реЗрддреНрд░, рднрдВрдбрд╛рд░ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рд╕рдорд░реНрдерди рдирд╣реАрдВ;
  • рдХрдорд╛рдВрдбрд▓рд╛рдЗрди - рдпрд╣ рдмрд╣реБрдд рдкреБрд░рд╛рдиреА рд╣реИ (2009 рдореЗрдВ рдЕрдВрддрд┐рдо рд░рд┐рд▓реАрдЬрд╝) рдФрд░ рдирд┐рд░реНрдмрд╛рдз;
  • CLIArgs - рдкреБрд░рд╛рдирд╛ (2010 рдореЗрдВ рдЕрдВрддрд┐рдо рд░рд┐рд▓реАрдЬрд╝)
  • opterator - рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рдкреБрд░рд╛рдирд╛ (2015 рдореЗрдВ рдЕрдВрддрд┐рдо рд░рд┐рд▓реАрдЬрд╝)

Source: https://habr.com/ru/post/hi469093/


All Articles