Skip to content
This repository was archived by the owner on Jan 15, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# `flake8-idom-hooks`
# `reactpy-flake8`

A Flake8 plugin that enforces the ["rules of hooks"](https://reactjs.org/docs/hooks-rules.html) for [IDOM](https://github.com/idom-team/idom).
A Flake8 plugin that enforces the ["rules of hooks"](https://reactjs.org/docs/hooks-rules.html) for [ReactPy](https://github.com/reactive-python/reactpy).

The implementation is based on React's own ESLint [plugin for hooks](https://github.com/facebook/react/tree/master/packages/eslint-plugin-react-hooks).

# Install

```bash
pip install flake8-idom-hooks
pip install reactpy-flake8
```

# Developer Installation
Expand All @@ -20,7 +20,7 @@ pip install -e .
Run the tests

```bash
tox
nox -s test
```

# Errors
Expand All @@ -31,34 +31,34 @@ tox
<th>Message</th>
</tr>
<tr>
<td>ROH100</td>
<td>REACTPY100</td>
<td>Hook is defined as a closure</td>
</tr>
<tr>
<td>ROH101</td>
<td>REACTPY101</td>
<td>Hook was used outside component or hook definition</td>
</tr>
<tr>
<td>ROH102</td>
<td>REACTPY102</td>
<td>Hook was used inside a conditional or loop statement</td>
</tr>
<tr>
<td>ROH103</td>
<td>REACTPY103</td>
<td>Hook was used after an early return</td>
</tr>
<tr>
<td>ROH200</td>
<td>REACTPY200</td>
<td>
A hook's dependency is not destructured - dependencies should be refered to
directly, not via an attribute or key of an object
</td>
</tr>
<tr>
<td>ROH201</td>
<td>REACTPY201</td>
<td>Hook dependency args should be a literal list, tuple or None</td>
</tr>
<tr>
<td>ROH202</td>
<td>REACTPY202</td>
<td>
Hook dependency is not specified
</td>
Expand All @@ -81,7 +81,7 @@ example, `exhaustive_hook_deps` would become `--exhaustive-hook-deps`.
<td><code>exhaustive_hook_deps</code></td>
<td>Boolean</td>
<td><code>False</code></td>
<td>Enable <code>ROH2**</code> errors (recommended)</td>
<td>Enable <code>REACTPY2**</code> errors (recommended)</td>
</tr>
<tr>
<td><code>component_decorator_pattern</code></td>
Expand Down
10 changes: 6 additions & 4 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from pathlib import Path

from nox import Session, session
from nox import Session, parametrize, session

ROOT = Path(".")
REQUIREMENTS_DIR = ROOT / "requirements"
Expand Down Expand Up @@ -32,12 +32,14 @@ def test_style(session: Session) -> None:
@session
def test_types(session: Session) -> None:
install_requirements(session, "types")
session.run("mypy", "--strict", "flake8_idom_hooks")
session.run("mypy", "--strict", "reactpy_flake8")


@session
def test_suite(session: Session) -> None:
@parametrize("flake8_version", ["3", "4", "5", "6"])
def test_suite(session: Session, flake8_version: str) -> None:
install_requirements(session, "test-env")
session.install(f"flake8=={flake8_version}.*")
session.install(".")
session.run("pytest", "tests")

Expand All @@ -54,7 +56,7 @@ def test_coverage(session: Session) -> None:
session.log("Coverage won't be checked")
session.install(".")
else:
posargs += ["--cov=flake8_idom_hooks", "--cov-report=term"]
posargs += ["--cov=reactpy_flake8", "--cov-report=term"]
session.install("-e", ".")

session.run("pytest", "tests", *posargs)
Expand Down
4 changes: 3 additions & 1 deletion flake8_idom_hooks/common.py → reactpy_flake8/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ def __init__(
self._component_decorator_pattern = re.compile(component_decorator_pattern)

def add_error(self, error_code: int, node: ast.AST, message: str) -> None:
self.errors.append((node.lineno, node.col_offset, f"ROH{error_code} {message}"))
self.errors.append(
(node.lineno, node.col_offset, f"REACTPY{error_code} {message}")
)

def is_hook_def(self, node: ast.FunctionDef) -> bool:
return self.is_hook_name(node.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

from flake8.options.manager import OptionManager

from flake8_idom_hooks import __version__
from flake8_idom_hooks.run import (
from reactpy_flake8 import __version__
from reactpy_flake8.run import (
DEFAULT_COMPONENT_DECORATOR_PATTERN,
DEFAULT_HOOK_FUNCTION_PATTERN,
run_checks,
Expand All @@ -16,7 +16,6 @@


class Plugin:

name = __name__
version = __version__

Expand Down
File renamed without changes.
8 changes: 4 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import setuptools

# the name of the project
name = "flake8_idom_hooks"
name = "reactpy_flake8"

# basic paths used to gather files
here = os.path.abspath(os.path.dirname(__file__))
Expand All @@ -18,12 +18,12 @@
package = {
"name": name,
"packages": setuptools.find_packages(exclude=["tests*"]),
"entry_points": {"flake8.extension": ["ROH=flake8_idom_hooks:plugin"]},
"entry_points": {"flake8.extension": ["REACTPY=reactpy_flake8:plugin"]},
"python_requires": ">=3.6",
"description": "Flake8 plugin to enforce the rules of hooks for IDOM",
"description": "Flake8 plugin to enforce the rules of hooks for ReactPy",
"author": "Ryan Morshead",
"author_email": "ryan.morshead@gmail.com",
"url": "https://github.com/idom-team/flake8-idom-hooks",
"url": "https://github.com/reactive-python/reactpy-flake8",
"license": "MIT",
"platforms": "Linux, Mac OS X, Windows",
"classifiers": [
Expand Down
4 changes: 2 additions & 2 deletions tests/cases/custom_component_decorator_pattern.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
@component
def check_normal_pattern():
if True:
# error: ROH102 hook 'use_state' used inside if statement
# error: REACTPY102 hook 'use_state' used inside if statement
use_state()


@custom_component
def check_custom_pattern():
if True:
# error: ROH102 hook 'use_state' used inside if statement
# error: REACTPY102 hook 'use_state' used inside if statement
use_state()
2 changes: 1 addition & 1 deletion tests/cases/custom_hook_function_pattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ def check():
if True:
# this get's ignored because of custom pattern
use_ignore_this()
# error: ROH102 hook 'use_state' used inside if statement
# error: REACTPY102 hook 'use_state' used inside if statement
use_state()
24 changes: 12 additions & 12 deletions tests/cases/exhaustive_deps.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# error: ROH101 hook 'use_effect' used outside component or hook definition
# error: REACTPY101 hook 'use_effect' used outside component or hook definition
use_effect(lambda: x) # no need to check deps outside component/hook


Expand All @@ -12,7 +12,7 @@ def check_effects():

use_effect(
lambda: (
# error: ROH202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
# error: REACTPY202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
x
+ y
),
Expand All @@ -21,49 +21,49 @@ def check_effects():

use_effect(
lambda: (
# error: ROH202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
# error: REACTPY202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
x
)
)

use_effect(
lambda: (
# error: ROH202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
# error: REACTPY202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
x.y
),
[
# error: ROH200 dependency arg of 'use_effect' is not destructured - dependencies should be refered to directly, not via an attribute or key of an object
# error: REACTPY200 dependency arg of 'use_effect' is not destructured - dependencies should be refered to directly, not via an attribute or key of an object
x.y
],
)

module.use_effect(
lambda: (
# error: ROH202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
# error: REACTPY202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
x
),
[],
)

module.submodule.use_effect(
lambda: (
# error: ROH202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
# error: REACTPY202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
x
),
[],
)

use_effect(
lambda: (
# error: ROH202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
# error: REACTPY202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
x
),
args=[],
)

use_effect(
function=lambda: (
# error: ROH202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
# error: REACTPY202 dependency 'x' of function 'lambda' is not specified in declaration of 'use_effect'
x
),
args=[],
Expand All @@ -75,7 +75,7 @@ def my_effect():

@use_effect(args=[])
def my_effect():
# error: ROH202 dependency 'x' of function 'my_effect' is not specified in declaration of 'use_effect'
# error: REACTPY202 dependency 'x' of function 'my_effect' is not specified in declaration of 'use_effect'
x

@use_effect(args=[])
Expand All @@ -86,7 +86,7 @@ def my_effect(*args, **kwargs):

@module.use_effect(args=[])
def my_effect():
# error: ROH202 dependency 'x' of function 'my_effect' is not specified in declaration of 'use_effect'
# error: REACTPY202 dependency 'x' of function 'my_effect' is not specified in declaration of 'use_effect'
x

@not_a_decorator_we_care_about
Expand All @@ -104,7 +104,7 @@ def impropper_usage_of_effect_as_decorator():

use_effect(
lambda: None,
# error: ROH201 dependency args of 'use_effect' should be a literal list, tuple, or None - not expression type 'Name'
# error: REACTPY201 dependency args of 'use_effect' should be a literal list, tuple, or None - not expression type 'Name'
not_a_list_or_tuple,
)

Expand Down
Loading