Skip to content

Commit 1f41318

Browse files
committed
[744] Add mypy type checking
1 parent dbf5998 commit 1f41318

16 files changed

+94
-50
lines changed

.github/workflows/main.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# This action is based on Github's default starter workflow for Python at
2+
# https://github.com/actions/starter-workflows/blob/master/ci/python-package.yml
3+
# (C) Github, MIT License
4+
5+
name: "Python type checking"
6+
7+
on: [push, pull_request]
8+
9+
jobs:
10+
build:
11+
12+
runs-on: ubuntu-latest
13+
14+
strategy:
15+
matrix:
16+
python-version: ['3.9']
17+
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- name: Set up Python ${{ matrix.python-version }}
22+
uses: actions/setup-python@v5
23+
with:
24+
python-version: ${{ matrix.python-version }}
25+
26+
- name: Install dependencies
27+
run: |
28+
pip install ./
29+
pip install mypy==1.16.1
30+
31+
- name: Run type checks
32+
run: |
33+
mypy --ignore-missing-imports irods
34+

irods/exception.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import numbers
77
import os
88
import sys
9+
from typing import Any, Dict
910

1011

1112
class PycommandsException(Exception):
@@ -91,7 +92,8 @@ def __repr__(self):
9192

9293

9394
class iRODSExceptionMeta(type):
94-
codes = {}
95+
# Use "Any" type for values because Codacity fails when using a more specific type.
96+
codes: Dict[int, Any] = {}
9597
positive_code_error_message = (
9698
"For {name}, a positive code of {attrs[code]} was declared."
9799
)

irods/manager/data_object_manager.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import logging
66
import os
77
import weakref
8+
from typing import Any, List, Type
89
from irods.models import DataObject, Collection
910
from irods.manager import Manager
1011
from irods.manager._internal import _api_impl, _logical_path
@@ -38,8 +39,8 @@
3839

3940
logger = logging.getLogger(__name__)
4041

41-
_update_types = []
42-
_update_functions = weakref.WeakKeyDictionary()
42+
_update_types: List[Type] = []
43+
_update_functions: weakref.WeakKeyDictionary[Type, Any] = weakref.WeakKeyDictionary()
4344

4445

4546
def register_update_instance(object_, updater): # updater
@@ -414,10 +415,10 @@ def chksum(self, path, **options):
414415
"[",
415416
"{",
416417
): # in iRODS 4.2.11 and later, myStr is in JSON format.
417-
exc = Server_Checksum_Warning(checksum)
418+
exception = Server_Checksum_Warning(checksum)
418419
if not r_error_stack:
419-
r_error_stack.fill(exc.response)
420-
raise exc
420+
r_error_stack.fill(exception.response)
421+
raise exception
421422
except iRODSMessage.ResponseNotParseable:
422423
# response.msg is None when VERIFY_CHKSUM_KW is used
423424
pass

irods/manager/metadata_manager.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
import copy
33
from os.path import dirname, basename
4+
from typing import Any, Dict
45

56
from irods.manager import Manager
67
from irods.message import MetadataRequest, iRODSMessage, JSON_Message
@@ -32,7 +33,7 @@ class MetadataManager(Manager):
3233
def use_timestamps(self):
3334
return getattr(self, "_use_ts", False)
3435

35-
__kw = {} # default (empty) keywords
36+
__kw : Dict[str, Any] = {} # default (empty) keywords
3637

3738
def _updated_keywords(self, opts):
3839
kw_ = self.__kw.copy()

irods/message/__init__.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import socket
66
import json
77
import irods.exception as ex
8+
from typing import Optional
89
import xml.etree.ElementTree as ET_xml
910
import defusedxml.ElementTree as ET_secure_xml
1011
from . import quasixml as ET_quasi_xml
@@ -85,15 +86,15 @@ class BadXMLSpec(RuntimeError):
8586

8687
_XML_strings = {k: v for k, v in vars(XML_Parser_Type).items() if k.endswith("_XML")}
8788

88-
_default_XML = os.environ.get(
89+
_default_XML_env = os.environ.get(
8990
"PYTHON_IRODSCLIENT_DEFAULT_XML", globals().get("_default_XML")
9091
)
9192

92-
if not _default_XML:
93+
if not _default_XML_env:
9394
_default_XML = XML_Parser_Type.STANDARD_XML
9495
else:
9596
try:
96-
_default_XML = _XML_strings[_default_XML]
97+
_default_XML = _XML_strings[_default_XML_env]
9798
except KeyError:
9899
raise BadXMLSpec("XML parser type not recognized")
99100

@@ -866,7 +867,7 @@ class VersionResponse(Message):
866867

867868
class _admin_request_base(Message):
868869

869-
_name = None
870+
_name : Optional[str] = None
870871

871872
def __init__(self, *args):
872873
if self.__class__._name is None:
@@ -1153,7 +1154,7 @@ class ModDataObjMeta(Message):
11531154
# -- A tuple-descended class which facilitates filling in a
11541155
# quasi-RError stack from a JSON formatted list.
11551156

1156-
_Server_Status_Message = namedtuple("server_status_msg", ("msg", "status"))
1157+
_Server_Status_Message = namedtuple("_Server_Status_Message", ("msg", "status"))
11571158

11581159

11591160
class RErrorStack(list):

irods/message/ordered.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,18 @@
22
# http://askawizard.blogspot.com/2008/10/ordered-properties-python-saga-part-5.html
33
from itertools import count
44

5-
try:
6-
next_counter = count().__next__
7-
except AttributeError:
8-
next_counter = count().next
9-
10-
115
class OrderedProperty:
126

137
def __init__(self, *args, **kws):
14-
self._creation_counter = next_counter()
8+
self._creation_counter = count().__next__()
159
super(OrderedProperty, self).__init__(*args, **kws)
1610

1711

1812
class OrderedMetaclass(type):
1913

2014
def __init__(self, name, bases, attys):
2115
super(OrderedMetaclass, self).__init__(name, bases, attys)
22-
self._creation_counter = next_counter()
16+
self._creation_counter = count().__next__()
2317
self._ordered_properties = sorted(
2418
(
2519
(name, value)

irods/message/quasixml.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,14 +176,8 @@ def parse_elem(tokens):
176176
return elem
177177

178178

179-
try:
180-
unicode # Python 2
181-
except NameError:
182-
unicode = str
183-
184-
185179
def fromstring(s):
186-
if type(s) is unicode:
180+
if type(s) is str:
187181
s = s.encode("utf-8")
188182
if type(s) is not bytes:
189183
raise TypeError("expected a bytes-object, got {}".format(type(s).__name__))

irods/models.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
from typing import Dict, List, Tuple
12
from irods.column import Column, Integer, String, DateTime, Keyword
23

34

45
class ModelBase(type):
5-
column_items = []
6-
column_dict = {}
6+
column_items : List[Tuple[int, Column]] = []
7+
column_dict : Dict[int, Column] = {}
78

89
@classmethod
910
def columns(cls):

irods/parallel.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import concurrent.futures
1010
import threading
1111
import multiprocessing
12+
from typing import List, Union
1213

1314
from irods.data_object import iRODSDataObject
1415
from irods.exception import DataObjectDoesNotExist
@@ -603,7 +604,8 @@ def setupLoggingWithDateTimeHeader(name, level=logging.DEBUG):
603604
sess = iRODSSession(irods_env_file=env_file, **ssl_settings)
604605
atexit.register(lambda: sess.cleanup())
605606

606-
opt, arg = getopt.getopt(sys.argv[1:], "vL:l:aR:N:")
607+
opt, arg_ = getopt.getopt(sys.argv[1:], "vL:l:aR:N:")
608+
arg: List[Union[str, int]] = list(arg_)
607609

608610
opts = dict(opt)
609611

@@ -622,8 +624,9 @@ def setupLoggingWithDateTimeHeader(name, level=logging.DEBUG):
622624

623625
kwarg = {k.lstrip("-"): v for k, v in opts.items()}
624626

625-
arg[1] = Oper.PUT if arg[1].lower() in ("w", "put", "a") else Oper.GET
626-
if async_xfer is not None:
627+
# The purpose of the isinstance calls in the lines below is to allow mypy to infer the current type
628+
arg[1] = Oper.PUT if isinstance(arg[1], str) and arg[1].lower() in ("w", "put", "a") else Oper.GET
629+
if isinstance(arg[1], int) and async_xfer is not None:
627630
arg[1] |= Oper.NONBLOCKING
628631

629632
ret = io_main(sess, *arg, **kwarg) # arg[0] = data object or path

irods/prc_write_irodsA.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import getopt
44
import textwrap
55
import sys
6+
from typing import Callable, Dict
67

78
from irods.auth.pam_password import _get_pam_password_from_stdin as get_password
89
from irods.client_init import write_pam_irodsA_file, write_native_irodsA_file
@@ -21,7 +22,7 @@
2122
"""
2223
)
2324

24-
vector = {"pam_password": write_pam_irodsA_file, "native": write_native_irodsA_file}
25+
vector : Dict[str, Callable] = {"pam_password": write_pam_irodsA_file, "native": write_native_irodsA_file}
2526
opts, args = getopt.getopt(sys.argv[1:], "hi:", ["ttl=", "help"])
2627
optD = dict(opts)
2728
help_selected = {*optD} & {"-h", "--help"}
@@ -45,10 +46,12 @@
4546
inp_stream = optD.get("-i", None)
4647
if "--ttl" in optD:
4748
options["ttl"] = optD["--ttl"]
48-
pw = get_password(
49-
sys.stdin if inp_stream in ("-", None) else open(inp_stream, "r"),
50-
prompt=f"Enter current password for scheme {scheme!r}: ",
51-
)
49+
if inp_stream is None or inp_stream == "-":
50+
pw = get_password(sys.stdin,
51+
prompt=f"Enter current password for scheme {scheme!r}: ",)
52+
else:
53+
pw = get_password(open(inp_stream, "r", encoding='utf-8'),
54+
prompt=f"Enter current password for scheme {scheme!r}: ",)
5255
vector[scheme](pw, **options)
5356
else:
5457
print("did not recognize authentication scheme argument", file=sys.stderr)

0 commit comments

Comments
 (0)