Skip to content

Commit e9bfb48

Browse files
authored
add FTPPath implementation (#485)
* tests: add ftp tests * typesafety: add ftp tests * upath: implement ftp filesystem * update readme and docs * changelog entry * tests: add test for mtime for ftp filesystem * upath._stat: support ftp modification time info format
1 parent 3bffbf2 commit e9bfb48

File tree

16 files changed

+207
-1
lines changed

16 files changed

+207
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
9-
...
9+
### Added
10+
- upath.implementations.ftp: added FTPPath support
1011

1112
## [0.3.6] - 2025-11-13
1213
### Added

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ For more examples, see the [example notebook here][example-notebook].
9191
- `memory:` Ephemeral filesystem in RAM
9292
- `az:`, `adl:`, `abfs:` and `abfss:` Azure Storage _(requires `adlfs`)_
9393
- `data:` RFC 2397 style data URLs _(requires `fsspec>=2023.12.2`)_
94+
- `ftp:` FTP filesystem
9495
- `github:` GitHub repository filesystem
9596
- `hf:` Hugging Face filesystem _(requires `huggingface_hub`)_
9697
- `http:` and `https:` HTTP(S)-based filesystem

docs/api/implementations.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,22 @@ Data URL scheme implementation for embedded data.
252252

253253
---
254254

255+
## upath.implementations.ftp
256+
257+
::: upath.implementations.ftp.FTPPath
258+
options:
259+
heading_level: 3
260+
show_root_heading: true
261+
show_root_full_path: false
262+
members: []
263+
show_bases: true
264+
265+
**Protocol:** `ftp://`
266+
267+
FTP (File Transfer Protocol) implementation.
268+
269+
---
270+
255271
## upath.implementations.cached
256272

257273
::: upath.implementations.cached.SimpleCachePath

docs/api/types.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ These help ensure correct parameter names and types when configuring different f
127127
- S3StorageOptions
128128
- AzureStorageOptions
129129
- DataStorageOptions
130+
- FTPStorageOptions
130131
- GitHubStorageOptions
131132
- HDFSStorageOptions
132133
- HTTPStorageOptions

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ if http_path.exists():
127127
- :fontawesome-solid-memory: `memory:` Ephemeral filesystem in RAM
128128
- :fontawesome-brands-microsoft: `az:`, `adl:`, `abfs:` and `abfss:` Azure Storage _(requires `adlfs`)_
129129
- :fontawesome-solid-database: `data:` RFC 2397 style data URLs _(requires `fsspec>=2023.12.2`)_
130+
- :fontawesome-solid-network-wired: `ftp:` FTP filesystem
130131
- :fontawesome-brands-github: `github:` GitHub repository filesystem
131132
- :fontawesome-solid-globe: `http:` and `https:` HTTP(S)-based filesystem
132133
- :fontawesome-solid-server: `hdfs:` Hadoop distributed filesystem

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ dev = [
6363
"cheroot",
6464
# "hadoop-test-cluster",
6565
# "pyarrow",
66+
"pyftpdlib",
6667
"typing_extensions; python_version<'3.11'",
6768
]
6869
dev-third-party = [

typesafety/test_upath_signatures.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@
7272
cls: HfPath
7373
- module: upath.implementations.data
7474
cls: DataPath
75+
- module: upath.implementations.ftp
76+
cls: FTPPath
7577
- module: upath.implementations.github
7678
cls: GitHubPath
7779
- module: upath.implementations.hdfs
@@ -259,6 +261,8 @@
259261
cls: HfPath
260262
- module: upath.implementations.data
261263
cls: DataPath
264+
- module: upath.implementations.ftp
265+
cls: FTPPath
262266
- module: upath.implementations.github
263267
cls: GitHubPath
264268
- module: upath.implementations.hdfs
@@ -576,6 +580,8 @@
576580
cls: HfPath
577581
- module: upath.implementations.data
578582
cls: DataPath
583+
- module: upath.implementations.ftp
584+
cls: FTPPath
579585
- module: upath.implementations.github
580586
cls: GitHubPath
581587
- module: upath.implementations.hdfs
@@ -972,6 +978,8 @@
972978
cls: HfPath
973979
- module: upath.implementations.data
974980
cls: DataPath
981+
- module: upath.implementations.ftp
982+
cls: FTPPath
975983
- module: upath.implementations.github
976984
cls: GitHubPath
977985
- module: upath.implementations.hdfs

typesafety/test_upath_types.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
protocol: hf
3636
- cls_fqn: upath.implementations.data.DataPath
3737
protocol: data
38+
- cls_fqn: upath.implementations.ftp.FTPPath
39+
protocol: ftp
3840
- cls_fqn: upath.implementations.github.GitHubPath
3941
protocol: github
4042
- cls_fqn: upath.implementations.hdfs.HDFSPath
@@ -112,6 +114,8 @@
112114
protocol: hf
113115
- cls_fqn: upath.implementations.data.DataPath
114116
protocol: data
117+
- cls_fqn: upath.implementations.ftp.FTPPath
118+
protocol: ftp
115119
- cls_fqn: upath.implementations.github.GitHubPath
116120
protocol: github
117121
- cls_fqn: upath.implementations.hdfs.HDFSPath
@@ -185,6 +189,10 @@
185189
cls: DataPath
186190
supported_example_name: use_listings_cache
187191
supported_example_value: False
192+
- module: upath.implementations.ftp
193+
cls: FTPPath
194+
supported_example_name: host
195+
supported_example_value: '"ftp.example.com"'
188196
- module: upath.implementations.github
189197
cls: GitHubPath
190198
supported_example_name: org
@@ -258,6 +266,10 @@
258266
cls: DataPath
259267
supported_example_name: use_listings_cache
260268
unsupported_example_value: '"blub"'
269+
- module: upath.implementations.ftp
270+
cls: FTPPath
271+
supported_example_name: host
272+
unsupported_example_value: '123'
261273
- module: upath.implementations.github
262274
cls: GitHubPath
263275
supported_example_name: repo
@@ -318,6 +330,8 @@
318330
cls: HfPath
319331
- module: upath.implementations.data
320332
cls: DataPath
333+
- module: upath.implementations.ftp
334+
cls: FTPPath
321335
- module: upath.implementations.github
322336
cls: GitHubPath
323337
- module: upath.implementations.hdfs
@@ -367,6 +381,9 @@
367381
- module: upath.implementations.data
368382
cls: DataPath
369383
td: DataStorageOptions
384+
- module: upath.implementations.ftp
385+
cls: FTPPath
386+
td: FTPStorageOptions
370387
- module: upath.implementations.github
371388
cls: GitHubPath
372389
td: GitHubStorageOptions

upath/_stat.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ def _convert_value_to_timestamp(value: Any) -> int | float:
2121
if isinstance(value, (int, float)):
2222
return value
2323
elif isinstance(value, str):
24+
if len(value) == 14:
25+
return datetime.strptime(value, r"%Y%m%d%H%M%S").timestamp()
2426
if value.endswith("Z"):
2527
value = value[:-1] + "+00:00"
2628
return datetime.fromisoformat(value).timestamp()
@@ -262,6 +264,7 @@ def st_mtime(self) -> int | float:
262264
"timeModified",
263265
"modificationTime",
264266
"modified_at",
267+
"modify",
265268
]:
266269
try:
267270
raw_value = self._info[key]

upath/core.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,13 @@ def __new__(
838838
**_: Any,
839839
) -> _uimpl.data.DataPath: ...
840840
@overload # noqa: E301
841+
def __new__(
842+
cls,
843+
*args: JoinablePathLike,
844+
protocol: Literal["ftp"],
845+
**_: Any,
846+
) -> _uimpl.ftp.FTPPath: ...
847+
@overload # noqa: E301
841848
def __new__(
842849
cls,
843850
*args: JoinablePathLike,

0 commit comments

Comments
 (0)