Skip to content

UPath

The UPath class is your default entry point for interacting with fsspec filesystems. When instantiating UPath, a specific UPath subclass will be returned, dependent on the detected or provided protocol. Here we document all methods and properties available on UPath instances.

Compatibility

All methods documented here work consistently across all supported Python versions, even if they were introduced in later Python versions. We consider it a bug if they don't 🐛 so please report and issue if you run into inconsistencies.

from upath import UPath

upath.core.UPath

Bases: _UPathMixin, WritablePath, ReadablePath

Base class for pathlike paths backed by an fsspec filesystem.

Note

The following attributes and methods are specific to UPath instances and are not available on pathlib.Path instances.

ATTRIBUTE DESCRIPTION
protocol

The fsspec protocol for the path.

TYPE: str

storage_options

The fsspec storage options for the path.

TYPE: Mapping[str, Any]

path

The path that a fsspec filesystem can use.

TYPE: str

fs

The cached fsspec filesystem instance for the path.

TYPE: AbstractFileSystem

METHOD DESCRIPTION
joinuri

Join URI parts to this path.

Info

Below are pathlib attributes and methods available on UPath instances.

ATTRIBUTE DESCRIPTION
drive

The drive component of the path.

TYPE: str

root

The root component of the path.

TYPE: str

anchor

The concatenation of the drive and root.

TYPE: str

parent

The logical parent of the path.

TYPE: Self

parents

An immutable sequence providing access to the logical ancestors of the path.

TYPE: Sequence[Self]

name

The final path component, excluding the drive and root, if any.

TYPE: str

suffix

The file extension of the final component, if any.

TYPE: str

suffixes

A list of the path's file extensions.

TYPE: list[str]

stem

The final path component, without its suffix.

TYPE: str

info

Filesystem information about the path.

TYPE: PathInfo

parser

The path parser instance for parsing path segments.

TYPE: UPathParser

METHOD DESCRIPTION
__truediv__

Combine this path with the argument using the / operator.

__rtruediv__

Combine the argument with this path using the / operator.

as_posix

Return the string representation of the path with forward slashes.

is_absolute

Return True if the path is absolute.

is_relative_to

Return True if the path is relative to another path.

is_reserved

Return True if the path is reserved under Windows.

joinpath

Combine this path with one or several arguments, and return a new path.

full_match

Match this path against the provided glob-style pattern.

match

Match this path against the provided glob-style pattern.

relative_to

Return a version of this path relative to another path.

with_name

Return a new path with the name changed.

with_stem

Return a new path with the stem changed.

with_suffix

Return a new path with the suffix changed.

with_segments

Construct a new path object from any number of path-like objects.

from_uri

Return a new path from the given URI.

as_uri

Return the path as a URI.

home

Return a new path pointing to the user's home directory.

expanduser

Return a new path with expanded ~ constructs.

cwd

Return a new path pointing to the current working directory.

absolute

Make the path absolute, without normalization or resolving symlinks.

resolve

Make the path absolute, resolving any symlinks.

readlink

Return the path to which the symbolic link points.

stat

Return the result of the stat() system call on this path.

lstat

Like stat(), but if the path points to a symlink, return the symlink's information.

exists

Return True if the path exists.

is_file

Return True if the path is a regular file.

is_dir

Return True if the path is a directory.

is_symlink

Return True if the path is a symbolic link.

is_junction

Return True if the path is a junction.

is_mount

Return True if the path is a mount point.

is_socket

Return True if the path is a socket.

is_fifo

Return True if the path is a FIFO.

is_block_device

Return True if the path is a block device.

is_char_device

Return True if the path is a character device.

samefile

Return True if this path points to the same file as other_path.

open

Open the file pointed to by the path.

read_text

Open the file in text mode, read it, and close the file.

read_bytes

Open the file in bytes mode, read it, and close the file.

write_text

Open the file in text mode, write to it, and close the file.

write_bytes

Open the file in bytes mode, write to it, and close the file.

iterdir

Yield path objects of the directory contents.

glob

Iterate over this subtree and yield all existing files matching the given pattern.

rglob

Recursively yield all existing files matching the given pattern.

walk

Generate the file names in a directory tree by walking the tree.

touch

Create this file with the given access mode, if it doesn't exist.

mkdir

Create a new directory at this given path.

symlink_to

Make this path a symbolic link pointing to target.

hardlink_to

Make this path a hard link pointing to the same file as target.

copy

Copy the contents of this file to the target file.

copy_into

Copy this file or directory into the target directory.

rename

Rename this path to the target path.

replace

Rename this path to the target path, overwriting if that path exists.

move

Move this file or directory tree to the target path.

move_into

Move this file or directory into the target directory.

unlink

Remove this file or link.

rmdir

Remove this directory.

owner

Return the login name of the file owner.

group

Return the group name of the file gid.

chmod

Change the permissions of the path.

lchmod

Like chmod() but, if the path points to a symlink, modify the symlink's permissions.

Source code in upath/core.py
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
class UPath(_UPathMixin, WritablePath, ReadablePath):
    """Base class for pathlike paths backed by an fsspec filesystem.

    Note
    ----
    The following attributes and methods are specific to UPath instances and are not
    available on pathlib.Path instances.

    Attributes
    ----------
    protocol :
        The fsspec protocol for the path.
    storage_options :
        The fsspec storage options for the path.
    path :
        The path that a fsspec filesystem can use.
    fs :
        The cached fsspec filesystem instance for the path.

    Methods
    -------
    joinuri(*parts) :
        Join URI parts to this path.


    Info
    ----
    Below are pathlib attributes and methods available on UPath instances.

    Attributes
    ----------
    drive :
        The drive component of the path.
    root :
        The root component of the path.
    anchor :
        The concatenation of the drive and root.
    parent :
        The logical parent of the path.
    parents :
        An immutable sequence providing access to the logical ancestors of the path.
    name :
        The final path component, excluding the drive and root, if any.
    suffix :
        The file extension of the final component, if any.
    suffixes :
        A list of the path's file extensions.
    stem :
        The final path component, without its suffix.
    info :
        Filesystem information about the path.
    parser :
        The path parser instance for parsing path segments.

    Methods
    -------
    __truediv__(key) :
        Combine this path with the argument using the `/` operator.
    __rtruediv__(key) :
        Combine the argument with this path using the `/` operator.
    as_posix() :
        Return the string representation of the path with forward slashes.
    is_absolute() :
        Return True if the path is absolute.
    is_relative_to(other) :
        Return True if the path is relative to another path.
    is_reserved() :
        Return True if the path is reserved under Windows.
    joinpath(*pathsegments) :
        Combine this path with one or several arguments, and return a new path.
    full_match(pattern, *, case_sensitive=None) :
        Match this path against the provided glob-style pattern.
    match(pattern, *, case_sensitive=None) :
        Match this path against the provided glob-style pattern.
    relative_to(other, walk_up=False) :
        Return a version of this path relative to another path.
    with_name(name) :
        Return a new path with the name changed.
    with_stem(stem) :
        Return a new path with the stem changed.
    with_suffix(suffix) :
        Return a new path with the suffix changed.
    with_segments(*pathsegments) :
        Construct a new path object from any number of path-like objects.
    from_uri(uri) :
        Return a new path from the given URI.
    as_uri() :
        Return the path as a URI.
    home() :
        Return a new path pointing to the user's home directory.
    expanduser() :
        Return a new path with expanded `~` constructs.
    cwd() :
        Return a new path pointing to the current working directory.
    absolute() :
        Make the path absolute, without normalization or resolving symlinks.
    resolve(strict=False) :
        Make the path absolute, resolving any symlinks.
    readlink() :
        Return the path to which the symbolic link points.
    stat(*, follow_symlinks=True) :
        Return the result of the stat() system call on this path.
    lstat() :
        Like stat(), but if the path points to a symlink, return the symlink's
        information.
    exists(*, follow_symlinks=True) :
        Return True if the path exists.
    is_file(*, follow_symlinks=True) :
        Return True if the path is a regular file.
    is_dir(*, follow_symlinks=True) :
        Return True if the path is a directory.
    is_symlink() :
        Return True if the path is a symbolic link.
    is_junction() :
        Return True if the path is a junction.
    is_mount() :
        Return True if the path is a mount point.
    is_socket() :
        Return True if the path is a socket.
    is_fifo() :
        Return True if the path is a FIFO.
    is_block_device() :
        Return True if the path is a block device.
    is_char_device() :
        Return True if the path is a character device.
    samefile(other_path) :
        Return True if this path points to the same file as other_path.
    open(mode='r', buffering=-1, encoding=None, errors=None, newline=None) :
        Open the file pointed to by the path.
    read_text(encoding=None, errors=None, newline=None) :
        Open the file in text mode, read it, and close the file.
    read_bytes() :
        Open the file in bytes mode, read it, and close the file.
    write_text(data, encoding=None, errors=None, newline=None) :
        Open the file in text mode, write to it, and close the file.
    write_bytes(data) :
        Open the file in bytes mode, write to it, and close the file.
    iterdir() :
        Yield path objects of the directory contents.
    glob(pattern, *, case_sensitive=None) :
        Iterate over this subtree and yield all existing files matching the
        given pattern.
    rglob(pattern, *, case_sensitive=None) :
        Recursively yield all existing files matching the given pattern.
    walk(top_down=True, on_error=None, follow_symlinks=False) :
        Generate the file names in a directory tree by walking the tree.
    touch(mode=0o666, exist_ok=True) :
        Create this file with the given access mode, if it doesn't exist.
    mkdir(mode=0o777, parents=False, exist_ok=False) :
        Create a new directory at this given path.
    symlink_to(target, target_is_directory=False) :
        Make this path a symbolic link pointing to target.
    hardlink_to(target) :
        Make this path a hard link pointing to the same file as target.
    copy(target, *, follow_symlinks=True, preserve_metadata=False) :
        Copy the contents of this file to the target file.
    copy_into(target_dir, *, follow_symlinks=True, preserve_metadata=False) :
        Copy this file or directory into the target directory.
    rename(target) :
        Rename this path to the target path.
    replace(target) :
        Rename this path to the target path, overwriting if that path exists.
    move(target) :
        Move this file or directory tree to the target path.
    move_into(target_dir) :
        Move this file or directory into the target directory.
    unlink(missing_ok=False) :
        Remove this file or link.
    rmdir() :
        Remove this directory.
    owner(*, follow_symlinks=True) :
        Return the login name of the file owner.
    group(*, follow_symlinks=True) :
        Return the group name of the file gid.
    chmod(mode, *, follow_symlinks=True) :
        Change the permissions of the path.
    lchmod(mode) :
        Like chmod() but, if the path points to a symlink, modify the symlink's
        permissions.

    """

    __slots__ = (
        "_chain",
        "_chain_parser",
        "_fs_cached",
        "_raw_urlpaths",
        "_relative_base",
    )

    if TYPE_CHECKING:  # noqa: C901
        _chain: Chain
        _chain_parser: FSSpecChainParser
        _fs_cached: AbstractFileSystem
        _raw_urlpaths: Sequence[JoinablePathLike]
        _relative_base: str | None

        @overload
        def __new__(
            cls,
        ) -> Self: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["simplecache"],
            **_: Any,
        ) -> _uimpl.cached.SimpleCachePath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["gcs", "gs"],
            **_: Any,
        ) -> _uimpl.cloud.GCSPath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["s3", "s3a"],
            **_: Any,
        ) -> _uimpl.cloud.S3Path: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["az", "abfs", "abfss", "adl"],
            **_: Any,
        ) -> _uimpl.cloud.AzurePath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["hf"],
            **_: Any,
        ) -> _uimpl.cloud.HfPath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["data"],
            **_: Any,
        ) -> _uimpl.data.DataPath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["ftp"],
            **_: Any,
        ) -> _uimpl.ftp.FTPPath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["github"],
            **_: Any,
        ) -> _uimpl.github.GitHubPath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["hdfs"],
            **_: Any,
        ) -> _uimpl.hdfs.HDFSPath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["http", "https"],
            **_: Any,
        ) -> _uimpl.http.HTTPPath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["file", "local"],
            **_: Any,
        ) -> _uimpl.local.FilePath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["memory"],
            **_: Any,
        ) -> _uimpl.memory.MemoryPath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["sftp", "ssh"],
            **_: Any,
        ) -> _uimpl.sftp.SFTPPath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["smb"],
            **_: Any,
        ) -> _uimpl.smb.SMBPath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["tar"],
            **_: Any,
        ) -> _uimpl.tar.TarPath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["webdav"],
            **_: Any,
        ) -> _uimpl.webdav.WebdavPath: ...
        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: Literal["zip"],
            **_: Any,
        ) -> _uimpl.zip.ZipPath: ...

        if sys.platform == "win32":

            @overload  # noqa: E301
            def __new__(
                cls,
                *args: JoinablePathLike,
                protocol: Literal[""],
                **_: Any,
            ) -> _uimpl.local.WindowsUPath: ...

        else:

            @overload  # noqa: E301
            def __new__(
                cls,
                *args: JoinablePathLike,
                protocol: Literal[""],
                **_: Any,
            ) -> _uimpl.local.PosixUPath: ...

        @overload  # noqa: E301
        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: str | None = ...,
            **_: Any,
        ) -> Self: ...

        def __new__(
            cls,
            *args: JoinablePathLike,
            protocol: str | None = ...,
            chain_parser: FSSpecChainParser = ...,
            **storage_options: Any,
        ) -> Self: ...

    # === JoinablePath attributes =====================================

    parser: UPathParser = LazyFlavourDescriptor()  # type: ignore[assignment]

    def with_segments(self, *pathsegments: JoinablePathLike) -> Self:
        """Construct a new path object from any number of path-like objects."""
        # we change joinpath behavior if called from a relative path
        # this is not fully ideal, but currently the best way to move forward
        if is_relative := self._relative_base is not None:
            pathsegments = (self._relative_base, *pathsegments)

        new_instance = type(self)(
            *pathsegments,
            protocol=self._protocol,
            **self.storage_options,
        )
        if hasattr(self, "_fs_cached"):
            new_instance._fs_cached = self._fs_cached

        if is_relative:
            new_instance._relative_base = self._relative_base
        return new_instance

    def __str__(self) -> str:
        if self._relative_base is not None:
            active_path = self._chain.active_path
            stripped_base = self.parser.strip_protocol(
                self._relative_base
            ).removesuffix(self.parser.sep)
            if not active_path.startswith(stripped_base):
                raise RuntimeError(
                    f"{active_path!r} is not a subpath of {stripped_base!r}"
                )

            return (
                active_path.removeprefix(stripped_base).removeprefix(self.parser.sep)
                or "."
            )
        else:
            return self._chain_parser.chain(self._chain.to_list())[0]

    def __vfspath__(self) -> str:
        if self._relative_base is not None:
            return self.__str__()
        else:
            return self.path

    def __repr__(self) -> str:
        cls_name = type(self).__name__
        path = self.__vfspath__()
        if self._relative_base is not None:
            return f"<relative {cls_name} {path!r}>"
        else:
            return f"{cls_name}({path!r}, protocol={self._protocol!r})"

    # === JoinablePath overrides ======================================

    @property
    def parts(self) -> Sequence[str]:
        """Provides sequence-like access to the filesystem path components.

        Examples
        --------
        >>> from upath import UPath
        >>> p = UPath("s3://my-bucket/path/to/file.txt")
        >>> p.parts
        ('my-bucket/', 'path', 'to', 'file.txt')
        >>> p2 = UPath("/foo/bar/baz.txt", protocol="memory")
        >>> p2.parts
        ('/', 'foo', 'bar', 'baz.txt')

        """
        # For relative paths, return parts of the relative path only
        if self._relative_base is not None:
            rel_str = str(self)
            if rel_str == ".":
                return ()
            return tuple(rel_str.split(self.parser.sep))

        split = self.parser.split
        sep = self.parser.sep

        path = self._chain.active_path
        drive = self.parser.splitdrive(self._chain.active_path)[0]
        stripped_path = self.parser.strip_protocol(path)
        if stripped_path:
            _, _, tail = path.partition(stripped_path)
            path = stripped_path + tail

        parent, name = split(path)
        names = []
        while path != parent:
            names.append(name)
            path = parent
            parent, name = split(path)

        if names and names[-1] == drive:
            names = names[:-1]
        if names and names[-1].startswith(sep):
            parts = [*names[:-1], names[-1].removeprefix(sep), drive + sep]
        else:
            parts = [*names, drive + sep]
        return tuple(reversed(parts))

    def with_name(self, name: str) -> Self:
        """Return a new path with the file name changed."""
        split = self.parser.split
        if self.parser.sep in name:  # `split(name)[0]`
            raise ValueError(f"Invalid name {name!r}")
        _path = self.__vfspath__()
        _path = _path.removesuffix(split(_path)[1]) + name
        return self.with_segments(_path)

    @property
    def anchor(self) -> str:
        """The concatenation of the drive and root or an empty string."""
        if self._relative_base is not None:
            return ""
        return self.drive + self.root

    @property
    def parent(self) -> Self:
        """The logical parent of the path.

        Examples
        --------
        >>> from upath import UPath
        >>> p = UPath("s3://my-bucket/path/to/file.txt")
        >>> p.parent
        S3Path('s3://my-bucket/path/to')

        """
        if self._relative_base is not None:
            if str(self) == ".":
                return self
            else:
                # this needs to be revisited...
                pth = type(self)(
                    self._relative_base,
                    str(self),
                    protocol=self._protocol,
                    **self.storage_options,
                )
                parent = pth.parent
                parent._relative_base = self._relative_base
                return parent
        return super().parent

    @property
    def parents(self) -> Sequence[Self]:
        """A sequence providing access to the logical ancestors of the path.

        Examples
        --------
        >>> from upath import UPath
        >>> p = UPath("memory:///foo/bar/baz.txt")
        >>> list(p.parents)
        [
          MemoryPath('memory:///foo/bar'),
          MemoryPath('memory:///foo'),
          MemoryPath('memory:///'),
        ]

        """
        if self._relative_base is not None:
            parents = []
            parent = self
            while True:
                if str(parent) == ".":
                    break
                parent = parent.parent
                parents.append(parent)
            return tuple(parents)
        return super().parents

    def joinpath(self, *pathsegments: JoinablePathLike) -> Self:
        """Combine this path with one or several arguments, and return a new path.

        For one argument, this is equivalent to using the `/` operator.

        Examples
        --------
        >>> from upath import UPath
        >>> p = UPath("s3://my-bucket/path/to")
        >>> p.joinpath("file.txt")
        S3Path('s3://my-bucket/path/to/file.txt')

        """
        return self.with_segments(self.__vfspath__(), *pathsegments)

    def __truediv__(self, key: JoinablePathLike) -> Self:
        try:
            return self.with_segments(self.__vfspath__(), key)
        except TypeError:
            return NotImplemented

    def __rtruediv__(self, key: JoinablePathLike) -> Self:
        try:
            return self.with_segments(key, self.__vfspath__())
        except TypeError:
            return NotImplemented

    # === ReadablePath attributes =====================================

    @property
    def info(self) -> PathInfo:
        """
        A PathInfo object that exposes the file type and other file attributes
        of this path.

        Returns
        -------
        : UPathInfo
            The UPathInfo object for this path.
        """
        return UPathInfo(self)

    def iterdir(self) -> Iterator[Self]:
        """Yield path objects of the directory contents.

        Examples
        --------
        >>> from upath import UPath
        >>> p = UPath("memory:///foo/")
        >>> p.joinpath("bar.txt").touch()
        >>> p.joinpath("baz.txt").touch()
        >>> for child in p.iterdir():
        ...     print(child)
        MemoryPath('memory:///foo/bar.txt')
        MemoryPath('memory:///foo/baz.txt')

        """
        sep = self.parser.sep
        base = self
        if self.parts[-1:] == ("",):
            base = self.parent
        fs = base.fs
        base_path = base.path
        if not fs.isdir(base_path):
            raise NotADirectoryError(str(self))
        for name in fs.listdir(base_path):
            # fsspec returns dictionaries
            if isinstance(name, dict):
                name = name.get("name")
            if name in {".", ".."}:
                # Yielding a path object for these makes little sense
                continue
            # only want the path name with iterdir
            _, _, name = name.removesuffix(sep).rpartition(self.parser.sep)
            yield base.with_segments(base_path, name)

    def __open_reader__(self) -> BinaryIO:
        return self.fs.open(self.path, mode="rb")

    if sys.version_info >= (3, 14):

        def __open_rb__(self, buffering: int = UNSET_DEFAULT) -> BinaryIO:
            return self.open("rb", buffering=buffering)

    def readlink(self) -> Self:
        _raise_unsupported(type(self).__name__, "readlink")

    @overload
    def copy(self, target: _WT, **kwargs: Any) -> _WT: ...

    @overload
    def copy(self, target: SupportsPathLike | str, **kwargs: Any) -> Self: ...

    def copy(self, target: _WT | SupportsPathLike | str, **kwargs: Any) -> _WT | UPath:
        """
        Recursively copy this file or directory tree to the given destination.
        """
        if isinstance(target, str):
            proto = get_upath_protocol(target)
            if proto != self.protocol:
                target = UPath(target)
            else:
                target = self.with_segments(target)
        elif not isinstance(target, UPath):
            target = UPath(target)
        if target.is_dir():
            raise IsADirectoryError(str(target))
        return super().copy(target, **kwargs)

    @overload
    def copy_into(self, target_dir: _WT, **kwargs: Any) -> _WT: ...

    @overload
    def copy_into(self, target_dir: SupportsPathLike | str, **kwargs: Any) -> Self: ...

    def copy_into(
        self, target_dir: _WT | SupportsPathLike | str, **kwargs: Any
    ) -> _WT | UPath:
        """
        Copy this file or directory tree into the given existing directory.
        """
        if isinstance(target_dir, str):
            proto = get_upath_protocol(target_dir)
            if proto != self.protocol:
                target_dir = UPath(target_dir)
            else:
                target_dir = self.with_segments(target_dir)
        elif not isinstance(target_dir, UPath):
            target_dir = UPath(target_dir)
        if not target_dir.exists():
            raise FileNotFoundError(str(target_dir))
        if not target_dir.is_dir():
            raise NotADirectoryError(str(target_dir))
        return super().copy_into(target_dir, **kwargs)

    @overload
    def move(self, target: _WT, **kwargs: Any) -> _WT: ...

    @overload
    def move(self, target: SupportsPathLike | str, **kwargs: Any) -> Self: ...

    def move(self, target: _WT | SupportsPathLike | str, **kwargs: Any) -> _WT | UPath:
        """
        Recursively move this file or directory tree to the given destination.
        """
        target = self.copy(target, **kwargs)
        self.fs.rm(self.path, recursive=self.is_dir())
        return target

    @overload
    def move_into(self, target_dir: _WT, **kwargs: Any) -> _WT: ...

    @overload
    def move_into(self, target_dir: SupportsPathLike | str, **kwargs: Any) -> Self: ...

    def move_into(
        self, target_dir: _WT | SupportsPathLike | str, **kwargs: Any
    ) -> _WT | UPath:
        """
        Move this file or directory tree into the given existing directory.
        """
        name = self.name
        if not name:
            raise ValueError(f"{self!r} has an empty name")
        elif hasattr(target_dir, "with_segments"):
            target = target_dir.with_segments(target_dir, name)  # type: ignore
        elif isinstance(target_dir, PurePath):
            target = UPath(target_dir, name)
        else:
            target = self.with_segments(target_dir, name)
        td = target.parent
        if not td.exists():
            raise FileNotFoundError(str(td))
        elif not td.is_dir():
            raise NotADirectoryError(str(td))
        return self.move(target)

    def _copy_from(
        self,
        source: ReadablePath,
        follow_symlinks: bool = True,
        on_name_collision: OnNameCollisionFunc | None = None,
        **kwargs: Any,
    ) -> None:
        """
        UPath custom:: Recursively copy the given path to this path.
        """
        # fixme: it would be best if this would be upstreamed
        from pathlib_abc import vfsopen
        from pathlib_abc import vfspath
        from pathlib_abc._os import copyfileobj
        from pathlib_abc._os import ensure_different_files

        stack: list[tuple[ReadablePath, WritablePath]] = [(source, self)]
        while stack:
            src, dst = stack.pop()
            info = src.info
            if not follow_symlinks and info.is_symlink():
                dst.symlink_to(vfspath(src.readlink()), src.info.is_dir())
            elif on_name_collision and info.is_file() and info.is_dir():
                dst_file, dst_dir = on_name_collision(src, dst)
                if dst_file is not None:
                    ensure_different_files(src, dst_file)
                    with vfsopen(src, "rb") as source_f:
                        with vfsopen(dst_file, "wb") as target_f:
                            copyfileobj(source_f, target_f)
                if dst_dir is not None:
                    children = src.iterdir()
                    dst_dir.mkdir()
                    # feed through dict.fromkeys to remove duplicates
                    for child in dict.fromkeys(children):
                        stack.append((child, dst_dir.joinpath(child.name)))
            elif info.is_dir():
                children = src.iterdir()
                dst.mkdir()
                # feed through dict.fromkeys to remove duplicates
                for child in dict.fromkeys(children):
                    stack.append((child, dst.joinpath(child.name)))
            else:
                ensure_different_files(src, dst)
                with vfsopen(src, "rb") as source_f:
                    with vfsopen(dst, "wb") as target_f:
                        copyfileobj(source_f, target_f)

    # --- WritablePath attributes -------------------------------------

    def symlink_to(
        self,
        target: ReadablePathLike,
        target_is_directory: bool = False,
    ) -> None:
        _raise_unsupported(type(self).__name__, "symlink_to")

    def mkdir(
        self,
        mode: int = 0o777,
        parents: bool = False,
        exist_ok: bool = False,
    ) -> None:
        """
        Create a new directory at this given path.
        """
        if parents and not exist_ok and self.exists():
            raise FileExistsError(str(self))
        try:
            self.fs.mkdir(
                self.path,
                create_parents=parents,
                mode=mode,
            )
        except FileExistsError:
            if not exist_ok:
                raise FileExistsError(str(self))
            if not self.is_dir():
                raise FileExistsError(str(self))

    def __open_writer__(self, mode: Literal["a", "w", "x"]) -> BinaryIO:
        return self.fs.open(self.path, mode=f"{mode}b")

    # --- upath overrides ---------------------------------------------

    @overload
    def open(
        self,
        mode: Literal["r", "w", "a"] = ...,
        buffering: int = ...,
        encoding: str = ...,
        errors: str = ...,
        newline: str = ...,
        **fsspec_kwargs: Any,
    ) -> TextIO: ...

    @overload
    def open(
        self,
        mode: Literal["rb", "wb", "ab"] = ...,
        buffering: int = ...,
        encoding: str = ...,
        errors: str = ...,
        newline: str = ...,
        **fsspec_kwargs: Any,
    ) -> BinaryIO: ...

    @overload
    def open(
        self,
        mode: str = ...,
        buffering: int = ...,
        encoding: str | None = ...,
        errors: str | None = ...,
        newline: str | None = ...,
        **fsspec_kwargs: Any,
    ) -> IO[Any]: ...

    def open(
        self,
        mode: str = "r",
        buffering: int = UNSET_DEFAULT,
        encoding: str | None = UNSET_DEFAULT,
        errors: str | None = UNSET_DEFAULT,
        newline: str | None = UNSET_DEFAULT,
        **fsspec_kwargs: Any,
    ) -> IO[Any]:
        """
        Open the file pointed by this path and return a file object, as
        the built-in open() function does.

        Parameters
        ----------
        mode:
            Opening mode. Default is 'r'.
        buffering:
            Default is the block size of the underlying fsspec filesystem.
        encoding:
            Encoding is only used in text mode. Default is None.
        errors:
            Error handling for encoding. Only used in text mode. Default is None.
        newline:
            Newline handling. Only used in text mode. Default is None.
        **fsspec_kwargs:
            Additional options for the fsspec filesystem.
        """
        # match the signature of pathlib.Path.open()
        if buffering is not UNSET_DEFAULT:
            if "block_size" in fsspec_kwargs:
                raise TypeError("cannot specify both 'buffering' and 'block_size'")
            block_size = _buffering2blocksize(mode, buffering)
            if block_size is not None:
                fsspec_kwargs.setdefault("block_size", block_size)
        if encoding is not UNSET_DEFAULT:
            fsspec_kwargs["encoding"] = encoding
        if errors is not UNSET_DEFAULT:
            fsspec_kwargs["errors"] = errors
        if newline is not UNSET_DEFAULT:
            fsspec_kwargs["newline"] = newline
        return self.fs.open(self.path, mode=mode, **fsspec_kwargs)

    # === pathlib.Path ================================================

    def stat(
        self,
        *,
        follow_symlinks: bool = True,
    ) -> StatResultType:
        """
        Return the result of the stat() system call on this path, like
        os.stat() does.

        Info
        ----
        For fsspec filesystems follow_symlinks is currently ignored.

        Returns
        -------
        : UPathStatResult
            The upath stat result for this path, emulating `os.stat_result`.

        """
        if not follow_symlinks:
            warnings.warn(
                f"{type(self).__name__}.stat(follow_symlinks=False):"
                " is currently ignored.",
                UserWarning,
                stacklevel=2,
            )
        return UPathStatResult.from_info(self.fs.info(self.path))

    def lstat(self) -> StatResultType:
        return self.stat(follow_symlinks=False)

    def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None:
        _raise_unsupported(type(self).__name__, "chmod")

    def exists(self, *, follow_symlinks: bool = True) -> bool:
        """
        Whether this path exists.

        Info
        ----
        For fsspec filesystems follow_symlinks is currently ignored.
        """
        if not follow_symlinks:
            warnings.warn(
                f"{type(self).__name__}.exists() follow_symlinks=False"
                " is currently ignored.",
                UserWarning,
                stacklevel=2,
            )
        return self.fs.exists(self.path)

    def is_dir(self, *, follow_symlinks: bool = True) -> bool:
        """
        Whether this path is a directory.
        """
        if not follow_symlinks:
            warnings.warn(
                f"{type(self).__name__}.is_dir() follow_symlinks=False"
                " is currently ignored.",
                UserWarning,
                stacklevel=2,
            )
        return self.fs.isdir(self.path)

    def is_file(self, *, follow_symlinks: bool = True) -> bool:
        """
        Whether this path is a regular file.
        """
        if not follow_symlinks:
            warnings.warn(
                f"{type(self).__name__}.is_file() follow_symlinks=False"
                " is currently ignored.",
                UserWarning,
                stacklevel=2,
            )
        return self.fs.isfile(self.path)

    def is_mount(self) -> bool:
        """
        Check if this path is a mount point

        Info
        ----
        For fsspec filesystems this is always False.
        """
        return False

    def is_symlink(self) -> bool:
        """
        Whether this path is a symbolic link.
        """
        try:
            info = self.fs.info(self.path)
            if "islink" in info:
                return bool(info["islink"])
        except FileNotFoundError:
            return False
        return False

    def is_junction(self) -> bool:
        """
        Whether this path is a junction.

        Info
        ----
        For fsspec filesystems this is always False.
        """
        return False

    def is_block_device(self) -> bool:
        """
        Whether this path is a block device.

        Info
        ----
        For fsspec filesystems this is always False.
        """
        return False

    def is_char_device(self) -> bool:
        """
        Whether this path is a character device.

        Info
        ----
        For fsspec filesystems this is always False.
        """
        return False

    def is_fifo(self) -> bool:
        """
        Whether this path is a FIFO (named pipe).

        Info
        ----
        For fsspec filesystems this is always False.
        """
        return False

    def is_socket(self) -> bool:
        """
        Whether this path is a socket.

        Info
        ----
        For fsspec filesystems this is always False.
        """
        return False

    def is_reserved(self) -> bool:
        """
        Whether this path is reserved under Windows.

        Info
        ----
        For fsspec filesystems this is always False.
        """
        return False

    def expanduser(self) -> Self:
        """Return a new path with expanded `~` constructs.

        Info
        ----
        For fsspec filesystems this is currently a no-op.
        """
        return self

    def glob(
        self,
        pattern: str,
        *,
        case_sensitive: bool | None = None,
        recurse_symlinks: bool = False,
    ) -> Iterator[Self]:
        """Iterate over this subtree and yield all existing files (of any
        kind, including directories) matching the given relative pattern."""
        if case_sensitive is not None:
            warnings.warn(
                "UPath.glob(): case_sensitive is currently ignored.",
                UserWarning,
                stacklevel=2,
            )
        if recurse_symlinks:
            warnings.warn(
                "UPath.glob(): recurse_symlinks=True is currently ignored.",
                UserWarning,
                stacklevel=2,
            )
        if self._relative_base is not None:
            self = self.absolute()
        path_pattern = self.joinpath(pattern).path
        sep = self.parser.sep
        base = self.path
        for name in self.fs.glob(path_pattern):
            name = name.removeprefix(base).removeprefix(sep)
            yield self.joinpath(name)

    def rglob(
        self,
        pattern: str,
        *,
        case_sensitive: bool | None = None,
        recurse_symlinks: bool = False,
    ) -> Iterator[Self]:
        """Recursively yield all existing files (of any kind, including
        directories) matching the given relative pattern, anywhere in
        this subtree.
        """
        if case_sensitive is not None:
            warnings.warn(
                "UPath.glob(): case_sensitive is currently ignored.",
                UserWarning,
                stacklevel=2,
            )
        if recurse_symlinks:
            warnings.warn(
                "UPath.glob(): recurse_symlinks=True is currently ignored.",
                UserWarning,
                stacklevel=2,
            )
        if _FSSPEC_HAS_WORKING_GLOB is None:
            _check_fsspec_has_working_glob()

        if _FSSPEC_HAS_WORKING_GLOB:
            r_path_pattern = self.joinpath("**", pattern).path
            sep = self.parser.sep
            base = self.path
            for name in self.fs.glob(r_path_pattern):
                name = name.removeprefix(base).removeprefix(sep)
                yield self.joinpath(name)

        else:
            path_pattern = self.joinpath(pattern).path
            r_path_pattern = self.joinpath("**", pattern).path
            sep = self.parser.sep
            base = self.path
            seen = set()
            for p in (path_pattern, r_path_pattern):
                for name in self.fs.glob(p):
                    name = name.removeprefix(base).removeprefix(sep)
                    if name in seen:
                        continue
                    else:
                        seen.add(name)
                        yield self.joinpath(name)

    def owner(self, *, follow_symlinks: bool = True) -> str:
        _raise_unsupported(type(self).__name__, "owner")

    def group(self, *, follow_symlinks: bool = True) -> str:
        _raise_unsupported(type(self).__name__, "group")

    def absolute(self) -> Self:
        """Return an absolute version of this path
        No normalization or symlink resolution is performed.

        Use resolve() to resolve symlinks and remove '..' segments.
        """
        if self._relative_base is not None:
            return self.cwd().joinpath(self.__vfspath__())
        return self

    def is_absolute(self) -> bool:
        """True if the path is absolute (has both a root and, if applicable,
        a drive)."""
        if self._relative_base is not None:
            return False
        else:
            return self.parser.isabs(self.__vfspath__())

    def __eq__(self, other: object) -> bool:
        """UPaths are considered equal if their protocol, path and
        storage_options are equal."""
        if not isinstance(other, UPath):
            return NotImplemented

        # For relative paths, compare the string representation instead of path
        if (
            self._relative_base is not None
            or getattr(other, "_relative_base", None) is not None
        ):
            # If both are relative paths, compare just the relative strings
            if (
                self._relative_base is not None
                and getattr(other, "_relative_base", None) is not None
            ):
                return str(self) == str(other)
            else:
                # One is relative, one is not - they can't be equal
                return False

        return (
            self.__vfspath__() == other.__vfspath__()
            and self.protocol == other.protocol
            and self.storage_options == other.storage_options
        )

    def __hash__(self) -> int:
        """The returned hash is based on the protocol and path only.

        Note: in the future, if hash collisions become an issue, we
          can add `fsspec.utils.tokenize(storage_options)`
        """
        return hash((self.protocol, self.__vfspath__()))

    def __lt__(self, other: object) -> bool:
        if not isinstance(other, UPath) or self.parser is not other.parser:
            return NotImplemented
        return self.__vfspath__() < other.__vfspath__()

    def __le__(self, other: object) -> bool:
        if not isinstance(other, UPath) or self.parser is not other.parser:
            return NotImplemented
        return self.__vfspath__() <= other.__vfspath__()

    def __gt__(self, other: object) -> bool:
        if not isinstance(other, UPath) or self.parser is not other.parser:
            return NotImplemented
        return self.__vfspath__() > other.__vfspath__()

    def __ge__(self, other: object) -> bool:
        if not isinstance(other, UPath) or self.parser is not other.parser:
            return NotImplemented
        return self.__vfspath__() >= other.__vfspath__()

    def resolve(self, strict: bool = False) -> Self:
        """
        Make the path absolute, resolving all symlinks on the way and also
        normalizing it.
        """
        if self._relative_base is not None:
            self = self.absolute()
        _parts = self.parts

        # Do not attempt to normalize path if no parts are dots
        if ".." not in _parts and "." not in _parts:
            return self

        resolved: list[str] = []
        resolvable_parts = _parts[1:]
        for part in resolvable_parts:
            if part == "..":
                if resolved:
                    resolved.pop()
            elif part != ".":
                resolved.append(part)

        return self.with_segments(*_parts[:1], *resolved)

    def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
        """Create this file with the given access mode, if it doesn't exist."""
        exists = self.fs.exists(self.path)
        if exists and not exist_ok:
            raise FileExistsError(str(self))
        if not exists:
            try:
                self.fs.touch(self.path, truncate=True)
            except NotImplementedError:
                _raise_unsupported(type(self).__name__, "touch")
        else:
            try:
                self.fs.touch(self.path, truncate=False)
            except (NotImplementedError, ValueError):
                pass  # unsupported by filesystem

    def lchmod(self, mode: int) -> None:
        _raise_unsupported(type(self).__name__, "lchmod")

    def unlink(self, missing_ok: bool = False) -> None:
        """
        Remove this file or link.
        If the path is a directory, use rmdir() instead.
        """
        if not self.exists():
            if not missing_ok:
                raise FileNotFoundError(str(self))
            return
        self.fs.rm(self.path, recursive=False)

    def rmdir(self, recursive: bool = True) -> None:  # fixme: non-standard
        """
        Remove this directory.

        Warning
        -------
        This method is non-standard compared to pathlib.Path.rmdir(),
        as it supports a `recursive` parameter to remove non-empty
        directories and defaults to recursive deletion.

        This behavior is likely to change in future releases once
        `.delete()` is introduced.

        """
        if not self.is_dir():
            raise NotADirectoryError(str(self))
        if not recursive and next(self.iterdir()):  # type: ignore[arg-type]
            raise OSError(f"Not recursive and directory not empty: {self}")
        self.fs.rm(self.path, recursive=recursive)

    def rename(
        self,
        target: WritablePathLike,
        *,  # note: non-standard compared to pathlib
        recursive: bool = UNSET_DEFAULT,
        maxdepth: int | None = UNSET_DEFAULT,
        **kwargs: Any,
    ) -> Self:
        """
        Rename this file or directory to the given target.

        The target path may be absolute or relative. Relative paths are
        interpreted relative to the current working directory, *not* the
        directory of the Path object.

        Returns the new Path instance pointing to the target path.

        Info
        ----
        For filesystems that don't have a root character, i.e. for which
        relative paths can be ambiguous, you can explicitly indicate a
        relative path via prefixing with `./`

        Warning
        -------
        This method is non-standard compared to pathlib.Path.rename(),
        as it supports `recursive` and `maxdepth` parameters for
        directory moves. This will be revisited in future releases.

        It's better to use `.move()` or `.move_into()` to avoid
        running into future compatibility issues.

        """
        # check protocol compatibility
        target_protocol = get_upath_protocol(target)
        if target_protocol and target_protocol != self.protocol:
            raise ValueError(
                f"expected protocol {self.protocol!r}, got: {target_protocol!r}"
            )
        # ensure target is an absolute UPath
        if not isinstance(target, type(self)):
            if isinstance(target, (UPath, PurePath)):
                target_str = target.as_posix()
            else:
                target_str = str(target)
            if target_protocol:
                # target protocol provided indicates absolute path
                target = self.with_segments(target_str)
            elif self.anchor and target_str.startswith(self.anchor):
                # self.anchor can be used to indicate absolute path
                target = self.with_segments(target_str)
            elif not self.anchor and target_str.startswith("./"):
                # indicate relative via "./"
                target = (
                    self.cwd()
                    .joinpath(target_str.removeprefix("./"))
                    .relative_to(self.cwd())
                )
            else:
                # all other cases
                target = self.cwd().joinpath(target_str).relative_to(self.cwd())
        # return early if renaming to same path
        if target == self:
            return self
        # ensure source and target are absolute
        source_abs = self.absolute()
        target_abs = target.absolute()
        # avoid calling .resolve for if not needed
        if ".." in target_abs.parts or "." in target_abs.parts:
            target_abs = target_abs.resolve()
        if kwargs:
            warnings.warn(
                "Passing additional keyword arguments to "
                f"{type(self).__name__}.rename() is deprecated and will be"
                " removed in future univeral-pathlib versions.",
                DeprecationWarning,
                stacklevel=2,
            )
        if recursive is not UNSET_DEFAULT:
            warnings.warn(
                f"{type(self).__name__}.rename()'s `recursive` keyword argument is"
                " deprecated and will be removed in future universal-pathlib versions."
                f" Please use {type(self).__name__}.move() or .move_into() instead.",
                DeprecationWarning,
                stacklevel=2,
            )
            kwargs["recursive"] = recursive
        if maxdepth is not UNSET_DEFAULT:
            warnings.warn(
                f"{type(self).__name__}.rename()'s `maxdepth` keyword argument is"
                " deprecated and will be removed in future universal-pathlib versions.",
                DeprecationWarning,
                stacklevel=2,
            )
            kwargs["maxdepth"] = maxdepth
        self.fs.mv(
            source_abs.path,
            target_abs.path,
            **kwargs,
        )
        return target

    def replace(self, target: WritablePathLike) -> Self:
        """
        Rename this path to the target path, overwriting if that path exists.

        The target path may be absolute or relative. Relative paths are
        interpreted relative to the current working directory, *not* the
        directory of the Path object.

        Returns the new Path instance pointing to the target path.

        Warning
        -------
        This method is currently not implemented.

        """
        _raise_unsupported(type(self).__name__, "replace")

    @property
    def drive(self) -> str:
        """The drive prefix (letter or UNC path), if any.

        Info
        ----
        On non-Windows systems, the drive is always an empty string.
        On cloud storage systems, the drive is the bucket name or equivalent.
        """
        if self._relative_base is not None:
            return ""
        return self.parser.splitroot(str(self))[0]

    @property
    def root(self) -> str:
        """The root of the path, if any."""
        if self._relative_base is not None:
            return ""
        return self.parser.splitroot(str(self))[1]

    def __reduce__(self):
        if self._relative_base is None:
            args = (self.__vfspath__(),)
            kwargs = {
                "protocol": self._protocol,
                **self.storage_options,
            }
        else:
            args = (self._relative_base, self.__vfspath__())
            # Include _relative_base in the state if it's set
            kwargs = {
                "protocol": self._protocol,
                **self.storage_options,
                "_relative_base": self._relative_base,
            }
        return _make_instance, (type(self), args, kwargs)

    @classmethod
    def from_uri(cls, uri: str, **storage_options: Any) -> Self:
        return cls(uri, **storage_options)

    def as_uri(self) -> str:
        """Return the string representation of the path as a URI."""
        if self._relative_base is not None:
            raise ValueError(
                f"relative path can't be expressed as a {self.protocol} URI"
            )
        return str(self)

    def as_posix(self) -> str:
        """Return the string representation of the path with POSIX-style separators."""
        return str(self)

    def samefile(self, other_path) -> bool:
        st = self.stat()
        if isinstance(other_path, UPath):
            other_st = other_path.stat()
        else:
            other_st = self.with_segments(other_path).stat()
        return st == other_st

    @classmethod
    def cwd(cls) -> Self:
        """
        Return a new UPath object representing the current working directory.

        Info
        ----
        None of the fsspec filesystems support a global current working
        directory, so this method only works for the base UPath class,
        returning the local current working directory.

        """
        if cls is UPath:
            # default behavior for UPath.cwd() is to return local cwd
            return get_upath_class("").cwd()  # type: ignore[union-attr,return-value]
        else:
            _raise_unsupported(cls.__name__, "cwd")

    @classmethod
    def home(cls) -> Self:
        """
        Return a new UPath object representing the user's home directory.

        Info
        ----
        None of the fsspec filesystems support user home directories,
        so this method only works for the base UPath class, returning the
        local user's home directory.

        """
        if cls is UPath:
            return get_upath_class("").home()  # type: ignore[union-attr,return-value]
        else:
            _raise_unsupported(cls.__name__, "home")

    def relative_to(  # type: ignore[override]
        self,
        other: Self | str,
        /,
        *_deprecated: Any,
        walk_up: bool = False,
    ) -> Self:
        """Return the relative path to another path identified by the passed
        arguments.  If the operation is not possible (because this is not
        related to the other path), raise ValueError.

        The *walk_up* parameter controls whether `..` may be used to resolve
        the path.
        """
        if walk_up:
            raise NotImplementedError("walk_up=True is not implemented yet")

        if isinstance(other, UPath):
            # revisit: ...
            if self.__class__ is not other.__class__:
                raise ValueError(
                    "incompatible protocols:"
                    f" {self.protocol!r} != {other.protocol!r}"
                )
            if self.storage_options != other.storage_options:
                raise ValueError(
                    "incompatible storage_options:"
                    f" {self.storage_options!r} != {other.storage_options!r}"
                )
        elif isinstance(other, str):
            other = self.with_segments(other)
        else:
            raise TypeError(f"expected UPath or str, got {type(other).__name__}")

        if other not in self.parents and self != other:
            raise ValueError(f"{self!s} is not in the subpath of {other!s}")
        else:
            rel = copy(self)
            rel._relative_base = other.path
            return rel

    def is_relative_to(
        self,
        other: Self | str,
        /,
        *_deprecated: Any,
    ) -> bool:  # type: ignore[override]
        """Return True if the path is relative to another path identified."""
        if isinstance(other, UPath) and self.storage_options != other.storage_options:
            return False
        elif isinstance(other, str):
            other = self.with_segments(other)
        return self == other or other in self.parents

    def hardlink_to(self, target: ReadablePathLike) -> None:
        _raise_unsupported(type(self).__name__, "hardlink_to")

    def full_match(
        self,
        pattern: str | SupportsPathLike,
        *,
        case_sensitive: bool | None = None,
    ) -> bool:
        """Match this path against the provided glob-style pattern.
        Return True if matching is successful, False otherwise.
        """
        if case_sensitive is not None:
            warnings.warn(
                f"{type(self).__name__}.full_match(): case_sensitive"
                " is currently ignored.",
                UserWarning,
                stacklevel=2,
            )
        return super().full_match(str(pattern))

    def match(
        self,
        path_pattern: str | SupportsPathLike,
        *,
        case_sensitive: bool | None = None,
    ) -> bool:
        """Match this path against the provided non-recursive glob-style pattern.
        Return True if matching is successful, False otherwise.
        """
        path_pattern = str(path_pattern)
        if not path_pattern:
            raise ValueError("pattern cannot be empty")
        if case_sensitive is not None:
            warnings.warn(
                f"{type(self).__name__}.match(): case_sensitive is currently ignored.",
                UserWarning,
                stacklevel=2,
            )
        return self.full_match(path_pattern.replace("**", "*"))

    @classmethod
    def __get_pydantic_core_schema__(
        cls, _source_type: Any, _handler: GetCoreSchemaHandler
    ) -> CoreSchema:
        from pydantic_core import core_schema

        str_schema = core_schema.chain_schema(
            [
                core_schema.str_schema(),
                core_schema.no_info_plain_validator_function(
                    lambda path: {
                        "path": path,
                        "protocol": None,
                        "storage_options": {},
                    },
                ),
            ]
        )

        object_schema = core_schema.typed_dict_schema(
            {
                "path": core_schema.typed_dict_field(
                    core_schema.str_schema(), required=True
                ),
                "protocol": core_schema.typed_dict_field(
                    core_schema.with_default_schema(
                        core_schema.nullable_schema(
                            core_schema.str_schema(),
                        ),
                        default=None,
                    ),
                    required=False,
                ),
                "storage_options": core_schema.typed_dict_field(
                    core_schema.with_default_schema(
                        core_schema.dict_schema(
                            core_schema.str_schema(),
                            core_schema.any_schema(),
                        ),
                        default_factory=dict,
                    ),
                    required=False,
                ),
            },
            extra_behavior="forbid",
        )

        deserialization_schema = core_schema.chain_schema(
            [
                core_schema.union_schema([str_schema, object_schema]),
                core_schema.no_info_plain_validator_function(
                    lambda dct: cls(
                        dct.pop("path"),
                        protocol=dct.pop("protocol"),
                        **dct["storage_options"],
                    )
                ),
            ]
        )

        serialization_schema = core_schema.plain_serializer_function_ser_schema(
            lambda u: {
                "path": u.path,
                "protocol": u.protocol,
                "storage_options": dict(u.storage_options),
            }
        )

        return core_schema.json_or_python_schema(
            json_schema=deserialization_schema,
            python_schema=core_schema.union_schema(
                [core_schema.is_instance_schema(UPath), deserialization_schema]
            ),
            serialization=serialization_schema,
        )

__init__

__init__(
    *args: JoinablePathLike,
    protocol: str | None = None,
    chain_parser: FSSpecChainParser = DEFAULT_CHAIN_PARSER,
    **storage_options: Any,
) -> None

When instantiating a UPath, the detected or provided protocol determines the UPath subclass that will be instantiated. The protocol is looked up via the get_upath_protocol function, which loads the registered UPath implementation from the registry. If no UPath implementation is found for the detected protocol, but a registered fsspec filesystem exists for the protocol, a default dynamically created UPath implementation will be used.

PARAMETER DESCRIPTION
*args

The path (or uri) segments to construct the UPath from. The first argument is used to detect the protocol if no protocol is provided.

TYPE: JoinablePathLike DEFAULT: ()

protocol

The protocol to use for the path.

TYPE: str | None DEFAULT: None

chain_parser

A chain parser instance for chained urlpaths. (experimental)

TYPE: FSSpecChainParser DEFAULT: DEFAULT_CHAIN_PARSER

**storage_options

Additional storage options for the path.

TYPE: Any DEFAULT: {}

Source code in upath/core.py
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
def __init__(
    self,
    *args: JoinablePathLike,
    protocol: str | None = None,
    chain_parser: FSSpecChainParser = DEFAULT_CHAIN_PARSER,
    **storage_options: Any,
) -> None:
    """Initialize a UPath instance

    When instantiating a `UPath`, the detected or provided protocol determines
    the `UPath` subclass that will be instantiated. The protocol is looked up
    via the `get_upath_protocol` function, which loads the registered `UPath`
    implementation from the registry. If no `UPath` implementation is found for
    the detected protocol, but a registered `fsspec` filesystem exists for the
    protocol, a default dynamically created `UPath` implementation will be used.

    Parameters
    ----------
    *args :
        The path (or uri) segments to construct the UPath from. The first
        argument is used to detect the protocol if no protocol is provided.
    protocol :
        The protocol to use for the path.
    chain_parser :
        A chain parser instance for chained urlpaths. _(experimental)_
    **storage_options :
        Additional storage options for the path.

    """
    # todo: avoid duplicating this call from __new__
    protocol = get_upath_protocol(
        args[0] if args else "",
        protocol=protocol,
        storage_options=storage_options,
    )
    args, protocol, storage_options = type(self)._transform_init_args(
        args, protocol, storage_options
    )

    # check that UPath subclasses in args are compatible
    # TODO:
    #   Future versions of UPath could verify that storage_options
    #   can be combined between UPath instances. Not sure if this
    #   is really necessary though. A warning might be enough...
    if not compatible_protocol(protocol, *args):
        raise ValueError("can't combine incompatible UPath protocols")

    # subclasses should default to their own protocol
    if not protocol:
        impl_protocols = _get_implementation_protocols(type(self))
        if impl_protocols:
            protocol = impl_protocols[0]

    if args:
        args0 = args[0]
        if isinstance(args0, UPath):
            storage_options = {
                **args0._chain.nest().storage_options,
                **storage_options,
            }
            str_args0 = args0.__vfspath__()

        else:
            if hasattr(args0, "__fspath__") and args0.__fspath__ is not None:
                str_args0 = args0.__fspath__()
            elif hasattr(args0, "__vfspath__") and args0.__vfspath__ is not None:
                str_args0 = args0.__vfspath__()
            elif isinstance(args0, str):
                str_args0 = args0
            else:
                raise TypeError(
                    "argument should be a UPath, str, "
                    f"or support __vfspath__ or __fspath__, not {type(args0)!r}"
                )
            storage_options = type(self)._parse_storage_options(
                str_args0, protocol, storage_options
            )
    else:
        str_args0 = "."

    segments = chain_parser.unchain(
        str_args0,
        protocol=protocol,
        storage_options=storage_options,
    )
    # FIXME: normalization needs to happen in unchain already...
    chain = Chain.from_list(Chain.from_list(segments).to_list())
    if len(args) > 1:
        flavour = WrappedFileSystemFlavour.from_protocol(chain.active_path_protocol)
        joined = flavour.join(chain.active_path, *args[1:])
        stripped = flavour.strip_protocol(joined)
        chain = chain.replace(path=stripped)
    self._chain = chain
    self._chain_parser = chain_parser
    self._raw_urlpaths = args
    self._relative_base = None

protocol property

protocol: str

The fsspec protocol for the path.

Note

Protocols are linked to upath and fsspec filesystems via the upath.registry and fsspec.registry modules. They basically represent the URI scheme used for the specific filesystem.

Examples:

>>> from upath import UPath
>>> p0 = UPath("s3://my-bucket/path/to/file.txt")
>>> p0.protocol
's3'
>>> p1 = UPath("/foo/bar/baz.txt", protocol="memory")
>>> p1.protocol
'memory'

storage_options property

storage_options: Mapping[str, Any]

The read-only fsspec storage options for the path.

Note

Storage options are specific to each fsspec filesystem and can include parameters such as authentication credentials, connection settings, and other options that affect how the filesystem interacts with the underlying storage.

Examples:

>>> from upath import UPath
>>> p = UPath("s3://my-bucket/path/to/file.txt", anon=True)
>>> p.storage_options['anon']
True

fs property

fs: AbstractFileSystem

The cached fsspec filesystem instance for the path.

This is the underlying fsspec filesystem instance. It's instantiated on first filesystem access and cached. Can be used to access fsspec-specific functionality not exposed by the UPath API.

Examples:

>>> from upath import UPath
>>> p = UPath("s3://my-bucket/path/to/file.txt")
>>> p.fs
<s3fs.core.S3FileSystem object at 0x...>
>>> p.fs.get_tags(p.path)
{'VersionId': 'null', 'ContentLength': 12345, ...}

path property

path: str

The path used by fsspec filesystem.

FSSpec filesystems usually handle paths stripped of protocol. This property returns the path suitable for use with the underlying fsspec filesystem. It guarantees that a filesystem's strip_protocol method is applied correctly.

Examples:

>>> from upath import UPath
>>> p = UPath("memory:///foo/bar.txt")
>>> str(p)
'memory:///foo/bar.txt'
>>> p.path
'/foo/bar.txt'
>>> p.fs.exists(p.path)
True

parts property

parts: Sequence[str]

Provides sequence-like access to the filesystem path components.

Examples:

>>> from upath import UPath
>>> p = UPath("s3://my-bucket/path/to/file.txt")
>>> p.parts
('my-bucket/', 'path', 'to', 'file.txt')
>>> p2 = UPath("/foo/bar/baz.txt", protocol="memory")
>>> p2.parts
('/', 'foo', 'bar', 'baz.txt')

name property

name: str

The final path component, if any.

stem property

stem: str

The final path component, minus its last suffix.

drive property

drive: str

The drive prefix (letter or UNC path), if any.

Info

On non-Windows systems, the drive is always an empty string. On cloud storage systems, the drive is the bucket name or equivalent.

root property

root: str

The root of the path, if any.

anchor property

anchor: str

The concatenation of the drive and root or an empty string.

suffix property

suffix: str

The final component's last suffix, if any.

This includes the leading period. For example: '.txt'

suffixes property

suffixes: list[str]

A list of the final component's suffixes, if any.

These include the leading periods. For example: ['.tar', '.gz']

parent property

parent: Self

The logical parent of the path.

Examples:

>>> from upath import UPath
>>> p = UPath("s3://my-bucket/path/to/file.txt")
>>> p.parent
S3Path('s3://my-bucket/path/to')

parents property

parents: Sequence[Self]

A sequence providing access to the logical ancestors of the path.

Examples:

>>> from upath import UPath
>>> p = UPath("memory:///foo/bar/baz.txt")
>>> list(p.parents)
[
  MemoryPath('memory:///foo/bar'),
  MemoryPath('memory:///foo'),
  MemoryPath('memory:///'),
]

joinpath

joinpath(*pathsegments: JoinablePathLike) -> Self

Combine this path with one or several arguments, and return a new path.

For one argument, this is equivalent to using the / operator.

Examples:

>>> from upath import UPath
>>> p = UPath("s3://my-bucket/path/to")
>>> p.joinpath("file.txt")
S3Path('s3://my-bucket/path/to/file.txt')
Source code in upath/core.py
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
def joinpath(self, *pathsegments: JoinablePathLike) -> Self:
    """Combine this path with one or several arguments, and return a new path.

    For one argument, this is equivalent to using the `/` operator.

    Examples
    --------
    >>> from upath import UPath
    >>> p = UPath("s3://my-bucket/path/to")
    >>> p.joinpath("file.txt")
    S3Path('s3://my-bucket/path/to/file.txt')

    """
    return self.with_segments(self.__vfspath__(), *pathsegments)

joinuri

joinuri(uri: JoinablePathLike) -> UPath

Join with urljoin behavior for UPath instances.

Examples:

>>> from upath import UPath
>>> p = UPath("https://example.com/dir/subdir/")
>>> p.joinuri("file.txt")
HTTPSPath('https://example.com/dir/subdir/file.txt')
>>> p.joinuri("/anotherdir/otherfile.txt")
HTTPSPath('https://example.com/anotherdir/otherfile.txt')
>>> p.joinuri("memory:///foo/bar.txt"
MemoryPath('memory:///foo/bar.txt')
Source code in upath/core.py
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
def joinuri(self, uri: JoinablePathLike) -> UPath:
    """Join with urljoin behavior for UPath instances.

    Examples
    --------
    >>> from upath import UPath
    >>> p = UPath("https://example.com/dir/subdir/")
    >>> p.joinuri("file.txt")
    HTTPSPath('https://example.com/dir/subdir/file.txt')
    >>> p.joinuri("/anotherdir/otherfile.txt")
    HTTPSPath('https://example.com/anotherdir/otherfile.txt')
    >>> p.joinuri("memory:///foo/bar.txt"
    MemoryPath('memory:///foo/bar.txt')

    """
    # short circuit if the new uri uses a different protocol
    other_protocol = get_upath_protocol(uri)
    if other_protocol and other_protocol != self._protocol:
        return UPath(uri)
    return UPath(
        upath_urijoin(str(self), str(uri)),
        protocol=other_protocol or self._protocol,
        **self.storage_options,
    )

with_name

with_name(name: str) -> Self

Return a new path with the file name changed.

Source code in upath/core.py
1093
1094
1095
1096
1097
1098
1099
1100
def with_name(self, name: str) -> Self:
    """Return a new path with the file name changed."""
    split = self.parser.split
    if self.parser.sep in name:  # `split(name)[0]`
        raise ValueError(f"Invalid name {name!r}")
    _path = self.__vfspath__()
    _path = _path.removesuffix(split(_path)[1]) + name
    return self.with_segments(_path)

with_stem

with_stem(stem: str) -> Self

Return a new path with the stem changed.

Source code in pathlib_abc/__init__.py
168
169
170
171
172
173
174
175
176
177
def with_stem(self, stem):
    """Return a new path with the stem changed."""
    suffix = self.suffix
    if not suffix:
        return self.with_name(stem)
    elif not stem:
        # If the suffix is non-empty, we can't make the stem empty.
        raise ValueError(f"{self!r} has a non-empty suffix")
    else:
        return self.with_name(stem + suffix)

with_suffix

with_suffix(suffix: str) -> Self

Return a new path with the file suffix changed. If the path has no suffix, add given suffix. If the given suffix is an empty string, remove the suffix from the path.

Source code in pathlib_abc/__init__.py
179
180
181
182
183
184
185
186
187
188
189
190
191
def with_suffix(self, suffix):
    """Return a new path with the file suffix changed.  If the path
    has no suffix, add given suffix.  If the given suffix is an empty
    string, remove the suffix from the path.
    """
    stem = self.stem
    if not stem:
        # If the stem is empty, we can't make the suffix non-empty.
        raise ValueError(f"{self!r} has an empty name")
    elif suffix and not suffix.startswith('.'):
        raise ValueError(f"Invalid suffix {suffix!r}")
    else:
        return self.with_name(stem + suffix)

with_segments

with_segments(*pathsegments: JoinablePathLike) -> Self

Construct a new path object from any number of path-like objects.

Source code in upath/core.py
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
def with_segments(self, *pathsegments: JoinablePathLike) -> Self:
    """Construct a new path object from any number of path-like objects."""
    # we change joinpath behavior if called from a relative path
    # this is not fully ideal, but currently the best way to move forward
    if is_relative := self._relative_base is not None:
        pathsegments = (self._relative_base, *pathsegments)

    new_instance = type(self)(
        *pathsegments,
        protocol=self._protocol,
        **self.storage_options,
    )
    if hasattr(self, "_fs_cached"):
        new_instance._fs_cached = self._fs_cached

    if is_relative:
        new_instance._relative_base = self._relative_base
    return new_instance

relative_to

relative_to(
    other: Self | str,
    /,
    *_deprecated: Any,
    walk_up: bool = False,
) -> Self

Return the relative path to another path identified by the passed arguments. If the operation is not possible (because this is not related to the other path), raise ValueError.

The walk_up parameter controls whether .. may be used to resolve the path.

Source code in upath/core.py
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
def relative_to(  # type: ignore[override]
    self,
    other: Self | str,
    /,
    *_deprecated: Any,
    walk_up: bool = False,
) -> Self:
    """Return the relative path to another path identified by the passed
    arguments.  If the operation is not possible (because this is not
    related to the other path), raise ValueError.

    The *walk_up* parameter controls whether `..` may be used to resolve
    the path.
    """
    if walk_up:
        raise NotImplementedError("walk_up=True is not implemented yet")

    if isinstance(other, UPath):
        # revisit: ...
        if self.__class__ is not other.__class__:
            raise ValueError(
                "incompatible protocols:"
                f" {self.protocol!r} != {other.protocol!r}"
            )
        if self.storage_options != other.storage_options:
            raise ValueError(
                "incompatible storage_options:"
                f" {self.storage_options!r} != {other.storage_options!r}"
            )
    elif isinstance(other, str):
        other = self.with_segments(other)
    else:
        raise TypeError(f"expected UPath or str, got {type(other).__name__}")

    if other not in self.parents and self != other:
        raise ValueError(f"{self!s} is not in the subpath of {other!s}")
    else:
        rel = copy(self)
        rel._relative_base = other.path
        return rel

is_relative_to

is_relative_to(
    other: Self | str, /, *_deprecated: Any
) -> bool

Return True if the path is relative to another path identified.

Source code in upath/core.py
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
def is_relative_to(
    self,
    other: Self | str,
    /,
    *_deprecated: Any,
) -> bool:  # type: ignore[override]
    """Return True if the path is relative to another path identified."""
    if isinstance(other, UPath) and self.storage_options != other.storage_options:
        return False
    elif isinstance(other, str):
        other = self.with_segments(other)
    return self == other or other in self.parents

match

match(
    path_pattern: str | SupportsPathLike,
    *,
    case_sensitive: bool | None = None,
) -> bool

Match this path against the provided non-recursive glob-style pattern. Return True if matching is successful, False otherwise.

Source code in upath/core.py
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
def match(
    self,
    path_pattern: str | SupportsPathLike,
    *,
    case_sensitive: bool | None = None,
) -> bool:
    """Match this path against the provided non-recursive glob-style pattern.
    Return True if matching is successful, False otherwise.
    """
    path_pattern = str(path_pattern)
    if not path_pattern:
        raise ValueError("pattern cannot be empty")
    if case_sensitive is not None:
        warnings.warn(
            f"{type(self).__name__}.match(): case_sensitive is currently ignored.",
            UserWarning,
            stacklevel=2,
        )
    return self.full_match(path_pattern.replace("**", "*"))

full_match

full_match(
    pattern: str | SupportsPathLike,
    *,
    case_sensitive: bool | None = None,
) -> bool

Match this path against the provided glob-style pattern. Return True if matching is successful, False otherwise.

Source code in upath/core.py
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
def full_match(
    self,
    pattern: str | SupportsPathLike,
    *,
    case_sensitive: bool | None = None,
) -> bool:
    """Match this path against the provided glob-style pattern.
    Return True if matching is successful, False otherwise.
    """
    if case_sensitive is not None:
        warnings.warn(
            f"{type(self).__name__}.full_match(): case_sensitive"
            " is currently ignored.",
            UserWarning,
            stacklevel=2,
        )
    return super().full_match(str(pattern))

as_posix

as_posix() -> str

Return the string representation of the path with POSIX-style separators.

Source code in upath/core.py
2071
2072
2073
def as_posix(self) -> str:
    """Return the string representation of the path with POSIX-style separators."""
    return str(self)

as_uri

as_uri() -> str

Return the string representation of the path as a URI.

Source code in upath/core.py
2063
2064
2065
2066
2067
2068
2069
def as_uri(self) -> str:
    """Return the string representation of the path as a URI."""
    if self._relative_base is not None:
        raise ValueError(
            f"relative path can't be expressed as a {self.protocol} URI"
        )
    return str(self)

open

open(
    mode: Literal["r", "w", "a"] = ...,
    buffering: int = ...,
    encoding: str = ...,
    errors: str = ...,
    newline: str = ...,
    **fsspec_kwargs: Any,
) -> TextIO
open(
    mode: Literal["rb", "wb", "ab"] = ...,
    buffering: int = ...,
    encoding: str = ...,
    errors: str = ...,
    newline: str = ...,
    **fsspec_kwargs: Any,
) -> BinaryIO
open(
    mode: str = ...,
    buffering: int = ...,
    encoding: str | None = ...,
    errors: str | None = ...,
    newline: str | None = ...,
    **fsspec_kwargs: Any,
) -> IO[Any]
open(
    mode: str = "r",
    buffering: int = UNSET_DEFAULT,
    encoding: str | None = UNSET_DEFAULT,
    errors: str | None = UNSET_DEFAULT,
    newline: str | None = UNSET_DEFAULT,
    **fsspec_kwargs: Any,
) -> IO[Any]

Open the file pointed by this path and return a file object, as the built-in open() function does.

PARAMETER DESCRIPTION
mode

Opening mode. Default is 'r'.

TYPE: str DEFAULT: 'r'

buffering

Default is the block size of the underlying fsspec filesystem.

TYPE: int DEFAULT: UNSET_DEFAULT

encoding

Encoding is only used in text mode. Default is None.

TYPE: str | None DEFAULT: UNSET_DEFAULT

errors

Error handling for encoding. Only used in text mode. Default is None.

TYPE: str | None DEFAULT: UNSET_DEFAULT

newline

Newline handling. Only used in text mode. Default is None.

TYPE: str | None DEFAULT: UNSET_DEFAULT

**fsspec_kwargs

Additional options for the fsspec filesystem.

TYPE: Any DEFAULT: {}

Source code in upath/core.py
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
def open(
    self,
    mode: str = "r",
    buffering: int = UNSET_DEFAULT,
    encoding: str | None = UNSET_DEFAULT,
    errors: str | None = UNSET_DEFAULT,
    newline: str | None = UNSET_DEFAULT,
    **fsspec_kwargs: Any,
) -> IO[Any]:
    """
    Open the file pointed by this path and return a file object, as
    the built-in open() function does.

    Parameters
    ----------
    mode:
        Opening mode. Default is 'r'.
    buffering:
        Default is the block size of the underlying fsspec filesystem.
    encoding:
        Encoding is only used in text mode. Default is None.
    errors:
        Error handling for encoding. Only used in text mode. Default is None.
    newline:
        Newline handling. Only used in text mode. Default is None.
    **fsspec_kwargs:
        Additional options for the fsspec filesystem.
    """
    # match the signature of pathlib.Path.open()
    if buffering is not UNSET_DEFAULT:
        if "block_size" in fsspec_kwargs:
            raise TypeError("cannot specify both 'buffering' and 'block_size'")
        block_size = _buffering2blocksize(mode, buffering)
        if block_size is not None:
            fsspec_kwargs.setdefault("block_size", block_size)
    if encoding is not UNSET_DEFAULT:
        fsspec_kwargs["encoding"] = encoding
    if errors is not UNSET_DEFAULT:
        fsspec_kwargs["errors"] = errors
    if newline is not UNSET_DEFAULT:
        fsspec_kwargs["newline"] = newline
    return self.fs.open(self.path, mode=mode, **fsspec_kwargs)

read_text

read_text(
    encoding: str | None = None,
    errors: str | None = None,
    newline: str | None = None,
) -> str

Open the file in text mode, read it, and close the file.

Source code in pathlib_abc/__init__.py
315
316
317
318
319
320
321
322
323
def read_text(self, encoding=None, errors=None, newline=None):
    """
    Open the file in text mode, read it, and close the file.
    """
    # Call io.text_encoding() here to ensure any warning is raised at an
    # appropriate stack level.
    encoding = text_encoding(encoding)
    with vfsopen(self, mode='r', encoding=encoding, errors=errors, newline=newline) as f:
        return f.read()

read_bytes

read_bytes() -> bytes

Open the file in bytes mode, read it, and close the file.

Source code in pathlib_abc/__init__.py
308
309
310
311
312
313
def read_bytes(self):
    """
    Open the file in bytes mode, read it, and close the file.
    """
    with vfsopen(self, mode='rb') as f:
        return f.read()

write_text

write_text(
    data: str,
    encoding: str | None = None,
    errors: str | None = None,
    newline: str | None = None,
) -> int

Open the file in text mode, write to it, and close the file.

Source code in pathlib_abc/__init__.py
447
448
449
450
451
452
453
454
455
456
457
458
def write_text(self, data, encoding=None, errors=None, newline=None):
    """
    Open the file in text mode, write to it, and close the file.
    """
    # Call io.text_encoding() here to ensure any warning is raised at an
    # appropriate stack level.
    encoding = text_encoding(encoding)
    if not isinstance(data, str):
        raise TypeError('data must be str, not %s' %
                        data.__class__.__name__)
    with vfsopen(self, mode='w', encoding=encoding, errors=errors, newline=newline) as f:
        return f.write(data)

write_bytes

write_bytes(data: bytes) -> int

Open the file in bytes mode, write to it, and close the file.

Source code in pathlib_abc/__init__.py
438
439
440
441
442
443
444
445
def write_bytes(self, data):
    """
    Open the file in bytes mode, write to it, and close the file.
    """
    # type-check for the buffer interface before truncating the file
    view = memoryview(data)
    with vfsopen(self, mode='wb') as f:
        return f.write(view)

iterdir

iterdir() -> Iterator[Self]

Yield path objects of the directory contents.

Examples:

>>> from upath import UPath
>>> p = UPath("memory:///foo/")
>>> p.joinpath("bar.txt").touch()
>>> p.joinpath("baz.txt").touch()
>>> for child in p.iterdir():
...     print(child)
MemoryPath('memory:///foo/bar.txt')
MemoryPath('memory:///foo/baz.txt')
Source code in upath/core.py
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
def iterdir(self) -> Iterator[Self]:
    """Yield path objects of the directory contents.

    Examples
    --------
    >>> from upath import UPath
    >>> p = UPath("memory:///foo/")
    >>> p.joinpath("bar.txt").touch()
    >>> p.joinpath("baz.txt").touch()
    >>> for child in p.iterdir():
    ...     print(child)
    MemoryPath('memory:///foo/bar.txt')
    MemoryPath('memory:///foo/baz.txt')

    """
    sep = self.parser.sep
    base = self
    if self.parts[-1:] == ("",):
        base = self.parent
    fs = base.fs
    base_path = base.path
    if not fs.isdir(base_path):
        raise NotADirectoryError(str(self))
    for name in fs.listdir(base_path):
        # fsspec returns dictionaries
        if isinstance(name, dict):
            name = name.get("name")
        if name in {".", ".."}:
            # Yielding a path object for these makes little sense
            continue
        # only want the path name with iterdir
        _, _, name = name.removesuffix(sep).rpartition(self.parser.sep)
        yield base.with_segments(base_path, name)

glob

glob(
    pattern: str,
    *,
    case_sensitive: bool | None = None,
    recurse_symlinks: bool = False,
) -> Iterator[Self]

Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern.

Source code in upath/core.py
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
def glob(
    self,
    pattern: str,
    *,
    case_sensitive: bool | None = None,
    recurse_symlinks: bool = False,
) -> Iterator[Self]:
    """Iterate over this subtree and yield all existing files (of any
    kind, including directories) matching the given relative pattern."""
    if case_sensitive is not None:
        warnings.warn(
            "UPath.glob(): case_sensitive is currently ignored.",
            UserWarning,
            stacklevel=2,
        )
    if recurse_symlinks:
        warnings.warn(
            "UPath.glob(): recurse_symlinks=True is currently ignored.",
            UserWarning,
            stacklevel=2,
        )
    if self._relative_base is not None:
        self = self.absolute()
    path_pattern = self.joinpath(pattern).path
    sep = self.parser.sep
    base = self.path
    for name in self.fs.glob(path_pattern):
        name = name.removeprefix(base).removeprefix(sep)
        yield self.joinpath(name)

rglob

rglob(
    pattern: str,
    *,
    case_sensitive: bool | None = None,
    recurse_symlinks: bool = False,
) -> Iterator[Self]

Recursively yield all existing files (of any kind, including directories) matching the given relative pattern, anywhere in this subtree.

Source code in upath/core.py
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
def rglob(
    self,
    pattern: str,
    *,
    case_sensitive: bool | None = None,
    recurse_symlinks: bool = False,
) -> Iterator[Self]:
    """Recursively yield all existing files (of any kind, including
    directories) matching the given relative pattern, anywhere in
    this subtree.
    """
    if case_sensitive is not None:
        warnings.warn(
            "UPath.glob(): case_sensitive is currently ignored.",
            UserWarning,
            stacklevel=2,
        )
    if recurse_symlinks:
        warnings.warn(
            "UPath.glob(): recurse_symlinks=True is currently ignored.",
            UserWarning,
            stacklevel=2,
        )
    if _FSSPEC_HAS_WORKING_GLOB is None:
        _check_fsspec_has_working_glob()

    if _FSSPEC_HAS_WORKING_GLOB:
        r_path_pattern = self.joinpath("**", pattern).path
        sep = self.parser.sep
        base = self.path
        for name in self.fs.glob(r_path_pattern):
            name = name.removeprefix(base).removeprefix(sep)
            yield self.joinpath(name)

    else:
        path_pattern = self.joinpath(pattern).path
        r_path_pattern = self.joinpath("**", pattern).path
        sep = self.parser.sep
        base = self.path
        seen = set()
        for p in (path_pattern, r_path_pattern):
            for name in self.fs.glob(p):
                name = name.removeprefix(base).removeprefix(sep)
                if name in seen:
                    continue
                else:
                    seen.add(name)
                    yield self.joinpath(name)

walk

walk(
    top_down: bool = True,
    on_error: OnErrorCallable | None = None,
    follow_symlinks: bool = False,
) -> Iterator[tuple[Self, list[str], list[str]]]

Walk the directory tree from this directory, similar to os.walk().

Source code in pathlib_abc/__init__.py
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
def walk(self, top_down=True, on_error=None, follow_symlinks=False):
    """Walk the directory tree from this directory, similar to os.walk()."""
    paths = [self]
    while paths:
        path = paths.pop()
        if isinstance(path, tuple):
            yield path
            continue
        dirnames = []
        filenames = []
        if not top_down:
            paths.append((path, dirnames, filenames))
        try:
            for child in path.iterdir():
                if child.info.is_dir(follow_symlinks=follow_symlinks):
                    if not top_down:
                        paths.append(child)
                    dirnames.append(child.name)
                else:
                    filenames.append(child.name)
        except OSError as error:
            if on_error is not None:
                on_error(error)
            if not top_down:
                while not isinstance(paths.pop(), tuple):
                    pass
            continue
        if top_down:
            yield path, dirnames, filenames
            paths += [path.joinpath(d) for d in reversed(dirnames)]

mkdir

mkdir(
    mode: int = 511,
    parents: bool = False,
    exist_ok: bool = False,
) -> None

Create a new directory at this given path.

Source code in upath/core.py
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
def mkdir(
    self,
    mode: int = 0o777,
    parents: bool = False,
    exist_ok: bool = False,
) -> None:
    """
    Create a new directory at this given path.
    """
    if parents and not exist_ok and self.exists():
        raise FileExistsError(str(self))
    try:
        self.fs.mkdir(
            self.path,
            create_parents=parents,
            mode=mode,
        )
    except FileExistsError:
        if not exist_ok:
            raise FileExistsError(str(self))
        if not self.is_dir():
            raise FileExistsError(str(self))

rmdir

rmdir(recursive: bool = True) -> None

Remove this directory.

Warning

This method is non-standard compared to pathlib.Path.rmdir(), as it supports a recursive parameter to remove non-empty directories and defaults to recursive deletion.

This behavior is likely to change in future releases once .delete() is introduced.

Source code in upath/core.py
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
def rmdir(self, recursive: bool = True) -> None:  # fixme: non-standard
    """
    Remove this directory.

    Warning
    -------
    This method is non-standard compared to pathlib.Path.rmdir(),
    as it supports a `recursive` parameter to remove non-empty
    directories and defaults to recursive deletion.

    This behavior is likely to change in future releases once
    `.delete()` is introduced.

    """
    if not self.is_dir():
        raise NotADirectoryError(str(self))
    if not recursive and next(self.iterdir()):  # type: ignore[arg-type]
        raise OSError(f"Not recursive and directory not empty: {self}")
    self.fs.rm(self.path, recursive=recursive)

touch

touch(mode: int = 438, exist_ok: bool = True) -> None

Create this file with the given access mode, if it doesn't exist.

Source code in upath/core.py
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
    """Create this file with the given access mode, if it doesn't exist."""
    exists = self.fs.exists(self.path)
    if exists and not exist_ok:
        raise FileExistsError(str(self))
    if not exists:
        try:
            self.fs.touch(self.path, truncate=True)
        except NotImplementedError:
            _raise_unsupported(type(self).__name__, "touch")
    else:
        try:
            self.fs.touch(self.path, truncate=False)
        except (NotImplementedError, ValueError):
            pass  # unsupported by filesystem
unlink(missing_ok: bool = False) -> None

Remove this file or link. If the path is a directory, use rmdir() instead.

Source code in upath/core.py
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
def unlink(self, missing_ok: bool = False) -> None:
    """
    Remove this file or link.
    If the path is a directory, use rmdir() instead.
    """
    if not self.exists():
        if not missing_ok:
            raise FileNotFoundError(str(self))
        return
    self.fs.rm(self.path, recursive=False)

rename

rename(
    target: WritablePathLike,
    *,
    recursive: bool = UNSET_DEFAULT,
    maxdepth: int | None = UNSET_DEFAULT,
    **kwargs: Any,
) -> Self

Rename this file or directory to the given target.

The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.

Returns the new Path instance pointing to the target path.

Info

For filesystems that don't have a root character, i.e. for which relative paths can be ambiguous, you can explicitly indicate a relative path via prefixing with ./

Warning

This method is non-standard compared to pathlib.Path.rename(), as it supports recursive and maxdepth parameters for directory moves. This will be revisited in future releases.

It's better to use .move() or .move_into() to avoid running into future compatibility issues.

Source code in upath/core.py
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
def rename(
    self,
    target: WritablePathLike,
    *,  # note: non-standard compared to pathlib
    recursive: bool = UNSET_DEFAULT,
    maxdepth: int | None = UNSET_DEFAULT,
    **kwargs: Any,
) -> Self:
    """
    Rename this file or directory to the given target.

    The target path may be absolute or relative. Relative paths are
    interpreted relative to the current working directory, *not* the
    directory of the Path object.

    Returns the new Path instance pointing to the target path.

    Info
    ----
    For filesystems that don't have a root character, i.e. for which
    relative paths can be ambiguous, you can explicitly indicate a
    relative path via prefixing with `./`

    Warning
    -------
    This method is non-standard compared to pathlib.Path.rename(),
    as it supports `recursive` and `maxdepth` parameters for
    directory moves. This will be revisited in future releases.

    It's better to use `.move()` or `.move_into()` to avoid
    running into future compatibility issues.

    """
    # check protocol compatibility
    target_protocol = get_upath_protocol(target)
    if target_protocol and target_protocol != self.protocol:
        raise ValueError(
            f"expected protocol {self.protocol!r}, got: {target_protocol!r}"
        )
    # ensure target is an absolute UPath
    if not isinstance(target, type(self)):
        if isinstance(target, (UPath, PurePath)):
            target_str = target.as_posix()
        else:
            target_str = str(target)
        if target_protocol:
            # target protocol provided indicates absolute path
            target = self.with_segments(target_str)
        elif self.anchor and target_str.startswith(self.anchor):
            # self.anchor can be used to indicate absolute path
            target = self.with_segments(target_str)
        elif not self.anchor and target_str.startswith("./"):
            # indicate relative via "./"
            target = (
                self.cwd()
                .joinpath(target_str.removeprefix("./"))
                .relative_to(self.cwd())
            )
        else:
            # all other cases
            target = self.cwd().joinpath(target_str).relative_to(self.cwd())
    # return early if renaming to same path
    if target == self:
        return self
    # ensure source and target are absolute
    source_abs = self.absolute()
    target_abs = target.absolute()
    # avoid calling .resolve for if not needed
    if ".." in target_abs.parts or "." in target_abs.parts:
        target_abs = target_abs.resolve()
    if kwargs:
        warnings.warn(
            "Passing additional keyword arguments to "
            f"{type(self).__name__}.rename() is deprecated and will be"
            " removed in future univeral-pathlib versions.",
            DeprecationWarning,
            stacklevel=2,
        )
    if recursive is not UNSET_DEFAULT:
        warnings.warn(
            f"{type(self).__name__}.rename()'s `recursive` keyword argument is"
            " deprecated and will be removed in future universal-pathlib versions."
            f" Please use {type(self).__name__}.move() or .move_into() instead.",
            DeprecationWarning,
            stacklevel=2,
        )
        kwargs["recursive"] = recursive
    if maxdepth is not UNSET_DEFAULT:
        warnings.warn(
            f"{type(self).__name__}.rename()'s `maxdepth` keyword argument is"
            " deprecated and will be removed in future universal-pathlib versions.",
            DeprecationWarning,
            stacklevel=2,
        )
        kwargs["maxdepth"] = maxdepth
    self.fs.mv(
        source_abs.path,
        target_abs.path,
        **kwargs,
    )
    return target

replace

replace(target: WritablePathLike) -> Self

Rename this path to the target path, overwriting if that path exists.

The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.

Returns the new Path instance pointing to the target path.

Warning

This method is currently not implemented.

Source code in upath/core.py
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
def replace(self, target: WritablePathLike) -> Self:
    """
    Rename this path to the target path, overwriting if that path exists.

    The target path may be absolute or relative. Relative paths are
    interpreted relative to the current working directory, *not* the
    directory of the Path object.

    Returns the new Path instance pointing to the target path.

    Warning
    -------
    This method is currently not implemented.

    """
    _raise_unsupported(type(self).__name__, "replace")

copy

copy(target: _WT, **kwargs: Any) -> _WT
copy(target: SupportsPathLike | str, **kwargs: Any) -> Self
copy(
    target: _WT | SupportsPathLike | str, **kwargs: Any
) -> _WT | UPath

Recursively copy this file or directory tree to the given destination.

Source code in upath/core.py
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
def copy(self, target: _WT | SupportsPathLike | str, **kwargs: Any) -> _WT | UPath:
    """
    Recursively copy this file or directory tree to the given destination.
    """
    if isinstance(target, str):
        proto = get_upath_protocol(target)
        if proto != self.protocol:
            target = UPath(target)
        else:
            target = self.with_segments(target)
    elif not isinstance(target, UPath):
        target = UPath(target)
    if target.is_dir():
        raise IsADirectoryError(str(target))
    return super().copy(target, **kwargs)

move

move(target: _WT, **kwargs: Any) -> _WT
move(target: SupportsPathLike | str, **kwargs: Any) -> Self
move(
    target: _WT | SupportsPathLike | str, **kwargs: Any
) -> _WT | UPath

Recursively move this file or directory tree to the given destination.

Source code in upath/core.py
1305
1306
1307
1308
1309
1310
1311
def move(self, target: _WT | SupportsPathLike | str, **kwargs: Any) -> _WT | UPath:
    """
    Recursively move this file or directory tree to the given destination.
    """
    target = self.copy(target, **kwargs)
    self.fs.rm(self.path, recursive=self.is_dir())
    return target

copy_into

copy_into(target_dir: _WT, **kwargs: Any) -> _WT
copy_into(
    target_dir: SupportsPathLike | str, **kwargs: Any
) -> Self
copy_into(
    target_dir: _WT | SupportsPathLike | str, **kwargs: Any
) -> _WT | UPath

Copy this file or directory tree into the given existing directory.

Source code in upath/core.py
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
def copy_into(
    self, target_dir: _WT | SupportsPathLike | str, **kwargs: Any
) -> _WT | UPath:
    """
    Copy this file or directory tree into the given existing directory.
    """
    if isinstance(target_dir, str):
        proto = get_upath_protocol(target_dir)
        if proto != self.protocol:
            target_dir = UPath(target_dir)
        else:
            target_dir = self.with_segments(target_dir)
    elif not isinstance(target_dir, UPath):
        target_dir = UPath(target_dir)
    if not target_dir.exists():
        raise FileNotFoundError(str(target_dir))
    if not target_dir.is_dir():
        raise NotADirectoryError(str(target_dir))
    return super().copy_into(target_dir, **kwargs)

move_into

move_into(target_dir: _WT, **kwargs: Any) -> _WT
move_into(
    target_dir: SupportsPathLike | str, **kwargs: Any
) -> Self
move_into(
    target_dir: _WT | SupportsPathLike | str, **kwargs: Any
) -> _WT | UPath

Move this file or directory tree into the given existing directory.

Source code in upath/core.py
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
def move_into(
    self, target_dir: _WT | SupportsPathLike | str, **kwargs: Any
) -> _WT | UPath:
    """
    Move this file or directory tree into the given existing directory.
    """
    name = self.name
    if not name:
        raise ValueError(f"{self!r} has an empty name")
    elif hasattr(target_dir, "with_segments"):
        target = target_dir.with_segments(target_dir, name)  # type: ignore
    elif isinstance(target_dir, PurePath):
        target = UPath(target_dir, name)
    else:
        target = self.with_segments(target_dir, name)
    td = target.parent
    if not td.exists():
        raise FileNotFoundError(str(td))
    elif not td.is_dir():
        raise NotADirectoryError(str(td))
    return self.move(target)

exists

exists(*, follow_symlinks: bool = True) -> bool

Whether this path exists.

Info

For fsspec filesystems follow_symlinks is currently ignored.

Source code in upath/core.py
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
def exists(self, *, follow_symlinks: bool = True) -> bool:
    """
    Whether this path exists.

    Info
    ----
    For fsspec filesystems follow_symlinks is currently ignored.
    """
    if not follow_symlinks:
        warnings.warn(
            f"{type(self).__name__}.exists() follow_symlinks=False"
            " is currently ignored.",
            UserWarning,
            stacklevel=2,
        )
    return self.fs.exists(self.path)

is_file

is_file(*, follow_symlinks: bool = True) -> bool

Whether this path is a regular file.

Source code in upath/core.py
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
def is_file(self, *, follow_symlinks: bool = True) -> bool:
    """
    Whether this path is a regular file.
    """
    if not follow_symlinks:
        warnings.warn(
            f"{type(self).__name__}.is_file() follow_symlinks=False"
            " is currently ignored.",
            UserWarning,
            stacklevel=2,
        )
    return self.fs.isfile(self.path)

is_dir

is_dir(*, follow_symlinks: bool = True) -> bool

Whether this path is a directory.

Source code in upath/core.py
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
def is_dir(self, *, follow_symlinks: bool = True) -> bool:
    """
    Whether this path is a directory.
    """
    if not follow_symlinks:
        warnings.warn(
            f"{type(self).__name__}.is_dir() follow_symlinks=False"
            " is currently ignored.",
            UserWarning,
            stacklevel=2,
        )
    return self.fs.isdir(self.path)
is_symlink() -> bool

Whether this path is a symbolic link.

Source code in upath/core.py
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
def is_symlink(self) -> bool:
    """
    Whether this path is a symbolic link.
    """
    try:
        info = self.fs.info(self.path)
        if "islink" in info:
            return bool(info["islink"])
    except FileNotFoundError:
        return False
    return False

is_absolute

is_absolute() -> bool

True if the path is absolute (has both a root and, if applicable, a drive).

Source code in upath/core.py
1766
1767
1768
1769
1770
1771
1772
def is_absolute(self) -> bool:
    """True if the path is absolute (has both a root and, if applicable,
    a drive)."""
    if self._relative_base is not None:
        return False
    else:
        return self.parser.isabs(self.__vfspath__())

stat

stat(*, follow_symlinks: bool = True) -> StatResultType

Return the result of the stat() system call on this path, like os.stat() does.

Info

For fsspec filesystems follow_symlinks is currently ignored.

RETURNS DESCRIPTION
UPathStatResult

The upath stat result for this path, emulating os.stat_result.

Source code in upath/core.py
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
def stat(
    self,
    *,
    follow_symlinks: bool = True,
) -> StatResultType:
    """
    Return the result of the stat() system call on this path, like
    os.stat() does.

    Info
    ----
    For fsspec filesystems follow_symlinks is currently ignored.

    Returns
    -------
    : UPathStatResult
        The upath stat result for this path, emulating `os.stat_result`.

    """
    if not follow_symlinks:
        warnings.warn(
            f"{type(self).__name__}.stat(follow_symlinks=False):"
            " is currently ignored.",
            UserWarning,
            stacklevel=2,
        )
    return UPathStatResult.from_info(self.fs.info(self.path))

info property

info: PathInfo

A PathInfo object that exposes the file type and other file attributes of this path.

RETURNS DESCRIPTION
UPathInfo

The UPathInfo object for this path.

absolute

absolute() -> Self

Return an absolute version of this path No normalization or symlink resolution is performed.

Use resolve() to resolve symlinks and remove '..' segments.

Source code in upath/core.py
1756
1757
1758
1759
1760
1761
1762
1763
1764
def absolute(self) -> Self:
    """Return an absolute version of this path
    No normalization or symlink resolution is performed.

    Use resolve() to resolve symlinks and remove '..' segments.
    """
    if self._relative_base is not None:
        return self.cwd().joinpath(self.__vfspath__())
    return self

resolve

resolve(strict: bool = False) -> Self

Make the path absolute, resolving all symlinks on the way and also normalizing it.

Source code in upath/core.py
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
def resolve(self, strict: bool = False) -> Self:
    """
    Make the path absolute, resolving all symlinks on the way and also
    normalizing it.
    """
    if self._relative_base is not None:
        self = self.absolute()
    _parts = self.parts

    # Do not attempt to normalize path if no parts are dots
    if ".." not in _parts and "." not in _parts:
        return self

    resolved: list[str] = []
    resolvable_parts = _parts[1:]
    for part in resolvable_parts:
        if part == "..":
            if resolved:
                resolved.pop()
        elif part != ".":
            resolved.append(part)

    return self.with_segments(*_parts[:1], *resolved)

expanduser

expanduser() -> Self

Return a new path with expanded ~ constructs.

Info

For fsspec filesystems this is currently a no-op.

Source code in upath/core.py
1662
1663
1664
1665
1666
1667
1668
1669
def expanduser(self) -> Self:
    """Return a new path with expanded `~` constructs.

    Info
    ----
    For fsspec filesystems this is currently a no-op.
    """
    return self

cwd classmethod

cwd() -> Self

Return a new UPath object representing the current working directory.

Info

None of the fsspec filesystems support a global current working directory, so this method only works for the base UPath class, returning the local current working directory.

Source code in upath/core.py
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
@classmethod
def cwd(cls) -> Self:
    """
    Return a new UPath object representing the current working directory.

    Info
    ----
    None of the fsspec filesystems support a global current working
    directory, so this method only works for the base UPath class,
    returning the local current working directory.

    """
    if cls is UPath:
        # default behavior for UPath.cwd() is to return local cwd
        return get_upath_class("").cwd()  # type: ignore[union-attr,return-value]
    else:
        _raise_unsupported(cls.__name__, "cwd")

home classmethod

home() -> Self

Return a new UPath object representing the user's home directory.

Info

None of the fsspec filesystems support user home directories, so this method only works for the base UPath class, returning the local user's home directory.

Source code in upath/core.py
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
@classmethod
def home(cls) -> Self:
    """
    Return a new UPath object representing the user's home directory.

    Info
    ----
    None of the fsspec filesystems support user home directories,
    so this method only works for the base UPath class, returning the
    local user's home directory.

    """
    if cls is UPath:
        return get_upath_class("").home()  # type: ignore[union-attr,return-value]
    else:
        _raise_unsupported(cls.__name__, "home")

See Also 🔗