dynamic-tables 0.1.0__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.
@@ -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, dbname, user, password, host):
92
+ def connectHC(self, database, user, password, host):
30
93
  """Helper function to open a connection using hardcoded credentials."""
31
- self.connection_open(dbname, user, password, host)
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("config.json") as config_file:
99
+ with open(config_path) as config_file:
37
100
  config = json.load(config_file)
38
- self.conn = psycopg2.connect(**config)
39
- self.cur = self.conn.cursor()
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
- 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()
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 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
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
- 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 = ''
140
+ except Exception as e:
141
+ logging.error(f"Error retrieving tables: {e}", exc_info=True)
142
+ return None
70
143
 
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]
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
- column_dict[column_name] = args[column_number]
160
+ logging.warning(f"No columns found for table '{table_name}' or the table does not exist.")
161
+ return []
77
162
 
78
- if self.table_name_dynamic:
79
- self.create_table(self.table_name_dynamic, self.column_list)
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
- self.insert_data(self.table_name_dynamic, column_dict)
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 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."""
273
+ def delete_tables(self):
274
+ """Deletes all tables that match the current table prefix."""
138
275
  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()
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
- 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}")
283
+ self.cur.execute(query, (prefix_pattern,))
284
+ tables = self.cur.fetchall()
156
285
 
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])
286
+ if tables:
287
+ logging.info(f"Found {len(tables)} tables to delete.")
288
+ logging.debug(f"Tables to delete: {tables}")
162
289
 
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()
290
+ for table in tables:
291
+ table_name = table[0]
292
+ logging.info(f"Dropping table: {table_name}")
168
293
 
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.")
294
+ drop_query = sql.SQL("DROP TABLE IF EXISTS {} CASCADE;").format(sql.Identifier(table_name))
295
+ self.cur.execute(drop_query)
174
296
 
175
- return rows
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
- 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,))
302
+ except Exception as e:
303
+ logging.error(f"Error deleting tables: {e}", exc_info=True)
186
304
 
187
- tables = self.cur.fetchall()
188
- print("DEBUG - Found tables to delete:", tables) # Debugging output
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
- for table in tables:
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
- drop_query = sql.SQL("DROP TABLE IF EXISTS {} CASCADE;").format(sql.Identifier(table_name))
195
- self.cur.execute(drop_query)
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
- self.conn.commit()
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
- 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]))
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
- 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
331
+ column_dict[column_name] = args[column_number]
217
332
 
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')
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,12 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dynamic-tables
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: A dynamic table creation and management library for PostgreSQL
5
- Home-page: https://github.com/scottrodeo/dynamic_tables
5
+ Home-page: https://github.com/scottrodeo/dynamic-tables-python
6
6
  Author: Scott Rodeo
7
7
  Author-email: signcactus@gmail.com
8
8
  License: UNKNOWN
9
- Project-URL: Author Website, https://patreon.com/scottrodeo
10
9
  Platform: UNKNOWN
11
10
  Classifier: Programming Language :: Python :: 3
12
11
  Classifier: License :: OSI Approved :: MIT License
@@ -16,8 +15,11 @@ Description-Content-Type: text/markdown
16
15
  Requires-Dist: psycopg2
17
16
 
18
17
  # Dynamic Tables (Python)
18
+
19
19
  A Python library for dynamically creating and managing PostgreSQL tables based on input data.
20
20
 
21
+ ---
22
+
21
23
  ## 🚀 Features
22
24
  - Automatically creates tables based on incoming data.
23
25
  - Supports dynamic naming conventions.
@@ -27,16 +29,19 @@ A Python library for dynamically creating and managing PostgreSQL tables based o
27
29
  ---
28
30
 
29
31
  ## 📥 Installation
30
- ### **1️⃣ Install via GitHub (Recommended for Development)**
32
+
33
+ ### 1️⃣ Install via GitHub (Recommended for Development)
31
34
  Clone the repository and install in editable mode:
35
+
32
36
  ```bash
33
37
  git clone https://github.com/scottrodeo/dynamic-tables-python.git
34
38
  cd dynamic-tables-python
35
39
  pip install -e .
36
40
  ```
37
41
 
38
- ### **2️⃣ Install Directly via `pip`**
39
- The package is available on PyPI, you can install it with:
42
+ ### 2️⃣ Install Directly via `pip`
43
+ The package is available on PyPI, install it with:
44
+
40
45
  ```bash
41
46
  pip install dynamic-tables
42
47
  ```
@@ -44,22 +49,21 @@ pip install dynamic-tables
44
49
  ---
45
50
 
46
51
  ## 🏃‍♂️ 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:
52
+
53
+ ### 1️⃣ Quick Run (Without Installation)
54
+ Run the example script directly:
55
+
49
56
  ```bash
50
57
  python3 examples/example.py
51
58
  ```
59
+
52
60
  💡 *This works because the script dynamically adjusts `sys.path`.*
53
61
 
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
62
 
60
63
  ---
61
64
 
62
65
  ## 📌 Example Usage
66
+
63
67
  Once installed, you can use `dynamic_tables` in your Python scripts:
64
68
 
65
69
  ```python
@@ -68,11 +72,12 @@ from dynamic_tables import DynamicTables
68
72
  # Initialize the dynamic table manager
69
73
  tables = DynamicTables()
70
74
 
71
- # Example: Creating and inserting data dynamically
75
+ # Configure dynamic table properties
72
76
  tables.set_table_prefix("dtbl_")
73
77
  tables.set_columns("domain TEXT, category TEXT, lang TEXT")
74
78
  tables.set_dynamic_column("domain")
75
79
 
80
+ # Insert dynamic data
76
81
  tables.input("wikipedia.org", "cats", "en")
77
82
  tables.input("wikipedia.org", "dogs", "en")
78
83
 
@@ -83,6 +88,7 @@ tables.show_tables()
83
88
  ---
84
89
 
85
90
  ## 🛠️ Available Functions
91
+
86
92
  | Function | Description |
87
93
  |----------|-------------|
88
94
  | `set_columns("name TYPE, age TYPE")` | Define table schema |
@@ -91,20 +97,39 @@ tables.show_tables()
91
97
  | `input(value1, value2, ...)` | Insert a new row dynamically |
92
98
  | `show_tables()` | List all dynamically created tables |
93
99
  | `show_columns("table_name")` | Show column details for a specific table |
100
+ | `show_columns_all()` | Show column details for all tables |
94
101
  | `select_table("table_name")` | Retrieve all rows from a table |
95
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 |
96
118
 
97
119
  ---
98
120
 
99
121
  ## ⚡ Development
100
- ### **Running Tests**
101
- To run the test suite:
122
+
123
+ ### Running Tests
124
+ Run the test suite:
125
+
102
126
  ```bash
103
127
  pytest tests/
104
128
  ```
105
129
 
106
- ### **Linting**
130
+ ### Linting
107
131
  Ensure your code follows best practices:
132
+
108
133
  ```bash
109
134
  flake8 dynamic_tables/
110
135
  ```
@@ -112,7 +137,8 @@ flake8 dynamic_tables/
112
137
  ---
113
138
 
114
139
  ## 🤝 Contributing
115
- Contributions are welcome! If you'd like to improve `dynamic_tables`, follow these steps:
140
+
141
+ Contributions are welcome! To contribute:
116
142
  1. Fork the repository.
117
143
  2. Create a new branch (`git checkout -b feature-branch`).
118
144
  3. Commit your changes (`git commit -m "Added new feature"`).
@@ -122,18 +148,19 @@ Contributions are welcome! If you'd like to improve `dynamic_tables`, follow the
122
148
  ---
123
149
 
124
150
  ## 📄 License
151
+
125
152
  This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.
126
153
 
127
154
  ---
128
155
 
129
156
  ## 🌎 Links
157
+
130
158
  - **GitHub Repository:** [Dynamic Tables (Python)](https://github.com/scottrodeo/dynamic-tables-python)
131
- - **Documentation:** *(To be added)*
132
159
  - **Issue Tracker:** [Report Issues](https://github.com/scottrodeo/dynamic-tables-python/issues)
133
160
 
134
161
  ---
135
162
 
136
- ### **🚀 Happy Coding!**
163
+ ### 🚀 Happy Coding!
137
164
 
138
165
 
139
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.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,,