Package: cellbase
Cellbase v0.1.2Abstraction layer for accessing spreadsheet as database, built on top
ofopenpyxl.UsageRead, write or edit spreadsheet in database like environment, for example:cellbase=Cellbase().load('simple.xlsx')dao=SimpleDAO(cellbase)# Object inherits from DAOentity=Simple(id=1,name='jp')# Object inherits from Entity# Basic database operationsdao.insert(entity)dao.query({'row_idx':entity.row_idx})entity.name='imjp'dao.update(entity)dao.delete({'row_idx':entity.row_idx})# Format cells' font, fill, border, etc...dao.format({'row_idx':entity.row_idx},fill=PatternFill(fill_type="solid",fgColor="00FFFF00"))# Access openpyxl.cell.Cell directlydao.traverse(lambdacell:do_something(cell),{'row_idx':entity.row_idx},select=['id'])cellbase.save()InstallingInstall from pypi:pip install cellbaseFor Your InformationThere are some rules/concepts being followed by Cellbase,
not necessary to know but it is nice to be awared of them.Cellbase = Workbook = DatabaseCelltable = Worksheet = TableDAO is the helper to access data from CellbaseEntity is resposible to convert data to/from dictCellbase named 'load' for reading file instead of 'open' as currently it
does not open connection/stream to file, which means any changes made
are not saved or updated until save/save_as is calledImplemetation of DAO & Entity are optional'where' argument in most methods expect dict in format as below:where={'col_name_1',value_1,'col_name_2':value_2}'select' argument in traverse & format expect list in format as below:select=['col_name_1','col_name_2']'row_idx' is the actual row index in spreadsheet'row_idx' starts from 2 as 1st row is taken by header, which means:dao.query({'row_idx',1})# Will raise KeyErrorCellbase doesn't expect input values(dict) consist of 'row_idx' but values
returned by query() will definitely consist 'row_idx'Cellbase expect variable names declared in first row.Empty variable will caused whole column to be ignored(column 3).It doesn't really matter for rows, empty row as row 3 is still a valid
row.var_1var_2(empty)var_3datadatadatadata(empty)(empty)(empty)(empty)datadata(empty)dataGetting StartedCellbase is made to be easily picked up, you may start right away in python
console or implement DAO & Entity to simplify the codes in your scripts.fromcellbaseimportCellbase# Without specifying filename, it will save as 'cellbase.xlsx' by defaultcellbase=CellBase()# Register the format of worksheet to deal with(only for new worksheet)# 'Simple' is the worksheet name, while 'id' and 'name' are column namescellbase.register({'Simple':['id','name']})Without DAO & Entity:row_idx=cellbase.insert('Simple',{'id':1,'name':'jp'})values=cellbase.query('Simple',{'row_idx':row_idx})cellbase.update('Simple',{'row_idx':row_idx,'id':1,'name':'imjp'})cellbase.delete('Simple',{'row_idx':row_idx})With DAO & Entity:First create DAO,dao=SimpleDAO(cellbase)then do what the last example did,except saving declaration of table name &
access data from object inherits Entityentity=Simple(id=1,name='jp')dao.insert(entity)dao.query({'row_idx':entity.row_idx})entity.name='imjp'dao.update(entity)dao.delete({'row_idx':entity.row_idx})Finally, save it to filecellbase.save()MoreCellbase load, save, save_as, drop, registerLoad from filecellbase.load('filename.xlsx')Save to filename used in load, otherwise,
current working directory as 'cellbase.xlsx'cellbase.save()Save as another file, will raise FileExistsError if overwrite is Falsecellbase.save_as('another_filename.xlsx',overwrite=True)Drop worksheetcellbase.drop('worksheet_name')# or drop with DAOdao.drop()Register structure of worksheet to deal with(only required for new worksheet),
otherwise, ValueError will be raised when creating worksheet as Cellbase
doesn't know what are the title of worksheet and column names to create.cellbase.register({'TABLE_NAME_1':['COL_NAME_1','COL_NAME_2']})Example of DAO & EntityDAOfromcellbaseimportDAOclassSimpleDAO(DAO):# Optional, just to make life easierTABLE_NAME='Simple'COL_ID='id'COL_NAME='name'defworksheet_name(self):returnSimpleDAO.TABLE_NAMEdefnew_entity(self):returnSimple()# New instance of entity for query to return resultEntityfromcellbaseimportEntityclassSimple(Entity):def__init__(self,id=0,name=""):super().__init__()# Declare row_idxself.id=idself.name=namedeffrom_dict(self,values):super().from_dict(values)# Inherits to handle row_idxself.id=values[SimpleDAO.COL_ID]self.name=values[SimpleDAO.COL_NAME]returnselfdefto_dict(self):values=super().to_dict()# Inherits to handle row_idxvalues[SimpleDAO.COL_ID]=self.idvalues[SimpleDAO.COL_NAME]=self.namereturnvaluesLambdaAfter getting used with Cellbase you might find that simple
equality search like this is not enough:dao.query({'id':1,'name':'imjp'})For example, if you need to access all records where name contains 'jp',
you might find lambda useful:dao.query({'name':lambdavalue:'jp'invalue})dao.update(entity,{'name':lambdavalue:'jp'invalue})cellbase.query(worksheet_name,{'name':lambdavalue:'jp'invalue})cellbase.update(worksheet_name,data,{'name':lambdavalue:'jp'invalue})# So as traverse & format...or find with row_idxdao.query({'row_idx':lambdarow_idx:3<=row_idx<=9})dao.update(entity,{'row_idx':lambdarow_idx:3<=row_idx<=9})cellbase.query(worksheet_name,{'row_idx':lambdarow_idx:3<=row_idx<=9})cellbase.update(worksheet_name,data,{'row_idx':lambdarow_idx:3<=row_idx<=9})# So as traverse & format...Magic method(Must implement DAO & Entity)# Magic method only works with row_idxtotal_row_number=len(dao)# __len__entity=dao[row_idx]# __getitem__dao[row_idx]=entity# __setitem__contains=row_idxindao# __contains__deldao[row_idx]# __delitem# Of course it works with lambda/callable tooentity=dao[lambdarow_idx:3<=row_idx<=9]# __getitem__contains=lambdarow_idx:3<=row_idx<=9indao# __contains__deldao[lambdarow_idx:3<=row_idx<=9]# __delitem# Exception# __setitem__ only support update, insertion will raise warningiflambdarow_idx:3<=row_idx<=9indao:dao[lambdarow_idx:3<=row_idx<=9]=entity# updateelse:dao[lambdarow_idx:3<=row_idx<=9]=entity# no effect at allFormattingOther than setting value, you may format cells as well:dao.format(where,select,fill,font,border...)# or wrap all formats in CellFormatterdao.format(where,select,cell_formatter)SeeCellFormatter, for more information.Low Level AccessLow level might be a strong word, but you can have direct access to
cells(openpyxl.cell.Cell) through traverse:dao.traverse(lambdacell:do_something(cell),where,select)For more example, checkoutTestsLicenseThis project is licensed under the MIT License - see theLICENSE.mdfile for details