Skip to content

Commit

Permalink
Merge pull request #3315 from hiro-o918/master
Browse files Browse the repository at this point in the history
Implement mypy plugin for `luigi.Task`
  • Loading branch information
RRap0so authored Sep 24, 2024
2 parents 8804843 + 4744560 commit 829fc0c
Show file tree
Hide file tree
Showing 16 changed files with 623 additions and 19 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/pythonbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,9 @@ jobs:
tox-env: py312-azureblob


- python-version: 3.9
- python-version: "3.10"
tox-env: flake8
- python-version: 3.9
- python-version: "3.10"
tox-env: docs

steps:
Expand Down
2 changes: 2 additions & 0 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ def _warn_node(self, msg, node, *args, **kwargs):
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

autodoc_mock_imports = ["mypy"]

# Some regression introduced
# https://github.com/sphinx-doc/sphinx/issues/2330
# https://github.com/spotify/luigi/pull/1555
Expand Down
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Table of Contents
configuration.rst
logging.rst
design_and_limitations.rst
mypy.rst

API Reference
-------------
Expand Down
42 changes: 42 additions & 0 deletions doc/mypy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Mypy plugin
--------------

Mypy plugin provides type checking for ``luigi.Task`` using Mypy.

Require Python 3.8 or later.

How to use
~~~~~~~~~~

Configure Mypy to use this plugin by adding the following to your ``mypy.ini`` file:

.. code:: ini
[mypy]
plugins = luigi.mypy
or by adding the following to your ``pyproject.toml`` file:

.. code:: toml
[tool.mypy]
plugins = ["luigi.mypy"]
Then, run Mypy as usual.

Examples
~~~~~~~~

For example the following code linted by Mypy:

.. code:: python
import luigi
class MyTask(luigi.Task):
foo: int = luigi.IntParameter()
bar: str = luigi.Parameter()
MyTask(foo=1, bar='2') # OK
MyTask(foo='1', bar='2') # Error: Argument 1 to "Foo" has incompatible type "str"; expected "int"
2 changes: 1 addition & 1 deletion luigi/configuration/cfg_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def before_write(self, parser, section, option, value):
class LuigiConfigParser(BaseParser, ConfigParser):
NO_DEFAULT = object()
enabled = True
optionxform = str
optionxform = str # type: ignore
_instance = None
_config_paths = [
'/etc/luigi/client.cfg', # Deprecated old-style global luigi config
Expand Down
8 changes: 5 additions & 3 deletions luigi/configuration/toml_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,22 @@
#
import os.path
from configparser import ConfigParser
from typing import Any, Dict

try:
import toml
toml_enabled = True
except ImportError:
toml = False
toml_enabled = False

from .base_parser import BaseParser
from ..freezing import recursively_freeze


class LuigiTomlParser(BaseParser, ConfigParser):
NO_DEFAULT = object()
enabled = bool(toml)
data = dict()
enabled = bool(toml_enabled)
data: Dict[str, Any] = dict()
_instance = None
_config_paths = [
'/etc/luigi/luigi.toml',
Expand Down
6 changes: 3 additions & 3 deletions luigi/db_task_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def find_task_by_id(self, id, session=None):
return session.query(TaskRecord).get(id)


class TaskParameter(Base):
class TaskParameter(Base): # type: ignore
"""
Table to track luigi.Parameter()s of a Task.
"""
Expand All @@ -201,7 +201,7 @@ def __repr__(self):
return "TaskParameter(task_id=%d, name=%s, value=%s)" % (self.task_id, self.name, self.value)


class TaskEvent(Base):
class TaskEvent(Base): # type: ignore
"""
Table to track when a task is scheduled, starts, finishes, and fails.
"""
Expand All @@ -215,7 +215,7 @@ def __repr__(self):
return "TaskEvent(task_id=%s, event_name=%s, ts=%s" % (self.task_id, self.event_name, self.ts)


class TaskRecord(Base):
class TaskRecord(Base): # type: ignore
"""
Base table to track information about a luigi.Task.
Expand Down
2 changes: 1 addition & 1 deletion luigi/freezing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
try:
from collections.abc import Mapping
except ImportError:
from collections import Mapping
from collections import Mapping # type: ignore
import operator
import functools

Expand Down
Loading

0 comments on commit 829fc0c

Please sign in to comment.