main - feat: Add pre-commit and fix all files

This commit is contained in:
Yoel Bassin 2025-04-26 21:51:32 +03:00
parent 37cb51f056
commit 185e68f809
16 changed files with 116 additions and 73 deletions

2
.gitignore vendored
View File

@ -171,4 +171,4 @@ cython_debug/
.ruff_cache/ .ruff_cache/
# PyPI configuration file # PyPI configuration file
.pypirc .pypirc

33
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,33 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: debug-statements
- id: name-tests-test
args: [--pytest-test-first]
- id: requirements-txt-fixer
- repo: https://github.com/asottile/setup-cfg-fmt
rev: v2.8.0
hooks:
- id: setup-cfg-fmt
- repo: https://github.com/pycqa/isort
rev: 6.0.1
hooks:
- id: isort
name: isort (python)
- repo: https://github.com/psf/black
rev: 22.10.0
hooks:
- id: black
- repo: https://github.com/PyCQA/flake8
rev: 7.2.0
hooks:
- id: flake8
args: [--max-line-length=88]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.15.0
hooks:
- id: mypy

View File

@ -2,4 +2,4 @@
"python.analysis.extraPaths": [ "python.analysis.extraPaths": [
"./src" "./src"
] ]
} }

View File

@ -7,15 +7,15 @@ Install GNURadio, follow the installation process in [InstallingGR](https://wiki
```bash ```bash
brew install gnuradio brew install gnuradio
``` ```
Now create a virtual environment to run the project. Now create a virtual environment to run the project.
```bash ```bash
python3.13 -m venv --system-site-packages venv python3.13 -m venv --system-site-packages venv
source venv/bin/activate source venv/bin/activate
pip install -e . pip install -e .
``` ```
we use the `--system-site-packages` flag since GNURadio installs the `gnuradio` python package globally. we use the `--system-site-packages` flag since GNURadio installs the `gnuradio` python package globally.
Run using Run using
```bash ```bash
python -m grc python -m grc
``` ```

13
main.py
View File

@ -1,14 +1,13 @@
import logging from __future__ import annotations
import logging.handlers
import platform
import sys
from pathlib import Path
import sys
from gnuradio_mcp.middlewares.platform import PlatformMiddleware
# Load GNU Radio # Load GNU Radio
try: try:
from gnuradio import gr from gnuradio import gr
except ImportError as ex: except ImportError:
# Throw a new exception with more information # Throw a new exception with more information
print( print(
"Cannot find GNU Radio! (Have you sourced the environment file?)", "Cannot find GNU Radio! (Have you sourced the environment file?)",
@ -18,7 +17,6 @@ except ImportError as ex:
raise Exception("Cannot find GNU Radio!") from None raise Exception("Cannot find GNU Radio!") from None
from gnuradio.grc.core.platform import Platform from gnuradio.grc.core.platform import Platform
from gnuradio.grc.core.FlowGraph import FlowGraph
platform = Platform( platform = Platform(
version=gr.version(), version=gr.version(),
@ -28,7 +26,6 @@ platform = Platform(
) )
platform.build_library() platform.build_library()
from gnuradio_mcp.middlewares.platform import PlatformMiddleware
platform_middleware = PlatformMiddleware(platform) platform_middleware = PlatformMiddleware(platform)

View File

@ -18,6 +18,7 @@ dependencies = [
[project.optional-dependencies] [project.optional-dependencies]
dev = [ dev = [
"pytest >= 7.0", "pytest >= 7.0",
"pre-commit"
] ]
[tool.ruff] [tool.ruff]

View File

@ -1,4 +1,5 @@
from typing import List from __future__ import annotations
from gnuradio.grc.core.blocks.block import Block from gnuradio.grc.core.blocks.block import Block
from gnuradio_mcp.models import SINK, SOURCE, ParamModel, PortModel from gnuradio_mcp.models import SINK, SOURCE, ParamModel, PortModel
@ -9,13 +10,13 @@ class BlockMiddleware:
self._block = block self._block = block
@property @property
def params(self) -> List[ParamModel]: def params(self) -> list[ParamModel]:
return [ParamModel.from_param(param) for param in self._block.params.values()] return [ParamModel.from_param(param) for param in self._block.params.values()]
@property @property
def sinks(self) -> List[PortModel]: def sinks(self) -> list[PortModel]:
return [PortModel.from_port(port, SINK) for port in self._block.sinks] return [PortModel.from_port(port, SINK) for port in self._block.sinks]
@property @property
def sources(self) -> List[PortModel]: def sources(self) -> list[PortModel]:
return [PortModel.from_port(port, SOURCE) for port in self._block.sources] return [PortModel.from_port(port, SOURCE) for port in self._block.sources]

View File

@ -1,5 +1,7 @@
from typing import List, Optional from __future__ import annotations
from gnuradio.grc.core.FlowGraph import FlowGraph from gnuradio.grc.core.FlowGraph import FlowGraph
from gnuradio_mcp.middlewares.block import BlockMiddleware from gnuradio_mcp.middlewares.block import BlockMiddleware
from gnuradio_mcp.models import BlockModel from gnuradio_mcp.models import BlockModel
@ -9,7 +11,7 @@ class FlowGraphMiddleware:
self._flowgraph = flowgraph self._flowgraph = flowgraph
@property @property
def blocks(self) -> List[BlockModel]: def blocks(self) -> list[BlockModel]:
return [ return [
BlockModel(key=block.key, label=block.label) BlockModel(key=block.key, label=block.label)
for block in self._flowgraph.blocks for block in self._flowgraph.blocks

View File

@ -1,9 +1,11 @@
from typing import List, Optional from __future__ import annotations
from gnuradio.grc.core.platform import Platform from gnuradio.grc.core.platform import Platform
from gnuradio.grc.core.FlowGraph import FlowGraph
from gnuradio_mcp.middlewares.flowgraph import FlowGraphMiddleware from gnuradio_mcp.middlewares.flowgraph import FlowGraphMiddleware
from gnuradio_mcp.models import BlockModel from gnuradio_mcp.models import BlockModel
class PlatformMiddleware: class PlatformMiddleware:
def __init__(self, platform: Platform): def __init__(self, platform: Platform):
self._platform = platform self._platform = platform
@ -11,9 +13,11 @@ class PlatformMiddleware:
self._flowgraph_mw = FlowGraphMiddleware(flowgraph) self._flowgraph_mw = FlowGraphMiddleware(flowgraph)
@property @property
def blocks(self) -> List[BlockModel]: def blocks(self) -> list[BlockModel]:
return [BlockModel.from_block(block) for block in self._platform.blocks.values()] return [
BlockModel.from_block(block) for block in self._platform.blocks.values()
]
@property @property
def flowgraph(self) -> FlowGraphMiddleware: def flowgraph(self) -> FlowGraphMiddleware:
return self._flowgraph_mw return self._flowgraph_mw

View File

@ -1,17 +1,21 @@
from typing import Any, Literal, Optional, get_args from __future__ import annotations
from pydantic import BaseModel
from typing import Any, Literal, get_args
from gnuradio.grc.core.blocks.block import Block from gnuradio.grc.core.blocks.block import Block
from gnuradio.grc.core.ports.port import Port
from gnuradio.grc.core.params.param import Param from gnuradio.grc.core.params.param import Param
from gnuradio.grc.core.ports.port import Port
from pydantic import BaseModel
class BlockModel(BaseModel): class BlockModel(BaseModel):
label: str label: str
key: str key: str
@classmethod @classmethod
def from_block(cls, block: Block) -> "BlockModel": def from_block(cls, block: Block) -> BlockModel:
return cls(label=block.label, key=block.key) return cls(label=block.label, key=block.key)
class ParamModel(BaseModel): class ParamModel(BaseModel):
parent: str parent: str
@ -21,7 +25,7 @@ class ParamModel(BaseModel):
value: Any value: Any
@classmethod @classmethod
def from_param(cls, param: Param) -> "ParamModel": def from_param(cls, param: Param) -> ParamModel:
return cls( return cls(
parent=param.parent.name, parent=param.parent.name,
key=param.key, key=param.key,
@ -29,12 +33,12 @@ class ParamModel(BaseModel):
dtype=param.dtype, dtype=param.dtype,
value=param.get_value(), value=param.get_value(),
) )
DirectionType = Literal["sink", "source"] DirectionType = Literal["sink", "source"]
SINK, SOURCE = get_args(DirectionType) SINK, SOURCE = get_args(DirectionType)
class PortModel(BaseModel): class PortModel(BaseModel):
parent: str parent: str
key: str key: str
@ -45,8 +49,10 @@ class PortModel(BaseModel):
@classmethod @classmethod
def from_port( def from_port(
cls, port: Port, direction: Optional[DirectionType] = None cls,
) -> "PortModel": port: Port,
direction: DirectionType | None = None,
) -> PortModel:
direction = direction or port._dir direction = direction or port._dir
return cls( return cls(
parent=port.parent.name, parent=port.parent.name,
@ -55,4 +61,4 @@ class PortModel(BaseModel):
dtype=port.dtype, dtype=port.dtype,
direction=direction, direction=direction,
optional=port.optional, optional=port.optional,
) )

View File

@ -1,22 +1,30 @@
from __future__ import annotations
import pytest import pytest
from gnuradio.grc.core.platform import Platform
from gnuradio import gr from gnuradio import gr
from gnuradio.grc.core.platform import Platform
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def platform() -> Platform: def platform() -> Platform:
platform = Platform( platform = Platform(
version=gr.version(), version=gr.version(),
version_parts=(gr.major_version(), gr.api_version(), gr.minor_version()), version_parts=(
gr.major_version(),
gr.api_version(),
gr.minor_version(),
),
prefs=gr.prefs(), prefs=gr.prefs(),
) )
platform.build_library() platform.build_library()
return platform return platform
@pytest.fixture(params=[1, 2, 10]) # Arbitrary number of blocks to test
@pytest.fixture(params=[1, 2, 10]) # Arbitrary number of blocks to test
def block_key(platform, request): def block_key(platform, request):
block_keys = list(platform.blocks.keys()) block_keys = list(platform.blocks.keys())
assert block_keys, "No blocks available in platform library." assert block_keys, "No blocks available in platform library."
idx = request.param idx = request.param
if idx < len(block_keys): if idx < len(block_keys):
return block_keys[idx] return block_keys[idx]
return block_keys[0] return block_keys[0]

View File

@ -1,9 +1,9 @@
from typing import List from __future__ import annotations
import pytest import pytest
from gnuradio.grc.core.platform import Platform
from gnuradio.grc.core.blocks.block import Block from gnuradio.grc.core.blocks.block import Block
from gnuradio.grc.core.FlowGraph import FlowGraph from gnuradio.grc.core.platform import Platform
from gnuradio import gr
from gnuradio_mcp.middlewares.block import BlockMiddleware from gnuradio_mcp.middlewares.block import BlockMiddleware
from gnuradio_mcp.middlewares.flowgraph import FlowGraphMiddleware from gnuradio_mcp.middlewares.flowgraph import FlowGraphMiddleware
from gnuradio_mcp.models import SINK, SOURCE, ParamModel from gnuradio_mcp.models import SINK, SOURCE, ParamModel
@ -36,7 +36,7 @@ def test_block_middleware_sources(block: Block):
check_port_models(middleware.sources, block.sources, SOURCE) check_port_models(middleware.sources, block.sources, SOURCE)
def check_param_models(block: Block, params: List[ParamModel]): def check_param_models(block: Block, params: list[ParamModel]):
assert params assert params
assert len(params) == len(block.params) assert len(params) == len(block.params)
for param in params: for param in params:

View File

@ -1,10 +1,10 @@
from typing import List from __future__ import annotations
import pytest import pytest
from gnuradio.grc.core.platform import Platform from gnuradio.grc.core.platform import Platform
from gnuradio_mcp.middlewares.flowgraph import FlowGraphMiddleware from gnuradio_mcp.middlewares.flowgraph import FlowGraphMiddleware
from gnuradio import gr
from gnuradio_mcp.models import BlockModel from gnuradio_mcp.models import BlockModel
from .utils import get_block_keys, add_block, remove_block, get_current_blocks
@pytest.fixture @pytest.fixture
@ -24,23 +24,29 @@ def initial_blocks(flowgraph_middleware: FlowGraphMiddleware):
def test_flowgraph_block_addition_and_removal( def test_flowgraph_block_addition_and_removal(
flowgraph_middleware: FlowGraphMiddleware, flowgraph_middleware: FlowGraphMiddleware,
platform: Platform, platform: Platform,
initial_blocks: List[BlockModel], initial_blocks: list[BlockModel],
block_key: str, block_key: str,
): ):
block_keys = get_block_keys(platform) block_keys = platform.blocks.keys()
assert block_keys, "No blocks available in platform library." assert block_keys, "No blocks available in platform library."
block_name = f"test_block_{block_key}" block_name = f"test_block_{block_key}"
add_block(flowgraph_middleware, block_key, block_name) flowgraph_middleware.add_block(block_key, block_name)
blocks = flowgraph_middleware.blocks blocks = flowgraph_middleware.blocks
assert all(b in blocks for b in initial_blocks) assert all(b in blocks for b in initial_blocks)
assert any(b.key == block_key for b in blocks) assert any(b.key == block_key for b in blocks)
remove_block(flowgraph_middleware, block_name) flowgraph_middleware._flowgraph.remove_element(
current_blocks = get_current_blocks(flowgraph_middleware) flowgraph_middleware._flowgraph.get_block(block_name),
)
current_blocks = [
BlockModel(key=block.key, label=block.label)
for block in flowgraph_middleware._flowgraph.blocks
]
assert current_blocks == initial_blocks assert current_blocks == initial_blocks
def test_flowgraph_initial_state( def test_flowgraph_initial_state(
flowgraph_middleware: FlowGraphMiddleware, initial_blocks: List[BlockModel] flowgraph_middleware: FlowGraphMiddleware,
initial_blocks: list[BlockModel],
): ):
assert flowgraph_middleware.blocks == initial_blocks assert flowgraph_middleware.blocks == initial_blocks

View File

@ -1,8 +1,9 @@
import pytest from __future__ import annotations
from gnuradio_mcp.middlewares.platform import BlockModel, PlatformMiddleware
from gnuradio.grc.core.blocks.block import Block from gnuradio.grc.core.blocks.block import Block
from gnuradio.grc.core.platform import Platform from gnuradio.grc.core.platform import Platform
from gnuradio import gr
from gnuradio_mcp.middlewares.platform import BlockModel, PlatformMiddleware
def test_block_model_from_block(platform: Platform): def test_block_model_from_block(platform: Platform):

View File

@ -1,18 +0,0 @@
from gnuradio_mcp.models import BlockModel
def get_block_keys(platform):
return list(platform.blocks.keys())
def add_block(flowgraph_middleware, block_key, block_name):
flowgraph_middleware.add_block(block_key, block_name)
def remove_block(flowgraph_middleware, block_name):
flowgraph_middleware._flowgraph.remove_element(
flowgraph_middleware._flowgraph.get_block(block_name)
)
def get_current_blocks(flowgraph_middleware):
return [
BlockModel(key=block.key, label=block.label)
for block in flowgraph_middleware._flowgraph.blocks
]

2
tox.ini Normal file
View File

@ -0,0 +1,2 @@
[pep8]
ignore = E265,E501,W504