polyhattrick 0.2.0__tar.gz → 0.2.1__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.
Files changed (22) hide show
  1. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/PKG-INFO +1 -8
  2. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/README.md +0 -7
  3. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/pyproject.toml +1 -1
  4. polyhattrick-0.2.1/src/polyhattrick/__init__.py +1 -0
  5. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/api/client.py +4 -4
  6. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/interactive/application.py +13 -2
  7. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/polyhattrick.py +0 -1
  8. polyhattrick-0.2.1/src/polyhattrick/tips.py +65 -0
  9. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/views.py +36 -1
  10. polyhattrick-0.2.0/src/polyhattrick/__init__.py +0 -1
  11. polyhattrick-0.2.0/src/polyhattrick/tips.py +0 -37
  12. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/LICENSE +0 -0
  13. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/api/__init__.py +0 -0
  14. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/commands/__init__.py +0 -0
  15. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/commands/common.py +0 -0
  16. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/commands/data.py +0 -0
  17. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/commands/live.py +0 -0
  18. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/commands/login.py +0 -0
  19. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/commands/support.py +0 -0
  20. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/interactive/__init__.py +0 -0
  21. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/output.py +0 -0
  22. {polyhattrick-0.2.0 → polyhattrick-0.2.1}/src/polyhattrick/settings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polyhattrick
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Live Hattrick scores in your terminal and polybar
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -159,17 +159,10 @@ Optional, in `~/.config/polyhattrick/configuration.toml`:
159
159
 
160
160
  ```toml
161
161
  server = "https://api.polyhattrick.sesamemonster.de" # the polyhattrick server to use
162
- tips = false # never show the support reminder
163
162
  ```
164
163
 
165
164
  `POLYHATTRICK_SERVER` overrides `server` for a single run.
166
165
 
167
- ## Support
168
-
169
- polyhattrick is free. `polyhattrick support` tells you how to support it.
170
- Now and then, after a command, one line reminds you of that; it never shows
171
- in scripts, and `tips = false` turns it off.
172
-
173
166
  ## Notes
174
167
 
175
168
  - Made for Linux.
@@ -88,17 +88,10 @@ Optional, in `~/.config/polyhattrick/configuration.toml`:
88
88
 
89
89
  ```toml
90
90
  server = "https://api.polyhattrick.sesamemonster.de" # the polyhattrick server to use
91
- tips = false # never show the support reminder
92
91
  ```
93
92
 
94
93
  `POLYHATTRICK_SERVER` overrides `server` for a single run.
95
94
 
96
- ## Support
97
-
98
- polyhattrick is free. `polyhattrick support` tells you how to support it.
99
- Now and then, after a command, one line reminds you of that; it never shows
100
- in scripts, and `tips = false` turns it off.
101
-
102
95
  ## Notes
103
96
 
104
97
  - Made for Linux.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "polyhattrick"
3
- version = "0.2.0"
3
+ version = "0.2.1"
4
4
  description = "Live Hattrick scores in your terminal and polybar"
5
5
  authors = [
6
6
  {name = "Peter Toth",email = "work@petertoth.de"}
@@ -0,0 +1 @@
1
+ __version__ = "0.2.1"
@@ -60,8 +60,8 @@ class Client:
60
60
 
61
61
  # Data
62
62
 
63
- def about(self):
64
- return self._request("GET", "/v1/about", authenticated=False)
63
+ def about(self, timeout=TIMEOUT_SECONDS):
64
+ return self._request("GET", "/v1/about", authenticated=False, timeout=timeout)
65
65
 
66
66
  def my_teams(self):
67
67
  return self._request("GET", "/v1/me/teams")
@@ -102,13 +102,13 @@ class Client:
102
102
  headers["Authorization"] = f"Bearer {self.secret}"
103
103
  return headers
104
104
 
105
- def _send(self, method, path, headers, **arguments):
105
+ def _send(self, method, path, headers, timeout=TIMEOUT_SECONDS, **arguments):
106
106
  try:
107
107
  return requests.request(
108
108
  method,
109
109
  f"{self.server}{path}",
110
110
  headers=headers,
111
- timeout=TIMEOUT_SECONDS,
111
+ timeout=timeout,
112
112
  **arguments,
113
113
  )
114
114
  except requests.RequestException as error:
@@ -80,6 +80,7 @@ class PolyhattrickApplication(App):
80
80
  Binding("r", "refresh", "Refresh"),
81
81
  Binding("t", "switch_team", "Next team"),
82
82
  Binding("q", "quit", "Quit"),
83
+ Binding("escape", "focus_sections", "Sections", show=False),
83
84
  ]
84
85
 
85
86
  def __init__(self, client=None):
@@ -131,11 +132,21 @@ class PolyhattrickApplication(App):
131
132
  view.display = True
132
133
  view.update(f"[red]{error.message}[/red]")
133
134
 
134
- @on(OptionList.OptionSelected, "#sections")
135
135
  @on(OptionList.OptionHighlighted, "#sections")
136
- def _section_chosen(self, event):
136
+ def _section_highlighted(self, event):
137
+ if event.option.id != self.section:
138
+ self.show_section(event.option.id)
139
+
140
+ @on(OptionList.OptionSelected, "#sections")
141
+ def _section_entered(self, event):
142
+ """Enter moves the cursor into the section, so arrows and Enter act there."""
137
143
  if event.option.id != self.section:
138
144
  self.show_section(event.option.id)
145
+ target = "#squad" if event.option.id == "squad" else "#content"
146
+ self.query_one(target).focus()
147
+
148
+ def action_focus_sections(self):
149
+ self.query_one("#sections", OptionList).focus()
139
150
 
140
151
  def show_section(self, section):
141
152
  self.section = section
@@ -21,7 +21,6 @@ application.command("support")(support.support)
21
21
  def _version(value: bool):
22
22
  if value:
23
23
  print(f"polyhattrick {__version__}")
24
- print("Support the project: polyhattrick support")
25
24
  raise typer.Exit()
26
25
 
27
26
 
@@ -0,0 +1,65 @@
1
+ """The occasional line asking for support.
2
+
3
+ Never in the first `INTERVAL_DAYS` after the first use, then at most once
4
+ every `INTERVAL_DAYS`, after a command succeeded, and only to a person:
5
+ never with `--json`, never when stderr is not a terminal (pipes, scripts,
6
+ polybar). `tips = false` in the configuration file turns it off for good.
7
+
8
+ It only appears when the server announces a funding link: a reminder with
9
+ nowhere to send support is just noise. The server is asked only when a
10
+ reminder is due, and at most once a day while it has no link.
11
+ """
12
+
13
+ import sys
14
+ from datetime import date, timedelta
15
+
16
+ from polyhattrick import output, settings
17
+ from polyhattrick.api.client import ApiError, Client
18
+
19
+ INTERVAL_DAYS = 14
20
+ ABOUT_TIMEOUT_SECONDS = 3
21
+ LINE = (
22
+ "Enjoying polyhattrick? See `polyhattrick support` for how to help keep it running."
23
+ )
24
+
25
+
26
+ def _day(state, key):
27
+ value = state.get(key)
28
+ return date.fromisoformat(value) if value else None
29
+
30
+
31
+ def due(state, today):
32
+ """Whether `INTERVAL_DAYS` have passed since the first use and the last reminder."""
33
+ starts = [
34
+ day for day in (_day(state, "first_used"), _day(state, "tip_shown")) if day
35
+ ]
36
+ return bool(starts) and max(starts) + timedelta(days=INTERVAL_DAYS) <= today
37
+
38
+
39
+ def _funding_url():
40
+ try:
41
+ return Client().about(timeout=ABOUT_TIMEOUT_SECONDS).get("funding_url")
42
+ except ApiError:
43
+ return None
44
+
45
+
46
+ def maybe_show(as_json, today=None):
47
+ if as_json or not sys.stderr.isatty() or not settings.configuration().tips:
48
+ return
49
+
50
+ today = today or date.today()
51
+ state = settings.read_state()
52
+ if "first_used" not in state:
53
+ state["first_used"] = today.isoformat()
54
+ settings.write_state(state)
55
+ return
56
+
57
+ if not due(state, today) or _day(state, "funding_checked") == today:
58
+ return
59
+
60
+ if _funding_url():
61
+ output.error_output.print(f"\n[dim]{LINE}[/dim]", highlight=False)
62
+ state["tip_shown"] = today.isoformat()
63
+ else:
64
+ state["funding_checked"] = today.isoformat()
65
+ settings.write_state(state)
@@ -309,6 +309,41 @@ def club(club):
309
309
  )
310
310
 
311
311
 
312
+ # Short labels for the server's match types; `--json` keeps the server's values.
313
+ MATCH_TYPE_LABELS = {
314
+ "league": "League",
315
+ "qualification": "Qualification",
316
+ "cup": "Cup",
317
+ "friendly": "Friendly",
318
+ "friendly_cup_rules": "Friendly (cup)",
319
+ "international_friendly": "Friendly (int)",
320
+ "international_friendly_cup_rules": "Friendly (int) (cup)",
321
+ "hattrick_masters": "Masters",
322
+ "national_teams_competition": "National team",
323
+ "national_teams_competition_cup_rules": "National team (cup)",
324
+ "national_teams_friendly": "National team friendly",
325
+ "tournament_league": "Tournament",
326
+ "tournament_playoff": "Tournament (playoff)",
327
+ "duel": "Duel",
328
+ "ladder": "Ladder",
329
+ "preparation": "Preparation",
330
+ "youth_league": "Youth league",
331
+ "youth_friendly": "Youth friendly",
332
+ "youth_friendly_cup_rules": "Youth friendly (cup)",
333
+ "youth_international_friendly": "Youth friendly (int)",
334
+ "youth_international_friendly_cup_rules": "Youth friendly (int) (cup)",
335
+ }
336
+
337
+
338
+ def match_type(value):
339
+ """`international_friendly` → `Friendly (int)`; `unknown_63` → `Other (63)`."""
340
+ if value is None:
341
+ return "-"
342
+ if value.startswith("unknown_"):
343
+ return f"Other ({value.removeprefix('unknown_')})"
344
+ return MATCH_TYPE_LABELS.get(value, words(value))
345
+
346
+
312
347
  def matches(matches):
313
348
  table = Table(title="Matches")
314
349
  table.add_column("Date")
@@ -324,7 +359,7 @@ def matches(matches):
324
359
  )
325
360
  table.add_row(
326
361
  date(match["date"]),
327
- words(match["match_type"]),
362
+ match_type(match["match_type"]),
328
363
  match["home_team"] and match["home_team"]["name"],
329
364
  score,
330
365
  match["away_team"] and match["away_team"]["name"],
@@ -1 +0,0 @@
1
- __version__ = "0.2.0"
@@ -1,37 +0,0 @@
1
- """The occasional line asking for support.
2
-
3
- Shown at most once every `INTERVAL_DAYS`, after a command succeeded, and
4
- only to a person: never with `--json`, never when stderr is not a terminal
5
- (pipes, scripts, polybar). `tips = false` in the configuration file turns
6
- it off for good.
7
- """
8
-
9
- import sys
10
- from datetime import date, timedelta
11
-
12
- from polyhattrick import output, settings
13
-
14
- INTERVAL_DAYS = 30
15
- LINE = (
16
- "Enjoying polyhattrick? See `polyhattrick support` for how to help keep it running."
17
- )
18
-
19
-
20
- def due(today=None):
21
- today = today or date.today()
22
- last = settings.read_state().get("tip_shown")
23
- return (
24
- last is None
25
- or date.fromisoformat(last) + timedelta(days=INTERVAL_DAYS) <= today
26
- )
27
-
28
-
29
- def maybe_show(as_json, today=None):
30
- if as_json or not sys.stderr.isatty() or not settings.configuration().tips:
31
- return
32
- if not due(today):
33
- return
34
- output.error_output.print(f"\n[dim]{LINE}[/dim]", highlight=False)
35
- state = settings.read_state()
36
- state["tip_shown"] = (today or date.today()).isoformat()
37
- settings.write_state(state)
File without changes