Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
the
Jul 18, 2004

by Cowcaster
Ok, cool.

So, I'm importing a list of every single zipcode in the US and its corresponding latitude/longitude and state abbreviation. That seems like a prime candidate for a dictionary sorted by zipcode, right?

Adbot
ADBOT LOVES YOU

SurgicalOntologist
Jun 17, 2004

If you're going to be retrieving information later by zipcode, then yes. If you're going to be retrieving information by state, then use state for the keys. Etc.

the
Jul 18, 2004

by Cowcaster

SurgicalOntologist posted:

If you're going to be retrieving information later by zipcode, then yes. If you're going to be retrieving information by state, then use state for the keys. Etc.

It's going to be by zipcode, because I need to map the zip codes I retrieved in the previous posts with the ones I'd import from this list.

namaste friends
Sep 18, 2004

by Smythe

the posted:

It's going to be by zipcode, because I need to map the zip codes I retrieved in the previous posts with the ones I'd import from this list.

Dude, if you build a dictionary by zipcode, you're not going to have to do any searching to look up an entry.

e: This is also one of my favorite things about Python, defaultdict:
http://ianloic.com/2011/06/16/pythons-collections-defaultdict/


e2: oh wow I just stumbled across this tutorial on comprehensions:

http://tech.pro/tutorial/1554/four-tricks-for-comprehensions-in-python

namaste friends fucked around with this message at 17:04 on Jul 11, 2014

SurgicalOntologist
Jun 17, 2004

I have another OCD best-practices question about library design.

Is it bad form to have two functions with the same name in different modules?

I have pyphase.discrete.relative_phase and pyphase.continuous.relative_phase. Is that okay? They're not drop-in replacements for each other, because the discrete version also returns the indices at which it's reporting phases, although for symmetry I could make the continuous version return all the indices.

onionradish
Jul 6, 2006

That's spicy.

the posted:

I'm using Beatbox to query a database in Salesforce. I'm grabbing a list of Account zip code fields. They get returned as type 'instance' and I convert them to a string before doing anything with them.

the, when you initialize beatbox, are you using beatbox.Client() or beatbox.PythonClient()?

I remember looking at the code for beatbox when you were posting about having to wrap everything in str() and shuddering -- as SurgicalOntologist has suggested, the API is godawful.

However, it looks like it's because the default Client API is just a wrapper around some horrifying XML thing that is just dumping out results in a list that you then have to wrap in str(), which is what's part of what's causing your encoding issues.

beatbox includes PythonClient which claims to turn "the returned objects into proper Python data types. e.g. integer fields return integers" and appears to return a list of dictionaries (their example):

Python code:
>>> svc = beatbox.PythonClient()
>>> svc.login('username', 'passwordTOKEN')
>>> res = svc.query("SELECT Id, FirstName, LastName FROM Contact WHERE LastName='Doe'")
>>> res[0]
{'LastName': 'Doe', 'type': 'Contact', 'Id': '0037000000eRf6vAAC', 'FirstName': 'John'}

the
Jul 18, 2004

by Cowcaster
Huh, I've been using Client. Interesting.

onionradish
Jul 6, 2006

That's spicy.

the posted:

Huh, I've been using Client. Interesting.

Switch and your code should be MUCH easier to work with. You'll have to change some of your code where you were doing list indexing to get access a record's field, but result['FirstName'] will be a lot easier to read and work with than remembering that result[3] is supposed to be FirstName.

It looks like PythonClient also supports accessing the dictionary in dot-notation, meaning result.FirstName would also work.

the
Jul 18, 2004

by Cowcaster
Appending onto my earlier posts, has anyone used Basemap within matplotlib for map projections before? I've got a list here of ~95,000 latitude/longitude coordinates, and I'd like to at least put them as dots on a map, and ideally have some way to measure density by increasing dot size or something.

For example the docs list a variety of mapping projections, but I am not really sure which one I need to use.

FoiledAgain
May 6, 2007

BabyFur Denny posted:

Ok, thanks for that, and I think I made some progress in understanding the whole thing.

But the way you set up show_selection, I cannot do anything with the selected class, since the function only has access to zahl_var and it's value, not the actual class. If I try to pass the class to show_selection via command=self.show_selection(element) in the radio button (and of course using def show_selection(self, element): it no longer works.

And I haven't found out how to switch the messagebox for a label that can be updated in show_selection.

For any of the tkinter widgets that have a "command" option, you have to pass a function *name*. You can't pass a call to a function, because, well, that calls your function immediately rather than waiting for a click. So always do this:

Button(master, command=self.some_func)

Never do this:

Button(master, command=self.some_func())

That means you cannot easily pass arguments to the function, but there are ways around this. One is to make stuff that needs to be shared across methods into attributes of App, and use tkinter variables, so they are available everywhere. Here's how you could that for your code, although this is not the most elegant soluation to this particular problem.

code:
from tkinter import *
import tkinter.messagebox as MessageBox

class App(Toplevel):

    def __init__(self,master):
        super(App, self).__init__(master)#this is Python 3, don't know about Python 2
        self.elements = [Zahl('Eins','Eine Eins'), Zahl('Zwei','Eine Zwei'), Zahl('Drei','Eine Drei')]
        self.zahl_var = StringVar()#you should google "tkinter variables" if you don't know about these yet
        self.zahl_var.set(self.elements[0].Beschreibung)
        self.generiereButtons()

    def generiereButtons(self):
        button_frame = LabelFrame(self, text='Click a button!')
        self.zahl_label = Label(button_frame)
        for element in self.elements:
            r = Radiobutton(button_frame, text=element.name, variable=self.zahl_var, value=element.name, command=self.show_selection)
            r.pack()
        self.zahl_label.pack()
        button_frame.pack()

    def show_selection(self):
        selection = self.zahl_var.get()
        zahl = self.elements(selection)
        self.zahl_label.config(text = selection) 


class Zahl():
    def __init__(self, name, Beschreibung):
        self.name = name
        self.Beschreibung = Beschreibung


if __name__ == '__main__':

    root = Tk()
    app = App(root)
    root.mainloop()
If you abosolutely have to call a method with an argument from a button, then you can use lambdas, but it can be ugly. In your case you would change the for-loop to look like this:

code:
for element in self.elements:
            r = Radiobutton(button_frame, text=element.name, variable=self.zahl_var, value=element.name, command=lambda x=element, y=label:self.show_selection(element,label))
But in your case, we can actually accomplish what you want by only using tkinter variables, and without even calling a show_selection method. If you give a Label a textvariable, then its text will change automatically whenever the value of that variable changes. So here if you use the same variable for the Label and the Radiobutton, and the Label will change each time the user clicks a different radion button:

code:
from tkinter import *

class App(Toplevel):

    def __init__(self,master):
        super(App, self).__init__(master)#this is Python 3, don't know about Python 2
        self.elements = [Zahl('Eins','Eine Eins'), Zahl('Zwei','Eine Zwei'), Zahl('Drei','Eine Drei')]
        self.zahl_var = StringVar()#you should google "tkinter variables" if you don't know about these yet
        self.zahl_var.set(self.elements[0].Beschreibung)
        self.generiereButtons()

    def generiereButtons(self):
        button_frame = LabelFrame(self, text='Click a button!')
        zahl_label = Label(button_frame,textvariable = self.zahl_var)
        for element in self.elements:
            r = Radiobutton(button_frame, text=element.name, variable=self.zahl_var, value=element.name)
            r.pack()
        zahl_label.pack()
        button_frame.pack()

class Zahl():
    def __init__(self, name, Beschreibung):
        self.name = name
        self.Beschreibung = Beschreibung


if __name__ == '__main__':
    root = Tk()
    app = App(root)
    root.mainloop()

QuarkJets
Sep 8, 2008

SurgicalOntologist posted:

I have another OCD best-practices question about library design.

Is it bad form to have two functions with the same name in different modules?

I have pyphase.discrete.relative_phase and pyphase.continuous.relative_phase. Is that okay? They're not drop-in replacements for each other, because the discrete version also returns the indices at which it's reporting phases, although for symmetry I could make the continuous version return all the indices.

Yes, it's totally okay so long as you keep your namespace clean when working with both functions. Someone doing something like this would run into issues:

Python code:
from pyphase.continuous import *
from pyphase.discrete import *
In theory, an unwitting user who uses bad namespace practices like the ones above could screw themselves up without realizing it. MATLAB users transitioning to Python tend to do this more than anyone else, since they're used to having a polluted namespace and like not having to import stuff. It's up to you to decide whether you care enough to rename one of the functions (I don't think that you should bother)

the
Jul 18, 2004

by Cowcaster
:getin:

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell


Nicely done!

so, that's the coordinates associated with each zip code right? I guess that's the geographical center?

the
Jul 18, 2004

by Cowcaster

Thermopyle posted:

Nicely done!

so, that's the coordinates associated with each zip code right? I guess that's the geographical center?

Yeah, I ended up centering the map on the geographical center of the US, and I guessed the borders based on looking at a map. If anyone is interested, this tutorial explains it very well.

code:
map = Basemap(projection='merc', lat_0=39.8, lon_0 = -98.7, 
resolution = 'h', area_thresh = 1000.0, llcrnrlon=-125, llcrnrlat=25, urcrnrlon=-65,urcrnrlat=50)

x,y = map(lons,lats)

map.plot(x,y, 'bo', markersize=1)
map.drawcoastlines()
map.drawcountries()
map.drawmapboundary()

plt.show()

the
Jul 18, 2004

by Cowcaster
So, again, there's probably a faster and more "pythonic" way to do this. Basically, in the mapping I'm doing, if there is a duplicate zip code (like two business in the same city) it will just overwrite the same dot. To account for this, I've decided to "nudge" the coordinate slightly to a random direction, so that the points won't overwrite each other.

The issue I'm coming up with is that the loop I use to check for the duplicates is rather lengthy, and I'm looking for a faster way. Right now the list I'm working with is 18,660 locations, so the loop below is running 348,195,600 times. Not ideal.

code:
lats = []
lons = []

icount = 0
for i in final_map_list:
	icount += 1
	jcount = 0
	for j in final_map_list:
		jcount += 1
		sum1 = i[0] + i[1]
		sum2 = j[0] + j[1]
		if icount != jcount and sum1 == sum2:
			i[0],i[1] = nudge(i[0], i[1])
			lats.append(i[0])
			lons.append(i[1])
		else:
			lats.append(i[0])
			lons.append(i[1])
In that code, map_list is a list of latitudes and longitudes, so map_list[1] = [24.34214, -34,20033]

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

the posted:

So, again, there's probably a faster and more "pythonic" way to do this. Basically, in the mapping I'm doing, if there is a duplicate zip code (like two business in the same city) it will just overwrite the same dot. To account for this, I've decided to "nudge" the coordinate slightly to a random direction, so that the points won't overwrite each other.

The issue I'm coming up with is that the loop I use to check for the duplicates is rather lengthy, and I'm looking for a faster way. Right now the list I'm working with is 18,660 locations, so the loop below is running 348,195,600 times. Not ideal.

code:
lats = []
lons = []

icount = 0
for i in final_map_list:
	icount += 1
	jcount = 0
	for j in final_map_list:
		jcount += 1
		sum1 = i[0] + i[1]
		sum2 = j[0] + j[1]
		if icount != jcount and sum1 == sum2:
			i[0],i[1] = nudge(i[0], i[1])
			lats.append(i[0])
			lons.append(i[1])
		else:
			lats.append(i[0])
			lons.append(i[1])
In that code, map_list is a list of latitudes and longitudes, so map_list[1] = [24.34214, -34,20033]

This icount and jcount business isn't needed, Python gives you enumerate() to do this. Also, part of the if-else code is duplicated between the two cases.

code:
lats = []
lons = []

for (icount, i) in enumerate(final_map_list):
	for (jcount, j) in enumerate(final_map_list):
		sum1 = i[0] + i[1]
		sum2 = j[0] + j[1]
		if icount != jcount and sum1 == sum2:
			i[0],i[1] = nudge(i[0], i[1])
		lats.append(i[0])
		lons.append(i[1])
Do you really mean to append each latitude and each longitude n times, where n is the number of points in final_map_list? That's what you appear to be doing, although I don't know what nudge() does I didn't read your post.

Hammerite fucked around with this message at 21:38 on Jul 11, 2014

SurgicalOntologist
Jun 17, 2004

I'd recommend just adding some random jitter to every point. A lot of high-level plotting libraries have that functionality, it's the standard way to solve the problem of overlapping points. Checking which points are overlapping is overkill, IMO.

You can do this without a loop with numpy, or use a list comprehension to add a random number to everything. Numpy will be very fast if speed is the issue here.

An alternative/additional thing to do is to set the alpha level (transparency) so it gets darker where there are more points.

SurgicalOntologist fucked around with this message at 21:39 on Jul 11, 2014

the
Jul 18, 2004

by Cowcaster

Hammerite posted:

Do you really mean to append each latitude and each longitude n times, where n is the number of points in final_map_list? That's what you appear to be doing, although I don't know what nudge() does I didn't read your post.

Oh, oops. Yeah I just want to replace/fix it if it's a duplicate. Thanks for that catch.

SurgicalOntologist posted:

I'd recommend just adding some random jitter to every point. A lot of high-level plotting libraries have that functionality, it's the standard way to solve the problem of overlapping points. Checking which points are overlapping is overkill, IMO.

You can do this without a loop with numpy, or use a list comprehension to add a random number to everything. Numpy will be very fast if speed is the issue here.

An alternative/additional thing to do is to set the alpha level (transparency) so it gets darker where there are more points.

You know what, that's a better idea. Instead of trying to find the duplicates, I could just move every single point just slightly, and that would solve it. Thanks for that great suggestion.

the fucked around with this message at 23:08 on Jul 11, 2014

BabyFur Denny
Mar 18, 2003
I am parsing a textfile, the information there consists of several levels:
lines, semicolon, comma.
I want to put each line as an element in a tuple, and each line should be a tuple of all elements separated by semicolon, and those elements are tuples again of all elements separated by comma.

e.g.:
a;b;c,d
e;f;g,h

will become
[[a,b,[c,d]],[e,f,[g,h]]]
Additionally I want to clean up the elements (strip spaces).
My code works but it looks convulated and ugly. I am sure it can be improved but my attempts only resulted in red error messages:

code:
def splitstrip(string,sep):
    splitstring = string.split(sep)
    for i, x in enumerate(splitstring):
        splitstring[i] = x.strip()
    return splitstring

with codecs.open('input.txt', "r", "utf-8") as f:
    lines = [x.splitlines() for x in f.readlines()[1:]]
    attributes = []
    for x in lines:
        attributes += [splitstrip(y,';') for y in x]
    
for row in attributes:
    for i, field in enumerate(row):
        if ',' in field:
            row[i] = splitstrip(field,',')

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
Might be too dense for some tastes, but here is a way.

code:
import itertools, operator

def tiered_split (string, separators = None):
    if separators is None:
        separators = ['\n', ';', ',']
    if not separators:
        raise ValueError('No separators supplied')
    elif len(separators) == 1:
        return list(map(
            operator.methodcaller('strip'),
            string.split(separators[0])
        ))
    else:
        return list(map(
            tiered_split,
            string.split(separators[0]),
            itertools.repeat(separators[1:])
        ))
code:
>>> tiered_split('a ; b ;c, d\ne ;f; g ,h ')
[[['a'], ['b'], ['c', 'd']], [['e'], ['f'], ['g', 'h']]]
>>>
NB. You would not use readlines() if you used this, because it's splitting on newlines for you.

Carrier
May 12, 2009


420...69...9001...
Does matplotlib work in python 3.4? The website seems to suggest it only supports 3.3.

null gallagher
Jan 1, 2014
This isn't strictly Python-related, but I'm curious about it for a dumb little script I wrote: is there any way to negate a regular expression? Basically, "anything that does not match this pattern".

I ended up doing this, and I get the feeling there's a better way of doing it

Python code:
matches = [ (word, re.match(pattern, word)) for word in words ]
not_matches = [ m[0] for m in matches if m[1] is None ]

Dominoes
Sep 20, 2007

Carrier posted:

Does matplotlib work in python 3.4? The website seems to suggest it only supports 3.3.

Yes

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

null gallagher posted:

This isn't strictly Python-related, but I'm curious about it for a dumb little script I wrote: is there any way to negate a regular expression? Basically, "anything that does not match this pattern".

I ended up doing this, and I get the feeling there's a better way of doing it

Python code:
matches = [ (word, re.match(pattern, word)) for word in words ]
not_matches = [ m[0] for m in matches if m[1] is None ]

Negative lookahead assertion.

code:
not_matches = [word for word in words if re.match("(?!" + pattern + ")", word)]
But there isn't really anything wrong with just testing whether None is returned, like you were already doing...

code:
not_matches = [word for word in words if re.match(pattern, word) is None]

null gallagher
Jan 1, 2014
Neat, I didn't remember negative lookahead from my compilers textbook's regex section. Both of those look a little cleaner but still readable, thanks!

BigRedDot
Mar 6, 2008

In all the commotion of SciPy I forgot to come here an mention that we released Bokeh 0.5. Lots of good new stuff: log axes, minor ticks, tighter pandas integration, easier embedding, super high level bokeh.charts interface, and maybe most importantly, widgets!



You can also see my SciPy talk on Bokeh (and any of the SciPy talks, Nich Coghlan gave a great Keynote this year) already on YouTube:

https://www.youtube.com/watch?v=B9NpLOyp-dI

the
Jul 18, 2004

by Cowcaster

BigRedDot posted:

In all the commotion of SciPy I forgot to come here an mention that we released Bokeh 0.5.

This looks like something I might need to learn at some point. I'm doing a lot of stuff that would probably benefit from such a package.

BigRedDot
Mar 6, 2008

the posted:

This looks like something I might need to learn at some point. I'm doing a lot of stuff that would probably benefit from such a package.

Well we have a mailing list and a GitHub, or feel free to PM me, always happy to help anyone use Bokeh!

the
Jul 18, 2004

by Cowcaster
Is there an API out there where I can query by name and get out a listed address? I guess Yelp could do that, but I'll mainly be doing things like municipalities and facilities, so I don't think there would be many listings.

QuarkJets
Sep 8, 2008

Is there a simple way to use shutil.rmtree in a non-blocking way? I have a function where for one of the steps I'm basically just removing a temporary directory, but sometimes the directory contains some really huge files that take awhile to delete. I could use subprocess I guess, but that's clunky

Edison was a dick
Apr 3, 2010

direct current :roboluv: only

QuarkJets posted:

Is there a simple way to use shutil.rmtree in a non-blocking way? I have a function where for one of the steps I'm basically just removing a temporary directory, but sometimes the directory contains some really huge files that take awhile to delete. I could use subprocess I guess, but that's clunky

It's either that, or a thread.

code:
import threading, shutil
class RMTreeThread(threading.Thread):
    def __init__(self, dir):
        self._dir = dir
    def run(self):
        shutil.rmtree(self._dir)

rmtreethread = RMTreeThread(dir)
rmtreethread.start()
There's some fairly large warnings about threading in python, since it doesn't play nicely with subprocesses, and the GIL means you get poor performance if you're trying to run a lot of python code in different threads, but it should do what you need, and let you run python code while shutil.rmtree is removing large files.

Frankly, I'd see if you can move to a file system that doesn't take so long to remove files.

suffix
Jul 27, 2013

Wheeee!

QuarkJets posted:

Is there a simple way to use shutil.rmtree in a non-blocking way? I have a function where for one of the steps I'm basically just removing a temporary directory, but sometimes the directory contains some really huge files that take awhile to delete. I could use subprocess I guess, but that's clunky

The simplest way to run anything in a non-blocking way is to start in it a thread

Python code:
from threading import Thread
rmtree_thread = Thread(target=shutil.rmtree, args=(tmp_dir,))
rmtree_thread.start()
This works well for simple fire-and-forget things where you never need the result.

the
Jul 18, 2004

by Cowcaster
Looks like python-twitter doesn't support using the streaming API. I'm looking to grab as many possible tweets as I can about a subject, I want to build a database of tweets over the course of the past few years to look at trends.

Are there any modules that support connecting to the API in this way?

the fucked around with this message at 17:31 on Jul 16, 2014

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

the posted:

Looks like python-twitter doesn't support using the streaming API. I'm looking to grab as many possible tweets as I can about a subject, I want to build a database of tweets over the course of the past few years to look at trends.

Are there any modules that support connecting to the API in this way?

You edited it out just as I hit quote, but I just wanted to mention that when you're trying to figure out a dense data structure like that, the pprint module is a godsend.

the
Jul 18, 2004

by Cowcaster
Sorry, thanks. I'll look into that.

Also, in doing research online, it looks like there isn't really away to get long-term search result data from twitter? It seems like this is something that they don't allow with the public api.

supercrooky
Sep 12, 2006

the posted:

Sorry, thanks. I'll look into that.

Also, in doing research online, it looks like there isn't really away to get long-term search result data from twitter? It seems like this is something that they don't allow with the public api.

Nope, the most you can get is 7 days through the search API. Selling data was the major source of revenue for twitter until their ad platform starting taking off.

Historical is a giant pain in the rear end to get, and expensive. Datasift will do it, but you need a subscription. Gnip will do one-off data, but you are starting at $500+, and if you are looking at years of data even for a narrow search its going up quickly from there.

Try tweepy if you are using the streaming api.

the
Jul 18, 2004

by Cowcaster

onionradish posted:

the, when you initialize beatbox, are you using beatbox.Client() or beatbox.PythonClient()?

I remember looking at the code for beatbox when you were posting about having to wrap everything in str() and shuddering -- as SurgicalOntologist has suggested, the API is godawful.

However, it looks like it's because the default Client API is just a wrapper around some horrifying XML thing that is just dumping out results in a list that you then have to wrap in str(), which is what's part of what's causing your encoding issues.

beatbox includes PythonClient which claims to turn "the returned objects into proper Python data types. e.g. integer fields return integers" and appears to return a list of dictionaries (their example):

Python code:
>>> svc = beatbox.PythonClient()
>>> svc.login('username', 'passwordTOKEN')
>>> res = svc.query("SELECT Id, FirstName, LastName FROM Contact WHERE LastName='Doe'")
>>> res[0]
{'LastName': 'Doe', 'type': 'Contact', 'Id': '0037000000eRf6vAAC', 'FirstName': 'John'}

FYI I just tried this and it's popping an error. Ideas?

code:
sf = beatbox._tPartnerNS
svc = beatbox.PythonClient()
svc.login(sf_username,sf_pass)

sales_list = []

squery = "SELECT Price FROM Opportunity WHERE Opportunity.RecordType = \'FD - Buying\'"

query = svc.query(squery)

for i in query[sf.records:]:
	print i
	raw_input()
Pops AttributeError: 'module' object has no attribute 'PythonClient'

Space Kablooey
May 6, 2009


e: disregard

onionradish
Jul 6, 2006

That's spicy.

the posted:

FYI I just tried this and it's popping an error. Ideas?

code:
sf = beatbox._tPartnerNS
svc = beatbox.PythonClient()
svc.login(sf_username,sf_pass)

sales_list = []

squery = "SELECT Price FROM Opportunity WHERE Opportunity.RecordType = \'FD - Buying\'"

query = svc.query(squery)

for i in query[sf.records:]:
	print i
	raw_input()
Pops AttributeError: 'module' object has no attribute 'PythonClient'
I don't have access to a SalesForce account anymore, so can't directly test access or queries.

Are you getting that error on the svc = beatbox.PythonClient() line or somewhere else? If you do import beatbox; dir(beatbox) does PythonClient show up in the list? If not, see if your version is the same as the PyPi version.

I'm assuming you retyped the code; the first colon looks like a typo here: for i in query[sf.records:]:

Adbot
ADBOT LOVES YOU

the
Jul 18, 2004

by Cowcaster

onionradish posted:

Are you getting that error on the svc = beatbox.PythonClient() line or somewhere else? If you do import beatbox; dir(beatbox) does PythonClient show up in the list? If not, see if your version is the same as the PyPi version.

Looks like it isn't. Reading that page it looks like this is an updated version of the one I was using. Thanks for the heads up.

  • Locked thread