How to make a hard-coded HTTP processing script dynamic? - python

I have a Jython 2.7 script that receives a URL and uses the parameters/values in the URL to create or update records.
Example URL: http://server:host/maximo/oslc/script/CREATEWO?&wonum=WO0001&description=Legacy&classstructureid=1666&wopriority=1&worktype=CM
Details:
Receive the URL and put the parameters/values in variables:
from psdi.server import MXServer
from psdi.mbo import MboSet
resp = {}
wonum = request.getQueryParam("wonum")
description = request.getQueryParam("description")
classstructureid = request.getQueryParam("classstructureid")
wopriority = request.getQueryParam("wopriority")
worktype = request.getQueryParam("worktype")
Some lines that aren't relevant to the question:
woset = MXServer.getMXServer().getMboSet("workorder",request.getUserInfo())
whereClause = "wonum= '" + wonum + "'"
woset.setWhere(whereClause)
woset.reset()
woMbo = woset.moveFirst()
Then use the values to either create a new record or update an existing record:
#If workorder already exists, update it:
if woMbo is not None:
woMbo.setValue("description", description)
woMbo.setValue("classstructureid", classstructureid)
woMbo.setValue("wopriority", wopriority)
woMbo.setValue("worktype", worktype)
woset.save()
woset.clear()
woset.close()
resp[0]='Updated workorder ' + wonum
#Else, create a new workorder
else:
woMbo=woset.add()
woMbo.setValue("wonum",wonum)
woMbo.setValue("description", description)
woMbo.setValue("classstructureid", classstructureid)
woMbo.setValue("wopriority", wopriority)
woMbo.setValue("worktype", worktype)
woset.save()
woset.clear()
woset.close()
resp[0]='Created workorder ' + wonum
responseBody =resp[0]
Question:
Unfortunately, the field names/values are hardcoded in 3 different places in the script.
I would like to enhance the script so that it is dynamic -- not hardcoded.
In other words, it would be great if the script could accept a list of parameters/values and simply loop through them to update or create a record in the respective fields.
Is it possible to do this?

You're using the Maximo Next Gen. REST API to execute an automation script that accepts an HTTP request with parameters and creates or updates a Work Order in the system. You want to make your script more generic (presumably to accept more paramaters for the created/updated work order) and/or other mbo's.
This can be achieved without developing automation scripts and just using the Next Gen. API you're already using to execute the script. The API already accepts create & update requests on the mxwo object structure with the ability to use all the fields, child objects, etc.
https://developer.ibm.com/static/site-id/155/maximodev/restguide/Maximo_Nextgen_REST_API.html#_creating_and_updating_resources

Assuming you are working always with the same query parameters, rather than define variables, loop through a list of strings and put them as key-value pairs
To populate
items = ["wonum", "description"]
resp = {k: request.getQueryParam(k) for k in items}
Then to set
for i in items:
woMbo.setValue(i, resp[i])
Otherwise, you are looking for URL parsing and the getQuery method, followed by a split("="), giving you ["wonum", "WO0001", "description", "Legacy"], for example, and you can loop over every other element to get you dynamic entries
l = ["wonum", "WO0001", "description", "Legacy"]
for i in range(0, len(l)-1, 2):
print(f'key:{l[i]}\tvalue:{l[i+1]}')
key:wonum value:WO0001
key:description value:Legacy
Note: This is subject to SQL injection attacks, and should be fixed
whereClause = "wonum= '" + wonum + "'"

Related

passing instance variable methods of a class [duplicate]

This question already has answers here:
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
Closed 5 years ago.
I'm working on a small web app to create some diagrams and I need to create a variable to hold a unique file name for each web app session so that users don't end up getting the wrong file when they save the diagram as a pdf. To do this I've wrapped the related views in a class using flask_classful and created an instance variable to hold the file name.
class PiperView(FlaskView):
route_base = '/'
def __init__(self):
self.piper_name = '_init_.pdf'
self.tst_index = 0
self.tst_plot = 0
self.tst_download = 0
self.tst_master = 0
#route('/',methods=['GET','POST'])
#route('/index/',methods=['GET','POST'],endpoint='index')
#nocache
def index(self):
self.piper_name = '_piper.pdf'
#test Code
#=======================================================================
file = open(fpath+'index.txt','a')
self.tst_index += 1
self.tst_master += 1
file.write(str(self.tst_index)+"."+str(self.tst_master)+") " +str(self.piper_name)+', ')
file.close()
#=======================================================================
plot_data = np.loadtxt('piper_data.csv', delimiter=',', skiprows=1 )
html_plot = Markup(piper(plot_data, ' ', alphalevel=1.0, color=False, file_nam=self.piper_name))
return render_template('plot.html',title='The Plot', figure=html_plot)
#route('/plot',methods=['GET','POST'],endpoint='plot')
#nocache
def plot(self):
self.piper_name = str(random.randint(0,10000001))+'_piper.pdf'
#test Code
#=======================================================================
file = open(fpath+'plot.txt','a')
self.tst_plot += 1
self.tst_master += 1
file.write(str(self.tst_plot)+"."+str(self.tst_master)+" ) " +str(self.piper_name)+', ')
file.close()
#=======================================================================
try:
f = request.files['data_file']
plot_data = np.loadtxt(f, delimiter=',', skiprows=1 )
html_plot = Markup(piper( plot_data, ' ', alphalevel=1.0, color=False, file_nam=self.piper_name))
return render_template('plot.html',title='The Plot', figure=html_plot)
except:
return render_template('plot.html',title='The Plot', figure="There Seems To Be A Problem With Your Data")
#route('/download',methods=['GET','POST'],endpoint='download')
#nocache
def download(self):
#test Code
#=======================================================================
file = open(fpath+'download.txt','a')
self.tst_download += 1
self.tst_master += 1
file.write(str(self.tst_download)+"."+str(self.tst_master)+") " +str(self.piper_name)+', ')
file.close()
#=======================================================================
return send_from_directory(directory=fpath,filename=self.piper_name)
The problem is that the instance variable that holds the file name doesn't get shared between methods. I added some test code to try and figure out what was happening. The 'tst_index', 'tst_plot' and 'tst_download' each behave as expected in that they get incremented but the 'tst_master' does not get incremented between method calls.
The output from the test code is:
index.txt
1.1) _piper.pdf,
plot.txt
1.1 ) 7930484_piper.pdf, 2.2 ) 9579691_piper.pdf,
download.txt
1.1) init.pdf, 2.2) init.pdf,
when I call the index view one (1) time, the plot view two (2) times and the download view (2) times. As you can see the 'tst_master' instance variable is not getting updated between method calls.
I know this would work in plain python as I tested it but what am I missing about flask and flask_classful that is causing this?
You are overcomplicating your task. You probably don't need to use flask-classful for it.
You can use ordinary flask sessions. Session is unique for each user. The only thing you need is to use some unique ID for each file. This file id can be user id if your users log in into your web app and their credentials are stored in the db. Or you can randomly generate this file id. Then you can store the filename in the flask session like this:
from flask import session
...
def plot(...):
session['user_file_name'] = user_file_name
def download(...):
user_file_name = session['user_file_name']
Hope this helps.
Embedding state like that in your application is generally a bad idea. There is no guarantee that the view instance the generates a response will persist for more than that one request. Store your data outside of flask- server-side on a database, a key-value store, or even a file on disk somewhere, or client-side in the browser. Flask has a number of plugins that make that easier (flask-sqlalchemy, flask-session, flask-redis, etc).
Flask natively offers the flask.session object, which stores information in cookies on the client side. flask-session would probably do what you want without much additional overhead if you were concerned with storing things server side. Just configure it with the File System session interface and you get a flask.session variable that handles all the magic of linking user requests to data stored on the filesystem.

SyntaxError: Missing parentheses in call to 'print' [duplicate]

This question already has answers here:
What does "SyntaxError: Missing parentheses in call to 'print'" mean in Python?
(11 answers)
Closed 5 years ago.
I've been trying to scrape some twitter's data, but when ever I run this code I get the error SyntaxError: Missing parentheses in call to 'print'.
Can someone please help me out with this one?
Thanks for your time :)
"""
Use Twitter API to grab user information from list of organizations;
export text file
Uses Twython module to access Twitter API
"""
import sys
import string
import simplejson
from twython import Twython
#WE WILL USE THE VARIABLES DAY, MONTH, AND YEAR FOR OUR OUTPUT FILE NAME
import datetime
now = datetime.datetime.now()
day=int(now.day)
month=int(now.month)
year=int(now.year)
#FOR OAUTH AUTHENTICATION -- NEEDED TO ACCESS THE TWITTER API
t = Twython(app_key='APP_KEY', #REPLACE 'APP_KEY' WITH YOUR APP KEY, ETC., IN THE NEXT 4 LINES
app_secret='APP_SECRET',
oauth_token='OAUTH_TOKEN',
oauth_token_secret='OAUTH_TOKEN_SECRET')
#REPLACE WITH YOUR LIST OF TWITTER USER IDS
ids = "4816,9715012,13023422, 13393052, 14226882, 14235041, 14292458, 14335586, 14730894,\
15029174, 15474846, 15634728, 15689319, 15782399, 15946841, 16116519, 16148677, 16223542,\
16315120, 16566133, 16686673, 16801671, 41900627, 42645839, 42731742, 44157002, 44988185,\
48073289, 48827616, 49702654, 50310311, 50361094,"
#ACCESS THE LOOKUP_USER METHOD OF THE TWITTER API -- GRAB INFO ON UP TO 100 IDS WITH EACH API CALL
#THE VARIABLE USERS IS A JSON FILE WITH DATA ON THE 32 TWITTER USERS LISTED ABOVE
users = t.lookup_user(user_id = ids)
#NAME OUR OUTPUT FILE - %i WILL BE REPLACED BY CURRENT MONTH, DAY, AND YEAR
outfn = "twitter_user_data_%i.%i.%i.txt" % (now.month, now.day, now.year)
#NAMES FOR HEADER ROW IN OUTPUT FILE
fields = "id screen_name name created_at url followers_count friends_count statuses_count \
favourites_count listed_count \
contributors_enabled description protected location lang expanded_url".split()
#INITIALIZE OUTPUT FILE AND WRITE HEADER ROW
outfp = open(outfn, "w")
outfp.write(string.join(fields, "\t") + "\n") # header
#THE VARIABLE 'USERS' CONTAINS INFORMATION OF THE 32 TWITTER USER IDS LISTED ABOVE
#THIS BLOCK WILL LOOP OVER EACH OF THESE IDS, CREATE VARIABLES, AND OUTPUT TO FILE
for entry in users:
#CREATE EMPTY DICTIONARY
r = {}
for f in fields:
r[f] = ""
#ASSIGN VALUE OF 'ID' FIELD IN JSON TO 'ID' FIELD IN OUR DICTIONARY
r['id'] = entry['id']
#SAME WITH 'SCREEN_NAME' HERE, AND FOR REST OF THE VARIABLES
r['screen_name'] = entry['screen_name']
r['name'] = entry['name']
r['created_at'] = entry['created_at']
r['url'] = entry['url']
r['followers_count'] = entry['followers_count']
r['friends_count'] = entry['friends_count']
r['statuses_count'] = entry['statuses_count']
r['favourites_count'] = entry['favourites_count']
r['listed_count'] = entry['listed_count']
r['contributors_enabled'] = entry['contributors_enabled']
r['description'] = entry['description']
r['protected'] = entry['protected']
r['location'] = entry['location']
r['lang'] = entry['lang']
#NOT EVERY ID WILL HAVE A 'URL' KEY, SO CHECK FOR ITS EXISTENCE WITH IF CLAUSE
if 'url' in entry['entities']:
r['expanded_url'] = entry['entities']['url']['urls'][0]['expanded_url']
else:
r['expanded_url'] = ''
print r
#CREATE EMPTY LIST
lst = []
#ADD DATA FOR EACH VARIABLE
for f in fields:
lst.append(unicode(r[f]).replace("\/", "/"))
#WRITE ROW WITH DATA IN LIST
outfp.write(string.join(lst, "\t").encode("utf-8") + "\n")
outfp.close()
It seems like you are using python 3.x, however the code you are running here is python 2.x code. Two ways to solve this:
Download python 2.x on Python's website and use it to run your script
Add parentheses around your print call at the end by replacing print r by print(r) at the end (and keep using python 3)
But today, a growing majority of python programmers are using python 3, and the official python wiki states the following:
Python 2.x is legacy, Python 3.x is the present and future of the
language
If I were you, I'd go with the second option and keep using python 3.
Looks like you trying to run Python 2 code in Python 3, where print is function and required parentheses:
print(foo)
You just need to add pranethesis to your print statmetnt to convert it to a function, like the error says:
print expression -> print(expression)
In Python 2, print is a statement, but in Python 3, print is a function. So you could alternatively just run your code with Python 2. print(expression) is backwards compatible with Python 2.
Also, why are you capitalizing all your comments? It's annoying. Your code also violates PEP 8 in several ways. Get an editor like PyCharm (it's free) that can automatically detect errors like this.
You didn't leave a space between # and your comment
You didn't leave spaces between = and other tokens
Within python 2, print has been a statement, not a function. That means you can use it without parentheses. In python 3, that has changed. It is a function there and you need to use print(foo) instead of print foo.

Updating DataStore JSON values using endpoints (Python)

I am trying to use endpoints to update some JSON values in my datastore. I have the following Datastore in GAE...
class UsersList(ndb.Model):
UserID = ndb.StringProperty(required=True)
ArticlesRead = ndb.JsonProperty()
ArticlesPush = ndb.JsonProperty()
In general what I am trying to do with the API is have the method take in a UserID and a list of articles read (with an article being represented by a dictionary holding an ID and a boolean field saying whether or not the user liked the article). My messages (centered on this logic) are the following...
class UserID(messages.Message):
id = messages.StringField(1, required=True)
class Articles(messages.Message):
id = messages.StringField(1, required=True)
userLiked = messages.BooleanField(2, required=True)
class UserIDAndArticles(messages.Message):
id = messages.StringField(1, required=True)
items = messages.MessageField(Articles, 2, repeated=True)
class ArticleList(messages.Message):
items = messages.MessageField(Articles, 1, repeated=True)
And my API/Endpoint method that is trying to do this update is the following...
#endpoints.method(UserIDAndArticles, ArticleList,
name='user.update',
path='update',
http_method='GET')
def get_update(self, request):
userID = request.id
articleList = request.items
queryResult = UsersList.query(UsersList.UserID == userID)
currentList = []
#This query always returns only one result back, and this for loop is the only way
# I could figure out how to access the query results.
for thing in queryResult:
currentList = json.loads(thing.ArticlesRead)
for item in articleList:
currentList.append(item)
for blah in queryResult:
blah.ArticlesRead = json.dumps(currentList)
blah.put()
for thisThing in queryResult:
pushList = json.loads(thisThing.ArticlesPush)
return ArticleList(items = pushList)
I am having two problems with this code. The first is that I can't seem to figure out (using the localhost Google APIs Explorer) how to send a list of articles to the endpoints method using my UserIDAndArticles class. Is it possible to have a messages.MessageField() as an input to an endpoint method?
The other problem is that I am getting an error on the 'blah.ArticlesRead = json.dumps(currentList)' line. When I try to run this method with some random inputs, I get the following error...
TypeError: <Articles
id: u'hi'
userLiked: False> is not JSON serializable
I know that I have to make my own JSON encoder to get around this, but I'm not sure what the format of the incoming request.items is like and how I should encode it.
I am new to GAE and endpoints (as well as this kind of server side programming in general), so please bear with me. And thanks so much in advance for the help.
A couple things:
http_method should definitely be POST, or better yet PATCH because you're not overwriting all existing values but only modifying a list, i.e. patching.
you don't need json.loads and json.dumps, NDB does it automatically for you.
you're mixing Endpoints messages and NDB model properties.
Here's the method body I came up with:
# get UsersList entity and raise an exception if none found.
uid = request.id
userlist = UsersList.query(UsersList.UserID == uid).get()
if userlist is None:
raise endpoints.NotFoundException('List for user ID %s not found' % uid)
# update user's read articles list, which is actually a dict.
for item in request.items:
userslist.ArticlesRead[item.id] = item.userLiked
userslist.put()
# assuming userlist.ArticlesPush is actually a list of article IDs.
pushItems = [Article(id=id) for id in userlist.ArticlesPush]
return ArticleList(items=pushItems)
Also, you should probably wrap this method in a transaction.

couchdb-python change notifications

I'm trying to use couchdb.py to create and update databases. I'd like to implement notification changes, preferably in continuous mode. Running the test code posted below, I don't see how the changes scheme works within python.
class SomeDocument(Document):
#############################################################################
# def __init__ (self):
intField = IntegerField()#for now - this should to be an integer
textField = TextField()
couch = couchdb.Server('http://127.0.0.1:5984')
databasename = 'testnotifications'
if databasename in couch:
print 'Deleting then creating database ' + databasename + ' from server'
del couch[databasename]
db = couch.create(databasename)
else:
print 'Creating database ' + databasename + ' on server'
db = couch.create(databasename)
for iii in range(5):
doc = SomeDocument(intField=iii,textField='somestring'+str(iii))
doc.store(db)
print doc.id + '\t' + doc.rev
something = db.changes(feed='continuous',since=4,heartbeat=1000)
for iii in range(5,10):
doc = SomeDocument(intField=iii,textField='somestring'+str(iii))
doc.store(db)
time.sleep(1)
print something
print db.changes(since=iii-1)
The value
db.changes(since=iii-1)
returns information that is of interest, but in a format from which I haven't worked out how to extract the sequence or revision numbers, or the document information:
{u'last_seq': 6, u'results': [{u'changes': [{u'rev': u'1-9c1e4df5ceacada059512a8180ead70e'}], u'id': u'7d0cb1ccbfd9675b4b6c1076f40049a8', u'seq': 5}, {u'changes': [{u'rev': u'1-bbe2953a5ef9835a0f8d548fa4c33b42'}], u'id': u'7d0cb1ccbfd9675b4b6c1076f400560d', u'seq': 6}]}
Meanwhile, the code I'm really interested in using:
db.changes(feed='continuous',since=4,heartbeat=1000)
Returns a generator object and doesn't appear to provide notifications as they come in, as the CouchDB guide suggests ....
Has anyone used changes in couchdb-python successfully?
I use long polling rather than continous, and that works ok for me. In long polling mode db.changes blocks until at least one change has happened, and then returns all the changes in a generator object.
Here is the code I use to handle changes. settings.db is my CouchDB Database object.
since = 1
while True:
changes = settings.db.changes(since=since)
since = changes["last_seq"]
for changeset in changes["results"]:
try:
doc = settings.db[changeset["id"]]
except couchdb.http.ResourceNotFound:
continue
else:
// process doc
As you can see it's an infinite loop where we call changes on each iteration. The call to changes returns a dictionary with two elements, the sequence number of the most recent update and the objects that were modified. I then loop through each result loading the appropriate object and processing it.
For a continuous feed, instead of the while True: line use for changes in settings.db.changes(feed="continuous", since=since).
I setup a mailspooler using something similar to this. You'll need to also load couchdb.Session() I also use a filter for only receiving unsent emails to the spooler changes feed.
from couchdb import Server
s = Server('http://localhost:5984/')
db = s['testnotifications']
# the since parameter defaults to 'last_seq' when using continuous feed
ch = db.changes(feed='continuous',heartbeat='1000',include_docs=True)
for line in ch:
doc = line['doc']
// process doc here
doc['priority'] = 'high'
doc['recipient'] = 'Joe User'
# doc['state'] + 'sent'
db.save(doc)
This will allow you access your doc directly from the changes feed, manipulate your data as you see fit, and finally update you document. I use a try/except block on the actual 'db.save(doc)' so I can catch when a document has been updated while I was editing and reload the doc before saving.

SUDS - programmatic access to methods and types

I'm investigating SUDS as a SOAP client for python. I want to inspect the methods available from a specified service, and the types required by a specified method.
The aim is to generate a user interface, allowing users to select a method, then fill in values in a dynamically generated form.
I can get some information on a particular method, but am unsure how to parse it:
client = Client(url)
method = client.sd.service.methods['MyMethod']
I am unable to programmaticaly figure out what object type I need to create to be able to call the service
obj = client.factory.create('?')
res = client.service.MyMethod(obj, soapheaders=authen)
Does anyone have some sample code?
Okay, so SUDS does quite a bit of magic.
A suds.client.Client, is built from a WSDL file:
client = suds.client.Client("http://mssoapinterop.org/asmx/simple.asmx?WSDL")
It downloads the WSDL and creates a definition in client.wsdl. When you call a method using SUDS via client.service.<method> it's actually doing a whole lot of recursive resolve magic behind the scenes against that interpreted WSDL. To discover the parameters and types for methods you'll need to introspect this object.
For example:
for method in client.wsdl.services[0].ports[0].methods.values():
print '%s(%s)' % (method.name, ', '.join('%s: %s' % (part.type, part.name) for part in method.soap.input.body.parts))
This should print something like:
echoInteger((u'int', http://www.w3.org/2001/XMLSchema): inputInteger)
echoFloatArray((u'ArrayOfFloat', http://soapinterop.org/): inputFloatArray)
echoVoid()
echoDecimal((u'decimal', http://www.w3.org/2001/XMLSchema): inputDecimal)
echoStructArray((u'ArrayOfSOAPStruct', http://soapinterop.org/xsd): inputStructArray)
echoIntegerArray((u'ArrayOfInt', http://soapinterop.org/): inputIntegerArray)
echoBase64((u'base64Binary', http://www.w3.org/2001/XMLSchema): inputBase64)
echoHexBinary((u'hexBinary', http://www.w3.org/2001/XMLSchema): inputHexBinary)
echoBoolean((u'boolean', http://www.w3.org/2001/XMLSchema): inputBoolean)
echoStringArray((u'ArrayOfString', http://soapinterop.org/): inputStringArray)
echoStruct((u'SOAPStruct', http://soapinterop.org/xsd): inputStruct)
echoDate((u'dateTime', http://www.w3.org/2001/XMLSchema): inputDate)
echoFloat((u'float', http://www.w3.org/2001/XMLSchema): inputFloat)
echoString((u'string', http://www.w3.org/2001/XMLSchema): inputString)
So the first element of the part's type tuple is probably what you're after:
>>> client.factory.create(u'ArrayOfInt')
(ArrayOfInt){
_arrayType = ""
_offset = ""
_id = ""
_href = ""
_arrayType = ""
}
Update:
For the Weather service it appears that the "parameters" are a part with an element not a type:
>>> client = suds.client.Client('http://www.webservicex.net/WeatherForecast.asmx?WSDL')
>>> client.wsdl.services[0].ports[0].methods.values()[0].soap.input.body.parts[0].element
(u'GetWeatherByZipCode', http://www.webservicex.net)
>>> client.factory.create(u'GetWeatherByZipCode')
(GetWeatherByZipCode){
ZipCode = None
}
But this is magic'd into the parameters of the method call (a la client.service.GetWeatherByZipCode("12345"). IIRC this is SOAP RPC binding style? I think there's enough information here to get you started. Hint: the Python command line interface is your friend!
According to suds documentation, you can inspect service object with __str()__. So the following gets a list of methods and complex types:
from suds.client import Client;
url = 'http://www.webservicex.net/WeatherForecast.asmx?WSDL'
client = Client(url)
temp = str(client);
The code above produces following result (contents of temp):
Suds ( https://fedorahosted.org/suds/ ) version: 0.3.4 (beta) build: R418-20081208
Service ( WeatherForecast ) tns="http://www.webservicex.net"
Prefixes (1)
ns0 = "http://www.webservicex.net"
Ports (2):
(WeatherForecastSoap)
Methods (2):
GetWeatherByPlaceName(xs:string PlaceName, )
GetWeatherByZipCode(xs:string ZipCode, )
Types (3):
ArrayOfWeatherData
WeatherData
WeatherForecasts
(WeatherForecastSoap12)
Methods (2):
GetWeatherByPlaceName(xs:string PlaceName, )
GetWeatherByZipCode(xs:string ZipCode, )
Types (3):
ArrayOfWeatherData
WeatherData
WeatherForecasts
This would be much easier to parse. Also every method is listed with their parameters along with their types. You could, probably, even use just regular expression to extract information you need.
Here's a quick script I wrote based on the above information to list the input methods suds reports as available on a WSDL. Pass in the WSDL URL. Works for the project I'm currently on, I can't guarantee it for yours.
import suds
def list_all(url):
client = suds.client.Client(url)
for service in client.wsdl.services:
for port in service.ports:
methods = port.methods.values()
for method in methods:
print(method.name)
for part in method.soap.input.body.parts:
part_type = part.type
if(not part_type):
part_type = part.element[0]
print(' ' + str(part.name) + ': ' + str(part_type))
o = client.factory.create(part_type)
print(' ' + str(o))
You can access suds's ServiceDefinition object. Here's a quick sample:
from suds.client import Client
c = Client('http://some/wsdl/link')
types = c.sd[0].types
Now, if you want to know the prefixed name of a type, it's also quite easy:
c.sd[0].xlate(c.sd[0].types[0][0])
This double bracket notation is because the types are a list (hence a first [0]) and then in each item on this list there may be two items. However, suds's internal implementation of __unicode__ does exactly that (i.e. takes only the first item on the list):
s.append('Types (%d):' % len(self.types))
for t in self.types:
s.append(indent(4))
s.append(self.xlate(t[0]))
Happy coding ;)
Once you created WSDL method object you can get information about it from it's __metadata__, including list of it's arguments' names.
Given the argument's name, you can access it's actual instance in the method created. That instance also contains it's information in __metadata__, there you can get it's type name
# creating method object
method = client.factory.create('YourMethod')
# getting list of arguments' names
arg_names = method.__metadata__.ordering
# getting types of those arguments
types = [method.__getitem__(arg).__metadata__.sxtype.name for arg in arg_names]
Disclaimer: this only works with complex WSDL types. Simple types, like strings and numbers, are defaulted to None
from suds.client import Client
url = 'http://localhost:1234/sami/2009/08/reporting?wsdl'
client = Client(url)
functions = [m for m in client.wsdl.services[0].ports[0].methods]
count = 0
for function_name in functions:
print (function_name)
count+=1
print ("\nNumber of services exposed : " ,count)
i needed an example of using suds with objects.
beside the answers found here, i found a very good article
that answered my question even further.
here is a short summary:
first, print the client to see an overview of it's content.
from suds.client import Client client =
Client("https://wsvc.cdiscount.com/MarketplaceAPIService.svc?wsdl")
print client
second, create an instance of a type (using it's name including it's prefix ns*.), and print it, to see it's member data.
HeaderMessage = client.factory.create('ns0:HeaderMessage')
print HeaderMessage
to fill your object's data members, either assign them a scalar value for scalar members, or a dict, to object members.
HeaderMessage.Context = {
"CatalogID": "XXXXX"
"CustomerID": 'XXXXX'
"SiteID": 123
}
members whose type name start with ArrayOf expect a list of objects of the type mentioned in the rest of the type name.
ArrayOfDomainRights = client.factory.create('ns0:ArrayOfDomainRights')
ArrayOfDomainRights.DomainRights = [XXXXXXXXXXXXX, XXXXXXXXXXXX]
i needed an example of using suds with objects.
beside the answers found here, i found a very good article
that answered my question even further.
here is a short summary:
first, print the client to see an overview of it's content.
from suds.client import Client client =
Client("https://wsvc.cdiscount.com/MarketplaceAPIService.svc?wsdl")
print client
second, create an instance of a type (using it's name including it's prefix ns*.), and print it, to see it's member data.
HeaderMessage = client.factory.create('ns0:HeaderMessage')
print HeaderMessage
to fill your object's data members, either assign them a scalar value for scalar members, or a dict, to object members.
HeaderMessage.Context = {
"CatalogID": "XXXXX"
"CustomerID": 'XXXXX'
"SiteID": 123
}
members whose type name start with ArrayOf expect a list of objects of the type mentioned in the rest of the type name.
ArrayOfDomainRights = client.factory.create('ns0:ArrayOfDomainRights')
ArrayOfDomainRights.DomainRights = [XXXXXXXXXXXXX, XXXXXXXXXXXX]

Categories