data-finder 0.1.0__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 (42) hide show
  1. data_finder-0.1.0/PKG-INFO +38 -0
  2. data_finder-0.1.0/README.md +3 -0
  3. data_finder-0.1.0/calc/src/calc/__init__.py +0 -0
  4. data_finder-0.1.0/calc/src/calc/calc_protocol.py +56 -0
  5. data_finder-0.1.0/calc/src/calc/simple_price.py +24 -0
  6. data_finder-0.1.0/calc/tests/test_calc.py +52 -0
  7. data_finder-0.1.0/data_finder.egg-info/PKG-INFO +38 -0
  8. data_finder-0.1.0/data_finder.egg-info/SOURCES.txt +73 -0
  9. data_finder-0.1.0/data_finder.egg-info/dependency_links.txt +1 -0
  10. data_finder-0.1.0/data_finder.egg-info/requires.txt +28 -0
  11. data_finder-0.1.0/data_finder.egg-info/top_level.txt +1 -0
  12. data_finder-0.1.0/datafinder/src/datafinder/__init__.py +6 -0
  13. data_finder-0.1.0/datafinder/src/datafinder/attribute.py +26 -0
  14. data_finder-0.1.0/datafinder/src/datafinder/finder.py +7 -0
  15. data_finder-0.1.0/datafinder/src/datafinder/operation.py +162 -0
  16. data_finder-0.1.0/datafinder/src/datafinder/output.py +15 -0
  17. data_finder-0.1.0/datafinder/src/datafinder/runner.py +30 -0
  18. data_finder-0.1.0/datafinder/src/datafinder/typed_attributes.py +43 -0
  19. data_finder-0.1.0/datafinder/src/datafinder/typed_operations.py +80 -0
  20. data_finder-0.1.0/datafinder_duckdb/__init__.py +0 -0
  21. data_finder-0.1.0/datafinder_duckdb/duckdb_engine.py +30 -0
  22. data_finder-0.1.0/datafinder_generator/src/datafinder_generator/generator.py +25 -0
  23. data_finder-0.1.0/datafinder_ibis/src/datafinder_ibis/__init__.py +0 -0
  24. data_finder-0.1.0/datafinder_ibis/src/datafinder_ibis/ibis_engine.py +31 -0
  25. data_finder-0.1.0/datafinder_ibis/tests/test_ibis_engine.py +8 -0
  26. data_finder-0.1.0/datafinder_ibis_duckdb/tests/test_datafinder_ibis_duckdb.py +53 -0
  27. data_finder-0.1.0/example/__init__.py +0 -0
  28. data_finder-0.1.0/example/account_finder.py +37 -0
  29. data_finder-0.1.0/example/contractualposition_finder.py +56 -0
  30. data_finder-0.1.0/example/instrument_finder.py +37 -0
  31. data_finder-0.1.0/example/mappings.py +106 -0
  32. data_finder-0.1.0/example/queries.py +29 -0
  33. data_finder-0.1.0/example/trade_finder.py +47 -0
  34. data_finder-0.1.0/example_duckdb/__init__.py +0 -0
  35. data_finder-0.1.0/example_duckdb/duckdb_example.py +20 -0
  36. data_finder-0.1.0/example_duckdb/duckdb_trade_finder.py +24 -0
  37. data_finder-0.1.0/model/src/model/__init__.py +0 -0
  38. data_finder-0.1.0/model/src/model/m3.py +51 -0
  39. data_finder-0.1.0/model/src/model/mapping.py +19 -0
  40. data_finder-0.1.0/model/src/model/relational.py +41 -0
  41. data_finder-0.1.0/pyproject.toml +53 -0
  42. data_finder-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,38 @@
1
+ Metadata-Version: 2.4
2
+ Name: data-finder
3
+ Version: 0.1.0
4
+ Summary: Model driven data finders
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: atpublic==4.1.0
8
+ Requires-Dist: bidict==0.23.1
9
+ Requires-Dist: duckdb==1.0.0
10
+ Requires-Dist: greenlet==3.0.3
11
+ Requires-Dist: ibis-framework==9.0.0
12
+ Requires-Dist: iniconfig==2.1.0
13
+ Requires-Dist: jinja2==3.1.6
14
+ Requires-Dist: markdown-it-py==3.0.0
15
+ Requires-Dist: markupsafe==3.0.2
16
+ Requires-Dist: mdurl==0.1.2
17
+ Requires-Dist: numpy==1.26.4
18
+ Requires-Dist: packaging==25.0
19
+ Requires-Dist: pandas==2.2.2
20
+ Requires-Dist: parsy==2.1
21
+ Requires-Dist: pluggy==1.6.0
22
+ Requires-Dist: pyarrow==16.1.0
23
+ Requires-Dist: pyarrow-hotfix==0.7
24
+ Requires-Dist: pygments==2.19.1
25
+ Requires-Dist: pytest==8.3.4
26
+ Requires-Dist: python-dateutil==2.9.0.post0
27
+ Requires-Dist: pytz==2024.1
28
+ Requires-Dist: rich==13.9.4
29
+ Requires-Dist: six==1.16.0
30
+ Requires-Dist: sqlglot==23.12.2
31
+ Requires-Dist: toml==0.10.2
32
+ Requires-Dist: toolz==0.12.1
33
+ Requires-Dist: typing-extensions==4.12.2
34
+ Requires-Dist: tzdata==2024.1
35
+
36
+ # Experimental typed finders
37
+
38
+ This generates helper classes to query data using a logical model and mapping
@@ -0,0 +1,3 @@
1
+ # Experimental typed finders
2
+
3
+ This generates helper classes to query data using a logical model and mapping
File without changes
@@ -0,0 +1,56 @@
1
+ from abc import ABC
2
+
3
+ from numpy import ndarray
4
+
5
+ from datafinder import Attribute
6
+
7
+
8
+ class DomainAwareCalcProtocol:
9
+ def name(self):
10
+ raise NotImplementedError
11
+
12
+ # TODO should this be an ordered set ? to avoid duplicates
13
+ def inputs_spec(self) -> list[Attribute]:
14
+ raise NotImplementedError
15
+
16
+ def output_spec(self) -> Attribute:
17
+ raise NotImplementedError
18
+
19
+ #TODO should have key and time?
20
+ def calculate(self, inputs:ndarray) -> []:
21
+ raise NotImplementedError
22
+
23
+
24
+ # From https://charlesreid1.github.io/python-patterns-the-registry.html
25
+ class RegistryBase(type):
26
+
27
+ REGISTRY = {}
28
+
29
+ def __new__(cls, name, bases, attrs):
30
+ # instantiate a new type corresponding to the type of class being defined
31
+ # this is currently RegisterBase but in child classes will be the child class
32
+ new_cls = type.__new__(cls, name, bases, attrs)
33
+ cls.REGISTRY[new_cls.__name__] = new_cls
34
+ return new_cls
35
+
36
+ @classmethod
37
+ def get_registry(cls):
38
+ return dict(cls.REGISTRY)
39
+
40
+
41
+ class BaseRegisteredClass(metaclass=RegistryBase):
42
+ pass
43
+
44
+
45
+ class CalcEngineRegistry(metaclass=RegistryBase):
46
+ calcs = {}
47
+
48
+ @staticmethod
49
+ def register(calc:DomainAwareCalcProtocol):
50
+ CalcEngineRegistry.calcs[calc.name()] = calc
51
+
52
+
53
+ class DomainAwareCalc(DomainAwareCalcProtocol, ABC):
54
+
55
+ def __init__(self):
56
+ CalcEngineRegistry.register(self)
@@ -0,0 +1,24 @@
1
+ from calc.calc_protocol import DomainAwareCalc
2
+ from contractualposition_finder import ContractualPositionFinder
3
+ from datafinder import Attribute
4
+ from numpy import array
5
+
6
+
7
+ def npv(quantity: array, price: array):
8
+ return quantity * price
9
+
10
+
11
+ class PositionNPVCalc(DomainAwareCalc):
12
+
13
+ def name(self) -> str:
14
+ return 'npv'
15
+
16
+ def inputs_spec(self) -> list[Attribute]:
17
+ return [ContractualPositionFinder.quantity(),
18
+ ContractualPositionFinder.instrument().price()]
19
+
20
+ def calculate(self, inputs):
21
+ return npv(inputs[0], inputs[1])
22
+
23
+ def output_spec(self) -> Attribute:
24
+ return ContractualPositionFinder.npv()
@@ -0,0 +1,52 @@
1
+ import datetime
2
+
3
+ import duckdb
4
+ import numpy
5
+
6
+ from calc.calc_protocol import CalcEngineRegistry
7
+ from numpy.testing import assert_array_almost_equal
8
+
9
+ from datafinder import QueryRunnerBase
10
+ from mappings import generate_mappings
11
+
12
+
13
+ class TestCalc:
14
+
15
+ def setup(self):
16
+ #Register the Ibis engine
17
+ from datafinder_ibis.ibis_engine import IbisConnect
18
+ assert QueryRunnerBase.get_runner() == IbisConnect
19
+
20
+ generate_mappings()
21
+ con = duckdb.connect('test.db')
22
+ con.execute("DROP TABLE IF EXISTS contractualposition;")
23
+ con.execute(
24
+ "CREATE TABLE contractualposition(DATE DATE, INSTRUMENT VARCHAR, CPTY_ID INT, QUANTITY DOUBLE); COPY contractualposition FROM 'data/contractualpositions.csv'")
25
+ con.sql("SELECT * from contractualposition").show()
26
+
27
+ con.execute("DROP TABLE IF EXISTS price;")
28
+ con.execute(
29
+ "CREATE TABLE price(DATE_TIME DATETIME, SYM VARCHAR, PRICE DOUBLE); COPY price FROM 'data/prices.csv'")
30
+
31
+ def test_price(self):
32
+ self.setup()
33
+ # TODO - we have to import this first for it to register due to Python's dynamic nature
34
+ # need to do imports to force the load = https://stackoverflow.com/questions/73829483/register-classes-in-different-files-to-a-class-factory
35
+ from calc.simple_price import PositionNPVCalc
36
+ calc = PositionNPVCalc()
37
+ assert len(CalcEngineRegistry.calcs) == 1
38
+
39
+ inputs = calc.inputs_spec()
40
+
41
+ #Calc run
42
+ from contractualposition_finder import ContractualPositionFinder
43
+ input_data = ContractualPositionFinder.find_all(datetime.date.today(), datetime.date.today(), "LATEST",
44
+ inputs).to_numpy()
45
+
46
+ output = calc.calculate(input_data)
47
+
48
+ assert_array_almost_equal(output, numpy.array([200000.0, 54999.95]), decimal=2)
49
+
50
+
51
+
52
+
@@ -0,0 +1,38 @@
1
+ Metadata-Version: 2.4
2
+ Name: data-finder
3
+ Version: 0.1.0
4
+ Summary: Model driven data finders
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: atpublic==4.1.0
8
+ Requires-Dist: bidict==0.23.1
9
+ Requires-Dist: duckdb==1.0.0
10
+ Requires-Dist: greenlet==3.0.3
11
+ Requires-Dist: ibis-framework==9.0.0
12
+ Requires-Dist: iniconfig==2.1.0
13
+ Requires-Dist: jinja2==3.1.6
14
+ Requires-Dist: markdown-it-py==3.0.0
15
+ Requires-Dist: markupsafe==3.0.2
16
+ Requires-Dist: mdurl==0.1.2
17
+ Requires-Dist: numpy==1.26.4
18
+ Requires-Dist: packaging==25.0
19
+ Requires-Dist: pandas==2.2.2
20
+ Requires-Dist: parsy==2.1
21
+ Requires-Dist: pluggy==1.6.0
22
+ Requires-Dist: pyarrow==16.1.0
23
+ Requires-Dist: pyarrow-hotfix==0.7
24
+ Requires-Dist: pygments==2.19.1
25
+ Requires-Dist: pytest==8.3.4
26
+ Requires-Dist: python-dateutil==2.9.0.post0
27
+ Requires-Dist: pytz==2024.1
28
+ Requires-Dist: rich==13.9.4
29
+ Requires-Dist: six==1.16.0
30
+ Requires-Dist: sqlglot==23.12.2
31
+ Requires-Dist: toml==0.10.2
32
+ Requires-Dist: toolz==0.12.1
33
+ Requires-Dist: typing-extensions==4.12.2
34
+ Requires-Dist: tzdata==2024.1
35
+
36
+ # Experimental typed finders
37
+
38
+ This generates helper classes to query data using a logical model and mapping
@@ -0,0 +1,73 @@
1
+ README.md
2
+ pyproject.toml
3
+ ./calc/src/calc/__init__.py
4
+ ./calc/src/calc/calc_protocol.py
5
+ ./calc/src/calc/simple_price.py
6
+ ./calc/tests/test_calc.py
7
+ ./datafinder/src/datafinder/__init__.py
8
+ ./datafinder/src/datafinder/attribute.py
9
+ ./datafinder/src/datafinder/finder.py
10
+ ./datafinder/src/datafinder/operation.py
11
+ ./datafinder/src/datafinder/output.py
12
+ ./datafinder/src/datafinder/runner.py
13
+ ./datafinder/src/datafinder/typed_attributes.py
14
+ ./datafinder/src/datafinder/typed_operations.py
15
+ ./datafinder_duckdb/__init__.py
16
+ ./datafinder_duckdb/duckdb_engine.py
17
+ ./datafinder_generator/src/datafinder_generator/generator.py
18
+ ./datafinder_ibis/src/datafinder_ibis/__init__.py
19
+ ./datafinder_ibis/src/datafinder_ibis/ibis_engine.py
20
+ ./datafinder_ibis/tests/test_ibis_engine.py
21
+ ./datafinder_ibis_duckdb/tests/test_datafinder_ibis_duckdb.py
22
+ ./example/__init__.py
23
+ ./example/account_finder.py
24
+ ./example/contractualposition_finder.py
25
+ ./example/instrument_finder.py
26
+ ./example/mappings.py
27
+ ./example/queries.py
28
+ ./example/trade_finder.py
29
+ ./example_duckdb/__init__.py
30
+ ./example_duckdb/duckdb_example.py
31
+ ./example_duckdb/duckdb_trade_finder.py
32
+ ./model/src/model/__init__.py
33
+ ./model/src/model/m3.py
34
+ ./model/src/model/mapping.py
35
+ ./model/src/model/relational.py
36
+ calc/src/calc/__init__.py
37
+ calc/src/calc/calc_protocol.py
38
+ calc/src/calc/simple_price.py
39
+ calc/tests/test_calc.py
40
+ data_finder.egg-info/PKG-INFO
41
+ data_finder.egg-info/SOURCES.txt
42
+ data_finder.egg-info/dependency_links.txt
43
+ data_finder.egg-info/requires.txt
44
+ data_finder.egg-info/top_level.txt
45
+ datafinder/src/datafinder/__init__.py
46
+ datafinder/src/datafinder/attribute.py
47
+ datafinder/src/datafinder/finder.py
48
+ datafinder/src/datafinder/operation.py
49
+ datafinder/src/datafinder/output.py
50
+ datafinder/src/datafinder/runner.py
51
+ datafinder/src/datafinder/typed_attributes.py
52
+ datafinder/src/datafinder/typed_operations.py
53
+ datafinder_duckdb/__init__.py
54
+ datafinder_duckdb/duckdb_engine.py
55
+ datafinder_generator/src/datafinder_generator/generator.py
56
+ datafinder_ibis/src/datafinder_ibis/__init__.py
57
+ datafinder_ibis/src/datafinder_ibis/ibis_engine.py
58
+ datafinder_ibis/tests/test_ibis_engine.py
59
+ datafinder_ibis_duckdb/tests/test_datafinder_ibis_duckdb.py
60
+ example/__init__.py
61
+ example/account_finder.py
62
+ example/contractualposition_finder.py
63
+ example/instrument_finder.py
64
+ example/mappings.py
65
+ example/queries.py
66
+ example/trade_finder.py
67
+ example_duckdb/__init__.py
68
+ example_duckdb/duckdb_example.py
69
+ example_duckdb/duckdb_trade_finder.py
70
+ model/src/model/__init__.py
71
+ model/src/model/m3.py
72
+ model/src/model/mapping.py
73
+ model/src/model/relational.py
@@ -0,0 +1,28 @@
1
+ atpublic==4.1.0
2
+ bidict==0.23.1
3
+ duckdb==1.0.0
4
+ greenlet==3.0.3
5
+ ibis-framework==9.0.0
6
+ iniconfig==2.1.0
7
+ jinja2==3.1.6
8
+ markdown-it-py==3.0.0
9
+ markupsafe==3.0.2
10
+ mdurl==0.1.2
11
+ numpy==1.26.4
12
+ packaging==25.0
13
+ pandas==2.2.2
14
+ parsy==2.1
15
+ pluggy==1.6.0
16
+ pyarrow==16.1.0
17
+ pyarrow-hotfix==0.7
18
+ pygments==2.19.1
19
+ pytest==8.3.4
20
+ python-dateutil==2.9.0.post0
21
+ pytz==2024.1
22
+ rich==13.9.4
23
+ six==1.16.0
24
+ sqlglot==23.12.2
25
+ toml==0.10.2
26
+ toolz==0.12.1
27
+ typing-extensions==4.12.2
28
+ tzdata==2024.1
@@ -0,0 +1 @@
1
+ data-finder
@@ -0,0 +1,6 @@
1
+ from .attribute import *
2
+ from .operation import *
3
+ from .typed_attributes import *
4
+ from .typed_operations import *
5
+ from .output import *
6
+ from .runner import *
@@ -0,0 +1,26 @@
1
+ from typing import Any
2
+
3
+
4
+ class Attribute:
5
+ __name: str
6
+ __column_db_type: str
7
+ __owner: str
8
+ __parent: Any
9
+
10
+ def __init__(self, name: str, column_db_type: str, owner:str, parent=None):
11
+ self.__name = name
12
+ self.__column_db_type = column_db_type
13
+ self.__owner = owner
14
+ self.__parent = parent
15
+
16
+ def column_name(self) -> str:
17
+ return self.__name
18
+
19
+ def column_type(self) -> str:
20
+ return self.__column_db_type
21
+
22
+ def owner(self) -> str:
23
+ return self.__owner
24
+
25
+ def parent(self) -> Any:
26
+ return self.__parent
@@ -0,0 +1,7 @@
1
+ from datafinder import JoinOperation, Attribute
2
+
3
+
4
+ class RelatedFinder:
5
+ def __init__(self, source: Attribute, target: Attribute):
6
+ self.__join = JoinOperation(source, target)
7
+
@@ -0,0 +1,162 @@
1
+ import datetime
2
+
3
+ from datafinder.attribute import Attribute
4
+
5
+
6
+ class TableAlias:
7
+ def __init__(self, table: str, alias: str):
8
+ self.table = table
9
+ self.alias = alias
10
+
11
+
12
+ class ColumnAlias:
13
+ def __init__(self, column_name: str, table_alias: TableAlias):
14
+ self.column_name = column_name
15
+ self.table_alias = table_alias
16
+
17
+
18
+ class Join:
19
+ def __init__(self, source: ColumnAlias, target: ColumnAlias):
20
+ self.source = source
21
+ self.target = target
22
+
23
+
24
+ class QueryEngine:
25
+ _select: list[ColumnAlias]
26
+ _from: set[TableAlias]
27
+ _where: list[str]
28
+ _join: list[Join]
29
+ __table_alias_incr: int
30
+
31
+ def __init__(self):
32
+ self._where = []
33
+ self._select = []
34
+ self._from = set()
35
+ self._join = []
36
+ self.__table_alias_incr = 0
37
+ self.__table_aliases_by_table = {}
38
+
39
+ def select(self, cols: list[Attribute]):
40
+ for col in cols:
41
+ table = col.owner()
42
+ ta = self.__table_alias_for_table(table)
43
+ parent: JoinOperation = col.parent()
44
+ if parent is not None:
45
+ left = parent.left
46
+ sc = ColumnAlias(left.column_name(), self.__table_alias_for_table(left.owner()))
47
+ right = parent.right
48
+ tc = ColumnAlias(right.column_name(), self.__table_alias_for_table(right.owner()))
49
+ self._join.append(Join(sc, tc))
50
+ else:
51
+ self._from.add(ta)
52
+ ca = ColumnAlias(col.column_name(), ta)
53
+ self._select.append(ca)
54
+
55
+ def __table_alias_for_table(self, table: str) -> TableAlias:
56
+ ta = None
57
+ if table in self.__table_aliases_by_table:
58
+ ta = self.__table_aliases_by_table[table]
59
+ else:
60
+ ta = TableAlias(table, "t" + str(self.__table_alias_incr))
61
+ self.__table_alias_incr = self.__table_alias_incr + 1
62
+ self.__table_aliases_by_table[table] = ta
63
+ return ta
64
+
65
+ def append_where_binary_clause(self, op: str):
66
+ self._where.append(op)
67
+
68
+ def append_where_clause(self, attr: Attribute, op: str, value: str):
69
+ ta = self.__table_alias_for_table(attr.owner())
70
+ self._where.append(ta.alias + '.' + attr.column_name() + ' ' + op + ' ' + value)
71
+
72
+ def build_query_string(self) -> str:
73
+ joins = map(lambda j: ' LEFT OUTER JOIN ' + j.target.table_alias.table + ' AS ' + j.target.table_alias.alias +
74
+ ' ON ' + j.source.table_alias.alias + '.' + j.source.column_name + ' = ' +
75
+ j.target.table_alias.alias + '.' + j.target.column_name, self._join)
76
+ return 'SELECT ' + ','.join(map(lambda ca: ca.table_alias.alias + '.' + ca.column_name, self._select)) \
77
+ + ' FROM ' + ','.join(map(lambda ta: ta.table + ' AS ' + ta.alias, self._from)) \
78
+ + ''.join(joins) \
79
+ + self.__build_where()
80
+
81
+ def __build_where(self) -> str:
82
+ if len(self._where) > 0:
83
+ return ' WHERE ' + ''.join(self._where)
84
+ else:
85
+ return ''
86
+
87
+ def where_clauses(self):
88
+ return self._where
89
+
90
+ def start_and(self):
91
+ pass
92
+
93
+ def end_and(self):
94
+ pass
95
+
96
+
97
+ # Interface
98
+ class Operation:
99
+
100
+ def generate_query(self, query: QueryEngine):
101
+ pass
102
+
103
+
104
+ class NoOperation(Operation):
105
+ def __init__(self):
106
+ pass
107
+
108
+
109
+ class SelectOperation(Operation):
110
+ def __init__(self, display: list[Attribute], table: str, filter: Operation):
111
+ self.__display = display
112
+ self.__table = table
113
+ self.__filter = filter
114
+
115
+ def generate_query(self, qe: QueryEngine):
116
+ qe.select(self.__display)
117
+ self.__filter.generate_query(qe)
118
+
119
+
120
+ class AndOperation(Operation):
121
+ __left: Operation
122
+ __right: Operation
123
+
124
+ def __init__(self, lhs: Operation, rhs: Operation):
125
+ self.__left = lhs
126
+ self.__right = rhs
127
+
128
+ def generate_query(self, query: QueryEngine):
129
+ query.start_and()
130
+ self.__left.generate_query(query)
131
+ query.append_where_binary_clause(" and ")
132
+ self.__right.generate_query(query)
133
+ query.end_and()
134
+
135
+
136
+ class BusinessTemporalOperation(Operation):
137
+ # TODO - which date format should we use
138
+ __business_date_from_inclusive: datetime.date
139
+ __business_date_to_inclusive: datetime.date
140
+
141
+
142
+ class BaseOperation(Operation):
143
+
144
+ def and_op(self, rhs: Operation):
145
+ return AndOperation(self, rhs)
146
+
147
+
148
+ class JoinOperation(Operation):
149
+ left: Attribute
150
+ right: Attribute
151
+
152
+ def __init__(self, lhs: Attribute, rhs: Attribute):
153
+ self.left = lhs
154
+ self.right = rhs
155
+
156
+
157
+ def select_sql_to_string(columns: list[Attribute], table: str, op: Operation) -> str:
158
+ qe = QueryEngine()
159
+ select = SelectOperation(columns, table, op)
160
+ select.generate_query(qe)
161
+ return qe.build_query_string()
162
+
@@ -0,0 +1,15 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+
4
+
5
+ class ToNumpy:
6
+
7
+ def to_numpy(self) -> np.array:
8
+ pass
9
+
10
+
11
+ class DataFrame(ToNumpy):
12
+
13
+ def to_pandas(self) -> pd.DataFrame:
14
+ pass
15
+
@@ -0,0 +1,30 @@
1
+ from datafinder import Attribute, Operation, DataFrame
2
+
3
+
4
+ class RegistryBase(type):
5
+ REGISTRY = {}
6
+
7
+ def __new__(cls, name, bases, attrs):
8
+ # instantiate a new type corresponding to the type of class being defined
9
+ # this is currently RegisterBase but in child classes will be the child class
10
+ new_cls = type.__new__(cls, name, bases, attrs)
11
+ cls.REGISTRY[new_cls.__name__] = new_cls
12
+ return new_cls
13
+
14
+ @classmethod
15
+ def get_registry(cls):
16
+ return dict(cls.REGISTRY)
17
+
18
+
19
+ class QueryRunnerBase(metaclass=RegistryBase):
20
+
21
+ @staticmethod
22
+ def select(columns: list[Attribute], table: str, op: Operation) -> DataFrame:
23
+ pass
24
+
25
+ @staticmethod
26
+ def get_runner():
27
+ for k in RegistryBase.REGISTRY.keys():
28
+ if k != 'QueryRunnerBase':
29
+ return RegistryBase.REGISTRY[k]
30
+ raise Exception("No query runner registered")
@@ -0,0 +1,43 @@
1
+ from .operation import *
2
+ from .typed_operations import *
3
+
4
+
5
+ class StringAttribute(Attribute):
6
+
7
+ def __init__(self, name: str, column_db_type: str, owner:str, parent=None):
8
+ super().__init__(name, column_db_type, owner, parent)
9
+
10
+ def eq(self, value: str) -> Operation:
11
+ return StringEqOperation(self, value)
12
+
13
+ def __eq__(self, value: str) -> Operation:
14
+ return StringEqOperation(self, value)
15
+
16
+
17
+ class FloatAttribute(Attribute):
18
+
19
+ def __init__(self, name: str, column_db_type: str, owner:str, parent=None):
20
+ super().__init__(name, column_db_type, owner, parent)
21
+
22
+ def eq(self, value: float) -> Operation:
23
+ return PrimitiveEqOperation(self, value)
24
+
25
+ def __eq__(self, value: float) -> Operation:
26
+ return PrimitiveEqOperation(self, value)
27
+
28
+ def __gt__(self, value: float) -> Operation:
29
+ return PrimitiveGreaterThanOperation(self, value)
30
+
31
+ class IntegerAttribute(Attribute):
32
+
33
+ def __init__(self, name: str, column_db_type: str, owner:str, parent=None):
34
+ super().__init__(name, column_db_type, owner, parent)
35
+
36
+ def eq(self, value: float) -> Operation:
37
+ return PrimitiveEqOperation(self, value)
38
+
39
+ def __eq__(self, value: float) -> Operation:
40
+ return PrimitiveEqOperation(self, value)
41
+
42
+ def __gt__(self, value: float) -> Operation:
43
+ return PrimitiveGreaterThanOperation(self, value)