Use SMO DLL in Python using win32com - python

I'm attempting to use the SQL Server SMO library from Python 2.7 using pyWin32. I can import win32com, but I've been stymied in any attempt to access the library. The code I am attempting is below.
import sys
sys.path.append(r'C:\Program Files\Microsoft SQL Server\100\SDK\Assemblies')
import win32com.client
server = win32com.client.Dispatch('Microsoft.SqlServer.Management.SMO.Server')
def main():
print server
if __name__ == '__main__':
main()
When this code is run, I get pywintypes.com_error: (-2147221005, 'Invalid class string', None, None).
It seems likely that I am simply getting the library's name wrong in the call to Dispatch, but I can't figure out any way to know what it should be.
It seems like this may actually be a path problem.
This works:
import win32api
win32api.LoadLibrary(r'C:\Program Files\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.Smo.dll')
However, this does not:
import sys
sys.path.append(r'C:\Program Files\Microsoft SQL Server\100\SDK\Assemblies')
import win32api
win32api.LoadLibrary(r'Microsoft.SqlServer.Smo.dll')

win32com is for using COM libraries and it doesn't know anything about .NET assemblies. Currently, there is no way to use .NET directly from CPython, so your options are to use IronPython or write a command line tool in C# or whatever and then call it from Python.

In addition to #Pondlife's answer, which is correct for the question asked, it is possible to load .NET assemblies in CPython using the Python for .NET module and the following code:
import clr
clr.AddReference("Microsoft.SqlServer.Smo")
from Microsoft.SqlServer.Management.Smo import Server
To make this work, I needed to add the assembly's path to PYTHONPATH manually. I couldn't get it to work using sys.path.append.

Related

How to get available modules with pythonnet

I'm trying to import a .net dll into python and would like to figure out how to see what modules are available.
import clr
clr.AddReference("System.Windows.Forms")
from System.Windows.Forms import Form
After the clr.AddReference line how can I see what is available to import? I would like to know that System.Windows.Forms is available and that Form is available.
I have an internal .net dll I am trying to work with, and couldn't figure out how to see what the modules I needed to call without an example. Once I got this point, I can see what's available with something like
form = Form()
print(dir(form))
I was able to get the info I needed with the following code:
dll_ref = System.Reflection.Assembly.LoadFile(full_path)
print(dll_ref.FullName)
print(dll_ref.Location)
for i in range(len(dll_ref.DefinedTypes)):
print(dll_ref.DefinedTypes[i])
There are tools that can show you members in .NET DLL. One is Object Explorer in Visual Studio. There is also a free tool from JetBrains called dotPeek.
If you want to do it from Python, you need to either dir on a namespace that you must know in advance, or use .NET reflection to inspect the DLL programmatically.

pythonnet clr how to add reference to a dll assembly?

I am trying to import a dll package into python through pythonnet clr. I am aware that the package CLR and pythonnet both end up having a namespace called clr so the command "import clr" can be equivocal. Long story short, I seem to need pythonnet not the other one. I would like to be able to specify the address of the dll assembly; this one works:
import os as os
import clr
#https://pypi.org/project/pythonnet/#:~:text=NET%20Common%20Language%20Runtime%20(CLR,to%20embed%20Python%20into%20a%20.
import sys
Apath=os.path.normpath("C://Folder//Folder//Folder//AssemblyA.dll")
clr.AddReference(Apath)
but this one fails (got the idea of this one from here):
import os as os
import clr
#https://pypi.org/project/pythonnet/#:~:text=NET%20Common%20Language%20Runtime%20(CLR,to%20embed%20Python%20into%20a%20.
import sys
BfolderPath=os.path.normpath("C://Folder//Folder//Folder")
sys.path.append(BfolderPath)
clr.AddReference('AssemblyB.dll')
I get the following error when I try running the second one:
"System.IO.FileNotFoundException: Unable to find assembly 'AssemblyB.dll'.
at Python.Runtime.CLRModule.AddReference(String name)"
this one also fails
import os as os
import clr
#https://pypi.org/project/pythonnet/#:~:text=NET%20Common%20Language%20Runtime%20(CLR,to%20embed%20Python%20into%20a%20.
import sys
BfolderPath=os.path.normpath("C://Folder//Folder//Folder")
clr.AddReferenceToFileAndPath(Bpath)
"AttributeError: module 'clr' has no attribute 'AddReferenceToFileAndPath'"
ps1. I need the second or the third way to work because I have to be sure the second assembly is not confused with another one with a similar name.
ps2. I cannot find the documentation of pythonnet or see what kind of commands are available in my clr. Any idea?
Any tip is appreciated.
In second idea,
remove .dll from clr.AddReference('AssemblyB.dll') and use clr.AddReference('AssemblyB') because clr.AddReference() Requires only assembly name whether is it .exe of .dll not the folder path
That's why first idea is not working!
And for third idea clr.AddReferenceToFileAndPath() is not working because it part of Ironpython not pythonnet.
Ironpython is also used like pythonnet, but Ironpython is using Managed python code, while pythonnet is not using Managed code.

Unable to refer python libraries from Nifi ExecuteScript processor

I have been trying to run a python script in NiFi's ExecuteScript processor. Though the catch here is that I don't have server file location access and all the python libraries are installed at "/data/jython", "/data/jython/Lib/site-packages/" and "data/nltk"
Below is the import section of my python script:
import json, traceback, pycountry, requests, geocoder, re, sys, nltk
from nltk.sentiment.vader import SentimentIntensityAnalyzer
from nltk.corpus import stopwords
from java.nio.charset import StandardCharsets
from org.apache.commons.io import IOUtils
from org.apache.nifi.processor.io import StreamCallback
from org.python.core.util import StringUtil
I have added path reference to the packages/libraries:
Heres the screenshot of the error message:
Is there something I am missing? I have referred to another answer here, but couldn't figure out whats wrong with my code.
As the other answers state, Apache NiFi's ExecuteScript processor uses Jython, not Python. There is a limitation on the Jython library that it cannot handle native modules (modules that end in .so or are compiled C code, etc.). It is very likely that the pycountry module contains some native module. You can try a work-around proposed by Matt Burgess on the NiFi Developers Mailing List here.
ExecuteScript processor uses its own Jython Engine to execute your python scripts.
As the libraries which you are importing are not available in NIFI inbuild Jython Engine its throwing error.
SOLUTION:
If python is already installed on our machine with all those libraries (the same machine where your NIFI is installed) you can use that python engine
to execute your script. you can execute your python code using ExecuteProcess processor. see the configuration of ExecuteProcess.

Including modules in IronPython for .Net

I'm using IronPython 2.7.7 for .Net to run some python code (Installed using NuGet in an MVC project).
I got a simple test case to work quite easily, but when I went to include the actual python code I want to call I ran into problems with missing modules.
No module named Crypto.Cipher Description: An unhandled exception
occurred during the execution of the current web request. Please
review the stack trace for more information about the error and where
it originated in the code.
Exception Details: IronPython.Runtime.Exceptions.ImportException: No module named Crypto.Cipher
These are the modules / libraries that the python script has at the beginning, I can see in visual studio that it's complaining about missing Crypto.Cipter and random.
from datetime import datetime
from Crypto.Cipher import AES
import time
import random
import socket
This is the .Net code that I'm calling the Python code with.
var basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
var realPath = Path.Combine(basePath, #"Python/PythonThingy.py");
var ipy = Python.CreateRuntime();
dynamic pyThing = ipy.UseFile(realPath);
var items = pyThing.discover(timeout: 5);
I am not allowed to install Python on the production server, so I'm hoping I can include these libraries in some way and avoid rewriting a quite huge set of functions. Any tips on how to do this?
P.S. If not apparent from post, I know very little about python.

Extract GUID from ActiveX COM DLL using Python

How would you extract the GUID of an ActiveX COM DLL using only Python in a cross-platform manner?
I ran across pythoncom, which comes with pywin32. It has a LoadTypeLib function which can do just that:
import pythoncom
dll = pythoncom.LoadTypeLib("C:\\path\to\\my.dll")
print str(dll.GetLibAttr()[0])
This is better than my current solution which relies on an external CLI application, however a cross-platform solution would be even better as I don't believe pywin32 can be installed on a Linux CI easily.
I ended up using the wonderful comtypes package:
from comtypes.typeinfo import LoadTypeLibEx
lib = LoadTypeLibEx("C:\\path\to\\my.dll")
print lib.GetLibAttr().guid
The code is effectively the same; it literally calls the same LoadTypeLib from OleAut32 so it is Windows-only, however comtypes is installable through pip which makes the distribution easier.

Categories

Resources