Module geode.lib.database.filesystem
Expand source code
# ------------------------------------------------------------------------------
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
# ------------------------------------------------------------------------------
# Geode
from geode.lib.common import CommonPath, CommonConfiguration
# ------------------------------------------------------------------------------
# Class
# ------------------------------------------------------------------------------
class FileSystemDatabase(CommonPath):
def __init__(self, *paths, extension="ini", mkdir=False, **kwargs):
""" Constructor
Parameters
----------
paths : tuple
Represents database directory paths on filesystem based of str or
pathlib.Path values.
extension : str, optional
Extension used to mark database file (Default: ini).
mkdir : bool, optional
Generate the database directory when the path not exists and the
value is True, raises an exception otherwise (Default: False).
kwargs : dict, optional
Positional arguments used by pathlib.Path.mkdir method.
See Also
--------
pathlib.Path.mkdir : Create a new directoy at the specified path.
Raises
------
NotADirectoryError
When the specified path is not a directory.
FileNotFoundError
When the specified path not exists and mkdir flag is set to False.
"""
CommonPath.__init__(self, *paths)
if self.path.exists() and not self.path.is_dir():
raise NotADirectoryError(
f"Specified path '{self.path}' is not a directory")
if not self.path.exists():
if not mkdir:
raise FileNotFoundError(
f"Cannot found '{self.path}' directory on filesystem")
self.path.mkdir(**kwargs)
if type(extension) is not str:
raise TypeError(f"File extension needs to be a str, "
f"not a {type(extension).__name__}")
self.__extension = extension
# Keep table files based on filename without extension as keys
self.__tables = dict()
def __get_table(self, table):
""" Retrieve a specific table from local cache
Parameters
----------
table : str
Table name to find in local cache.
Returns
-------
geode.lib.common.CommonConfiguration
Table object
Raises
------
TypeError
When the specified table name type is not a str.
FileNotFoundError
When the specified table name is not in local cache.
"""
if type(table) is not str:
raise TypeError(
f"Table name needs to be a str, not a {type(table).__name__}")
if table not in self.__tables.keys():
raise FileNotFoundError(
f"Cannot found table '{table}' in database folder")
return self.__tables[table]
def read(self):
""" Read and retrieve available files in database directory
Files are retrieving from the 'extension' attribute set in object
constructor.
Raises
------
FileNotFoundError
When the database directory was not found on filesystem.
"""
if not self.exists():
raise FileNotFoundError(
f"Cannot found '{self.path}' directory on filesystem")
for filepath in self.path.glob(f"*.{self.__extension}"):
self.__tables[filepath.stem] = CommonConfiguration(filepath)
def rename_table(self, table, new_name):
""" Rename a specific table
Parameters
----------
table : str
Table name to find in local cache.
new_name : str
New table name.
Returns
-------
geode.lib.common.CommonConfiguration
Renamed database object.
Raises
------
TypeError
When the specified new table name type is not a str.
FileExistsError
When the specified new table name was already used by another
database file on filesystem.
"""
table_object = self.__get_table(table)
if type(new_name) is not str:
raise TypeError(f"New table name needs to be a str, "
f"not a {type(new_name).__name__}")
filepath = self.path.joinpath(f"{new_name}.{self.__extension}")
if filepath.exists():
raise FileExistsError(f"Cannot use '{new_name}' as new table name "
f"since this name is already taken")
table_object.path.rename(filepath)
self.__tables[new_name] = table_object
del self.__tables[table]
return table_object
def create_table(self, table):
""" Create a new table from a specific name
Parameters
----------
table : str
Table name.
Returns
-------
geode.lib.common.CommonConfiguration
Created database object.
Raises
------
TypeError
When the specified table name type is not a str.
FileExistsError
When the specified table name is already used by another database
file.
"""
if type(table) is not str:
raise TypeError(
f"Table name needs to be a str, not a {type(table).__name__}")
if table in self.__tables.keys():
raise FileExistsError(
f"Table '{table}' already exists in database folder")
filepath = self.path.joinpath(f"{table}.{self.__extension}")
table_object = CommonConfiguration(filepath)
table_object.write()
self.__tables[filepath.stem] = table_object
return table_object
def drop_table(self, table):
""" Drop a specific table
Parameters
----------
table : str
Table name to find in local cache.
Raises
------
TypeError
When the specified table name type is not a str.
FileNotFoundError
When the specified table name cannot be found in database
directory.
"""
if type(table) is not str:
raise TypeError(
f"Table name needs to be a str, not a {type(table).__name__}")
if table not in self.__tables.keys():
raise FileNotFoundError(
f"Table '{table}' did not exists and cannot be removed")
table_object = self.__get_table(table)
table_object.path.unlink()
del table_object, self.__tables[table]
def delete(self, table, row):
""" Delete a specific row from specified table
Parameters
----------
table : str
Table name to find in local cache.
row : str
Raises
------
TypeError
When the specified row identifier type is not a str.
KeyError
When the specified row identifier did not exists in table object.
"""
table_object = self.__get_table(table)
if type(row) is not str:
raise TypeError(f"Row identifier needs to be a str, "
f"not a {type(row).__name__}")
if not table_object.has_section(row):
raise KeyError(f"Cannot update row '{row}' since this one did not "
f"exists in table '{table}'")
table_object.remove_section(row)
table_object.write()
def select(self, table, *rows):
""" Select specific rows from specified table
Parameters
----------
table : str
Table name to find in local cache.
rows : tuple of str, optional
Rows identifiers to check in founded table object (Default: all).
Returns
-------
dict
Founded rows from specified table with row identifier as keys.
"""
table_object = self.__get_table(table)
if not rows:
rows = table_object.sections()
results = dict()
for row in rows:
if type(row) is not str:
raise TypeError(f"Row identifier needs to be a str, "
f"not a {type(row).__name__}")
if not table_object.has_section(row):
continue
results[row] = dict(table_object.items(row))
return results
def insert(self, table, row, **data):
""" Insert a new row in specified table
Parameters
----------
table : str
Table name to find in local cache.
row : str
Row identifier key to check in founded table object.
data : dict
Row data.
Raises
------
TypeError
When the specified row identifier type is not a str.
ValueError
When the specified row identifier already exists in table object.
"""
table_object = self.__get_table(table)
if type(row) is not str:
raise TypeError(f"Row identifier needs to be a str, "
f"not a {type(row).__name__}")
if table_object.has_section(row):
raise ValueError(f"Cannot insert row '{row}' since this one "
f"already exists in table '{table}'")
table_object.add_section(row)
try:
for key, value in data.items():
table_object.set(row, key, value)
table_object.write()
except TypeError as error:
table_object.remove_section(row)
raise TypeError(error)
def update(self, table, row, **data):
""" Update a specific row in specified table
Parameters
----------
table : str
Table name to find in local cache.
row : str
Row identifier key to check in founded table object.
data : dict
New row data.
Raises
------
TypeError
When the specified row identifier type is not a str.
KeyError
When the specified row identifier did not exists in table object.
"""
if type(row) is not str:
raise TypeError(f"Row identifier needs to be a str, "
f"not a {type(row).__name__}")
table_object = self.__get_table(table)
if not table_object.has_section(row):
raise KeyError(f"Cannot update row '{row}' since this one did not "
f"exists in table '{table}'")
for key, value in data.items():
table_object.set(row, key, value)
table_object.write()
Classes
class FileSystemDatabase (*paths, extension='ini', mkdir=False, **kwargs)
-
Constructor
Parameters
paths
:tuple
- Represents database directory paths on filesystem based of str or pathlib.Path values.
extension
:str
, optional- Extension used to mark database file (Default: ini).
mkdir
:bool
, optional- Generate the database directory when the path not exists and the value is True, raises an exception otherwise (Default: False).
kwargs
:dict
, optional- Positional arguments used by pathlib.Path.mkdir method.
See Also
pathlib.Path.mkdir
- Create a new directoy at the specified path.
Raises
NotADirectoryError
- When the specified path is not a directory.
FileNotFoundError
- When the specified path not exists and mkdir flag is set to False.
Expand source code
class FileSystemDatabase(CommonPath): def __init__(self, *paths, extension="ini", mkdir=False, **kwargs): """ Constructor Parameters ---------- paths : tuple Represents database directory paths on filesystem based of str or pathlib.Path values. extension : str, optional Extension used to mark database file (Default: ini). mkdir : bool, optional Generate the database directory when the path not exists and the value is True, raises an exception otherwise (Default: False). kwargs : dict, optional Positional arguments used by pathlib.Path.mkdir method. See Also -------- pathlib.Path.mkdir : Create a new directoy at the specified path. Raises ------ NotADirectoryError When the specified path is not a directory. FileNotFoundError When the specified path not exists and mkdir flag is set to False. """ CommonPath.__init__(self, *paths) if self.path.exists() and not self.path.is_dir(): raise NotADirectoryError( f"Specified path '{self.path}' is not a directory") if not self.path.exists(): if not mkdir: raise FileNotFoundError( f"Cannot found '{self.path}' directory on filesystem") self.path.mkdir(**kwargs) if type(extension) is not str: raise TypeError(f"File extension needs to be a str, " f"not a {type(extension).__name__}") self.__extension = extension # Keep table files based on filename without extension as keys self.__tables = dict() def __get_table(self, table): """ Retrieve a specific table from local cache Parameters ---------- table : str Table name to find in local cache. Returns ------- geode.lib.common.CommonConfiguration Table object Raises ------ TypeError When the specified table name type is not a str. FileNotFoundError When the specified table name is not in local cache. """ if type(table) is not str: raise TypeError( f"Table name needs to be a str, not a {type(table).__name__}") if table not in self.__tables.keys(): raise FileNotFoundError( f"Cannot found table '{table}' in database folder") return self.__tables[table] def read(self): """ Read and retrieve available files in database directory Files are retrieving from the 'extension' attribute set in object constructor. Raises ------ FileNotFoundError When the database directory was not found on filesystem. """ if not self.exists(): raise FileNotFoundError( f"Cannot found '{self.path}' directory on filesystem") for filepath in self.path.glob(f"*.{self.__extension}"): self.__tables[filepath.stem] = CommonConfiguration(filepath) def rename_table(self, table, new_name): """ Rename a specific table Parameters ---------- table : str Table name to find in local cache. new_name : str New table name. Returns ------- geode.lib.common.CommonConfiguration Renamed database object. Raises ------ TypeError When the specified new table name type is not a str. FileExistsError When the specified new table name was already used by another database file on filesystem. """ table_object = self.__get_table(table) if type(new_name) is not str: raise TypeError(f"New table name needs to be a str, " f"not a {type(new_name).__name__}") filepath = self.path.joinpath(f"{new_name}.{self.__extension}") if filepath.exists(): raise FileExistsError(f"Cannot use '{new_name}' as new table name " f"since this name is already taken") table_object.path.rename(filepath) self.__tables[new_name] = table_object del self.__tables[table] return table_object def create_table(self, table): """ Create a new table from a specific name Parameters ---------- table : str Table name. Returns ------- geode.lib.common.CommonConfiguration Created database object. Raises ------ TypeError When the specified table name type is not a str. FileExistsError When the specified table name is already used by another database file. """ if type(table) is not str: raise TypeError( f"Table name needs to be a str, not a {type(table).__name__}") if table in self.__tables.keys(): raise FileExistsError( f"Table '{table}' already exists in database folder") filepath = self.path.joinpath(f"{table}.{self.__extension}") table_object = CommonConfiguration(filepath) table_object.write() self.__tables[filepath.stem] = table_object return table_object def drop_table(self, table): """ Drop a specific table Parameters ---------- table : str Table name to find in local cache. Raises ------ TypeError When the specified table name type is not a str. FileNotFoundError When the specified table name cannot be found in database directory. """ if type(table) is not str: raise TypeError( f"Table name needs to be a str, not a {type(table).__name__}") if table not in self.__tables.keys(): raise FileNotFoundError( f"Table '{table}' did not exists and cannot be removed") table_object = self.__get_table(table) table_object.path.unlink() del table_object, self.__tables[table] def delete(self, table, row): """ Delete a specific row from specified table Parameters ---------- table : str Table name to find in local cache. row : str Raises ------ TypeError When the specified row identifier type is not a str. KeyError When the specified row identifier did not exists in table object. """ table_object = self.__get_table(table) if type(row) is not str: raise TypeError(f"Row identifier needs to be a str, " f"not a {type(row).__name__}") if not table_object.has_section(row): raise KeyError(f"Cannot update row '{row}' since this one did not " f"exists in table '{table}'") table_object.remove_section(row) table_object.write() def select(self, table, *rows): """ Select specific rows from specified table Parameters ---------- table : str Table name to find in local cache. rows : tuple of str, optional Rows identifiers to check in founded table object (Default: all). Returns ------- dict Founded rows from specified table with row identifier as keys. """ table_object = self.__get_table(table) if not rows: rows = table_object.sections() results = dict() for row in rows: if type(row) is not str: raise TypeError(f"Row identifier needs to be a str, " f"not a {type(row).__name__}") if not table_object.has_section(row): continue results[row] = dict(table_object.items(row)) return results def insert(self, table, row, **data): """ Insert a new row in specified table Parameters ---------- table : str Table name to find in local cache. row : str Row identifier key to check in founded table object. data : dict Row data. Raises ------ TypeError When the specified row identifier type is not a str. ValueError When the specified row identifier already exists in table object. """ table_object = self.__get_table(table) if type(row) is not str: raise TypeError(f"Row identifier needs to be a str, " f"not a {type(row).__name__}") if table_object.has_section(row): raise ValueError(f"Cannot insert row '{row}' since this one " f"already exists in table '{table}'") table_object.add_section(row) try: for key, value in data.items(): table_object.set(row, key, value) table_object.write() except TypeError as error: table_object.remove_section(row) raise TypeError(error) def update(self, table, row, **data): """ Update a specific row in specified table Parameters ---------- table : str Table name to find in local cache. row : str Row identifier key to check in founded table object. data : dict New row data. Raises ------ TypeError When the specified row identifier type is not a str. KeyError When the specified row identifier did not exists in table object. """ if type(row) is not str: raise TypeError(f"Row identifier needs to be a str, " f"not a {type(row).__name__}") table_object = self.__get_table(table) if not table_object.has_section(row): raise KeyError(f"Cannot update row '{row}' since this one did not " f"exists in table '{table}'") for key, value in data.items(): table_object.set(row, key, value) table_object.write()
Ancestors
Methods
def create_table(self, table)
-
Create a new table from a specific name
Parameters
table
:str
- Table name.
Returns
CommonConfiguration
- Created database object.
Raises
TypeError
- When the specified table name type is not a str.
FileExistsError
- When the specified table name is already used by another database file.
Expand source code
def create_table(self, table): """ Create a new table from a specific name Parameters ---------- table : str Table name. Returns ------- geode.lib.common.CommonConfiguration Created database object. Raises ------ TypeError When the specified table name type is not a str. FileExistsError When the specified table name is already used by another database file. """ if type(table) is not str: raise TypeError( f"Table name needs to be a str, not a {type(table).__name__}") if table in self.__tables.keys(): raise FileExistsError( f"Table '{table}' already exists in database folder") filepath = self.path.joinpath(f"{table}.{self.__extension}") table_object = CommonConfiguration(filepath) table_object.write() self.__tables[filepath.stem] = table_object return table_object
def delete(self, table, row)
-
Delete a specific row from specified table
Parameters
table
:str
- Table name to find in local cache.
row
:str
Raises
TypeError
- When the specified row identifier type is not a str.
KeyError
- When the specified row identifier did not exists in table object.
Expand source code
def delete(self, table, row): """ Delete a specific row from specified table Parameters ---------- table : str Table name to find in local cache. row : str Raises ------ TypeError When the specified row identifier type is not a str. KeyError When the specified row identifier did not exists in table object. """ table_object = self.__get_table(table) if type(row) is not str: raise TypeError(f"Row identifier needs to be a str, " f"not a {type(row).__name__}") if not table_object.has_section(row): raise KeyError(f"Cannot update row '{row}' since this one did not " f"exists in table '{table}'") table_object.remove_section(row) table_object.write()
def drop_table(self, table)
-
Drop a specific table
Parameters
table
:str
- Table name to find in local cache.
Raises
TypeError
- When the specified table name type is not a str.
FileNotFoundError
- When the specified table name cannot be found in database directory.
Expand source code
def drop_table(self, table): """ Drop a specific table Parameters ---------- table : str Table name to find in local cache. Raises ------ TypeError When the specified table name type is not a str. FileNotFoundError When the specified table name cannot be found in database directory. """ if type(table) is not str: raise TypeError( f"Table name needs to be a str, not a {type(table).__name__}") if table not in self.__tables.keys(): raise FileNotFoundError( f"Table '{table}' did not exists and cannot be removed") table_object = self.__get_table(table) table_object.path.unlink() del table_object, self.__tables[table]
def insert(self, table, row, **data)
-
Insert a new row in specified table
Parameters
table
:str
- Table name to find in local cache.
row
:str
- Row identifier key to check in founded table object.
data
:dict
- Row data.
Raises
TypeError
- When the specified row identifier type is not a str.
ValueError
- When the specified row identifier already exists in table object.
Expand source code
def insert(self, table, row, **data): """ Insert a new row in specified table Parameters ---------- table : str Table name to find in local cache. row : str Row identifier key to check in founded table object. data : dict Row data. Raises ------ TypeError When the specified row identifier type is not a str. ValueError When the specified row identifier already exists in table object. """ table_object = self.__get_table(table) if type(row) is not str: raise TypeError(f"Row identifier needs to be a str, " f"not a {type(row).__name__}") if table_object.has_section(row): raise ValueError(f"Cannot insert row '{row}' since this one " f"already exists in table '{table}'") table_object.add_section(row) try: for key, value in data.items(): table_object.set(row, key, value) table_object.write() except TypeError as error: table_object.remove_section(row) raise TypeError(error)
def read(self)
-
Read and retrieve available files in database directory
Files are retrieving from the 'extension' attribute set in object constructor.
Raises
FileNotFoundError
- When the database directory was not found on filesystem.
Expand source code
def read(self): """ Read and retrieve available files in database directory Files are retrieving from the 'extension' attribute set in object constructor. Raises ------ FileNotFoundError When the database directory was not found on filesystem. """ if not self.exists(): raise FileNotFoundError( f"Cannot found '{self.path}' directory on filesystem") for filepath in self.path.glob(f"*.{self.__extension}"): self.__tables[filepath.stem] = CommonConfiguration(filepath)
def rename_table(self, table, new_name)
-
Rename a specific table
Parameters
table
:str
- Table name to find in local cache.
new_name
:str
- New table name.
Returns
CommonConfiguration
- Renamed database object.
Raises
TypeError
- When the specified new table name type is not a str.
FileExistsError
- When the specified new table name was already used by another database file on filesystem.
Expand source code
def rename_table(self, table, new_name): """ Rename a specific table Parameters ---------- table : str Table name to find in local cache. new_name : str New table name. Returns ------- geode.lib.common.CommonConfiguration Renamed database object. Raises ------ TypeError When the specified new table name type is not a str. FileExistsError When the specified new table name was already used by another database file on filesystem. """ table_object = self.__get_table(table) if type(new_name) is not str: raise TypeError(f"New table name needs to be a str, " f"not a {type(new_name).__name__}") filepath = self.path.joinpath(f"{new_name}.{self.__extension}") if filepath.exists(): raise FileExistsError(f"Cannot use '{new_name}' as new table name " f"since this name is already taken") table_object.path.rename(filepath) self.__tables[new_name] = table_object del self.__tables[table] return table_object
def select(self, table, *rows)
-
Select specific rows from specified table
Parameters
table
:str
- Table name to find in local cache.
rows
:tuple
ofstr
, optional- Rows identifiers to check in founded table object (Default: all).
Returns
dict
- Founded rows from specified table with row identifier as keys.
Expand source code
def select(self, table, *rows): """ Select specific rows from specified table Parameters ---------- table : str Table name to find in local cache. rows : tuple of str, optional Rows identifiers to check in founded table object (Default: all). Returns ------- dict Founded rows from specified table with row identifier as keys. """ table_object = self.__get_table(table) if not rows: rows = table_object.sections() results = dict() for row in rows: if type(row) is not str: raise TypeError(f"Row identifier needs to be a str, " f"not a {type(row).__name__}") if not table_object.has_section(row): continue results[row] = dict(table_object.items(row)) return results
def update(self, table, row, **data)
-
Update a specific row in specified table
Parameters
table
:str
- Table name to find in local cache.
row
:str
- Row identifier key to check in founded table object.
data
:dict
- New row data.
Raises
TypeError
- When the specified row identifier type is not a str.
KeyError
- When the specified row identifier did not exists in table object.
Expand source code
def update(self, table, row, **data): """ Update a specific row in specified table Parameters ---------- table : str Table name to find in local cache. row : str Row identifier key to check in founded table object. data : dict New row data. Raises ------ TypeError When the specified row identifier type is not a str. KeyError When the specified row identifier did not exists in table object. """ if type(row) is not str: raise TypeError(f"Row identifier needs to be a str, " f"not a {type(row).__name__}") table_object = self.__get_table(table) if not table_object.has_section(row): raise KeyError(f"Cannot update row '{row}' since this one did not " f"exists in table '{table}'") for key, value in data.items(): table_object.set(row, key, value) table_object.write()
Inherited members