wbreport 2.2.1__py2.py3-none-any.whl

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.

Potentially problematic release.


This version of wbreport might be problematic. Click here for more details.

Files changed (66) hide show
  1. wbreport/__init__.py +1 -0
  2. wbreport/admin.py +87 -0
  3. wbreport/apps.py +6 -0
  4. wbreport/defaults/__init__.py +0 -0
  5. wbreport/defaults/factsheets/__init__.py +0 -0
  6. wbreport/defaults/factsheets/base.py +990 -0
  7. wbreport/defaults/factsheets/menu.py +93 -0
  8. wbreport/defaults/factsheets/mixins.py +35 -0
  9. wbreport/defaults/factsheets/multitheme.py +947 -0
  10. wbreport/dynamic_preferences_registry.py +15 -0
  11. wbreport/factories/__init__.py +8 -0
  12. wbreport/factories/data_classes.py +48 -0
  13. wbreport/factories/reports.py +79 -0
  14. wbreport/filters.py +37 -0
  15. wbreport/migrations/0001_initial_squashed_squashed_0007_report_key.py +238 -0
  16. wbreport/migrations/0008_alter_report_file_content_type.py +25 -0
  17. wbreport/migrations/0009_alter_report_color_palette.py +27 -0
  18. wbreport/migrations/0010_auto_20240103_0947.py +43 -0
  19. wbreport/migrations/0011_auto_20240207_1629.py +35 -0
  20. wbreport/migrations/0012_reportversion_lock.py +17 -0
  21. wbreport/migrations/0013_alter_reportversion_context.py +18 -0
  22. wbreport/migrations/0014_alter_reportcategory_options_and_more.py +25 -0
  23. wbreport/migrations/__init__.py +0 -0
  24. wbreport/mixins.py +183 -0
  25. wbreport/models.py +781 -0
  26. wbreport/pdf/__init__.py +0 -0
  27. wbreport/pdf/charts/__init__.py +0 -0
  28. wbreport/pdf/charts/legend.py +15 -0
  29. wbreport/pdf/charts/pie.py +169 -0
  30. wbreport/pdf/charts/timeseries.py +77 -0
  31. wbreport/pdf/sandbox/__init__.py +0 -0
  32. wbreport/pdf/sandbox/run.py +17 -0
  33. wbreport/pdf/sandbox/templates/__init__.py +0 -0
  34. wbreport/pdf/sandbox/templates/basic_factsheet.py +908 -0
  35. wbreport/pdf/sandbox/templates/fund_factsheet.py +864 -0
  36. wbreport/pdf/sandbox/templates/long_industry_exposure_factsheet.py +898 -0
  37. wbreport/pdf/sandbox/templates/multistrat_factsheet.py +872 -0
  38. wbreport/pdf/sandbox/templates/testfile.pdf +434 -0
  39. wbreport/pdf/tables/__init__.py +0 -0
  40. wbreport/pdf/tables/aggregated_tables.py +156 -0
  41. wbreport/pdf/tables/data_tables.py +75 -0
  42. wbreport/serializers.py +191 -0
  43. wbreport/tasks.py +60 -0
  44. wbreport/templates/__init__.py +0 -0
  45. wbreport/templatetags/__init__.py +0 -0
  46. wbreport/templatetags/portfolio_tags.py +35 -0
  47. wbreport/tests/__init__.py +0 -0
  48. wbreport/tests/conftest.py +24 -0
  49. wbreport/tests/test_models.py +253 -0
  50. wbreport/tests/test_tasks.py +17 -0
  51. wbreport/tests/test_viewsets.py +0 -0
  52. wbreport/tests/tests.py +12 -0
  53. wbreport/urls.py +29 -0
  54. wbreport/urls_public.py +10 -0
  55. wbreport/viewsets/__init__.py +10 -0
  56. wbreport/viewsets/configs/__init__.py +18 -0
  57. wbreport/viewsets/configs/buttons.py +193 -0
  58. wbreport/viewsets/configs/displays.py +116 -0
  59. wbreport/viewsets/configs/endpoints.py +23 -0
  60. wbreport/viewsets/configs/menus.py +8 -0
  61. wbreport/viewsets/configs/titles.py +30 -0
  62. wbreport/viewsets/viewsets.py +330 -0
  63. wbreport-2.2.1.dist-info/METADATA +6 -0
  64. wbreport-2.2.1.dist-info/RECORD +66 -0
  65. wbreport-2.2.1.dist-info/WHEEL +5 -0
  66. wbreport-2.2.1.dist-info/licenses/LICENSE +4 -0
File without changes
File without changes
@@ -0,0 +1,15 @@
1
+ from reportlab.graphics.charts.legends import Legend
2
+ from reportlab.graphics.shapes import Circle
3
+ from reportlab.lib.colors import transparent
4
+
5
+
6
+ class CustomLegend(Legend):
7
+ def _defaultSwatch(self, x, thisy, dx, dy, fillColor, strokeWidth, strokeColor):
8
+ return Circle(
9
+ x,
10
+ thisy + dx / 2,
11
+ dx / 2,
12
+ fillColor=fillColor,
13
+ strokeColor=transparent,
14
+ strokeWidth=strokeWidth,
15
+ )
@@ -0,0 +1,169 @@
1
+ from reportlab.graphics.charts.piecharts import Pie
2
+ from reportlab.graphics.shapes import Drawing
3
+ from reportlab.lib import colors
4
+ from reportlab.lib.units import cm
5
+ from wbreport.pdf.charts.legend import CustomLegend
6
+
7
+
8
+ def get_data_and_labels_from_df(df, color_palette, percent=True):
9
+ data = list()
10
+ colornamepairs = list()
11
+
12
+ for index, row in enumerate(df.itertuples()):
13
+ data.append(float(row.weighting))
14
+
15
+ label = f"{row[2]*100:.1f}%" if percent else f"{row[2]:.1f}"
16
+ colornamepairs.append((colors.HexColor(color_palette[index]), f"{row[1]} {label}"))
17
+
18
+ return data, colornamepairs
19
+
20
+
21
+ def get_legend_height(df, r2_legend=0.3 * cm, legend_padding=1, legend_max_cols=7):
22
+ return min(len(df), legend_max_cols) * (r2_legend + legend_padding)
23
+
24
+
25
+ def get_pie_chart_vertical_height(
26
+ df,
27
+ r2=2.5 * cm,
28
+ padding=0.45 * cm,
29
+ r2_legend=0.3 * cm,
30
+ legend_padding=1,
31
+ legend_max_cols=7,
32
+ ):
33
+ return 3 * padding + r2 + get_legend_height(df, r2_legend, legend_padding, legend_max_cols)
34
+
35
+
36
+ def get_pie_chart_vertical(
37
+ df,
38
+ width,
39
+ height,
40
+ color_palette,
41
+ r2=2.5 * cm,
42
+ padding=0.45 * cm,
43
+ r2_legend=0.3 * cm,
44
+ legend_padding=1,
45
+ legend_max_cols=7,
46
+ ):
47
+ drawing = Drawing(width, height)
48
+ pie = Pie()
49
+
50
+ pie.width = r2
51
+ pie.height = r2
52
+
53
+ pie.x = (width - r2) / 2
54
+ pie.y = height - r2 - padding
55
+ df = df.sort_values(by=["weighting"], ascending=False)
56
+ data, colornamepairs = get_data_and_labels_from_df(df, color_palette)
57
+
58
+ for i, color in enumerate(colornamepairs):
59
+ pie.slices[i].fillColor = color[0]
60
+ pie.slices[i].strokeColor = colors.transparent
61
+ pie.slices[i].strokeWidth = 0 # Border width for wedge
62
+ pie.slices.strokeWidth = 0 # Width of the border around the pie chart.
63
+ pie.data = data
64
+
65
+ drawing.add(pie)
66
+
67
+ legend = CustomLegend()
68
+
69
+ legend.alignment = "right"
70
+ legend.boxAnchor = "nw"
71
+ legend.x = 0
72
+ legend.y = height - r2 - 2 * padding
73
+ legend.dx = legend.dy = r2_legend
74
+ legend.strokeWidth = -1
75
+ legend.columnMaximum = legend_max_cols
76
+ legend.colorNamePairs = colornamepairs
77
+ legend.fontName = "customfont"
78
+ legend.fontSize = 6
79
+
80
+ legend.deltax = 0 # Here
81
+ legend.deltay = legend_padding
82
+ legend.swdx = 12
83
+ legend.swdy = 0
84
+
85
+ legend.dxTextSpace = r2_legend
86
+
87
+ legend.variColumn = True
88
+
89
+ drawing.add(legend)
90
+ return drawing
91
+
92
+
93
+ def get_pie_chart_horizontal_height(
94
+ df,
95
+ r2=2.5 * cm,
96
+ padding=0.45 * cm,
97
+ r2_legend=0.3 * cm,
98
+ legend_padding=1,
99
+ legend_max_cols=7,
100
+ ):
101
+ return max(
102
+ 2 * padding + r2,
103
+ 2 * padding + get_legend_height(df, r2_legend, legend_padding, legend_max_cols),
104
+ )
105
+
106
+
107
+ def get_pie_chart_horizontal(
108
+ df,
109
+ width,
110
+ height,
111
+ color_palette,
112
+ col_width,
113
+ r2=2.5 * cm,
114
+ padding=0.45 * cm,
115
+ r2_legend=0.3 * cm,
116
+ legend_padding=1,
117
+ legend_max_cols=7,
118
+ legend_x=None,
119
+ ):
120
+ drawing = Drawing(width, height)
121
+ pie = Pie()
122
+
123
+ pie.width = r2
124
+ pie.height = r2
125
+
126
+ pie.x = (col_width - r2) / 2
127
+ pie.y = height - r2 - padding
128
+ df = df.sort_values(by=["weighting"], ascending=False)
129
+ data, colornamepairs = get_data_and_labels_from_df(df, color_palette)
130
+
131
+ for i, color in enumerate(colornamepairs):
132
+ pie.slices[i].fillColor = color[0]
133
+ pie.slices[i].strokeColor = colors.transparent
134
+ pie.slices[i].strokeWidth = 0 # Border width for wedge.
135
+ pie.slices.strokeWidth = 0 # Width of the border around the pie chart.
136
+ pie.data = data
137
+
138
+ drawing.add(pie)
139
+
140
+ legend = CustomLegend()
141
+
142
+ # legend.x = 4.82 * cm
143
+ # legend.y += 0.78 * cm
144
+
145
+ legend_height = get_legend_height(df, r2_legend, legend_padding, legend_max_cols)
146
+
147
+ legend.alignment = "right"
148
+ legend.boxAnchor = "nw"
149
+
150
+ if legend_x:
151
+ legend.x = legend_x
152
+ else:
153
+ legend.x = width - col_width
154
+
155
+ legend.y = (height + legend_height) / 2
156
+ legend.dx = legend.dy = r2_legend
157
+ legend.strokeWidth = -1
158
+ legend.columnMaximum = legend_max_cols
159
+ legend.colorNamePairs = colornamepairs
160
+ legend.fontName = "customfont"
161
+ legend.fontSize = 6
162
+
163
+ legend.deltax = 0
164
+ legend.deltay = legend_padding
165
+ legend.swdx = 12
166
+ legend.swdy = 0
167
+
168
+ drawing.add(legend)
169
+ return drawing
@@ -0,0 +1,77 @@
1
+ from enum import Enum
2
+
3
+ from reportlab.graphics.charts.axes import LogYValueAxis, NormalDateXValueAxis
4
+ from reportlab.graphics.charts.lineplots import LinePlot, SimpleTimeSeriesPlot
5
+ from reportlab.graphics.shapes import Drawing
6
+ from reportlab.lib import colors
7
+ from reportlab.lib.units import cm
8
+
9
+
10
+ class Scale(Enum):
11
+ ARITHMETIC = 1
12
+ LOGARITHMIC = 2
13
+
14
+
15
+ class LogScaleTimeSeriesPlot(LinePlot):
16
+ def __init__(self):
17
+ super().__init__()
18
+
19
+ class CustomYAxis(LogYValueAxis):
20
+ def _calcTickPositions(self):
21
+ return self._calcStepAndTickPositions()[1]
22
+
23
+ self.xValueAxis = NormalDateXValueAxis()
24
+ self.yValueAxis = CustomYAxis()
25
+
26
+
27
+ def get_timeseries_chart(
28
+ data, width, height, color, fill_color, grid_color, scale, x_label_format="{mm}/{yy}", **chart_attributes
29
+ ):
30
+ width -= 0.65 * cm
31
+ chart_map = {
32
+ Scale.ARITHMETIC.value: SimpleTimeSeriesPlot,
33
+ Scale.LOGARITHMIC.value: LogScaleTimeSeriesPlot,
34
+ }
35
+ data = [list(filter(lambda x: x[1] > 0, data[0]))]
36
+ max_x_ticks = 20
37
+
38
+ # ensure that if the data count is too low (e.g. less than a month range), we don't overcrowds the X axis
39
+ if len(data[0]) < max_x_ticks:
40
+ x_label_format = "{dd}/{mm}/{yy}"
41
+ max_x_ticks = 10
42
+
43
+ drawing = Drawing(width, height)
44
+
45
+ chart = chart_map[scale]()
46
+ chart.width = width
47
+ chart.height = height
48
+
49
+ for key, value in chart_attributes.items():
50
+ setattr(chart, key, value)
51
+
52
+ chart.data = data
53
+
54
+ chart.lines[0].strokeWidth = 0.5
55
+ chart.lines[0].strokeColor = color
56
+ chart.lines[0].fillColor = fill_color
57
+ chart.lines[0].inFill = True
58
+
59
+ chart.yValueAxis.strokeWidth = -1
60
+ chart.yValueAxis.strokeColor = colors.white
61
+ chart.yValueAxis.labels.fontSize = 7
62
+ chart.yValueAxis.labels.fontName = "customfont"
63
+ chart.yValueAxis.labels.dx = width + 0.55 * cm
64
+ chart.yValueAxis.maximumTicks = 100
65
+ chart.yValueAxis.labelTextFormat = "%d"
66
+
67
+ chart.xValueAxis.strokeWidth = 0
68
+ chart.xValueAxis.labels.fontSize = 7
69
+ chart.xValueAxis.labels.fontName = "customfont"
70
+ chart.xValueAxis.maximumTicks = max_x_ticks
71
+ chart.xValueAxis.visibleGrid = 1
72
+ chart.xValueAxis.gridStrokeDashArray = (0.2, 0, 0.2)
73
+ chart.xValueAxis.gridStrokeColor = grid_color
74
+ chart.xValueAxis.xLabelFormat = x_label_format
75
+
76
+ drawing.add(chart)
77
+ return drawing
File without changes
@@ -0,0 +1,17 @@
1
+ import importlib
2
+ import sys
3
+ from datetime import datetime
4
+
5
+ from wbportfolio.models import Product
6
+
7
+ report = sys.argv[1]
8
+
9
+ module = importlib.import_module("wbreport.pdf.sandbox.templates.{report}")
10
+ product = Product.objects.get(id=sys.argv[2])
11
+
12
+ start = datetime.strptime(sys.argv[3], "%Y-%m-%d").date()
13
+ end = datetime.strptime(sys.argv[4], "%Y-%m-%d").date()
14
+ context = product.report._get_file_context(start=start, end=end)
15
+ result = module.generate_report(context)
16
+ with open("portfolio/report/pdf/sandbox/templates/testfile.pdf", "wb") as test_file:
17
+ test_file.write(result.read())
File without changes