Skip to content

Commit a25a989

Browse files
authored
Setup a minimal mypy config (#1268)
* Minimal mypy setup * Fix mypy errors * Use `from __future__ import annotations`
1 parent 979a590 commit a25a989

File tree

15 files changed

+91
-25
lines changed

15 files changed

+91
-25
lines changed

.github/workflows/main.yaml

+16
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ jobs:
6868
- uses: actions/setup-python@main
6969
- uses: pre-commit/action@main
7070

71+
typecheck:
72+
runs-on: ubuntu-latest
73+
steps:
74+
- name: Checkout
75+
uses: actions/checkout@v3
76+
77+
- name: Setup conda
78+
uses: mamba-org/provision-with-micromamba@main
79+
with:
80+
environment-file: ci/environment-typecheck.yml
81+
82+
- name: mypy
83+
shell: bash -l {0}
84+
run: |
85+
mypy fsspec
86+
7187
downstream:
7288
name: downstream
7389
runs-on: ubuntu-latest

ci/environment-typecheck.yml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: test_env
2+
channels:
3+
- conda-forge
4+
dependencies:
5+
- mypy=1.3
6+
- pyarrow
7+
- python=3.8
8+
- pip
9+
- pip:
10+
- types-paramiko
11+
- types-requests
12+
- types-tqdm
13+
- types-ujson

fsspec/_version.py

-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ class NotThisMethod(Exception):
5151
"""Exception raised if a method is not valid for the current scenario."""
5252

5353

54-
LONG_VERSION_PY = {}
5554
HANDLERS = {}
5655

5756

fsspec/asyn.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import threading
1010
from contextlib import contextmanager
1111
from glob import has_magic
12-
from typing import Iterable
12+
from typing import TYPE_CHECKING, Iterable
1313

1414
from .callbacks import _DEFAULT_CALLBACK
1515
from .exceptions import FSTimeoutError
@@ -154,13 +154,18 @@ def get_loop():
154154
return loop[0]
155155

156156

157-
try:
157+
if TYPE_CHECKING:
158158
import resource
159-
except ImportError:
160-
resource = None
161-
ResourceError = OSError
159+
160+
ResourceError = resource.error
162161
else:
163-
ResourceError = getattr(resource, "error", IOError)
162+
try:
163+
import resource
164+
except ImportError:
165+
resource = None
166+
ResourceError = OSError
167+
else:
168+
ResourceError = getattr(resource, "error", IOError)
164169

165170
_DEFAULT_BATCH_SIZE = 128
166171
_NOFILES_DEFAULT_BATCH_SIZE = 1280

fsspec/config.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
from __future__ import annotations
2+
13
import configparser
24
import json
35
import os
46
import warnings
7+
from typing import Any
58

6-
conf = {}
9+
conf: dict[str, dict[str, Any]] = {}
710
default_conf_dir = os.path.join(os.path.expanduser("~"), ".config/fsspec")
811
conf_dir = os.environ.get("FSSPEC_CONFIG_DIR", default_conf_dir)
912

fsspec/gui.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import logging
44
import os
55
import re
6+
from typing import ClassVar, Sequence
67

78
import panel as pn
89

@@ -25,9 +26,11 @@ class SigSlot(object):
2526
By default, all signals emit a DEBUG logging statement.
2627
"""
2728

28-
signals = [] # names of signals that this class may emit
29-
# each of which must be set by _register for any new instance
30-
slots = [] # names of actions that this class may respond to
29+
# names of signals that this class may emit each of which must be
30+
# set by _register for any new instance
31+
signals: ClassVar[Sequence[str]] = []
32+
# names of actions that this class may respond to
33+
slots: ClassVar[Sequence[str]] = []
3134

3235
# each of which must be a method name
3336

fsspec/implementations/cached.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import contextlib
24
import hashlib
35
import inspect
@@ -7,6 +9,7 @@
79
import tempfile
810
import time
911
from shutil import rmtree
12+
from typing import ClassVar
1013

1114
from fsspec import AbstractFileSystem, filesystem
1215
from fsspec.callbacks import _DEFAULT_CALLBACK
@@ -39,7 +42,7 @@ class CachingFileSystem(AbstractFileSystem):
3942
allowed, for testing
4043
"""
4144

42-
protocol = ("blockcache", "cached")
45+
protocol: ClassVar[str | tuple[str, ...]] = ("blockcache", "cached")
4346

4447
def __init__(
4548
self,

fsspec/implementations/memory.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
from __future__ import absolute_import, division, print_function
1+
from __future__ import absolute_import, annotations, division, print_function
22

33
import logging
44
from datetime import datetime
55
from errno import ENOTEMPTY
66
from io import BytesIO
7+
from typing import Any, ClassVar
78

89
from fsspec import AbstractFileSystem
910

@@ -17,7 +18,7 @@ class MemoryFileSystem(AbstractFileSystem):
1718
in memory filesystem.
1819
"""
1920

20-
store = {} # global, do not overwrite!
21+
store: ClassVar[dict[str, Any]] = {} # global, do not overwrite!
2122
pseudo_dirs = [""] # global, do not overwrite!
2223
protocol = "memory"
2324
root_marker = "/"

fsspec/implementations/reference.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
import math
77
import os
88
from functools import lru_cache
9+
from typing import TYPE_CHECKING
910

1011
import fsspec.core
1112

1213
try:
1314
import ujson as json
1415
except ImportError:
15-
import json
16+
if not TYPE_CHECKING:
17+
import json
1618

1719
from ..asyn import AsyncFileSystem
1820
from ..callbacks import _DEFAULT_CALLBACK
@@ -803,11 +805,11 @@ def cat(self, path, recursive=False, on_error="raise", **kwargs):
803805
urls.append(u)
804806
starts.append(s)
805807
ends.append(e)
806-
except FileNotFoundError as e:
808+
except FileNotFoundError as err:
807809
if on_error == "raise":
808810
raise
809811
if on_error != "omit":
810-
out[p] = e
812+
out[p] = err
811813

812814
# process references into form for merging
813815
urls2 = []
@@ -924,7 +926,6 @@ def _render_jinja(u):
924926
self.references.update(self._process_gen(references.get("gen", [])))
925927

926928
def _process_templates(self, tmp):
927-
928929
self.templates = {}
929930
if self.template_overrides is not None:
930931
tmp.update(self.template_overrides)
@@ -939,7 +940,6 @@ def _process_templates(self, tmp):
939940
self.templates[k] = v
940941

941942
def _process_gen(self, gens):
942-
943943
out = {}
944944
for gen in gens:
945945
dimension = {

fsspec/implementations/tar.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def __init__(
8181

8282
self._fo_ref = fo
8383
self.fo = fo # the whole instance is a context
84-
self.tar: tarfile.TarFile = tarfile.TarFile(fileobj=self.fo)
84+
self.tar = tarfile.TarFile(fileobj=self.fo)
8585
self.dir_cache = None
8686

8787
self.index_store = index_store

fsspec/implementations/tests/test_tar.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
from __future__ import annotations
2+
13
import os
24
import shutil
35
import tarfile
46
import tempfile
57
from io import BytesIO
68
from pathlib import Path
7-
from typing import Dict
89

910
import pytest
1011

@@ -210,7 +211,7 @@ def test_ls_with_folders(compression: str, tmp_path: Path):
210211
but make sure that the reading filesystem is still able to resolve the
211212
intermediate folders, like the ZipFileSystem.
212213
"""
213-
tar_data: Dict[str, bytes] = {
214+
tar_data: dict[str, bytes] = {
214215
"a.pdf": b"Hello A!",
215216
"b/c.pdf": b"Hello C!",
216217
"d/e/f.pdf": b"Hello F!",

fsspec/registry.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
from __future__ import annotations
2+
13
import importlib
24
import types
35
import warnings
46

57
__all__ = ["registry", "get_filesystem_class", "default"]
68

79
# internal, mutable
8-
_registry = {}
10+
_registry: dict[str, type] = {}
911

1012
# external, immutable
1113
registry = types.MappingProxyType(_registry)

fsspec/spec.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import io
24
import logging
35
import os
@@ -7,6 +9,7 @@
79
from errno import ESPIPE
810
from glob import has_magic
911
from hashlib import sha256
12+
from typing import ClassVar
1013

1114
from .callbacks import _DEFAULT_CALLBACK
1215
from .config import apply_config, conf
@@ -101,7 +104,7 @@ class AbstractFileSystem(metaclass=_Cached):
101104
_cached = False
102105
blocksize = 2**22
103106
sep = "/"
104-
protocol = "abstract"
107+
protocol: ClassVar[str | tuple[str, ...]] = "abstract"
105108
_latest = None
106109
async_impl = False
107110
mirror_sync_methods = False

fsspec/utils.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import logging
24
import math
35
import os
@@ -110,7 +112,7 @@ def update_storage_options(options, inherited=None):
110112

111113

112114
# Compression extensions registered via fsspec.compression.register_compression
113-
compressions = {}
115+
compressions: dict[str, str] = {}
114116

115117

116118
def infer_compression(filename):

setup.cfg

+15
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,18 @@ skip=
3737
docs/source/conf.py
3838
versioneer.py
3939
fsspec/_version
40+
41+
[mypy]
42+
follow_imports = normal
43+
ignore_missing_imports = True
44+
enable_error_code = ignore-without-code,truthy-bool,truthy-iterable,unused-awaitable
45+
46+
disallow_untyped_decorators = True
47+
strict_equality = True
48+
warn_redundant_casts = True
49+
warn_unused_configs = True
50+
warn_unused_ignores = True
51+
52+
53+
# don't bother type-checking test_*.py or conftest.py files
54+
exclude = (test_.*|conftest)\.py$

0 commit comments

Comments
 (0)