Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit fe08dc2

Browse files
authoredJan 13, 2025··
🔀 Merge pull request #12 from davep/revamp-repo
Overhaul the repository
2 parents e9be534 + a02990a commit fe08dc2

27 files changed

+323
-789
lines changed
 

‎.github/FUNDING.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# These are supported funding model platforms
2+
3+
ko_fi: davepearson

‎.github/workflows/style-and-lint.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Code quality tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
11+
style-lint-and-test:
12+
13+
name: Style and lint
14+
runs-on: ubuntu-latest
15+
strategy:
16+
matrix:
17+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
18+
19+
steps:
20+
21+
- name: Checkout Code
22+
uses: actions/checkout@v4
23+
24+
- name: Set up Python
25+
uses: actions/setup-python@v4
26+
with:
27+
python-version: ${{ matrix.python-version }}
28+
29+
- name: Install Rye
30+
uses: eifinger/setup-rye@v4
31+
with:
32+
version: "latest"
33+
34+
- name: Install Dependencies
35+
run: make setup
36+
37+
- name: Check the Code style
38+
run: make codestyle
39+
40+
- name: Lint the code
41+
run: make lint
42+
43+
- name: Type check the code
44+
run: make stricttypecheck
45+
46+
### style-and-lint.yaml ends here

‎.pre-commit-config.yaml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
repos:
2-
- repo: https://github.com/pycqa/isort
3-
rev: 5.12.0
2+
- repo: https://github.com/astral-sh/ruff-pre-commit
3+
# Ruff version.
4+
rev: v0.6.4
45
hooks:
5-
- id: isort
6-
name: isort (python)
7-
language_version: '3.10'
8-
args: ["--profile", "black", "--filter-files"]
9-
- repo: https://github.com/psf/black
10-
rev: 23.3.0
11-
hooks:
12-
- id: black
13-
language_version: python3.10
6+
# Run the linter.
7+
- id: ruff
8+
args: [ --fix, --select, I ]
9+
# Run the formatter.
10+
- id: ruff-format

‎.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.13.1

‎ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
- Added <kbd>backspace</kbd> as a navigation shortcut for "change to parent"
88
([thanks to ihabunek](https://github.com/davep/textual-fspicker/pull/7)).
9+
- Added support for drive selection on Microsoft Windows
10+
([davidfokkema](https://github.com/davep/textual-fspicker/pull/9)),
911

1012
## v0.0.10
1113

‎Makefile

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,104 @@
1-
###############################################################################
2-
# Common make values.
31
lib := textual_fspicker
4-
run := pipenv run
2+
src := src/
3+
run := rye run
4+
test := rye test
55
python := $(run) python
6-
lint := $(run) pylint
6+
lint := rye lint -- --select I
7+
fmt := rye fmt
78
mypy := $(run) mypy
8-
twine := $(run) twine
9-
build := $(python) -m build
10-
black := $(run) black
119

1210
##############################################################################
13-
# Run the plotter.
11+
# Local "interactive testing" of the code.
1412
.PHONY: run
15-
run:
13+
run: # Run the code in a testing context
1614
$(python) -m $(lib)
1715

1816
.PHONY: debug
19-
debug:
17+
debug: # Run the code with Textual devtools enabled
2018
TEXTUAL=devtools make
2119

2220
.PHONY: console
23-
console:
21+
console: # Run the textual console
2422
$(run) textual console
2523

2624
##############################################################################
2725
# Setup/update packages the system requires.
2826
.PHONY: setup
29-
setup: # Install all dependencies
30-
pipenv sync --dev
27+
setup: # Set up the repository for development
28+
rye sync
3129
$(run) pre-commit install
3230

33-
.PHONY: resetup
34-
resetup: # Recreate the virtual environment from scratch
35-
rm -rf $(shell pipenv --venv)
36-
pipenv sync --dev
37-
38-
.PHONY: depsoutdated
39-
depsoutdated: # Show a list of outdated dependencies
40-
pipenv update --outdated
41-
42-
.PHONY: depsupdate
43-
depsupdate: # Update all dependencies
44-
pipenv update --dev
31+
.PHONY: update
32+
update: # Update all dependencies
33+
rye sync --update-all
4534

46-
.PHONY: depsshow
47-
depsshow: # Show the dependency graph
48-
pipenv graph
35+
.PHONY: resetup
36+
resetup: realclean # Recreate the virtual environment from scratch
37+
make setup
4938

5039
##############################################################################
5140
# Checking/testing/linting/etc.
5241
.PHONY: lint
53-
lint: # Run Pylint over the library
54-
$(lint) $(lib)
42+
lint: # Check the code for linting issues
43+
$(lint) $(src)
44+
45+
.PHONY: codestyle
46+
codestyle: # Is the code formatted correctly?
47+
$(fmt) --check $(src)
5548

5649
.PHONY: typecheck
5750
typecheck: # Perform static type checks with mypy
58-
$(mypy) --scripts-are-modules $(lib)
51+
$(mypy) --scripts-are-modules $(src)
5952

6053
.PHONY: stricttypecheck
6154
stricttypecheck: # Perform a strict static type checks with mypy
62-
$(mypy) --scripts-are-modules --strict $(lib)
55+
$(mypy) --scripts-are-modules --strict $(src)
6356

6457
.PHONY: checkall
65-
checkall: lint stricttypecheck # Check all the things
58+
checkall: codestyle lint stricttypecheck # Check all the things
6659

6760
##############################################################################
6861
# Package/publish.
6962
.PHONY: package
7063
package: # Package the library
71-
$(build) -w
64+
rye build
7265

7366
.PHONY: spackage
7467
spackage: # Create a source package for the library
75-
$(build) -s
76-
77-
.PHONY: packagecheck
78-
packagecheck: package spackage # Check the packaging.
79-
$(twine) check dist/*
68+
rye build --sdist
8069

8170
.PHONY: testdist
82-
testdist: packagecheck # Perform a test distribution
83-
$(twine) upload --skip-existing --repository testpypi dist/*
71+
testdist: package # Perform a test distribution
72+
rye publish --yes --skip-existing --repository testpypi --repository-url https://test.pypi.org/legacy/
8473

8574
.PHONY: dist
86-
dist: packagecheck # Upload to pypi
87-
$(twine) upload --skip-existing dist/*
75+
dist: package # Upload to pypi
76+
rye publish --yes --skip-existing
8877

8978
##############################################################################
9079
# Utility.
91-
.PHONY: ugly
92-
ugly: # Reformat the code with black.
93-
$(black) $(lib)
94-
9580
.PHONY: repl
96-
repl: # Start a Python REPL
81+
repl: # Start a Python REPL in the venv.
9782
$(python)
9883

84+
.PHONY: delint
85+
delint: # Fix linting issues.
86+
$(lint) --fix $(src)
87+
88+
.PHONY: pep8ify
89+
pep8ify: # Reformat the code to be as PEP8 as possible.
90+
$(fmt) $(src)
91+
92+
.PHONY: tidy
93+
tidy: delint pep8ify # Tidy up the code, fixing lint and format issues.
94+
9995
.PHONY: clean
10096
clean: # Clean the build directories
101-
rm -rf build dist $(lib).egg-info
97+
rm -rf dist
98+
99+
.PHONY: realclean
100+
realclean: clean # Clean the venv and build directories
101+
rm -rf .venv
102102

103103
.PHONY: help
104104
help: # Display this help

‎Pipfile

Lines changed: 0 additions & 19 deletions
This file was deleted.

‎Pipfile.lock

Lines changed: 0 additions & 638 deletions
This file was deleted.

‎README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Right at the moment there's just two dialogs available:
2727
- `SelectDirectory` -- For selecting a directory from the filesysrem.
2828

2929
You can see them in action in the [demo/test
30-
code](https://github.com/davep/textual-fspicker/blob/main/textual_fspicker/__main__.py).
30+
code](https://github.com/davep/textual-fspicker/blob/main/src/textual_fspicker/__main__.py).
3131

3232
Yes, I know that documentation is lacking right now -- I'm still fleshing
3333
out how this will work and what it will provide -- so the best place to see
@@ -43,7 +43,7 @@ how the code can be used is in that demo/test code.
4343
- [X] Add file filtering (extensions using `Select`)
4444
- [X] Expose the hidden show/hide facility of the navigator in the dialogs
4545
- [ ] Better documentation
46-
- [ ] Test on Windows
46+
- [X] Test on Windows
4747
- [ ] Add custom mtime formatting
4848
- [ ] Add support for showing different times
4949

‎pyproject.toml

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,63 @@
1+
[project]
2+
name = "textual-fspicker"
3+
version = "0.1.0"
4+
description = "A simple Textual filesystem picker dialog library."
5+
authors = [
6+
{ name = "Dave Pearson", email = "davep@davep.org" }
7+
]
8+
dependencies = [
9+
"textual>=1.0.0",
10+
]
11+
readme = "README.md"
12+
requires-python = ">=3.8"
13+
license = { text = "License :: OSI Approved :: MIT License" }
14+
keywords = [
15+
"terminal",
16+
"library",
17+
"file system",
18+
"filesystem",
19+
"dialog",
20+
]
21+
classifiers = [
22+
"License :: OSI Approved :: MIT License",
23+
"Environment :: Console",
24+
"Development Status :: 3 - Alpha",
25+
"Intended Audience :: Developers",
26+
"Operating System :: OS Independent",
27+
"Programming Language :: Python :: 3.8",
28+
"Programming Language :: Python :: 3.9",
29+
"Programming Language :: Python :: 3.10",
30+
"Programming Language :: Python :: 3.11",
31+
"Programming Language :: Python :: 3.12",
32+
"Programming Language :: Python :: 3.13",
33+
"Topic :: Terminals",
34+
"Topic :: Software Development :: Libraries",
35+
"Typing :: Typed",
36+
]
37+
38+
[project.urls]
39+
Homepage = "https://github.com/davep/textual-fspicker"
40+
Repository = "https://github.com/davep/textual-fspicker"
41+
Documentation = "https://github.com/davep/textual-fspicker/blob/main/README.md"
42+
Source = "https://github.com/davep/textual-fspicker"
43+
Issues = "https://github.com/davep/textual-fspicker/issues"
44+
Discussions = "https://github.com/davep/textual-fspicker/discussions"
45+
146
[build-system]
2-
requires = ["setuptools>=42", "wheel"]
3-
build-backend = "setuptools.build_meta"
47+
# https://github.com/astral-sh/rye/issues/1446
48+
requires = ["hatchling==1.26.3", "hatch-vcs"]
49+
# requires = ["hatchling"]
50+
build-backend = "hatchling.build"
51+
52+
[tool.rye]
53+
managed = true
54+
dev-dependencies = [
55+
"pre-commit>=4.0.1",
56+
"mypy>=1.14.1",
57+
]
58+
59+
[tool.hatch.metadata]
60+
allow-direct-references = true
461

5-
### pyproject.toml ends here
62+
[tool.hatch.build.targets.wheel]
63+
packages = ["src/textual_fspicker"]

‎requirements-dev.lock

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# generated by rye
2+
# use `rye lock` or `rye sync` to update this lockfile
3+
#
4+
# last locked with the following flags:
5+
# pre: false
6+
# features: []
7+
# all-features: false
8+
# with-sources: false
9+
# generate-hashes: false
10+
# universal: false
11+
12+
-e file:.
13+
cfgv==3.4.0
14+
# via pre-commit
15+
distlib==0.3.9
16+
# via virtualenv
17+
filelock==3.16.1
18+
# via virtualenv
19+
identify==2.6.5
20+
# via pre-commit
21+
linkify-it-py==2.0.3
22+
# via markdown-it-py
23+
markdown-it-py==3.0.0
24+
# via mdit-py-plugins
25+
# via rich
26+
# via textual
27+
mdit-py-plugins==0.4.2
28+
# via markdown-it-py
29+
mdurl==0.1.2
30+
# via markdown-it-py
31+
mypy==1.14.1
32+
mypy-extensions==1.0.0
33+
# via mypy
34+
nodeenv==1.9.1
35+
# via pre-commit
36+
platformdirs==4.3.6
37+
# via textual
38+
# via virtualenv
39+
pre-commit==4.0.1
40+
pygments==2.19.1
41+
# via rich
42+
pyyaml==6.0.2
43+
# via pre-commit
44+
rich==13.9.4
45+
# via textual
46+
textual==1.0.0
47+
# via textual-fspicker
48+
typing-extensions==4.12.2
49+
# via mypy
50+
# via textual
51+
uc-micro-py==1.0.3
52+
# via linkify-it-py
53+
virtualenv==20.28.1
54+
# via pre-commit

‎requirements.lock

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# generated by rye
2+
# use `rye lock` or `rye sync` to update this lockfile
3+
#
4+
# last locked with the following flags:
5+
# pre: false
6+
# features: []
7+
# all-features: false
8+
# with-sources: false
9+
# generate-hashes: false
10+
# universal: false
11+
12+
-e file:.
13+
linkify-it-py==2.0.3
14+
# via markdown-it-py
15+
markdown-it-py==3.0.0
16+
# via mdit-py-plugins
17+
# via rich
18+
# via textual
19+
mdit-py-plugins==0.4.2
20+
# via markdown-it-py
21+
mdurl==0.1.2
22+
# via markdown-it-py
23+
platformdirs==4.3.6
24+
# via textual
25+
pygments==2.19.1
26+
# via rich
27+
rich==13.9.4
28+
# via textual
29+
textual==1.0.0
30+
# via textual-fspicker
31+
typing-extensions==4.12.2
32+
# via textual
33+
uc-micro-py==1.0.3
34+
# via linkify-it-py

‎setup.cfg

Lines changed: 0 additions & 45 deletions
This file was deleted.

‎textual_fspicker/__init__.py renamed to ‎src/textual_fspicker/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
"""A library that provides a widgets for selecting things from the filesystem."""
1+
"""A library that provides widgets for selecting things from the filesystem."""
2+
3+
##############################################################################
4+
# Python imports.
5+
from importlib.metadata import version
26

37
######################################################################
48
# Main app information.
@@ -7,7 +11,7 @@
711
__credits__ = ["Dave Pearson"]
812
__maintainer__ = "Dave Pearson"
913
__email__ = "davep@davep.org"
10-
__version__ = "0.0.11"
14+
__version__ = version("textual_fspicker")
1115
__licence__ = "MIT"
1216

1317
##############################################################################

‎textual_fspicker/__main__.py renamed to ‎src/textual_fspicker/__main__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
"""Main entry point for testing the library."""
22

33
##############################################################################
4-
# Python imports.
4+
# Backward compatibility.
55
from __future__ import annotations
6+
7+
##############################################################################
8+
# Python imports.
69
from pathlib import Path
710

811
##############################################################################
912
# Textual imports.
1013
from textual import on
1114
from textual.app import App, ComposeResult
1215
from textual.containers import Center, Horizontal
13-
from textual.widgets import Label, Button, Footer
16+
from textual.widgets import Button, Footer, Label
1417

1518
##############################################################################
1619
# Local imports.
@@ -38,8 +41,6 @@ class TestApp(App[None]):
3841
}
3942
"""
4043

41-
BINDINGS = [("d", "toggle_dark", "Light/Dark")]
42-
4344
def compose(self) -> ComposeResult:
4445
"""Compose the layout of the test application."""
4546
with Horizontal():

‎textual_fspicker/base_dialog.py renamed to ‎src/textual_fspicker/base_dialog.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
"""The base dialog code for the other dialogs in the library."""
22

33
##############################################################################
4-
# Python imports.
4+
# Backward compatibility.
55
from __future__ import annotations
66

7+
##############################################################################
8+
# Python imports.
79
import sys
810
from pathlib import Path
911
from typing import Optional
@@ -44,12 +46,17 @@ class FileSystemPickerScreen(ModalScreen[Optional[Path]]):
4446
FileSystemPickerScreen Dialog {
4547
width: 80%;
4648
height: 80%;
47-
border: panel $panel-lighten-2;
48-
background: $panel-lighten-1;
49+
border: $border;
50+
background: $panel;
4951
border-title-color: $text;
50-
border-title-background: $panel-lighten-2;
52+
border-title-background: $panel;
5153
border-subtitle-color: $text;
5254
border-subtitle-background: $error;
55+
56+
OptionList, OptionList:focus {
57+
background: $panel;
58+
background-tint: $panel;
59+
}
5360
}
5461
5562
FileSystemPickerScreen DirectoryNavigation {

‎textual_fspicker/file_dialog.py renamed to ‎src/textual_fspicker/file_dialog.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
"""Base file-oriented dialog."""
22

33
##############################################################################
4-
# Python imports.
4+
# Backward compatibility.
55
from __future__ import annotations
66

7+
##############################################################################
8+
# Python imports.
79
import sys
810
from pathlib import Path
911

@@ -163,8 +165,7 @@ def _confirm_file(self, event: Input.Submitted | Button.Pressed) -> None:
163165
try:
164166
if chosen.is_dir():
165167
if sys.platform == "win32":
166-
drive = MakePath.of(file_name.value).drive
167-
if drive:
168+
if drive := MakePath.of(file_name.value).drive:
168169
self.query_one(DriveNavigation).drive = drive
169170
self.query_one(DirectoryNavigation).location = chosen
170171
self.query_one(DirectoryNavigation).focus()

‎textual_fspicker/file_open.py renamed to ‎src/textual_fspicker/file_open.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
"""Provides a file opening dialog."""
22

33
##############################################################################
4-
# Python imports.
4+
# Backward compatibility.
55
from __future__ import annotations
6+
7+
##############################################################################
8+
# Python imports.
69
from pathlib import Path
710

811
##############################################################################

‎textual_fspicker/file_save.py renamed to ‎src/textual_fspicker/file_save.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
"""Provides a file save dialog."""
22

33
##############################################################################
4-
# Python imports.
4+
# Backward compatibility.
55
from __future__ import annotations
6+
7+
##############################################################################
8+
# Python imports.
69
from pathlib import Path
710

811
##############################################################################

‎textual_fspicker/parts/directory_navigation.py renamed to ‎src/textual_fspicker/parts/directory_navigation.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
"""Provides a widget for directory navigation."""
22

33
##############################################################################
4-
# Python imports.
4+
# Backward compatibility.
55
from __future__ import annotations
66

7+
##############################################################################
8+
# Python imports.
79
from dataclasses import dataclass
810
from datetime import datetime
911
from pathlib import Path
1012
from typing import ClassVar, Iterable, NamedTuple, Optional
11-
from typing_extensions import Final
1213

1314
##############################################################################
1415
# Rich imports.
@@ -25,12 +26,13 @@
2526
from textual.widgets import OptionList
2627
from textual.widgets.option_list import Option
2728
from textual.worker import get_current_worker
29+
from typing_extensions import Final
2830

2931
##############################################################################
3032
# Local imports.
31-
from ..safe_tests import is_dir, is_file, is_symlink
3233
from ..path_filters import Filter
3334
from ..path_maker import MakePath
35+
from ..safe_tests import is_dir, is_file, is_symlink
3436

3537

3638
##############################################################################
@@ -342,7 +344,7 @@ def hide(self, path: Path) -> bool:
342344
# passed so far; not do final checks.
343345
return self.is_hidden(path) and not self.show_hidden
344346

345-
def action_navigate_up(self):
347+
def action_navigate_up(self) -> None:
346348
"""Navigate to the parent location"""
347349
self._location = self._location.parent
348350

‎textual_fspicker/parts/drive_navigation.py renamed to ‎src/textual_fspicker/parts/drive_navigation.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
from dataclasses import dataclass
77
from pathlib import Path
88

9+
##############################################################################
10+
# Import or provide a version of listdrives.
911
try:
1012
from os import listdrives # type: ignore[attr-defined]
1113
except ImportError:
@@ -46,11 +48,17 @@ class DriveEntry(Option):
4648
"""A drive entry for the `DriveNavigation` class."""
4749

4850
def __init__(self, drive: Path | str) -> None:
51+
"""Initialise the object.
52+
53+
Args:
54+
drive: The drive to handle.
55+
"""
4956
self.drive_root: Path = MakePath.of(drive)
5057
"""The drive root for this entry."""
5158
super().__init__(self.drive_root.drive, id=self.drive_root.drive)
5259

5360

61+
##############################################################################
5462
class DriveNavigation(OptionList):
5563
"""A drive navigation widget.
5664

‎textual_fspicker/path_filters.py renamed to ‎src/textual_fspicker/path_filters.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
"""Code to handle the filters for the dialogs."""
22

33
##############################################################################
4-
# Python imports.
4+
# Backward compatibility.
55
from __future__ import annotations
6+
7+
##############################################################################
8+
# Python imports.
69
from pathlib import Path
710
from typing import Callable, NamedTuple
11+
12+
##############################################################################
13+
# Typing extension imports.
814
from typing_extensions import TypeAlias
915

1016
##############################################################################

‎textual_fspicker/path_maker.py renamed to ‎src/textual_fspicker/path_maker.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ class to use when making a fresh Path instance. Designed to allow the use of
77
"""
88

99
##############################################################################
10-
# Python imports.
10+
# Backward compatibility.
1111
from __future__ import annotations
12+
13+
##############################################################################
14+
# Python imports.
1215
from pathlib import Path
1316
from typing import Callable
1417

File renamed without changes.
File renamed without changes.

‎textual_fspicker/select_directory.py renamed to ‎src/textual_fspicker/select_directory.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
"""Provides a directory selection dialog."""
22

33
##############################################################################
4-
# Python imports.
4+
# Backward compatibility.
55
from __future__ import annotations
6+
7+
##############################################################################
8+
# Python imports.
69
from pathlib import Path
710

811
##############################################################################

0 commit comments

Comments
 (0)
Please sign in to comment.