dbhydra 0.3.0__tar.gz → 2.2.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 (40) hide show
  1. {dbhydra-0.3.0 → dbhydra-2.2.0}/PKG-INFO +3 -6
  2. {dbhydra-0.3.0 → dbhydra-2.2.0}/README.md +2 -1
  3. dbhydra-2.2.0/dbhydra/__init__.py +3 -0
  4. dbhydra-2.2.0/dbhydra/dbhydra_core.py +63 -0
  5. dbhydra-2.2.0/dbhydra/src/abstract_db.py +206 -0
  6. dbhydra-2.2.0/dbhydra/src/abstract_table.py +435 -0
  7. dbhydra-2.2.0/dbhydra/src/bigquery_db.py +63 -0
  8. dbhydra-2.2.0/dbhydra/src/errors/__init__.py +0 -0
  9. dbhydra-2.2.0/dbhydra/src/errors/exceptions.py +2 -0
  10. dbhydra-2.2.0/dbhydra/src/migrator.py +395 -0
  11. dbhydra-2.2.0/dbhydra/src/mongo_db.py +57 -0
  12. dbhydra-2.2.0/dbhydra/src/mysql_db.py +77 -0
  13. dbhydra-2.2.0/dbhydra/src/postgres_db.py +55 -0
  14. dbhydra-2.2.0/dbhydra/src/sqlserver_db.py +91 -0
  15. dbhydra-2.2.0/dbhydra/src/tables.py +1142 -0
  16. dbhydra-2.2.0/dbhydra/src/xlsx_db.py +112 -0
  17. dbhydra-2.2.0/dbhydra/tests/__init__.py +0 -0
  18. dbhydra-2.2.0/dbhydra/tests/test_cases.py +20 -0
  19. dbhydra-2.2.0/dbhydra/tests/test_mongo.py +64 -0
  20. dbhydra-2.2.0/dbhydra/tests/test_sql.py +101 -0
  21. {dbhydra-0.3.0 → dbhydra-2.2.0}/dbhydra.egg-info/PKG-INFO +3 -6
  22. dbhydra-2.2.0/dbhydra.egg-info/SOURCES.txt +27 -0
  23. {dbhydra-0.3.0 → dbhydra-2.2.0}/dbhydra.egg-info/requires.txt +1 -0
  24. {dbhydra-0.3.0 → dbhydra-2.2.0}/setup.py +2 -2
  25. dbhydra-0.3.0/dbhydra/dbhydra_builder.py +0 -57
  26. dbhydra-0.3.0/dbhydra/dbhydra_core.py +0 -1472
  27. dbhydra-0.3.0/dbhydra/dbhydra_liquibase.py +0 -56
  28. dbhydra-0.3.0/dbhydra/dbhydra_model.py +0 -42
  29. dbhydra-0.3.0/dbhydra/dbhydra_mysql_example - kopie.py +0 -19
  30. dbhydra-0.3.0/dbhydra/dbhydra_mysql_example.py +0 -132
  31. dbhydra-0.3.0/dbhydra/dbhydra_pandas_framework.py +0 -19
  32. dbhydra-0.3.0/dbhydra/migrator_example.py +0 -101
  33. dbhydra-0.3.0/dbhydra/mongo.py +0 -41
  34. dbhydra-0.3.0/dbhydra/test.py +0 -45
  35. dbhydra-0.3.0/dbhydra.egg-info/SOURCES.txt +0 -19
  36. {dbhydra-0.3.0 → dbhydra-2.2.0}/LICENSE +0 -0
  37. {dbhydra-0.3.0/dbhydra → dbhydra-2.2.0/dbhydra/src}/__init__.py +0 -0
  38. {dbhydra-0.3.0 → dbhydra-2.2.0}/dbhydra.egg-info/dependency_links.txt +0 -0
  39. {dbhydra-0.3.0 → dbhydra-2.2.0}/dbhydra.egg-info/top_level.txt +0 -0
  40. {dbhydra-0.3.0 → dbhydra-2.2.0}/setup.cfg +0 -0
@@ -1,12 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbhydra
3
- Version: 0.3.0
3
+ Version: 2.2.0
4
4
  Summary: Data science friendly ORM combining Python
5
5
  Home-page: https://github.com/DovaX/dbhydra
6
6
  Author: DovaX
7
7
  Author-email: dovax.ai@gmail.com
8
- License: UNKNOWN
9
- Platform: UNKNOWN
10
8
  Classifier: Programming Language :: Python :: 3
11
9
  Classifier: License :: OSI Approved :: MIT License
12
10
  Classifier: Operating System :: OS Independent
@@ -16,7 +14,7 @@ License-File: LICENSE
16
14
 
17
15
  # dbhydra
18
16
  Data science friendly ORM (Object Relational Mapping) library combining Python, Pandas, and various SQL dialects
19
- For full documentation see official [documentation](http://app.forloop.ai/dbhydra/documentation)
17
+ For full documentation see official [documentation](http://app.forloop.ai/dbhydra/documentation) - currently unavailable but we're working on it!
20
18
 
21
19
  ## Installation
22
20
 
@@ -62,6 +60,7 @@ print(table_test.columns)
62
60
 
63
61
  table2 = dh.Table(db1,"test_new",["id","test2"],["int","nvarchar(20)"])
64
62
  #table2.create()
63
+ #table2.drop()
65
64
  ```
66
65
  ## Current scope
67
66
  Aims: Easy integration with Pandas, SQL SERVER/MySQL database, and exports/imports to/from excel/CSV format
@@ -76,5 +75,3 @@ Pull requests are welcome. For major changes, please open an issue first to disc
76
75
 
77
76
  ## License
78
77
  [MIT](https://choosealicense.com/licenses/mit/)
79
-
80
-
@@ -1,6 +1,6 @@
1
1
  # dbhydra
2
2
  Data science friendly ORM (Object Relational Mapping) library combining Python, Pandas, and various SQL dialects
3
- For full documentation see official [documentation](http://app.forloop.ai/dbhydra/documentation)
3
+ For full documentation see official [documentation](http://app.forloop.ai/dbhydra/documentation) - currently unavailable but we're working on it!
4
4
 
5
5
  ## Installation
6
6
 
@@ -46,6 +46,7 @@ print(table_test.columns)
46
46
 
47
47
  table2 = dh.Table(db1,"test_new",["id","test2"],["int","nvarchar(20)"])
48
48
  #table2.create()
49
+ #table2.drop()
49
50
  ```
50
51
  ## Current scope
51
52
  Aims: Easy integration with Pandas, SQL SERVER/MySQL database, and exports/imports to/from excel/CSV format
@@ -0,0 +1,3 @@
1
+ from dbhydra import *
2
+
3
+ __all__=["dbhydra_core", "src", "tests"]
@@ -0,0 +1,63 @@
1
+ """DB Hydra ORM"""
2
+ import abc
3
+ from typing import Any
4
+
5
+ import pandas as pd
6
+ from pydantic import BaseModel
7
+
8
+ ##### Do not remove imports - they are expored in the package
9
+ from dbhydra.src.sqlserver_db import SqlServerDb, db
10
+ from dbhydra.src.mysql_db import MysqlDb, Mysqldb
11
+ from dbhydra.src.bigquery_db import BigQueryDb
12
+ from dbhydra.src.mongo_db import MongoDb
13
+ from dbhydra.src.postgres_db import PostgresDb
14
+ from dbhydra.src.xlsx_db import XlsxDb, XlsxDB
15
+ from dbhydra.src.abstract_db import AbstractDb
16
+ from dbhydra.src.tables import SqlServerTable, PostgresTable, MysqlTable, XlsxTable, AbstractTable, MongoTable, BigQueryTable, Table, AbstractSelectable, AbstractJoinable
17
+ ##### Do not remove imports - they are expored in the package
18
+
19
+
20
+ class Jsonable(str):
21
+ """Is used as type in python_database_type_mapping"""
22
+ pass
23
+
24
+
25
+
26
+ # dataframe - dictionary auxiliary functions
27
+ def df_to_dict(df, column1, column2):
28
+ dictionary = df.set_index(column1).to_dict()[column2]
29
+ return (dictionary)
30
+
31
+
32
+ def dict_to_df(dictionary, column1, column2):
33
+ df = pd.DataFrame(list(dictionary.items()), columns=[column1, column2])
34
+ return (df)
35
+
36
+
37
+
38
+ from pydantic_core import CoreSchema, core_schema
39
+ from pydantic import GetCoreSchemaHandler
40
+
41
+
42
+ class AbstractModel(abc.ABC, BaseModel):
43
+ @classmethod
44
+ def generate_dbhydra_table(cls, table_class: AbstractTable, db1, name, id_column_name="id"):
45
+ column_type_dict = create_table_structure_dict(cls, id_column_name=id_column_name)
46
+ dbhydra_table = table_class.init_from_column_type_dict(db1, name, column_type_dict, id_column_name=id_column_name)
47
+ return dbhydra_table
48
+
49
+ @classmethod
50
+ def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
51
+ return core_schema.no_info_after_validator_function(cls, handler(str))
52
+
53
+
54
+
55
+ def create_table_structure_dict(api_class_instance, id_column_name="id"):
56
+ """
57
+ Accepts instance of API data class (e.g. APIDatabase) and converts it to dictionary {attribute_name: attribute_type}
58
+ """
59
+ table_structure_dict = {id_column_name: "int"}
60
+ table_structure_dict = {**table_structure_dict,
61
+ **{attribute_name: attribute_type.__name__ for attribute_name, attribute_type in api_class_instance.__annotations__.items()}}
62
+
63
+ return table_structure_dict
@@ -0,0 +1,206 @@
1
+ import abc
2
+ import threading
3
+ from contextlib import contextmanager
4
+ from typing import Optional
5
+
6
+ from dbhydra.src.migrator import Migrator
7
+ from dbhydra.src.tables import AbstractTable
8
+
9
+
10
+ def read_connection_details(config_file):
11
+ def read_file(file):
12
+ """Reads txt file -> list"""
13
+ with open(file, "r") as f:
14
+ rows = f.readlines()
15
+ for i, row in enumerate(rows):
16
+ rows[i] = row.replace("\n", "")
17
+ return (rows)
18
+
19
+ connection_details = read_file(config_file)
20
+ db_details = {}
21
+ for detail in connection_details:
22
+ key = detail.split("=")[0]
23
+ value = detail.split("=")[1]
24
+ db_details[key] = value
25
+
26
+ # Skip empty lines to avoid error when reading config file
27
+ if not detail:
28
+ continue
29
+
30
+ print(", ".join([db_details['DB_SERVER'], db_details['DB_DATABASE'], db_details['DB_USERNAME']]))
31
+ return (db_details)
32
+
33
+
34
+
35
+
36
+
37
+ class Transaction:
38
+ def __init__(self, connection):
39
+ self.connection = connection
40
+
41
+ def commit(self):
42
+ self.connection.commit()
43
+
44
+ def rollback(self):
45
+ self.connection.rollback()
46
+
47
+
48
+
49
+
50
+ class AbstractDb(abc.ABC):
51
+ matching_table_class = AbstractTable
52
+
53
+ typing_to_python_mapping = {
54
+ 'List': 'list',
55
+ 'Dict': 'dict',
56
+ 'Tuple': 'tuple',
57
+ 'Set': 'set',
58
+ 'Union': 'object',
59
+ 'Optional': 'object',
60
+ 'Jsonable': 'Jsonable',
61
+ # 'FrozenSet': frozenset,
62
+ # 'Deque': list,
63
+ # 'Any': object,
64
+ #
65
+ # 'Callable': object,
66
+ # 'Type': type,
67
+ # 'TypeVar': object,
68
+ # 'Generic': object,
69
+ # 'Sequence': list,
70
+ # 'Iterable': list,
71
+ # 'Mapping': dict,
72
+ # 'AbstractSet': set,
73
+ }
74
+ python_database_type_mapping = {}
75
+ def __init__(self, config_file="config.ini", db_details=None):
76
+ if db_details is None:
77
+ db_details = read_connection_details(config_file)
78
+
79
+ self.locally = True
80
+ if db_details["LOCALLY"] == "False":
81
+ self.locally = False
82
+
83
+ self.DB_SERVER = db_details["DB_SERVER"]
84
+ self.DB_DATABASE = db_details["DB_DATABASE"]
85
+ self.DB_USERNAME = db_details["DB_USERNAME"]
86
+ self.DB_PASSWORD = db_details["DB_PASSWORD"]
87
+
88
+ self.is_autocommiting=True
89
+
90
+ if "DB_PORT" in db_details.keys():
91
+ self.DB_PORT = int(db_details["DB_PORT"])
92
+ else:
93
+ self.DB_PORT = None
94
+
95
+ if "DB_DRIVER" in db_details.keys():
96
+ self.DB_DRIVER = db_details["DB_DRIVER"]
97
+ else:
98
+ self.DB_DRIVER = "ODBC Driver 13 for SQL Server"
99
+
100
+ self.lock = threading.Lock()
101
+
102
+ # This call to `self.connect_to_db` is not doing anything as it returns a
103
+ # context manager object
104
+ # self.connect_to_db()
105
+
106
+ self.active_transactions=[]
107
+ self.last_table_inserted_into: Optional[str] = None
108
+ self.identifier_quote = ''
109
+
110
+ @abc.abstractmethod
111
+ def connect_locally(self):
112
+ pass
113
+
114
+ @abc.abstractmethod
115
+ def connect_remotely(self):
116
+ pass
117
+
118
+ def _connect(self):
119
+ if self.locally:
120
+ self.connect_locally()
121
+ else:
122
+ self.connect_remotely()
123
+
124
+ def connect(self):
125
+ print("DEPRECATION WARNING: use `connect_to_db` context manager instead of `connect` method")
126
+ if self.locally:
127
+ self.connect_locally()
128
+ else:
129
+ self.connect_remotely()
130
+
131
+ #@abc.abstractmethod
132
+ def get_all_tables(self):
133
+ pass
134
+
135
+ #@abc.abstractmethod
136
+ def generate_table_dict(self):
137
+ pass
138
+
139
+ def get_table(self, table_name: str):
140
+ """
141
+ Retrieves Table from DB using its name.
142
+ """
143
+
144
+ try:
145
+ table = self.generate_table_dict()[table_name]
146
+ except KeyError:
147
+ print(f'Table "{table_name}" was not found in the DB.')
148
+ raise KeyError
149
+
150
+ return table
151
+
152
+ @contextmanager
153
+ def connect_to_db(self):
154
+ try:
155
+ self._connect()
156
+ yield None
157
+ finally:
158
+ self.close_connection()
159
+
160
+ @contextmanager
161
+ def connect_to_table(self, table_name):
162
+ with self.connect_to_db():
163
+ table = self.generate_table_dict()[table_name]
164
+
165
+ yield table
166
+
167
+
168
+ @contextmanager
169
+ def transaction(self):
170
+ self.is_autocommiting=False
171
+ transaction = Transaction(self.connection)
172
+ self.active_transactions.append(transaction)
173
+ try:
174
+ yield transaction
175
+ except Exception as e:
176
+ transaction.rollback()
177
+ raise e
178
+ else:
179
+ transaction.commit()
180
+ finally:
181
+ self.active_transactions.remove(transaction)
182
+ if len(self.active_transactions)==0:
183
+ self.is_autocommiting=True
184
+
185
+
186
+ def execute(self, query):
187
+ result=self.cursor.execute(query)
188
+ if self.is_autocommitting:
189
+ self.cursor.commit()
190
+ return(result)
191
+
192
+ def close_connection(self):
193
+ self.connection.close()
194
+ print("DB connection closed")
195
+
196
+ def initialize_migrator(self):
197
+ self.migrator = Migrator(self)
198
+
199
+ def _convert_column_type_dict_from_python(self, column_type_dict):
200
+ """
201
+ First apply mapping from python typing module to standard python.
202
+ Then apply mapping from python to database types
203
+ """
204
+ typing_python_mapping = {column_name: self.typing_to_python_mapping.get(column_type,column_type) for column_name, column_type in column_type_dict.items()}
205
+ return {column_name: self.python_database_type_mapping[column_type] for column_name, column_type in typing_python_mapping.items()}
206
+