abstract-database 0.0.0.1__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.
- abstract_database-0.0.0.1/MANIFEST.in +1 -0
- abstract_database-0.0.0.1/PKG-INFO +17 -0
- abstract_database-0.0.0.1/README.md +1 -0
- abstract_database-0.0.0.1/setup.cfg +4 -0
- abstract_database-0.0.0.1/setup.py +30 -0
- abstract_database-0.0.0.1/src/abstract_database/__init__.py +1 -0
- abstract_database-0.0.0.1/src/abstract_database/abstract_database_cmd.py +256 -0
- abstract_database-0.0.0.1/src/abstract_database/directory_mgr.py +8 -0
- abstract_database-0.0.0.1/src/abstract_database.egg-info/PKG-INFO +17 -0
- abstract_database-0.0.0.1/src/abstract_database.egg-info/SOURCES.txt +11 -0
- abstract_database-0.0.0.1/src/abstract_database.egg-info/dependency_links.txt +1 -0
- abstract_database-0.0.0.1/src/abstract_database.egg-info/requires.txt +3 -0
- abstract_database-0.0.0.1/src/abstract_database.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include src/databases/*.db
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: abstract_database
|
|
3
|
+
Version: 0.0.0.1
|
|
4
|
+
Author: putkoff
|
|
5
|
+
Author-email: partners@abstractendeavors.com
|
|
6
|
+
Classifier: Development Status :: 3 - Alpha
|
|
7
|
+
Classifier: Intended Audience :: Developers
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Requires-Python: >=3.6
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: sqlalchemy
|
|
14
|
+
Requires-Dist: abstract_pandas
|
|
15
|
+
Requires-Dist: pandas
|
|
16
|
+
|
|
17
|
+
#magnets... how do they work? who invented them?
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#magnets... how do they work? who invented them?
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import setuptools
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
5
|
+
long_description = fh.read()
|
|
6
|
+
|
|
7
|
+
setuptools.setup(
|
|
8
|
+
name='abstract_database',
|
|
9
|
+
version='0.0.0.1',
|
|
10
|
+
author='putkoff',
|
|
11
|
+
author_email='partners@abstractendeavors.com',
|
|
12
|
+
description="",
|
|
13
|
+
long_description=long_description,
|
|
14
|
+
long_description_content_type='text/markdown',
|
|
15
|
+
classifiers=[
|
|
16
|
+
'Development Status :: 3 - Alpha',
|
|
17
|
+
'Intended Audience :: Developers',
|
|
18
|
+
'License :: OSI Approved :: MIT License',
|
|
19
|
+
'Programming Language :: Python :: 3',
|
|
20
|
+
'Programming Language :: Python :: 3.11',
|
|
21
|
+
],
|
|
22
|
+
install_requires=['sqlalchemy', 'abstract_pandas', 'pandas'],
|
|
23
|
+
package_dir={"": "src"},
|
|
24
|
+
packages=setuptools.find_packages(where="src"),
|
|
25
|
+
python_requires=">=3.6",
|
|
26
|
+
# Add this line to include wheel format in your distribution
|
|
27
|
+
setup_requires=['wheel'],
|
|
28
|
+
include_package_data=True, # Include package data specified in MANIFEST.in
|
|
29
|
+
|
|
30
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .abstract_database_cmd import *
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from sqlalchemy import create_engine, MetaData, Table, text, inspect, Column, String, Integer, Float
|
|
4
|
+
from sqlalchemy.orm import sessionmaker, declarative_base
|
|
5
|
+
from sqlalchemy.sql import column
|
|
6
|
+
def get_abs_path():
|
|
7
|
+
return os.path.abspath(__name__)
|
|
8
|
+
def get_abs_dir():
|
|
9
|
+
return os.path.dirname(get_abs_path())
|
|
10
|
+
def create_abs_path(path):
|
|
11
|
+
return os.path.join(get_abs_dir(),path)
|
|
12
|
+
def get_db_url(db_path):
|
|
13
|
+
db_url = f"sqlite:///{db_path}"
|
|
14
|
+
return db_url
|
|
15
|
+
class DatabaseBrowser:
|
|
16
|
+
def __init__(self, db_path):
|
|
17
|
+
self.db_url=get_db_url(db_path)
|
|
18
|
+
self.engine = create_engine(db_url)
|
|
19
|
+
self.Session = sessionmaker(bind=self.engine)
|
|
20
|
+
self.session = self.Session()
|
|
21
|
+
self.metadata = MetaData()
|
|
22
|
+
self.inspector = inspect(self.engine)
|
|
23
|
+
|
|
24
|
+
def list_tables(self):
|
|
25
|
+
"""List all tables in the database."""
|
|
26
|
+
tables = self.inspector.get_table_names()
|
|
27
|
+
print("Available tables:")
|
|
28
|
+
for idx, table in enumerate(tables):
|
|
29
|
+
print(f"{idx + 1}. {table}")
|
|
30
|
+
return tables
|
|
31
|
+
|
|
32
|
+
def list_columns(self, table_name):
|
|
33
|
+
"""List all columns in a table."""
|
|
34
|
+
try:
|
|
35
|
+
table = Table(table_name, self.metadata, autoload_with=self.engine)
|
|
36
|
+
columns = [column.name for column in table.columns]
|
|
37
|
+
print(f"Columns in {table_name}:")
|
|
38
|
+
for idx, column in enumerate(columns):
|
|
39
|
+
print(f"{idx + 1}. {column}")
|
|
40
|
+
return columns
|
|
41
|
+
except Exception as e:
|
|
42
|
+
print(f"Error loading table {table_name}: {e}")
|
|
43
|
+
return []
|
|
44
|
+
|
|
45
|
+
def view_table(self, table_name, start=0, end=5):
|
|
46
|
+
"""View a range of rows in a table."""
|
|
47
|
+
try:
|
|
48
|
+
table = Table(table_name, self.metadata, autoload_with=self.engine)
|
|
49
|
+
query = table.select().offset(start).limit(end - start)
|
|
50
|
+
result = self.session.execute(query)
|
|
51
|
+
rows = result.fetchall()
|
|
52
|
+
|
|
53
|
+
if rows:
|
|
54
|
+
df = pd.DataFrame(rows)
|
|
55
|
+
df.columns = result.keys()
|
|
56
|
+
# Set pandas options to display all rows and columns
|
|
57
|
+
pd.set_option('display.max_rows', None)
|
|
58
|
+
pd.set_option('display.max_columns', None)
|
|
59
|
+
pd.set_option('display.width', None)
|
|
60
|
+
pd.set_option('display.max_colwidth', None)
|
|
61
|
+
print(df)
|
|
62
|
+
# Reset pandas options to default
|
|
63
|
+
pd.reset_option('display.max_rows')
|
|
64
|
+
pd.reset_option('display.max_columns')
|
|
65
|
+
pd.reset_option('display.width')
|
|
66
|
+
pd.reset_option('display.max_colwidth')
|
|
67
|
+
else:
|
|
68
|
+
print(f"No data found in table {table_name} from row {start} to {end}")
|
|
69
|
+
except Exception as e:
|
|
70
|
+
print(f"Error viewing table {table_name}: {e}")
|
|
71
|
+
|
|
72
|
+
def search_table(self, table_name, column_name, search_value):
|
|
73
|
+
"""Search for a specific value in a table."""
|
|
74
|
+
try:
|
|
75
|
+
table = Table(table_name, self.metadata, autoload_with=self.engine)
|
|
76
|
+
except Exception as e:
|
|
77
|
+
print(f"Error loading table {table_name}: {e}")
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
if column_name not in [col.name for col in table.columns]:
|
|
81
|
+
print(f"Column {column_name} does not exist in table {table_name}.")
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
query = text(f"SELECT * FROM {table_name} WHERE {column_name} = :val")
|
|
86
|
+
result = self.session.execute(query, {"val": search_value})
|
|
87
|
+
rows = result.fetchall()
|
|
88
|
+
|
|
89
|
+
if rows:
|
|
90
|
+
df = pd.DataFrame(rows)
|
|
91
|
+
df.columns = result.keys()
|
|
92
|
+
print(df)
|
|
93
|
+
else:
|
|
94
|
+
print(f"No results found for {search_value} in {column_name} of {table_name}")
|
|
95
|
+
except Exception as e:
|
|
96
|
+
print(f"Error executing search query: {e}")
|
|
97
|
+
|
|
98
|
+
def alter_column_type(self, table_name, column_name, new_type):
|
|
99
|
+
"""Alter the type of a specific column in a table."""
|
|
100
|
+
if new_type not in ['String', 'Integer', 'Float']:
|
|
101
|
+
print("Invalid type. Please choose from 'String', 'Integer', or 'Float'.")
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
# Load the table
|
|
106
|
+
table = Table(table_name, self.metadata, autoload_with=self.engine)
|
|
107
|
+
old_column = table.c[column_name]
|
|
108
|
+
|
|
109
|
+
# Determine the new column type
|
|
110
|
+
if new_type == 'String':
|
|
111
|
+
new_column = Column(column_name, String, nullable=old_column.nullable)
|
|
112
|
+
elif new_type == 'Integer':
|
|
113
|
+
new_column = Column(column_name, Integer, nullable=old_column.nullable)
|
|
114
|
+
elif new_type == 'Float':
|
|
115
|
+
new_column = Column(column_name, Float, nullable=old_column.nullable)
|
|
116
|
+
|
|
117
|
+
# Perform the column type change
|
|
118
|
+
with self.engine.connect() as connection:
|
|
119
|
+
connection.execute(text(f"ALTER TABLE {table_name} RENAME COLUMN {column_name} TO {column_name}_old"))
|
|
120
|
+
connection.execute(text(f"ALTER TABLE {table_name} ADD COLUMN {column_name} {new_type}"))
|
|
121
|
+
connection.execute(text(f"UPDATE {table_name} SET {column_name} = {column_name}_old"))
|
|
122
|
+
connection.execute(text(f"ALTER TABLE {table_name} DROP COLUMN {column_name}_old"))
|
|
123
|
+
connection.commit()
|
|
124
|
+
|
|
125
|
+
print(f"Column {column_name} in table {table_name} successfully altered to {new_type}.")
|
|
126
|
+
except Exception as e:
|
|
127
|
+
print(f"Error altering column type: {e}")
|
|
128
|
+
|
|
129
|
+
def update_all_entries(self, table_name, column_name, new_value):
|
|
130
|
+
"""Update all entries in a specific column with a new value."""
|
|
131
|
+
try:
|
|
132
|
+
table = Table(table_name, self.metadata, autoload_with=self.engine)
|
|
133
|
+
query = table.update().values({column_name: new_value})
|
|
134
|
+
result = self.session.execute(query)
|
|
135
|
+
self.session.commit()
|
|
136
|
+
print(f"All entries in column {column_name} of table {table_name} updated to {new_value}.")
|
|
137
|
+
except Exception as e:
|
|
138
|
+
print(f"Error updating entries: {e}")
|
|
139
|
+
|
|
140
|
+
def export_data_by_zipcode(self, table_name, zipcode, file_path):
|
|
141
|
+
"""Export data from a specific zipcode to an Excel file."""
|
|
142
|
+
try:
|
|
143
|
+
query = text(f"SELECT * FROM {table_name} WHERE zipcode = :zipcode")
|
|
144
|
+
result = self.session.execute(query, {"zipcode": zipcode})
|
|
145
|
+
rows = result.fetchall()
|
|
146
|
+
|
|
147
|
+
if rows:
|
|
148
|
+
df = pd.DataFrame(rows)
|
|
149
|
+
df.columns = result.keys()
|
|
150
|
+
df.to_excel(file_path, index=False)
|
|
151
|
+
print(f"Data for zipcode {zipcode} exported to {file_path}")
|
|
152
|
+
else:
|
|
153
|
+
print(f"No data found for zipcode {zipcode} in table {table_name}")
|
|
154
|
+
except Exception as e:
|
|
155
|
+
print(f"Error exporting data: {e}")
|
|
156
|
+
|
|
157
|
+
def get_integer_input(self, prompt, min_value, max_value):
|
|
158
|
+
"""Get an integer input from the user within a specified range."""
|
|
159
|
+
while True:
|
|
160
|
+
try:
|
|
161
|
+
value = int(input(f"{prompt} ({min_value}-{max_value}): "))
|
|
162
|
+
if min_value <= value <= max_value:
|
|
163
|
+
return value
|
|
164
|
+
else:
|
|
165
|
+
print(f"Please enter a number between {min_value} and {max_value}.")
|
|
166
|
+
except ValueError:
|
|
167
|
+
print("Invalid input. Please enter a valid number.")
|
|
168
|
+
|
|
169
|
+
def main(self):
|
|
170
|
+
while True:
|
|
171
|
+
print("\nMenu:")
|
|
172
|
+
print("0. Exit")
|
|
173
|
+
print("1. List tables")
|
|
174
|
+
print("2. Search table")
|
|
175
|
+
print("3. View table contents")
|
|
176
|
+
print("4. List columns in a table")
|
|
177
|
+
print("5. Alter column type")
|
|
178
|
+
print("6. Update all entries in a column")
|
|
179
|
+
print("7. Export data by zipcode")
|
|
180
|
+
|
|
181
|
+
choice = input("Enter your choice: ")
|
|
182
|
+
|
|
183
|
+
if choice == "0":
|
|
184
|
+
logging.info("Exiting the program")
|
|
185
|
+
print("Exiting...")
|
|
186
|
+
break
|
|
187
|
+
elif choice == "1":
|
|
188
|
+
self.list_tables()
|
|
189
|
+
elif choice == "2":
|
|
190
|
+
tables = self.list_tables()
|
|
191
|
+
if not tables:
|
|
192
|
+
continue
|
|
193
|
+
table_choice = self.get_integer_input("Choose a table", 1, len(tables)) - 1
|
|
194
|
+
table_name = tables[table_choice]
|
|
195
|
+
columns = self.list_columns(table_name)
|
|
196
|
+
if not columns:
|
|
197
|
+
continue
|
|
198
|
+
column_choice = self.get_integer_input("Choose a column", 1, len(columns)) - 1
|
|
199
|
+
column_name = columns[column_choice]
|
|
200
|
+
search_value = input(f"Enter value to search for in {column_name}: ")
|
|
201
|
+
self.search_table(table_name, column_name, search_value)
|
|
202
|
+
elif choice == "3":
|
|
203
|
+
tables = self.list_tables()
|
|
204
|
+
if not tables:
|
|
205
|
+
continue
|
|
206
|
+
table_choice = self.get_integer_input("Choose a table", 1, len(tables)) - 1
|
|
207
|
+
table_name = tables[table_choice]
|
|
208
|
+
table_row_count = self.session.execute(text(f"SELECT COUNT(*) FROM {table_name}")).scalar()
|
|
209
|
+
start = self.get_integer_input(f"Enter start row (0-{table_row_count - 1})", 0, table_row_count - 1)
|
|
210
|
+
end = self.get_integer_input(f"Enter end row ({start + 1}-{table_row_count})", start + 1, table_row_count)
|
|
211
|
+
self.view_table(table_name, start, end)
|
|
212
|
+
elif choice == "4":
|
|
213
|
+
tables = self.list_tables()
|
|
214
|
+
if not tables:
|
|
215
|
+
continue
|
|
216
|
+
table_choice = self.get_integer_input("Choose a table", 1, len(tables)) - 1
|
|
217
|
+
table_name = tables[table_choice]
|
|
218
|
+
self.list_columns(table_name)
|
|
219
|
+
elif choice == "5":
|
|
220
|
+
tables = self.list_tables()
|
|
221
|
+
if not tables:
|
|
222
|
+
continue
|
|
223
|
+
table_choice = self.get_integer_input("Choose a table", 1, len(tables)) - 1
|
|
224
|
+
table_name = tables[table_choice]
|
|
225
|
+
columns = self.list_columns(table_name)
|
|
226
|
+
if not columns:
|
|
227
|
+
continue
|
|
228
|
+
column_choice = self.get_integer_input("Choose a column", 1, len(columns)) - 1
|
|
229
|
+
column_name = columns[column_choice]
|
|
230
|
+
new_type = input("Enter new type (String, Integer, Float): ")
|
|
231
|
+
self.alter_column_type(table_name, column_name, new_type)
|
|
232
|
+
elif choice == "6":
|
|
233
|
+
tables = self.list_tables()
|
|
234
|
+
if not tables:
|
|
235
|
+
continue
|
|
236
|
+
table_choice = self.get_integer_input("Choose a table", 1, len(tables)) - 1
|
|
237
|
+
table_name = tables[table_choice]
|
|
238
|
+
columns = self.list_columns(table_name)
|
|
239
|
+
if not columns:
|
|
240
|
+
continue
|
|
241
|
+
column_choice = self.get_integer_input("Choose a column", 1, len(columns)) - 1
|
|
242
|
+
column_name = columns[column_choice]
|
|
243
|
+
new_value = input(f"Enter new value for all entries in {column_name}: ")
|
|
244
|
+
self.update_all_entries(table_name, column_name, new_value)
|
|
245
|
+
elif choice == "7":
|
|
246
|
+
tables = self.list_tables()
|
|
247
|
+
if not tables:
|
|
248
|
+
continue
|
|
249
|
+
table_choice = self.get_integer_input("Choose a table", 1, len(tables)) - 1
|
|
250
|
+
table_name = tables[table_choice]
|
|
251
|
+
zipcode = input("Enter the zipcode to filter by: ")
|
|
252
|
+
file_path = input("Enter the file path to save the Excel file: ")
|
|
253
|
+
self.export_data_by_zipcode(table_name, zipcode, file_path)
|
|
254
|
+
else:
|
|
255
|
+
print("Invalid choice. Please try again.")
|
|
256
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: abstract_database
|
|
3
|
+
Version: 0.0.0.1
|
|
4
|
+
Author: putkoff
|
|
5
|
+
Author-email: partners@abstractendeavors.com
|
|
6
|
+
Classifier: Development Status :: 3 - Alpha
|
|
7
|
+
Classifier: Intended Audience :: Developers
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Requires-Python: >=3.6
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: sqlalchemy
|
|
14
|
+
Requires-Dist: abstract_pandas
|
|
15
|
+
Requires-Dist: pandas
|
|
16
|
+
|
|
17
|
+
#magnets... how do they work? who invented them?
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
MANIFEST.in
|
|
2
|
+
README.md
|
|
3
|
+
setup.py
|
|
4
|
+
src/abstract_database/__init__.py
|
|
5
|
+
src/abstract_database/abstract_database_cmd.py
|
|
6
|
+
src/abstract_database/directory_mgr.py
|
|
7
|
+
src/abstract_database.egg-info/PKG-INFO
|
|
8
|
+
src/abstract_database.egg-info/SOURCES.txt
|
|
9
|
+
src/abstract_database.egg-info/dependency_links.txt
|
|
10
|
+
src/abstract_database.egg-info/requires.txt
|
|
11
|
+
src/abstract_database.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
abstract_database
|