pyfilechoose 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jonathan Katende Pinto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,162 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyfilechoose
3
+ Version: 0.1.0
4
+ Summary: A simple replication of R's file.choose() for Python.
5
+ Author-email: Jonathan Katende Pinto <katendepinto@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Pinto-Katende-Jonathan/pyfilechoose
8
+ Project-URL: Repository, https://github.com/Pinto-Katende-Jonathan/pyfilechoose
9
+ Project-URL: Issues, https://github.com/Pinto-Katende-Jonathan/pyfilechoose/issues
10
+ Project-URL: Changelog, https://github.com/Pinto-Katende-Jonathan/pyfilechoose/blob/main/CHANGELOG.md
11
+ Keywords: file,dialog,tkinter,file.choose,R,filedialog
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Software Development :: User Interfaces
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7.0; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # pyfilechoose
32
+
33
+ R's `file.choose()`, reimplemented for Python.
34
+
35
+ [![PyPI version](https://img.shields.io/pypi/v/pyfilechoose.svg)](https://pypi.org/project/pyfilechoose/)
36
+ [![Python versions](https://img.shields.io/pypi/pyversions/pyfilechoose.svg)](https://pypi.org/project/pyfilechoose/)
37
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
38
+
39
+ In R, `file.choose()` opens a file picker and returns the path you select.
40
+ `pyfilechoose` gives you the same one-liner in Python, with no GUI boilerplate
41
+ and no leftover Tk windows.
42
+
43
+ It uses `tkinter` from the standard library, so it has no third-party
44
+ dependencies.
45
+
46
+ ## Installation
47
+
48
+ With pip:
49
+
50
+ ```bash
51
+ pip install pyfilechoose
52
+ ```
53
+
54
+ With [uv](https://docs.astral.sh/uv/):
55
+
56
+ ```bash
57
+ # Add it to your project
58
+ uv add pyfilechoose
59
+
60
+ # ...or install it into the current environment
61
+ uv pip install pyfilechoose
62
+
63
+ # ...or run a one-off script that uses it, no install needed
64
+ uv run --with pyfilechoose your_script.py
65
+ ```
66
+
67
+ On Linux, `tkinter` ships with most Python builds but may need to be installed
68
+ separately, e.g. `sudo apt install python3-tk`.
69
+
70
+ ## Usage
71
+
72
+ ### Pick a single file
73
+
74
+ ```python
75
+ from pyfilechoose import file_choose
76
+
77
+ path = file_choose()
78
+ print(path) # absolute path of the file you selected
79
+ ```
80
+
81
+ ### With pandas (the classic R workflow)
82
+
83
+ `file_choose()` returns a path string, so it works with any function that takes
84
+ a file path, including `pd.read_csv`:
85
+
86
+ ```python
87
+ import pandas as pd
88
+ from pyfilechoose import file_choose
89
+
90
+ # Just like df <- read.csv(file.choose()) in R
91
+ df = pd.read_csv(file_choose())
92
+ ```
93
+
94
+ You can still pass the usual pandas options, and filter the picker to CSVs:
95
+
96
+ ```python
97
+ df = pd.read_csv(file_choose(filetypes=[("CSV files", "*.csv")]), sep=";")
98
+ ```
99
+
100
+ ### Filter file types and set a starting directory
101
+
102
+ ```python
103
+ path = file_choose(
104
+ title="Pick your dataset",
105
+ filetypes=[("CSV files", "*.csv"), ("All files", "*.*")],
106
+ initialdir="~/Documents",
107
+ )
108
+ ```
109
+
110
+ ### Pick several files at once
111
+
112
+ ```python
113
+ from pyfilechoose import files_choose
114
+
115
+ paths = files_choose(filetypes=[("Images", "*.png *.jpg")])
116
+ for p in paths:
117
+ print(p)
118
+ ```
119
+
120
+ ## API
121
+
122
+ ### `file_choose(*, title="Select a file", filetypes=None, initialdir=None) -> str`
123
+
124
+ Opens a dialog and returns the absolute path of the chosen file.
125
+ Raises `FileNotFoundError` if the user cancels.
126
+
127
+ ### `files_choose(*, title="Select one or more files", filetypes=None, initialdir=None) -> list[str]`
128
+
129
+ Same as above but allows multiple selections; returns a list of absolute paths.
130
+ Raises `FileNotFoundError` if nothing is selected.
131
+
132
+ | Argument | Type | Description |
133
+ | ------------ | ----------------------------- | --------------------------------------------------------- |
134
+ | `title` | `str` | Title of the dialog window. |
135
+ | `filetypes` | `list[tuple[str, str]]` \| `None` | `(label, pattern)` pairs, e.g. `[("CSV", "*.csv")]`. |
136
+ | `initialdir` | `str` \| `None` | Directory the dialog opens in. |
137
+
138
+ ## Development
139
+
140
+ ```bash
141
+ git clone https://github.com/Pinto-Katende-Jonathan/pyfilechoose.git
142
+ cd pyfilechoose
143
+ ```
144
+
145
+ With uv, which creates and manages the virtualenv for you:
146
+
147
+ ```bash
148
+ uv sync --extra dev # set up the environment with dev dependencies
149
+ uv run pytest # run the test suite
150
+ ```
151
+
152
+ With pip:
153
+
154
+ ```bash
155
+ python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
156
+ pip install -e ".[dev]"
157
+ pytest
158
+ ```
159
+
160
+ ## License
161
+
162
+ [MIT](LICENSE) © Jonathan Katende Pinto
@@ -0,0 +1,132 @@
1
+ # pyfilechoose
2
+
3
+ R's `file.choose()`, reimplemented for Python.
4
+
5
+ [![PyPI version](https://img.shields.io/pypi/v/pyfilechoose.svg)](https://pypi.org/project/pyfilechoose/)
6
+ [![Python versions](https://img.shields.io/pypi/pyversions/pyfilechoose.svg)](https://pypi.org/project/pyfilechoose/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
+
9
+ In R, `file.choose()` opens a file picker and returns the path you select.
10
+ `pyfilechoose` gives you the same one-liner in Python, with no GUI boilerplate
11
+ and no leftover Tk windows.
12
+
13
+ It uses `tkinter` from the standard library, so it has no third-party
14
+ dependencies.
15
+
16
+ ## Installation
17
+
18
+ With pip:
19
+
20
+ ```bash
21
+ pip install pyfilechoose
22
+ ```
23
+
24
+ With [uv](https://docs.astral.sh/uv/):
25
+
26
+ ```bash
27
+ # Add it to your project
28
+ uv add pyfilechoose
29
+
30
+ # ...or install it into the current environment
31
+ uv pip install pyfilechoose
32
+
33
+ # ...or run a one-off script that uses it, no install needed
34
+ uv run --with pyfilechoose your_script.py
35
+ ```
36
+
37
+ On Linux, `tkinter` ships with most Python builds but may need to be installed
38
+ separately, e.g. `sudo apt install python3-tk`.
39
+
40
+ ## Usage
41
+
42
+ ### Pick a single file
43
+
44
+ ```python
45
+ from pyfilechoose import file_choose
46
+
47
+ path = file_choose()
48
+ print(path) # absolute path of the file you selected
49
+ ```
50
+
51
+ ### With pandas (the classic R workflow)
52
+
53
+ `file_choose()` returns a path string, so it works with any function that takes
54
+ a file path, including `pd.read_csv`:
55
+
56
+ ```python
57
+ import pandas as pd
58
+ from pyfilechoose import file_choose
59
+
60
+ # Just like df <- read.csv(file.choose()) in R
61
+ df = pd.read_csv(file_choose())
62
+ ```
63
+
64
+ You can still pass the usual pandas options, and filter the picker to CSVs:
65
+
66
+ ```python
67
+ df = pd.read_csv(file_choose(filetypes=[("CSV files", "*.csv")]), sep=";")
68
+ ```
69
+
70
+ ### Filter file types and set a starting directory
71
+
72
+ ```python
73
+ path = file_choose(
74
+ title="Pick your dataset",
75
+ filetypes=[("CSV files", "*.csv"), ("All files", "*.*")],
76
+ initialdir="~/Documents",
77
+ )
78
+ ```
79
+
80
+ ### Pick several files at once
81
+
82
+ ```python
83
+ from pyfilechoose import files_choose
84
+
85
+ paths = files_choose(filetypes=[("Images", "*.png *.jpg")])
86
+ for p in paths:
87
+ print(p)
88
+ ```
89
+
90
+ ## API
91
+
92
+ ### `file_choose(*, title="Select a file", filetypes=None, initialdir=None) -> str`
93
+
94
+ Opens a dialog and returns the absolute path of the chosen file.
95
+ Raises `FileNotFoundError` if the user cancels.
96
+
97
+ ### `files_choose(*, title="Select one or more files", filetypes=None, initialdir=None) -> list[str]`
98
+
99
+ Same as above but allows multiple selections; returns a list of absolute paths.
100
+ Raises `FileNotFoundError` if nothing is selected.
101
+
102
+ | Argument | Type | Description |
103
+ | ------------ | ----------------------------- | --------------------------------------------------------- |
104
+ | `title` | `str` | Title of the dialog window. |
105
+ | `filetypes` | `list[tuple[str, str]]` \| `None` | `(label, pattern)` pairs, e.g. `[("CSV", "*.csv")]`. |
106
+ | `initialdir` | `str` \| `None` | Directory the dialog opens in. |
107
+
108
+ ## Development
109
+
110
+ ```bash
111
+ git clone https://github.com/Pinto-Katende-Jonathan/pyfilechoose.git
112
+ cd pyfilechoose
113
+ ```
114
+
115
+ With uv, which creates and manages the virtualenv for you:
116
+
117
+ ```bash
118
+ uv sync --extra dev # set up the environment with dev dependencies
119
+ uv run pytest # run the test suite
120
+ ```
121
+
122
+ With pip:
123
+
124
+ ```bash
125
+ python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
126
+ pip install -e ".[dev]"
127
+ pytest
128
+ ```
129
+
130
+ ## License
131
+
132
+ [MIT](LICENSE) © Jonathan Katende Pinto
@@ -0,0 +1,45 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pyfilechoose"
7
+ version = "0.1.0"
8
+ description = "A simple replication of R's file.choose() for Python."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Jonathan Katende Pinto", email = "katendepinto@gmail.com" },
14
+ ]
15
+ keywords = ["file", "dialog", "tkinter", "file.choose", "R", "filedialog"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "Intended Audience :: Science/Research",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.8",
24
+ "Programming Language :: Python :: 3.9",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Topic :: Software Development :: User Interfaces",
29
+ ]
30
+ dependencies = []
31
+
32
+ [project.optional-dependencies]
33
+ dev = ["pytest>=7.0"]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/Pinto-Katende-Jonathan/pyfilechoose"
37
+ Repository = "https://github.com/Pinto-Katende-Jonathan/pyfilechoose"
38
+ Issues = "https://github.com/Pinto-Katende-Jonathan/pyfilechoose/issues"
39
+ Changelog = "https://github.com/Pinto-Katende-Jonathan/pyfilechoose/blob/main/CHANGELOG.md"
40
+
41
+ [tool.setuptools.packages.find]
42
+ where = ["src"]
43
+
44
+ [tool.setuptools.package-data]
45
+ pyfilechoose = ["py.typed"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,12 @@
1
+ """pyfilechoose - R's ``file.choose()``, reimplemented for Python.
2
+
3
+ Open a native file-selection dialog and get back an absolute path:
4
+
5
+ >>> from pyfilechoose import file_choose
6
+ >>> path = file_choose()
7
+ """
8
+
9
+ from .core import file_choose, files_choose
10
+
11
+ __all__ = ["file_choose", "files_choose"]
12
+ __version__ = "0.1.0"
@@ -0,0 +1,149 @@
1
+ """Core implementation of :func:`file_choose` and :func:`files_choose`.
2
+
3
+ These functions open a native "Open file" dialog using :mod:`tkinter`
4
+ (part of the Python standard library) and return the selected path(s).
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ from typing import Iterable, Optional, Sequence, Tuple
11
+
12
+ __all__ = ["file_choose", "files_choose"]
13
+
14
+ # Type alias for the ``filetypes`` argument, e.g. ``[("CSV files", "*.csv")]``.
15
+ FileTypes = Sequence[Tuple[str, str]]
16
+
17
+
18
+ def _open_dialog(
19
+ *,
20
+ multiple: bool,
21
+ title: str,
22
+ filetypes: Optional[FileTypes],
23
+ initialdir: Optional[str],
24
+ ):
25
+ """Open a Tkinter file dialog and return the raw selection.
26
+
27
+ A hidden root window is created, forced to the foreground, used for a
28
+ single dialog, then destroyed so no resources leak.
29
+ """
30
+ # Imported lazily so that merely importing the package does not require
31
+ # a working Tk installation (e.g. on a headless server).
32
+ try:
33
+ import tkinter as tk
34
+ from tkinter import filedialog
35
+ except ImportError as exc: # pragma: no cover - platform dependent
36
+ raise RuntimeError(
37
+ "tkinter is not available in this Python installation. "
38
+ "On Linux install it with your package manager, e.g. "
39
+ "'sudo apt install python3-tk'."
40
+ ) from exc
41
+
42
+ root = tk.Tk()
43
+ root.withdraw()
44
+ # Force the dialog to appear on top of other windows.
45
+ root.wm_attributes("-topmost", 1)
46
+
47
+ options = {"title": title}
48
+ if filetypes is not None:
49
+ options["filetypes"] = list(filetypes)
50
+ if initialdir is not None:
51
+ options["initialdir"] = initialdir
52
+
53
+ try:
54
+ if multiple:
55
+ selection = filedialog.askopenfilenames(**options)
56
+ else:
57
+ selection = filedialog.askopenfilename(**options)
58
+ finally:
59
+ # Always release the Tk resources, even if the dialog raises.
60
+ root.destroy()
61
+
62
+ return selection
63
+
64
+
65
+ def file_choose(
66
+ *,
67
+ title: str = "Select a file",
68
+ filetypes: Optional[FileTypes] = None,
69
+ initialdir: Optional[str] = None,
70
+ ) -> str:
71
+ """Open a dialog and return the absolute path of the chosen file.
72
+
73
+ A small replication of R's ``file.choose()`` for Python.
74
+
75
+ Parameters
76
+ ----------
77
+ title:
78
+ Title shown in the dialog window.
79
+ filetypes:
80
+ Optional sequence of ``(label, pattern)`` pairs used to filter the
81
+ files shown, e.g. ``[("CSV files", "*.csv"), ("All files", "*.*")]``.
82
+ initialdir:
83
+ Directory the dialog should open in. Defaults to the platform's
84
+ last-used directory.
85
+
86
+ Returns
87
+ -------
88
+ str
89
+ The absolute path of the selected file.
90
+
91
+ Raises
92
+ ------
93
+ FileNotFoundError
94
+ If the user cancels the dialog without selecting a file.
95
+
96
+ Examples
97
+ --------
98
+ >>> import pandas as pd
99
+ >>> df = pd.read_csv(file_choose(filetypes=[("CSV files", "*.csv")]))
100
+ """
101
+ file_path = _open_dialog(
102
+ multiple=False,
103
+ title=title,
104
+ filetypes=filetypes,
105
+ initialdir=initialdir,
106
+ )
107
+
108
+ # askopenfilename returns an empty string when the user cancels.
109
+ if not file_path:
110
+ raise FileNotFoundError("No file was selected.")
111
+
112
+ return os.path.abspath(file_path)
113
+
114
+
115
+ def files_choose(
116
+ *,
117
+ title: str = "Select one or more files",
118
+ filetypes: Optional[FileTypes] = None,
119
+ initialdir: Optional[str] = None,
120
+ ) -> list[str]:
121
+ """Open a dialog allowing multiple selections and return absolute paths.
122
+
123
+ Parameters
124
+ ----------
125
+ title, filetypes, initialdir:
126
+ See :func:`file_choose`.
127
+
128
+ Returns
129
+ -------
130
+ list of str
131
+ Absolute paths of every selected file, in selection order.
132
+
133
+ Raises
134
+ ------
135
+ FileNotFoundError
136
+ If the user cancels the dialog without selecting any file.
137
+ """
138
+ selection: Iterable[str] = _open_dialog(
139
+ multiple=True,
140
+ title=title,
141
+ filetypes=filetypes,
142
+ initialdir=initialdir,
143
+ )
144
+
145
+ paths = [os.path.abspath(p) for p in selection]
146
+ if not paths:
147
+ raise FileNotFoundError("No file was selected.")
148
+
149
+ return paths
File without changes
@@ -0,0 +1,162 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyfilechoose
3
+ Version: 0.1.0
4
+ Summary: A simple replication of R's file.choose() for Python.
5
+ Author-email: Jonathan Katende Pinto <katendepinto@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Pinto-Katende-Jonathan/pyfilechoose
8
+ Project-URL: Repository, https://github.com/Pinto-Katende-Jonathan/pyfilechoose
9
+ Project-URL: Issues, https://github.com/Pinto-Katende-Jonathan/pyfilechoose/issues
10
+ Project-URL: Changelog, https://github.com/Pinto-Katende-Jonathan/pyfilechoose/blob/main/CHANGELOG.md
11
+ Keywords: file,dialog,tkinter,file.choose,R,filedialog
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Software Development :: User Interfaces
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7.0; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # pyfilechoose
32
+
33
+ R's `file.choose()`, reimplemented for Python.
34
+
35
+ [![PyPI version](https://img.shields.io/pypi/v/pyfilechoose.svg)](https://pypi.org/project/pyfilechoose/)
36
+ [![Python versions](https://img.shields.io/pypi/pyversions/pyfilechoose.svg)](https://pypi.org/project/pyfilechoose/)
37
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
38
+
39
+ In R, `file.choose()` opens a file picker and returns the path you select.
40
+ `pyfilechoose` gives you the same one-liner in Python, with no GUI boilerplate
41
+ and no leftover Tk windows.
42
+
43
+ It uses `tkinter` from the standard library, so it has no third-party
44
+ dependencies.
45
+
46
+ ## Installation
47
+
48
+ With pip:
49
+
50
+ ```bash
51
+ pip install pyfilechoose
52
+ ```
53
+
54
+ With [uv](https://docs.astral.sh/uv/):
55
+
56
+ ```bash
57
+ # Add it to your project
58
+ uv add pyfilechoose
59
+
60
+ # ...or install it into the current environment
61
+ uv pip install pyfilechoose
62
+
63
+ # ...or run a one-off script that uses it, no install needed
64
+ uv run --with pyfilechoose your_script.py
65
+ ```
66
+
67
+ On Linux, `tkinter` ships with most Python builds but may need to be installed
68
+ separately, e.g. `sudo apt install python3-tk`.
69
+
70
+ ## Usage
71
+
72
+ ### Pick a single file
73
+
74
+ ```python
75
+ from pyfilechoose import file_choose
76
+
77
+ path = file_choose()
78
+ print(path) # absolute path of the file you selected
79
+ ```
80
+
81
+ ### With pandas (the classic R workflow)
82
+
83
+ `file_choose()` returns a path string, so it works with any function that takes
84
+ a file path, including `pd.read_csv`:
85
+
86
+ ```python
87
+ import pandas as pd
88
+ from pyfilechoose import file_choose
89
+
90
+ # Just like df <- read.csv(file.choose()) in R
91
+ df = pd.read_csv(file_choose())
92
+ ```
93
+
94
+ You can still pass the usual pandas options, and filter the picker to CSVs:
95
+
96
+ ```python
97
+ df = pd.read_csv(file_choose(filetypes=[("CSV files", "*.csv")]), sep=";")
98
+ ```
99
+
100
+ ### Filter file types and set a starting directory
101
+
102
+ ```python
103
+ path = file_choose(
104
+ title="Pick your dataset",
105
+ filetypes=[("CSV files", "*.csv"), ("All files", "*.*")],
106
+ initialdir="~/Documents",
107
+ )
108
+ ```
109
+
110
+ ### Pick several files at once
111
+
112
+ ```python
113
+ from pyfilechoose import files_choose
114
+
115
+ paths = files_choose(filetypes=[("Images", "*.png *.jpg")])
116
+ for p in paths:
117
+ print(p)
118
+ ```
119
+
120
+ ## API
121
+
122
+ ### `file_choose(*, title="Select a file", filetypes=None, initialdir=None) -> str`
123
+
124
+ Opens a dialog and returns the absolute path of the chosen file.
125
+ Raises `FileNotFoundError` if the user cancels.
126
+
127
+ ### `files_choose(*, title="Select one or more files", filetypes=None, initialdir=None) -> list[str]`
128
+
129
+ Same as above but allows multiple selections; returns a list of absolute paths.
130
+ Raises `FileNotFoundError` if nothing is selected.
131
+
132
+ | Argument | Type | Description |
133
+ | ------------ | ----------------------------- | --------------------------------------------------------- |
134
+ | `title` | `str` | Title of the dialog window. |
135
+ | `filetypes` | `list[tuple[str, str]]` \| `None` | `(label, pattern)` pairs, e.g. `[("CSV", "*.csv")]`. |
136
+ | `initialdir` | `str` \| `None` | Directory the dialog opens in. |
137
+
138
+ ## Development
139
+
140
+ ```bash
141
+ git clone https://github.com/Pinto-Katende-Jonathan/pyfilechoose.git
142
+ cd pyfilechoose
143
+ ```
144
+
145
+ With uv, which creates and manages the virtualenv for you:
146
+
147
+ ```bash
148
+ uv sync --extra dev # set up the environment with dev dependencies
149
+ uv run pytest # run the test suite
150
+ ```
151
+
152
+ With pip:
153
+
154
+ ```bash
155
+ python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
156
+ pip install -e ".[dev]"
157
+ pytest
158
+ ```
159
+
160
+ ## License
161
+
162
+ [MIT](LICENSE) © Jonathan Katende Pinto
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/pyfilechoose/__init__.py
5
+ src/pyfilechoose/core.py
6
+ src/pyfilechoose/py.typed
7
+ src/pyfilechoose.egg-info/PKG-INFO
8
+ src/pyfilechoose.egg-info/SOURCES.txt
9
+ src/pyfilechoose.egg-info/dependency_links.txt
10
+ src/pyfilechoose.egg-info/requires.txt
11
+ src/pyfilechoose.egg-info/top_level.txt
12
+ tests/test_core.py
@@ -0,0 +1,3 @@
1
+
2
+ [dev]
3
+ pytest>=7.0
@@ -0,0 +1 @@
1
+ pyfilechoose
@@ -0,0 +1,68 @@
1
+ """Tests for pyfilechoose.
2
+
3
+ The Tk dialog itself is replaced with a fake so the suite can run headless
4
+ (in CI, without a display). We only verify the logic around the dialog:
5
+ absolute-path conversion, cancellation handling, and argument forwarding.
6
+ """
7
+
8
+ import os
9
+
10
+ import pytest
11
+
12
+ from pyfilechoose import core, file_choose, files_choose
13
+
14
+
15
+ def test_file_choose_returns_absolute_path(tmp_path, monkeypatch):
16
+ target = tmp_path / "data.csv"
17
+ target.write_text("a,b\n1,2\n")
18
+
19
+ monkeypatch.setattr(core, "_open_dialog", lambda **kwargs: str(target))
20
+
21
+ result = file_choose()
22
+ assert result == os.path.abspath(str(target))
23
+ assert os.path.isabs(result)
24
+
25
+
26
+ def test_file_choose_raises_on_cancel(monkeypatch):
27
+ # An empty string is what Tk returns when the user cancels.
28
+ monkeypatch.setattr(core, "_open_dialog", lambda **kwargs: "")
29
+
30
+ with pytest.raises(FileNotFoundError):
31
+ file_choose()
32
+
33
+
34
+ def test_file_choose_forwards_arguments(monkeypatch):
35
+ captured = {}
36
+
37
+ def fake(**kwargs):
38
+ captured.update(kwargs)
39
+ return "/some/file.csv"
40
+
41
+ monkeypatch.setattr(core, "_open_dialog", fake)
42
+
43
+ file_choose(
44
+ title="Pick one",
45
+ filetypes=[("CSV", "*.csv")],
46
+ initialdir="/tmp",
47
+ )
48
+
49
+ assert captured["multiple"] is False
50
+ assert captured["title"] == "Pick one"
51
+ assert captured["filetypes"] == [("CSV", "*.csv")]
52
+ assert captured["initialdir"] == "/tmp"
53
+
54
+
55
+ def test_files_choose_returns_list(monkeypatch):
56
+ monkeypatch.setattr(
57
+ core, "_open_dialog", lambda **kwargs: ("/a/one.txt", "/b/two.txt")
58
+ )
59
+
60
+ result = files_choose()
61
+ assert result == [os.path.abspath("/a/one.txt"), os.path.abspath("/b/two.txt")]
62
+
63
+
64
+ def test_files_choose_raises_on_empty(monkeypatch):
65
+ monkeypatch.setattr(core, "_open_dialog", lambda **kwargs: ())
66
+
67
+ with pytest.raises(FileNotFoundError):
68
+ files_choose()