fsspec 2025.9.0__tar.gz → 2025.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. {fsspec-2025.9.0 → fsspec-2025.10.0}/PKG-INFO +1 -1
  2. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/source/api.rst +61 -61
  3. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/source/changelog.rst +27 -0
  4. fsspec-2025.10.0/docs/source/code-of-conduct.rst +126 -0
  5. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/source/features.rst +3 -1
  6. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/source/index.rst +5 -0
  7. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/_version.py +2 -2
  8. fsspec-2025.10.0/fsspec/conftest.py +125 -0
  9. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/core.py +2 -2
  10. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/generic.py +2 -0
  11. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/arrow.py +7 -4
  12. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/cached.py +7 -3
  13. fsspec-2025.10.0/fsspec/implementations/chained.py +23 -0
  14. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/gist.py +25 -16
  15. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/http.py +1 -0
  16. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/jupyter.py +7 -2
  17. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/memory.py +4 -4
  18. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/reference.py +14 -8
  19. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/sftp.py +7 -0
  20. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/webhdfs.py +1 -1
  21. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/spec.py +17 -6
  22. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/utils.py +8 -0
  23. fsspec-2025.9.0/fsspec/conftest.py +0 -55
  24. {fsspec-2025.9.0 → fsspec-2025.10.0}/.codespellrc +0 -0
  25. {fsspec-2025.9.0 → fsspec-2025.10.0}/.coveragerc +0 -0
  26. {fsspec-2025.9.0 → fsspec-2025.10.0}/.gitattributes +0 -0
  27. {fsspec-2025.9.0 → fsspec-2025.10.0}/.github/workflows/main.yaml +0 -0
  28. {fsspec-2025.9.0 → fsspec-2025.10.0}/.github/workflows/pypipublish.yaml +0 -0
  29. {fsspec-2025.9.0 → fsspec-2025.10.0}/.gitignore +0 -0
  30. {fsspec-2025.9.0 → fsspec-2025.10.0}/.pre-commit-config.yaml +0 -0
  31. {fsspec-2025.9.0 → fsspec-2025.10.0}/LICENSE +0 -0
  32. {fsspec-2025.9.0 → fsspec-2025.10.0}/README.md +0 -0
  33. {fsspec-2025.9.0 → fsspec-2025.10.0}/ci/environment-downstream.yml +0 -0
  34. {fsspec-2025.9.0 → fsspec-2025.10.0}/ci/environment-friends.yml +0 -0
  35. {fsspec-2025.9.0 → fsspec-2025.10.0}/ci/environment-linux.yml +0 -0
  36. {fsspec-2025.9.0 → fsspec-2025.10.0}/ci/environment-win.yml +0 -0
  37. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/Makefile +0 -0
  38. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/README.md +0 -0
  39. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/environment.yml +0 -0
  40. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/make.bat +0 -0
  41. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/source/_static/custom.css +0 -0
  42. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/source/async.rst +0 -0
  43. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/source/conf.py +0 -0
  44. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/source/copying.rst +0 -0
  45. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/source/developer.rst +0 -0
  46. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/source/img/gui.png +0 -0
  47. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/source/intro.rst +0 -0
  48. {fsspec-2025.9.0 → fsspec-2025.10.0}/docs/source/usage.rst +0 -0
  49. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/__init__.py +0 -0
  50. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/archive.py +0 -0
  51. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/asyn.py +0 -0
  52. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/caching.py +0 -0
  53. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/callbacks.py +0 -0
  54. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/compression.py +0 -0
  55. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/config.py +0 -0
  56. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/dircache.py +0 -0
  57. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/exceptions.py +0 -0
  58. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/fuse.py +0 -0
  59. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/gui.py +0 -0
  60. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/__init__.py +0 -0
  61. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/asyn_wrapper.py +0 -0
  62. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/cache_mapper.py +0 -0
  63. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/cache_metadata.py +0 -0
  64. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/dask.py +0 -0
  65. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/data.py +0 -0
  66. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/dbfs.py +0 -0
  67. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/dirfs.py +0 -0
  68. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/ftp.py +0 -0
  69. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/git.py +0 -0
  70. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/github.py +0 -0
  71. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/http_sync.py +0 -0
  72. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/libarchive.py +0 -0
  73. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/local.py +0 -0
  74. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/smb.py +0 -0
  75. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/tar.py +0 -0
  76. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/implementations/zip.py +0 -0
  77. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/json.py +0 -0
  78. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/mapping.py +0 -0
  79. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/parquet.py +0 -0
  80. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/registry.py +0 -0
  81. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/tests/abstract/__init__.py +0 -0
  82. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/tests/abstract/common.py +0 -0
  83. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/tests/abstract/copy.py +0 -0
  84. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/tests/abstract/get.py +0 -0
  85. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/tests/abstract/mv.py +0 -0
  86. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/tests/abstract/open.py +0 -0
  87. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/tests/abstract/pipe.py +0 -0
  88. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/tests/abstract/put.py +0 -0
  89. {fsspec-2025.9.0 → fsspec-2025.10.0}/fsspec/transaction.py +0 -0
  90. {fsspec-2025.9.0 → fsspec-2025.10.0}/install_s3fs.sh +0 -0
  91. {fsspec-2025.9.0 → fsspec-2025.10.0}/pyproject.toml +0 -0
  92. {fsspec-2025.9.0 → fsspec-2025.10.0}/readthedocs.yml +0 -0
  93. {fsspec-2025.9.0 → fsspec-2025.10.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fsspec
3
- Version: 2025.9.0
3
+ Version: 2025.10.0
4
4
  Summary: File-system specification
5
5
  Project-URL: Changelog, https://filesystem-spec.readthedocs.io/en/latest/changelog.html
6
6
  Project-URL: Documentation, https://filesystem-spec.readthedocs.io/en/latest/
@@ -7,17 +7,17 @@ User Functions
7
7
  --------------
8
8
 
9
9
  .. autosummary::
10
- fsspec.available_compressions
11
- fsspec.available_protocols
12
- fsspec.filesystem
13
- fsspec.fuse.run
14
- fsspec.generic.rsync
15
- fsspec.get_filesystem_class
16
- fsspec.get_mapper
17
- fsspec.gui.FileSelector
18
- fsspec.open
19
- fsspec.open_files
20
- fsspec.open_local
10
+ available_compressions
11
+ available_protocols
12
+ filesystem
13
+ fuse.run
14
+ generic.rsync
15
+ get_filesystem_class
16
+ get_mapper
17
+ gui.FileSelector
18
+ open
19
+ open_files
20
+ open_local
21
21
 
22
22
  .. autofunction:: fsspec.available_compressions
23
23
  .. autofunction:: fsspec.available_protocols
@@ -36,24 +36,24 @@ Base Classes
36
36
  ------------
37
37
 
38
38
  .. autosummary::
39
- fsspec.archive.AbstractArchiveFileSystem
40
- fsspec.asyn.AsyncFileSystem
41
- fsspec.callbacks.Callback
42
- fsspec.callbacks.DotPrinterCallback
43
- fsspec.callbacks.NoOpCallback
44
- fsspec.callbacks.TqdmCallback
45
- fsspec.core.BaseCache
46
- fsspec.core.OpenFile
47
- fsspec.core.OpenFiles
48
- fsspec.core.get_fs_token_paths
49
- fsspec.core.url_to_fs
50
- fsspec.dircache.DirCache
51
- fsspec.FSMap
52
- fsspec.generic.GenericFileSystem
53
- fsspec.registry.register_implementation
54
- fsspec.spec.AbstractBufferedFile
55
- fsspec.spec.AbstractFileSystem
56
- fsspec.spec.Transaction
39
+ archive.AbstractArchiveFileSystem
40
+ asyn.AsyncFileSystem
41
+ callbacks.Callback
42
+ callbacks.DotPrinterCallback
43
+ callbacks.NoOpCallback
44
+ callbacks.TqdmCallback
45
+ core.BaseCache
46
+ core.OpenFile
47
+ core.OpenFiles
48
+ core.get_fs_token_paths
49
+ core.url_to_fs
50
+ dircache.DirCache
51
+ FSMap
52
+ generic.GenericFileSystem
53
+ registry.register_implementation
54
+ spec.AbstractBufferedFile
55
+ spec.AbstractFileSystem
56
+ spec.Transaction
57
57
 
58
58
  .. autoclass:: fsspec.archive.AbstractArchiveFileSystem
59
59
  :members:
@@ -107,31 +107,31 @@ Built-in Implementations
107
107
  ------------------------
108
108
 
109
109
  .. autosummary::
110
- fsspec.implementations.arrow.ArrowFSWrapper
111
- fsspec.implementations.arrow.HadoopFileSystem
112
- fsspec.implementations.cached.CachingFileSystem
113
- fsspec.implementations.cached.SimpleCacheFileSystem
114
- fsspec.implementations.cached.WholeFileCacheFileSystem
115
- fsspec.implementations.dask.DaskWorkerFileSystem
116
- fsspec.implementations.data.DataFileSystem
117
- fsspec.implementations.dbfs.DatabricksFileSystem
118
- fsspec.implementations.dirfs.DirFileSystem
119
- fsspec.implementations.ftp.FTPFileSystem
120
- fsspec.implementations.gist.GistFileSystem
121
- fsspec.implementations.git.GitFileSystem
122
- fsspec.implementations.github.GithubFileSystem
123
- fsspec.implementations.http.HTTPFileSystem
124
- fsspec.implementations.jupyter.JupyterFileSystem
125
- fsspec.implementations.libarchive.LibArchiveFileSystem
126
- fsspec.implementations.local.LocalFileSystem
127
- fsspec.implementations.memory.MemoryFileSystem
128
- fsspec.implementations.reference.ReferenceFileSystem
129
- fsspec.implementations.reference.LazyReferenceMapper
130
- fsspec.implementations.sftp.SFTPFileSystem
131
- fsspec.implementations.smb.SMBFileSystem
132
- fsspec.implementations.tar.TarFileSystem
133
- fsspec.implementations.webhdfs.WebHDFS
134
- fsspec.implementations.zip.ZipFileSystem
110
+ implementations.arrow.ArrowFSWrapper
111
+ implementations.arrow.HadoopFileSystem
112
+ implementations.cached.CachingFileSystem
113
+ implementations.cached.SimpleCacheFileSystem
114
+ implementations.cached.WholeFileCacheFileSystem
115
+ implementations.dask.DaskWorkerFileSystem
116
+ implementations.data.DataFileSystem
117
+ implementations.dbfs.DatabricksFileSystem
118
+ implementations.dirfs.DirFileSystem
119
+ implementations.ftp.FTPFileSystem
120
+ implementations.gist.GistFileSystem
121
+ implementations.git.GitFileSystem
122
+ implementations.github.GithubFileSystem
123
+ implementations.http.HTTPFileSystem
124
+ implementations.jupyter.JupyterFileSystem
125
+ implementations.libarchive.LibArchiveFileSystem
126
+ implementations.local.LocalFileSystem
127
+ implementations.memory.MemoryFileSystem
128
+ implementations.reference.ReferenceFileSystem
129
+ implementations.reference.LazyReferenceMapper
130
+ implementations.sftp.SFTPFileSystem
131
+ implementations.smb.SMBFileSystem
132
+ implementations.tar.TarFileSystem
133
+ implementations.webhdfs.WebHDFS
134
+ implementations.zip.ZipFileSystem
135
135
 
136
136
  .. autoclass:: fsspec.implementations.arrow.ArrowFSWrapper
137
137
  :members: __init__
@@ -296,12 +296,12 @@ Read Buffering
296
296
  --------------
297
297
 
298
298
  .. autosummary::
299
- fsspec.caching.BlockCache
300
- fsspec.caching.BytesCache
301
- fsspec.caching.MMapCache
302
- fsspec.caching.ReadAheadCache
303
- fsspec.caching.FirstChunkCache
304
- fsspec.caching.BackgroundBlockCache
299
+ caching.BlockCache
300
+ caching.BytesCache
301
+ caching.MMapCache
302
+ caching.ReadAheadCache
303
+ caching.FirstChunkCache
304
+ caching.BackgroundBlockCache
305
305
 
306
306
  .. autoclass:: fsspec.caching.BlockCache
307
307
  :members:
@@ -326,7 +326,7 @@ Utilities
326
326
 
327
327
  .. autosummary::
328
328
 
329
- fsspec.utils.read_block
329
+ utils.read_block
330
330
 
331
331
  .. autofunction:: fsspec.utils.read_block
332
332
 
@@ -1,6 +1,33 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ 2025.10.0
5
+ ---------
6
+
7
+ Enhancements
8
+
9
+ - specify storage_options not use use for tokenising; test instance cache (#1933)
10
+ - base class "chained" for FSs that pass through operations (#1929)
11
+
12
+ Fixes
13
+
14
+ - strip protocol for sftp (#1940)
15
+ - use one-step mv in jupyterfs (#1937)
16
+ - raise errors in jupyterfs, not return (#1936)
17
+ - add protocol attribute to http(#1935)
18
+ - allow ls() on a single file for arrowFS (#1931)
19
+ - support kwargs in webhdfs ls() (#1928)
20
+ - better discrimination for parquet in referenceFS (#1923)
21
+ - accept all mode= types in memoryFS (#1922)
22
+ - pass path list to put() in localtempfile for efficiency (#1920)
23
+ - fix docs errors (#1917)
24
+
25
+ Other
26
+
27
+ - add CoC (#1924)
28
+ - restrict github/gist tests because of rate limiting (#1918)
29
+
30
+
4
31
  2025.9.0
5
32
  --------
6
33
 
@@ -0,0 +1,126 @@
1
+ Code of Conduct
2
+ ===============
3
+
4
+ All participants in the fsspec community are expected to adhere to a Code of Conduct.
5
+
6
+ As contributors and maintainers of this project, and in the interest of
7
+ fostering an open and welcoming community, we pledge to respect all people who
8
+ contribute through reporting issues, posting feature requests, updating
9
+ documentation, submitting pull requests or patches, and other activities.
10
+
11
+ We are committed to making participation in this project a harassment-free
12
+ experience for everyone, treating everyone as unique humans deserving of
13
+ respect.
14
+
15
+ Examples of unacceptable behaviour by participants include:
16
+
17
+ - The use of sexualized language or imagery
18
+ - Personal attacks
19
+ - Trolling or insulting/derogatory comments
20
+ - Public or private harassment
21
+ - Publishing other's private information, such as physical or electronic
22
+ addresses, without explicit permission
23
+ - Other unethical or unprofessional conduct
24
+
25
+ Project maintainers have the right and responsibility to remove, edit, or
26
+ reject comments, commits, code, wiki edits, issues, and other contributions
27
+ that are not aligned to this Code of Conduct, or to ban temporarily or
28
+ permanently any contributor for other behaviours that they deem inappropriate,
29
+ threatening, offensive, or harmful.
30
+
31
+ By adopting this Code of Conduct, project maintainers commit themselves
32
+ to fairly and consistently applying these principles to every aspect of
33
+ managing this project. Project maintainers who do not follow or enforce
34
+ the Code of Conduct may be permanently removed from the project team.
35
+
36
+ This code of conduct applies both within project spaces and in public
37
+ spaces when an individual is representing the project or its community.
38
+
39
+ If you feel the code of conduct has been violated, please report the
40
+ incident to the fsspec core team.
41
+
42
+ Reporting
43
+ ---------
44
+
45
+ If you believe someone is violating theCode of Conduct we ask that you report it
46
+ to the Project by emailing community@anaconda.com. All reports will be kept
47
+ confidential. In some cases we may determine that a public statement will need
48
+ to be made. If that's the case, the identities of all victims and reporters
49
+ will remain confidential unless those individuals instruct us otherwise.
50
+ If you believe anyone is in physical danger, please notify appropriate law
51
+ enforcement first.
52
+
53
+ In your report please include:
54
+
55
+ - Your contact info
56
+ - Names (real, nicknames, or pseudonyms) of any individuals involved.
57
+ If there were other witnesses besides you, please try to include them as well.
58
+ - When and where the incident occurred. Please be as specific as possible.
59
+ - Your account of what occurred. If there is a publicly available record
60
+ please include a link.
61
+ - Any extra context you believe existed for the incident.
62
+ - If you believe this incident is ongoing.
63
+ - If you believe any member of the core team has a conflict of interest
64
+ in adjudicating the incident.
65
+ - What, if any, corrective response you believe would be appropriate.
66
+ - Any other information you believe we should have.
67
+
68
+ Core team members are obligated to maintain confidentiality with regard
69
+ to the reporter and details of an incident.
70
+
71
+ What happens next?
72
+ ~~~~~~~~~~~~~~~~~~
73
+
74
+ You will receive an email acknowledging receipt of your complaint.
75
+ The core team will immediately meet to review the incident and determine:
76
+
77
+ - What happened.
78
+ - Whether this event constitutes a code of conduct violation.
79
+ - Who the bad actor was.
80
+ - Whether this is an ongoing situation, or if there is a threat to anyone's
81
+ physical safety.
82
+ - If this is determined to be an ongoing incident or a threat to physical safety,
83
+ the working groups' immediate priority will be to protect everyone involved.
84
+
85
+ If a member of the core team is one of the named parties, they will not be
86
+ included in any discussions, and will not be provided with any confidential
87
+ details from the reporter.
88
+
89
+ If anyone on the core team believes they have a conflict of interest in
90
+ adjudicating on a reported issue, they will inform the other core team
91
+ members, and exempt themselves from any discussion about the issue.
92
+ Following this declaration, they will not be provided with any confidential
93
+ details from the reporter.
94
+
95
+ Once the working group has a complete account of the events they will make a
96
+ decision as to how to response. Responses may include:
97
+
98
+ - Nothing (if we determine no violation occurred).
99
+ - A private reprimand from the working group to the individual(s) involved.
100
+ - A public reprimand.
101
+ - An imposed vacation
102
+ - A permanent or temporary ban from some or all spaces (GitHub repositories, etc.)
103
+ - A request for a public or private apology.
104
+
105
+ We'll respond within one week to the person who filed the report with either a
106
+ resolution or an explanation of why the situation is not yet resolved.
107
+
108
+ Once we've determined our final action, we'll contact the original reporter
109
+ to let them know what action (if any) we'll be taking. We'll take into account
110
+ feedback from the reporter on the appropriateness of our response, but we
111
+ don't guarantee we'll act on it.
112
+
113
+ Acknowledgement
114
+ ---------------
115
+
116
+ This CoC is modified from the one by `BeeWare`_, which in turn refers to
117
+ the `Contributor Covenant`_ and the `Django`_ project.
118
+
119
+ .. _BeeWare: https://beeware.org/community/behavior/code-of-conduct/
120
+ .. _Contributor Covenant: https://www.contributor-covenant.org/version/1/3/0/code-of-conduct/
121
+ .. _Django: https://www.djangoproject.com/conduct/reporting/
122
+
123
+ .. raw:: html
124
+
125
+ <script data-goatcounter="https://projspec.goatcounter.com/count"
126
+ async src="//gc.zgo.at/count.js"></script>
@@ -241,7 +241,9 @@ reads the same zip-file, but extracts the CSV files and stores them locally in t
241
241
  **For developers**: this "chaining" methods works by formatting the arguments passed to ``open_*``
242
242
  into ``target_protocol`` (a simple string) and ``target_options`` (a dict) and also optionally
243
243
  ``fo`` (target path, if a specific file is required). In order for an implementation to chain
244
- successfully like this, it must look for exactly those named arguments.
244
+ successfully like this, it must look for exactly those named arguments. Implementations that
245
+ require access to the target path of their nested targets should inherit from ``ChainedFileSystem``,
246
+ which will trigger pass-through of the nested path automatically.
245
247
 
246
248
  Caching Files Locally
247
249
  ---------------------
@@ -119,6 +119,11 @@ The current list of known implementations can be found as follows
119
119
  async.rst
120
120
  api.rst
121
121
  changelog.rst
122
+ code-of-conduct.rst
123
+
124
+
125
+ These docs pages collect anonymous tracking data using goatcounter, and the
126
+ dashboard is available to the public: https://fsspec.goatcounter.com/ .
122
127
 
123
128
  .. raw:: html
124
129
 
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '2025.9.0'
32
- __version_tuple__ = version_tuple = (2025, 9, 0)
31
+ __version__ = version = '2025.10.0'
32
+ __version_tuple__ = version_tuple = (2025, 10, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -0,0 +1,125 @@
1
+ import os
2
+ import shutil
3
+ import subprocess
4
+ import sys
5
+ import time
6
+ from collections import deque
7
+ from collections.abc import Generator, Sequence
8
+
9
+ import pytest
10
+
11
+ import fsspec
12
+
13
+
14
+ @pytest.fixture()
15
+ def m():
16
+ """
17
+ Fixture providing a memory filesystem.
18
+ """
19
+ m = fsspec.filesystem("memory")
20
+ m.store.clear()
21
+ m.pseudo_dirs.clear()
22
+ m.pseudo_dirs.append("")
23
+ try:
24
+ yield m
25
+ finally:
26
+ m.store.clear()
27
+ m.pseudo_dirs.clear()
28
+ m.pseudo_dirs.append("")
29
+
30
+
31
+ class InstanceCacheInspector:
32
+ """
33
+ Helper class to inspect instance caches of filesystem classes in tests.
34
+ """
35
+
36
+ def clear(self) -> None:
37
+ """
38
+ Clear instance caches of all currently imported filesystem classes.
39
+ """
40
+ classes = deque([fsspec.spec.AbstractFileSystem])
41
+ while classes:
42
+ cls = classes.popleft()
43
+ cls.clear_instance_cache()
44
+ classes.extend(cls.__subclasses__())
45
+
46
+ def gather_counts(self, *, omit_zero: bool = True) -> dict[str, int]:
47
+ """
48
+ Gather counts of filesystem instances in the instance caches
49
+ of all currently imported filesystem classes.
50
+
51
+ Parameters
52
+ ----------
53
+ omit_zero:
54
+ Whether to omit instance types with no cached instances.
55
+ """
56
+ out: dict[str, int] = {}
57
+ classes = deque([fsspec.spec.AbstractFileSystem])
58
+ while classes:
59
+ cls = classes.popleft()
60
+ count = len(cls._cache) # there is no public interface for the cache
61
+ # note: skip intermediate AbstractFileSystem subclasses
62
+ # if they proxy the protocol attribute via a property.
63
+ if isinstance(cls.protocol, (Sequence, str)):
64
+ key = cls.protocol if isinstance(cls.protocol, str) else cls.protocol[0]
65
+ if count or not omit_zero:
66
+ out[key] = count
67
+ classes.extend(cls.__subclasses__())
68
+ return out
69
+
70
+
71
+ @pytest.fixture(scope="function", autouse=True)
72
+ def instance_caches() -> Generator[InstanceCacheInspector, None, None]:
73
+ """
74
+ Fixture to ensure empty filesystem instance caches before and after a test.
75
+
76
+ Used by default for all tests.
77
+ Clears caches of all imported filesystem classes.
78
+ Can be used to write test assertions about instance caches.
79
+
80
+ Usage:
81
+
82
+ def test_something(instance_caches):
83
+ # Test code here
84
+ fsspec.open("file://abc")
85
+ fsspec.open("memory://foo/bar")
86
+
87
+ # Test assertion
88
+ assert instance_caches.gather_counts() == {"file": 1, "memory": 1}
89
+
90
+ Returns
91
+ -------
92
+ instance_caches: An instance cache inspector for clearing and inspecting caches.
93
+ """
94
+ ic = InstanceCacheInspector()
95
+
96
+ ic.clear()
97
+ try:
98
+ yield ic
99
+ finally:
100
+ ic.clear()
101
+
102
+
103
+ @pytest.fixture(scope="function")
104
+ def ftp_writable(tmpdir):
105
+ """
106
+ Fixture providing a writable FTP filesystem.
107
+ """
108
+ pytest.importorskip("pyftpdlib")
109
+
110
+ d = str(tmpdir)
111
+ with open(os.path.join(d, "out"), "wb") as f:
112
+ f.write(b"hello" * 10000)
113
+ P = subprocess.Popen(
114
+ [sys.executable, "-m", "pyftpdlib", "-d", d, "-u", "user", "-P", "pass", "-w"]
115
+ )
116
+ try:
117
+ time.sleep(1)
118
+ yield "localhost", 2121, "user", "pass"
119
+ finally:
120
+ P.terminate()
121
+ P.wait()
122
+ try:
123
+ shutil.rmtree(tmpdir)
124
+ except Exception:
125
+ pass
@@ -330,7 +330,7 @@ def open_files(
330
330
 
331
331
  def _un_chain(path, kwargs):
332
332
  # Avoid a circular import
333
- from fsspec.implementations.cached import CachingFileSystem
333
+ from fsspec.implementations.chained import ChainedFileSystem
334
334
 
335
335
  if "::" in path:
336
336
  x = re.compile(".*[^a-z]+.*") # test for non protocol-like single word
@@ -358,7 +358,7 @@ def _un_chain(path, kwargs):
358
358
  **kws,
359
359
  )
360
360
  bit = cls._strip_protocol(bit)
361
- if "target_protocol" not in kw and issubclass(cls, CachingFileSystem):
361
+ if "target_protocol" not in kw and issubclass(cls, ChainedFileSystem):
362
362
  bit = previous_bit
363
363
  out.append((bit, protocol, kw))
364
364
  previous_bit = bit
@@ -118,6 +118,8 @@ def rsync(
118
118
  if otherfile in otherfiles:
119
119
  if update_cond == "always":
120
120
  allfiles[k] = otherfile
121
+ elif update_cond == "never":
122
+ allfiles.pop(k)
121
123
  elif update_cond == "different":
122
124
  inf1 = source_field(v) if callable(source_field) else v[source_field]
123
125
  v2 = otherfiles[otherfile]
@@ -75,10 +75,13 @@ class ArrowFSWrapper(AbstractFileSystem):
75
75
  path = self._strip_protocol(path)
76
76
  from pyarrow.fs import FileSelector
77
77
 
78
- entries = [
79
- self._make_entry(entry)
80
- for entry in self.fs.get_file_info(FileSelector(path))
81
- ]
78
+ try:
79
+ entries = [
80
+ self._make_entry(entry)
81
+ for entry in self.fs.get_file_info(FileSelector(path))
82
+ ]
83
+ except (FileNotFoundError, NotADirectoryError):
84
+ entries = [self.info(path, **kwargs)]
82
85
  if detail:
83
86
  return entries
84
87
  else:
@@ -9,13 +9,14 @@ import weakref
9
9
  from shutil import rmtree
10
10
  from typing import TYPE_CHECKING, Any, Callable, ClassVar
11
11
 
12
- from fsspec import AbstractFileSystem, filesystem
12
+ from fsspec import filesystem
13
13
  from fsspec.callbacks import DEFAULT_CALLBACK
14
14
  from fsspec.compression import compr
15
15
  from fsspec.core import BaseCache, MMapCache
16
16
  from fsspec.exceptions import BlocksizeMismatchError
17
17
  from fsspec.implementations.cache_mapper import create_cache_mapper
18
18
  from fsspec.implementations.cache_metadata import CacheMetadata
19
+ from fsspec.implementations.chained import ChainedFileSystem
19
20
  from fsspec.implementations.local import LocalFileSystem
20
21
  from fsspec.spec import AbstractBufferedFile
21
22
  from fsspec.transaction import Transaction
@@ -39,7 +40,7 @@ class WriteCachedTransaction(Transaction):
39
40
  self.fs = None # break cycle
40
41
 
41
42
 
42
- class CachingFileSystem(AbstractFileSystem):
43
+ class CachingFileSystem(ChainedFileSystem):
43
44
  """Locally caching filesystem, layer over any other FS
44
45
 
45
46
  This class implements chunk-wise local storage of remote files, for quick
@@ -60,6 +61,7 @@ class CachingFileSystem(AbstractFileSystem):
60
61
  """
61
62
 
62
63
  protocol: ClassVar[str | tuple[str, ...]] = ("blockcache", "cached")
64
+ _strip_tokenize_options = ("fo",)
63
65
 
64
66
  def __init__(
65
67
  self,
@@ -984,7 +986,9 @@ class LocalTempFile:
984
986
  os.remove(self.fn)
985
987
 
986
988
  def commit(self):
987
- self.fs.put(self.fn, self.path, **self.kwargs)
989
+ # calling put() with list arguments avoids path expansion and additional operations
990
+ # like isdir()
991
+ self.fs.put([self.fn], [self.path], **self.kwargs)
988
992
  # we do not delete the local copy, it's still in the cache.
989
993
 
990
994
  @property
@@ -0,0 +1,23 @@
1
+ from typing import ClassVar
2
+
3
+ from fsspec import AbstractFileSystem
4
+
5
+ __all__ = ("ChainedFileSystem",)
6
+
7
+
8
+ class ChainedFileSystem(AbstractFileSystem):
9
+ """Chained filesystem base class.
10
+
11
+ A chained filesystem is designed to be layered over another FS.
12
+ This is useful to implement things like caching.
13
+
14
+ This base class does very little on its own, but is used as a marker
15
+ that the class is designed for chaining.
16
+
17
+ Right now this is only used in `url_to_fs` to provide the path argument
18
+ (`fo`) to the chained filesystem from the underlying filesystem.
19
+
20
+ Additional functionality may be added in the future.
21
+ """
22
+
23
+ protocol: ClassVar[str] = "chained"
@@ -14,21 +14,21 @@ class GistFileSystem(AbstractFileSystem):
14
14
 
15
15
  Parameters
16
16
  ----------
17
- gist_id : str
17
+ gist_id: str
18
18
  The ID of the gist you want to access (the long hex value from the URL).
19
- filenames : list[str] (optional)
19
+ filenames: list[str] (optional)
20
20
  If provided, only make a file system representing these files, and do not fetch
21
21
  the list of all files for this gist.
22
- sha : str (optional)
22
+ sha: str (optional)
23
23
  If provided, fetch a particular revision of the gist. If omitted,
24
24
  the latest revision is used.
25
- username : str (optional)
26
- GitHub username for authentication (required if token is given).
27
- token : str (optional)
28
- GitHub personal access token (required if username is given).
29
- timeout : (float, float) or float, optional
25
+ username: str (optional)
26
+ GitHub username for authentication.
27
+ token: str (optional)
28
+ GitHub personal access token (required if username is given), or.
29
+ timeout: (float, float) or float, optional
30
30
  Connect and read timeouts for requests (default 60s each).
31
- kwargs : dict
31
+ kwargs: dict
32
32
  Stored on `self.request_kw` and passed to `requests.get` when fetching Gist
33
33
  metadata or reading ("opening") a file.
34
34
  """
@@ -51,10 +51,8 @@ class GistFileSystem(AbstractFileSystem):
51
51
  self.gist_id = gist_id
52
52
  self.filenames = filenames
53
53
  self.sha = sha # revision of the gist (optional)
54
- if (username is None) ^ (token is None):
55
- # Both or neither must be set
56
- if username or token:
57
- raise ValueError("Auth requires both username and token, or neither.")
54
+ if username is not None and token is None:
55
+ raise ValueError("User auth requires a token")
58
56
  self.username = username
59
57
  self.token = token
60
58
  self.request_kw = kwargs
@@ -67,9 +65,18 @@ class GistFileSystem(AbstractFileSystem):
67
65
  @property
68
66
  def kw(self):
69
67
  """Auth parameters passed to 'requests' if we have username/token."""
70
- if self.username is not None and self.token is not None:
71
- return {"auth": (self.username, self.token), **self.request_kw}
72
- return self.request_kw
68
+ kw = {
69
+ "headers": {
70
+ "Accept": "application/vnd.github+json",
71
+ "X-GitHub-Api-Version": "2022-11-28",
72
+ }
73
+ }
74
+ kw.update(self.request_kw)
75
+ if self.username and self.token:
76
+ kw["auth"] = (self.username, self.token)
77
+ elif self.token:
78
+ kw["headers"]["Authorization"] = f"Bearer {self.token}"
79
+ return kw
73
80
 
74
81
  def _fetch_gist_metadata(self):
75
82
  """
@@ -229,4 +236,6 @@ class GistFileSystem(AbstractFileSystem):
229
236
  pass # skip
230
237
  else:
231
238
  out[p] = e
239
+ if len(paths) == 1 and paths[0] == path:
240
+ return out[path]
232
241
  return out