Skip to content

Commit d473a4b

Browse files
committed
Add Python formatting checks
1 parent 30f9e2d commit d473a4b

10 files changed

+139
-124
lines changed

.github/workflows/python-test.yml

+10-19
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,6 @@ defaults:
1313
working-directory: ./python
1414

1515
jobs:
16-
lint:
17-
runs-on: ubuntu-latest
18-
steps:
19-
- uses: actions/checkout@v4
20-
- name: Setup Python
21-
uses: actions/setup-python@v4
22-
with:
23-
python-version: 3.12
24-
- name: Install dev dependencies
25-
run: |
26-
pip3 install -r requirements-dev.txt
27-
- name: Type checking
28-
run: |
29-
mypy python
30-
3116
test:
3217
strategy:
3318
fail-fast: false
@@ -68,13 +53,19 @@ jobs:
6853
sccache: 'true'
6954
container: 'off'
7055
working-directory: ./python
71-
args: --features kerberos
56+
args: --features kerberos --extras devel
7257

73-
- name: Install dev dependencies and run tests
58+
- name: Run lints
59+
run: |
60+
source .venv/bin/activate
61+
mypy
62+
isort . --check
63+
black . --check
64+
65+
- name: Run tests
7466
run: |
7567
source .venv/bin/activate
76-
pip3 install -r requirements-dev.txt
77-
pytest
68+
mypy
7869
7970
build:
8071
runs-on: ubuntu-latest

python/README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ The same requirements apply as the Rust tests, requiring Java, Maven, Hadoop, an
2222
python3 -m venv .venv
2323
source .venv/bin/activate
2424
pip3 install maturin
25-
pip3 install -r requirements-dev.txt
26-
maturin develop
25+
maturin develop -E devel
2726
pytest
2827
```

python/conftest.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
import subprocess
2+
import urllib
13
import urllib.parse
4+
25
import fsspec
3-
import subprocess
46
import pytest
5-
import urllib
67

78
from hdfs_native.fsspec import HdfsFileSystem
89

9-
@pytest.fixture(scope='module')
10+
11+
@pytest.fixture(scope="module")
1012
def minidfs():
1113
child = subprocess.Popen(
1214
[
@@ -23,7 +25,7 @@ def minidfs():
2325
stderr=subprocess.DEVNULL,
2426
universal_newlines=True,
2527
encoding="utf8",
26-
bufsize=0
28+
bufsize=0,
2729
)
2830

2931
output = child.stdout.readline().strip()
@@ -36,7 +38,8 @@ def minidfs():
3638
except:
3739
child.kill()
3840

39-
@pytest.fixture(scope='module')
41+
42+
@pytest.fixture(scope="module")
4043
def fs(minidfs: str) -> HdfsFileSystem:
4144
url = urllib.parse.urlparse(minidfs)
42-
return fsspec.filesystem(url.scheme, host=url.hostname, port=url.port)
45+
return fsspec.filesystem(url.scheme, host=url.hostname, port=url.port)

python/hdfs_native/__init__.py

+23-13
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
import io
22
import os
33
from typing import Dict, Iterator, Optional
4-
from typing_extensions import Buffer
4+
5+
# For some reason mypy doesn't think this exists
6+
from typing_extensions import Buffer # type: ignore
57

68
from ._internal import *
79

10+
811
class FileReader(io.RawIOBase):
9-
12+
1013
def __init__(self, inner: "RawFileReader"):
1114
self.inner = inner
1215

1316
def __len__(self) -> int:
1417
return self.inner.file_length()
15-
18+
1619
def __enter__(self):
1720
# Don't need to do anything special here
1821
return self
19-
22+
2023
def __exit__(self, *_args):
2124
# Future updates could close the file manually here if that would help clean things up
2225
pass
@@ -34,11 +37,11 @@ def seek(self, offset: int, whence=os.SEEK_SET):
3437
elif whence == os.SEEK_END:
3538
self.inner.seek(self.inner.file_length() + offset)
3639
else:
37-
raise ValueError(f'Unsupported whence {whence}')
40+
raise ValueError(f"Unsupported whence {whence}")
3841

3942
def seekable(self):
4043
return True
41-
44+
4245
def tell(self) -> int:
4346
return self.inner.tell()
4447

@@ -48,17 +51,18 @@ def readable(self) -> bool:
4851
def read(self, size: int = -1) -> bytes:
4952
"""Read up to `size` bytes from the file, or all content if -1"""
5053
return self.inner.read(size)
51-
54+
5255
def readall(self) -> bytes:
5356
return self.read()
5457

5558
def read_range(self, offset: int, len: int) -> bytes:
5659
"""Read `len` bytes from the file starting at `offset`. Doesn't affect the position in the file"""
5760
return self.inner.read_range(offset, len)
58-
61+
5962
def close(self) -> None:
6063
pass
6164

65+
6266
class FileWriter(io.RawIOBase):
6367

6468
def __init__(self, inner: "RawFileWriter"):
@@ -77,10 +81,11 @@ def close(self) -> None:
7781

7882
def __enter__(self) -> "FileWriter":
7983
return self
80-
84+
8185
def __exit__(self, *_args):
8286
self.close()
8387

88+
8489
class Client:
8590

8691
def __init__(self, url: str, config: Optional[Dict[str, str]] = None):
@@ -101,7 +106,7 @@ def read(self, path: str) -> FileReader:
101106
def create(self, path: str, write_options: WriteOptions) -> FileWriter:
102107
"""Creates a new file and opens it for writing at `path`"""
103108
return FileWriter(self.inner.create(path, write_options))
104-
109+
105110
def append(self, path: str) -> FileWriter:
106111
"""Opens an existing file to append to at `path`"""
107112
return FileWriter(self.inner.append(path))
@@ -129,15 +134,20 @@ def delete(self, path: str, recursive: bool) -> bool:
129134
is a non-empty directory, this will fail.
130135
"""
131136
return self.inner.delete(path, recursive)
132-
137+
133138
def set_times(self, path: str, mtime: int, atime: int) -> None:
134139
"""
135140
Changes the modification time and access time of the file at `path` to `mtime` and `atime`, respectively.
136141
"""
137142
return self.inner.set_times(path, mtime, atime)
138143

139-
def set_owner(self, path: str, owner: Optional[str] = None, group: Optional[str] = None) -> None:
144+
def set_owner(
145+
self,
146+
path: str,
147+
owner: Optional[str] = None,
148+
group: Optional[str] = None,
149+
) -> None:
140150
"""
141151
Sets the owner and/or group for the file at `path`
142152
"""
143-
return self.inner.set_owner(path, owner, group)
153+
return self.inner.set_owner(path, owner, group)

python/hdfs_native/_internal.pyi

+8-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import Dict, Iterator, Optional
2-
from typing_extensions import Buffer
32

3+
# For some reason mypy doesn't think this exists
4+
from typing_extensions import Buffer # type: ignore
45

56
class FileStatus:
67
path: str
@@ -44,23 +45,18 @@ class RawFileWriter:
4445

4546
class RawClient:
4647
def __init__(self, url: str, config: Optional[Dict[str, str]]) -> None: ...
47-
4848
def get_file_info(self, path: str) -> FileStatus: ...
49-
5049
def list_status(self, path: str, recursive: bool) -> Iterator[FileStatus]: ...
51-
5250
def read(self, path: str) -> RawFileReader: ...
53-
5451
def create(self, path: str, write_options: WriteOptions) -> RawFileWriter: ...
55-
5652
def append(self, path: str) -> RawFileWriter: ...
57-
5853
def mkdirs(self, path: str, permission: int, create_parent: bool) -> None: ...
59-
6054
def rename(self, src: str, dst: str, overwrite: bool) -> None: ...
61-
6255
def delete(self, path: str, recursive: bool) -> bool: ...
63-
6456
def set_times(self, path: str, mtime: int, atime: int) -> None: ...
65-
66-
def set_owner(self, path: str, owner: Optional[str], group: Optional[str]) -> None: ...
57+
def set_owner(
58+
self,
59+
path: str,
60+
owner: Optional[str],
61+
group: Optional[str],
62+
) -> None: ...

python/hdfs_native/fsspec.py

+27-25
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
from contextlib import suppress
2-
from datetime import datetime
31
import secrets
42
import shutil
53
import time
4+
from contextlib import suppress
5+
from datetime import datetime
66
from typing import TYPE_CHECKING, Dict, List, Optional, Union
7+
78
from fsspec import AbstractFileSystem
89
from fsspec.utils import tokenize
910

@@ -12,36 +13,37 @@
1213
if TYPE_CHECKING:
1314
from . import FileStatus
1415

16+
1517
class HdfsFileSystem(AbstractFileSystem):
1618
def __init__(self, host: str, port: Optional[int] = None, *args, **storage_options):
1719
super().__init__(host, port, *args, **storage_options)
1820
self.host = host
1921
self.port = port
20-
url = f'{self.protocol}://{host}'
22+
url = f"{self.protocol}://{host}"
2123
if port:
22-
url += f':{port}'
24+
url += f":{port}"
2325
self.client = Client(url)
2426

2527
@property
2628
def fsid(self):
27-
return f'hdfs_native_{tokenize(self.protocol, self.host, self.port)}'
29+
return f"hdfs_native_{tokenize(self.protocol, self.host, self.port)}"
2830

29-
def _convert_file_status(self, file_status: 'FileStatus') -> Dict:
31+
def _convert_file_status(self, file_status: "FileStatus") -> Dict:
3032
return {
31-
'name': file_status.path,
32-
'size': file_status.length,
33-
'type': 'directory' if file_status.isdir else 'file',
34-
'permission': file_status.permission,
35-
'owner': file_status.owner,
36-
'group': file_status.group,
37-
'modification_time': file_status.modification_time,
38-
'access_time': file_status.access_time
33+
"name": file_status.path,
34+
"size": file_status.length,
35+
"type": "directory" if file_status.isdir else "file",
36+
"permission": file_status.permission,
37+
"owner": file_status.owner,
38+
"group": file_status.group,
39+
"modification_time": file_status.modification_time,
40+
"access_time": file_status.access_time,
3941
}
4042

4143
def info(self, path, **_kwargs) -> Dict:
4244
file_status = self.client.get_file_info(path)
4345
return self._convert_file_status(file_status)
44-
46+
4547
def exists(self, path, **_kwargs):
4648
try:
4749
self.info(path)
@@ -58,23 +60,23 @@ def ls(self, path: str, detail=True, **kwargs) -> List[Union[str, Dict]]:
5860

5961
def touch(self, path: str, truncate=True, **kwargs):
6062
if truncate or not self.exists(path):
61-
with self.open(path, 'wb', **kwargs):
63+
with self.open(path, "wb", **kwargs):
6264
pass
6365
else:
6466
now = int(time.time() * 1000)
6567
self.client.set_times(path, now, now)
6668

6769
def mkdir(self, path: str, create_parents=True, **kwargs):
68-
self.client.mkdirs(path, kwargs.get('permission', 0o755), create_parents)
70+
self.client.mkdirs(path, kwargs.get("permission", 0o755), create_parents)
6971

7072
def makedirs(self, path: str, exist_ok=False):
7173
if not exist_ok and self.exists(path):
72-
raise FileExistsError('File or directory already exists')
74+
raise FileExistsError("File or directory already exists")
7375

7476
return self.mkdir(path, create_parents=True)
7577

7678
def mv(self, path1: str, path2: str, **kwargs):
77-
self.client.rename(path1, path2, kwargs.get('overwrite', False))
79+
self.client.rename(path1, path2, kwargs.get("overwrite", False))
7880

7981
def cp_file(self, path1, path2, **kwargs):
8082
with self._open(path1, "rb") as lstream:
@@ -93,7 +95,7 @@ def rmdir(self, path: str) -> None:
9395

9496
def rm(self, path: str, recursive=False, maxdepth: Optional[int] = None) -> None:
9597
if maxdepth is not None:
96-
raise NotImplementedError('maxdepth is not supported')
98+
raise NotImplementedError("maxdepth is not supported")
9799
self.client.delete(path, recursive)
98100

99101
def rm_file(self, path: str):
@@ -110,19 +112,19 @@ def _open(
110112
overwrite=True,
111113
replication: Optional[int] = None,
112114
block_size: Optional[int] = None,
113-
**_kwargs
115+
**_kwargs,
114116
):
115-
if mode == 'rb':
117+
if mode == "rb":
116118
return self.client.read(path)
117-
elif mode == 'wb':
119+
elif mode == "wb":
118120
write_options = WriteOptions()
119121
write_options.overwrite = overwrite
120122
if replication:
121123
write_options.replication = replication
122124
if block_size:
123125
write_options.block_size = block_size
124126
return self.client.create(path, write_options=write_options)
125-
elif mode == 'ab':
127+
elif mode == "ab":
126128
return self.client.append(path)
127129
else:
128-
raise ValueError(f'Mode {mode} is not supported')
130+
raise ValueError(f"Mode {mode} is not supported")

0 commit comments

Comments
 (0)