Outside the Box 2 – Calling the Shapeways API from Python
I received a question on accessing the ShapeWays API from my last “Outside the Box” blog and figured I should dig in and figure out what is going on. Shapeways has a web service API that uses SOAP and a WSDL page (http://en.wikipedia.org/wiki/Web_Services_Description_Language) as described here
http://www.shapeways.com/api
This API is a bit different than the REST API which I wrote a script to access in my previous blog post. In order to use this API, I ended up modifying a script originally put together by Michael Foord (author of “IronPython in Action”) that creates a .NET assembly on the fly for a given WSDL url.
The two scripts are in gists at the end of this post
Place both of these scripts in the same directory and open the “useshapeways.py” script. Here’s the script itself
"""Sample script that accesses the shapeways API [url]http://www.shapeways.com/api[/url] """ import wsdlprovider wsdl_url = "http://api.shapeways.com/v1/wsdl.php" username = "username" password = "password" application_id = "rhinotest" assembly = wsdlprovider.GetWebservice(wsdl_url) shapeways = assembly.SWwsdlService() session_id = shapeways.login(username, password, application_id) if session_id: #get list of printers available printers = shapeways.getPrinters(session_id, "", application_id) if printers: for printer in printers: print "printer:", printer.title for material in printer.materials: print " - material ", material.title
The script uses the wsdlprovider script to generate a .NET assembly from the shapeways wsdl url. This assembly has a class in it called SWwsdlService which we create an instance of and call functions on. It looks like a normal class to python, but all of the function calls are sent to ShapeWays over the internet and response are turned into classes that you can use. This sample simply logs into shapeways to get a “session id” and then asks Shapeways for a list of it’s available printers along with what materials each printer supports.
At the time of this blog post, the printed output from this script is
printer: Somatech FDM
- material Grey Robust
printer: Somatech Objet 720
- material Black Detail
- material White Detail
- material Transparent Detail
printer: SLS Printer
- material White Strong & Flexible
printer: Metal Printer matt
- material Gold Plated Glossy
- material Antique Bronze Glossy
- material Antique Bronze Matte
- material Stainless Steel
printer: SLS Color Printer
- material Black Strong & Flexible
printer: Silver Printer
- material Silver Glossy
- material Silver
printer: ZPrinter 650
- material Sandstone
- material Full Color Sandstone
printer: SLS Alumide
- material Alumide
printer: Glass Printer
- material High Gloss Black Glass
- material High Gloss White Glass
- material Milky White Matte Glass
printer: Metal printer Gold
- material Gold Plated Matte
printer: SLS Color Printer New
- material Dark Grey Strong and Flexible
- material Indigo Strong and Flexible
- material Winter Red Strong and Flexible
printer: HD printer
- material Frosted Detail
printer: UHD printer
- material Frosted Ultra Detail
printer: SLS Printer polished
- material White Strong & Flexible Polished
printer: Ceramics printer
- material Glazed Ceramics
Pretty neat!
"""Sample script that accesses the shapeways API | |
http://www.shapeways.com/api | |
""" | |
import wsdlprovider | |
wsdl_url = "http://api.shapeways.com/v1/wsdl.php" | |
username = "username" | |
password = "password" | |
application_id = "rhinotest" | |
assembly = wsdlprovider.GetWebservice(wsdl_url) | |
shapeways = assembly.SWwsdlService() | |
session_id = shapeways.login(username, password, application_id) | |
if session_id: | |
#get list of printers available | |
printers = shapeways.getPrinters(session_id, "", application_id) | |
if printers: | |
for printer in printers: | |
print "printer:", printer.title | |
for material in printer.materials: | |
print " – material ", material.title |
''' | |
Generate a proxy class for a SOAP web service from its WSDL. | |
Based on C# implementation from the DynamicWebService IronPython example. | |
''' | |
# Original script from "IronPython in Action" Book code found at | |
# http://code.google.com/p/ironpython/ | |
# http://www.voidspace.org.uk/ironpython/ | |
# 2 June 2011 – S. Baer | |
# Modified to cache the generated assemblies for performance purposes | |
import clr | |
clr.AddReference("System.Web.Services") | |
clr.AddReference("System.Xml") | |
from System.Web.Services.Description import ( | |
ServiceDescription, ServiceDescriptionImporter | |
) | |
from System.Web.Services.Protocols import SoapHttpClientProtocol | |
from System.IO import MemoryStream | |
from System.Net import WebClient | |
from System.CodeDom import ( | |
CodeCompileUnit, CodeNamespace | |
) | |
from System.CodeDom.Compiler import CodeDomProvider, CompilerParameters | |
from System.Xml.Serialization import CodeGenerationOptions | |
def GetBytes(url): | |
'download the file at url' | |
return WebClient().DownloadData(url) | |
def CreateWebServiceFromWsdl(wsdl): | |
'convert the WSDL into an assembly containing the web service proxy classes' | |
# generate codeDom from wsdl | |
sd = ServiceDescription.Read(MemoryStream(wsdl)) | |
importer = ServiceDescriptionImporter() | |
importer.ServiceDescriptions.Add(sd) | |
codeCompileUnit = CodeCompileUnit() | |
codeNamespace = CodeNamespace("") | |
codeCompileUnit.Namespaces.Add(codeNamespace) | |
importer.CodeGenerationOptions = (CodeGenerationOptions.GenerateNewAsync | |
| CodeGenerationOptions.GenerateOldAsync) | |
importer.Import(codeNamespace, codeCompileUnit) | |
# compile CodeDom into an assembly | |
provider = CodeDomProvider.CreateProvider("CS") | |
compilerParams = CompilerParameters() | |
compilerParams.GenerateInMemory = True | |
compilerParams.IncludeDebugInformation = False | |
results = provider.CompileAssemblyFromDom(compilerParams, codeCompileUnit) | |
generatedAssembly = results.CompiledAssembly | |
return generatedAssembly | |
# dictionary used to cache assemblies generated from wsdl | |
__assembly_cache = {} | |
def GetWebservice(url): | |
key = url.lower() | |
if not __assembly_cache.has_key(key): | |
'download the WSDL for the service URL and generate an assembly from it' | |
if url.lower().endswith(".asmx"): url += "?WSDL" | |
data = GetBytes(url) | |
assembly = CreateWebServiceFromWsdl(data) | |
if not assembly: return None | |
__assembly_cache[key] = assembly | |
return __assembly_cache[key] | |
def FindProxyType(assembly): | |
"""if you aren't sure of the name of the proxy type that will be generated, | |
use this to find it""" | |
for name in dir(assembly): | |
attr = getattr(assembly, name) | |
if type(attr) is type and issubclass(attr, SoapHttpClientProtocol): | |
return attr |
Leave a Reply