dynamic-tables 0.1.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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