Skip to content

Commit 67d1314

Browse files
Merge branch 'master' into master
2 parents d3631b7 + 969361e commit 67d1314

20 files changed

+254
-343
lines changed

.github/renovate.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
3+
"extends": ["config:recommended"]
4+
}

.github/workflows/publish-pypi.yml

+26-8
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,41 @@
11
name: Build and publish Python distributions to PyPI
22

33
on:
4-
- push
5-
- workflow_dispatch
4+
push:
5+
branches: [ 'master' ]
6+
tags: [ '*' ]
7+
pull_request:
8+
branches: [ '*' ]
69

710
jobs:
11+
checks:
12+
name: Checks
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@master
16+
- name: Install uv
17+
uses: astral-sh/setup-uv@v5
18+
with:
19+
version: "0.5.21"
20+
- name: Pytest
21+
run: uv run pytest
22+
- name: Ruff check
23+
run: uv run ruff check
24+
- name: Ruff format
25+
run: uv run ruff format --check
26+
827
build-n-publish:
928
name: Build and publish Python distributions to PyPI
1029
runs-on: ubuntu-latest
30+
needs: checks
1131
steps:
1232
- uses: actions/checkout@master
13-
- name: Set up Python 3.11
14-
uses: actions/setup-python@v4
33+
- name: Install uv
34+
uses: astral-sh/setup-uv@v5
1535
with:
16-
python-version: 3.11
36+
version: "0.5.21"
1737
- name: Build wheel
18-
run: |
19-
python3 -m pip install wheel
20-
python3 setup.py sdist bdist_wheel
38+
run: uv build
2139
- name: Publish distribution to PyPI
2240
if: startsWith(github.event.ref, 'refs/tags')
2341
uses: pypa/gh-action-pypi-publish@release/v1.9

MANIFEST.in

-1
This file was deleted.

README.md

+5-6
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,15 @@ If no arguments are supplied pytr will look for them in the file `~/.pytr/creden
9292

9393
## Linting and Code Formatting
9494

95-
This project uses [black](https://github.com/psf/black) for code linting and auto-formatting. You can auto-format the code by running:
95+
This project uses [Ruff](https://astral.sh/ruff) for code linting and auto-formatting. You can auto-format the code by running:
9696

9797
```bash
98-
# Install black if not already installed
99-
pip install black
100-
101-
# Auto-format code
102-
black ./pytr
98+
uv run ruff format # Format code
99+
uv run ruff check --fix-only # Remove unneeded imports, order imports, etc.
103100
```
104101

102+
Ruff runs as part of CI and your Pull Request cannot be merged unless it satisfies the linting and formatting checks.
103+
105104
## Setting Up a Development Environment
106105

107106
1. Clone the repository:

pyproject.toml

+17-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[build-system]
2-
requires = ["setuptools>=42", "wheel", "babel"]
3-
build-backend = "setuptools.build_meta"
2+
requires = ["hatchling", "hatch-babel"]
3+
build-backend = "hatchling.build"
44

55
[project]
66
name = "pytr"
@@ -12,7 +12,7 @@ license = { text = "MIT" }
1212
authors = [
1313
{ name = "marzzzello", email = "[email protected]" }
1414
]
15-
urls = { "Homepage" = "https://gitlab.com/pytr-org/pytr/" }
15+
urls = { "Homepage" = "https://github.com/pytr-org/pytr" }
1616
classifiers = [
1717
"License :: OSI Approved :: MIT License",
1818
"Programming Language :: Python :: 3 :: Only",
@@ -30,16 +30,24 @@ dependencies = [
3030
"pygments",
3131
"requests_futures",
3232
"shtab",
33-
"websockets>=10.1",
33+
"websockets>=10.1,<14",
3434
"babel",
3535
]
3636

3737
[project.scripts]
3838
pytr = "pytr.main:main"
3939

40-
[tool.setuptools]
41-
include-package-data = true
42-
packages = ["pytr"]
40+
[tool.hatch.build.hooks.babel]
41+
locale_dir = "pytr/locale"
4342

44-
[tool.setuptools.package-data]
45-
pytr = ["pytr/locale/*/*/*.mo", "pytr/locale/*/*/*.po"]
43+
[dependency-groups]
44+
dev = [
45+
"ruff>=0.9.4",
46+
"pytest>=8.3.4",
47+
]
48+
49+
[tool.ruff]
50+
line-length = 120
51+
52+
[tool.ruff.lint]
53+
extend-select = ["I"]

pytr/account.py

+11-20
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,27 @@
11
import json
22
import sys
3-
from pygments import highlight, lexers, formatters
43
import time
54
from getpass import getpass
65

7-
from pytr.api import TradeRepublicApi, CREDENTIALS_FILE
6+
from pygments import formatters, highlight, lexers
7+
8+
from pytr.api import CREDENTIALS_FILE, TradeRepublicApi
89
from pytr.utils import get_logger
910

1011

1112
def get_settings(tr):
1213
formatted_json = json.dumps(tr.settings(), indent=2)
1314
if sys.stdout.isatty():
14-
colorful_json = highlight(
15-
formatted_json, lexers.JsonLexer(), formatters.TerminalFormatter()
16-
)
15+
colorful_json = highlight(formatted_json, lexers.JsonLexer(), formatters.TerminalFormatter())
1716
return colorful_json
1817
else:
1918
return formatted_json
2019

2120

22-
def login(phone_no=None, pin=None, web=True):
21+
def login(phone_no=None, pin=None, web=True, store_credentials=False):
2322
"""
24-
If web is true, use web login method as else simulate app login.
25-
Check if credentials file exists else create it.
23+
If web is true, use web login method, else simulate app login.
24+
Handle credentials parameters and store to credentials file if requested.
2625
If no parameters are set but are needed then ask for input
2726
"""
2827
log = get_logger(__name__)
@@ -41,9 +40,7 @@ def login(phone_no=None, pin=None, web=True):
4140
CREDENTIALS_FILE.parent.mkdir(parents=True, exist_ok=True)
4241
if phone_no is None:
4342
log.info("Credentials file not found")
44-
print(
45-
"Please enter your TradeRepublic phone number in the format +4912345678:"
46-
)
43+
print("Please enter your TradeRepublic phone number in the format +4912345678:")
4744
phone_no = input()
4845
else:
4946
log.info("Phone number provided as argument")
@@ -52,17 +49,13 @@ def login(phone_no=None, pin=None, web=True):
5249
print("Please enter your TradeRepublic pin:")
5350
pin = getpass(prompt="Pin (Input is hidden):")
5451

55-
print('Save credentials? Type "y" to save credentials:')
56-
save = input()
57-
if save == "y":
52+
if store_credentials:
5853
with open(CREDENTIALS_FILE, "w") as f:
5954
f.writelines([phone_no + "\n", pin + "\n"])
6055

6156
log.info(f"Saved credentials in {CREDENTIALS_FILE}")
62-
6357
else:
6458
save_cookies = False
65-
log.info("Credentials not saved")
6659

6760
tr = TradeRepublicApi(phone_no=phone_no, pin=pin, save_cookies=save_cookies)
6861

@@ -78,15 +71,13 @@ def login(phone_no=None, pin=None, web=True):
7871
exit(1)
7972
request_time = time.time()
8073
print("Enter the code you received to your mobile app as a notification.")
81-
print(
82-
f"Enter nothing if you want to receive the (same) code as SMS. (Countdown: {countdown})"
83-
)
74+
print(f"Enter nothing if you want to receive the (same) code as SMS. (Countdown: {countdown})")
8475
code = input("Code: ")
8576
if code == "":
8677
countdown = countdown - (time.time() - request_time)
8778
for remaining in range(int(countdown)):
8879
print(
89-
f"Need to wait {int(countdown-remaining)} seconds before requesting SMS...",
80+
f"Need to wait {int(countdown - remaining)} seconds before requesting SMS...",
9081
end="\r",
9182
)
9283
time.sleep(1)

pytr/alarms.py

+5-15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import asyncio
22
from datetime import datetime
33

4-
from pytr.utils import preview, get_logger
4+
from pytr.utils import get_logger, preview
55

66

77
class Alarms:
@@ -19,9 +19,7 @@ async def alarms_loop(self):
1919
recv += 1
2020
self.alarms = response
2121
else:
22-
print(
23-
f"unmatched subscription of type '{subscription['type']}':\n{preview(response)}"
24-
)
22+
print(f"unmatched subscription of type '{subscription['type']}':\n{preview(response)}")
2523

2624
if recv == 1:
2725
return
@@ -36,9 +34,7 @@ async def ticker_loop(self):
3634
recv += 1
3735
self.alarms = response
3836
else:
39-
print(
40-
f"unmatched subscription of type '{subscription['type']}':\n{preview(response)}"
41-
)
37+
print(f"unmatched subscription of type '{subscription['type']}':\n{preview(response)}")
4238

4339
if recv == 1:
4440
return
@@ -47,11 +43,7 @@ def overview(self):
4743
print("ISIN status created target diff% createdAt triggeredAT")
4844
self.log.debug(f"Processing {len(self.alarms)} alarms")
4945

50-
for (
51-
a
52-
) in (
53-
self.alarms
54-
): # sorted(positions, key=lambda x: x['netValue'], reverse=True):
46+
for a in self.alarms: # sorted(positions, key=lambda x: x['netValue'], reverse=True):
5547
self.log.debug(f" Processing {a} alarm")
5648
ts = int(a["createdAt"]) / 1000.0
5749
target_price = float(a["targetPrice"])
@@ -61,9 +53,7 @@ def overview(self):
6153
triggered = "-"
6254
else:
6355
ts = int(a["triggeredAt"]) / 1000.0
64-
triggered = datetime.fromtimestamp(ts).isoformat(
65-
sep=" ", timespec="minutes"
66-
)
56+
triggered = datetime.fromtimestamp(ts).isoformat(sep=" ", timespec="minutes")
6757

6858
if a["createdPrice"] == 0:
6959
diffP = 0.0

0 commit comments

Comments
 (0)