Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3ff49c7
introduce .editorconfig
tschm Nov 10, 2025
05088bf
remove isort black and flake8, move towards ruff
tschm Nov 10, 2025
3bff10e
pip install the package
tschm Nov 10, 2025
f3864c4
towards ruff
tschm Nov 11, 2025
acb0a58
check whether all hooks are respected
tschm Nov 11, 2025
699a70e
ruff.toml (mostly deactivated for now)
tschm Nov 11, 2025
623a64c
fixing basic ruff issues (use uvx ruff check --fix .)
tschm Nov 11, 2025
da22f1e
bunch of isort problems in the notebooks
tschm Nov 11, 2025
d79234c
Merge branch 'main' into editorconfig2
tschm Nov 11, 2025
3a3b721
towards working ruff
tschm Nov 11, 2025
8ba2107
line length 88
tschm Nov 11, 2025
1d4cf44
mild impact of linting
tschm Nov 11, 2025
3b30b4e
linting also in notebooks
tschm Nov 11, 2025
72434b6
don't test isort, black and flake explicitly
tschm Nov 11, 2025
b562804
don't test isort, black and flake explicitly
tschm Nov 11, 2025
8d4cd97
flake8 traces removed
tschm Nov 11, 2025
95a0ba3
pre-commit now correctly complains about outdated codecov-action
tschm Nov 11, 2025
a9a03b8
stricter linting
tschm Nov 11, 2025
eddc3f7
remove link to tschm/.config-templates
tschm Nov 11, 2025
4b121d8
remove commented out linting
tschm Nov 11, 2025
3a2828c
ruff.toml integrated into pyproject.toml. excluded the notebooks from…
tschm Nov 12, 2025
a9460fc
revisit dev dependencies
tschm Nov 12, 2025
72ee4c7
Merge branch 'PyPortfolio:main' into editorconfig2
tschm Nov 14, 2025
109873d
Merge branch 'main' into pr/653
fkiraly Nov 14, 2025
fb8b1f4
Update pre-commit.yml
fkiraly Nov 14, 2025
5d589ee
Update pyproject.toml
fkiraly Nov 14, 2025
7600c44
move to main
fkiraly Nov 14, 2025
4e71fd2
Update .pre-commit-config.yaml
fkiraly Nov 14, 2025
dd9b865
Update __init__.py
fkiraly Nov 14, 2025
853d939
isort
fkiraly Nov 14, 2025
15fea9a
Revert "isort"
fkiraly Nov 14, 2025
b1dcc79
Update main.yml
fkiraly Nov 14, 2025
80fdc9f
Update __init__.py
fkiraly Nov 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# This file is part of the tschm/.config-templates repository
# (https://github.com/tschm/.config-templates).
#
root = true

# Default settings for all files
[*]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
charset = utf-8

# Python, reStructuredText, and text files
[*.{py,rst,txt}]
indent_style = space
indent_size = 4

# YAML, JSON, and other config files
[*.{yml,yaml,json}]
indent_style = space
indent_size = 2

# Markdown files
# [*.{md,markdown}]
# trim_trailing_whitespace = false

# Don't apply editorconfig rules to vendor/ resources
# This is a "defensive" rule for the day we may have
# the vendor folder
[vendor/**]
charset = unset
end_of_line = unset
indent_size = unset
indent_style = unset
insert_final_newline = unset
trim_trailing_whitespace = unset
5 changes: 0 additions & 5 deletions .flake8

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
- name: Upload coverage to Codecov
# if false in order to skip for now
if: false
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v5
with:
files: ./coverage.xml
fail_ci_if_error: true
49 changes: 37 additions & 12 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,44 @@ concurrency:
cancel-in-progress: true

jobs:
code-quality:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5

- uses: actions/setup-python@v6
with:
python-version: '3.13'

- name: install pre-commit
run: python3 -m pip install pre-commit

- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0

- name: Get changed files
id: changed-files
run: |
CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | tr '\n' ' ')
echo "CHANGED_FILES=${CHANGED_FILES}" >> $GITHUB_ENV

- name: Print changed files
run: |
echo "Changed files: $CHANGED_FILES"

- name: Run pre-commit on changed files
run: |
if [ -n "$CHANGED_FILES" ]; then
pre-commit run --color always --files $CHANGED_FILES --show-diff-on-failure
else
echo "No changed files to check."
fi

pytest:
needs: code-quality
name: py${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
Expand Down Expand Up @@ -53,15 +90,3 @@ jobs:
- name: Test with pytest
run: |
pytest ./tests

- name: Check with isort
run: |
isort --check --diff .

- name: Check with black
run: |
black --check --diff .

- name: Check with flake8
run: |
flake8 --show-source --statistics .
15 changes: 15 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: check-toml
- id: check-yaml

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.14.5'
hooks:
- id: ruff
args: [ --fix, --exit-non-zero-on-fix, --unsafe-fixes ]

# Run the formatter
- id: ruff-format
717 changes: 360 additions & 357 deletions cookbook/1-RiskReturnModels.ipynb

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions pypfopt/black_litterman.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def __init__(
view_confidences=None,
tau=0.05,
risk_aversion=1,
**kwargs
**kwargs,
):
"""
:param cov_matrix: NxN covariance matrix of returns
Expand Down Expand Up @@ -296,8 +296,7 @@ def _set_omega(self, omega, view_confidences):
elif omega == "idzorek":
if view_confidences is None:
raise ValueError(
"To use Idzorek's method, please supply a vector of percentage "
"confidence levels for each view."
"To use Idzorek's method, please supply a vector of percentage confidence levels for each view."
)
if not isinstance(view_confidences, np.ndarray):
try:
Expand Down
16 changes: 8 additions & 8 deletions pypfopt/cla.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,11 +314,11 @@ def _solve(self):
covarF_inv = np.linalg.inv(covarF)
j = 0
for i in f:
l, bi = self._compute_lambda(
lam, bi = self._compute_lambda(
covarF_inv, covarFB, meanF, wB, j, [self.lB[i], self.uB[i]]
)
if CLA._infnone(l) > CLA._infnone(l_in):
l_in, i_in, bi_in = l, i, bi
if CLA._infnone(lam) > CLA._infnone(l_in):
l_in, i_in, bi_in = lam, i, bi
j += 1
# 2) case b): Free one bounded weight
l_out = None
Expand All @@ -327,18 +327,18 @@ def _solve(self):
for i in b:
covarF, covarFB, meanF, wB = self._get_matrices(f + [i])
covarF_inv = np.linalg.inv(covarF)
l, bi = self._compute_lambda(
lam, bi = self._compute_lambda(
covarF_inv,
covarFB,
meanF,
wB,
meanF.shape[0] - 1,
self.w[-1][i],
)
if (self.ls[-1] is None or l < self.ls[-1]) and l > CLA._infnone(
l_out
):
l_out, i_out = l, i
if (
self.ls[-1] is None or lam < self.ls[-1]
) and lam > CLA._infnone(l_out):
l_out, i_out = lam, i
if (l_in is None or l_in < 0) and (l_out is None or l_out < 0):
# 3) compute minimum variance solution
self.ls.append(0)
Expand Down
4 changes: 2 additions & 2 deletions pypfopt/risk_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def semicovariance(
benchmark=0.000079,
frequency=252,
log_returns=False,
**kwargs
**kwargs,
):
"""
Estimate the semicovariance matrix, i.e the covariance given that
Expand Down Expand Up @@ -290,7 +290,7 @@ def min_cov_determinant(
frequency=252,
random_state=None,
log_returns=False,
**kwargs
**kwargs,
): # pragma: no cover
warnings.warn("min_cov_determinant is deprecated and will be removed in v1.5")

Expand Down
35 changes: 26 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,9 @@ all_extras = [

# dev - the developer dependency set, for contributors and CI
dev = [
"pytest>=7.1.2",
"flake8>=4.0.1",
"black>=22.3.0",
"pytest-cov>=3.0.0",
"yfinance>=0.1.70",
"isort",
"pytest>=9.0.0",
"pytest-cov>=7.0.0",
"yfinance>=0.2.66",
]

# notebook tests
Expand All @@ -91,8 +88,28 @@ requires = [
[tool.setuptools.packages.find]
exclude = ["example", "example.*", "tests", "tests.*"]

[tool.black]
[tool.ruff]
line-length = 88
# Keep Ruff aligned with project target version
target-version = "py311"
# Exclude individual files/patterns from Ruff linting/formatting
exclude = [
"tests/test_imports.py",
"cookbook/*.ipynb",
]

[tool.ruff.lint]
# Keep the same selected rule sets as in ruff.toml
select = ["F", "I"]

[tool.ruff.format]
# Formatting configuration
quote-style = "double"
indent-style = "space"
line-ending = "auto"
skip-magic-trailing-comma = false

[tool.isort]
profile = "black"
[tool.ruff.lint.isort]
known-first-party = ["pypfopt"]
combine-as-imports = true
force-sort-within-sections = true
6 changes: 3 additions & 3 deletions tests/test_plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ def test_dendrogram_plot():

ax = plotting.plot_dendrogram(hrp, showfig=False)
assert len(ax.findobj()) > 180
assert type(ax.findobj()[0]) == matplotlib.collections.LineCollection
assert isinstance(ax.findobj()[0], matplotlib.collections.LineCollection)
plt.clf()

ax = plotting.plot_dendrogram(hrp, show_tickers=False, showfig=False)
assert len(ax.findobj()) > 60
assert type(ax.findobj()[0]) == matplotlib.collections.LineCollection
assert isinstance(ax.findobj()[0], matplotlib.collections.LineCollection)
plt.clf()
plt.close()

Expand All @@ -78,7 +78,7 @@ def test_dendrogram_plot():
== "hrp param has not been optimized. Attempting optimization."
)
assert len(ax.findobj()) > 60
assert type(ax.findobj()[0]) == matplotlib.collections.LineCollection
assert isinstance(ax.findobj()[0], matplotlib.collections.LineCollection)
plt.clf()
plt.close()

Expand Down