forked from sheetjs/docs.sheetjs.com
		
	
		
			
	
	
		
			137 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			137 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								from base64 import b64encode, b64decode
							 | 
						||
| 
								 | 
							
								from contextlib import contextmanager
							 | 
						||
| 
								 | 
							
								from STPyV8 import JSContext, JSArray, JSObject
							 | 
						||
| 
								 | 
							
								from functools import wraps
							 | 
						||
| 
								 | 
							
								from os.path import splitext
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def to_py(method):
							 | 
						||
| 
								 | 
							
								  # `convert` from STPyV8 tests/test_Wrapper.py
							 | 
						||
| 
								 | 
							
								  def convert(obj):
							 | 
						||
| 
								 | 
							
								    if isinstance(obj, JSArray):
							 | 
						||
| 
								 | 
							
								      return [convert(v) for v in obj]
							 | 
						||
| 
								 | 
							
								    if isinstance(obj, JSObject):
							 | 
						||
| 
								 | 
							
								      return dict([[str(k), convert(obj.__getattr__(str(k)))] for k in obj.__dir__()])
							 | 
						||
| 
								 | 
							
								    return obj
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  @wraps(method)
							 | 
						||
| 
								 | 
							
								  def func(self, *args, **kwargs):
							 | 
						||
| 
								 | 
							
								    res = method(self, *args, **kwargs)
							 | 
						||
| 
								 | 
							
								    return convert(res)
							 | 
						||
| 
								 | 
							
								  return func
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class SheetJSWorksheet:
							 | 
						||
| 
								 | 
							
								  ws = None
							 | 
						||
| 
								 | 
							
								  ctxt = None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def __init__(self, ctxt, ws):
							 | 
						||
| 
								 | 
							
								    self.ctxt = ctxt
							 | 
						||
| 
								 | 
							
								    self.ws = ws
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def js(self): return self.ws
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  @to_py
							 | 
						||
| 
								 | 
							
								  def get_rows(self):
							 | 
						||
| 
								 | 
							
								    return self.ctxt.eval("(ws => XLSX.utils.sheet_to_json(ws))")(self.ws)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class SheetJSWorkbook:
							 | 
						||
| 
								 | 
							
								  wb = None
							 | 
						||
| 
								 | 
							
								  ctxt = None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def __init__(self, ctxt, wb):
							 | 
						||
| 
								 | 
							
								    self.ctxt = ctxt
							 | 
						||
| 
								 | 
							
								    self.wb = wb
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def js(self): return self.wb
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  @to_py
							 | 
						||
| 
								 | 
							
								  def sheet_names(self):
							 | 
						||
| 
								 | 
							
								    return self.wb.SheetNames
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def get_sheet(self, name):
							 | 
						||
| 
								 | 
							
								    return SheetJSWorksheet(self.ctxt, self.wb.Sheets[name])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def to_file(self, path, book_type=""):
							 | 
						||
| 
								 | 
							
								    b64ify = self.ctxt.eval("((wb, bT) => XLSX.write(wb, {type:'base64', bookType:bT}))")
							 | 
						||
| 
								 | 
							
								    if not book_type: book_type = splitext(path)[1][1:]
							 | 
						||
| 
								 | 
							
								    b64 = b64ify(self.wb, book_type)
							 | 
						||
| 
								 | 
							
								    raw = b64decode(b64)
							 | 
						||
| 
								 | 
							
								    with open(path, mode="wb") as f:
							 | 
						||
| 
								 | 
							
								      f.write(raw)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class SheetJSWrapper:
							 | 
						||
| 
								 | 
							
								  ctxt = None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def __init__(self, ctx):
							 | 
						||
| 
								 | 
							
								    self.ctxt = ctx
							 | 
						||
| 
								 | 
							
								    with open("xlsx.full.min.js") as f: self.ctxt.eval(f.read())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def version(self):
							 | 
						||
| 
								 | 
							
								    return self.ctxt.eval("XLSX.version")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def read_binary(self, data):
							 | 
						||
| 
								 | 
							
								    read = self.ctxt.eval("(b64 => XLSX.read(b64, {type: 'base64', dense: true}))")
							 | 
						||
| 
								 | 
							
								    return SheetJSWorkbook(self.ctxt, read(b64encode(data)))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def read_file(self, path):
							 | 
						||
| 
								 | 
							
								    with open(path, mode="rb") as f:
							 | 
						||
| 
								 | 
							
								      return self.read_binary(f.read())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def sheet_from_json(self, json):
							 | 
						||
| 
								 | 
							
								    jsonify = self.ctxt.eval("(json => XLSX.utils.json_to_sheet(JSON.parse(json)) )")
							 | 
						||
| 
								 | 
							
								    return SheetJSWorksheet(self.ctxt, jsonify(json))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def book_new(self):
							 | 
						||
| 
								 | 
							
								    booknew = self.ctxt.eval("XLSX.utils.book_new()")
							 | 
						||
| 
								 | 
							
								    return SheetJSWorkbook(self.ctxt, booknew)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def book_append_sheet(self, book, sheet, wsname):
							 | 
						||
| 
								 | 
							
								    bas = self.ctxt.eval("((wb, ws, wsname) => XLSX.utils.book_append_sheet(wb, ws, wsname))")
							 | 
						||
| 
								 | 
							
								    bas(book.js(), sheet.js(), wsname)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def book_from_json(self, json, wsname = "Sheet1"):
							 | 
						||
| 
								 | 
							
								    booknew = self.book_new()
							 | 
						||
| 
								 | 
							
								    sheet = self.sheet_from_json(json)
							 | 
						||
| 
								 | 
							
								    self.book_append_sheet(booknew, sheet, wsname)
							 | 
						||
| 
								 | 
							
								    return booknew
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def book_from_df(self, df):
							 | 
						||
| 
								 | 
							
								    # convert from dataframe to JSON string
							 | 
						||
| 
								 | 
							
								    json = df.to_json(orient="records")
							 | 
						||
| 
								 | 
							
								    return self.book_from_json(json)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@contextmanager
							 | 
						||
| 
								 | 
							
								def SheetJS():
							 | 
						||
| 
								 | 
							
								  """
							 | 
						||
| 
								 | 
							
								  SheetJS Library context manager
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  Returns an instance of the SheetJSWrapper class
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  Reading data from file to Pandas DataFrame:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ```py
							 | 
						||
| 
								 | 
							
								  with SheetJS() as sheetjs:
							 | 
						||
| 
								 | 
							
								      # read data from file
							 | 
						||
| 
								 | 
							
								      wb = sheetjs.read_file(argv[1])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      # get first worksheet
							 | 
						||
| 
								 | 
							
								      first_ws_name = wb.sheet_names()[0]
							 | 
						||
| 
								 | 
							
								      ws = wb.get_sheet(wsname)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      # get data from first worksheet (list of dicts)
							 | 
						||
| 
								 | 
							
								      rows = ws.get_rows()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      # generate pandas DataFrame
							 | 
						||
| 
								 | 
							
								      df = pd.DataFrame.from_records(rows)
							 | 
						||
| 
								 | 
							
								  ```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  Writing data from Pandas DataFrame to file:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ```py
							 | 
						||
| 
								 | 
							
								  with SheetJS() as sheetjs:
							 | 
						||
| 
								 | 
							
								    sheetjs.book_from_df(df).to_file(outf)
							 | 
						||
| 
								 | 
							
								  ```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  """
							 | 
						||
| 
								 | 
							
								  with JSContext() as ctxt:
							 | 
						||
| 
								 | 
							
								    yield SheetJSWrapper(ctxt)
							 |