grynn-fplot 0.3.1__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/.github/workflows/publish.yml +0 -31
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/PKG-INFO +4 -4
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/grynn_fplot/cli.py +9 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/grynn_fplot/core.py +9 -3
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/grynn_fplot/filter_parser.py +112 -0
- grynn_fplot-0.3.2/pyproject.toml +66 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/uv.lock +1 -1
- grynn_fplot-0.3.1/pyproject.toml +0 -66
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/.devcontainer/devcontainer.json +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/.github/copilot-instructions.md +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/.github/dependabot.yml +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/.gitignore +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/.pre-commit-config.yaml +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/.secrets.baseline +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/.vscode/settings.json +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/FILTER_DESIGN.md +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/FILTER_EXAMPLES.sh +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/Makefile +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/PERFORMANCE_OPTIMIZATION.md +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/README.md +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/SUMMARY.md +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/WEB_REFACTOR.md +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/example_usage.sh +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/grynn_fplot/__init__.py +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/grynn_fplot/drawdowns.py +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/grynn_fplot/index.html +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/grynn_fplot/plot_option_interactive.py +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/grynn_fplot/serve.py +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/grynn_fplot/web_api.py +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/tests/test_cli_options.py +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/tests/test_filter_evaluation.py +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/tests/test_filter_parser.py +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/tests/test_fplot.py +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/tests/test_options.py +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/tests/test_web_api.py +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/tests/test_web_interface.py +0 -0
- {grynn_fplot-0.3.1 → grynn_fplot-0.3.2}/todo.md +0 -0
|
@@ -7,15 +7,6 @@ on:
|
|
|
7
7
|
release:
|
|
8
8
|
types: [published]
|
|
9
9
|
workflow_dispatch:
|
|
10
|
-
inputs:
|
|
11
|
-
target:
|
|
12
|
-
description: 'Publish target'
|
|
13
|
-
required: true
|
|
14
|
-
default: 'testpypi'
|
|
15
|
-
type: choice
|
|
16
|
-
options:
|
|
17
|
-
- testpypi
|
|
18
|
-
- pypi
|
|
19
10
|
|
|
20
11
|
jobs:
|
|
21
12
|
build:
|
|
@@ -44,28 +35,6 @@ jobs:
|
|
|
44
35
|
name: python-package-distributions
|
|
45
36
|
path: dist/
|
|
46
37
|
|
|
47
|
-
publish-testpypi:
|
|
48
|
-
name: Publish to TestPyPI
|
|
49
|
-
if: github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'testpypi'
|
|
50
|
-
needs: build
|
|
51
|
-
runs-on: ubuntu-latest
|
|
52
|
-
environment:
|
|
53
|
-
name: testpypi
|
|
54
|
-
url: https://test.pypi.org/p/grynn-fplot
|
|
55
|
-
permissions:
|
|
56
|
-
id-token: write
|
|
57
|
-
steps:
|
|
58
|
-
- name: Download distributions
|
|
59
|
-
uses: actions/download-artifact@v4
|
|
60
|
-
with:
|
|
61
|
-
name: python-package-distributions
|
|
62
|
-
path: dist/
|
|
63
|
-
|
|
64
|
-
- name: Publish to TestPyPI
|
|
65
|
-
uses: pypa/gh-action-pypi-publish@release/v1
|
|
66
|
-
with:
|
|
67
|
-
repository-url: https://test.pypi.org/legacy/
|
|
68
|
-
|
|
69
38
|
publish-pypi:
|
|
70
39
|
name: Publish to PyPI
|
|
71
40
|
if: github.event_name == 'push' || github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'pypi')
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: grynn-fplot
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: CLI tool for plotting financial data and analyzing options
|
|
5
|
-
Project-URL: Homepage, https://github.com/Grynn/
|
|
6
|
-
Project-URL:
|
|
7
|
-
Project-URL:
|
|
5
|
+
Project-URL: Homepage, https://github.com/Grynn/grynn_cli_fplot
|
|
6
|
+
Project-URL: Issues, https://github.com/Grynn/grynn_cli_fplot/issues
|
|
7
|
+
Project-URL: Repository, https://github.com/Grynn/grynn_cli_fplot
|
|
8
8
|
Author-email: Grynn <vishal.doshi@gmail.com>
|
|
9
9
|
License: MIT
|
|
10
10
|
Keywords: cli,finance,options,plotting,stocks
|
|
@@ -52,6 +52,7 @@ except importlib.metadata.PackageNotFoundError:
|
|
|
52
52
|
default=None,
|
|
53
53
|
help="Filter expression (e.g., 'dte>300', 'dte>10, dte<15', 'dte>300 + strike<100')",
|
|
54
54
|
)
|
|
55
|
+
@click.option("--filter-help", is_flag=True, help="Show help for filter expressions and exit")
|
|
55
56
|
@click.option("--web", "-w", is_flag=True, help="Launch interactive web interface")
|
|
56
57
|
@click.option("--port", type=int, default=8000, help="Port for web interface")
|
|
57
58
|
@click.option("--host", type=str, default="127.0.0.1", help="Host for web interface")
|
|
@@ -68,6 +69,7 @@ def display_plot(
|
|
|
68
69
|
min_dte,
|
|
69
70
|
show_all,
|
|
70
71
|
filter_expr,
|
|
72
|
+
filter_help,
|
|
71
73
|
web,
|
|
72
74
|
port,
|
|
73
75
|
host,
|
|
@@ -107,6 +109,13 @@ def display_plot(
|
|
|
107
109
|
print(f"fplot {__version__}")
|
|
108
110
|
return
|
|
109
111
|
|
|
112
|
+
# Show filter help if requested
|
|
113
|
+
if filter_help:
|
|
114
|
+
from grynn_fplot.filter_parser import get_filter_help
|
|
115
|
+
|
|
116
|
+
print(get_filter_help())
|
|
117
|
+
return
|
|
118
|
+
|
|
110
119
|
# Launch web interface if --web flag is used
|
|
111
120
|
if web:
|
|
112
121
|
launch_web_interface(ticker, since, interval, port, host, no_browser, debug)
|
|
@@ -486,19 +486,25 @@ def format_options_for_display(
|
|
|
486
486
|
strike = option.get("strike", 0)
|
|
487
487
|
volume = option.get("volume", 0) or 0 # Handle None values
|
|
488
488
|
last_price = option.get("lastPrice", 0) or 0
|
|
489
|
-
|
|
489
|
+
|
|
490
490
|
# Get last trade date and calculate days since last trade
|
|
491
491
|
last_trade_date = option.get("lastTradeDate", None)
|
|
492
492
|
lt_days = None
|
|
493
493
|
if last_trade_date:
|
|
494
494
|
try:
|
|
495
|
-
from datetime import datetime
|
|
495
|
+
from datetime import datetime, timezone
|
|
496
|
+
|
|
496
497
|
# lastTradeDate can be a timestamp or datetime
|
|
497
498
|
if isinstance(last_trade_date, (int, float)):
|
|
498
499
|
last_trade_dt = datetime.fromtimestamp(last_trade_date)
|
|
499
500
|
else:
|
|
500
501
|
last_trade_dt = last_trade_date
|
|
501
|
-
|
|
502
|
+
# Convert both to timezone-aware UTC for comparison
|
|
503
|
+
now_utc = datetime.now(timezone.utc)
|
|
504
|
+
if last_trade_dt.tzinfo is None:
|
|
505
|
+
# If last_trade_dt is naive, assume UTC
|
|
506
|
+
last_trade_dt = last_trade_dt.replace(tzinfo=timezone.utc)
|
|
507
|
+
lt_days = (now_utc - last_trade_dt).days
|
|
502
508
|
except Exception:
|
|
503
509
|
lt_days = None
|
|
504
510
|
|
|
@@ -26,6 +26,39 @@ from typing import Any, Dict, List, Union
|
|
|
26
26
|
from dataclasses import dataclass
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
# Registry of available filter fields with descriptions
|
|
30
|
+
FILTER_FIELDS = {
|
|
31
|
+
"dte": {"description": "Days to expiry", "type": "integer", "example": "dte>150"},
|
|
32
|
+
"volume": {"description": "Option trading volume", "type": "integer", "example": "volume>100"},
|
|
33
|
+
"price": {"description": "Last traded price", "type": "float", "example": "price<5.0"},
|
|
34
|
+
"return": {
|
|
35
|
+
"description": "Return metric (CAGR for calls, annualized return for puts)",
|
|
36
|
+
"type": "float",
|
|
37
|
+
"aliases": ["ret", "ar"],
|
|
38
|
+
"example": "return>0.15",
|
|
39
|
+
},
|
|
40
|
+
"ret": {"description": "Alias for 'return'", "type": "float", "alias_of": "return", "example": "ret>0.15"},
|
|
41
|
+
"ar": {
|
|
42
|
+
"description": "Alias for 'return' (annualized return)",
|
|
43
|
+
"type": "float",
|
|
44
|
+
"alias_of": "return",
|
|
45
|
+
"example": "ar>0.15",
|
|
46
|
+
},
|
|
47
|
+
"strike_pct": {
|
|
48
|
+
"description": "Strike percentage relative to spot price (positive = above spot, negative = below spot)",
|
|
49
|
+
"type": "float",
|
|
50
|
+
"aliases": ["sp"],
|
|
51
|
+
"example": "strike_pct>5",
|
|
52
|
+
},
|
|
53
|
+
"sp": {"description": "Alias for 'strike_pct'", "type": "float", "alias_of": "strike_pct", "example": "sp>5"},
|
|
54
|
+
"lt_days": {
|
|
55
|
+
"description": "Days since last trade (useful for filtering stale/illiquid options)",
|
|
56
|
+
"type": "integer",
|
|
57
|
+
"example": "lt_days<7",
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
29
62
|
@dataclass
|
|
30
63
|
class FilterNode:
|
|
31
64
|
"""Represents a single filter condition"""
|
|
@@ -451,3 +484,82 @@ def filter_to_string(filter_dict: Dict[str, Any]) -> str:
|
|
|
451
484
|
return f"({separator.join(children_strs)})"
|
|
452
485
|
else:
|
|
453
486
|
raise ValueError(f"Invalid filter dictionary: {filter_dict}")
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def get_filter_help() -> str:
|
|
490
|
+
"""Generate formatted help text for available filter fields.
|
|
491
|
+
|
|
492
|
+
Returns:
|
|
493
|
+
Formatted help text describing all filter fields, operators, and syntax
|
|
494
|
+
"""
|
|
495
|
+
help_lines = []
|
|
496
|
+
|
|
497
|
+
# Header
|
|
498
|
+
help_lines.append("Filter Expression Reference")
|
|
499
|
+
help_lines.append("=" * 50)
|
|
500
|
+
help_lines.append("")
|
|
501
|
+
|
|
502
|
+
# Available Fields
|
|
503
|
+
help_lines.append("Available Filter Fields:")
|
|
504
|
+
help_lines.append("-" * 50)
|
|
505
|
+
|
|
506
|
+
# Group main fields (exclude aliases)
|
|
507
|
+
main_fields = {k: v for k, v in FILTER_FIELDS.items() if "alias_of" not in v}
|
|
508
|
+
|
|
509
|
+
for field_name in sorted(main_fields.keys()):
|
|
510
|
+
field_info = main_fields[field_name]
|
|
511
|
+
help_lines.append(f"\n {field_name}")
|
|
512
|
+
help_lines.append(f" {field_info['description']}")
|
|
513
|
+
help_lines.append(f" Type: {field_info['type']}")
|
|
514
|
+
|
|
515
|
+
# Show aliases if any
|
|
516
|
+
if "aliases" in field_info:
|
|
517
|
+
aliases_str = ", ".join(field_info["aliases"])
|
|
518
|
+
help_lines.append(f" Aliases: {aliases_str}")
|
|
519
|
+
|
|
520
|
+
help_lines.append(f" Example: {field_info['example']}")
|
|
521
|
+
|
|
522
|
+
# Operators
|
|
523
|
+
help_lines.append("\n")
|
|
524
|
+
help_lines.append("Comparison Operators:")
|
|
525
|
+
help_lines.append("-" * 50)
|
|
526
|
+
help_lines.append(" > Greater than")
|
|
527
|
+
help_lines.append(" < Less than")
|
|
528
|
+
help_lines.append(" >= Greater than or equal")
|
|
529
|
+
help_lines.append(" <= Less than or equal")
|
|
530
|
+
help_lines.append(" = Equal (also ==)")
|
|
531
|
+
help_lines.append(" != Not equal")
|
|
532
|
+
|
|
533
|
+
# Logical Operators
|
|
534
|
+
help_lines.append("\n")
|
|
535
|
+
help_lines.append("Logical Operators:")
|
|
536
|
+
help_lines.append("-" * 50)
|
|
537
|
+
help_lines.append(" , AND - all conditions must be true")
|
|
538
|
+
help_lines.append(" + OR - at least one condition must be true")
|
|
539
|
+
help_lines.append(" () Parentheses for grouping")
|
|
540
|
+
|
|
541
|
+
# Time Value Formats
|
|
542
|
+
help_lines.append("\n")
|
|
543
|
+
help_lines.append("Time Value Formats:")
|
|
544
|
+
help_lines.append("-" * 50)
|
|
545
|
+
help_lines.append(" DTE-style (returns days): 1y, 6m, 2w, 30d")
|
|
546
|
+
help_lines.append(" Duration (returns hours): 2d15h, 30m, 1h")
|
|
547
|
+
help_lines.append(" Plain integers: 5, 150, 300")
|
|
548
|
+
|
|
549
|
+
# Examples
|
|
550
|
+
help_lines.append("\n")
|
|
551
|
+
help_lines.append("Example Filters:")
|
|
552
|
+
help_lines.append("-" * 50)
|
|
553
|
+
help_lines.append(" dte>150")
|
|
554
|
+
help_lines.append(" Options with more than 150 days to expiry")
|
|
555
|
+
help_lines.append("")
|
|
556
|
+
help_lines.append(" dte>150, lt_days<7")
|
|
557
|
+
help_lines.append(" Options with DTE > 150 AND traded in last 7 days")
|
|
558
|
+
help_lines.append("")
|
|
559
|
+
help_lines.append(" (dte>300 + dte<30), volume>100")
|
|
560
|
+
help_lines.append(" Options with (DTE > 300 OR DTE < 30) AND volume > 100")
|
|
561
|
+
help_lines.append("")
|
|
562
|
+
help_lines.append(" return>0.20, sp>5, sp<15")
|
|
563
|
+
help_lines.append(" Options with return > 20%, strike 5-15% above spot")
|
|
564
|
+
|
|
565
|
+
return "\n".join(help_lines)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
build-backend = "hatchling.build"
|
|
3
|
+
requires = ["hatchling"]
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
authors = [{name = "Grynn", email = "vishal.doshi@gmail.com"}]
|
|
7
|
+
classifiers = [
|
|
8
|
+
"Development Status :: 4 - Beta",
|
|
9
|
+
"Environment :: Console",
|
|
10
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
11
|
+
"License :: OSI Approved :: MIT License",
|
|
12
|
+
"Programming Language :: Python :: 3.12",
|
|
13
|
+
"Programming Language :: Python :: 3.13",
|
|
14
|
+
"Topic :: Office/Business :: Financial :: Investment",
|
|
15
|
+
]
|
|
16
|
+
dependencies = [
|
|
17
|
+
"click ~= 8.1.7",
|
|
18
|
+
"matplotlib >= 3.9.2",
|
|
19
|
+
"dateparser ~= 1.2.0",
|
|
20
|
+
"mplcursors ~= 0.5.3",
|
|
21
|
+
"fastapi ~= 0.115.0",
|
|
22
|
+
"uvicorn ~= 0.32.0",
|
|
23
|
+
"scikit-learn >= 1.6.1",
|
|
24
|
+
"grynn-pylib",
|
|
25
|
+
"ipywidgets>=8.1.5",
|
|
26
|
+
"tabulate>=0.9.0",
|
|
27
|
+
"yfinance",
|
|
28
|
+
"pandas>=2.2.3",
|
|
29
|
+
]
|
|
30
|
+
description = "CLI tool for plotting financial data and analyzing options"
|
|
31
|
+
keywords = ["finance", "stocks", "options", "plotting", "cli"]
|
|
32
|
+
license = {text = "MIT"}
|
|
33
|
+
name = "grynn-fplot"
|
|
34
|
+
readme = "README.md"
|
|
35
|
+
requires-python = ">=3.12"
|
|
36
|
+
version = "0.3.2"
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
fplot = "grynn_fplot.cli:display_plot"
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
Homepage = "https://github.com/Grynn/grynn_cli_fplot"
|
|
43
|
+
Issues = "https://github.com/Grynn/grynn_cli_fplot/issues"
|
|
44
|
+
Repository = "https://github.com/Grynn/grynn_cli_fplot"
|
|
45
|
+
|
|
46
|
+
[project.optional-dependencies]
|
|
47
|
+
dev = [
|
|
48
|
+
"ipykernel>=6.29.5",
|
|
49
|
+
"ipython>=8.18.1",
|
|
50
|
+
"mypy>=1.14.1",
|
|
51
|
+
"pytest>=8.3.4",
|
|
52
|
+
"ruff>=0.9.2",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[tool.uv.sources]
|
|
56
|
+
grynn-pylib = {git = "https://github.com/Grynn/grynn_pylib.git"}
|
|
57
|
+
yfinance = {git = "https://github.com/ranaroussi/yfinance.git"}
|
|
58
|
+
|
|
59
|
+
[dependency-groups]
|
|
60
|
+
dev = [
|
|
61
|
+
"httpx>=0.28.1",
|
|
62
|
+
"pre-commit>=4.1.0",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
[tool.ruff]
|
|
66
|
+
line-length = 120
|
grynn_fplot-0.3.1/pyproject.toml
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["hatchling"]
|
|
3
|
-
build-backend = "hatchling.build"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "grynn-fplot"
|
|
7
|
-
version = "0.3.1"
|
|
8
|
-
description = "CLI tool for plotting financial data and analyzing options"
|
|
9
|
-
authors = [{ name = "Grynn", email = "vishal.doshi@gmail.com" }]
|
|
10
|
-
requires-python = ">=3.12"
|
|
11
|
-
readme = "README.md"
|
|
12
|
-
license = { text = "MIT" }
|
|
13
|
-
keywords = ["finance", "stocks", "options", "plotting", "cli"]
|
|
14
|
-
classifiers = [
|
|
15
|
-
"Development Status :: 4 - Beta",
|
|
16
|
-
"Environment :: Console",
|
|
17
|
-
"Intended Audience :: Financial and Insurance Industry",
|
|
18
|
-
"License :: OSI Approved :: MIT License",
|
|
19
|
-
"Programming Language :: Python :: 3.12",
|
|
20
|
-
"Programming Language :: Python :: 3.13",
|
|
21
|
-
"Topic :: Office/Business :: Financial :: Investment",
|
|
22
|
-
]
|
|
23
|
-
dependencies = [
|
|
24
|
-
"click ~= 8.1.7",
|
|
25
|
-
"matplotlib >= 3.9.2",
|
|
26
|
-
"dateparser ~= 1.2.0",
|
|
27
|
-
"mplcursors ~= 0.5.3",
|
|
28
|
-
"fastapi ~= 0.115.0",
|
|
29
|
-
"uvicorn ~= 0.32.0",
|
|
30
|
-
"scikit-learn >= 1.6.1",
|
|
31
|
-
"grynn-pylib",
|
|
32
|
-
"ipywidgets>=8.1.5",
|
|
33
|
-
"tabulate>=0.9.0",
|
|
34
|
-
"yfinance",
|
|
35
|
-
"pandas>=2.2.3",
|
|
36
|
-
]
|
|
37
|
-
|
|
38
|
-
[project.scripts]
|
|
39
|
-
fplot = "grynn_fplot.cli:display_plot"
|
|
40
|
-
|
|
41
|
-
[project.urls]
|
|
42
|
-
Homepage = "https://github.com/Grynn/grynn_fplot"
|
|
43
|
-
Repository = "https://github.com/Grynn/grynn_fplot"
|
|
44
|
-
Issues = "https://github.com/Grynn/grynn_fplot/issues"
|
|
45
|
-
|
|
46
|
-
[project.optional-dependencies]
|
|
47
|
-
dev = [
|
|
48
|
-
"ipykernel>=6.29.5",
|
|
49
|
-
"ipython>=8.18.1",
|
|
50
|
-
"mypy>=1.14.1",
|
|
51
|
-
"pytest>=8.3.4",
|
|
52
|
-
"ruff>=0.9.2",
|
|
53
|
-
]
|
|
54
|
-
|
|
55
|
-
[tool.uv.sources]
|
|
56
|
-
grynn-pylib = { git = "https://github.com/Grynn/grynn_pylib.git" }
|
|
57
|
-
yfinance = { git = "https://github.com/ranaroussi/yfinance.git" }
|
|
58
|
-
|
|
59
|
-
[dependency-groups]
|
|
60
|
-
dev = [
|
|
61
|
-
"httpx>=0.28.1",
|
|
62
|
-
"pre-commit>=4.1.0",
|
|
63
|
-
]
|
|
64
|
-
|
|
65
|
-
[tool.ruff]
|
|
66
|
-
line-length = 120
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|