Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/source/trait_types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ Miscellaneous

.. autoclass:: CRegExp

.. autoclass:: Path

.. autoclass:: Union
:members: __init__

Expand Down
16 changes: 16 additions & 0 deletions tests/test_traitlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from __future__ import annotations

import decimal
import pathlib
import pickle
import re
import typing as t
Expand Down Expand Up @@ -44,6 +45,7 @@
Long,
MetaHasTraits,
ObjectName,
Path,
Set,
TCPAddress,
This,
Expand Down Expand Up @@ -1643,6 +1645,20 @@ class TestTCPAddress(TraitTestBase):
_bad_values = [(0, 0), ("localhost", 10.0), ("localhost", -1), None]


class PathTrait(HasTraits):
value = Path()


class TestPath(TraitTestBase):
obj = PathTrait()

_good_values = ["foo", "foo/bar", pathlib.Path("foo"), pathlib.PurePath("foo")]
_bad_values = [0, 10.0, None, ["foo"]]

def coerce(self, value):
return pathlib.Path(value)


class ListTrait(HasTraits):
value = List(Int())

Expand Down
21 changes: 21 additions & 0 deletions traitlets/traitlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import inspect
import numbers
import os
import pathlib
import re
import sys
import types
Expand Down Expand Up @@ -111,6 +112,7 @@
"MetaHasTraits",
"ObjectName",
"ObserveHandler",
"Path",
"Set",
"TCPAddress",
"This",
Expand Down Expand Up @@ -4208,6 +4210,25 @@ def validate(self, obj: t.Any, value: t.Any) -> re.Pattern[t.Any] | None:
self.error(obj, value)


class Path(TraitType["pathlib.Path", t.Union["pathlib.Path", str, "os.PathLike[str]"]]):
"""A trait for filesystem paths.

Accepts strings and :class:`os.PathLike` objects. The resulting
attribute will be a :class:`pathlib.Path` instance."""

info_text = "a filesystem path"

def validate(self, obj: t.Any, value: t.Any) -> pathlib.Path | None:
if isinstance(value, (str, os.PathLike)):
return pathlib.Path(value)
self.error(obj, value)

def from_string(self, s: str) -> pathlib.Path | None:
if self.allow_none and s == "None":
return None
return pathlib.Path(s)


class UseEnum(TraitType[t.Any, t.Any]):
"""Use a Enum class as model for the data type description.
Note that if no default-value is provided, the first enum-value is used
Expand Down
Loading