Skip to content

Commit

Permalink
Blacker (#139)
Browse files Browse the repository at this point in the history
* turn it black

* Updating README.m and version
  • Loading branch information
Katzmann1983 authored Nov 5, 2024
1 parent daa19aa commit ee1f260
Show file tree
Hide file tree
Showing 14 changed files with 737 additions and 525 deletions.
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,41 @@ $ pytr login --phone_no +49123456789 --pin 1234
```

If no arguments are supplied pytr will look for them in the file `~/.pytr/credentials` (the first line must contain the phone number, the second line the pin). If the file doesn't exist pytr will ask for for the phone number and pin.


## Linting and Code Formatting

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

```bash
# Install black if not already installed
pip install black

# Auto-format code
black ./pytr
```

## Setting Up a Development Environment

1. Clone the repository:
```bash
git clone https://github.com/pytr-org/pytr.git
```

2. Install dependencies:
```bash
pip install .
```

3. Run the tests to ensure everything is set up correctly:
```bash
pytest
```

## Help and Support

For help or feedback, please reach out via email at [[email protected]](mailto:[email protected]).

## License

This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "pytr"
version = "0.3.0"
version = "0.3.1"
description = "Use TradeRepublic in terminal"
readme = "README.md"
requires-python = ">=3.8"
Expand Down
4 changes: 2 additions & 2 deletions pytr/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

from pytr.main import main

if __name__ == '__main__':
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
log = logging.getLogger(__name__)
log.info('Exiting...')
log.info("Exiting...")
exit()
except Exception as e:
log = logging.getLogger(__name__)
Expand Down
69 changes: 39 additions & 30 deletions pytr/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,98 +11,107 @@
def get_settings(tr):
formatted_json = json.dumps(tr.settings(), indent=2)
if sys.stdout.isatty():
colorful_json = highlight(formatted_json, lexers.JsonLexer(), formatters.TerminalFormatter())
colorful_json = highlight(
formatted_json, lexers.JsonLexer(), formatters.TerminalFormatter()
)
return colorful_json
else:
return formatted_json


def login(phone_no=None, pin=None, web=True):
'''
"""
If web is true, use web login method as else simulate app login.
Check if credentials file exists else create it.
If no parameters are set but are needed then ask for input
'''
"""
log = get_logger(__name__)
save_cookies = True

if phone_no is None and CREDENTIALS_FILE.is_file():
log.info('Found credentials file')
log.info("Found credentials file")
with open(CREDENTIALS_FILE) as f:
lines = f.readlines()
phone_no = lines[0].strip()
pin = lines[1].strip()
phone_no_masked = phone_no[:-8] + '********'
pin_masked = len(pin) * '*'
log.info(f'Phone: {phone_no_masked}, PIN: {pin_masked}')
phone_no_masked = phone_no[:-8] + "********"
pin_masked = len(pin) * "*"
log.info(f"Phone: {phone_no_masked}, PIN: {pin_masked}")
else:
CREDENTIALS_FILE.parent.mkdir(parents=True, exist_ok=True)
if phone_no is None:
log.info('Credentials file not found')
print('Please enter your TradeRepublic phone number in the format +4912345678:')
log.info("Credentials file not found")
print(
"Please enter your TradeRepublic phone number in the format +4912345678:"
)
phone_no = input()
else:
log.info('Phone number provided as argument')
log.info("Phone number provided as argument")

if pin is None:
print('Please enter your TradeRepublic pin:')
pin = getpass(prompt='Pin (Input is hidden):')
print("Please enter your TradeRepublic pin:")
pin = getpass(prompt="Pin (Input is hidden):")

print('Save credentials? Type "y" to save credentials:')
save = input()
if save == 'y':
with open(CREDENTIALS_FILE, 'w') as f:
f.writelines([phone_no + '\n', pin + '\n'])
if save == "y":
with open(CREDENTIALS_FILE, "w") as f:
f.writelines([phone_no + "\n", pin + "\n"])

log.info(f'Saved credentials in {CREDENTIALS_FILE}')
log.info(f"Saved credentials in {CREDENTIALS_FILE}")

else:
save_cookies = False
log.info('Credentials not saved')
log.info("Credentials not saved")

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

if web:
# Use same login as app.traderepublic.com
if tr.resume_websession():
log.info('Web session resumed')
log.info("Web session resumed")
else:
try:
countdown = tr.inititate_weblogin()
except ValueError as e:
log.fatal(str(e))
exit(1)
request_time = time.time()
print('Enter the code you received to your mobile app as a notification.')
print(f'Enter nothing if you want to receive the (same) code as SMS. (Countdown: {countdown})')
code = input('Code: ')
if code == '':
print("Enter the code you received to your mobile app as a notification.")
print(
f"Enter nothing if you want to receive the (same) code as SMS. (Countdown: {countdown})"
)
code = input("Code: ")
if code == "":
countdown = countdown - (time.time() - request_time)
for remaining in range(int(countdown)):
print(f'Need to wait {int(countdown-remaining)} seconds before requesting SMS...', end='\r')
print(
f"Need to wait {int(countdown-remaining)} seconds before requesting SMS...",
end="\r",
)
time.sleep(1)
print()
tr.resend_weblogin()
code = input('SMS requested. Enter the confirmation code:')
code = input("SMS requested. Enter the confirmation code:")
tr.complete_weblogin(code)
else:
# Try to login. Ask for device reset if needed
try:
tr.login()
except (KeyError, AttributeError):
# old keyfile or no keyfile
print('Error logging in. Reset device? (y)')
print("Error logging in. Reset device? (y)")
confirmation = input()
if confirmation == 'y':
if confirmation == "y":
tr.initiate_device_reset()
print('You should have received a SMS with a token. Please type it in:')
print("You should have received a SMS with a token. Please type it in:")
token = input()
tr.complete_device_reset(token)
print('Reset done')
print("Reset done")
else:
print('Cancelling reset')
print("Cancelling reset")
exit(1)

log.info('Logged in')
log.info("Logged in")
# log.debug(get_settings(tr))
return tr
43 changes: 27 additions & 16 deletions pytr/alarms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from pytr.utils import preview, get_logger


class Alarms:
def __init__(self, tr):
self.tr = tr
Expand All @@ -14,11 +15,13 @@ async def alarms_loop(self):
while True:
_subscription_id, subscription, response = await self.tr.recv()

if subscription['type'] == 'priceAlarms':
if subscription["type"] == "priceAlarms":
recv += 1
self.alarms = response
else:
print(f"unmatched subscription of type '{subscription['type']}':\n{preview(response)}")
print(
f"unmatched subscription of type '{subscription['type']}':\n{preview(response)}"
)

if recv == 1:
return
Expand All @@ -29,39 +32,47 @@ async def ticker_loop(self):
while True:
_subscription_id, subscription, response = await self.tr.recv()

if subscription['type'] == 'priceAlarms':
if subscription["type"] == "priceAlarms":
recv += 1
self.alarms = response
else:
print(f"unmatched subscription of type '{subscription['type']}':\n{preview(response)}")
print(
f"unmatched subscription of type '{subscription['type']}':\n{preview(response)}"
)

if recv == 1:
return

def overview(self):
print('ISIN status created target diff% createdAt triggeredAT')
print("ISIN status created target diff% createdAt triggeredAT")
self.log.debug(f"Processing {len(self.alarms)} alarms")

for a in self.alarms: # sorted(positions, key=lambda x: x['netValue'], reverse=True):
for (
a
) in (
self.alarms
): # sorted(positions, key=lambda x: x['netValue'], reverse=True):
self.log.debug(f" Processing {a} alarm")
ts = int(a['createdAt']) / 1000.0
target_price = float(a['targetPrice'])
created_price = float(a['createdPrice'])
created = datetime.fromtimestamp(ts).isoformat(sep=' ', timespec='minutes')
if a['triggeredAt'] is None:
triggered = '-'
ts = int(a["createdAt"]) / 1000.0
target_price = float(a["targetPrice"])
created_price = float(a["createdPrice"])
created = datetime.fromtimestamp(ts).isoformat(sep=" ", timespec="minutes")
if a["triggeredAt"] is None:
triggered = "-"
else:
ts = int(a['triggeredAt']) / 1000.0
triggered = datetime.fromtimestamp(ts).isoformat(sep=' ', timespec='minutes')
ts = int(a["triggeredAt"]) / 1000.0
triggered = datetime.fromtimestamp(ts).isoformat(
sep=" ", timespec="minutes"
)

if a['createdPrice'] == 0:
if a["createdPrice"] == 0:
diffP = 0.0
else:
diffP = (target_price / created_price) * 100 - 100

print(
f"{a['instrumentId']} {a['status']} {created_price:>7.2f} {target_price:>7.2f} "
+ f'{diffP:>5.1f}% {created} {triggered}'
+ f"{diffP:>5.1f}% {created} {triggered}"
)

def get(self):
Expand Down
Loading

0 comments on commit ee1f260

Please sign in to comment.