ci: add Ruff config, pre-commit hooks, and GitHub Actions lint workflow

- Add [tool.ruff] config to pyproject.toml (E/F/I rules, 120-char limit,
  per-file ignores for __init__.py)
- Add .pre-commit-config.yaml with ruff lint + format hooks
- Add .github/workflows/lint.yml triggering on PRs and pushes to main
- Auto-fix 90 violations (unsorted imports, unused imports, f-strings)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Alex Korbonits 2026-04-12 14:04:26 -07:00
parent 10c136f49c
commit b30e3f14a7
41 changed files with 184 additions and 135 deletions

17
.github/workflows/lint.yml vendored Normal file
View File

@ -0,0 +1,17 @@
name: Lint
on:
push:
branches: [main]
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- run: uv python install 3.10
- run: uv pip install ruff
- run: uv run ruff check .
- run: uv run ruff format --check .

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

@ -0,0 +1,7 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.2
hooks:
- id: ruff
args: [--fix]
- id: ruff-format

View File

@ -1,4 +1,5 @@
import getpass
import requests
from rich.console import Console
from rich.panel import Panel

View File

@ -1,34 +1,32 @@
from typing import Optional
import datetime
import typer
from pathlib import Path
from functools import wraps
from rich.console import Console
from pathlib import Path
import typer
from dotenv import load_dotenv
from rich.console import Console
# Load environment variables from .env file
load_dotenv()
from rich.panel import Panel
from rich.spinner import Spinner
from rich.live import Live
from rich.columns import Columns
from rich.markdown import Markdown
from rich.layout import Layout
from rich.text import Text
from rich.table import Table
from collections import deque
import time
from rich.tree import Tree
from collections import deque
from rich import box
from rich.align import Align
from rich.layout import Layout
from rich.live import Live
from rich.markdown import Markdown
from rich.panel import Panel
from rich.rule import Rule
from rich.spinner import Spinner
from rich.table import Table
from rich.text import Text
from tradingagents.graph.trading_graph import TradingAgentsGraph
from tradingagents.default_config import DEFAULT_CONFIG
from cli.models import AnalystType
from cli.utils import *
from cli.announcements import fetch_announcements, display_announcements
from cli.announcements import display_announcements, fetch_announcements
from cli.stats_handler import StatsCallbackHandler
from cli.utils import *
from tradingagents.default_config import DEFAULT_CONFIG
from tradingagents.graph.trading_graph import TradingAgentsGraph
console = Console()

View File

@ -1,6 +1,4 @@
from enum import Enum
from typing import List, Optional, Dict
from pydantic import BaseModel
class AnalystType(str, Enum):

View File

@ -1,9 +1,9 @@
import threading
from typing import Any, Dict, List, Union
from typing import Any, Dict, List
from langchain_core.callbacks import BaseCallbackHandler
from langchain_core.outputs import LLMResult
from langchain_core.messages import AIMessage
from langchain_core.outputs import LLMResult
class StatsCallbackHandler(BaseCallbackHandler):

View File

@ -1,6 +1,6 @@
import questionary
from typing import List, Optional, Tuple, Dict
from typing import List, Tuple
import questionary
from rich.console import Console
from cli.models import AnalystType

View File

@ -1,8 +1,8 @@
from tradingagents.graph.trading_graph import TradingAgentsGraph
from tradingagents.default_config import DEFAULT_CONFIG
from dotenv import load_dotenv
from tradingagents.default_config import DEFAULT_CONFIG
from tradingagents.graph.trading_graph import TradingAgentsGraph
# Load environment variables from .env file
load_dotenv()

View File

@ -40,3 +40,16 @@ include = ["tradingagents*", "cli*"]
[tool.setuptools.package-data]
cli = ["static/*"]
[tool.ruff]
line-length = 120
[tool.ruff.lint]
select = ["E", "F", "I"]
ignore = ["E501", "E402", "E731", "F403", "F405", "F841"]
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
[tool.uv]
# Install with: uv sync

View File

@ -1,5 +1,6 @@
import time
from tradingagents.dataflows.y_finance import get_YFin_data_online, get_stock_stats_indicators_window, get_balance_sheet as get_yfinance_balance_sheet, get_cashflow as get_yfinance_cashflow, get_income_statement as get_yfinance_income_statement, get_insider_transactions as get_yfinance_insider_transactions
from tradingagents.dataflows.y_finance import get_stock_stats_indicators_window
print("Testing optimized implementation with 30-day lookback:")
start_time = time.time()

View File

@ -1,2 +1,3 @@
import os
os.environ.setdefault("PYTHONUTF8", "1")

View File

@ -1,23 +1,18 @@
from .utils.agent_utils import create_msg_delete
from .utils.agent_states import AgentState, InvestDebateState, RiskDebateState
from .utils.memory import FinancialSituationMemory
from .analysts.fundamentals_analyst import create_fundamentals_analyst
from .analysts.market_analyst import create_market_analyst
from .analysts.news_analyst import create_news_analyst
from .analysts.social_media_analyst import create_social_media_analyst
from .managers.portfolio_manager import create_portfolio_manager
from .managers.research_manager import create_research_manager
from .researchers.bear_researcher import create_bear_researcher
from .researchers.bull_researcher import create_bull_researcher
from .risk_mgmt.aggressive_debator import create_aggressive_debator
from .risk_mgmt.conservative_debator import create_conservative_debator
from .risk_mgmt.neutral_debator import create_neutral_debator
from .managers.research_manager import create_research_manager
from .managers.portfolio_manager import create_portfolio_manager
from .trader.trader import create_trader
from .utils.agent_states import AgentState, InvestDebateState, RiskDebateState
from .utils.agent_utils import create_msg_delete
from .utils.memory import FinancialSituationMemory
__all__ = [
"FinancialSituationMemory",

View File

@ -1,14 +1,13 @@
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from tradingagents.agents.utils.agent_utils import (
build_instrument_context,
get_balance_sheet,
get_cashflow,
get_fundamentals,
get_income_statement,
get_insider_transactions,
get_language_instruction,
)
from tradingagents.dataflows.config import get_config
def create_fundamentals_analyst(llm):

View File

@ -1,11 +1,11 @@
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from tradingagents.agents.utils.agent_utils import (
build_instrument_context,
get_indicators,
get_language_instruction,
get_stock_data,
)
from tradingagents.dataflows.config import get_config
def create_market_analyst(llm):

View File

@ -1,11 +1,11 @@
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from tradingagents.agents.utils.agent_utils import (
build_instrument_context,
get_global_news,
get_language_instruction,
get_news,
)
from tradingagents.dataflows.config import get_config
def create_news_analyst(llm):

View File

@ -1,6 +1,6 @@
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from tradingagents.agents.utils.agent_utils import build_instrument_context, get_language_instruction, get_news
from tradingagents.dataflows.config import get_config
def create_social_media_analyst(llm):

View File

@ -1,6 +1,7 @@
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import MessagesState
from typing_extensions import TypedDict
# Researcher team state

View File

@ -1,23 +1,6 @@
from langchain_core.messages import HumanMessage, RemoveMessage
# Import tools from separate utility files
from tradingagents.agents.utils.core_stock_tools import (
get_stock_data
)
from tradingagents.agents.utils.technical_indicators_tools import (
get_indicators
)
from tradingagents.agents.utils.fundamental_data_tools import (
get_fundamentals,
get_balance_sheet,
get_cashflow,
get_income_statement
)
from tradingagents.agents.utils.news_data_tools import (
get_news,
get_insider_transactions,
get_global_news
)
def get_language_instruction() -> str:

View File

@ -1,5 +1,7 @@
from langchain_core.tools import tool
from typing import Annotated
from langchain_core.tools import tool
from tradingagents.dataflows.interface import route_to_vendor

View File

@ -1,5 +1,7 @@
from langchain_core.tools import tool
from typing import Annotated
from langchain_core.tools import tool
from tradingagents.dataflows.interface import route_to_vendor

View File

@ -4,9 +4,10 @@ Uses BM25 (Best Matching 25) algorithm for retrieval - no API calls,
no token limits, works offline with any LLM provider.
"""
from rank_bm25 import BM25Okapi
from typing import List, Tuple
import re
from typing import List, Tuple
from rank_bm25 import BM25Okapi
class FinancialSituationMemory:

View File

@ -1,7 +1,10 @@
from langchain_core.tools import tool
from typing import Annotated
from langchain_core.tools import tool
from tradingagents.dataflows.interface import route_to_vendor
@tool
def get_news(
ticker: Annotated[str, "Ticker symbol"],

View File

@ -1,7 +1,10 @@
from langchain_core.tools import tool
from typing import Annotated
from langchain_core.tools import tool
from tradingagents.dataflows.interface import route_to_vendor
@tool
def get_indicators(
symbol: Annotated[str, "ticker symbol of the company"],

View File

@ -1,5 +1 @@
# Import functions from specialized modules
from .alpha_vantage_stock import get_stock
from .alpha_vantage_indicator import get_indicator
from .alpha_vantage_fundamentals import get_fundamentals, get_balance_sheet, get_cashflow, get_income_statement
from .alpha_vantage_news import get_news, get_global_news, get_insider_transactions

View File

@ -1,10 +1,11 @@
import os
import requests
import pandas as pd
import json
import os
from datetime import datetime
from io import StringIO
import pandas as pd
import requests
API_BASE_URL = "https://www.alphavantage.co/query"
def get_api_key() -> str:

View File

@ -1,5 +1,6 @@
from .alpha_vantage_common import _make_api_request
def get_indicator(
symbol: str,
indicator: str,
@ -25,6 +26,7 @@ def get_indicator(
String containing indicator values and description
"""
from datetime import datetime
from dateutil.relativedelta import relativedelta
supported_indicators = {

View File

@ -1,5 +1,6 @@
from .alpha_vantage_common import _make_api_request, format_datetime_for_api
def get_news(ticker, start_date, end_date) -> dict[str, str] | str:
"""Returns live and historical market news & sentiment data from premier news outlets worldwide.

View File

@ -1,5 +1,7 @@
from datetime import datetime
from .alpha_vantage_common import _make_api_request, _filter_csv_by_date_range
from .alpha_vantage_common import _filter_csv_by_date_range, _make_api_request
def get_stock(
symbol: str,

View File

@ -1,6 +1,7 @@
import tradingagents.default_config as default_config
from typing import Dict, Optional
import tradingagents.default_config as default_config
# Use default config but allow it to be overridden
_config: Optional[Dict] = None

View File

@ -1,31 +1,56 @@
from typing import Annotated
# Import from vendor-specific modules
from .y_finance import (
get_YFin_data_online,
get_stock_stats_indicators_window,
get_fundamentals as get_yfinance_fundamentals,
get_balance_sheet as get_yfinance_balance_sheet,
get_cashflow as get_yfinance_cashflow,
get_income_statement as get_yfinance_income_statement,
get_insider_transactions as get_yfinance_insider_transactions,
from .alpha_vantage import (
get_balance_sheet as get_alpha_vantage_balance_sheet,
)
from .alpha_vantage import (
get_cashflow as get_alpha_vantage_cashflow,
)
from .alpha_vantage import (
get_fundamentals as get_alpha_vantage_fundamentals,
)
from .alpha_vantage import (
get_global_news as get_alpha_vantage_global_news,
)
from .alpha_vantage import (
get_income_statement as get_alpha_vantage_income_statement,
)
from .alpha_vantage import (
get_indicator as get_alpha_vantage_indicator,
)
from .alpha_vantage import (
get_insider_transactions as get_alpha_vantage_insider_transactions,
)
from .alpha_vantage import (
get_news as get_alpha_vantage_news,
)
from .yfinance_news import get_news_yfinance, get_global_news_yfinance
from .alpha_vantage import (
get_stock as get_alpha_vantage_stock,
get_indicator as get_alpha_vantage_indicator,
get_fundamentals as get_alpha_vantage_fundamentals,
get_balance_sheet as get_alpha_vantage_balance_sheet,
get_cashflow as get_alpha_vantage_cashflow,
get_income_statement as get_alpha_vantage_income_statement,
get_insider_transactions as get_alpha_vantage_insider_transactions,
get_news as get_alpha_vantage_news,
get_global_news as get_alpha_vantage_global_news,
)
from .alpha_vantage_common import AlphaVantageRateLimitError
# Configuration and routing logic
from .config import get_config
from .y_finance import (
get_balance_sheet as get_yfinance_balance_sheet,
)
from .y_finance import (
get_cashflow as get_yfinance_cashflow,
)
from .y_finance import (
get_fundamentals as get_yfinance_fundamentals,
)
from .y_finance import (
get_income_statement as get_yfinance_income_statement,
)
from .y_finance import (
get_insider_transactions as get_yfinance_insider_transactions,
)
from .y_finance import (
get_stock_stats_indicators_window,
get_YFin_data_online,
)
from .yfinance_news import get_global_news_yfinance, get_news_yfinance
# Tools organized by category
TOOLS_CATEGORIES = {

View File

@ -1,12 +1,13 @@
import time
import logging
import os
import time
from typing import Annotated
import pandas as pd
import yfinance as yf
from yfinance.exceptions import YFRateLimitError
from stockstats import wrap
from typing import Annotated
import os
from yfinance.exceptions import YFRateLimitError
from .config import get_config
logger = logging.getLogger(__name__)

View File

@ -1,9 +1,8 @@
import os
import json
import pandas as pd
from datetime import date, timedelta, datetime
from datetime import date, datetime, timedelta
from typing import Annotated
import pandas as pd
SavePathType = Annotated[str, "File path to save data. If None, data is not saved."]
def save_output(data: pd.DataFrame, tag: str, save_path: SavePathType = None) -> None:

View File

@ -1,10 +1,12 @@
from typing import Annotated
from datetime import datetime
from dateutil.relativedelta import relativedelta
from typing import Annotated
import pandas as pd
import yfinance as yf
import os
from .stockstats_utils import StockstatsUtils, _clean_dataframe, yf_retry, load_ohlcv, filter_financials_by_date
from dateutil.relativedelta import relativedelta
from .stockstats_utils import StockstatsUtils, filter_financials_by_date, load_ohlcv, yf_retry
def get_YFin_data_online(
symbol: Annotated[str, "ticker symbol of the company"],

View File

@ -1,7 +1,8 @@
"""yfinance-based news data fetching functions."""
import yfinance as yf
from datetime import datetime
import yfinance as yf
from dateutil.relativedelta import relativedelta
from .stockstats_utils import yf_retry

View File

@ -1,11 +1,11 @@
# TradingAgents/graph/__init__.py
from .trading_graph import TradingAgentsGraph
from .conditional_logic import ConditionalLogic
from .setup import GraphSetup
from .propagation import Propagator
from .reflection import Reflector
from .setup import GraphSetup
from .signal_processing import SignalProcessor
from .trading_graph import TradingAgentsGraph
__all__ = [
"TradingAgentsGraph",

View File

@ -1,8 +1,8 @@
# TradingAgents/graph/propagation.py
from typing import Dict, Any, List, Optional
from typing import Any, Dict, List, Optional
from tradingagents.agents.utils.agent_states import (
AgentState,
InvestDebateState,
RiskDebateState,
)

View File

@ -1,6 +1,7 @@
# TradingAgents/graph/setup.py
from typing import Any, Dict
from langgraph.graph import END, START, StateGraph
from langgraph.prebuilt import ToolNode

View File

@ -1,42 +1,35 @@
# TradingAgents/graph/trading_graph.py
import json
import os
from pathlib import Path
import json
from datetime import date
from typing import Dict, Any, Tuple, List, Optional
from typing import Any, Dict, List, Optional
from langgraph.prebuilt import ToolNode
from tradingagents.llm_clients import create_llm_client
from tradingagents.agents import *
from tradingagents.default_config import DEFAULT_CONFIG
from tradingagents.agents.utils.memory import FinancialSituationMemory
from tradingagents.agents.utils.agent_states import (
AgentState,
InvestDebateState,
RiskDebateState,
)
from tradingagents.dataflows.config import set_config
# Import the new abstract tool methods from agent_utils
from tradingagents.agents.utils.agent_utils import (
get_stock_data,
get_indicators,
get_fundamentals,
get_balance_sheet,
get_cashflow,
get_fundamentals,
get_global_news,
get_income_statement,
get_news,
get_indicators,
get_insider_transactions,
get_global_news
get_news,
get_stock_data,
)
from tradingagents.agents.utils.memory import FinancialSituationMemory
from tradingagents.dataflows.config import set_config
from tradingagents.default_config import DEFAULT_CONFIG
from tradingagents.llm_clients import create_llm_client
from .conditional_logic import ConditionalLogic
from .setup import GraphSetup
from .propagation import Propagator
from .reflection import Reflector
from .setup import GraphSetup
from .signal_processing import SignalProcessor

View File

@ -1,6 +1,6 @@
import warnings
from abc import ABC, abstractmethod
from typing import Any, Optional
import warnings
def normalize_content(response):

View File

@ -1,9 +1,9 @@
from typing import Optional
from .base_client import BaseLLMClient
from .openai_client import OpenAIClient
from .anthropic_client import AnthropicClient
from .base_client import BaseLLMClient
from .google_client import GoogleClient
from .openai_client import OpenAIClient
def create_llm_client(

View File

@ -2,7 +2,6 @@
from .model_catalog import get_known_models
VALID_MODELS = {
provider: models
for provider, models in get_known_models().items()