open All Channels
seplocked EVE Technology Lab
blankseplocked Advanced Python EVE API wrapper
 
This thread is older than 90 days and has been locked due to inactivity.


 
Pages: [1] 2 3 4

Author Topic

Entity
X-Factor Industries
Synthetic Existence
Posted - 2007.07.10 10:55:00 - [1]
 

Edited by: Entity on 08/09/2011 18:16:56
PLEASE USE THE THREAD ON THE NEW FORUMS HERE:
https://forums.eveonline.com/default.aspx?g=posts&t=6504
___________________________________________________________________

I've made an EVE API wrapper for python.

You can find it here:
Python EVE API on Github

This wrapper has no external dependencies and will work with any Python version from 2.4 onward, and will likely work with future versions of the EVE API.

An extensive demonstration script is provided.

Feel free to post suggestions for improvements and bug reports here, or mail me ingame.

-----
# Version: 1.1.9 - 2 September 2011
# - added workaround for row tags with attributes that were not defined
# in their rowset (this should fix AssetList)
#
# Version: 1.1.8 - 1 September 2011
# - fix for inconsistent columns attribute in rowsets.
#
# Version: 1.1.7 - 1 September 2011
# - auth() method updated to work with the new authentication scheme.
#
# Version: 1.1.6 - 27 May 2011
# - Now supports composite keys for IndexRowsets.
# - Fixed calls not working if a path was specified in the root url.
#
# Version: 1.1.5 - 27 Januari 2011
# - Now supports (and defaults to) HTTPS. Non-SSL proxies will still work by
# explicitly specifying http:// in the url.
#
# Version: 1.1.4 - 1 December 2010
# - Empty explicit CDATA tags are now properly handled.
# - _autocast now receives the name of the variable it's trying to typecast,
# enabling custom/future casting functions to make smarter decisions.
#
# Version: 1.1.3 - 6 November 2010
# - Added support for anonymous CDATA inside row tags. This makes the body of
# mails in the rows of char/MailBodies available through the .data attribute.
#
# Version: 1.1.2 - 2 July 2010
# - Fixed __str__ on row objects to work properly with unicode strings.
#
# Version: 1.1.1 - 10 Januari 2010
# - Fixed bug that causes nested tags to not appear in rows of rowsets created
# from normal Elements. This should fix the corp.MemberSecurity method,
# which now returns all data for members. [jehed]
#
# Version: 1.1.0 - 15 Januari 2009
# - Added Select() method to Rowset class. Using it avoids the creation of
# temporary row instances, speeding up iteration considerably.
# - Added ParseXML() function, which can be passed arbitrary API XML file or
# string objects.
# - Added support for proxy servers. A proxy can be specified globally or
# per api connection instance. [suggestion by graalman]
# - Some minor refactoring.
# - Fixed deprecation warning when using Python 2.6.
#
# Version: 1.0.7 - 14 November 2008
# - Added workaround for rowsets that are missing the (required!) columns
# attribute. If missing, it will use the columns found in the first row.
# Note that this is will still break when expecting columns, if the rowset
# is empty [Flux/Entity]
#
# Version: 1.0.6 - 18 July 2008
# - Enabled expat text buffering to avoid content breaking up [BigWhale]
#
# Version: 1.0.5 - 03 February 2008
# - Added workaround to make broken XML responses (like the "row:name" bug in
# eve/CharacterID) work as intended.
# - Bogus datestamps before the epoch in XML responses are now set to 0 to
# avoid breaking certain date/time functions. [Anathema Matou]
#
# Version: 1.0.4 - 23 December 2007
# - Changed _autocast() to use timegm() instead of mktime(). [Invisible Hand]
# - Fixed missing attributes of elements inside rows. [Elandra Tenari]
#
# Version: 1.0.3 - 13 December 2007
# - Fixed keyless columns bugging out the parser (in CorporationSheet for ex.)
#
# Version: 1.0.2 - 12 December 2007
# - Fixed parser not working with indented XML.
#
# Version: 1.0.1
# - Some micro optimizations
#
# Version: 1.0
# - Initial release
#

Herio Mortis
Dark Nebula Academy
O X I D E
Posted - 2007.07.10 13:44:00 - [2]
 

Brilliant, much appreciated.
This will come in handy.

foiblealt
Posted - 2007.07.29 23:36:00 - [3]
 

Getting errors when running apitest.py:

EXAMPLE 4: GETTING CHARACTER SHEET INFORMATION

Traceback (most recent call last):
File "apitest.py", line 153, in <module>
skilltree = api.eve.SkillTree()
File "/home/ibscott/eve/eveapi.py", line 143, in __call__
return self._root(self._path, **kw)
File "/home/ibscott/eve/eveapi.py", line 213, in __call__
obj = _Parser().Parse(response, True)
File "/home/ibscott/eve/eveapi.py", line 278, in Parse
p.ParseFile(data)
File "/home/ibscott/eve/eveapi.py", line 287, in tag_start
columns = attributes[attributes.index('columns')+1].split(",")
ValueError: list.index(x): x not in list

Lilian Imp
Posted - 2007.07.30 08:43:00 - [4]
 

Originally by: foiblealt
Getting errors when running apitest.py:

EXAMPLE 4: GETTING CHARACTER SHEET INFORMATION

Traceback (most recent call last):
File "apitest.py", line 153, in <module>
skilltree = api.eve.SkillTree()
File "/home/ibscott/eve/eveapi.py", line 143, in __call__
return self._root(self._path, **kw)
File "/home/ibscott/eve/eveapi.py", line 213, in __call__
obj = _Parser().Parse(response, True)
File "/home/ibscott/eve/eveapi.py", line 278, in Parse
p.ParseFile(data)
File "/home/ibscott/eve/eveapi.py", line 287, in tag_start
columns = attributes[attributes.index('columns')+1].split(",")
ValueError: list.index(x): x not in list


Try This

Entity
X-Factor Industries
Synthetic Existence
Posted - 2007.07.31 15:55:00 - [5]
 

Originally by: foiblealt
Getting errors when running apitest.py


Thanks. There appears to be a bug in the data returned by the API, not the actual eveapi.py.
I have filed a bug report on this.

Durente Galaica
Amarr
Fortunate Few
Posted - 2007.11.10 17:51:00 - [6]
 

Originally by: Entity
# Now use the Get() method to get a row directly.
# Assumes ISD alliance exists. If it doesn't, we probably have bigger
# problems than the unhandled exception here -_-
print alliances_by_ticker.Get("ISD")


Traceback (most recent call last):
File "C:\Documents and Settings\user\EVE\Program\apitest.py", line 239, in <module>
print alliances_by_ticker.Get("ISD")
File "C:\Documents and Settings\user\EVE\Program\eveapi.py", line 563, in Get
raise KeyError, key
KeyError: 'ISD'

--------------------------

Sorry I couldn't resist Laughing

On a feedback note, this wrapper is fantastic. I havn't used it more than the test, but after looking through your work, I plan on using it extensivly in the coming weeks! Thanks! Very Happy

Entity
X-Factor Industries
Synthetic Existence
Posted - 2007.11.22 13:50:00 - [7]
 

heehee... yeah CCP keeps forgetting to pay the alliance bills it seems Rolling Eyes

Thanks for the feedback ♥

Entity
X-Factor Industries
Synthetic Existence
Posted - 2007.12.12 16:19:00 - [8]
 

Edited by: Entity on 12/12/2007 16:37:26
Version 1.0.2 is now available, which fixes an issue with the new formatting of the XML.

Download it here

I'm probably going to use a different parser for this in the next version because I do not like the current solution much ugh

Note: to use the API v2 features, instead of:

api = eveapi.EVEAPIConnection()


use:

api = eveapi.EVEAPIConnection().context(version=2)



Macdeth
Ephemeral Misgivings
Posted - 2007.12.12 18:06:00 - [9]
 

Appears to bail on KillLog, CorporationSheet, and I think I saw it somewhere else but API server just went down as I was checking while composing this.

Thanks for writing & actively supporting this thus saving a whole bunch of us the effort!

Entity
X-Factor Industries
Synthetic Existence
Posted - 2007.12.13 00:21:00 - [10]
 

Edited by: Entity on 13/12/2007 00:22:41
Originally by: Macdeth
Appears to bail on KillLog, CorporationSheet, and I think I saw it somewhere else but API server just went down as I was checking while composing this.


The KillLog error is indeed a bug in my code, and it's been fixed. v1.0.3 now available for download.

However it looks like CorporationSheet is missing the required columns attribute, which is a bug in the XML. I have informed Garthagk about this and it'll be fix0red Soon™

Thanks for pointing this out.

SelanirO
Phoibe Enterprises
Shadow of xXDEATHXx
Posted - 2007.12.18 23:17:00 - [11]
 

Many thanks!
Very handy

Invisible Hand
Archetype Holdings
Posted - 2007.12.21 10:04:00 - [12]
 

Useful module, thanks for writing this!

Minor bug report: in _autocast() you do:

return int(mktime(strptime(s, "%Y-%m-%d %H:%M:%S")))

However the time strings are in UTC, while mktime expects a tuple in the local timezone. So the parsed values are not the expected seconds-since-epoch value unless your local timezone happens to match UTC. This means that (among other things) you can't just compare cachedUntil to time.time().

I changed my copy to use calendar.timegm() instead of time.mktime() and it works perfectly now - all the time values are parsed into seconds-since-epoch.

Elandra Tenari
Gallente
StateCorp
Posted - 2007.12.21 17:17:00 - [13]
 

Thanks for writing this, it's proving very useful.

One minor bug I found whilst processing KillLogs is that the raw Element for the Victim has no attributes. So I changed the if self.container._isrow: section of the tag_end function to pick up attributes on single elements.

My updated version here.

Lake
The Praxis Initiative
Gentlemen's Agreement
Posted - 2007.12.21 19:02:00 - [14]
 

This has made implementing the API-facing section of my latest project utterly trivial.

Entity
X-Factor Industries
Synthetic Existence
Posted - 2007.12.22 08:51:00 - [15]
 

Originally by: Invisible Hand
Useful module, thanks for writing this!

Minor bug report: in _autocast() you do:

return int(mktime(strptime(s, "%Y-%m-%d %H:%M:%S")))

However the time strings are in UTC, while mktime expects a tuple in the local timezone. So the parsed values are not the expected seconds-since-epoch value unless your local timezone happens to match UTC. This means that (among other things) you can't just compare cachedUntil to time.time().

I changed my copy to use calendar.timegm() instead of time.mktime() and it works perfectly now - all the time values are parsed into seconds-since-epoch.


Hmm, not sure about this one; I convert my local time to UTC before comparing times, and I wanted the input times to stay exactly as they are (which mktime achieves)... I guess it depends on which way you look at the problem :)

I'm not really a fan of timezone stuff in programming, so I might very well be doing this the wrong way around... Comments, anyone?


Invisible Hand
Archetype Holdings
Posted - 2007.12.22 12:50:00 - [16]
 

Edited by: Invisible Hand on 22/12/2007 12:52:01
Originally by: Entity
Originally by: Invisible Hand
Useful module, thanks for writing this!

Minor bug report: in _autocast() you do:

return int(mktime(strptime(s, "%Y-%m-%d %H:%M:%S")))

However the time strings are in UTC, while mktime expects a tuple in the local timezone. So the parsed values are not the expected seconds-since-epoch value unless your local timezone happens to match UTC. This means that (among other things) you can't just compare cachedUntil to time.time().

I changed my copy to use calendar.timegm() instead of time.mktime() and it works perfectly now - all the time values are parsed into seconds-since-epoch.


Hmm, not sure about this one; I convert my local time to UTC before comparing times, and I wanted the input times to stay exactly as they are (which mktime achieves)... I guess it depends on which way you look at the problem :)

I'm not really a fan of timezone stuff in programming, so I might very well be doing this the wrong way around... Comments, anyone?




The usual way of dealing with this sort of thing is to work internally in seconds-since-epoch and then convert to timezones only when actually outputting data. seconds-since-epoch identifies a particular instant in time unambiguously, regardless of what timezone you are in, so it's much easier to work with that. I assumed that since _autocast() was converting to an integer, it was meant to be converting seconds-since-epoch since that's what all the time functions expect to see and it's the most common integer representation of time around..

What do you mean by "convert your local time to UTC before comparing"? If you're dealing in seconds-since-epoch values, that's independent of timezone already, you shouldn't need to do any conversion at all.

Note that without this change the simple&obvious caching mechanism used in apitest.py just doesn't work with any local timezone other than UTC.

You might want to have a dig around in 'pydoc time', it has a good summary of the different representations.

Entity
X-Factor Industries
Synthetic Existence
Posted - 2007.12.23 13:09:00 - [17]
 

Originally by: Invisible Hand
Edited by: Invisible Hand on 22/12/2007 12:52:01
Note that without this change the simple&obvious caching mechanism used in apitest.py just doesn't work with any local timezone other than UTC.



Actually, it works fine since im using the server times and calculate seconds-til-expiry and add it to local time. Have you actually tried it?

Anyway, you have some valid points, I'll change the thing to use timegm().

Entity
X-Factor Industries
Synthetic Existence
Posted - 2007.12.23 13:32:00 - [18]
 

Edited by: Entity on 23/12/2007 13:34:01
Originally by: Elandra Tenari
Thanks for writing this, it's proving very useful.

One minor bug I found whilst processing KillLogs is that the raw Element for the Victim has no attributes. So I changed the if self.container._isrow: section of the tag_end function to pick up attributes on single elements.

My updated version here.


Cheers.

v 1.0.4 available for download (see top post)

Invisible Hand
Archetype Holdings
Posted - 2007.12.24 01:43:00 - [19]
 

Originally by: Entity
Originally by: Invisible Hand
Edited by: Invisible Hand on 22/12/2007 12:52:01
Note that without this change the simple&obvious caching mechanism used in apitest.py just doesn't work with any local timezone other than UTC.



Actually, it works fine since im using the server times and calculate seconds-til-expiry and add it to local time. Have you actually tried it?

Oh, you're right, I grabbed the retrieve half of the caching mechanism for my own code and didn't see the store half that adjusted the time.

Anyway, thanks for changing this Very Happy

Lake
The Praxis Initiative
Gentlemen's Agreement
Posted - 2008.01.10 07:43:00 - [20]
 

Too useful to be sitting down here on page 4.

Entity
X-Factor Industries
Synthetic Existence
Posted - 2008.02.03 23:31:00 - [21]
 

1.0.5 now available. see original post.

Durente Galaica
Amarr
Fortunate Few
Posted - 2008.03.04 21:12:00 - [22]
 

I really like this wrapper, and Entity's comments are great for quick and meaningful interpretation. But if you're like me, you will stop working on a project for a few weeks and forget what certain classes and methods do. Then you must dig through the source code, to find the commented section.

Thankfully python allows you to modify the __doc__ file, just by the way you comment! Just take Entity's current comments and change them so slightly to produce the desired result, following this example:

(Pretend the .......'s are whitespace)
>>> class foo():
....... ''' ... This is how you write multiple
....... ....... line comments.
....... '''
....... def __init__(self):
....... ....... "This is a one line comment"
....... ....... pass

>>> help(foo)
Help on class foo in module __main__:

class foo
| This is how you write multiple
| line comments.
|
| Methods defined here:
|
| __init__(self)
| ...... This is a one line comment

>>> help(foo.__init__)
Help on method __init__ in module __main__:

__init__(self) unbound __main__.foo method
.... This is a one line comment

It's great to see that you continue to support this Entity. Thanks for all the work you have put into this!

Demiurgis
Posted - 2008.03.06 06:25:00 - [23]
 

Edited by: Demiurgis on 06/03/2008 06:25:58
this is really cool, I think I am going to use this in a project for my python class. The teacher wants us to use a few modules, and this could be one of them

will most of this work with a limited API key?

Kanmahr
Misfit Toys
Posted - 2008.03.09 11:56:00 - [24]
 

Great work. There does however seem to be a problem with the trained to level of a skill. The values the API returns seem to be one over the current level. Currently working around it but would be nice to fix :)

Cheers!!!!

Flios Bror
Amarr
Wildly Inappropriate
Posted - 2008.03.28 22:04:00 - [25]
 

First of all: thanks for making this library, it makes programming a lot easier. And while reading the source-code of the library I learned new things to do in python.
I have a few questions:
  1. What is the syntax for getting the next page, of for example the WalletJournal. I know it's an exercise for the reader, but I didn't manage to find the documentation for this in the library source-code yet.

  2. How can I get the date+times for the currentTime and the cachedUntil from a element-object returned from a query?

  3. Last a more general API-question: when several accounts have access to corporate WalletJournal, is the caching-time for everyone at the same time, or is it for each account seperately?

Entity
X-Factor Industries
Synthetic Existence
Posted - 2008.04.16 01:46:00 - [26]
 

Edited by: Entity on 16/04/2008 01:47:35
Hm I should be paying more attention to this thread. Too bad this board doesn't let you "subscribe" to threads.

Anyway...

Originally by: Flios Bror

What is the syntax for getting the next page, of for example the WalletJournal. I know it's an exercise for the reader, but I didn't manage to find the documentation for this in the library source-code yet.


You simply add the appropriate beforeRefID=X (where X is the refID of the last/oldest entry of the last query) to the subsequent query.

Originally by: Flios Bror
How can I get the date+times for the currentTime and the cachedUntil from a element-object returned from a query?


the currentTime and cachedUntil are available through the _meta attribute on the result root, like this:

result = api.blablabla()
foo = result._meta.currentTime


Originally by: Flios Bror
Last a more general API-question: when several accounts have access to corporate WalletJournal, is the caching-time for everyone at the same time, or is it for each account seperately?


Not sure, there's a lot of different caching schemes used :-/

Originally by: Kanmahr
Great work. There does however seem to be a problem with the trained to level of a skill. The values the API returns seem to be one over the current level. Currently working around it but would be nice to fix :)


Seeing as this wrapper does not have any code that deals with skill levels, nor have any knowledge of the methods exposed by the server, it's problem CCP would have to fix (if it's still the case) Wink

Originally by: Demiurgis
will most of this work with a limited API key?


Limited keys only give limited access! (who would have guessed?) Very Happy You can do plenty of fun stuff with limited keys though. Check the API reference


Thanks everyone, for the feedback :)

bowindah
Posted - 2008.07.05 17:51:00 - [27]
 

Nice wrapper.

I am trying to use it with AssetList which returns nested rowsets.

The following works,
for asset in result2.assets:
self.response.out.write("%s<br/>" % asset)

Sometimes it returns,
Row(itemID:271302566,locationID:61000108,typeID:588,quantity:1,flag:4,singleton:1,contents:Rowset(columns=[itemID,typeID,quantity,flag,singleton], rows=3))
whereas other times it returns,
Row(itemID:561829276,locationID:61000108,typeID:11489,quantity:1,flag:4,singleton:1,contents:None)

So my question is, how to test and enumerate over the nested Rowset?

Chruker
Posted - 2008.07.06 23:03:00 - [28]
 

*meow*

How can this have been missing my eyes for almost a year...

Entity
X-Factor Industries
Synthetic Existence
Posted - 2008.07.12 11:04:00 - [29]
 

Originally by: bowindah
Nice wrapper.

I am trying to use it with AssetList which returns nested rowsets.

The following works,
for asset in result2.assets:
self.response.out.write("%s<br/>" % asset)

Sometimes it returns,
Row(itemID:271302566,locationID:61000108,typeID:588,quantity:1,flag:4,singleton:1,contents:Rowset(columns=[itemID,typeID,quantity,flag,singleton], rows=3))
whereas other times it returns,
Row(itemID:561829276,locationID:61000108,typeID:11489,quantity:1,flag:4,singleton:1,contents:None)

So my question is, how to test and enumerate over the nested Rowset?



Either use a recursive function to walk the tree, or use the flat list.
The flat list is easier to process in most cases.
Just do blablabla.AssetList(flat=1)


Entity
X-Factor Industries
Synthetic Existence
Posted - 2008.07.18 12:02:00 - [30]
 

Just uploaded the 1.0.6 release.

Apparently I had forgotten to enable text buffering on the xml parser so it was possible for text content to be cut because it wasn't prepared to handle multiple parts for the same content. Fixed now :)



Pages: [1] 2 3 4

This thread is older than 90 days and has been locked due to inactivity.


 


The new forums are live

Please adjust your bookmarks to https://forums.eveonline.com

These forums are archived and read-only