Uninstalling menus

Installing discord.ext.menus
Updating Requirements
pull/2/head
sgoudham 4 years ago
parent 42348e0ae2
commit 9439532533

@ -1,8 +1,7 @@
import datetime
import discord
from discord import Embed, Colour
from discord.ext import commands
from discord.ext import commands, menus
from discord.ext.commands import command
@ -175,7 +174,7 @@ def embeds(self):
print(ex)
class HelpMenu(discord.ext.menus.Menu):
class HelpMenu(menus.Menu):
def __init__(self, i, bot):
super().__init__()
self.i = i
@ -185,7 +184,7 @@ class HelpMenu(discord.ext.menus.Menu):
initial = embeds(self)[self.i]
return await channel.send(embed=initial)
@discord.ext.menus.button('\N{LEFTWARDS BLACK ARROW}')
@menus.button('\N{LEFTWARDS BLACK ARROW}')
async def on_left_arrow(self, payload):
def check(m):
return m.author == payload.member
@ -199,7 +198,7 @@ class HelpMenu(discord.ext.menus.Menu):
else:
return
@discord.ext.menus.button('\N{BLACK RIGHTWARDS ARROW}')
@menus.button('\N{BLACK RIGHTWARDS ARROW}')
async def on_right_arrow(self, payload):
def check(m):
return m.author == payload.member
@ -213,7 +212,7 @@ class HelpMenu(discord.ext.menus.Menu):
else:
return
@discord.ext.menus.button('\N{BLACK SQUARE FOR STOP}\ufe0f')
@menus.button('\N{BLACK SQUARE FOR STOP}\ufe0f')
async def on_stop(self, payload):
stop = stop_embed(self)
await self.message.edit(embed=stop)

@ -11,4 +11,4 @@ discord.py
owotext
aiohttp
discord
menus
discord-ext-menus

@ -1,15 +0,0 @@
Metadata-Version: 2.0
Name: Menus
Version: 0.2.0
Summary: Create cli menus with ease
Home-page: https://github.com/JMSwag/Menus
Author: Digital Sapphire
Author-email: menus@digitalsapphire.io
License: MIT
Platform: UNKNOWN
Requires-Dist: dsdev-utils
Requires-Dist: six
UNKNOWN

@ -1,24 +0,0 @@
Menus-0.2.0.dist-info/DESCRIPTION.rst,sha256=OCTuuN6LcWulhHS3d5rfjdsQtW22n7HENFRh6jC6ego,10
Menus-0.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
Menus-0.2.0.dist-info/METADATA,sha256=5E660I04WM6yX5M3KfFsqJZNz5l4kckz3MFAou_1Iu0,280
Menus-0.2.0.dist-info/RECORD,,
Menus-0.2.0.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110
Menus-0.2.0.dist-info/metadata.json,sha256=k5fJgBoAIoSIFjuR1yUm6YALlY9n5FTybcF8RqhDLjQ,480
Menus-0.2.0.dist-info/top_level.txt,sha256=mr-Mm53IP5nmAdXmK0MURdgtX5aoNBmIrgHgyPdKUac,11
Menus-0.2.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
menus/__init__.py,sha256=Racmika2iOJjIGPzbSZs8hQARcJaif_N2rLyz0uUGJY,1419
menus/__pycache__/__init__.cpython-36.pyc,,
menus/__pycache__/_version.cpython-36.pyc,,
menus/__pycache__/engine.cpython-36.pyc,,
menus/__pycache__/example.cpython-36.pyc,,
menus/__pycache__/exceptions.cpython-36.pyc,,
menus/__pycache__/menu.cpython-36.pyc,,
menus/__pycache__/utils.cpython-36.pyc,,
menus/_version.py,sha256=Z0DxOc2U4ydSV42gG9XZ6DRszh-5f53SRi3SAzpPxKU,471
menus/engine.py,sha256=tG6395XNJ4LcKzE76hdcDGGrOFPRYrOXdV6pjIN9Rb0,3315
menus/example.py,sha256=tLYJJTtloPBfFc3kui6s-d_nPAXyEdGs8gqjssHOIpA,3292
menus/exceptions.py,sha256=Widb24ezSJNpMy8Dt8Wi_xQmXA561x3cI4hj27Br2_4,2400
menus/menu.py,sha256=kMzIcnwPsFHQLEN2NKQ0m4EUqTlzBKNlVnje7tJ6Cbs,6983
menus/utils.py,sha256=ReoV8xbA9SjX6psiSPevG-A7NVJWQLmz0rVw7MLuPIQ,3670
site/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
site/__pycache__/__init__.cpython-36.pyc,,

@ -1,6 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.29.0)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

@ -1 +0,0 @@
{"extensions": {"python.details": {"contacts": [{"email": "menus@digitalsapphire.io", "name": "Digital Sapphire", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/JMSwag/Menus"}}}, "extras": [], "generator": "bdist_wheel (0.29.0)", "license": "MIT", "metadata_version": "2.0", "name": "Menus", "run_requires": [{"requires": ["dsdev-utils", "six"]}], "summary": "Create cli menus with ease", "version": "0.2.0"}

@ -1,37 +0,0 @@
# The MIT License (MIT)
#
# Copyright (c) 2016 Digital Sapphire
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import logging
from menus.engine import Engine
from menus.exceptions import MenusError
from menus.menu import BaseMenu
__all__ = ['BaseMenu', 'Engine', 'MenusError']
log = logging.getLogger()
from ._version import get_versions # noqa
__version__ = get_versions()['version']
del get_versions

@ -1,21 +0,0 @@
# This file was generated by 'versioneer.py' (0.15) from
# revision-control system data, or from the parent directory name of an
# unpacked source archive. Distribution tarballs contain a pre-generated copy
# of this file.
import json
import sys
version_json = '''
{
"dirty": false,
"error": null,
"full-revisionid": "4dd50cb49a508b57d56a4d512ef40da67b01ab77",
"version": "0.2.0"
}
''' # END VERSION_JSON
def get_versions():
return json.loads(version_json)

@ -1,96 +0,0 @@
# --------------------------------------------------------------------------
# Copyright (c) 2016 Digital Sapphire
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the
# following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
# ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
# TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
# --------------------------------------------------------------------------
import logging
import sys
from menus.example import load_example_menus
from menus.exceptions import MenusError
from menus.menu import BaseMenu, MainMenu
from menus.utils import check_commands_else_raise
log = logging.getLogger(__name__)
# Ensure that a custom menus subclasses BaseMenu
def check_mro(c):
if issubclass(c.__class__, BaseMenu) is False:
raise MenusError('Not a sublcass of BaseMenu \n\nclass '
'{}'.format(c.__class__.__name__),
expected=True)
return True
class Engine(object):
def __init__(self, app_name=None, menus=None, example=False):
# Name used in every menu header
if app_name is None:
app_name = 'ACME'
# Create initial commands for main menu
sub_menus = []
# Adding submenus
if example is True:
sub_menus += load_example_menus()
else:
if menus is not None:
for m in menus:
check_mro(m)
sub_menus += menus
# Commands with app_name added to it
new_sub_menus = []
for sub in sub_menus:
# Adding the app name to the menu
sub.app_name = app_name
sub.commands.append(('Main Menu', getattr(sub, 'done')))
# Quick hack to add users class name as menu option
# only for main menu
new_sub_menu = (sub.menu_name, sub)
new_sub_menus.append(new_sub_menu)
new_sub_menus.append(('Quit', self.quit))
# Sanatisation checks on passed commands
check_commands_else_raise(new_sub_menus)
# Initilazie main menu with submenus
self.main = MainMenu(new_sub_menus)
# Adding the app name to the main menu
self.main.app_name = app_name
# Starts event loop
def start(self): # pragma: no cover
while 1:
start = self.main.display()
start()
def quit(self): # pragma: no cover
log.debug('Quitting')
sys.exit(0)

@ -1,98 +0,0 @@
# --------------------------------------------------------------------------
# Copyright (c) 2016 Digital Sapphire
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the
# following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
# ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
# TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
# --------------------------------------------------------------------------
import logging
from menus.menu import BaseMenu
log = logging.getLogger(__name__)
class Cool(BaseMenu):
def __init__(self):
# An option is a tuple which consists of ('Display Name', function)
commands = [('Speak', self.speak)]
super(Cool, self).__init__(commands=commands)
def speak(self):
# Used to nicely display a message towards
# the middle of the screen
self.display_msg('Cool is speaking')
# Will pause for 3 seconds
self.pause(seconds=3)
# Used to return to Cool Menu. If omitted
# the user will be returned to the Main Menu
self()
class Hot(BaseMenu):
def __init__(self):
# An option is a tuple which consists of ('Display Name', function)
commands = [('Speak', self.speak)]
super(Hot, self).__init__(commands=commands, menu_name='Really Hot')
def speak(self):
# Used to nicely display a message towards
# the middle of the screen
self.display_msg("It's getting hot in here!")
# Will pause for 3 seconds
self.pause(seconds=3)
# Used to return to Cool Menu. If omitted
# the user will be returned to the Main Menu
self()
class Keys(BaseMenu):
def __init__(self):
# An option is a tuple which consists of ('Display Name', function)
commands = [('Show Public Key', self.show_public_key)]
super(Keys, self).__init__(commands=commands)
def show_public_key(self):
log.debug('Show public key')
# Used to nicely display a message towards
# the middle of the screen
self.display_msg('thdkalfjl;da;ksfkda;fdkj')
# Will prompt user to press enter to continue
self.pause(enter_to_continue=True)
# Used to return to Cool Menu. If omitted
# the user will be returned to the Main Menu
self()
# List of menus to be used when user initializes Engine(example=True)
def load_example_menus():
return [Cool(), Hot(), Keys()]

@ -1,69 +0,0 @@
# --------------------------------------------------------------------------
# Copyright (c) 2016 Digital Sapphire
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the
# following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
# ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
# TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
# --------------------------------------------------------------------------
from __future__ import unicode_literals
import sys
import traceback
class STDError(Exception):
"""Extends exceptions to show added message if error isn't expected.
Args:
msg (str): error message
Kwargs:
tb (obj): is the original traceback so that it can be printed.
expected (bool):
Meaning:
True - Report issue msg not shown
False - Report issue msg shown
"""
def __init__(self, msg, tb=None, expected=False):
if not expected:
msg = msg + ('; please report this issue on https://git'
'hub.com/JMSwag/Menus')
msg = '\n\n' + msg
super(STDError, self).__init__(msg)
self.traceback = tb
self.exc_info = sys.exc_info() # preserve original exception
def format_traceback(self):
if self.traceback is None:
return None
return ''.join(traceback.format_tb(self.traceback))
class MenusError(STDError):
"""Raised for Archiver exceptions"""
def __init__(self, *args, **kwargs):
super(MenusError, self).__init__(*args, **kwargs)

@ -1,206 +0,0 @@
# --------------------------------------------------------------------------
# Copyright (c) 2016 Digital Sapphire
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the
# following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
# ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
# TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
# --------------------------------------------------------------------------
from __future__ import print_function
import logging
import os
import time
import warnings
from dsdev_utils.terminal import (ask_yes_no,
get_correct_answer,
get_terminal_size)
import six
from menus.exceptions import MenusError
from menus.utils import clear_screen_cmd, Getch
log = logging.getLogger(__name__)
class BaseMenu(object):
def __init__(self, **kwargs):
# Used to display the apps name on all menu headers
self.app_name = None
# The custom menu name
self.menu_name = kwargs.get('menu_name')
# If we do not have a custom menu
# name then use the class name
if self.menu_name is None:
self.menu_name = self.__class__.__name__
# A message to display when this menus loads
self.message = kwargs.get('message')
# User commands for this menu
self._commands = kwargs.get('commands', [])
# ToDo: Remove in v1.0
# User commands for this menu
options = kwargs.get('options', [])
if len(options) > 0:
if len(self._commands) > 0:
raise MenusError('Cannot mix old & new API. Use '
'commands kwarg only.')
warn_msg = ('BaseMenu(options=[]) is deprecated, '
'user BaseMenu(commands=[]')
warnings.warn(warn_msg)
self._commands += options
# End ToDo
@property
def commands(self):
return self._commands
def __call__(self):
x = self.display()
x()
def display(self):
self._display_menu_header()
self.display_msg(self.message)
return self._menu_options(self._commands)
def pause(self, seconds=5, enter_to_continue=False):
if not isinstance(enter_to_continue, bool):
raise MenusError('enter_to_continue must be boolean',
expected=True)
if not isinstance(seconds, six.integer_types):
raise MenusError('seconds must be integer', expected=True)
if enter_to_continue is True:
self.display_msg('Press enter to quit')
six.moves.input()
else:
time.sleep(seconds)
return True
# Prompt the user with a question & only accept
# yes or no answers
def ask_yes_no(self, question, default):
return ask_yes_no(question, default)
# Promot the user with a question & confirm it's correct.
# If required is True, user won't be able to enter a blank answer
def get_correct_answer(self, question, default, required=False):
return get_correct_answer(question, default, required)
# Display a message centered on the screen.
def display_msg(self, message=None):
self._display_msg(message)
def done(self):
pass
# ToDo: Remove in v1.0
def get_correct_action(self, question, default, required):
return get_correct_answer(question, default, required)
# End ToDo
# Takes a string and adds it to the menu header along side
# the app name.
def _display_menu_header(self):
window_size = get_terminal_size()[0]
# Adding some styling to the header
def add_style():
top = '*' * window_size + '\n'
bottom = '\n' + '*' * window_size + '\n'
header = self.app_name + ' - ' + self.menu_name
header = header.center(window_size)
msg = top + header + bottom
return msg
os.system(clear_screen_cmd)
print(add_style())
def _display_msg(self, message):
window_size = get_terminal_size()[0]
if message is None:
return ''
if not isinstance(message, six.string_types):
log.warning('Did not pass str')
return ''
# Home grown word wrap
def format_msg():
formatted = []
finished = ['\n']
count = 0
words = message.split(' ')
for w in words:
w = w + ' '
if count + len(w) > window_size / 2:
finished.append(''.join(formatted).center(window_size))
finished.append('\n')
count = len(w)
# Starting a new line.
formatted = []
formatted.append(w)
else:
formatted.append(w)
count += len(w)
finished.append(''.join(formatted).center(window_size))
finished.append('\n')
return ''.join(finished)
print(format_msg())
# Takes a list of tuples(menu_name, call_back) adds menu numbers
# then prints menu to screen.
# Gets input from user, then returns the callback
def _menu_options(self, commands=None):
def add_options():
getch = Getch()
menu = []
count = 1
for s in commands:
item = '{}. {}\n'.format(count, s[0])
menu.append(item)
count += 1
print(''.join(menu))
answers = []
for a in six.moves.range(1, len(menu) + 1):
answers.append(str(a))
while 1:
ans = getch()
if ans in answers:
break
else:
log.debug('Not an acceptable answer!')
return commands[int(ans) - 1][1]
return add_options()
# This is used as the initial Menu
class MainMenu(BaseMenu):
def __init__(self, commands):
super(MainMenu, self).__init__(commands=commands)

@ -1,118 +0,0 @@
# The MIT License (MIT)
#
# Copyright (c) 2016 Digital Sapphire
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import logging
import sys
import six
from menus.exceptions import MenusError
# Preventing import errors on non windows
# platforms
if sys.platform == 'win32':
import msvcrt
else:
import termios
import tty
log = logging.getLogger(__name__)
if sys.platform == 'win32':
clear_screen_cmd = 'cls'
else:
clear_screen_cmd = 'clear'
def check_commands_else_raise(options):
# We need a least one thing to display
# Using this as a teaching aid. Also making the use of
# Engine(example=Ture) very explicit
if len(options) == 0:
msg = ('You must pass a menus object or initilize '
'like -> Engine(example=True)')
raise MenusError(msg, expected=True)
# We need a list or tuple to loop through
if not isinstance(options, list):
if not isinstance(options, tuple):
msg = ('You must pass a list or tuple to menus.')
raise MenusError(msg, expected=True)
if len(options) > 9:
msg = ('Cannot have more then 8 options per menu')
raise MenusError(msg, expected=True)
for o in options:
# Ensuring each item in list/tuple is a tuple
if not isinstance(o, tuple):
raise MenusError('Item must be tuple: {}'.format(o), expected=True)
if len(o) != 2:
raise MenusError('Invalid number of tuple '
'items:\n\n{}'.format(o))
# Ensure index 0 is a str
if not isinstance(o[0], six.string_types):
msg = 'Menus are passed as [("Menu Name", MenuObject())]'
raise MenusError(msg)
return True
# Gets a single character form standard input. Does not echo to the screen
class Getch(object):
def __init__(self):
if sys.platform == 'win32':
self.impl = GetchWindows()
else:
self.impl = GetchUnix()
def __call__(self):
return self.impl()
class GetchUnix(object):
def __init__(self):
# Not sure if these imports are required here
# import tty, sys
pass
def __call__(self):
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
class GetchWindows(object):
def __init__(self):
# Not sure if this import is required
# import msvcrt
pass
def __call__(self):
return msvcrt.getch()
Loading…
Cancel
Save