dynamic-tables 0.1.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.
@@ -0,0 +1,5 @@
1
+ # __init__.py
2
+ from .dynamic_tables import DynamicTables
3
+
4
+
5
+
@@ -0,0 +1,224 @@
1
+ # this is dynamic_tables.py
2
+
3
+ import psycopg2, re
4
+ from psycopg2 import sql
5
+
6
+ class DynamicTables:
7
+
8
+ def __init__(self):
9
+ """Initialize the class by calling self.initialize() to set up default values."""
10
+ self.initialize()
11
+
12
+ def initialize(self):
13
+ """Sets up default attributes for the table structure."""
14
+ self.column_list = []
15
+ self.column_dynamic = ''
16
+ self.table_prefix = 'dtbl_'
17
+ self.table_name_dynamic = ''
18
+
19
+ def connection_open(self, dbname, user, password, host):
20
+ """Opens a connection to the PostgreSQL database and initializes the cursor."""
21
+ self.conn = psycopg2.connect(
22
+ dbname=dbname,
23
+ user=user,
24
+ password=password,
25
+ host=host
26
+ )
27
+ self.cur = self.conn.cursor()
28
+
29
+ def connectHC(self, dbname, user, password, host):
30
+ """Helper function to open a connection using hardcoded credentials."""
31
+ self.connection_open(dbname, user, password, host)
32
+
33
+ def connectJSON(self):
34
+ """Opens a database connection using credentials from a JSON config file."""
35
+ import json
36
+ with open("config.json") as config_file:
37
+ config = json.load(config_file)
38
+ self.conn = psycopg2.connect(**config)
39
+ self.cur = self.conn.cursor()
40
+
41
+ def connectENVS(self):
42
+ """Opens a database connection using environment variables."""
43
+ import os
44
+ self.conn = psycopg2.connect(
45
+ host=os.getenv("DTABLES_ENVS_PGSQL_HOST"),
46
+ user=os.getenv("DTABLES_ENVS_PGSQL_USER"),
47
+ password=os.getenv("DTABLES_ENVS_PGSQL_PASSWORD"),
48
+ database=os.getenv("DTABLES_ENVS_PGSQL_DATABASE")
49
+ )
50
+ self.cur = self.conn.cursor()
51
+
52
+ def connection_close(self):
53
+ """Closes the database cursor and connection."""
54
+ self.cur.close()
55
+ self.conn.close()
56
+
57
+ def close(self):
58
+ """Alias for connection_close() to improve readability."""
59
+ self.connection_close()
60
+
61
+ def format_table_name(self, input_column):
62
+ """Formats an input column name to create a valid table name."""
63
+ cleaned = re.sub(r'[^a-zA-Z0-9_]', '', input_column)
64
+ return self.table_prefix + cleaned
65
+
66
+ def input(self, *args):
67
+ """Handles data insertion by dynamically determining the table name and inserting values."""
68
+ column_dict = {}
69
+ self.table_name_dynamic = ''
70
+
71
+ for column_number, (column_name, _) in enumerate(self.column_list):
72
+ if column_name == self.column_dynamic:
73
+ self.table_name_dynamic = self.format_table_name(args[column_number])
74
+ column_dict[column_name] = args[column_number]
75
+ else:
76
+ column_dict[column_name] = args[column_number]
77
+
78
+ if self.table_name_dynamic:
79
+ self.create_table(self.table_name_dynamic, self.column_list)
80
+
81
+ self.insert_data(self.table_name_dynamic, column_dict)
82
+
83
+ def insert_data(self, table_name, data_dict):
84
+ """Inserts data into a dynamically created table."""
85
+ columns = data_dict.keys()
86
+ values = list(data_dict.values())
87
+
88
+ query = sql.SQL("""
89
+ INSERT INTO {} ({})
90
+ VALUES ({});
91
+ """).format(
92
+ sql.Identifier(table_name),
93
+ sql.SQL(', ').join(map(sql.Identifier, columns)),
94
+ sql.SQL(', ').join(sql.Placeholder() for _ in columns)
95
+ )
96
+
97
+ self.cur.execute(query, values)
98
+ self.conn.commit()
99
+
100
+ def create_table(self, table_name, columns):
101
+ """Creates a table dynamically if it does not already exist."""
102
+ column_definitions = sql.SQL(", ").join(
103
+ sql.SQL("{} {}").format(sql.Identifier(col_name), sql.SQL(col_type))
104
+ for col_name, col_type in columns
105
+ )
106
+
107
+ query = sql.SQL("""
108
+ CREATE TABLE IF NOT EXISTS {} (
109
+ id SERIAL PRIMARY KEY,
110
+ {}
111
+ );
112
+ """).format(sql.Identifier(table_name), column_definitions)
113
+
114
+ self.cur.execute(query)
115
+ self.conn.commit()
116
+
117
+ def show_db(self):
118
+ """Lists all available databases."""
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."""
138
+ try:
139
+ query = sql.SQL("""
140
+ SELECT column_name, data_type
141
+ FROM information_schema.columns
142
+ WHERE table_name = %s
143
+ ORDER BY ordinal_position;
144
+ """)
145
+ self.cur.execute(query, (table_name,))
146
+ columns = self.cur.fetchall()
147
+
148
+ if columns:
149
+ print(f"Columns in table '{table_name}':")
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}")
156
+
157
+ def show_columns_all(self):
158
+ """Lists column details for all tables."""
159
+ self.cur.execute("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';")
160
+ for table in self.cur.fetchall():
161
+ self.show_columns(table[0])
162
+
163
+ def select_table(self, table_name):
164
+ """Retrieves and prints all rows from the specified table."""
165
+ query = sql.SQL("SELECT * FROM {}").format(sql.Identifier(table_name))
166
+ self.cur.execute(query)
167
+ rows = self.cur.fetchall()
168
+
169
+ if rows:
170
+ for row in rows:
171
+ print(f"Row: {row}")
172
+ else:
173
+ print(f"Table '{table_name}' exists but has no data.")
174
+
175
+ return rows
176
+
177
+ def delete_tables(self):
178
+ """Deletes all tables that match the current table prefix."""
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,))
186
+
187
+ tables = self.cur.fetchall()
188
+ print("DEBUG - Found tables to delete:", tables) # Debugging output
189
+
190
+ for table in tables:
191
+ table_name = table[0]
192
+ print(f"Dropping table: {table_name}")
193
+
194
+ drop_query = sql.SQL("DROP TABLE IF EXISTS {} CASCADE;").format(sql.Identifier(table_name))
195
+ self.cur.execute(drop_query)
196
+
197
+ self.conn.commit()
198
+
199
+ def set_columns(self, input_columns):
200
+ """Sets the columns for table creation based on user input."""
201
+ self.column_list = []
202
+ for column in input_columns.split(','):
203
+ column = column.strip()
204
+ parts = column.split(maxsplit=1)
205
+ if len(parts) == 2:
206
+ self.column_list.append((parts[0], parts[1]))
207
+ else:
208
+ print(f"Invalid column format: '{column}'")
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
217
+
218
+ def status(self):
219
+ """Displays the currently configured column settings."""
220
+ print('\nConfigured Columns:')
221
+ for column in self.column_list:
222
+ print(column)
223
+ print('\nDynamic Column:\n', self.column_dynamic, '\n')
224
+
File without changes
@@ -0,0 +1,139 @@
1
+ Metadata-Version: 2.1
2
+ Name: dynamic-tables
3
+ Version: 0.1.0
4
+ Summary: A dynamic table creation and management library for PostgreSQL
5
+ Home-page: https://github.com/scottrodeo/dynamic_tables
6
+ Author: Scott Rodeo
7
+ Author-email: signcactus@gmail.com
8
+ License: UNKNOWN
9
+ Project-URL: Author Website, https://patreon.com/scottrodeo
10
+ Platform: UNKNOWN
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.6
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: psycopg2
17
+
18
+ # Dynamic Tables (Python)
19
+ A Python library for dynamically creating and managing PostgreSQL tables based on input data.
20
+
21
+ ## 🚀 Features
22
+ - Automatically creates tables based on incoming data.
23
+ - Supports dynamic naming conventions.
24
+ - Provides easy database connectivity with PostgreSQL.
25
+ - Includes helper functions for querying and deleting tables.
26
+
27
+ ---
28
+
29
+ ## 📥 Installation
30
+ ### **1️⃣ Install via GitHub (Recommended for Development)**
31
+ Clone the repository and install in editable mode:
32
+ ```bash
33
+ git clone https://github.com/scottrodeo/dynamic-tables-python.git
34
+ cd dynamic-tables-python
35
+ pip install -e .
36
+ ```
37
+
38
+ ### **2️⃣ Install Directly via `pip`**
39
+ The package is available on PyPI, you can install it with:
40
+ ```bash
41
+ pip install dynamic-tables
42
+ ```
43
+
44
+ ---
45
+
46
+ ## 🏃‍♂️ Running the Example
47
+ ### **1️⃣ Quick Run (Without Installation)**
48
+ If you don't want to install the package, you can directly run the example script:
49
+ ```bash
50
+ python3 examples/example.py
51
+ ```
52
+ 💡 *This works because the script dynamically adjusts `sys.path`.*
53
+
54
+ ### **2️⃣ Recommended (After Installation)**
55
+ If you've installed the package (`pip install -e .`), simply run:
56
+ ```bash
57
+ python3 examples/example.py
58
+ ```
59
+
60
+ ---
61
+
62
+ ## 📌 Example Usage
63
+ Once installed, you can use `dynamic_tables` in your Python scripts:
64
+
65
+ ```python
66
+ from dynamic_tables import DynamicTables
67
+
68
+ # Initialize the dynamic table manager
69
+ tables = DynamicTables()
70
+
71
+ # Example: Creating and inserting data dynamically
72
+ tables.set_table_prefix("dtbl_")
73
+ tables.set_columns("domain TEXT, category TEXT, lang TEXT")
74
+ tables.set_dynamic_column("domain")
75
+
76
+ tables.input("wikipedia.org", "cats", "en")
77
+ tables.input("wikipedia.org", "dogs", "en")
78
+
79
+ # Show all tables
80
+ tables.show_tables()
81
+ ```
82
+
83
+ ---
84
+
85
+ ## 🛠️ Available Functions
86
+ | Function | Description |
87
+ |----------|-------------|
88
+ | `set_columns("name TYPE, age TYPE")` | Define table schema |
89
+ | `set_table_prefix("prefix_")` | Set a custom table prefix |
90
+ | `set_dynamic_column("column_name")` | Set the column that determines dynamic table names |
91
+ | `input(value1, value2, ...)` | Insert a new row dynamically |
92
+ | `show_tables()` | List all dynamically created tables |
93
+ | `show_columns("table_name")` | Show column details for a specific table |
94
+ | `select_table("table_name")` | Retrieve all rows from a table |
95
+ | `delete_tables()` | Drop all tables matching the prefix |
96
+
97
+ ---
98
+
99
+ ## ⚡ Development
100
+ ### **Running Tests**
101
+ To run the test suite:
102
+ ```bash
103
+ pytest tests/
104
+ ```
105
+
106
+ ### **Linting**
107
+ Ensure your code follows best practices:
108
+ ```bash
109
+ flake8 dynamic_tables/
110
+ ```
111
+
112
+ ---
113
+
114
+ ## 🤝 Contributing
115
+ Contributions are welcome! If you'd like to improve `dynamic_tables`, follow these steps:
116
+ 1. Fork the repository.
117
+ 2. Create a new branch (`git checkout -b feature-branch`).
118
+ 3. Commit your changes (`git commit -m "Added new feature"`).
119
+ 4. Push to the branch (`git push origin feature-branch`).
120
+ 5. Open a pull request.
121
+
122
+ ---
123
+
124
+ ## 📄 License
125
+ This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.
126
+
127
+ ---
128
+
129
+ ## 🌎 Links
130
+ - **GitHub Repository:** [Dynamic Tables (Python)](https://github.com/scottrodeo/dynamic-tables-python)
131
+ - **Documentation:** *(To be added)*
132
+ - **Issue Tracker:** [Report Issues](https://github.com/scottrodeo/dynamic-tables-python/issues)
133
+
134
+ ---
135
+
136
+ ### **🚀 Happy Coding!**
137
+
138
+
139
+
@@ -0,0 +1,7 @@
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.0.dist-info/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ dynamic_tables-0.1.0.dist-info/METADATA,sha256=bDLWlQXC8f8ujUdOBUwRORJBqduQeS0mw_ruF4L6oKo,3871
5
+ dynamic_tables-0.1.0.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
6
+ dynamic_tables-0.1.0.dist-info/top_level.txt,sha256=IUnttnbuTiMp4f8hXorriWorV8twRB535pDm0yI6c3w,15
7
+ dynamic_tables-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.34.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ dynamic_tables