zeed-movs-viewer 0.0.1__tar.gz → 0.0.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zeed-movs-viewer
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  License: GNU AFFERO GENERAL PUBLIC LICENSE
5
5
  Version 3, 19 November 2007
6
6
 
@@ -6,7 +6,7 @@ requires = [
6
6
 
7
7
  [project]
8
8
  name = "zeed-movs-viewer"
9
- version = "0.0.1"
9
+ version = "0.0.2"
10
10
  requires-python = ">=3.12,<3.14"
11
11
  classifiers = [
12
12
  "Programming Language :: Python :: 3 :: Only",
@@ -79,6 +79,7 @@ composite = [
79
79
  "pdm bump patch --commit --tag",
80
80
  "pdm publish",
81
81
  "git push",
82
+ "git push --tags",
82
83
  ]
83
84
 
84
85
  [tool.ruff]
@@ -37,13 +37,13 @@ logger = getLogger(__name__)
37
37
 
38
38
 
39
39
  def get_options(dtemp: str) -> Options:
40
- options = Options()
41
-
42
- options.profile = FirefoxProfile()
40
+ profile = FirefoxProfile()
43
41
  # set download folder
44
- options.profile.set_preference('browser.download.folderList', 2)
45
- options.profile.set_preference('browser.download.dir', dtemp)
42
+ profile.set_preference('browser.download.folderList', 2)
43
+ profile.set_preference('browser.download.dir', dtemp)
46
44
 
45
+ options = Options()
46
+ options.profile = profile
47
47
  return options
48
48
 
49
49
 
@@ -231,7 +231,7 @@ class Chart(QChart):
231
231
  self.scroll(x_prev - x_curr, y_curr - y_prev)
232
232
 
233
233
 
234
- MONEY_HEADER = ColumnHeader('money')
234
+ MONEY_HEADER = ColumnHeader('money', '€')
235
235
 
236
236
 
237
237
  @dataclass
@@ -8,7 +8,6 @@ from guilib.chartwidget.viewmodel import (
8
8
  SortFilterViewModel as SortFilterViewModel2,
9
9
  )
10
10
  from guilib.multitabs.widget import MultiTabs
11
- from guilib.qwtplot.plot import Plot
12
11
  from guilib.searchsheet.widget import SearchSheet
13
12
  from PySide6.QtCore import QCoreApplication
14
13
  from PySide6.QtCore import QItemSelection
@@ -30,6 +29,7 @@ from PySide6.QtWidgets import QWidget
30
29
 
31
30
  from movsviewer.constants import MAINUI_UI_PATH
32
31
  from movsviewer.constants import SETTINGSUI_UI_PATH
32
+ from movsviewer.plotutils import PlotAndSliderWidget
33
33
  from movsviewer.plotutils import load_infos
34
34
  from movsviewer.settings import Settings
35
35
  from movsviewer.validator import Validator
@@ -142,7 +142,7 @@ class NewMainui:
142
142
  for data_path in data_paths:
143
143
  sheet, model = self.new_search_sheet(data_path)
144
144
  model2 = SortFilterViewModel2()
145
- plot = Plot(model2, None)
145
+ plot = PlotAndSliderWidget(model2, None)
146
146
  model2.update(load_infos((data_path, 'money')))
147
147
  idx = self.multi_tabs.add_double_box(sheet, plot, model.name)
148
148
  self.sheets_charts[data_path] = (sheet, model2, idx)
@@ -0,0 +1,90 @@
1
+ from collections import defaultdict
2
+ from datetime import date
3
+ from datetime import timedelta
4
+ from itertools import accumulate
5
+ from operator import attrgetter
6
+ from typing import TYPE_CHECKING
7
+
8
+ from guilib.chartslider.chartslider import ChartSlider
9
+ from guilib.chartwidget.model import Column
10
+ from guilib.chartwidget.model import ColumnHeader
11
+ from guilib.chartwidget.model import ColumnProto
12
+ from guilib.chartwidget.model import Info
13
+ from guilib.chartwidget.model import InfoProto
14
+ from guilib.qwtplot.plot import Plot
15
+ from movslib.reader import read
16
+ from PySide6.QtWidgets import QVBoxLayout
17
+ from PySide6.QtWidgets import QWidget
18
+
19
+ if TYPE_CHECKING:
20
+ from collections.abc import Iterable
21
+ from decimal import Decimal
22
+
23
+ from guilib.chartwidget.viewmodel import SortFilterViewModel
24
+ from movslib.model import Row
25
+ from movslib.model import Rows
26
+
27
+
28
+ def _acc_reset_by_year(rows: 'Rows') -> 'Iterable[tuple[date, Decimal]]':
29
+ def func(a: tuple[date, 'Decimal'], b: 'Row') -> tuple[date, 'Decimal']:
30
+ if b.date.year != a[0].year:
31
+ return b.date, b.money
32
+
33
+ return b.date, a[1] + b.money
34
+
35
+ it = iter(sorted(rows, key=attrgetter('date')))
36
+ head = next(it)
37
+ return accumulate(it, func, initial=(head.date, head.money))
38
+
39
+
40
+ def _acc(rows: 'Rows') -> 'Iterable[tuple[date, Decimal]]':
41
+ def func(a: tuple[date, 'Decimal'], b: 'Row') -> tuple[date, 'Decimal']:
42
+ return b.date, a[1] + b.money
43
+
44
+ it = iter(sorted(rows, key=attrgetter('date')))
45
+ head = next(it)
46
+ return accumulate(it, func, initial=(head.date, head.money))
47
+
48
+
49
+ def load_infos(*fn_names: tuple[str, str]) -> list[InfoProto]:
50
+ tmp = defaultdict[date, list[ColumnProto]](list)
51
+ for fn, name in fn_names:
52
+ _, rows = read(fn, name)
53
+
54
+ ch = ColumnHeader(rows.name, '€')
55
+ for d, m in _acc(rows):
56
+ tmp[d].append(Column(ch, m))
57
+
58
+ ch_year = ColumnHeader(f'{rows.name} (by year)', '€')
59
+ for d, m in _acc_reset_by_year(rows):
60
+ tmp[d].append(Column(ch_year, m))
61
+
62
+ sorted_days = sorted(tmp)
63
+
64
+ # add +/- 1 months of padding
65
+ ret: list[InfoProto] = []
66
+ ret.append(Info(sorted_days[0] - timedelta(days=30), []))
67
+ ret.extend(Info(d, tmp[d]) for d in sorted_days)
68
+ ret.append(Info(sorted_days[-1] + timedelta(days=30), []))
69
+
70
+ return ret
71
+
72
+
73
+ class PlotAndSliderWidget(QWidget):
74
+ """Composition of a Plot and a (Chart)Slider."""
75
+
76
+ def __init__(
77
+ self, model: 'SortFilterViewModel', parent: QWidget | None
78
+ ) -> None:
79
+ super().__init__(parent)
80
+
81
+ plot = Plot(model, self)
82
+ chart_slider = ChartSlider(model, self, dates_column=0)
83
+
84
+ layout = QVBoxLayout(self)
85
+ layout.addWidget(plot)
86
+ layout.addWidget(chart_slider)
87
+ self.setLayout(layout)
88
+
89
+ chart_slider.start_date_changed.connect(plot.start_date_changed)
90
+ chart_slider.end_date_changed.connect(plot.end_date_changed)
@@ -1,38 +0,0 @@
1
- from collections import defaultdict
2
- from datetime import date
3
- from itertools import accumulate
4
- from operator import attrgetter
5
- from typing import TYPE_CHECKING
6
-
7
- from guilib.chartwidget.model import Column
8
- from guilib.chartwidget.model import ColumnHeader
9
- from guilib.chartwidget.model import ColumnProto
10
- from guilib.chartwidget.model import Info
11
- from guilib.chartwidget.model import InfoProto
12
- from movslib.movs import read_txt
13
-
14
- if TYPE_CHECKING:
15
- from collections.abc import Iterable
16
- from decimal import Decimal
17
-
18
- from movslib.model import Row
19
- from movslib.model import Rows
20
-
21
-
22
- def _acc(rows: 'Rows') -> 'Iterable[tuple[date, Decimal]]':
23
- def func(a: 'tuple[date, Decimal]', b: 'Row') -> 'tuple[date, Decimal]':
24
- return (b.date, a[1] + b.money)
25
-
26
- it = iter(sorted(rows, key=attrgetter('date')))
27
- head = next(it)
28
- return accumulate(it, func, initial=(head.date, head.money))
29
-
30
-
31
- def load_infos(*fn_names: tuple[str, str]) -> list[InfoProto]:
32
- tmp = defaultdict[date, list[ColumnProto]](list)
33
- for fn, name in fn_names:
34
- _, rows = read_txt(fn, name)
35
- ch = ColumnHeader(rows.name)
36
- for d, m in _acc(rows):
37
- tmp[d].append(Column(ch, m))
38
- return [Info(d, tmp[d]) for d in sorted(tmp)]