1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-11 07:51:20 +00:00

Add flake8 plugin to ensure psycopg is imported from the right place

This commit is contained in:
Davide Silvestri 2025-02-13 20:08:13 +01:00 committed by Cezary Statkiewicz
parent 37b04d772f
commit 69e8530c61
8 changed files with 78 additions and 12 deletions
backend
.flake8
flake8_plugins
src/baserow
contrib/database/fields/utils
core
changelog/entries/unreleased/refactor

View file

@ -7,6 +7,7 @@ per-file-ignores =
../enterprise/backend/tests/*: F841
src/baserow/contrib/database/migrations/*: X1
src/baserow/core/migrations/*: X1
src/baserow/core/psycopg.py: BRP001
exclude =
.git,
__pycache__,
@ -16,4 +17,5 @@ exclude =
[flake8:local-plugins]
extension =
X1 = flake8_baserow:DocstringPlugin
BRP001 = flake8_baserow:BaserowPsycopgChecker
paths = ./flake8_plugins

View file

@ -1 +1 @@
from .flake8_baserow import DocstringPlugin
from .flake8_baserow import DocstringPlugin, BaserowPsycopgChecker

View file

@ -1,3 +1,4 @@
from .docstring import Plugin as DocstringPlugin
from .psycopg import BaserowPsycopgChecker
__all__ = ["DocstringPlugin"]
__all__ = ["DocstringPlugin", "BaserowPsycopgChecker"]

View file

@ -0,0 +1,30 @@
import ast
from typing import Iterator, Tuple, Any
class BaserowPsycopgChecker:
name = 'flake8-baserow-psycopg'
version = '0.1.0'
def __init__(self, tree: ast.AST, filename: str):
self.tree = tree
self.filename = filename
def run(self) -> Iterator[Tuple[int, int, str, Any]]:
for node in ast.walk(self.tree):
if isinstance(node, ast.Import):
for alias in node.names:
if alias.name in ('psycopg', 'psycopg2'):
yield (
node.lineno,
node.col_offset,
'BRP001 Import psycopg/psycopg2 from baserow.core.psycopg instead',
type(self)
)
elif isinstance(node, ast.ImportFrom):
if node.module in ('psycopg', 'psycopg2'):
yield (
node.lineno,
node.col_offset,
'BRP001 Import psycopg/psycopg2 from baserow.core.psycopg instead',
type(self)
)

View file

@ -0,0 +1,38 @@
import ast
from flake8_baserow.psycopg import BaserowPsycopgChecker
def run_checker(code: str):
tree = ast.parse(code)
checker = BaserowPsycopgChecker(tree, 'test.py')
return list(checker.run())
def test_direct_import():
code = '''
import psycopg
import psycopg2
from psycopg import connect
from psycopg2 import connect as pg_connect
'''
errors = run_checker(code)
assert len(errors) == 4
assert all(error[2].startswith('BRP001') for error in errors)
def test_allowed_import():
code = '''
from baserow.core.psycopg import connect
from baserow.core.psycopg import psycopg2
'''
errors = run_checker(code)
assert len(errors) == 0
def test_mixed_imports():
code = '''
import psycopg
from baserow.core.psycopg import connect
from psycopg2 import connect as pg_connect
'''
errors = run_checker(code)
assert len(errors) == 2
assert errors[0][2].startswith('BRP001')
assert errors[1][2].startswith('BRP001')

View file

@ -708,8 +708,9 @@ def text_value_sql_to_duration(field: "DurationField") -> str:
if is_psycopg3:
import psycopg
from psycopg.types.datetime import IntervalLoader
from psycopg.types.datetime import IntervalLoader # noqa: BRP001
from baserow.core.psycopg import psycopg
class BaserowIntervalLoader(IntervalLoader):
"""

View file

@ -27,7 +27,8 @@ from django.db.transaction import Atomic, get_connection
from loguru import logger
from .psycopg import sql
from baserow.core.psycopg import sql
from .utils import find_intermediate_order
ModelInstance = TypeVar("ModelInstance", bound=object)

View file

@ -1,7 +0,0 @@
{
"type": "refactor",
"message": "Upgrade to psycopg3",
"issue_number": 1689,
"bullet_points": [],
"created_at": "2025-01-08"
}