Skip to content

Commit c20a99a

Browse files
committed
chore(deps): uv-native workflow, pyproject SSOT, exported requirements
- Move dev tools to PEP 735 dependency-groups; drop yapic.json; add ccxt, fastjson, socks (aiohttp-socks), kafka (confluent-kafka, protobuf) extras; refresh all extra - Replace loguru with stdlib logging in ccxt generic feed - Align Python classifiers with requires-python >=3.12 - CI: uv sync --frozen + extras (socks/ccxt/kafka), drop uv pip/pip; fix BUF_V2BETA1_AGAINST via repository vars; dedupe pytest invocation - Lint: setup-uv + uv sync --frozen + uv run ruff/pyscn - pre-commit: uv-export for requirements.txt; pyscn via uv run - Regenerate uv.lock and requirements.txt (uv export --no-dev --no-editable) - CONTRIBUTING and README: uv workflow and Python 3.12+ badge Made-with: Cursor
1 parent 69d1bf5 commit c20a99a

9 files changed

Lines changed: 1227 additions & 61 deletions

File tree

.github/workflows/lint.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,21 @@ jobs:
1010
uses: actions/checkout@v4
1111

1212
- name: Install uv
13-
run: pip install uv
13+
uses: astral-sh/setup-uv@v7
14+
15+
- name: Set up Python
16+
uses: actions/setup-python@v4
17+
with:
18+
python-version: "3.12"
19+
20+
- name: Sync dev tools
21+
run: |
22+
uv sync --frozen
1423
1524
- name: Run ruff lint
1625
run: |
17-
uvx ruff check .
26+
uv run ruff check .
1827
1928
- name: Run pyscn quality check
2029
run: |
21-
uvx pyscn check --max-complexity 15 cryptofeed
30+
uv run pyscn check --max-complexity 15 cryptofeed

.github/workflows/tests.yml

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ jobs:
88
runs-on: ubuntu-latest
99
env:
1010
BUF_TOKEN: ${{ secrets.BUF_TOKEN }}
11+
BUF_V2BETA1_AGAINST: ${{ vars.BUF_V2BETA1_AGAINST }}
1112
strategy:
1213
matrix:
1314
python-version: ['3.12', '3.13', '3.14']
@@ -22,9 +23,7 @@ jobs:
2223
python-version: ${{ matrix.python-version }}
2324
- name: Install dependencies
2425
run: |
25-
uv sync --extra socks
26-
uv pip install pytest pytest-asyncio
27-
uv pip install -e .
26+
uv sync --frozen --python ${{ matrix.python-version }} --extra socks --extra ccxt --extra kafka
2827
- name: Set up Buf CLI
2928
run: |
3029
mkdir -p /usr/local/bin
@@ -41,15 +40,13 @@ jobs:
4140
buf breaking proto --against 'buf.build/tommyk/crypto-market-data:main'
4241
- name: Check for breaking changes (v2beta1)
4342
if: env.BUF_TOKEN != '' && env.BUF_V2BETA1_AGAINST != ''
44-
env:
45-
BUF_V2BETA1_AGAINST: ${{ env.BUF_V2BETA1_AGAINST }}
4643
run: |
4744
echo "Using against ref: ${BUF_V2BETA1_AGAINST}"
4845
buf breaking proto/cryptofeed/normalized/v2beta1 --against "${BUF_V2BETA1_AGAINST}"
4946
- name: Skip v2beta1 breaking (no target set)
5047
if: env.BUF_TOKEN != '' && env.BUF_V2BETA1_AGAINST == ''
5148
run: |
52-
echo "Skipping v2beta1 breaking check (set BUF_V2BETA1_AGAINST to enable)"
49+
echo "Skipping v2beta1 breaking check (set repository variable BUF_V2BETA1_AGAINST to enable)"
5350
- name: Generate Protobuf bindings
5451
run: |
5552
buf generate --template buf.gen.yaml proto
@@ -73,4 +70,3 @@ jobs:
7370
- name: Test with pytest
7471
run: |
7572
uv run pytest tests -v --tb=short
76-
uv run pytest tests/unit/kafka/test_import_guards.py -q

.pre-commit-config.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
repos:
2+
- repo: https://github.com/astral-sh/uv-pre-commit
3+
rev: 0.11.6
4+
hooks:
5+
- id: uv-export
6+
args: ["--frozen", "--no-dev", "--no-editable", "--output-file=requirements.txt", "--quiet"]
7+
28
- repo: https://github.com/astral-sh/ruff-pre-commit
39
rev: v0.7.4
410
hooks:
@@ -11,7 +17,7 @@ repos:
1117
hooks:
1218
- id: pyscn-check
1319
name: pyscn complexity/deadcode check
14-
entry: uvx pyscn check --max-complexity 15
20+
entry: uv run pyscn check --max-complexity 15
1521
language: system
1622
types: [python]
1723
files: >-

CONTRIBUTING.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ PRs, bug reports, feature requests, documentation, and other enhancements and im
1616
* Has it been tested? How?
1717
* Does the code style match the overall code style of the project? Long lines are preferred, so please do not use formatters that turn 1 line into 4 lines.
1818
* Please use type annotations.
19-
* Please run flake8 and fix any formatting issues it uncovers.
19+
* Use **uv** for installs (canonical): pin matches [`.python-version`](.python-version), then `uv sync` with any extras you need (`--extra socks`, `--extra ccxt`, `--extra kafka`, etc.), and `uv run pytest`.
20+
* After changing dependencies in [`pyproject.toml`](pyproject.toml): run `uv lock`, then `uv export --frozen --no-dev --no-editable --format requirements-txt -o requirements.txt` (or rely on the `uv-export` pre-commit hook). **Do not hand-edit** [`requirements.txt`](requirements.txt); it is generated for `pip install -r` compatibility only.
21+
* Please run **ruff** (`uv run ruff check .`) and fix any issues it uncovers.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Cryptocurrency Exchange Feed Handler
22
[![License](https://img.shields.io/badge/license-XFree86-blue.svg)](LICENSE)
3-
![Python](https://img.shields.io/badge/Python-3.9+-green.svg)
3+
![Python](https://img.shields.io/badge/Python-3.12+-green.svg)
44
[![PyPi](https://img.shields.io/badge/PyPi-cryptofeed-brightgreen.svg)](https://pypi.python.org/pypi/cryptofeed)
55
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/efa4e0d6e10b41d0b51454d08f7b33b1)](https://www.codacy.com/app/bmoscon/cryptofeed?utm_source=github.com&utm_medium=referral&utm_content=bmoscon/cryptofeed&utm_campaign=Badge_Grade)
66

cryptofeed/exchanges/ccxt/generic.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
from __future__ import annotations
33

44
import inspect
5+
import logging
6+
import sys
57
from dataclasses import dataclass
68
from decimal import Decimal
79
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Set
810
from urllib.parse import urlparse
9-
import sys
10-
11-
from loguru import logger
1211

1312
from cryptofeed.defines import (
1413
BALANCES,
@@ -26,6 +25,8 @@
2625
if TYPE_CHECKING: # pragma: no cover - import for type checking only
2726
from .transport import CcxtRestTransport, CcxtWsTransport
2827

28+
LOG = logging.getLogger('feedhandler')
29+
2930

3031
@dataclass(slots=True)
3132
class OrderBookSnapshot:
@@ -290,10 +291,10 @@ async def stream_trades_once(self) -> None:
290291
if self._ws_transport is not None:
291292
await self._ws_transport.close()
292293
self._ws_transport = None
293-
logger.warning(
294-
"ccxt feed falling back to REST",
295-
exchange=self.exchange_id,
296-
reason=str(exc),
294+
LOG.warning(
295+
"ccxt feed falling back to REST (exchange=%s reason=%s)",
296+
self.exchange_id,
297+
exc,
297298
)
298299

299300
async def close(self) -> None:
@@ -360,6 +361,6 @@ def get_supported_ccxt_exchanges() -> List[str]:
360361
ccxt = _dynamic_import('ccxt')
361362
exchanges = list(getattr(ccxt, 'exchanges', []))
362363
except ImportError:
363-
logger.warning("CCXT not available - returning empty exchange list")
364+
LOG.warning("CCXT not available - returning empty exchange list")
364365
return []
365366
return sorted(exchanges)

pyproject.toml

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,9 @@ classifiers = [
2828
"Intended Audience :: Developers",
2929
"Development Status :: 4 - Beta",
3030
"Programming Language :: Python :: 3 :: Only",
31-
"Programming Language :: Python :: 3.9",
32-
"Programming Language :: Python :: 3.10",
33-
"Programming Language :: Python :: 3.11",
3431
"Programming Language :: Python :: 3.12",
32+
"Programming Language :: Python :: 3.13",
33+
"Programming Language :: Python :: 3.14",
3534
"Framework :: AsyncIO",
3635
]
3736
requires-python = ">=3.12"
@@ -41,7 +40,6 @@ dependencies = [
4140
"pyyaml",
4241
"aiohttp>=3.9.4",
4342
"aiofile>=2.0.0",
44-
"yapic.json>=1.6.3",
4543
"uvloop ; platform_system!='Windows'",
4644
"order_book>=0.6.1",
4745
"aiodns>=1.1",
@@ -50,12 +48,21 @@ dependencies = [
5048
"pydantic-settings>=2.0.0",
5149
]
5250

51+
[dependency-groups]
52+
dev = [
53+
"pytest>=8.0",
54+
"pytest-asyncio>=0.24",
55+
"ruff>=0.8.0",
56+
"pyscn>=0.6.0",
57+
]
58+
5359
[project.optional-dependencies]
54-
dev = ["pyscn>=0.6.0"]
55-
socks = ["python-socks>=2.4.3"]
60+
fastjson = ["orjson>=3.10.0"]
61+
ccxt = ["ccxt>=4.5.9"]
62+
socks = ["python-socks>=2.4.3", "aiohttp-socks>=0.10.0"]
5663
arctic = ["arctic", "pandas"]
5764
gcp_pubsub = ["google_cloud_pubsub>=2.4.1", "gcloud_aio_pubsub"]
58-
kafka = ["aiokafka>=0.7.0"]
65+
kafka = ["aiokafka>=0.7.0", "confluent-kafka>=2.0.0", "protobuf>=5.0.0"]
5966
mongo = ["motor"]
6067
postgres = ["asyncpg"]
6168
quasardb = ["quasardb", "numpy"]
@@ -67,13 +74,19 @@ all = [
6774
"google_cloud_pubsub>=2.4.1",
6875
"gcloud_aio_pubsub",
6976
"aiokafka>=0.7.0",
77+
"confluent-kafka>=2.0.0",
78+
"protobuf>=5.0.0",
7079
"motor",
7180
"asyncpg",
7281
"aio_pika",
7382
"pika",
7483
"hiredis",
7584
"redis>=4.5.1",
7685
"pyzmq",
86+
"ccxt>=4.5.9",
87+
"orjson>=3.10.0",
88+
"python-socks>=2.4.3",
89+
"aiohttp-socks>=0.10.0",
7790
]
7891

7992
[project.urls]

0 commit comments

Comments
 (0)