К основному содержанию
правило

scipy — правило для Cursor: что делает и как установить

Набор правил для написания научного кода на SciPy в Cursor: оформление docstrings, именованные аргументы и вычисления.

Установить в Cursor · Вручную: положить файлы Все способы и платформы ↓
.cursor/rules/scipy.mdc
Открыть на GitHub

Что делает scipy

Правило задаёт стандарты оформления и архитектуры для Python-файлов при работе с библиотекой SciPy. Оно фиксирует лимит строки в 88 символов, NumPy-стиль документации и обязательные keyword-only аргументы через *, чтобы сигнатуры функций оставались расширяемыми при добавлении новых параметров.

Вместо кортежей правило предписывает возвращать dataclass или штатные структуры вроде OptimizeResult. В вычислениях акцент сделан на переменную SCIPY_ARRAY_API=1 для совместимости с тензорами PyTorch или JAX, а также на полный отказ от устаревшего np.matrix.

Вместо самописных циклов оптимизации правило требует вызывать готовые алгоритмы вроде scipy.optimize.minimize, иначе код теряет скорость C-библиотек. Для тестов вводится обязательное использование np.testing.assert_allclose при проверке чисел с плавающей точкой.

Какие задачи решает

  • структурировать сигнатуры функций через keyword-only параметры
  • оформить документацию модулей по стандарту NumPy docstrings
  • перевести расчёты на SCIPY_ARRAY_API=1 для поддержки PyTorch и JAX
  • заменить возвращаемые кортежи на типизированные датаклассы

Примеры запросов агенту

  • Напиши функцию минимизации функции потерь через scipy.optimize по правилам проекта.
  • Оформи сигнатуру и докстринг для этой функции обработки сигналов по стандарту NumPy.
  • Проверь расчёт матрицы признаков с флагом SCIPY_ARRAY_API=1.

Как установить scipy

Вручную: положить файлы

.cursor/rules/scipy.mdc

Во frontmatter: description, globs, alwaysApply

По шагам, с командами для каждой платформы: Cursor rules: файлы .mdc, четыре режима и замена .cursorrules

Вопросы о scipy

Как установить scipy в Cursor?

Создайте файл .cursor/rules/scipy.mdc в корне репозитория и добавьте туда содержимое правила.

Что делает правило scipy?

Оно направляет ИИ в Cursor следовать стандартам разработки SciPy: ограничению длины строк, стилю NumPy docstrings, использованию датаклассов и встроенных процедур оптимизации.

Какие требования к тестированию задаёт это правило?

Для сравнения массивов с плавающей точкой правило предписывает использовать np.testing.assert_allclose.

Исходный текст

scipy.mdc · CC0-1.0
---
description: This guide provides opinionated, actionable best practices for writing robust, performant, and maintainable Python code using SciPy, aligning with modern scientific computing standards.
globs: **/*.py
---
# SciPy Best Practices

This document outlines the definitive best practices for developing with SciPy. Adhering to these guidelines ensures your code is clean, efficient, and compatible with the broader scientific Python ecosystem.

## 1. Code Organization and Style

Strict adherence to style guides is non-negotiable for maintainability.

### 1.1. Line Length and Docstrings

Follow PEP 8 with a strict 88-character line limit. Docstrings must conform to PEP 257 and the NumPy docstring standard, using ASCII characters primarily, with a small whitelist of Unicode symbols.

❌ **BAD**
```python
def calculate_complex_metric(data_array, method='default', tolerance=1e-6, max_iterations=1000, verbose_output=False):
    """Calculates a very complex metric using various parameters and returns a tuple of results."""
    # ... implementation ...
    return result1, result2, result3
```

✅ **GOOD**
```python
def calculate_complex_metric(
    data_array: np.ndarray,
    *,
    method: str = 'default',
    tolerance: float = 1e-6,
    max_iterations: int = 1000,
    verbose_output: bool = False,
) -> MyResultObject:
    """Calculate a complex metric from `data_array`.

    Parameters
    ----------
    data_array : np.ndarray
        Input data array.
    method : {'default', 'optimized'}, optional
        Algorithm method to use. Default is 'default'.
    tolerance : float, optional
        Convergence tolerance. Default is 1e-6.
    max_iterations : int, optional
        Maximum number of iterations. Default is 1000.
    verbose_output : bool, optional
        If True, print detailed progress. Default is False.

    Returns
    -------
    res : MyResultObject
        An object with attributes:
        statistic : float
            The primary calculated statistic.
        pvalue : float
            The associated p-value.
        converged : bool
            True if the algorithm converged.
    """
    # ... implementation ...
    return MyResultObject(statistic=..., pvalue=..., converged=...)

@dataclass
class MyResultObject:
    statistic: float
    pvalue: float
    converged: bool
```

### 1.2. Keyword-Only Arguments

For functions with more than a few arguments, enforce keyword-only arguments after the initial "obvious" ones using `*`. This improves readability and allows for backward-compatible additions of new parameters.

❌ **BAD**
```python
def process_data(data, 0.1, 'linear', True): # What do these mean?
    pass
```

✅ **GOOD**
```python
def process_data(data: np.ndarray, *, threshold: float, method: str, normalize: bool):
    """Process data with explicit keyword arguments."""
    # ...
    pass

process_data(my_array, threshold=0.1, method='linear', normalize=True)
```

### 1.3. Return Non-Iterable Objects

When returning two or more conceptually distinct elements, always use a custom class or an existing SciPy return class (e.g., `OptimizeResult`). Avoid `tuple` or `namedtuple` to force explicit attribute access and enable future extensions.

❌ **BAD**
```python
def analyze_signal(signal: np.ndarray) -> tuple[float, float]:
    # ...
    return peak_freq, amplitude
```

✅ **GOOD**
```python
from dataclasses import dataclass

@dataclass
class SignalAnalysisResult:
    peak_frequency: float
    amplitude: float

def analyze_signal(signal: np.ndarray) -> SignalAnalysisResult:
    # ...
    return SignalAnalysisResult(peak_frequency=peak_freq, amplitude=amplitude)

result = analyze_signal(my_signal)
print(result.peak_frequency)
```

## 2. Common Patterns and Anti-patterns

Leverage modern SciPy features and avoid deprecated interfaces.

### 2.1. Array API Standard Support

Enable `SCIPY_ARRAY_API=1` for seamless interoperability with array libraries like PyTorch or JAX. This enforces stricter input validation and ensures `array type in equals array type out`.

❌ **BAD**
```python
# Relying on implicit NumPy conversion, potentially slow or incompatible
import numpy as np
from scipy.cluster.vq import vq

features = np.asmatrix([[1.9, 2.3, 1.7], [1.5, 2.5, 2.2]])
code_book = np.array([[1., 1., 1.], [2., 2., 2.]])
code, dist = vq(features, code_book) # Works without SCIPY_ARRAY_API=1, but matrix is deprecated
```

✅ **GOOD**
```python
# Set environment variable before import for Array API support
# export SCIPY_ARRAY_API=1
import numpy as np
import torch
from scipy.cluster.vq import vq

# Use standard arrays (NumPy or compatible tensors)
features_np = np.array([[1.9, 2.3, 1.7], [1.5, 2.5, 2.2]])
code_book_np = np.array([[1., 1., 1.], [2., 2., 2.]])
code_np, dist_np = vq(features_np, code_book_np)

features_torch = torch.tensor([[1.9, 2.3, 1.7], [1.5, 2.5, 2.2]])
code_book_torch = torch.tensor([[1., 1., 1.], [2., 2., 2.]])
code_torch, dist_torch = vq(features_torch, code_book_torch)

# Avoid np.matrix, np.ma.MaskedArray, or object dtypes when Array API is enabled
# This will raise TypeError:
# vq(np.asmatrix(features_np), code_book_np)
```

## 3. Performance Considerations

Optimize strategically: "Make it work → make it reliable → make it fast."

### 3.1. Profiling

Never optimize without measuring. Use `timeit` for micro-benchmarks and `cProfile` (or `line_profiler`) for identifying bottlenecks in larger applications.

```python
import numpy as np
import timeit

# Micro-benchmark with timeit
setup_code = "import numpy as np; a = np.arange(1000)"
stmt1 = "a ** 2"
stmt2 = "a * a"

print(f"a ** 2: {timeit.timeit(stmt1, setup=setup_code, number=100000):.3f}s")
print(f"a * a: {timeit.timeit(stmt2, setup=setup_code, number=100000):.3f}s")

# For larger scripts, use cProfile:
# python -m cProfile -o my_profile.prof your_script.py
# Then analyze with `snakeviz my_profile.prof`
```

### 3.2. Algorithmic Optimization

Prioritize choosing the right SciPy algorithm over low-level code tweaks. SciPy's routines are highly optimized (often in C/Fortran).

❌ **BAD**
```python
# Manually implementing a simple optimization loop in Python
import numpy as np
def my_custom_optimizer(func, x0, lr=0.01, max_iter=100):
    x = x0
    for _ in range(max_iter):
        grad = (func(x + 1e-6) - func(x - 1e-6)) / (2 * 1e-6) # Numerical gradient
        x -= lr * grad
    return x
```

✅ **GOOD**
```python
# Leverage SciPy's robust and optimized optimization routines
from scipy.optimize import minimize
import numpy as np

def objective_function(x):
    return (x[0] - 2)**2 + (x[1] - 3)**2

x0 = np.array([0.0, 0.0])
result = minimize(objective_function, x0, method='BFGS')
print(f"Optimized x: {result.x}")
```

## 4. Common Pitfalls and Gotchas

Avoid common mistakes that lead to subtle bugs or incorrect results.

### 4.1. Floating Point Comparisons

Always use `np.testing.assert_allclose` for floating-point array comparisons in tests. Avoid `assert_almost_equal` or `assert_approx_equal`.

❌ **BAD**
```python
import numpy as np
from numpy.testing import assert_almost_equal

arr1 = np.array([0.1 + 0.2, 0.3])
arr2 = np.array([0.3, 0.3])
assert_almost_equal(arr1, arr2) # Can fail due to precision issues
```

✅ **GOOD**
```python
import numpy as np
from numpy.testing import assert_allclose

arr1 = np.array([0.1 + 0.2, 0.3])
arr2 = np.array([0.3, 0.3])
assert_allclose(arr1, arr2, rtol=1e-7, atol=0) # Robust floating point comparison
```

### 4.2. Testing Exceptions and Warnings

Use `pytest.raises` and `pytest.warns` as context managers with the `match` argument to precisely test expected exceptions or warnings.

❌ **BAD**
```python
import numpy as np
from scipy import stats
from numpy.testing import assert_raises

def test_zmap_nan_policy_raise_bad():
    scores = np.array([1, 2, 3])
    compare = np.array([-8, -3, 2, 7, 12, np.nan])
    assert_raises(ValueError, stats.zmap, scores, compare, nan_policy='raise')
```

✅ **GOOD**
```python
import numpy as np
from scipy import stats
import pytest

def test_zmap_nan_policy_raise_good():
    scores = np.array([1, 2, 3])
    compare = np.array([-8, -3, 2, 7, 12, np.nan])
    with pytest.raises(ValueError, match='input contains nan'):
        stats.zmap(scores, compare, nan_policy='raise')
```

## 5. Type Hints

Embrace PEP 484-style type hints for improved code clarity, static analysis, and maintainability.

❌ **BAD**
```python
def process(data, config):
    # What are data and config?
    return data * config['scale']
```

✅ **GOOD**
```python
import numpy as np
from typing import Dict, Any

def process(data: np.ndarray, config: Dict[str, Any]) -> np.ndarray:
    """Process numerical data using a configuration dictionary."""
    return data * config['scale']
```

## 6. Virtual Environments

Always use a virtual environment (`venv` or `conda`) to manage dependencies. This isolates your project's dependencies and prevents conflicts.

```bash
# Create a virtual environment
python -m venv .venv

# Activate it
source .venv/bin/activate # On Windows: .venv\Scripts\activate

# Install SciPy and other dependencies
pip install scipy numpy pandas matplotlib
```

## 7. Packaging

For any project beyond a simple script, structure it as a proper Python package using `pyproject.toml`.

❌ **BAD**
```
my_script.py
data.csv
```

✅ **GOOD**
```
my_project/
├── pyproject.toml
├── README.md
├── my_project/
│   ├── __init__.py
│   ├── analysis.py
│   └── utils.py
└── tests/
    ├── __init__.py
    └── test_analysis.py
```

## 8. Testing Approaches

Comprehensive testing is crucial for reliable scientific code.

### 8.1. Pytest and Pre-commit Hooks

Use `pytest` as your testing framework. Integrate `pre-commit` hooks (e.g., `ruff`, `isort`, `black`) to automate style and linting checks before every commit.

```bash
# Install pre-commit
pip install pre-commit

# In your project root, create a .pre-commit-config.yaml
# Example:
# repos:
#   - repo: https://github.com/astral-sh/ruff-pre-commit
#     rev: v0.1.9
#     hooks:
#       - id: ruff
#         args: [--fix, --exit-non-zero-on-fix]
#   - repo: https://github.com/psf/black
#     rev: 23.12.1
#     hooks:
#       - id: black
#   - repo: https://github.com/PyCQA/isort
#     rev: 5.12.0
#     hooks:
#       - id: isort

# Install the hooks
pre-commit install

# Run tests
pytest
```

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Похожие правила IDE

Всё по теме «Наука и исследования» →
scipy-best-practices Mindrally Скилл задаёт агенту правила научных вычислений на SciPy: оптимизация, линейная алгебра, статистика, сигналы. Пригодится, когда код на Python считает числа, а не рисует интерфейсы. CX Codex +1 1 000установок matplotlib K-Dense-AI Скилл для построения и тонкой настройки научных графиков на Matplotlib: от отдельных осей до многопанельных фигур и экспорта в PNG, PDF и SVG. CX Codex +1 2 200установок linear-solvers HeshamFS Подбирает и настраивает решатели линейных систем Ax=b в численных симуляциях. Помогает при остановке сходимости и выборе предобуславливателей. CX Codex +1 ★ 83звёзд репо statistics-math pluginagentmarketplace Скилл для ИИ-кодинга: даёт агенту статистику, теорию вероятностей, линейную алгебру и регрессию на Python. Пригодится, когда нужно посчитать метрики или проверить гипотезу. CX Codex +1 432установок symbolic-equation lingzhi227 Подбирает физические формулы по наборам данных с помощью эволюционного поиска и языковых моделей. Пригодится для символьной регрессии и поиска законов в экспериментах. CX Codex +1 1 600установок correlation-analysis agiprolabs Считает корреляции между активами: скользящие окна, кластеризация, хвостовая зависимость. Нужен для оценки диверсификации и парного трейдинга. CX Codex +1 465установок

Из того же набора240

Весь набор →
sentry Правило задаёт, как инициализировать Sentry в проекте: где ставить SDK, какие переменные окружения использовать, как не сломать чужой код. ★ 3 580звёзд репо selenium Задаёт стандарты написания скриптов на Selenium в Python: обязывает использовать Page Object Model, явные ожидания и headless-режим. ★ 3 580звёзд репо seaborn Правило задаёт подход к графикам на Seaborn: от структуры данных и оформления до работы с большими наборами. Пригодится для Python-проектов с визуализацией данных. ★ 3 580звёзд репо scrapy Правило с набором практик для Scrapy: структура проекта, items, pipelines, middlewares. Пригодится, когда агент пишет парсеры на Python. ★ 3 580звёзд репо scikit-learn Правило направляет Cursor при работе с Python-кодом scikit-learn: помогает оформлять предобработку и модели через Pipeline и не допускать утечки данных. ★ 3 580звёзд репо scikit-image Правило задаёт команде единый стиль работы с scikit-image: неизменяемость входных массивов, float-диапазон [0, 1], векторизация вместо циклов по пикселям. ★ 3 580звёзд репо sanic Задаёт стандарты асинхронной разработки на Sanic в Python: фабрика create_app, Blueprints, вынос блокирующих вызовов в воркеры и запуск задач в фоне. ★ 3 580звёзд репо rust Правило задаёт стиль для Rust-кода: структуру модулей, типобезопасные паттерны, обработку ошибок и тесты. Подключается ко всем файлам проекта. ★ 3 580звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой