Skip to content

ttk::themes missing from ttk.py #61599

Closed as not planned
Closed as not planned

Description

@klappnase
mannequin
BPO 17397
Nosy @terryjreedy, @roseman, @serhiy-storchaka
Files
  • patch_ttk.diff
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/terryjreedy'
    closed_at = None
    created_at = <Date 2013-03-11.12:43:17.578>
    labels = ['type-feature', 'expert-tkinter']
    title = 'ttk::themes missing from ttk.py'
    updated_at = <Date 2015-08-07.20:09:47.144>
    user = 'https://bugs.python.org/klappnase'

    bugs.python.org fields:

    activity = <Date 2015-08-07.20:09:47.144>
    actor = 'markroseman'
    assignee = 'terry.reedy'
    closed = False
    closed_date = None
    closer = None
    components = ['Tkinter']
    creation = <Date 2013-03-11.12:43:17.578>
    creator = 'klappnase'
    dependencies = []
    files = ['29377']
    hgrepos = []
    issue_num = 17397
    keywords = ['patch']
    message_count = 13.0
    messages = ['183954', '184028', '184445', '184478', '184483', '184494', '203317', '204825', '204829', '204842', '204908', '248154', '248224']
    nosy_count = 6.0
    nosy_names = ['terry.reedy', 'klappnase', 'gpolo', 'Arfrever', 'markroseman', 'serhiy.storchaka']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue17397'
    versions = ['Python 3.6']

    Activity

    1. klappnase commented on Mar 11, 2013

      klappnasemannequin
      MannequinAuthor

      When trying to load third-party themes ttk.Style.theme_names() fails to list available themes. For example if the themes from the tile-themes project are installed one can do:

      >>> from tkinter import *
      >>> from tkinter import ttk
      >>> root=Tk()
      >>> s=ttk.Style()
      >>> s.theme_names()
      ('clam', 'alt', 'default', 'classic')
      >>> root.tk.call('ttk::themes')
      ('classic', 'default', 'clam', 'alt')
      >>> root.tk.call('package', 'require', 'tile-themes')
      '0.6'
      >>> s.theme_names()
      ('clam', 'alt', 'default', 'classic')
      >>> root.tk.call('ttk::themes')
      ('keramik', 'plastik', 'clam', 'winxpblue', 'alt', 'Aquativo', 'classic', 'default', 'keramik_alt')
      >>> 

      This has been discussed in more detail at tkinter-discuss:
      http://code.activestate.com/lists/python-tkinter-discuss/3373/

      As ttk::themes is described as being part of the Public API inside ttk.tcl and is also documented in the tcl wiki at http://wiki.tcl.tk/14796 resp. http://wiki.tcl.tk/23676 it appears safe to add it to ttk.py.

      Considering this I prepared a patch (against b10a9d4f08eb) that adds the following method to ttk.Style():

          def themes(self, pattern=None):
              '''Returns a list of theme names available. It can be passed an
              argument which is used as an lsearch glob pattern while looking
              for the theme names.'''
              return self.tk.splitlist(self.tk.call('ttk::themes', pattern))
    2. changed the title [-]ttk::themes missing form ttk.py[/-] [+]ttk::themes missing from ttk.py[/+] on Mar 12, 2013
    3. serhiy-storchaka commented on Mar 12, 2013

      @serhiy-storchaka
      Member

      Can you provide some tests for the new method?

    4. klappnase commented on Mar 18, 2013

      klappnasemannequin
      MannequinAuthor

      I am not familiar with python's test unit, but I tried my best.

      As far as I see there are three possibilities to invoke the function:

      • without pattern -> return tuple with all themes
      • with pattern that matches one or more themes
      • with pattern that matches no themes -> return empty tuple

      So I tried to add a method to test_style.StyleTest() :

          def test_themes(self):
              installed_themes = self.style.themes()
              some_themes = self.style.themes('*e*')
              no_themes = self.style.themes('foobarbaz')
      
              self.assertTrue(isinstance(installed_themes, tuple))
              self.assertTrue(isinstance(some_themes, tuple))
              self.assertTrue(isinstance(no_themes, tuple))

      Oddly enough this fails on my own system (debian squeeze, tk-8.5.8, python-3.1.3 / -2.6.6):

      $ python3 test_style.py
      test_configure (__main__.StyleTest) ... ok
      test_layout (__main__.StyleTest) ... ok
      test_lookup (__main__.StyleTest) ... ok
      test_map (__main__.StyleTest) ... ok
      test_theme_use (__main__.StyleTest) ... ok
      test_themes (__main__.StyleTest) ... ERROR

      ======================================================================
      ERROR: test_themes (main.StyleTest)
      ----------------------------------------------------------------------

      Traceback (most recent call last):
        File "test_style.py", line 97, in test_themes
          no_themes = self.style.themes('foobarbaz')
        File "/usr/lib/python3.1/tkinter/ttk.py", line 536, in themes
          return self.tk.splitlist(self.tk.call('ttk::themes', pattern))
      TypeError: Can't convert '_tkinter.Tcl_Obj' object to str implicitly

      Ran 6 tests in 0.086s

      FAILED (errors=1)
      Traceback (most recent call last):
        File "test_style.py", line 108, in <module>
          run_unittest(*tests_gui)
        File "/usr/lib/python3.1/test/support.py", line 955, in run_unittest
          _run_suite(suite)
        File "/usr/lib/python3.1/test/support.py", line 938, in _run_suite
          raise TestFailed(err)
      test.support.TestFailed: Traceback (most recent call last):
        File "test_style.py", line 97, in test_themes
          no_themes = self.style.themes('foobarbaz')
        File "/usr/lib/python3.1/tkinter/ttk.py", line 536, in themes
          return self.tk.splitlist(self.tk.call('ttk::themes', pattern))
      TypeError: Can't convert '_tkinter.Tcl_Obj' object to str implicitly

      The same error occurs with python-2.6.6 (same tk). Apparently this is because:

      $ python3
      Python 3.1.3 (r313:86834, Nov 28 2010, 11:28:10) 
      [GCC 4.4.5] on linux2
      Type "help", "copyright", "credits" or "license" for more information.
      >>> from tkinter import *
      >>> from tkinter import ttk
      >>> r=Tk()
      >>> s=ttk.Style()
      >>> x = s.themes('foo')
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "/usr/lib/python3.1/tkinter/ttk.py", line 536, in themes
          return self.tk.splitlist(self.tk.call('ttk::themes', pattern))
      TypeError: Can't convert '_tkinter.Tcl_Obj' object to str implicitly
      >>> x=r.tk.call('ttk::themes', 'foo')
      >>> x
      <StateSpec object at 0x9b1b6c8>
      >>> str(x)
      ''
      >>> 

      Called from wish the same call returns an empty string as expected:

      $ wish
      % ttk::themes
      classic default clam alt
      % ttk::themes *e*
      default
      % ttk::themes foobarbaz
      %

      In python2.6, when setting Tkinter.wantobjects to 0, themes('foo') returns an empty tuple as expected.
      So I guess this is due to a bug in debian's python/tkinter install. Can anyone confirm this?

    5. klappnase commented on Mar 18, 2013

      klappnasemannequin
      MannequinAuthor

      Update: I just tried Python-3.3.0 on WinXP, the same error, so it is obviously _not_ a bug specific to the debian python install.

    6. serhiy-storchaka commented on Mar 18, 2013

      @serhiy-storchaka
      Member

      This looks similar to bpo-16809 and requires a similar solution.

    7. klappnase commented on Mar 18, 2013

      klappnasemannequin
      MannequinAuthor

      Yes, I happen to encounter these TclObjects occasionally, e.g. (not tested with the latest python):

      $ python3
      Python 3.1.3 (r313:86834, Nov 28 2010, 11:28:10) 
      [GCC 4.4.5] on linux2
      Type "help", "copyright", "credits" or "license" for more information.
      >>> from tkinter import *
      >>> from tkinter import ttk
      >>> r=Tk()
      >>> p=ttk.Progressbar(r)
      >>> p.cget('mode')
      <index object at 0x879d338>
      >>> print(p.cget('mode'))
      determinate
      >>> p.cget('mode') == 'determinate'
      False
      >>> str(p.cget('mode')) == 'determinate'
      True
      >>> 

      In Python2 the easiest way to work around this imho is to set wantobjects to 0, however this does not seem to work in Python3 anymore, not sure if this is for some reason intentional or deserves another bug report:

      $ python3
      Python 3.1.3 (r313:86834, Nov 28 2010, 11:28:10) 
      [GCC 4.4.5] on linux2
      Type "help", "copyright", "credits" or "license" for more information.
      >>> import tkinter
      >>> tkinter.wantobjects = 0
      >>> from tkinter import ttk
      >>> r=tkinter.Tk()
      >>> p=ttk.Progressbar(r)
      >>> p.cget('mode')
      ''
      >>>

      To be honest, since these TclObjects never seem to work reliably I had preferred it a lot if they would have been turned off by default.

    8. serhiy-storchaka commented on Nov 18, 2013

      @serhiy-storchaka
      Member

      Since splitlist() works with Tcl_Obj-s, proposed test should pass.

      klappnase, could you please sign a Contributor Licensing Agreement?

      http://www.python.org/psf/contrib/contrib-form/

      What is your real name? What should I add in the Misc/ACKS file?

    9. klappnase commented on Nov 30, 2013

      klappnasemannequin
      MannequinAuthor

      What is your real name?
      Michael Lange
      What should I add in the Misc/ACKS file?
      Hmm, personally I'd prefer the nick, but it seems to be common practice to use the real name; I think I'll leave it to you ;)

    10. serhiy-storchaka commented on Nov 30, 2013

      @serhiy-storchaka
      Member

      Now CPython trunk in feature freeze stage until 3.4 realease. So we should wait several months before commit this patch.

    11. terryjreedy commented on Nov 30, 2013

      @terryjreedy
      Member

      As a non-tcl/tk user except via tkinter, I am not convinced that we should add a near-duplicate function. The *Python* doc for ttk.Style.theme_names says "Returns a list of all known themes." If it does not do that, which it seems not to, it should be changed (whether the change is called a fix or enhancement).

      From the referenced Epler post, the situation seems more complicated on the ttk side in that ttk has two similar functions: 'style theme_names', which only reports 'loaded' names, and 'themes' which reports 'loaded and available', though 'available' seems vague and dependent on strange package calls. For Python, a parameter for one function would suffice to restrict or augment the list returned, if indeed the option is needed.

      Are 'unloaded but available' themes really available to use? Does Style.theme_use(available_name) work? If so, it seems to me that available_name should be reported by theme_names. If not, what is the use of knowing it?

      Most any patch will need a doc patch.

    12. klappnase commented on Dec 1, 2013

      klappnasemannequin
      MannequinAuthor

      Are 'unloaded but available' themes really available to use?

      Yes.

      Does Style.theme_use(available_name) work?

      Yes.

      If so, it seems to me that available_name should
      be reported by theme_names.

      I agree, one should think so. I am not 100% certain about that, but to me it seems that on the tcl side ttk:themes is newer and thus preferable to theme names which maybe is only still there for backwards compatibility.

      Since as a Tkinter user I like Tkinter methods to behave like their Tcl/Tk counterparts (which, if nothing else, helps a lot in reading and understanding tcl code/documentation (and possibly "translating" tcl code into Python)) I had rather kept theme_names() intact to avoid confusion. Maybe there could simply a line like "Deprecated since Python-xy, use themes() instead." be added to theme_names' doc string ?

    13. terryjreedy commented on Aug 6, 2015

      @terryjreedy
      Member

      Mark, do you have any opinion of this? It apparently impinges on what themes we use or can offer as an option.

    14. roseman commented on Aug 7, 2015

      rosemanmannequin
      Mannequin

      I believe the ttk::themes call is older, part of when it was still Tile. There are a bunch of those kind of API's that were kept around (for compatibility I presume) when the official API (style theme names) was created and documented.

      As explained on the original mailing list thread, the difference has to do with Tcl's lazy loading of packages (i.e. it knows what package to load when you need a particular command, but will not necessarily load it until the command is used)
      http://code.activestate.com/lists/python-tkinter-discuss/3371/

      To summarize, even now you can install themes and use them, they just won't appear in the list until they're used.

      Because calls like ttk::themes are *not* part of the official, documented API, I would strongly suggest not adding a separate API in tkinter; instead, stay with Style.theme_names

      I would suggest that the default behaviour of theme_names be changed to call ttk::themes (falling back on theme use if it generates an error). I would also suggest adding a tkinter-only optional keyword parameter to this call (e.g. loaded, defaulting to False; if True is would call 'ttk::style theme names'). Then document that loaded=True is not guaranteed to be only loaded ones in future, because I wouldn't be surprised if Tk changes this at some point.

    15. transferred this issue fromon Apr 10, 2022
    16. added
      stdlibStandard Library Python modules in the Lib/ directory
      on Nov 23, 2023
    17. serhiy-storchaka commented on Jun 27, 2026

      @serhiy-storchaka
      Member

      Style.theme_names() wraps ttk::style theme names, the documented public ttk API. The ttk::themes command proposed here is still undocumented in Tk 9.0/9.1, and as Mark Roseman noted, it's a Tile-era leftover that was never made official.

      It also wouldn't deliver the title's goal: ttk::themes only lists themes registered as ttk::theme::* packages, so the common file-sourced third-party themes (azure, forest, ttkthemes) still wouldn't appear.

      Closing as not worth adding.

    18. removed their assignment
      on Jun 27, 2026
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      stdlibStandard Library Python modules in the Lib/ directorytopic-tkintertype-featureA feature request or enhancement

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions