Skip to content

Commit 1de86d8

Browse files
committed
Merge branch 'dev'
2 parents 0dfaf6b + ae7e851 commit 1de86d8

File tree

13 files changed

+199
-98
lines changed

13 files changed

+199
-98
lines changed

.appveyor.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
environment:
2+
matrix:
3+
- PYTHON: "C:\\PYTHON27"
4+
- PYTHON: "C:\\PYTHON35"
5+
- PYTHON: "C:\\PYTHON36"
6+
install:
7+
- "%PYTHON%\\python.exe -m pip install -U pip"
8+
- "%PYTHON%\\python.exe -m pip install nose coverage codecov psutil pynput babel pillow pypiwin32"
9+
build: off
10+
test_script:
11+
- "%PYTHON%\\python.exe -m pip install ."
12+
- "%PYTHON%\\python.exe -m nose --with-coverage"
13+
after_test:
14+
- "%PYTHON%\\Scripts\\codecov.exe"

.codecov.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
coverage:
22
ci:
33
- travis
4+
- appveyor
45
status:
56
patch: false
67
changes: false

README.rst

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
tkfilebrowser
22
=============
33

4-
|Release|_ |Linux| |Travis| |Codecov| |License| |Doc|
4+
|Release|_ |Linux| |Windows| |Travis| |Codecov| |License| |Doc|
55

66
tkfilebrowser is an alternative to tkinter.filedialog that allows the
77
user to select files or directories. The GUI is written with tkinter but
@@ -31,8 +31,16 @@ The documentation is also available here: https://tkfilebrowser.readthedocs.io
3131
Requirements
3232
------------
3333

34-
- Linux
35-
- Python 2.7 or 3.x with tkinter + ttk, python-psutil and python-babel
34+
- Linux or Windows
35+
- Python 2.7 or 3.x
36+
37+
And the python packages:
38+
39+
- tkinter (included in the python distribution for Windows)
40+
- psutil
41+
- babel
42+
- pywin32 (Windows only)
43+
- pillow (only if tkinter.TkVersion < 8.6)
3644

3745

3846
Installation
@@ -117,12 +125,17 @@ Documentation
117125
is asked to confirm its replacement.
118126

119127
Additional option:
128+
120129
- defaultext: extension added to filename if none is given (default is none)
121130

122131

123132
Changelog
124133
---------
125134

135+
- tkfilebrowser 2.3.0
136+
* Make package compatible with Windows
137+
* Set initial focus on entry in save mode
138+
126139
- tkfilebrowser 2.2.6
127140
* No longer reset path bar when clicking on a path button
128141
* Fix bug caused by broken links
@@ -271,7 +284,9 @@ Example
271284
:alt: Latest Release
272285
.. _Release: https://pypi.org/project/tkfilebrowser/
273286
.. |Linux| image:: https://img.shields.io/badge/platform-Linux-blue.svg
274-
:alt: Platform
287+
:alt: Platform Linux
288+
.. |Windows| image:: https://img.shields.io/badge/platform-Windows-blue.svg
289+
:alt: Platform Windows
275290
.. |Travis| image:: https://travis-ci.org/j4321/tkFileBrowser.svg?branch=master
276291
:target: https://travis-ci.org/j4321/tkFileBrowser
277292
:alt: Travis CI Build Status

docs/changelog.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
Changelog
22
=========
33

4+
tkfilebrowser 2.3.0
5+
-------------------
6+
7+
* Make package compatible with Windows
8+
* Set initial focus on entry in save mode
9+
410
tkfilebrowser 2.2.6
511
-------------------
612

@@ -22,7 +28,7 @@ tkfilebrowser 2.2.4
2228
tkfilebrowser 2.2.3
2329
-------------------
2430

25-
* Fix FileNotFoundError if initialdir does not exist
31+
* Fix :obj:`FileNotFoundError` if initialdir does not exist
2632
* Add Desktop in shortcuts (if found)
2733
* Improve filetype filtering
2834

@@ -54,7 +60,7 @@ tkfilebrowser 2.1.1
5460
tkfilebrowser 2.1.0
5561
-------------------
5662

57-
* Add compatibility with tkinter.filedialog keywords 'master' and 'defaultextension'
63+
* Add compatibility with :mod:`tkinter.filedialog` keywords 'master' and 'defaultextension'
5864
* Change look of filetype selector
5965
* Fix bugs when navigating without displaying hidden files
6066
* Fix color alternance bug when hiding hidden files

docs/index.rst

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,23 @@ the look is closer to GTK and the application uses GTK bookmarks (the
1414
one displayed in nautilus or thunar for instance). This filebrowser
1515
supports new directory creation and filtype filtering.
1616

17-
This module contains a general ``FileBrowser`` class which implements the
17+
This module contains a general :class:`~tkfilebrowser.FileBrowser` class which implements the
1818
filebrowser and the following functions, similar to the one in filedialog:
1919

20-
* ``askopenfilename`` that allow the selection of a single file
20+
* :func:`~tkfilebrowser.askopenfilename` that allow the selection of a single file
2121

22-
* ``askopenfilenames`` that allow the selection of multiple files
22+
* :func:`~tkfilebrowser.askopenfilenames` that allow the selection of multiple files
2323

24-
* ``askopendirname`` that allow the selection a single folder
24+
* :func:`~tkfilebrowser.askopendirname` that allow the selection a single folder
2525

26-
* ``askopendirnames`` that allow the selection of multiple folders
26+
* :func:`~tkfilebrowser.askopendirnames` that allow the selection of multiple folders
2727

28-
* ``asksaveasfilename`` that returns a single filename and give a warning if the file already exists
28+
* :func:`~tkfilebrowser.asksaveasfilename` that returns a single filename and give a warning if the file already exists
2929

3030
Project page: https://github.com/j4321/tkFileBrowser
3131

3232
.. toctree::
33-
:maxdepth: 4
33+
:maxdepth: 1
3434
:caption: Contents:
3535

3636
installation

docs/installation.rst

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,16 @@ Installation
44
Requirements
55
------------
66

7-
- Linux
8-
- Python 2.7 or 3.x with tkinter + ttk (and PIL if tk < 8.6.0), python-psutil and python-babel
7+
- Linux or Windows
8+
- Python 2.7 or 3.x
99

10+
And the python packages:
11+
12+
- tkinter (included in the python distribution for Windows)
13+
- psutil
14+
- babel
15+
- pywin32 (Windows only)
16+
- pillow (only if tkinter.TkVersion < 8.6)
1017

1118
Install
1219
-------

setup.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44
from setuptools import setup
55

66
from codecs import open
7-
from os import path
7+
from os import path, name
88

99
here = path.abspath(path.dirname(__file__))
1010

1111
with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
1212
long_description = f.read()
1313

14+
15+
1416
setup(name='tkfilebrowser',
15-
version='2.2.6',
17+
version='2.3.0',
1618
description='File browser for Tkinter, alternative to tkinter.filedialog in linux with GTK bookmarks support.',
1719
long_description=long_description,
1820
url='https://github.com/j4321/tkFileBrowser',
@@ -32,7 +34,8 @@
3234
'Programming Language :: Python :: 3.7',
3335
'Natural Language :: English',
3436
'Natural Language :: French',
35-
'Operating System :: POSIX :: Linux'],
37+
'Operating System :: POSIX :: Linux',
38+
'Operating System :: Microsoft :: Windows'],
3639
py_modules=["tkfilebrowser.autoscrollbar",
3740
"tkfilebrowser.constants",
3841
"tkfilebrowser.filebrowser",
@@ -43,5 +46,5 @@
4346
keywords=['tkinter', 'filedialog', 'filebrowser'],
4447
packages=["tkfilebrowser"],
4548
package_data={"tkfilebrowser": ["images/*"]},
46-
install_requires=["psutil", "babel"],
49+
install_requires=["psutil", "babel"] + (['pypiwin32'] if name == 'nt' else []),
4750
extras_require={'tk<8.6.0': 'Pillow'})

tests/test_filebrowser.py

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
except ImportError:
66
from tkinter import ttk
77
import os
8+
from pynput.keyboard import Key, Controller
89

910

1011
class TestFileBrowser(BaseWidgetTest):
@@ -104,7 +105,8 @@ def test_filebrowser_save(self):
104105
foldercreation=True)
105106
self.window.update()
106107
fb.validate()
107-
self.assertEqual(fb.get_result(), '/test.png')
108+
self.assertEqual(os.path.abspath(fb.get_result()),
109+
os.path.abspath('/test.png'))
108110
fb = FileBrowser(self.window, initialdir="/", initialfile="test.png", mode="save",
109111
filetypes=[("PNG", '*.png|*.PNG'), ("JPG", '*.jpg|*.JPG'),
110112
('ALL', '*')])
@@ -134,26 +136,31 @@ def test_filebrowser_keybrowse(self):
134136
self.window.update()
135137
fb.right_tree.focus_force()
136138
self.window.update()
137-
ch = fb.right_tree.tag_has('file')
138-
letters = [fb.right_tree.item(c, 'text')[0] for c in ch]
139+
ch = fb.right_tree.get_children('')
140+
letters = [fb.right_tree.item(c, 'text')[0].lower() for c in ch]
139141
i = 65
140-
while chr(i) in letters:
142+
while chr(i).lower() in letters:
141143
i += 1
142-
letter = chr(i)
144+
letter = chr(i).lower()
145+
keyboard = Controller()
143146
if letter.isalnum():
144-
fb.right_tree.event_generate('<%s>' % letter)
147+
fb.right_tree.focus_force()
148+
keyboard.press(letter)
149+
keyboard.release(letter)
145150
self.window.update()
146151
self.assertTrue(fb.key_browse_entry.winfo_ismapped())
147-
self.assertEqual(fb.key_browse_entry.get(), letter)
148-
fb.right_tree.event_generate('<Return>')
152+
self.assertEqual(fb.key_browse_entry.get().lower(), letter)
153+
fb.right_tree.event_generate('<Escape>')
149154
self.window.update()
150155
self.assertFalse(fb.key_browse_entry.winfo_ismapped())
151156
if ch:
157+
fb.right_tree.focus_force()
152158
letter = fb.right_tree.item(ch[0], 'text')[0]
153-
fb.right_tree.event_generate('<%s>' % letter)
159+
keyboard.press(letter)
160+
keyboard.release(letter)
154161
self.window.update()
155162
self.assertTrue(fb.key_browse_entry.winfo_ismapped())
156-
self.assertEqual(fb.key_browse_entry.get(), letter)
163+
self.assertEqual(fb.key_browse_entry.get().lower(), letter)
157164
self.assertEqual(fb.right_tree.selection(), (ch[0],))
158165
l = [c for c in ch if fb.right_tree.item(c, 'text')[0] == letter]
159166
fb.key_browse_entry.focus_force()
@@ -172,11 +179,16 @@ def test_filebrowser_keybrowse(self):
172179
self.window.update()
173180
self.assertFalse(fb.key_browse_entry.winfo_ismapped())
174181
fb.right_tree.focus_force()
175-
fb.right_tree.event_generate('<%s>' % letter)
182+
keyboard.press(letter)
183+
keyboard.release(letter)
176184
self.window.update()
177185
fb.right_tree.event_generate('<Return>')
178186
self.window.update()
179-
self.assertEqual(fb.get_result(), (ch[0],))
187+
item = os.path.realpath(ch[0])
188+
if os.path.isdir(item):
189+
self.assertEqual(fb.history[-1], ch[0])
190+
else:
191+
self.assertEqual(fb.get_result(), (item,))
180192

181193
# --- opendir
182194
fb = FileBrowser(self.window, initialdir="/", mode="opendir",
@@ -185,27 +197,31 @@ def test_filebrowser_keybrowse(self):
185197
fb.right_tree.focus_force()
186198
self.window.update()
187199
ch = fb.right_tree.tag_has('folder')
188-
letters = [fb.right_tree.item(c, 'text')[0] for c in ch]
200+
letters = [fb.right_tree.item(c, 'text')[0].lower() for c in ch]
189201
i = 65
190-
while chr(i) in letters:
202+
while chr(i).lower() in letters:
191203
i += 1
192-
letter = chr(i)
204+
letter = chr(i).lower()
193205
if letter.isalnum():
194-
fb.right_tree.event_generate('<%s>' % letter)
206+
fb.right_tree.focus_force()
207+
keyboard.press(letter)
208+
keyboard.release(letter)
195209
self.window.update()
196210
self.assertTrue(fb.key_browse_entry.winfo_ismapped())
197211
self.assertEqual(fb.key_browse_entry.get(), letter)
198212
fb.right_tree.event_generate('<Return>')
199213
self.window.update()
200-
self.assertEqual(fb.get_result(), ('/',))
214+
self.assertEqual(fb.get_result(), (os.path.abspath('/'),))
201215
fb = FileBrowser(self.window, initialdir="/", mode="opendir",
202216
multiple_selection=True)
203217
self.window.update()
204218
fb.right_tree.focus_force()
205219
if ch:
206-
letter = fb.right_tree.item(ch[-1], 'text')[0]
207-
l = [c for c in ch if fb.right_tree.item(c, 'text')[0] == letter]
208-
fb.right_tree.event_generate('<%s>' % letter)
220+
letter = fb.right_tree.item(ch[-1], 'text')[0].lower()
221+
l = [c for c in ch if fb.right_tree.item(c, 'text')[0].lower() == letter]
222+
fb.right_tree.focus_force()
223+
keyboard.press(letter)
224+
keyboard.release(letter)
209225
self.window.update()
210226
self.assertTrue(fb.key_browse_entry.winfo_ismapped())
211227
self.assertEqual(fb.key_browse_entry.get(), letter)
@@ -226,7 +242,8 @@ def test_filebrowser_keybrowse(self):
226242
self.window.update()
227243
self.assertFalse(fb.key_browse_entry.winfo_ismapped())
228244
fb.right_tree.focus_force()
229-
fb.right_tree.event_generate('<%s>' % letter)
245+
keyboard.press(letter)
246+
keyboard.release(letter)
230247
self.window.update()
231248
fb.right_tree.event_generate('<Return>')
232249
self.window.update()
@@ -266,11 +283,12 @@ def test_filebrowser_keybrowse(self):
266283
self.window.update()
267284

268285
def test_filebowser_foldercreation(self):
269-
fb = FileBrowser(self.window, initialdir="/",
286+
initdir = os.path.abspath('/')
287+
fb = FileBrowser(self.window, initialdir=initdir,
270288
foldercreation=True)
271289
self.window.update()
272290
self.assertTrue(fb.b_new_folder.winfo_ismapped())
273-
self.assertTrue('disabled' in fb.b_new_folder.state())
291+
self.assertIs('disabled' not in fb.b_new_folder.state(), os.access(initdir, os.W_OK))
274292
fb.display_folder(os.path.expanduser('~'))
275293
self.window.update()
276294
self.assertTrue(fb.b_new_folder.winfo_ismapped())
@@ -287,7 +305,7 @@ def test_filebrowser_sorting(self):
287305
okbuttontext=None, cancelbuttontext="Cancel",
288306
foldercreation=True)
289307
self.window.update()
290-
walk = os.walk('/')
308+
walk = os.walk(os.path.abspath('/'))
291309
root, dirs, files = walk.send(None)
292310
dirs = [os.path.join(root, d) for d in dirs]
293311
files = [os.path.join(root, f) for f in files]
@@ -363,8 +381,8 @@ def test_filebrowser_on_selection(self):
363381
fb.right_tree.selection_clear()
364382
fb.right_tree.selection_set(ch[0])
365383
self.window.update()
366-
self.assertEqual(fb.entry.get(),
367-
os.path.join(fb.right_tree.item(ch[0], 'text'), ''))
384+
self.assertEqual(os.path.abspath(fb.entry.get()),
385+
os.path.abspath(os.path.join(fb.right_tree.item(ch[0], 'text'), '')))
368386
fb.focus_force()
369387
fb.event_generate("<Control-l>")
370388
self.window.update()
@@ -390,8 +408,8 @@ def test_filebrowser_on_selection(self):
390408
fb.right_tree.selection_clear()
391409
fb.right_tree.selection_set(ch[0])
392410
self.window.update()
393-
self.assertEqual(fb.entry.get(),
394-
os.path.join(fb.right_tree.item(ch[0], 'text'), ''))
411+
self.assertEqual(os.path.abspath(fb.entry.get()),
412+
os.path.abspath(os.path.join(fb.right_tree.item(ch[0], 'text'), '')))
395413
ch = fb.right_tree.tag_has('file')
396414
if ch:
397415
fb.right_tree.selection_clear()

tkfilebrowser/constants.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@
7878
IM_RECENT = os.path.join(PATH, "images", "recent.png")
7979
IM_RECENT_24 = os.path.join(PATH, "images", "recent_24.png")
8080

81-
8281
# --- translation
8382
try:
8483
LANG = locale.getdefaultlocale()[0]

0 commit comments

Comments
 (0)