dynamic-tables 0.1.1__py3-none-any.whl → 0.2.0__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.
- dynamic_tables/dynamic_tables.py +235 -123
- dynamic_tables-0.2.0.dist-info/LICENSE +22 -0
- {dynamic_tables-0.1.1.dist-info → dynamic_tables-0.2.0.dist-info}/METADATA +46 -18
- dynamic_tables-0.2.0.dist-info/RECORD +7 -0
- dynamic_tables-0.1.1.dist-info/LICENSE +0 -0
- dynamic_tables-0.1.1.dist-info/RECORD +0 -7
- {dynamic_tables-0.1.1.dist-info → dynamic_tables-0.2.0.dist-info}/WHEEL +0 -0
- {dynamic_tables-0.1.1.dist-info → dynamic_tables-0.2.0.dist-info}/top_level.txt +0 -0
dynamic_tables/dynamic_tables.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# this is dynamic_tables.py
|
2
2
|
|
3
|
-
import psycopg2, re
|
3
|
+
import psycopg2, re, logging
|
4
4
|
from psycopg2 import sql
|
5
5
|
|
6
6
|
class DynamicTables:
|
@@ -15,7 +15,70 @@ class DynamicTables:
|
|
15
15
|
self.column_dynamic = ''
|
16
16
|
self.table_prefix = 'dtbl_'
|
17
17
|
self.table_name_dynamic = ''
|
18
|
+
self.version = '0.1.2'
|
19
|
+
"""Initialize with default logging level (CRITICAL) and no file logging."""
|
20
|
+
self.log_file_handler = None
|
21
|
+
self.setup_logging(level=logging.CRITICAL, log_to_file=False)
|
22
|
+
|
23
|
+
def setup_logging(self, level=logging.CRITICAL, log_to_file=False):
|
24
|
+
"""
|
25
|
+
Configures logging level and optionally enables file logging.
|
26
|
+
|
27
|
+
Args:
|
28
|
+
level (int): Logging level (e.g., logging.DEBUG, logging.INFO).
|
29
|
+
log_to_file (bool): Enable or disable file logging.
|
30
|
+
"""
|
31
|
+
logging.basicConfig(
|
32
|
+
level=level,
|
33
|
+
format="%(asctime)s [%(levelname)s] %(message)s",
|
34
|
+
handlers=[logging.StreamHandler()] # Console only by default
|
35
|
+
)
|
36
|
+
|
37
|
+
# Enable file logging if requested
|
38
|
+
if log_to_file and not self.log_file_handler:
|
39
|
+
self.log_file_handler = logging.FileHandler("dynamic_tables.log")
|
40
|
+
self.log_file_handler.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(message)s"))
|
41
|
+
logging.getLogger().addHandler(self.log_file_handler)
|
42
|
+
|
43
|
+
# Disable file logging if requested
|
44
|
+
elif not log_to_file and self.log_file_handler:
|
45
|
+
logging.getLogger().removeHandler(self.log_file_handler)
|
46
|
+
self.log_file_handler.close()
|
47
|
+
self.log_file_handler = None
|
48
|
+
|
49
|
+
logging.info(f"Logging level set to {logging.getLevelName(level)}")
|
50
|
+
if log_to_file:
|
51
|
+
logging.info("File logging enabled (dynamic_tables.log)")
|
52
|
+
|
53
|
+
def change_log_level(self, level_name):
|
54
|
+
"""
|
55
|
+
Change the logging level at runtime.
|
56
|
+
Args:
|
57
|
+
level_name (str): "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
|
58
|
+
"""
|
59
|
+
level = getattr(logging, level_name.upper(), logging.CRITICAL)
|
60
|
+
logging.getLogger().setLevel(level)
|
61
|
+
logging.info(f"Log level changed to {level_name.upper()}")
|
62
|
+
|
63
|
+
def set_columns(self, input_columns):
|
64
|
+
"""Sets the columns for table creation based on user input."""
|
65
|
+
self.column_list = []
|
66
|
+
for column in input_columns.split(','):
|
67
|
+
column = column.strip()
|
68
|
+
parts = column.split(maxsplit=1)
|
69
|
+
if len(parts) == 2:
|
70
|
+
self.column_list.append((parts[0], parts[1]))
|
71
|
+
else:
|
72
|
+
logging.warning(f"Invalid column format: '{column}'")
|
73
|
+
|
74
|
+
def set_table_prefix(self, input_prefix):
|
75
|
+
"""Defines a custom table name prefix."""
|
76
|
+
self.table_prefix = input_prefix
|
18
77
|
|
78
|
+
def set_dynamic_column(self, input_column):
|
79
|
+
"""Sets the column that determines dynamic table names."""
|
80
|
+
self.column_dynamic = input_column
|
81
|
+
|
19
82
|
def connection_open(self, dbname, user, password, host):
|
20
83
|
"""Opens a connection to the PostgreSQL database and initializes the cursor."""
|
21
84
|
self.conn = psycopg2.connect(
|
@@ -26,28 +89,29 @@ class DynamicTables:
|
|
26
89
|
)
|
27
90
|
self.cur = self.conn.cursor()
|
28
91
|
|
29
|
-
def connectHC(self,
|
92
|
+
def connectHC(self, database, user, password, host):
|
30
93
|
"""Helper function to open a connection using hardcoded credentials."""
|
31
|
-
self.connection_open(
|
94
|
+
self.connection_open(database, user, password, host)
|
32
95
|
|
33
|
-
def connectJSON(self):
|
96
|
+
def connectJSON(self, config_path="config.json"):
|
34
97
|
"""Opens a database connection using credentials from a JSON config file."""
|
35
98
|
import json
|
36
|
-
with open(
|
99
|
+
with open(config_path) as config_file:
|
37
100
|
config = json.load(config_file)
|
38
|
-
|
39
|
-
|
101
|
+
database=config["database"]
|
102
|
+
user=config["user"]
|
103
|
+
password=config["password"]
|
104
|
+
host=config["host"]
|
105
|
+
self.connection_open(database, user, password, host)
|
40
106
|
|
41
107
|
def connectENVS(self):
|
42
108
|
"""Opens a database connection using environment variables."""
|
43
109
|
import os
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
)
|
50
|
-
self.cur = self.conn.cursor()
|
110
|
+
database=os.getenv("DTABLES_ENVS_PGSQL_DATABASE")
|
111
|
+
user=os.getenv("DTABLES_ENVS_PGSQL_USER")
|
112
|
+
password=os.getenv("DTABLES_ENVS_PGSQL_PASSWORD")
|
113
|
+
host=os.getenv("DTABLES_ENVS_PGSQL_HOST")
|
114
|
+
self.connection_open(database, user, password, host)
|
51
115
|
|
52
116
|
def connection_close(self):
|
53
117
|
"""Closes the database cursor and connection."""
|
@@ -58,28 +122,120 @@ class DynamicTables:
|
|
58
122
|
"""Alias for connection_close() to improve readability."""
|
59
123
|
self.connection_close()
|
60
124
|
|
61
|
-
def
|
62
|
-
"""
|
63
|
-
|
64
|
-
|
125
|
+
def get_tables(self):
|
126
|
+
"""Returns a list of all table names in the public schema."""
|
127
|
+
try:
|
128
|
+
self.cur.execute("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';")
|
129
|
+
tables = self.cur.fetchall()
|
130
|
+
|
131
|
+
if tables:
|
132
|
+
table_list = [table[0] for table in tables] # Convert to a simple list of table names
|
133
|
+
logging.info(f"Found {len(table_list)} tables.")
|
134
|
+
logging.debug(f"Tables: {table_list}")
|
135
|
+
return table_list
|
136
|
+
else:
|
137
|
+
logging.info("No tables found.")
|
138
|
+
return [] # Empty list instead of None for consistency
|
65
139
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
self.table_name_dynamic = ''
|
140
|
+
except Exception as e:
|
141
|
+
logging.error(f"Error retrieving tables: {e}", exc_info=True)
|
142
|
+
return None
|
70
143
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
144
|
+
def get_columns(self, table_name):
|
145
|
+
"""Returns a list of all columns and their data types for a given table."""
|
146
|
+
try:
|
147
|
+
query = sql.SQL("""
|
148
|
+
SELECT column_name, data_type
|
149
|
+
FROM information_schema.columns
|
150
|
+
WHERE table_name = %s
|
151
|
+
ORDER BY ordinal_position;
|
152
|
+
""")
|
153
|
+
self.cur.execute(query, (table_name,))
|
154
|
+
columns = self.cur.fetchall()
|
155
|
+
|
156
|
+
if columns:
|
157
|
+
logging.info(f"Retrieved {len(columns)} columns from '{table_name}'.")
|
158
|
+
return columns
|
75
159
|
else:
|
76
|
-
|
160
|
+
logging.warning(f"No columns found for table '{table_name}' or the table does not exist.")
|
161
|
+
return []
|
77
162
|
|
78
|
-
|
79
|
-
|
163
|
+
except Exception as e:
|
164
|
+
logging.error(f"Error retrieving columns for '{table_name}': {e}", exc_info=True)
|
165
|
+
return None
|
80
166
|
|
81
|
-
|
167
|
+
def get_table_rows(self, table_name):
|
168
|
+
"""Retrieves all rows from the specified table and returns them."""
|
169
|
+
try:
|
170
|
+
query = sql.SQL("SELECT * FROM {}").format(sql.Identifier(table_name))
|
171
|
+
self.cur.execute(query)
|
172
|
+
rows = self.cur.fetchall()
|
173
|
+
|
174
|
+
if rows:
|
175
|
+
logging.info(f"Retrieved {len(rows)} rows from '{table_name}'.")
|
176
|
+
logging.debug(f"Rows from '{table_name}': {rows}")
|
177
|
+
return rows # Returns data for other functions
|
178
|
+
else:
|
179
|
+
logging.info(f"Table '{table_name}' exists but has no data.")
|
180
|
+
return []
|
181
|
+
|
182
|
+
except Exception as e:
|
183
|
+
logging.error(f"Error retrieving rows from '{table_name}': {e}", exc_info=True)
|
184
|
+
return None
|
185
|
+
|
186
|
+
def show_db(self):
|
187
|
+
"""Displays the name of the current database."""
|
188
|
+
self.cur.execute("SELECT current_database();")
|
189
|
+
db_name = self.cur.fetchone()[0]
|
190
|
+
logging.info(f"Connected to database: {db_name}")
|
191
|
+
|
192
|
+
def show_tables(self):
|
193
|
+
"""Prints a list of all table names (uses get_tables)."""
|
194
|
+
tables = self.get_tables()
|
195
|
+
|
196
|
+
if tables:
|
197
|
+
print("Tables in the database:")
|
198
|
+
for table in tables:
|
199
|
+
print(f" - {table}")
|
200
|
+
else:
|
201
|
+
print("No tables found or an error occurred.")
|
82
202
|
|
203
|
+
def show_columns(self, table_name):
|
204
|
+
"""Prints column details for human readability (uses get_columns)."""
|
205
|
+
columns = self.get_columns(table_name)
|
206
|
+
|
207
|
+
if columns:
|
208
|
+
print(f"Columns in '{table_name}':")
|
209
|
+
for name, dtype in columns:
|
210
|
+
print(f" - {name}: {dtype}")
|
211
|
+
else:
|
212
|
+
print(f"No columns found for '{table_name}' or the table does not exist.")
|
213
|
+
|
214
|
+
def show_columns_all(self):
|
215
|
+
"""Lists column details for all tables."""
|
216
|
+
self.cur.execute("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';")
|
217
|
+
for table in self.cur.fetchall():
|
218
|
+
self.show_columns(table[0])
|
219
|
+
|
220
|
+
def show_table(self, table_name):
|
221
|
+
"""Displays all rows from the specified table (uses get_table_rows)."""
|
222
|
+
rows = self.get_table_rows(table_name)
|
223
|
+
|
224
|
+
if rows:
|
225
|
+
print(f"Rows in '{table_name}':")
|
226
|
+
for row in rows:
|
227
|
+
print(f" - {row}")
|
228
|
+
else:
|
229
|
+
print(f"Table '{table_name}' exists but has no data or an error occurred.")
|
230
|
+
|
231
|
+
def show_version(self):
|
232
|
+
"""Show the current software version"""
|
233
|
+
print(self.version)
|
234
|
+
|
235
|
+
def select_table(self, table_name):
|
236
|
+
"""Retrieves and prints all rows from the specified table."""
|
237
|
+
self.show_table(table_name)
|
238
|
+
|
83
239
|
def insert_data(self, table_name, data_dict):
|
84
240
|
"""Inserts data into a dynamically created table."""
|
85
241
|
columns = data_dict.keys()
|
@@ -114,111 +270,67 @@ class DynamicTables:
|
|
114
270
|
self.cur.execute(query)
|
115
271
|
self.conn.commit()
|
116
272
|
|
117
|
-
def
|
118
|
-
"""
|
119
|
-
self.cur.execute("SELECT datname FROM pg_database WHERE datistemplate = false;")
|
120
|
-
for row in self.cur.fetchall():
|
121
|
-
print(row)
|
122
|
-
|
123
|
-
def show_tables(self):
|
124
|
-
"""Fetch and return a list of all table names."""
|
125
|
-
self.cur.execute("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';")
|
126
|
-
tables = self.cur.fetchall()
|
127
|
-
|
128
|
-
if tables:
|
129
|
-
table_list = [table[0] for table in tables] # Convert to a simple list of table names
|
130
|
-
print("\n".join(table_list)) # Print for debugging
|
131
|
-
return table_list
|
132
|
-
else:
|
133
|
-
print("No tables found.")
|
134
|
-
return [] # Return an empty list instead of None
|
135
|
-
|
136
|
-
def show_columns(self, table_name):
|
137
|
-
"""Displays all columns and their data types for a given table."""
|
273
|
+
def delete_tables(self):
|
274
|
+
"""Deletes all tables that match the current table prefix."""
|
138
275
|
try:
|
139
|
-
query =
|
140
|
-
SELECT
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
""
|
145
|
-
self.cur.execute(query, (table_name,))
|
146
|
-
columns = self.cur.fetchall()
|
276
|
+
query = """
|
277
|
+
SELECT table_name FROM information_schema.tables
|
278
|
+
WHERE table_schema = 'public' AND table_name LIKE %s;
|
279
|
+
"""
|
280
|
+
prefix_pattern = self.table_prefix + "%" # Dynamic prefix
|
281
|
+
logging.debug(f"Prefix pattern: {prefix_pattern}")
|
147
282
|
|
148
|
-
|
149
|
-
|
150
|
-
for column_name, data_type in columns:
|
151
|
-
print(f" - {column_name}: {data_type}")
|
152
|
-
else:
|
153
|
-
print(f"No columns found for table '{table_name}' or the table does not exist.")
|
154
|
-
except Exception as e:
|
155
|
-
print(f"Error retrieving columns for '{table_name}': {e}")
|
283
|
+
self.cur.execute(query, (prefix_pattern,))
|
284
|
+
tables = self.cur.fetchall()
|
156
285
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
for table in self.cur.fetchall():
|
161
|
-
self.show_columns(table[0])
|
286
|
+
if tables:
|
287
|
+
logging.info(f"Found {len(tables)} tables to delete.")
|
288
|
+
logging.debug(f"Tables to delete: {tables}")
|
162
289
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
self.cur.execute(query)
|
167
|
-
rows = self.cur.fetchall()
|
290
|
+
for table in tables:
|
291
|
+
table_name = table[0]
|
292
|
+
logging.info(f"Dropping table: {table_name}")
|
168
293
|
|
169
|
-
|
170
|
-
|
171
|
-
print(f"Row: {row}")
|
172
|
-
else:
|
173
|
-
print(f"Table '{table_name}' exists but has no data.")
|
294
|
+
drop_query = sql.SQL("DROP TABLE IF EXISTS {} CASCADE;").format(sql.Identifier(table_name))
|
295
|
+
self.cur.execute(drop_query)
|
174
296
|
|
175
|
-
|
297
|
+
self.conn.commit()
|
298
|
+
logging.info("Successfully deleted matching tables.")
|
299
|
+
else:
|
300
|
+
logging.info("No tables found matching the prefix.")
|
176
301
|
|
177
|
-
|
178
|
-
|
179
|
-
query = """
|
180
|
-
SELECT table_name FROM information_schema.tables
|
181
|
-
WHERE table_schema = 'public' AND table_name LIKE %s;
|
182
|
-
"""
|
183
|
-
prefix_pattern = self.table_prefix + "%" # Dynamic prefix
|
184
|
-
print("prefix_pattern:" + prefix_pattern) # Debugging output
|
185
|
-
self.cur.execute(query, (prefix_pattern,))
|
302
|
+
except Exception as e:
|
303
|
+
logging.error(f"Error deleting tables: {e}", exc_info=True)
|
186
304
|
|
187
|
-
|
188
|
-
|
305
|
+
def status(self):
|
306
|
+
"""Logs the currently configured column settings."""
|
307
|
+
if self.column_list:
|
308
|
+
logging.info("Configured Columns:")
|
309
|
+
for column in self.column_list:
|
310
|
+
logging.info(f" - {column}")
|
311
|
+
else:
|
312
|
+
logging.info("No columns configured.")
|
189
313
|
|
190
|
-
|
191
|
-
table_name = table[0]
|
192
|
-
print(f"Dropping table: {table_name}")
|
314
|
+
logging.info(f"Dynamic Column: {self.column_dynamic if self.column_dynamic else 'None'}")
|
193
315
|
|
194
|
-
|
195
|
-
|
316
|
+
def format_table_name(self, input_column):
|
317
|
+
"""Formats an input column name to create a valid table name."""
|
318
|
+
cleaned = re.sub(r'[^a-zA-Z0-9_]', '', input_column)
|
319
|
+
return self.table_prefix + cleaned
|
196
320
|
|
197
|
-
|
321
|
+
def input(self, *args):
|
322
|
+
"""Handles data insertion by dynamically determining the table name and inserting values."""
|
323
|
+
column_dict = {}
|
324
|
+
self.table_name_dynamic = ''
|
198
325
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
column = column.strip()
|
204
|
-
parts = column.split(maxsplit=1)
|
205
|
-
if len(parts) == 2:
|
206
|
-
self.column_list.append((parts[0], parts[1]))
|
326
|
+
for column_number, (column_name, _) in enumerate(self.column_list):
|
327
|
+
if column_name == self.column_dynamic:
|
328
|
+
self.table_name_dynamic = self.format_table_name(args[column_number])
|
329
|
+
column_dict[column_name] = args[column_number]
|
207
330
|
else:
|
208
|
-
|
209
|
-
|
210
|
-
def set_table_prefix(self, input_prefix):
|
211
|
-
"""Defines a custom table name prefix."""
|
212
|
-
self.table_prefix = input_prefix
|
213
|
-
|
214
|
-
def set_dynamic_column(self, input_column):
|
215
|
-
"""Sets the column that determines dynamic table names."""
|
216
|
-
self.column_dynamic = input_column
|
331
|
+
column_dict[column_name] = args[column_number]
|
217
332
|
|
218
|
-
|
219
|
-
|
220
|
-
print('\nConfigured Columns:')
|
221
|
-
for column in self.column_list:
|
222
|
-
print(column)
|
223
|
-
print('\nDynamic Column:\n', self.column_dynamic, '\n')
|
333
|
+
if self.table_name_dynamic:
|
334
|
+
self.create_table(self.table_name_dynamic, self.column_list)
|
224
335
|
|
336
|
+
self.insert_data(self.table_name_dynamic, column_dict)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dynamic-tables
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
4
4
|
Summary: A dynamic table creation and management library for PostgreSQL
|
5
5
|
Home-page: https://github.com/scottrodeo/dynamic-tables-python
|
6
6
|
Author: Scott Rodeo
|
@@ -15,8 +15,11 @@ Description-Content-Type: text/markdown
|
|
15
15
|
Requires-Dist: psycopg2
|
16
16
|
|
17
17
|
# Dynamic Tables (Python)
|
18
|
+
|
18
19
|
A Python library for dynamically creating and managing PostgreSQL tables based on input data.
|
19
20
|
|
21
|
+
---
|
22
|
+
|
20
23
|
## 🚀 Features
|
21
24
|
- Automatically creates tables based on incoming data.
|
22
25
|
- Supports dynamic naming conventions.
|
@@ -26,16 +29,19 @@ A Python library for dynamically creating and managing PostgreSQL tables based o
|
|
26
29
|
---
|
27
30
|
|
28
31
|
## 📥 Installation
|
29
|
-
|
32
|
+
|
33
|
+
### 1️⃣ Install via GitHub (Recommended for Development)
|
30
34
|
Clone the repository and install in editable mode:
|
35
|
+
|
31
36
|
```bash
|
32
37
|
git clone https://github.com/scottrodeo/dynamic-tables-python.git
|
33
38
|
cd dynamic-tables-python
|
34
39
|
pip install -e .
|
35
40
|
```
|
36
41
|
|
37
|
-
###
|
38
|
-
The package is available on PyPI,
|
42
|
+
### 2️⃣ Install Directly via `pip`
|
43
|
+
The package is available on PyPI, install it with:
|
44
|
+
|
39
45
|
```bash
|
40
46
|
pip install dynamic-tables
|
41
47
|
```
|
@@ -43,22 +49,21 @@ pip install dynamic-tables
|
|
43
49
|
---
|
44
50
|
|
45
51
|
## 🏃♂️ Running the Example
|
46
|
-
|
47
|
-
|
52
|
+
|
53
|
+
### 1️⃣ Quick Run (Without Installation)
|
54
|
+
Run the example script directly:
|
55
|
+
|
48
56
|
```bash
|
49
57
|
python3 examples/example.py
|
50
58
|
```
|
59
|
+
|
51
60
|
💡 *This works because the script dynamically adjusts `sys.path`.*
|
52
61
|
|
53
|
-
### **2️⃣ Recommended (After Installation)**
|
54
|
-
If you've installed the package (`pip install -e .`), simply run:
|
55
|
-
```bash
|
56
|
-
python3 examples/example.py
|
57
|
-
```
|
58
62
|
|
59
63
|
---
|
60
64
|
|
61
65
|
## 📌 Example Usage
|
66
|
+
|
62
67
|
Once installed, you can use `dynamic_tables` in your Python scripts:
|
63
68
|
|
64
69
|
```python
|
@@ -67,11 +72,12 @@ from dynamic_tables import DynamicTables
|
|
67
72
|
# Initialize the dynamic table manager
|
68
73
|
tables = DynamicTables()
|
69
74
|
|
70
|
-
#
|
75
|
+
# Configure dynamic table properties
|
71
76
|
tables.set_table_prefix("dtbl_")
|
72
77
|
tables.set_columns("domain TEXT, category TEXT, lang TEXT")
|
73
78
|
tables.set_dynamic_column("domain")
|
74
79
|
|
80
|
+
# Insert dynamic data
|
75
81
|
tables.input("wikipedia.org", "cats", "en")
|
76
82
|
tables.input("wikipedia.org", "dogs", "en")
|
77
83
|
|
@@ -82,6 +88,7 @@ tables.show_tables()
|
|
82
88
|
---
|
83
89
|
|
84
90
|
## 🛠️ Available Functions
|
91
|
+
|
85
92
|
| Function | Description |
|
86
93
|
|----------|-------------|
|
87
94
|
| `set_columns("name TYPE, age TYPE")` | Define table schema |
|
@@ -90,20 +97,39 @@ tables.show_tables()
|
|
90
97
|
| `input(value1, value2, ...)` | Insert a new row dynamically |
|
91
98
|
| `show_tables()` | List all dynamically created tables |
|
92
99
|
| `show_columns("table_name")` | Show column details for a specific table |
|
100
|
+
| `show_columns_all()` | Show column details for all tables |
|
93
101
|
| `select_table("table_name")` | Retrieve all rows from a table |
|
94
102
|
| `delete_tables()` | Drop all tables matching the prefix |
|
103
|
+
| `create_table("table_name", [("column1", "TYPE"), ("column2", "TYPE")])` | Create a table dynamically |
|
104
|
+
| `insert_data("table_name", {"column1": value1, "column2": value2})` | Insert data into a specific table |
|
105
|
+
| `get_tables()` | Retrieve a list of all tables in the database |
|
106
|
+
| `get_columns("table_name")` | Retrieve all columns for a given table |
|
107
|
+
| `get_table_rows("table_name")` | Retrieve all rows from a table |
|
108
|
+
| `connectHC("dbname", "user", "password", "host")` | Connect using hardcoded credentials |
|
109
|
+
| `connectJSON("config.json")` | Connect using credentials from a JSON config file |
|
110
|
+
| `connectENVS()` | Connect using environment variables |
|
111
|
+
| `connection_open("dbname", "user", "password", "host")` | Open a PostgreSQL database connection |
|
112
|
+
| `connection_close()` | Close the database connection |
|
113
|
+
| `status()` | Show the current configuration status |
|
114
|
+
| `show_db()` | Display the connected database name |
|
115
|
+
| `setup_logging(level, log_to_file)` | Configure logging settings |
|
116
|
+
| `change_log_level("LEVEL")` | Change the logging level at runtime |
|
117
|
+
| `show_version()` | Display the current version of the library |
|
95
118
|
|
96
119
|
---
|
97
120
|
|
98
121
|
## ⚡ Development
|
99
|
-
|
100
|
-
|
122
|
+
|
123
|
+
### Running Tests
|
124
|
+
Run the test suite:
|
125
|
+
|
101
126
|
```bash
|
102
127
|
pytest tests/
|
103
128
|
```
|
104
129
|
|
105
|
-
###
|
130
|
+
### Linting
|
106
131
|
Ensure your code follows best practices:
|
132
|
+
|
107
133
|
```bash
|
108
134
|
flake8 dynamic_tables/
|
109
135
|
```
|
@@ -111,7 +137,8 @@ flake8 dynamic_tables/
|
|
111
137
|
---
|
112
138
|
|
113
139
|
## 🤝 Contributing
|
114
|
-
|
140
|
+
|
141
|
+
Contributions are welcome! To contribute:
|
115
142
|
1. Fork the repository.
|
116
143
|
2. Create a new branch (`git checkout -b feature-branch`).
|
117
144
|
3. Commit your changes (`git commit -m "Added new feature"`).
|
@@ -121,18 +148,19 @@ Contributions are welcome! If you'd like to improve `dynamic_tables`, follow the
|
|
121
148
|
---
|
122
149
|
|
123
150
|
## 📄 License
|
151
|
+
|
124
152
|
This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.
|
125
153
|
|
126
154
|
---
|
127
155
|
|
128
156
|
## 🌎 Links
|
157
|
+
|
129
158
|
- **GitHub Repository:** [Dynamic Tables (Python)](https://github.com/scottrodeo/dynamic-tables-python)
|
130
|
-
- **Documentation:** *(To be added)*
|
131
159
|
- **Issue Tracker:** [Report Issues](https://github.com/scottrodeo/dynamic-tables-python/issues)
|
132
160
|
|
133
161
|
---
|
134
162
|
|
135
|
-
###
|
163
|
+
### 🚀 Happy Coding!
|
136
164
|
|
137
165
|
|
138
166
|
|
@@ -0,0 +1,7 @@
|
|
1
|
+
dynamic_tables/__init__.py,sha256=ttyVGUaIlALPqpfaHS3jX6CqLPoPfwvE-eFU_1ly4eY,59
|
2
|
+
dynamic_tables/dynamic_tables.py,sha256=ciBbvj6EVimTsBX-_BePHo-XjItxpH8KIB_OAAMMvCc,13018
|
3
|
+
dynamic_tables-0.2.0.dist-info/LICENSE,sha256=Vi3cItkblr6fZwGbNlp_HnBaMFwXSWYPkrVQLXX3LCs,1057
|
4
|
+
dynamic_tables-0.2.0.dist-info/METADATA,sha256=BNqat1kOqOcEjaW58r5A_Um6VC8l44s3-u3z6gVkIDk,4711
|
5
|
+
dynamic_tables-0.2.0.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
|
6
|
+
dynamic_tables-0.2.0.dist-info/top_level.txt,sha256=IUnttnbuTiMp4f8hXorriWorV8twRB535pDm0yI6c3w,15
|
7
|
+
dynamic_tables-0.2.0.dist-info/RECORD,,
|
File without changes
|
@@ -1,7 +0,0 @@
|
|
1
|
-
dynamic_tables/__init__.py,sha256=ttyVGUaIlALPqpfaHS3jX6CqLPoPfwvE-eFU_1ly4eY,59
|
2
|
-
dynamic_tables/dynamic_tables.py,sha256=y34xTOCxfYN0YLe82aq1zUqpdNoAcZ06kdE21EvxB_o,8298
|
3
|
-
dynamic_tables-0.1.1.dist-info/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
-
dynamic_tables-0.1.1.dist-info/METADATA,sha256=dIkcf9wNnr4A4xT9EpNVCH_NcUtriRsVnk-POy8hJIw,3818
|
5
|
-
dynamic_tables-0.1.1.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
|
6
|
-
dynamic_tables-0.1.1.dist-info/top_level.txt,sha256=IUnttnbuTiMp4f8hXorriWorV8twRB535pDm0yI6c3w,15
|
7
|
-
dynamic_tables-0.1.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|