squirrels 0.5.0b2__tar.gz → 0.5.0b3__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 (85) hide show
  1. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/PKG-INFO +1 -1
  2. squirrels-0.5.0b3/dateutils/__init__.py +6 -0
  3. squirrels-0.5.0b3/dateutils/_enums.py +25 -0
  4. squirrels-0.5.0b2/dateutils/__init__.py → squirrels-0.5.0b3/dateutils/_implementation.py +56 -107
  5. squirrels-0.5.0b3/dateutils/types.py +6 -0
  6. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/pyproject.toml +1 -1
  7. squirrels-0.5.0b3/squirrels/__init__.py +17 -0
  8. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_api_server.py +5 -5
  9. squirrels-0.5.0b2/squirrels/arguments/init_time_args.py → squirrels-0.5.0b3/squirrels/_arguments/_init_time_args.py +2 -2
  10. squirrels-0.5.0b2/squirrels/arguments/run_time_args.py → squirrels-0.5.0b3/squirrels/_arguments/_run_time_args.py +4 -26
  11. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_auth.py +2 -2
  12. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_connection_set.py +5 -5
  13. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_constants.py +1 -1
  14. squirrels-0.5.0b2/squirrels/dashboards.py → squirrels-0.5.0b3/squirrels/_dashboard_types.py +12 -12
  15. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_dashboards_io.py +2 -2
  16. squirrels-0.5.0b2/squirrels/data_sources.py → squirrels-0.5.0b3/squirrels/_data_sources.py +56 -55
  17. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_exceptions.py +1 -1
  18. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_initializer.py +31 -26
  19. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_manifest.py +5 -5
  20. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_model_configs.py +2 -2
  21. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_model_queries.py +1 -1
  22. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_models.py +28 -16
  23. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/dashboards/dashboard_example.py +4 -4
  24. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/dashboards/dashboard_example.yml +2 -2
  25. squirrels-0.5.0b3/squirrels/_package_data/base_project/macros/macros_example.sql +17 -0
  26. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/models/builds/build_example.py +2 -2
  27. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/models/builds/build_example.sql +1 -1
  28. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/models/dbviews/dbview_example.sql +1 -1
  29. squirrels-0.5.0b3/squirrels/_package_data/base_project/models/federates/federate_example.py +41 -0
  30. squirrels-0.5.0b3/squirrels/_package_data/base_project/models/federates/federate_example.sql +25 -0
  31. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/models/federates/federate_example.yml +6 -6
  32. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/parameters.yml +9 -8
  33. squirrels-0.5.0b3/squirrels/_package_data/base_project/pyconfigs/connections.py +14 -0
  34. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/pyconfigs/context.py +14 -16
  35. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/pyconfigs/parameters.py +13 -8
  36. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/pyconfigs/user.py +2 -2
  37. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_parameter_configs.py +34 -34
  38. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_parameter_sets.py +18 -18
  39. squirrels-0.5.0b2/squirrels/parameters.py → squirrels-0.5.0b3/squirrels/_parameters.py +54 -54
  40. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_project.py +37 -12
  41. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_utils.py +4 -2
  42. squirrels-0.5.0b3/squirrels/arguments.py +2 -0
  43. squirrels-0.5.0b3/squirrels/connections.py +1 -0
  44. squirrels-0.5.0b3/squirrels/dashboards.py +1 -0
  45. squirrels-0.5.0b3/squirrels/data_sources.py +8 -0
  46. squirrels-0.5.0b3/squirrels/parameter_options.py +8 -0
  47. squirrels-0.5.0b3/squirrels/parameters.py +9 -0
  48. squirrels-0.5.0b3/squirrels/types.py +11 -0
  49. squirrels-0.5.0b2/squirrels/__init__.py +0 -23
  50. squirrels-0.5.0b2/squirrels/package_data/base_project/macros/macros_example.sql +0 -15
  51. squirrels-0.5.0b2/squirrels/package_data/base_project/models/federates/federate_example.py +0 -44
  52. squirrels-0.5.0b2/squirrels/package_data/base_project/models/federates/federate_example.sql +0 -17
  53. squirrels-0.5.0b2/squirrels/package_data/base_project/pyconfigs/connections.py +0 -14
  54. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/.gitignore +0 -0
  55. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/LICENSE +0 -0
  56. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/README.md +0 -0
  57. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_api_response_models.py +0 -0
  58. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_command_line.py +0 -0
  59. /squirrels-0.5.0b2/squirrels/dataset_result.py → /squirrels-0.5.0b3/squirrels/_dataset_types.py +0 -0
  60. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_model_builder.py +0 -0
  61. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/.env +0 -0
  62. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/.env.example +0 -0
  63. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/assets/expenses.db +0 -0
  64. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/assets/weather.db +0 -0
  65. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/connections.yml +0 -0
  66. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/docker/.dockerignore +0 -0
  67. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/docker/Dockerfile +0 -0
  68. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/docker/compose.yml +0 -0
  69. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/duckdb_init.sql +0 -0
  70. /squirrels-0.5.0b2/squirrels/package_data/base_project/.gitignore → /squirrels-0.5.0b3/squirrels/_package_data/base_project/gitignore +0 -0
  71. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/models/builds/build_example.yml +0 -0
  72. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/models/dbviews/dbview_example.yml +0 -0
  73. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/models/sources.yml +0 -0
  74. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/seeds/seed_categories.csv +0 -0
  75. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/seeds/seed_categories.yml +0 -0
  76. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/seeds/seed_subcategories.csv +0 -0
  77. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/seeds/seed_subcategories.yml +0 -0
  78. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/squirrels.yml.j2 +0 -0
  79. {squirrels-0.5.0b2/squirrels/package_data → squirrels-0.5.0b3/squirrels/_package_data}/base_project/tmp/.gitignore +0 -0
  80. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_package_loader.py +0 -0
  81. /squirrels-0.5.0b2/squirrels/parameter_options.py → /squirrels-0.5.0b3/squirrels/_parameter_options.py +0 -0
  82. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_py_module.py +0 -0
  83. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_seeds.py +0 -0
  84. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_sources.py +0 -0
  85. {squirrels-0.5.0b2 → squirrels-0.5.0b3}/squirrels/_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: squirrels
3
- Version: 0.5.0b2
3
+ Version: 0.5.0b3
4
4
  Summary: Squirrels - API Framework for Data Analytics
5
5
  Project-URL: Homepage, https://squirrels-analytics.github.io
6
6
  Project-URL: Repository, https://github.com/squirrels-analytics/squirrels
@@ -0,0 +1,6 @@
1
+ from ._enums import DayOfWeekEnum, MonthEnum
2
+ from ._implementation import (
3
+ DayIdxOfMonthsCycle, DayIdxOfYear, DayIdxOfQuarter, DayIdxOfMonth, DayIdxOfWeek,
4
+ OffsetYears, OffsetMonths, OffsetWeeks, OffsetDays,
5
+ DateModPipeline, DateStringModifier, TimestampModifier
6
+ )
@@ -0,0 +1,25 @@
1
+ from enum import Enum
2
+
3
+
4
+ class DayOfWeekEnum(Enum):
5
+ Sunday = 0
6
+ Monday = 1
7
+ Tuesday = 2
8
+ Wednesday = 3
9
+ Thursday = 4
10
+ Friday = 5
11
+ Saturday = 6
12
+
13
+ class MonthEnum(Enum):
14
+ January = 1
15
+ February = 2
16
+ March = 3
17
+ April = 4
18
+ May = 5
19
+ June = 6
20
+ July = 7
21
+ August = 8
22
+ September = 9
23
+ October = 10
24
+ November = 11
25
+ December = 12
@@ -3,31 +3,8 @@ from dataclasses import dataclass
3
3
  from datetime import date as Date, datetime
4
4
  from dateutil.relativedelta import relativedelta
5
5
  from abc import ABCMeta, abstractmethod
6
- from enum import Enum
7
-
8
-
9
- class DayOfWeek(Enum):
10
- Sunday = 0
11
- Monday = 1
12
- Tuesday = 2
13
- Wednesday = 3
14
- Thursday = 4
15
- Friday = 5
16
- Saturday = 6
17
-
18
- class Month(Enum):
19
- January = 1
20
- February = 2
21
- March = 3
22
- April = 4
23
- May = 5
24
- June = 6
25
- July = 7
26
- August = 8
27
- September = 9
28
- October = 10
29
- November = 11
30
- December = 12
6
+
7
+ from ._enums import DayOfWeekEnum, MonthEnum
31
8
 
32
9
 
33
10
  class DateModifier(metaclass=ABCMeta):
@@ -52,20 +29,21 @@ class DateModifier(metaclass=ABCMeta):
52
29
  return datetype(year, month, day)
53
30
 
54
31
 
55
- class _DayIdxOfCalendarUnit(DateModifier):
32
+ @dataclass
33
+ class DayIdxOfCalendarUnit(DateModifier):
56
34
  """
57
35
  Interface for adjusting a date to some day of calendar unit
58
36
  """
59
- def __init__(self, idx: int) -> None:
60
- super().__init__()
61
- self.idx = idx
37
+ idx: int
38
+
39
+ def __post_init__(self) -> None:
62
40
  if self.idx == 0:
63
41
  raise ValueError(f"For constructors of class names that start with DayIdxOf_, idx cannot be zero")
64
42
  self.incr = self.idx - 1 if self.idx > 0 else self.idx
65
43
 
66
44
 
67
45
  @dataclass
68
- class DayIdxOfMonthsCycle(_DayIdxOfCalendarUnit):
46
+ class DayIdxOfMonthsCycle(DayIdxOfCalendarUnit):
69
47
  """
70
48
  DateModifier class to get the idx-th day of a cycle of months for an input date
71
49
 
@@ -74,23 +52,21 @@ class DayIdxOfMonthsCycle(_DayIdxOfCalendarUnit):
74
52
  num_months_in_cycle: 2 for one 6th of year, 3 for Quarter, 4 for one 3rd of year, 6 for half year, 12 for full year. Must fit evenly in 12
75
53
  first_month_of_cycle: The first month of months cycle of year. Default is January
76
54
  """
77
- _num_months_in_cycle: int
78
- _first_month_of_cycle: Month
55
+ num_months_in_cycle: int
56
+ first_month_of_cycle: MonthEnum = MonthEnum.January
79
57
 
80
- def __init__(self, idx: int, num_months_in_cycle: int, first_month_of_cycle: Month = Month.January) -> None:
81
- super().__init__(idx)
82
- self._num_months_in_cycle = num_months_in_cycle
83
- self._first_month_of_cycle = first_month_of_cycle
84
- if 12 % self._num_months_in_cycle != 0:
85
- raise ValueError(f"Value X must fit evenly in 12")
86
- self.first_month_of_first_cycle = (self._first_month_of_cycle.value - 1) % self._num_months_in_cycle + 1
58
+ def __post_init__(self) -> None:
59
+ super().__post_init__()
60
+ if 12 % self.num_months_in_cycle != 0:
61
+ raise ValueError(f"Argument 'num_months_in_cycle' must fit evenly in 12")
62
+ self.first_month_of_first_cycle = (self.first_month_of_cycle.value - 1) % self.num_months_in_cycle + 1
87
63
 
88
64
  def modify(self, date: Date) -> Date:
89
- current_cycle = (date.month - self.first_month_of_first_cycle) % 12 // self._num_months_in_cycle
90
- first_month_of_curr_cycle = current_cycle * self._num_months_in_cycle + self.first_month_of_first_cycle
65
+ current_cycle = (date.month - self.first_month_of_first_cycle) % 12 // self.num_months_in_cycle
66
+ first_month_of_curr_cycle = current_cycle * self.num_months_in_cycle + self.first_month_of_first_cycle
91
67
  year = date.year if date.month >= first_month_of_curr_cycle else date.year - 1
92
68
  first_day = self._get_date(type(date), year, first_month_of_curr_cycle, 1)
93
- ref_date = first_day if self.idx > 0 else first_day + relativedelta(months=self._num_months_in_cycle)
69
+ ref_date = first_day if self.idx > 0 else first_day + relativedelta(months=self.num_months_in_cycle)
94
70
  return ref_date + relativedelta(days=self.incr)
95
71
 
96
72
 
@@ -104,7 +80,7 @@ class DayIdxOfYear(DayIdxOfMonthsCycle):
104
80
  first_month_of_year: The first month of year. Default is January
105
81
  """
106
82
 
107
- def __init__(self, idx: int, first_month_of_year: Month = Month.January):
83
+ def __init__(self, idx: int, first_month_of_year: MonthEnum = MonthEnum.January):
108
84
  super().__init__(idx, num_months_in_cycle=12, first_month_of_cycle=first_month_of_year)
109
85
 
110
86
 
@@ -118,12 +94,12 @@ class DayIdxOfQuarter(DayIdxOfMonthsCycle):
118
94
  first_month_of_quarter: The first month of first quarter. Default is January
119
95
  """
120
96
 
121
- def __init__(self, idx: int, first_month_of_quarter: Month = Month.January):
97
+ def __init__(self, idx: int, first_month_of_quarter: MonthEnum = MonthEnum.January):
122
98
  super().__init__(idx, num_months_in_cycle=3, first_month_of_cycle=first_month_of_quarter)
123
99
 
124
100
 
125
101
  @dataclass
126
- class DayIdxOfMonth(_DayIdxOfCalendarUnit):
102
+ class DayIdxOfMonth(DayIdxOfCalendarUnit):
127
103
  """
128
104
  DateModifier class to get the idx-th day of month of an input date
129
105
 
@@ -131,9 +107,6 @@ class DayIdxOfMonth(_DayIdxOfCalendarUnit):
131
107
  idx: 1 for first, 2 for second, etc. Or, -1 for last, -2 for second last, etc. Must not be 0
132
108
  """
133
109
 
134
- def __init__(self, idx: int) -> None:
135
- super().__init__(idx)
136
-
137
110
  def modify(self, date: Date) -> Date:
138
111
  first_day = self._get_date(type(date), date.year, date.month, 1)
139
112
  ref_date = first_day if self.idx > 0 else first_day + relativedelta(months=1)
@@ -141,7 +114,7 @@ class DayIdxOfMonth(_DayIdxOfCalendarUnit):
141
114
 
142
115
 
143
116
  @dataclass
144
- class DayIdxOfWeek(_DayIdxOfCalendarUnit):
117
+ class DayIdxOfWeek(DayIdxOfCalendarUnit):
145
118
  """
146
119
  DateModifier class to get the idx-th day of week of an input date
147
120
 
@@ -149,12 +122,11 @@ class DayIdxOfWeek(_DayIdxOfCalendarUnit):
149
122
  idx: 1 for first, 2 for second, etc. Or, -1 for last, -2 for second last, etc. Must not be 0
150
123
  first_day_of_week: The day of week identified as the "first". Default is Monday
151
124
  """
152
- _first_day_of_week: DayOfWeek
125
+ first_day_of_week: DayOfWeekEnum = DayOfWeekEnum.Monday
153
126
 
154
- def __init__(self, idx: int, first_day_of_week: DayOfWeek = DayOfWeek.Monday) -> None:
155
- super().__init__(idx)
156
- self._first_day_of_week = first_day_of_week
157
- self.first_dow_num = self._first_day_of_week.value
127
+ def __post_init__(self) -> None:
128
+ super().__post_init__()
129
+ self.first_dow_num = self.first_day_of_week.value
158
130
 
159
131
  def modify(self, date: Date) -> Date:
160
132
  distance_from_first_day = (1 + date.weekday() - self.first_dow_num) % 7
@@ -162,17 +134,16 @@ class DayIdxOfWeek(_DayIdxOfCalendarUnit):
162
134
  return date + relativedelta(days=total_incr)
163
135
 
164
136
 
165
- class _OffsetUnits(DateModifier):
137
+ @dataclass
138
+ class OffsetUnits(DateModifier):
166
139
  """
167
140
  Abstract DateModifier class to offset an input date by some number of some calendar unit
168
141
  """
169
- def __init__(self, offset: int) -> None:
170
- super().__init__()
171
- self.offset = offset
142
+ offset: int
172
143
 
173
144
 
174
145
  @dataclass
175
- class OffsetYears(_OffsetUnits):
146
+ class OffsetYears(OffsetUnits):
176
147
  """
177
148
  DateModifier class to offset an input date by some number of years
178
149
 
@@ -180,15 +151,12 @@ class OffsetYears(_OffsetUnits):
180
151
  offset: The number of years to offset the input date.
181
152
  """
182
153
 
183
- def __init__(self, offset: int) -> None:
184
- super().__init__(offset)
185
-
186
154
  def modify(self, date: Date) -> Date:
187
155
  return date + relativedelta(years=self.offset)
188
156
 
189
157
 
190
158
  @dataclass
191
- class OffsetMonths(_OffsetUnits):
159
+ class OffsetMonths(OffsetUnits):
192
160
  """
193
161
  DateModifier class to offset an input date by some number of months
194
162
 
@@ -196,15 +164,12 @@ class OffsetMonths(_OffsetUnits):
196
164
  offset: The number of months to offset the input date.
197
165
  """
198
166
 
199
- def __init__(self, offset: int) -> None:
200
- super().__init__(offset)
201
-
202
167
  def modify(self, date: Date) -> Date:
203
168
  return date + relativedelta(months=self.offset)
204
169
 
205
170
 
206
171
  @dataclass
207
- class OffsetWeeks(_OffsetUnits):
172
+ class OffsetWeeks(OffsetUnits):
208
173
  """
209
174
  DateModifier class to offset an input date by some number of weeks
210
175
 
@@ -212,15 +177,12 @@ class OffsetWeeks(_OffsetUnits):
212
177
  offset: The number of weeks to offset the input date.
213
178
  """
214
179
 
215
- def __init__(self, offset: int) -> None:
216
- super().__init__(offset)
217
-
218
180
  def modify(self, date: Date) -> Date:
219
181
  return date + relativedelta(weeks=self.offset)
220
182
 
221
183
 
222
184
  @dataclass
223
- class OffsetDays(_OffsetUnits):
185
+ class OffsetDays(OffsetUnits):
224
186
  """
225
187
  DateModifier class to offset an input date by some number of days
226
188
 
@@ -228,9 +190,6 @@ class OffsetDays(_OffsetUnits):
228
190
  offset: The number of days to offset the input date.
229
191
  """
230
192
 
231
- def __init__(self, offset: int) -> None:
232
- super().__init__(offset)
233
-
234
193
  def modify(self, date: Date) -> Date:
235
194
  return date + relativedelta(days=self.offset)
236
195
 
@@ -243,14 +202,10 @@ class DateModPipeline(DateModifier):
243
202
  Attributes:
244
203
  modifiers: The list of DateModifier's to apply in sequence.
245
204
  """
246
- _date_modifiers: Sequence[DateModifier]
205
+ date_modifiers: Sequence[DateModifier]
247
206
 
248
- def __init__(self, date_modifiers: Sequence[DateModifier]) -> None:
249
- super().__init__()
250
- self._date_modifiers = tuple(date_modifiers)
251
-
252
207
  def modify(self, date: Date) -> Date:
253
- for modifier in self._date_modifiers:
208
+ for modifier in self.date_modifiers:
254
209
  date = modifier.modify(date)
255
210
  return date
256
211
 
@@ -265,7 +220,7 @@ class DateModPipeline(DateModifier):
265
220
  Returns:
266
221
  A new sequence of DateModifier
267
222
  """
268
- joined_modifiers = tuple(self._date_modifiers) + tuple(date_modifiers)
223
+ joined_modifiers = tuple(self.date_modifiers) + tuple(date_modifiers)
269
224
  return joined_modifiers
270
225
 
271
226
  def with_more_modifiers(self, date_modifiers: Sequence[DateModifier]):
@@ -298,7 +253,7 @@ class DateModPipeline(DateModifier):
298
253
  Returns:
299
254
  A list of datetime objects
300
255
  """
301
- assert isinstance(step, _OffsetUnits)
256
+ assert isinstance(step, OffsetUnits)
302
257
  if step.offset == 0:
303
258
  raise ValueError(f"The length of 'step' must not be zero")
304
259
 
@@ -313,12 +268,15 @@ class DateModPipeline(DateModifier):
313
268
  return output
314
269
 
315
270
 
316
- class _DateRepresentationModifier(metaclass=ABCMeta):
271
+ @dataclass
272
+ class DateRepresentationModifier(metaclass=ABCMeta):
317
273
  """
318
274
  Abstract class for modifying other representations of dates (such as string or unix timestemp)
319
275
  """
320
- def __init__(self, date_modifiers: Sequence[DateModifier]):
321
- self.date_modifier = DateModPipeline(date_modifiers)
276
+ date_modifiers: Sequence[DateModifier]
277
+
278
+ def __post_init__(self) -> None:
279
+ self.date_mod_pipeline = DateModPipeline(self.date_modifiers)
322
280
 
323
281
  @abstractmethod
324
282
  def with_more_modifiers(self, date_modifiers: Sequence[DateModifier]):
@@ -326,7 +284,7 @@ class _DateRepresentationModifier(metaclass=ABCMeta):
326
284
 
327
285
 
328
286
  @dataclass
329
- class DateStringModifier(_DateRepresentationModifier):
287
+ class DateStringModifier(DateRepresentationModifier):
330
288
  """
331
289
  Class to modify a string representation of a date given a DateModifier
332
290
 
@@ -334,12 +292,7 @@ class DateStringModifier(_DateRepresentationModifier):
334
292
  date_modifier: The DateModifier to apply on datetime objects
335
293
  date_format: Format of the output date string. Default is '%Y-%m-%d'
336
294
  """
337
- _date_modifiers: Sequence[DateModifier]
338
- _date_format: str
339
-
340
- def __init__(self, date_modifiers: Sequence[DateModifier], date_format: str = '%Y-%m-%d'):
341
- super().__init__(date_modifiers)
342
- self._date_format = date_format
295
+ date_format: str = '%Y-%m-%d'
343
296
 
344
297
  def with_more_modifiers(self, date_modifiers: Sequence[DateModifier]):
345
298
  """
@@ -351,11 +304,11 @@ class DateStringModifier(_DateRepresentationModifier):
351
304
  Returns:
352
305
  A new DateStringModifier
353
306
  """
354
- joined_modifiers = self.date_modifier.get_joined_modifiers(date_modifiers)
355
- return DateStringModifier(joined_modifiers, self._date_format)
307
+ joined_modifiers = self.date_mod_pipeline.get_joined_modifiers(date_modifiers)
308
+ return DateStringModifier(joined_modifiers, self.date_format)
356
309
 
357
310
  def _get_input_date_obj(self, date_str: str, input_format: str | None = None) -> Date:
358
- input_format = self._date_format if input_format is None else input_format
311
+ input_format = self.date_format if input_format is None else input_format
359
312
  return datetime.strptime(date_str, input_format).date()
360
313
 
361
314
  def modify(self, date_str: str, input_format: str | None = None) -> str:
@@ -370,7 +323,7 @@ class DateStringModifier(_DateRepresentationModifier):
370
323
  The resulting date string
371
324
  """
372
325
  date_obj = self._get_input_date_obj(date_str, input_format)
373
- return self.date_modifier.modify(date_obj).strftime(self._date_format)
326
+ return self.date_mod_pipeline.modify(date_obj).strftime(self.date_format)
374
327
 
375
328
  def get_date_list(self, start_date_str: str, step: DateModifier, input_format: str | None = None) -> Sequence[str]:
376
329
  """
@@ -390,14 +343,14 @@ class DateStringModifier(_DateRepresentationModifier):
390
343
  Returns:
391
344
  A list of date strings
392
345
  """
393
- assert isinstance(step, _OffsetUnits)
346
+ assert isinstance(step, OffsetUnits)
394
347
  curr_date = self._get_input_date_obj(start_date_str, input_format)
395
- output = self.date_modifier.get_date_list(curr_date, step)
396
- return [x.strftime(self._date_format) for x in output]
348
+ output = self.date_mod_pipeline.get_date_list(curr_date, step)
349
+ return [x.strftime(self.date_format) for x in output]
397
350
 
398
351
 
399
352
  @dataclass
400
- class TimestampModifier(_DateRepresentationModifier):
353
+ class TimestampModifier(DateRepresentationModifier):
401
354
  """
402
355
  Class to modify a numeric representation of a date (as Unix/Epoch/POSIX timestamp) given a DateModifier
403
356
 
@@ -405,10 +358,6 @@ class TimestampModifier(_DateRepresentationModifier):
405
358
  date_modifier: The DateModifier to apply on datetime objects
406
359
  date_format: Format of the date string. Default is '%Y-%m-%d'
407
360
  """
408
- _date_modifiers: Sequence[DateModifier]
409
-
410
- def __init__(self, date_modifiers: Sequence[DateModifier]):
411
- super().__init__(date_modifiers)
412
361
 
413
362
  def with_more_modifiers(self, date_modifiers: Sequence[DateModifier]):
414
363
  """
@@ -420,7 +369,7 @@ class TimestampModifier(_DateRepresentationModifier):
420
369
  Returns:
421
370
  A new TimestampModifier
422
371
  """
423
- joined_modifiers = self.date_modifier.get_joined_modifiers(date_modifiers)
372
+ joined_modifiers = self.date_mod_pipeline.get_joined_modifiers(date_modifiers)
424
373
  return TimestampModifier(joined_modifiers)
425
374
 
426
375
  def modify(self, timestamp: float) -> float:
@@ -434,7 +383,7 @@ class TimestampModifier(_DateRepresentationModifier):
434
383
  The resulting timestamp
435
384
  """
436
385
  date_obj = datetime.fromtimestamp(timestamp).date()
437
- modified_date = self.date_modifier.modify(date_obj)
386
+ modified_date = self.date_mod_pipeline.modify(date_obj)
438
387
  modified_datetime = datetime.combine(modified_date, datetime.min.time())
439
388
  return modified_datetime.timestamp()
440
389
 
@@ -456,5 +405,5 @@ class TimestampModifier(_DateRepresentationModifier):
456
405
  A list of timestamp as floats
457
406
  """
458
407
  curr_date = datetime.fromtimestamp(start_timestamp).date()
459
- output = self.date_modifier.get_date_list(curr_date, step)
408
+ output = self.date_mod_pipeline.get_date_list(curr_date, step)
460
409
  return [datetime.combine(x, datetime.min.time()).timestamp() for x in output]
@@ -0,0 +1,6 @@
1
+ from ._implementation import (
2
+ DateModifier,
3
+ DayIdxOfCalendarUnit,
4
+ OffsetUnits,
5
+ DateRepresentationModifier
6
+ )
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "squirrels"
3
- version = "0.5.0b2"
3
+ version = "0.5.0b3"
4
4
  description = "Squirrels - API Framework for Data Analytics"
5
5
  authors = [{ name = "Tim Huang", email = "tim.yuting@hotmail.com" }]
6
6
  requires-python = "~=3.10"
@@ -0,0 +1,17 @@
1
+ from ._version import __version__
2
+
3
+ from .arguments import *
4
+
5
+ from .connections import *
6
+
7
+ from .parameter_options import *
8
+
9
+ from .parameters import *
10
+
11
+ from .data_sources import *
12
+
13
+ from .dashboards import *
14
+
15
+ from .types import *
16
+
17
+ from ._project import SquirrelsProject
@@ -17,9 +17,9 @@ from ._version import __version__, sq_major_version
17
17
  from ._manifest import PermissionScope
18
18
  from ._auth import BaseUser, AccessToken, UserField
19
19
  from ._parameter_sets import ParameterSet
20
- from .dashboards import Dashboard
20
+ from ._dashboard_types import Dashboard
21
21
  from ._project import SquirrelsProject
22
- from .dataset_result import DatasetResult
22
+ from ._dataset_types import DatasetResult
23
23
  from ._parameter_configs import APIParamFieldInfo
24
24
 
25
25
  mimetypes.add_type('application/javascript', '.js')
@@ -189,17 +189,17 @@ class ApiServer:
189
189
  traceback.print_exception(exc.error, file=buffer)
190
190
  buffer.write(str(exc))
191
191
  response = JSONResponse(
192
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"message": f"An unexpected error occurred", "blame": "Squirrels project"}
192
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"message": f"An unexpected server error occurred", "blame": "Squirrels project"}
193
193
  )
194
194
  except ConfigurationError as exc:
195
195
  traceback.print_exc(file=buffer)
196
196
  response = JSONResponse(
197
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"message": f"An unexpected error occurred", "blame": "Squirrels project"}
197
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"message": f"An unexpected server error occurred", "blame": "Squirrels project"}
198
198
  )
199
199
  except Exception as exc:
200
200
  traceback.print_exc(file=buffer)
201
201
  response = JSONResponse(
202
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"message": f"An unexpected error occurred", "blame": "Squirrels framework"}
202
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"message": f"An unexpected server error occurred", "blame": "Squirrels framework"}
203
203
  )
204
204
 
205
205
  err_msg = buffer.getvalue()
@@ -88,14 +88,14 @@ class BuildModelArgs(_WithConnectionDictArgs):
88
88
 
89
89
  def run_sql_on_dataframes(self, sql_query: str, *, dataframes: dict[str, pl.LazyFrame] | None = None, **kwargs) -> pl.DataFrame:
90
90
  """
91
- Uses a dictionary of dataframes to execute a SQL query in an embedded in-memory database (sqlite or duckdb based on setting)
91
+ Uses a dictionary of dataframes to execute a SQL query in an embedded in-memory DuckDB database
92
92
 
93
93
  Arguments:
94
94
  sql_query: The SQL query to run
95
95
  dataframes: A dictionary of table names to their polars LazyFrame. If None, uses results of dependent models
96
96
 
97
97
  Returns:
98
- The result as a polars LazyFrame from running the query
98
+ The result as a polars DataFrame from running the query
99
99
  """
100
100
  if dataframes is None:
101
101
  dataframes = {x: self.ref(x) for x in self._dependencies}
@@ -1,31 +1,9 @@
1
1
  from typing import Callable, Any, Coroutine
2
2
  import polars as pl
3
3
 
4
- from .init_time_args import _WithConnectionDictArgs, ParametersArgs, BuildModelArgs, ConnectionsArgs
4
+ from ._init_time_args import ParametersArgs, BuildModelArgs
5
5
  from .._auth import BaseUser
6
- from ..parameters import Parameter, TextValue
7
-
8
-
9
- class AuthLoginArgs(_WithConnectionDictArgs):
10
-
11
- def __init__(
12
- self, conn_args: ConnectionsArgs, _connections: dict[str, Any],
13
- username: str,
14
- password: str
15
- ):
16
- super().__init__(conn_args.project_path, conn_args.proj_vars, conn_args.env_vars, _connections)
17
- self.username = username
18
- self.password = password
19
-
20
-
21
- class AuthTokenArgs(_WithConnectionDictArgs):
22
-
23
- def __init__(
24
- self, conn_args: ConnectionsArgs, _connections: dict[str, Any],
25
- token: str
26
- ):
27
- super().__init__(conn_args.project_path, conn_args.proj_vars, conn_args.env_vars, _connections)
28
- self.token = token
6
+ from .._parameters import Parameter, TextValue
29
7
 
30
8
 
31
9
  class ContextArgs(ParametersArgs):
@@ -57,7 +35,7 @@ class ContextArgs(ParametersArgs):
57
35
  return self._traits.copy()
58
36
 
59
37
  @property
60
- def placeholders(self) -> dict[str, Any]:
38
+ def _placeholders_copy(self) -> dict[str, Any]:
61
39
  """
62
40
  A dictionary of placeholder name to placeholder value
63
41
  """
@@ -103,7 +81,7 @@ class ModelArgs(BuildModelArgs, ContextArgs):
103
81
  self.user = ctx_args.user
104
82
  self._prms = ctx_args.prms
105
83
  self._traits = ctx_args.traits
106
- self._placeholders = ctx_args.placeholders
84
+ self._placeholders = ctx_args._placeholders_copy
107
85
  self._connections = build_model_args.connections
108
86
  self._dependencies = build_model_args.dependencies
109
87
  self._ref = build_model_args.ref
@@ -282,8 +282,8 @@ class Authenticator(_t.Generic[User]):
282
282
  if not update_user:
283
283
  raise InvalidInputError(101, f"User '{username}' already exists")
284
284
 
285
- if username == c.ADMIN_USERNAME:
286
- raise InvalidInputError(24, "Changing the admin user is not permitted")
285
+ if username == c.ADMIN_USERNAME and user_data.get("is_admin") is False:
286
+ raise InvalidInputError(24, "Setting the admin user to non-admin is not permitted")
287
287
  new_user = self.DbUser(password_hash=existing_user.password_hash, **user_data)
288
288
  session.delete(existing_user)
289
289
  else:
@@ -4,8 +4,8 @@ from sqlalchemy import Engine
4
4
  import time, polars as pl
5
5
 
6
6
  from . import _utils as u, _constants as c, _py_module as pm
7
- from .arguments.init_time_args import ConnectionsArgs
8
- from ._manifest import ManifestConfig, ConnectionProperties, ConnectionType
7
+ from ._arguments._init_time_args import ConnectionsArgs
8
+ from ._manifest import ManifestConfig, ConnectionProperties, ConnectionTypeEnum
9
9
 
10
10
 
11
11
  @dataclass
@@ -31,11 +31,11 @@ class ConnectionSet:
31
31
  def run_sql_query_from_conn_name(self, query: str, conn_name: str, placeholders: dict = {}) -> pl.DataFrame:
32
32
  conn = self.get_connection(conn_name)
33
33
  try:
34
- if isinstance(conn, ConnectionProperties) and (conn.type == ConnectionType.CONNECTORX or conn.type == ConnectionType.ADBC):
34
+ if isinstance(conn, ConnectionProperties) and (conn.type == ConnectionTypeEnum.CONNECTORX or conn.type == ConnectionTypeEnum.ADBC):
35
35
  if len(placeholders) > 0:
36
36
  raise u.ConfigurationError(f"Connection '{conn_name}' is a ConnectorX or ADBC connection, which does not support placeholders")
37
37
  df = pl.read_database_uri(query, conn.uri, engine=conn.type.value)
38
- elif isinstance(conn, ConnectionProperties) and conn.type == ConnectionType.SQLALCHEMY:
38
+ elif isinstance(conn, ConnectionProperties) and conn.type == ConnectionTypeEnum.SQLALCHEMY:
39
39
  with conn.engine.connect() as connection:
40
40
  df = pl.read_database(query, connection, execute_options={"parameters": placeholders})
41
41
  else:
@@ -52,7 +52,7 @@ class ConnectionSet:
52
52
  if isinstance(conn, Engine):
53
53
  conn.dispose()
54
54
  elif isinstance(conn, ConnectionProperties):
55
- if conn.type == ConnectionType.SQLALCHEMY:
55
+ if conn.type == ConnectionTypeEnum.SQLALCHEMY:
56
56
  conn.engine.dispose()
57
57
  elif hasattr(conn, 'close'):
58
58
  conn.close()
@@ -33,7 +33,7 @@ SQRL_CONNECTIONS_DEFAULT_NAME_USED = 'SQRL_CONNECTIONS__DEFAULT_NAME_USED'
33
33
  SQRL_DUCKDB_VENV_DB_FILE_PATH = 'SQRL_DUCKDB_VENV__DB_FILE_PATH'
34
34
 
35
35
  # Folder/File names
36
- PACKAGE_DATA_FOLDER = 'package_data'
36
+ PACKAGE_DATA_FOLDER = '_package_data'
37
37
  BASE_PROJECT_FOLDER = 'base_project'
38
38
 
39
39
  GLOBAL_ENV_FOLDER = '.squirrels'