def directory(**kwargs): """Asks the user to choose a directory, and return a path to it. This calls :man:`tk_chooseDirectory(3tk)`, and returns ``None`` if the user cancels. .. note:: By default, the user can choose a directory that doesn't exist yet. This behaviour is documented in :man:`tk_chooseDirectory(3tk)`. If you want the user to choose an existing directory, use ``mustexist=True``. """ result = teek.tcl_call(str, 'tk_chooseDirectory', *_options(kwargs)) if not result: return None return os.path.abspath(result)
def get_tag_names(widget, string): # TODO: add search to teek start = teek.tcl_call(widget.TextIndex, widget, 'search', string, '1.0') end = start.forward(chars=len(string)) tags = set(widget.get_all_tags(start)) # must be same tags in the whole text index = start while index < end: assert set(widget.get_all_tags(index)) == tags index = index.forward(chars=1) return { tag.name[len('soup-'):] for tag in tags if tag.name.startswith('soup-') }
def test_tk_class_names(all_widgets): for widget in all_widgets: if not isinstance(widget, teek.Window): winfo_result = teek.tcl_call(str, 'winfo', 'class', widget) assert winfo_result == type(widget).tk_class_name # special cases assert teek.Widget.tk_class_name is None assert teek.Window.tk_class_name is None class LolWidget(teek.Widget): pass class LolLabel(teek.Label): pass assert LolWidget.tk_class_name is None assert LolLabel.tk_class_name == 'TLabel'
def __init__(self, *args): if len(args) == 3: for name, value in zip(['red', 'green', 'blue'], args): if value not in range(256): raise ValueError("invalid %s value: %r" % (name, value)) self._color_string = '#%02x%02x%02x' % args elif len(args) == 1: self._color_string = args[0] else: # python raises TypeError for wrong number of arguments raise TypeError("use {0}(red, green, blue) or {0}(color_string)" .format(type(self).__name__)) # any widget will do, i'm using the '.' root window because it # always exists rgb = teek.tcl_call([int], 'winfo', 'rgb', '.', self._color_string) # tk uses 16-bit colors for some reason, but most people are more # familiar with 8-bit colors so we'll shift away the "useless" bits self._rgb = tuple(value >> 8 for value in rgb) assert len(self._rgb) == 3
def faker(name, return_value=None): called = [] def command_func(*args): called.append(list(args)) return return_value fake = teek.create_command(command_func, [], extra_args_type=str) teek.tcl_call(None, 'rename', name, name + '_real') try: teek.tcl_call(None, 'rename', fake, name) yield called finally: try: teek.delete_command(name) except teek.TclError: pass teek.tcl_call(None, 'rename', name + '_real', name)
def _messagebox(type, title, message, detail=None, **kwargs): kwargs['type'] = type kwargs['title'] = title kwargs['message'] = message if detail is not None: kwargs['detail'] = detail if type == 'ok': teek.tcl_call(None, 'tk_messageBox', *_options(kwargs)) return None if type == 'okcancel': return teek.tcl_call(str, 'tk_messageBox', *_options(kwargs)) == 'ok' if type == 'retrycancel': return ( teek.tcl_call(str, 'tk_messageBox', *_options(kwargs)) == 'retry') if type == 'yesno': return teek.tcl_call(str, 'tk_messageBox', *_options(kwargs)) == 'yes' # for anything else, return a string return teek.tcl_call(str, 'tk_messageBox', *_options(kwargs))
def test_create_command_arbitrary_args(capsys, handy_callback): @handy_callback def callback(a, b, *args): assert a == 1 assert isinstance(a, int) assert b == 'lol' assert list(args) == expected_args command = teek.create_command(callback, [int, str], extra_args_type=float) expected_args = [1.2, 3.4, 5.6] teek.tcl_call(None, command, '1', 'lol', '1.2', '3.4', '5.6') expected_args = [] teek.tcl_call(None, command, '1', 'lol') assert callback.ran == 2 teek.tcl_call(None, command, '1') output, errors = capsys.readouterr() assert not output assert errors.endswith( 'TypeError: expected at least 2 arguments, got 1 arguments\n')
def redither(self): """See ``imageName redither`` in :man:`photo(3tk)`.""" teek.tcl_call(None, self, 'redither')
def get(self, x, y): """Returns the :class:`.Color` of the pixel at (x,y).""" r, g, b = teek.tcl_call([int], self, 'get', x, y) return Color(r, g, b)
def read(self, filename, **kwargs): """See ``imageName read filename`` in :man:`photo(3tk)`.""" teek.tcl_call(None, self, 'read', filename, *_options(kwargs))
def blank(self): """See ``imageName blank`` in :man:`photo(3tk)`.""" teek.tcl_call(None, self, 'blank')
def height(self): """See :attr:`width`.""" return teek.tcl_call(int, 'image', 'height', self)
def getter(self): return teek.tcl_call(type_spec, "font", "actual", self, "-" + option)
def get_all_images(cls): """Return all existing images as a list of :class:`.Image` objects.""" return teek.tcl_call([cls], 'image', 'names')
def call_bind(returntype, *args): return teek.tcl_call(returntype, 'bind', bindtag, *args)
def get(self): """Returns the value of the variable.""" return teek.tcl_call(type(self).type_spec, 'set', self._name)
def test_eval_and_call(handy_commands, capfd): assert teek.tcl_eval(None, 'if {1 == 2} {puts omg}') is None assert teek.tcl_eval(str, 'list a b c') == 'a b c' assert teek.tcl_eval(int, 'expr 22 / 7') == 3 assert teek.tcl_eval(int, 'returnEmptyString') is None assert round(teek.tcl_eval(float, 'expr 22 / 7.0'), 2) == 3.14 assert teek.tcl_eval([int], 'list 1 2 3') == [1, 2, 3] assert teek.tcl_eval([str], 'list { a} {b } { c }') == [' a', 'b ', ' c '] assert (teek.tcl_eval((str, int, str, int), 'list a 1 b 2') == ('a', 1, 'b', 2)) assert teek.tcl_eval([int], 'list 0b11111111 0o377 0xff') == [255] * 3 assert teek.tcl_eval( {'a': int, 'c': bool}, 'dict create a 1 b 2') == {'a': 1, 'b': '2'} with pytest.raises(ValueError): teek.tcl_eval(int, 'returnArg lel') with pytest.raises(ValueError): teek.tcl_eval((str, str), 'list a b c') with pytest.raises(ValueError): teek.tcl_eval([int], 'list 1 2 3 yay') bools = ['true false', 'tru fal', 'yes no', 'y n', 'on off', '1 0'] for yes, no in map(str.split, bools): assert teek.tcl_call(bool, 'returnArg', yes.upper()) is True assert teek.tcl_call(bool, 'returnArg', no.upper()) is False assert teek.tcl_call(bool, 'returnArg', yes.lower()) is True assert teek.tcl_call(bool, 'returnArg', no.lower()) is False assert teek.tcl_eval(bool, 'returnEmptyString') is None with pytest.raises(ValueError): teek.tcl_eval(bool, 'returnArg lolwut') with pytest.raises(TypeError): teek.tcl_call(None, 'puts', object()) assert capfd.readouterr() == ('', '') with pytest.raises(TypeError): teek.tcl_eval(object(), 'puts hello') # tcl seems to use sometimes lf and sometimes crlf, lol output, errors = capfd.readouterr() assert output.replace('\r\n', '\n') == 'hello\n' assert not errors # forced to string converting relies on this test_data = [ ('ab', 'ab'), ('a b', 'a b'), (['a', 'b'], 'a b'), ([' a', 'b '], '{ a} {b }'), (['a ', ' b'], '{a } { b}'), (['a', 'b c'], 'a {b c}'), (('a', 'b c'), 'a {b c}'), (CustomSequence(), '{a b c} 123'), ] for before, after in test_data: assert teek.tcl_call(str, 'format', '%s', before) == after # test conversion to strings when teek.tcl_calling assert teek.tcl_call( str, 'list', True, 5, 3.14, [1, 2], {3: 4}, ('lol', 'wut'), ) == '1 5 3.14 {1 2} {3 4} {lol wut}' # special case: Tcl empty string is None in python teek.tcl_eval(None, 'proc returnEmpty {} { return {} }') class BrokenFromTcl: oh_no = False @classmethod def from_tcl(cls, tcl_string): cls.oh_no = True raise RuntimeError("NO!! THIS WASNT SUPPSOED TO RUN!!!") assert teek.tcl_call(BrokenFromTcl, 'returnEmpty') is None assert not BrokenFromTcl.oh_no assert capfd.readouterr() == ('', '')
def measure(self, text): """ Calls ``font measure`` documented in :man:`font(3tk)`, and returns an integer. """ return teek.tcl_call(int, "font", "measure", self, text)
def _set(self, option, value): self._tab._check_in_notebook() teek.tcl_call(None, self._tab.widget.parent, 'tab', self._tab.widget, '-' + option, value)
def setter(self, value): if not isinstance(self, NamedFont): raise AttributeError( "cannot change options of non-named fonts, but you can use " "the_font.to_named_font() to create a mutable font object") teek.tcl_call(None, "font", "configure", self, "-" + option, value)
def _config_entrycommand_caller(self, returntype, subcommand, *args): assert subcommand in {'cget', 'configure'} self._check_in_menu() return teek.tcl_call(returntype, self._menu, 'entry' + subcommand, self._index, *args)
def write(self, filename, **kwargs): """See ``imageName write`` in :man:`photo(3tk)`. .. seealso:: Use :meth:`get_bytes` if you don't want to create a file. """ teek.tcl_call(None, self, 'write', filename, *_options(kwargs))
def in_use(self): """True if any widget uses this image, or False if not. This calls ``image inuse`` documented in :man:`image(3tk)`. """ return teek.tcl_call(bool, 'image', 'inuse', self)
def _get(self, option): self._tab._check_in_notebook() return teek.tcl_call(self._types.get(option, str), self._tab.widget.parent, 'tab', self._tab.widget, '-' + option)
def get_all_named_fonts(cls): """Returns a list of all :class:`.NamedFont` objects.""" return list(map(cls, teek.tcl_call([str], 'font', 'names')))
def _list_options(self): self._tab._check_in_notebook() for option in teek.tcl_call({}, self._tab.widget.parent, 'tab', self._tab.widget): yield option.lstrip('-')
def windowingsystem(): return teek.tcl_call(str, 'tk', 'windowingsystem')