Search code examples
pythontkintersshwindows-subsystem-for-linuxmobaxterm

Why does tkinter X program work through SSH with MobaXterm, but give an error when using SSH through Windows Subsystem for Linux?


What I'm working on

I'm writing a Python program (front-end: tkinter, back-end: Python 3.6) on a remote Fedora server from a Windows 10 workstation. MobaXterm would sometimes stop displaying what you type after an exception so I decided to test the Windows subsystem for Linux.

Brief problem description

When executing the GUI using MobaXterm, it launches, when executing it from the subsystem, I get an "AttributeError: 'NoneType' object has no attribute 'days'" error.

System Information

Server Details

NAME=Fedora
VERSION="27 (Twenty Seven)"
ID=fedora
VERSION_ID=27
PRETTY_NAME="Fedora 27 (Twenty Seven)"
ANSI_COLOR="0;34"
CPE_NAME="cpe:/o:fedoraproject:fedora:27"
HOME_URL="fedoraproject" !!!Link removed because of SPAM flag!!!
SUPPORT_URL=!!!Link removed because of SPAM flag!!!
BUG_REPORT_URL=!!!Link removed because of SPAM flag!!!
REDHAT_BUGZILLA_PRODUCT="Fedora"
REDHAT_BUGZILLA_PRODUCT_VERSION=27
REDHAT_SUPPORT_PRODUCT="Fedora"
REDHAT_SUPPORT_PRODUCT_VERSION=27
PRIVACY_POLICY_URL= !!!Link removed because of SPAM flag!!!

Subsystem Details

NAME="Ubuntu"
VERSION="18.04.2 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.2 LTS"
VERSION_ID="18.04"
HOME_URL=!!!Link removed because of SPAM flag!!!
SUPPORT_URL=!!!Link removed because of SPAM flag!!!
BUG_REPORT_URL=!!!Link removed because of SPAM flag!!!
PRIVACY_POLICY_URL=!!!Link removed because of SPAM flag!!!
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

General Information

MobaXterm

Personal Edition v11.1 Build 3860

X11 forwarding from Fedora Server to Ubuntu Subsystem

Done using VcXsrv(vvcxsrv-64.1.20.1.4)

Export on Windows 10 has been tested and works on other programs (tested with xeyes, firefox, and display)

export DISPLAY=localhost:0.0

I've created a simplified version of the code that generates the problem. If you copy and paste the following code in a python live terminal it will execute.

It is a calendar which you can change, and the date to the left of the calendar can be clicked to reset the date to the current date. It works with MobaXterm and gives an error when connecting with

ssh -X -l username server.yourdomain.com

using the Windows Subsystem for Linux.

from tkinter import *
from tkinter import ttk
from tkinter import messagebox
from tkcalendar import Calendar, DateEntry
from datetime import date

# Update the dates in the date_picker variable as well as the date variable
def update_dates(date_frame_container):

    date_frame_container['date_picker'].set_date(date.today())
    date_frame_container['date'] = date_frame_container['date_picker'].get_date()

 # Create an instance of the datepicker and place it on the tab
def setup_date_picker(date_frame_container):

    calendar_style = ttk.Style(date_frame_container['frame'])
    calendar_style.theme_use('clam')

    date_frame_container['date_label'] = ttk.Label(
            date_frame_container['frame'],
            anchor='w',
            text='Today: %s' % date.today().strftime('%x'))
    date_frame_container['date_label'].pack(side = LEFT, anchor = 'w', fill='x')

    date_frame_container['date_picker'] = DateEntry(date_frame_container['frame'])
    date_frame_container['date_picker'].pack(side = RIGHT, anchor = 'e', padx = 10, pady = 10)

    date_frame_container['date_label'].bind("<Button-1>", lambda e : update_dates(date_frame_container))


input_values = {'batch_file': '',
                'scene_id': '',
                'date_frame_container': {
                      'frame': '',
                      'date_picker': '',
                      'date_label': '',
                      'date': ''},
                'lat': '',
                'lon': '',
                'surface_temp': ''}

master = Tk()
master.geometry('320x200')
master.option_add('*tearOff', False)
input_values['date_frame_container']['frame'] = ttk.Frame(master)
input_values['date_frame_container']['frame'].grid(row = 0, column = 1, padx = 10, pady = 10, sticky = 'e')
setup_date_picker(input_values['date_frame_container'])

The Error

When running the code using MobaXterm it works.

When running the code using ssh and the subsystem it doesn't work and I get a AttributeError: 'NoneType' object has no attribute 'days' error

The full Traceback is as follows

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 10, in setup_date_picker
  File "/usr/local/lib/python3.6/site-packages/tkcalendar/dateentry.py", line 93, in __init__
    self._calendar = Calendar(self._top_cal, **kw)
  File "/usr/local/lib/python3.6/site-packages/tkcalendar/calendar_.py", line 211, in __init__
    self._day_names = get_day_names('abbreviated', locale=locale)
  File "/usr/lib/python3.6/site-packages/babel/dates.py", line 305, in get_day_names
    return Locale.parse(locale).days[context][width]
AttributeError: 'NoneType' object has no attribute 'days'

Why would this happen and how can I solve it? The program needs to run in all environments (it's for a research team at university and needs to be used by students and scientists using every operating system you can think of)


Solution

  • Like Bryan Oakley said this is an issue with the locale, tkcalendar tries to determine the default locale and does not find any so the locale is set to None. Therefore any attempt at date formatting fails.

    I have encountered this error when testing tkcalendar on Continuous Integration platforms so next version of tkcalendar (v1.5.0) will address this issue by setting a fallback locale. But for now you can explicitly pass the locale when creating the DateEntry to avoid the error:

    date_frame_container['date_picker'] = DateEntry(date_frame_container['frame']), locale='en_US')