Executing VBAscript from Python - python
I am in need of some help in regards to win32com.client. I have the code working as far as creating the macro from Python and using Excel but I would like this code to also run the vbascript.
Thank you guys for all of your wonderful feedback!
import pyodbc
import win32com.client as win32
xl = win32.gencache.EnsureDispatch('Excel.Application')
xl.Visible = True
ss = xl.Workbooks.Add()
sh = ss.ActiveSheet
xlmodule = ss.VBProject.VBComponents.Add(1) # vbext_ct_StdModule
sCode = '''Sub Download_Standard_BOM()
'Initializes variables
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim ConnectionString As String
Dim StrQuery As String
ConnectionString = "Provider=SQLOLEDB; Network Library=dbmssocn;Password=********;User ID=*******;Initial Catalog=**;Data Source=*************;"
cnn.Open ConnectionString
cnn.CommandTimeout = 900
StrQuery = "SELECT * FROM car_search WHERE shop_id = *******"
rst.Open StrQuery, cnn
Sheets(1).Range("A2").CopyFromRecordset rst
End Sub'''
xlmodule.CodeModule.AddFromString(sCode)
You should be able to use Excel's Application.Run method:
xl.Run "Download_Standard_BOM"
EDIT
If you need to refer to ADO, then you can either use late-binding, like this:
Dim cnn As Object 'ADODB.Connection
Dim rst As Object 'ADODB.Recordset
Set cnn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")
Or, use early binding and add a reference to the VBA Project:
ss.VBProject.References.AddFromGuid "{2A75196C-D9EB-4129-B803-931327F72D5C}", 2, 8
Related
vb.net Builder Python Server Connection
Imports System.Text Public Class Form1 Const FileSplitter = "FILE" Dim stubBytes As Byte() Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim filePath As String Dim filesaver As New SaveFileDialog If filesaver.ShowDialog = Windows.Forms.DialogResult.OK Then filePath = filesaver.FileName Dim email As String = TextBox1.Text Dim fileSystem = My.Computer.FileSystem stubBytes = fileSystem.ReadAllBytes(Application.StartupPath & "\stub.exe") fileSystem.WriteAllBytes(filePath, stubBytes, False) fileSystem.WriteAllBytes(filePath, Encoding.Default.GetBytes(FileSplitter), True) fileSystem.WriteAllBytes(filePath, Encoding.Default.GetBytes(email), True) MessageBox.Show("Server build!") Else MessageBox.Show("error!") End If End Sub End Class I want to connect to a python server. Here is my code. I use pyinstaller and change server.py to server.exe str='FILE' print(str) I want to change FILE message using vb.net
How can I save the headers and values in Html <script> as a table in the csv file?
I'm new to writing code. Using slenium and beautifulsoup, I managed to reach the script I want among dozens of scripts on the web page. I am looking for script [17]. When these codes are executed, the script [17] gives a result as follows. the last part of my codes html=driver.page_source soup=BeautifulSoup(html, "html.parser") scripts=soup.find_all("script") x=scripts[17] print(x) result, output note: The list of dates is ahead of the script [17]. slide the bar. Dummy Data Dummy Data <script language="JavaScript"> var theHlp='/yardim/matris.asp';var theTitle = 'Piyasa Değeri';var theCaption='Cam (TL)';var lastmod = '';var h='<a class=hisselink href=../Hisse/HisseAnaliz.aspx?HNO=';var e='<a class=hisselink href=../endeks/endeksAnaliz.aspx?HNO=';var d='<center><font face=symbol size=1 color=#FF0000><b>ß</b></font></center>';var u='<center><font face=symbol size=1 color=#008000><b>İ</b></font></center>';var n='<center><font face=symbol size=1 color=#00A000><b>=</b></font></center>';var fr='<font color=#FF0000>';var fg='<font color=#008000>';var theFooter=new Array();var theCols = new Array();theCols[0] = new Array('Hisse',4,50);theCols[1] = new Array('2012.12',1,60);theCols[2] = new Array('2013.03',1,60);theCols[3] = new Array('2013.06',1,60);theCols[4] = new Array('2013.09',1,60);theCols[5] = new Array('2013.12',1,60);theCols[6] = new Array('2014.03',1,60);theCols[7] = new Array('2014.06',1,60);theCols[8] = new Array('2014.09',1,60);theCols[9] = new Array('2014.12',1,60);theCols[10] = new Array('2015.03',1,60);theCols[11] = new Array('2015.06',1,60);theCols[12] = new Array('2015.09',1,60);theCols[13] = new Array('2015.12',1,60);theCols[14] = new Array('2016.03',1,60);theCols[15] = new Array('2016.06',1,60);theCols[16] = new Array('2016.09',1,60);theCols[17] = new Array('2016.12',1,60);theCols[18] = new Array('2017.03',1,60);theCols[19] = new Array('2017.06',1,60);theCols[20] = new Array('2017.09',1,60);theCols[21] = new Array('2017.12',1,60);theCols[22] = new Array('2018.03',1,60);theCols[23] = new Array('2018.06',1,60);theCols[24] = new Array('2018.09',1,60);theCols[25] = new Array('2018.12',1,60);theCols[26] = new Array('2019.03',1,60);theCols[27] = new Array('2019.06',1,60);theCols[28] = new Array('2019.09',1,60);theCols[29] = new Array('2019.12',1,60);theCols[30] = new Array('2020.03',1,60);var theRows = new Array(); theRows[0] = new Array ('<b>'+h+'30>ANA</B></a>','1,114,919,783.60','1,142,792,778.19','1,091,028,645.38','991,850,000.48','796,800,000.38','697,200,000.34','751,150,000.36','723,720,000.33','888,000,000.40','790,320,000.36','883,560,000.40','927,960,000.42','737,040,000.33','879,120,000.40','914,640,000.41','927,960,000.42','1,172,160,000.53','1,416,360,000.64','1,589,520,000.72','1,552,500,000.41','1,972,500,000.53','2,520,000,000.67','2,160,000,000.58','2,475,000,000.66','2,010,000,000.54','2,250,000,000.60','2,077,500,000.55','2,332,500,000.62','3,270,000,000.87','2,347,500,000.63'); theRows[1] = new Array ('<b>'+h+'89>DEN</B></a>','55,200,000.00','55,920,000.00','45,960,000.00','42,600,000.00','35,760,000.00','39,600,000.00','40,200,000.00','47,700,000.00','50,460,000.00','45,300,000.00','41,760,000.00','59,340,000.00','66,600,000.00','97,020,000.00','81,060,000.00','69,300,000.00','79,800,000.00','68,400,000.00','66,900,000.00','66,960,000.00','71,220,000.00','71,520,000.00','71,880,000.00','60,600,000.00','69,120,000.00','62,640,000.00','57,180,000.00','89,850,000.00','125,100,000.00','85,350,000.00'); theRows[2] = new Array ('<b>'+h+'269>SIS</B></a>','4,425,000,000.00','4,695,000,000.00','4,050,000,000.00','4,367,380,000.00','4,273,120,000.00','3,644,720,000.00','4,681,580,000.00','4,913,000,000.00','6,188,000,000.00','5,457,000,000.00','6,137,000,000.00','5,453,000,000.00','6,061,000,000.00','6,954,000,000.00','6,745,000,000.00','6,519,000,000.00','7,851,500,000.00','8,548,500,000.00','9,430,000,000.00','9,225,000,000.00','10,575,000,000.00','11,610,000,000.00','9,517,500,000.00','13,140,000,000.00','12,757,500,000.00','13,117,500,000.00','11,677,500,000.00','10,507,500,000.00','11,857,500,000.00','9,315,000,000.00'); theRows[3] = new Array ('<b>'+h+'297>TRK</B></a>','1,692,579,200.00','1,983,924,800.00','1,831,315,200.00','1,704,000,000.00','1,803,400,000.00','1,498,100,000.00','1,803,400,000.00','1,884,450,000.00','2,542,160,000.00','2,180,050,000.00','2,069,200,000.00','1,682,600,000.00','1,619,950,000.00','1,852,650,000.00','2,040,600,000.00','2,315,700,000.00','2,641,200,000.00','2,938,800,000.00','3,599,100,000.00','4,101,900,000.00','5,220,600,000.00','5,808,200,000.00','4,689,500,000.00','5,375,000,000.00','3,787,500,000.00','4,150,000,000.00','3,662,500,000.00','3,712,500,000.00','4,375,000,000.00','3,587,500,000.00'); var thetable=new mytable();thetable.tableWidth=650;thetable.shownum=false;thetable.controlaccess=true;thetable.visCols=new Array(true,true,true,true,true);thetable.initsort=new Array(0,-1);thetable.inittable();thetable.refreshTable();</script> My purpose is to extract this output into a table and save it as a csv file. How can i extract this script as i want? all dates should be on top, all names should be on the far right, all values should be between the two. Hisse 2012.12 2013.3 2013.4 ... ANA 1,114,919,783.60 1,142,792,778.19 1,091,028,645.38 ... DEN 55,200,000.00 55,920,000.00 45,960,000.00 .... . . .
Solution The custom-function process_scripts() will produce what you are looking for. I am using the dummy data given below (at the end). First we check that the code does what it is expected and so we create a pandas dataframe to see the output. You could also open this Colab Jupyter Notebook and run it on Cloud for free. This will allow you to not worry about any installation or setup and simply focus on examining the solution itself. 1. Processing A Single Script ## Define CSV file-output folder-path OUTPUT_PATH = './output' ## Process scripts dfs = process_scripts(scripts = [s], output_path = OUTPUT_PATH, save_to_csv = False, verbose = 0) print(dfs[0].reset_index(drop=True)) Output: Name 2012.12 ... 2019.12 2020.03 0 ANA 1,114,919,783.60 ... 3,270,000,000.87 2,347,500,000.63 1 DEN 55,200,000.00 ... 125,100,000.00 85,350,000.00 2 SIS 4,425,000,000.00 ... 11,857,500,000.00 9,315,000,000.00 3 TRK 1,692,579,200.00 ... 4,375,000,000.00 3,587,500,000.00 [4 rows x 31 columns] 2. Processing All the Scripts You can process all your scripts using the custom-define function process_scripts(). The code is given below. ## Define CSV file-output folder-path OUTPUT_PATH = './output' ## Process scripts dfs = process_scripts(scripts, output_path = OUTPUT_PATH, save_to_csv = True, verbose = 0) ## To clear the output dir-contents #!rm -f $OUTPUT_PATH/* I did this on Google Colab and it worked as expected. 3. Making Paths in OS-agnostic Manner Making paths for windows or unix based systems could be very different. The following shows you a method to achieve that without having to worry about which OS you will run the code. I have used the os library here. However, I would suggest you to look at the Pathlib library as well. # Define relative path for output-folder OUTPUT_PATH = './output' # Dynamically define absolute path pwd = os.getcwd() # present-working-directory OUTPUT_PATH = os.path.join(pwd, os.path.abspath(OUTPUT_PATH)) 4. Code: custom function process_scripts() Here we use the regex (regular expression) library, along with pandas for organizing the data in a tabular format and then writing to csv file. The tqdm library is used to give you a nice progressbar while processing multiple scripts. Please see the comments in the code to know what to do if you are running it not from a jupyter notebook. The os library is used for path manipulation and creation of output-directory. #pip install -U pandas #pip install tqdm import pandas as pd import re # regex import os from tqdm.notebook import tqdm # Use the following line if not using a jupyter notebook # from tqdm import tqdm def process_scripts(scripts, output_path='./output', save_to_csv: bool=False, verbose: int=0): """Process all scripts and return a list of dataframes and optionally write each dataframe to a CSV file. Parameters ---------- scripts: list of scripts output_path (str): output-folder-path for csv files save_to_csv (bool): default is False verbose (int): prints output for verbose>0 Example ------- OUTPUT_PATH = './output' dfs = process_scripts(scripts, output_path = OUTPUT_PATH, save_to_csv = True, verbose = 0) ## To clear the output dir-contents #!rm -f $OUTPUT_PATH/* """ ## Define regex patterns and compile for speed pat_header = re.compile(r"theCols\[\d+\] = new Array\s*\([\'](\d{4}\.\d{1,2})[\'],\d+,\d+\)") pat_line = re.compile(r"theRows\[\d+\] = new Array\s*\((.*)\).*") pat_code = re.compile("([A-Z]{3})") # Calculate zfill-digits zfill_digits = len(str(len(scripts))) print(f'Total scripts: {len(scripts)}') # Create output_path if not os.path.exists(output_path): os.makedirs(output_path) # Define a list of dataframes: # An accumulator of all scripts dfs = [] ## If you do not have tqdm installed, uncomment the # next line and comment out the following line. #for script_num, script in enumerate(scripts): for script_num, script in enumerate(tqdm(scripts, desc='Scripts Processed')): ## Extract: Headers, Rows # Rows : code (Name: single column), line-data (multi-column) headers = script.strip().split('\n', 0)[0] headers = ['Name'] + re.findall(pat_header, headers) lines = re.findall(pat_line, script) codes = [re.findall(pat_code, line)[0] for line in lines] # Clean data for each row lines_data = dict() for line, code in zip(lines, codes): line_data = line.replace("','", "|").split('|') line_data[-1] = line_data[-1].replace("'", "") line_data[0] = code lines_data.update({code: line_data.copy()}) if verbose>0: print('{}: {}'.format(script_num, codes)) ## Load data into a pandas-dataframe # and write to csv. df = pd.DataFrame(lines_data).T df.columns = headers dfs.append(df.copy()) # update list # Write to CSV if save_to_csv: num_label = str(script_num).zfill(zfill_digits) script_file_csv = f'Script_{num_label}.csv' script_path = os.path.join(output_path, script_file_csv) df.to_csv(script_path, index=False) return dfs 5. Dummy Data ## Dummy Data s = """ <script language="JavaScript"> var theHlp='/yardim/matris.asp';var theTitle = 'Piyasa Değeri';var theCaption='Cam (TL)';var lastmod = '';var h='<a class=hisselink href=../Hisse/HisseAnaliz.aspx?HNO=';var e='<a class=hisselink href=../endeks/endeksAnaliz.aspx?HNO=';var d='<center><font face=symbol size=1 color=#FF0000><b>ß</b></font></center>';var u='<center><font face=symbol size=1 color=#008000><b>İ</b></font></center>';var n='<center><font face=symbol size=1 color=#00A000><b>=</b></font></center>';var fr='<font color=#FF0000>';var fg='<font color=#008000>';var theFooter=new Array();var theCols = new Array();theCols[0] = new Array('Hisse',4,50);theCols[1] = new Array('2012.12',1,60);theCols[2] = new Array('2013.03',1,60);theCols[3] = new Array('2013.06',1,60);theCols[4] = new Array('2013.09',1,60);theCols[5] = new Array('2013.12',1,60);theCols[6] = new Array('2014.03',1,60);theCols[7] = new Array('2014.06',1,60);theCols[8] = new Array('2014.09',1,60);theCols[9] = new Array('2014.12',1,60);theCols[10] = new Array('2015.03',1,60);theCols[11] = new Array('2015.06',1,60);theCols[12] = new Array('2015.09',1,60);theCols[13] = new Array('2015.12',1,60);theCols[14] = new Array('2016.03',1,60);theCols[15] = new Array('2016.06',1,60);theCols[16] = new Array('2016.09',1,60);theCols[17] = new Array('2016.12',1,60);theCols[18] = new Array('2017.03',1,60);theCols[19] = new Array('2017.06',1,60);theCols[20] = new Array('2017.09',1,60);theCols[21] = new Array('2017.12',1,60);theCols[22] = new Array('2018.03',1,60);theCols[23] = new Array('2018.06',1,60);theCols[24] = new Array('2018.09',1,60);theCols[25] = new Array('2018.12',1,60);theCols[26] = new Array('2019.03',1,60);theCols[27] = new Array('2019.06',1,60);theCols[28] = new Array('2019.09',1,60);theCols[29] = new Array('2019.12',1,60);theCols[30] = new Array('2020.03',1,60);var theRows = new Array(); theRows[0] = new Array ('<b>'+h+'30>ANA</B></a>','1,114,919,783.60','1,142,792,778.19','1,091,028,645.38','991,850,000.48','796,800,000.38','697,200,000.34','751,150,000.36','723,720,000.33','888,000,000.40','790,320,000.36','883,560,000.40','927,960,000.42','737,040,000.33','879,120,000.40','914,640,000.41','927,960,000.42','1,172,160,000.53','1,416,360,000.64','1,589,520,000.72','1,552,500,000.41','1,972,500,000.53','2,520,000,000.67','2,160,000,000.58','2,475,000,000.66','2,010,000,000.54','2,250,000,000.60','2,077,500,000.55','2,332,500,000.62','3,270,000,000.87','2,347,500,000.63'); theRows[1] = new Array ('<b>'+h+'89>DEN</B></a>','55,200,000.00','55,920,000.00','45,960,000.00','42,600,000.00','35,760,000.00','39,600,000.00','40,200,000.00','47,700,000.00','50,460,000.00','45,300,000.00','41,760,000.00','59,340,000.00','66,600,000.00','97,020,000.00','81,060,000.00','69,300,000.00','79,800,000.00','68,400,000.00','66,900,000.00','66,960,000.00','71,220,000.00','71,520,000.00','71,880,000.00','60,600,000.00','69,120,000.00','62,640,000.00','57,180,000.00','89,850,000.00','125,100,000.00','85,350,000.00'); theRows[2] = new Array ('<b>'+h+'269>SIS</B></a>','4,425,000,000.00','4,695,000,000.00','4,050,000,000.00','4,367,380,000.00','4,273,120,000.00','3,644,720,000.00','4,681,580,000.00','4,913,000,000.00','6,188,000,000.00','5,457,000,000.00','6,137,000,000.00','5,453,000,000.00','6,061,000,000.00','6,954,000,000.00','6,745,000,000.00','6,519,000,000.00','7,851,500,000.00','8,548,500,000.00','9,430,000,000.00','9,225,000,000.00','10,575,000,000.00','11,610,000,000.00','9,517,500,000.00','13,140,000,000.00','12,757,500,000.00','13,117,500,000.00','11,677,500,000.00','10,507,500,000.00','11,857,500,000.00','9,315,000,000.00'); theRows[3] = new Array ('<b>'+h+'297>TRK</B></a>','1,692,579,200.00','1,983,924,800.00','1,831,315,200.00','1,704,000,000.00','1,803,400,000.00','1,498,100,000.00','1,803,400,000.00','1,884,450,000.00','2,542,160,000.00','2,180,050,000.00','2,069,200,000.00','1,682,600,000.00','1,619,950,000.00','1,852,650,000.00','2,040,600,000.00','2,315,700,000.00','2,641,200,000.00','2,938,800,000.00','3,599,100,000.00','4,101,900,000.00','5,220,600,000.00','5,808,200,000.00','4,689,500,000.00','5,375,000,000.00','3,787,500,000.00','4,150,000,000.00','3,662,500,000.00','3,712,500,000.00','4,375,000,000.00','3,587,500,000.00'); var thetable=new mytable();thetable.tableWidth=650;thetable.shownum=false;thetable.controlaccess=true;thetable.visCols=new Array(true,true,true,true,true);thetable.initsort=new Array(0,-1);thetable.inittable();thetable.refreshTable();</script> """ ## Make a dummy list of scripts scripts = [s for _ in range(10)]
According to the provided <script> in your question, you can do something like code below to have a list of Dates for each name ANA, DEN ..: for _ in range(1, len(aaa.split("<b>'"))-1): s = aaa.split("<b>'")[_].split("'") print(_) lst = [] for i in s: if "</B>" in i: name = i.split('>')[1].split("<")[0] print("{} = ".format(name), end="") if any(j.isdigit() for j in i) and ',' in i: lst.append(i) print(lst) It's just an example code, so it's not that beautiful :) Hope this will help you.
How do you delete a virtual disk with pyvmomi
I am trying to write a Python program using the pyvmomi library to "erase" a virtual hard drive associated with a VM. The way this is done manually is to remove the virtual disk and create a new virtual disk with the same specs. I am expecting that I will need to do the same thing with pyvmomi so I have started down that path. My issue is that I can use ReconfigVM_Task to remove the virtual drive but that leaves the VMDK file itself. I originally tried using DeleteVStorageObject_Task (since DeleteVirtualDisk_Task is deprecated) to remove the virtual disk file but that requires the ID of the object (the VMDK file) which I am unable to find anywhere. Theoretically that's available from the VirtualDisk property vDiskId but that is null. In further research it seems to only be populated for first class disks. So I am instead trying to delete the VMDK file directly using DeleteDatastoreFile_Task but when I do that I end up with a XXXX-flat.vmdk file in the datastore so it seems to not actually delete the file. Any idea on where I'm going wrong here or how to better do this? The VMWare SDK documentation for pyvmomi is...lacking. Thanks!
You'll have to perform a ReconfigVM_Task operation. The keypoint for this is that the file operation should be destroy. Here's the raw output from performing the operation in the UI: spec = vim.vm.ConfigSpec() spec_deviceChange_0 = vim.vm.device.VirtualDeviceSpec() spec_deviceChange_0.fileOperation = 'destroy' spec_deviceChange_0.device = vim.vm.device.VirtualDisk() spec_deviceChange_0.device.shares = vim.SharesInfo() spec_deviceChange_0.device.shares.shares = 1000 spec_deviceChange_0.device.shares.level = 'normal' spec_deviceChange_0.device.capacityInBytes = 8589934592 spec_deviceChange_0.device.storageIOAllocation = vim.StorageResourceManager.IOAllocationInfo() spec_deviceChange_0.device.storageIOAllocation.shares = vim.SharesInfo() spec_deviceChange_0.device.storageIOAllocation.shares.shares = 1000 spec_deviceChange_0.device.storageIOAllocation.shares.level = 'normal' spec_deviceChange_0.device.storageIOAllocation.limit = -1 spec_deviceChange_0.device.storageIOAllocation.reservation = 0 spec_deviceChange_0.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo() spec_deviceChange_0.device.backing.backingObjectId = '' spec_deviceChange_0.device.backing.fileName = '[kruddy_2TB_01] web01/web01_2.vmdk' spec_deviceChange_0.device.backing.split = False spec_deviceChange_0.device.backing.writeThrough = False spec_deviceChange_0.device.backing.datastore = search_index.FindByUuid(None, "datastore-14", True, True) spec_deviceChange_0.device.backing.eagerlyScrub = True spec_deviceChange_0.device.backing.contentId = 'e26f44020e7897006bec81b1fffffffe' spec_deviceChange_0.device.backing.thinProvisioned = False spec_deviceChange_0.device.backing.diskMode = 'persistent' spec_deviceChange_0.device.backing.digestEnabled = False spec_deviceChange_0.device.backing.sharing = 'sharingNone' spec_deviceChange_0.device.backing.uuid = '6000C292-7895-54ee-a55c-49d0036ef1bb' spec_deviceChange_0.device.controllerKey = 200 spec_deviceChange_0.device.unitNumber = 0 spec_deviceChange_0.device.nativeUnmanagedLinkedClone = False spec_deviceChange_0.device.capacityInKB = 8388608 spec_deviceChange_0.device.deviceInfo = vim.Description() spec_deviceChange_0.device.deviceInfo.summary = '8,388,608 KB' spec_deviceChange_0.device.deviceInfo.label = 'Hard disk 2' spec_deviceChange_0.device.diskObjectId = '148-3000' spec_deviceChange_0.device.key = 3000 spec_deviceChange_0.operation = 'remove' spec.deviceChange = [spec_deviceChange_0] spec.cpuFeatureMask = [] managedObject.ReconfigVM_Task(spec)
Kyle Ruddy got me pointed in the right direction. Here's a code snippit showing how I made it work for future people searching for information on how to do this: #Assuming dev is already set to the vim.vm.device.VirtualDisk you want to delete... virtual_hdd_spec = vim.vm.device.VirtualDeviceSpec() virtual_hdd_spec.fileOperation = vim.vm.device.VirtualDeviceSpec.FileOperation.destroy virtual_hdd_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.remove virtual_hdd_spec.device = dev spec = vim.vm.ConfigSpec() spec.deviceChange = [virtual_hdd_spec] WaitForTask(vm.ReconfigVM_Task(spec=spec)) The API documentation for this is at https://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.device.VirtualDeviceSpec.html
Moving numpy arrays from VBA to Python and back
I have a VBA script in Microsoft Access. The VBA script is part of a large project with multiple people, and so it is not possible to leave the VBA environment. In a section of my script, I need to do complicated linear algebra on a table quickly. So, I move the VBA tables written as recordsets) into Python to do linear algebra, and back into VBA. The matrices in python are represented as numpy arrays. Some of the linear algebra is proprietary and so we are compiling the proprietary scripts with pyinstaller. The details of the process are as follows: The VBA script creates a csv file representing the table input.csv. The VBA script runs the python script through the command line The python script loads the csv file input.csv as a numpy matrix, does linear algebra on it, and creates an output csv file output.csv. VBA waits until python is done, then loads output.csv. VBA deletes the no-longer-needed input.csv file and output.csv file. This process is inefficient. Is there a way to load VBA matrices into Python (and back) without the csv clutter? Do these methods work with compiled python code through pyinstaller? I have found the following examples on stackoverflow that are relevant. However, they do not address my problem specifically. Return result from Python to Vba How to pass Variable from Python to VBA Sub
Solution 1 Either retrieve the COM running instance of Access and get/set the data directly with the python script via the COM API: VBA: Private Cache Public Function GetData() GetData = Cache Cache = Empty End Function Public Sub SetData(data) Cache = data End Sub Sub Usage() Dim wshell Set wshell = VBA.CreateObject("WScript.Shell") ' Make the data available via GetData()' Cache = Array(4, 6, 8, 9) ' Launch the python script compiled with pylauncher ' Debug.Assert 0 = wshell.Run("C:\dev\myapp.exe", 0, True) ' Handle the returned data ' Debug.Assert Cache(3) = 2 End Sub Python (myapp.exe): import win32com.client if __name__ == "__main__": # get the running instance of Access app = win32com.client.GetObject(Class="Access.Application") # get some data from Access data = app.run("GetData") # return some data to Access app.run("SetData", [1, 2, 3, 4]) Solution 2 Or create a COM server to expose some functions to Access : VBA: Sub Usage() Dim Py As Object Set Py = CreateObject("Python.MyModule") Dim result result = Py.MyFunction(Array(5, 6, 7, 8)) End Sub Python (myserver.exe or myserver.py): import sys, os, win32api, win32com.server.localserver, win32com.server.register class MyModule(object): _reg_clsid_ = "{5B4A4174-EE23-4B70-99F9-E57958CFE3DF}" _reg_desc_ = "My Python COM Server" _reg_progid_ = "Python.MyModule" _public_methods_ = ['MyFunction'] def MyFunction(self, data) : return [(1,2), (3, 4)] def register(*classes) : regsz = lambda key, val: win32api.RegSetValue(-2147483647, key, 1, val) isPy = not sys.argv[0].lower().endswith('.exe') python_path = isPy and win32com.server.register._find_localserver_exe(1) server_path = isPy and win32com.server.register._find_localserver_module() for cls in classes : if isPy : file_path = sys.modules[cls.__module__].__file__ class_name = '%s.%s' % (os.path.splitext(os.path.basename(file_path))[0], cls.__name__) command = '"%s" "%s" %s' % (python_path, server_path, cls._reg_clsid_) else : file_path = sys.argv[0] class_name = '%s.%s' % (cls.__module__, cls.__name__) command = '"%s" %s' % (file_path, cls._reg_clsid_) regsz("SOFTWARE\\Classes\\" + cls._reg_progid_ + '\\CLSID', cls._reg_clsid_) regsz("SOFTWARE\\Classes\\AppID\\" + cls._reg_clsid_, cls._reg_progid_) regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_, cls._reg_desc_) regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\LocalServer32', command) regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\ProgID', cls._reg_progid_) regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\PythonCOM', class_name) regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\PythonCOMPath', os.path.dirname(file_path)) regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\Debugging', "0") print('Registered ' + cls._reg_progid_) if __name__ == "__main__": if len(sys.argv) > 1 : win32com.server.localserver.serve(set([v for v in sys.argv if v[0] == '{'])) else : register(MyModule) Note that you'll have to run the script once without any argument to register the class and to make it available to VBA.CreateObject. Both solutions work with pylauncher and the array received in python can be converted with numpy.array(data). Dependency : https://pypi.python.org/pypi/pywin32
You can try loading your record set into an array, dim'ed as Double Dim arr(1 to 100, 1 to 100) as Double by looping, then pass the pointer to the first element ptr = VarPtr(arr(1, 1)) to Python, where arr = numpy.ctypeslib.as_array(ptr, (100 * 100,)) ? But VBA will still own the array memory
There is a very simple way of doing this with xlwings. See xlwings.org and make sure to follow the instructions to enable macro settings, tick xlwings in VBA references, etc. etc. The code would then look as simple as the following (a slightly silly block of code that just returns the same dataframe back, but you get the picture): import xlwings as xw import numpy as np import pandas as pd # the #xw.decorator is to tell xlwings to create an Excel VBA wrapper for this function. # It has no effect on how the function behaves in python #xw.func #xw.arg('pensioner_data', pd.DataFrame, index=False, header=True) #xw.ret(expand='table', index=False) def pensioner_CF(pensioner_data, mortality_table = "PA(90)", male_age_adj = 0, male_improv = 0, female_age_adj = 0, female_improv = 0, years_improv = 0, arrears_advance = 0, discount_rate = 0, qxy_tables=0): pensioner_data = pensioner_data.replace(np.nan, '', regex=True) cashflows_df = pd.DataFrame() return cashflows_df I'd be interested to hear if this answers the question. It certainly made my VBA / python experience a lot easier.
Python Paraview
How to extract data from server to the client in Paraview parallel running mode my script is: def getNumberOfBlocks(px): data1 = servermanager.Fetch(px,0) data2 = servermanager.Fetch(px,1) group = vtk.vtkMultiBlockDataGroupFilter() group.AddInputConnection(group.GetOutputPortn()) group.AddInputConnection(group.GetOutputPort()) group.Update() group.AddInputConnection(transformer2.GetOutputPort()) data3 = group.GetOutputPort() data = vtk.vtkMultiBlockDataGroupFilter.SafeDownCast(data3) return data.GetNumberOfBlocks() px is a proxy from where i am getting data. there are two port , i need to fetch the data from these port all at a time. thanks for help.
I'm a little confused by your script - won't it always return 3? If you just want to get the number of blocks and px is of type vtkSMSourceProxy, you can use the following: def getNumberOfBlocks(px): di = GetDataInformation() cdi = di.GetCompositeDataInformation() return cdi.GetNumberOfChildren()