How far can I see? -- A discussion of the limits of human knowledge, the destructivness of religion, and the spirituality of scientific enquiry.

When I was a child, I posed the question to my parents, "how far can I see?" I don't remember specifically what they said, but somehow I got it in my head that we can only see about 5 miles, which is probably true if you are talking about seeing something about the size of a house on completely flat ground.

Later in my life, my parents took me hiking in the mountains. When we were thousands of feet in the air I asked them again "how far can I see?", and my notion of the maximum distance that a human could know something increased to about 30-40 miles.

Now, I was young in both of these instances, probably not older than 10 or 11. One thing that was obvious was that I wasn't even asking the right question -- how far can I see what? See a mountain? a person? a bacteria? a star?

And my parents obviously weren't all to eager to get me to ask the deeper questions. Looking back on it, I think this took a conscious effort on their part. I think they were afraid to do so. I think they were afraid that if I were to come to an understanding and sense of wonder towards the ability to see galaxies that are billions of light years away, then that understanding could cause me to be less interested in questions about God.

In the end, they were right. In my teenage years I finally came to the understanding that, for some stars, it can take light billions of years to travel to the earth. It was therefore, for the first time, obvious that the bible was not entirely true. With this realization I became sceptical. I began the search for other contradictions. With the internet and google freely available, these contradictions were not hard to find.

In my search I came to another disheartening realization. As I began to critically think about some of the moral atrocities supposedly committed at the behest of a 'loving' God, I began to see this God as evil. There are bible stories they never tell in church except when they want to make people fear the wrath of God. These stories, when they are told, are told with qualifications of all kinds. I will not quote these here, but if you take a quick glance through Exodus you will find a God that condones the sexual enslavement and rape of young virgins, the blessing to commit genocide, and a God who is obsessed with blood sacrifice. When left bare of shallow qualifications and attempts to justify these actions, these stories make clear that the real Satan of the bible was in fact the God of the Israelites, the God I had been worshipping. Things don't get any better (in fact, they may even get worse if you believe them) with the coming of Christ and the creation of a place to torture people for all eternity. But I digress.

I now had the answer to my question--we can see a very very long ways. However, the sense of wonder I would have gained from this knowledge alone was now gone. It was not until now, reading the works of Carl Sagan, that I have felt any sort of wonder at the size of the universe. The answer to the question "how far can I see" is "hundreds of billions of light years." I can see entire galaxies, and this fact begs another question, one I would argue of far more spiritual importance. "Who can I see?"

So here I am, 23 years old, and I have a new question. How many other intelligent life forms are out there? I think it is reasonable to believe, with almost complete certainty, that we are not alone in the universe -- and probably not alone in our galaxy. In space, where the atmosphere no longer filters the dim glow of distant galaxies, some of the photons that would be hitting your eye, and which you would only be able to discern as a speck of dust in an infinite void, are entire galaxies -- glowing hundreds of billions of light years away with the strength of hundreds of billions of stars. This fact does more than make you feel small -- although it certainly does that -- it gives you hope that you are not alone. However, I think the possibility of there being other life forms is one of the scariest thoughts in the universe to those who are religious. It is no wonder that a faith which vehemently enforces the idea that we are so special would shun a line of questioning that would conclude the exact opposite. The western religions have the worldview -- no the universeview -- that God is so concerned about us that He created a heaven and hell in order to reward/punish us for the act of belief. It is no wonder that those who hold that belief system would back away in fear at a question regarding of the limits of human knowledge. If you look back through history, it has been dreadfully obvious that the amount which humans can know scares the living *#$% out of the religious. It has scared them so much that it used to be the policy to murder those who tried to advance accurate theories of knowledge based on honest scepticism and inquiry.

Breaking out of this "universe-view", this "man-centred" viewpoint, is an important step for the spirituality of the human race. Science is not religious. In fact science is the opposite of religion for the simple reasons that it does not value authority, dogma or ritual. But science is spiritual. The search for truth and unity of explanation -- these questions are driven by more than just some cold and disconnected gene-machine. Scientists search for truth because they value truth, they value open enquiry and scepticism, they value simplicity in utility; and these values are a result of more than our genes.

Let me ask a question. What do we mean when we say things like "the spirit of human enquiry"? When we are talking about the spiritual, are we not talking about going beyond our genetic fate? Going beyond any of our genetic ancestors? Our culture must recognize that most values are not evolved per-se. Scientific values in particular are a product of culture, experimentation, and continued realization through the entire course of human civilization. While some of these are reinforced by our genetic disposition (like pattern recognition), these ideas and questions represent, as much as anything proclaimed religious, the human spirit because they cannot be directly tied to evolution. Although our brains and bodies are the products of evolution, these ideas are clearly a step beyond evolution. Culture and memes, as Dawkins points out in The Selfish Gene, are not bound to the same principles as genes themselves are because they do not require sexual reproduction to replicate.

Our culture (and from culture some of our values) are one of the few things we do not have in common with the creatures who accompany us on this tumbling planet through space. Our abstract ideas and values actually do set us apart, in some small way. We are the only species who possess the possibility of diverting an incoming asteroid. However, we are also the only species with the possibility to cause more devastation than even an asteroid could. This is not to say we should believe we are removed from our environment -- that isn't true at all. We are integrally part of, and rely on, our environment. However, we are the only species who yet has the capability to spread our environment. We are the only species who can go to space.

And that is exactly what our spiritual goal as a species should be -- to preserve the ecosystem of the planet we originated on, as a sacred and holy site of the creation of our species, and to expand the evolution of this planet onto an astronomical, rather than just a global, scale. We alone have the potential to participate in an astronomical eco-system, with the possibility of cooperating and coexisting with other alien species. There is only one way that the life which has evolved on this planet will survive the next 4 billion years (when the sun will swallow us). The only way to sustain life is to move it to a different planet, or implement technology in some other ingenious way to stretch out the life of our sun. We are the only species with the ability to even think about such possibilities.

How can this knowledge make you feel anything other than mystic or spiritual? Unlike other inspirations of spirituality, this is not a false or fabricated hope. It is very real. It is very possible. We actually have been into space, our species actually has looked back at the earth. Additionally, we have observed other planets, around other stars. These planets contain huge amounts of complex organic compounds. They are very similar to our own and they may have or may yet evolve life. If there is no life, then we may be able to plant the seed. The only thing that can prevent this future, this future of exploring the stars and finding or creating new life, is ourselves. We are destined to either destroy ourselves or reach the stars. I say we ought to give everything we have, both intellectually and spiritually, in reaching for the stars. We should forget about this human centred world view that is a remnant of past civilizations. Look up, not back. Look at where we can go. Look at who we can be. Make it so.

ACTUALLY logging in python

over the past couple of days I have been figuring out the logging module in python.  It is both extraordinarily simple, and extraordinarily frustrating.  It seems to me that once you know a few simple facts and have a few pieces of code running, it all works smoothly and easily.  In addition, once you 'get' logging, it is a great way to get rid of headache.  Using print statements is fundamentally foolish because you will have to delete them eventually.  This is obviously not the case for logging. 

So here is all you need to know.

The first thing you need is a good way to view log files.  For that I suggest you check out logview (which you can get from http://pypi.python.org/pypi).  It is based on Qt and is very intuitive.  It even remembers the settings you assign to it!

The second thing you need is to setup your logger to work with logview.  To do this, just do the following.

def setuplog():
   from logging import handlers
   socketHandler = handlers.SocketHandler('localhost',
                    handlers.DEFAULT_TCP_LOGGING_PORT)
   rootLog = logging.getLogger('')
   rootLog.addHandler(socketHandler)

The root log will now automatically send to the TCP logging port that logview uses.  It is important to make sure that you ONLY CALL THIS ONCE.  If you call it more than once, it will duplicate messages -- which you don't want to do.  To achieve this I created a module called 'easy_log' that ensures that this is exactly what happens (easy_log does other things, like send logs to a file in my prefered format and reduce the amount of effort I have to put into creating logs for my modules, and automatically drop into pdb on exceptions if the logging level is set to debug).  You can check out easy_log in any future version of PyWorkbooks.toolbox (version > 0.0.10), and if you are a newer programmer, you may find some of the functions useful or instructive.

Now, the best way to create a log in your application is to just do:

import logging
from easy_log import getLogger (works the same as logging.getLogger but with some revisions as above)
log = getLogger(__name__, level = logging.DEBUG)

and that's it!  from now on you use it like a normal logger (i.e. log.debug('my debug message') will log 'my debug message' as a debug point).  Check it out, hopefully this helps someone!

Some words about Excel

For all my microsoft hatred, I am finding more and more that Excel is a polished and professional program.  While their COM system may pose a significant security threat, it makes developing python applications for Excel work flawlessly and easily.  Furthermore, excel is an excellent program in itself.  Their filtering mechanic is unparalled (from what I have seen) and I have to give them significant props for it.

That said, I hope open source can take some of these things and run with them.  Gnumeric is great, but it was (admittedly) very difficult to develop for, and impossible to extend upon (this has to do with how they implement python.  It is impossible to, for instance, control a Gnumeric instance from a separate thread).

Updates on PyWorkbooks
I've made a couple of minor updates over the past couple of weeks to PyWorkbooks, and fixed a couple of minor bugs.  Both Excel and Gnumeric versions now work VERY quickly, and I am almost ready to release an accompaying GUI toolbox application.  Furthermore, the ability to add and rename sheets has been added.

I'm really eagerly looking at adding google spreadsheet support.  I've taken a couple of glances at the API and am starting to think about it.

PyWorkbook : A base python module for all your spreadsheet needs. Interface with excel, gnumeric, and hopefully others (soon) seamlessly.

PyWorkbook is a base class for two classes: GnWorkbook and ExWorkbook, the Gnumeric and Excel workbook classes, respectively.  All the workbooks have (or will have) the exact same behavior, as they are all based on the same base class, PyWorkbook, with very few additions necessary.

The code for all future renditions of the project will be hosted here:
https://sourceforge.net/projects/pyworkbooks/files/

Download the zip file and check out the documentation.  Currently in-cell macros are not supported, but will be very shortly as I work out some of the kinks that happened when I updated the code.  On the bright side, it is no longer necessary for you to add your working directory to the system path in a special cell, as I have figured out a way to get it (a little bit of a hack but it works).

Pygnumeric updates: Performance, useability, and having multiple generators. Lists, tuples and numpy -- Oh my!

The code has undergone revisions and will now always be hosted here:

https://sourceforge.net/projects/pyworkbooks/files/

Most of this tutorial is still valid, but I recommend you view the pdf file included above.

 

 

 

So I said I wouldn't make a lot of updates, but here is another big update.  I've added several features to the code.  The previous tutorial still applies, except that when you type

>>> print B[:10, 1]

you will get a different value out.  The best way to teach is to show, so I will do an interactive interpreter


Usability Improvements:

type in the following
>>> mymatrix = [[n*p for n in range(100)] for p in range(100)]
>>> B.change_sheet(0)
>>> B[0,0] = mymatrix
>>> import sys; sys.path.append("/home/garrett/.gnumeric/1.10.8/plugins/Pygnumeric/"); import Pygnumeric; import Gnumeric; gBook = Pygnumeric.GnWorkbook(Gnumeric); B = gBook

and you are back where we ended last time.

There are several new features, the first one is write protection.
if you type the following:
>>> B.protect_sheet(0)
>>> B[0,5] = 8

you will receive an error.  This way you can write protect sheets (like the ones your macros are on)

now type:

>>> B.unprotect_sheet(0)   # unprotects the sheet
>>> data = B['A1: F20']
>>> print data
<Generator like object> with 20 values remaining and dtype of <type 'list'>

notice that it is no longer a generator object, but a generator like object.  Also note that it displays the data type and length.  I'll get to that in a minute, for now lets play with it.

>>> print len(data)
20

keeps track of its length

>>> print data.next()
[0 0 0 0 0 0]
>>> print len(data)
19

works like any normal generator

>>> print data[0]
[0 1 2 3 4 5]
>>> print len(data)
18
>>> print data[:2]
[[ 0  2  4  6  8 10]
 [ 0  3  6  9 12 15]]
>>> print len(data)
16

This is different from a generator.  What it is doing is reading whatever lines are next and displays them.  Note that line 0 is NOT necessarily the first line in the original generator!  If you didn't store data[0] you have to re-create the generator to get it back.

>>> print data[:]
will get the rest of the data.  If you try to take any more:

>>> print len(data)
0
>>> data[0]
IndexError: Not that much data left available

It returns an error.

One thing to note is that data[1] will just skip data[0].
>>> data = B['A1: F20']
>>> len(data)
20
>>> print data[1]
[0.0, 1.0, 2.0, 3.0, 4.0, 5.0]
>>> len(data)
18

It removed two elements (remember, it is a generator.  It never actually stores any data).

If you want to skip data, you can also ORIGINALLY use stepping in your splice.  For example:
>>> data = B[0:20:2, 0:6]

will give you every other row (starting with the 0th row)

>>> len(data)
10
>>> data.next()
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
>>> data.next()
[0.0, 2.0, 4.0, 6.0, 8.0, 10.0]
>>> len(data)
8

as you can see it is skipping every other line

Data Types
Now, what is the deal with this dtype buisness?  Well, I realized that people might want lists, tuples, or numpy arrays.  If you want one of these type:

>>> B.change_dtype(list)
>>> B[:10, 1]
[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
outputs a list
Also Note: I have made it so that you no longer receive a generator if you request a single array.  In the previous version this was the case.  If you WANT to receive a generator, just type:
B.ALWAYS_GENERATE = True
and you will receive a generator for both a matrix and an array (most users will never use this and you can probably ignore it)

>>> B.change_dtype(tuple)
>>> B[:10, 1]
(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
outputs a tuple

>>> import numpy
>>> B.change_dtype(int)
>>> B[:10, 1]
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> B.change_dtype(float)
>>> B[:10, 1]
array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.])
outputs respective numpy dtypes

Of course you can also do this with matrixes, which is what it was REALLY intended for
>>> B.change_dtype(list)
>>> data = B['A1: F20']
<Generator like object> with 20 values remaining and dtype of <type 'list'>
>>> data[:4]
[[0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 2.0, 3.0, 4.0, 5.0], [0.0, 2.0, 4.0, 6.0, 8.0, 10.0], [0.0, 3.0, 6.0, 9.0, 12.0, 15.0]]

>>> B.change_dtype(tuple)
>>> data = B['A1: F20']
>>> data[:4]
((0.0, 0.0, 0.0, 0.0, 0.0, 0.0), (0.0, 1.0, 2.0, 3.0, 4.0, 5.0), (0.0, 2.0, 4.0, 6.0, 8.0, 10.0), (0.0, 3.0, 6.0, 9.0, 12.0, 15.0))

>>> B.change_dtype(int)
>>> data = B['A1: F20']
>>> data[:4]
array([[ 0,  0,  0,  0,  0,  0],
       [ 0,  1,  2,  3,  4,  5],
       [ 0,  2,  4,  6,  8, 10],
       [ 0,  3,  6,  9, 12, 15]])

What are the advantages of this?  Well, maybe I should talk about performance, but first I should mention one more thing:

Simultanious Generators:
It is now OK to use simultaneous generators!  You can use it across sheets, with different data types, using different cell references, it doesn't matter.  The Generator like object will keep track of all of it :D
(if you don't know what this means, just know that you don't have to worry about screwing anything up... ever)

Performance:
I've done several things to increase performance (cleaning up the code and such), and dtypes are the biggest part of them.  The code written for the data call routine (i.e. data[0], etc) is as fast as I could make it, with as little memory overhead as possible (ive tested it, comparing other alternatives).  If you know how to make it faster, please tell me, but it is pretty quick.  Just know that if you use the standard calls, you will get data as fast as it can be generated (as far as I know).  This could be important in your spreadsheet program, as you don't want your python taking up too much computing power or memory.

Soon to come:
The next feature I am going to add is the ability to undo in a derived superclass (the one that you will be using for the interactive interpreter).  Until then.

Alpha Launch of Pygnumeric, the python macro and cell function class

The Code has undergone significant revisions and will now always be hosted here:

https://sourceforge.net/projects/pyworkbooks/files/

I recommend you view the documentation included there.

 



Note: This is my third tutorial piece on Gnumeric.  See the first two here and here


I've put in a TON of work on this over the weekend, and it is now nearly seamless, see the attachment for details.  I wouldn't yet trust it completely (the possibilities for bugs are still there), but it should be ready for you to use on a basic scale.  Check the outputs, report on bugs.

New Features:
In addition to the old features, I have added several functionalities to obtaining data.  To see any of this tutorial in action, download the attached file, follow the README and do the following:

Go to tools -> python console and copy-paste the following line and press enter (FIRST replacing "garrett" with your own name!!!):

import sys; sys.path.append("/home/garrett/.gnumeric/1.10.8/plugins/Pygnumeric/"); import Pygnumeric; import Gnumeric; gBook = Pygnumeric.GnWorkbook(Gnumeric); B = gBook

This will let you follow along in the interactive interpreter (do this in a new workbook, one where you can't destroy any important data :D)

Here is my interactive interpreter session, with me playing with some stuff


If you copied the above line, then you can access your workbook using either "gBook" or "B".  I will be using "B'"

Look at 'Sheet2' while you type the following
>>> B
<Pygnumeric.GnWorkbook object at 0xb403608c>
>>> print B
<Pygnumeric.GnWorkbook object at 0xb403608c> : sheetname = 'Sheet1', cellref = (row 0, col 0)
>>> B.change_sheet('Sheet2')
>>> print B
<Pygnumeric.GnWorkbook object at 0xb403608c> : sheetname = 'Sheet2', cellref = (row 0, col 0)
>>> B[0,0] = 'cell 0,0'
>>> B['A2'] = 'cell A2'
>>> B['A4:C4'] = 'whoa'
>>> B[6, :10] = range(100)

Watch Sheet2 while you type this.  You can see a couple of things while you do this.  The first is that you can change your active sheet by using the B.change_sheet function.  The second is that it is easy to read values.  If you are familiar with the module numpy, this module is designed to interact almost exactly the same : except you can also input strings of cell ranges!

now type the following:

>>> data = B[6, :30]
>>> data
<generator object <genexpr> at 0xb4031e14>

we have a generator object.  Pygnumeric outputs generators to reduce memory consumption when the user is requesting large amounts of data.  If you want it to be in a friendly tuple, just type:

>>> mytuple = tuple(data)
>>> mytuple
(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0)

and you have a tuple of data.  You can also retrieve a matrix of data.  First we have to create one:

>>> mymatrix = [[n*p for n in range(100)] for p in range(100)]

To get a nice big matrix of data.  First lets switch to a different sheet (we wouldn't want to destroy
our precious data!)

>>> B.change_sheet(0)
>>> B[0,0] = mymatrix

and you will get a huge matrix to fill in!

also try
>>> B[0,0,'Sheet3'] = mymatrix
or
>>> B[0,0,2] = mymatrix

and observe that you don't have to change sheets in order to do things.  To get some of the data back just type something like

>>> mydata = B[:100,:100,'Sheet3']
or
>>> mydata = B['A1:AA:100', 'Sheet3']

and you will receive tuples of data.

Note: Notice that this returns a tuple directly.  When retrieving large amounts of data, you should always do it from within the sheet that you are in, not using the sheetcall method above.  Because of the inner-workings of the class, it has to return a full tuple (rather than a generator) if you specifiy the sheet in the way shown above.  In most cases, it won't matter.  Only worry about it if you are pulling in tens of thousands of points of data.  Also, don't ever have multiple generators in separate sheets simultaneously.  Eventually this may be altered, but it is fairly standard for a class to not allow multiple iterations through it at the same time (although some do).  It SHOULD be ok to retrieve data by the method shown above even when you have generators in other sheets (needs further testing).  If this note didn't make sense to you, don't worry about.  Learn a little about generators, tuples, etc first.  In most cases this isn't important.

The end

That's all I have for tonight.  Play with the class and the interactive interpreter.  Build your own stuff.  Report any bugs to me.


Looking to the future

In the future this project will:

- Have no bugs (or very few :D)
               
- Have a superclass with undo and redo member functions, so that users can play with data without worrying (as much...) about destroying their work.  This superclass will only be used in the interactive interpreter - as it will slow down operations by at least 2x

- Hopefully come packaged with the standard python module.  I'm talking to some of the developers now about it.  When this is done, the variable "B" used above will automatically exist in the python interpreter (so you don't have to copy-paste that line of code every time)

- It also needs some kind of gui where you can link functions off the worksheet.  The cell function linking mechanism is a little bit of a hack (a hack that works and is kind of cool imo, but a hack none the less).

- Provide better performance, optimize code, and failsafe against events that cause Gnumeric to crash (there are a few of these currently.  You should never see them if you stick with what I have done here.  If you poke around in the inner workings of the class, you might run into one and they are annoying )

- Have better documentation and intro to newbies.  Imo, this is an EXCELLENT intro to python, as it allows you to see and manipulate data in a form people are familiar with.  Also, I encourage newbies to take a look at the class DataHandler in the file GnClasses.  It could be used to interface with ANY database that supports single cell retrieval and/or manipulation.

 

What you can do

-  Right now the biggest things I need is bug reports and publicity.  If you like the program, I strongly encourage you to do things like post on yahoo answers/reddit/your message boards/facebook/twitter/tell the people at work/tell your freinds/tell your girlfriend (only if she uses spreadsheets and likes to code python though.  If she does both of these things, feel free to also send me her number).  This code is free to use and free to steal, so my only tangible benefits from my efforts are becomming a better programmer and the joy of having people benefit from my blood sweat and tears (no seriously, it was really fun to make and I enjoyed it)

Anyway, MY girlfriend is here for the week, so don't expect too many updates this week!

 

The TRUE Python Spreadsheet Macro Class

The Code has undergone significant revisions and will now always be hosted here:

https://sourceforge.net/projects/pyworkbooks/files/

I recommend you view the documentation included there.

 

 

So there is a post I made not too long ago about the python addon for Gnumeric.  All the information there is still valid, but the program just got a WHOLE LOT better

I don't have a ton of time to give a long example now, but there is a tutorial included with the file.   Basically it allows for COMPLETE (and I mean complete) control of your entire workbook through python, even through the built-in interpreter if you run a few commands.  There are only three things you need to know to edit any cell in your spreadsheet

If you follow the macro, you can have an object called gBook.  This is the object that represents your worksheet.

gBook.change_sheet(sheetobject) can be passed an integer, a string, or a cell -- it will change your currently active sheet to that cell.  So if you have a sheet called "sandbox" and you say gBook.change_sheet("sandbox") then you can start editing the sheet sandbox!

gBook.change_range( tuple or cell_range) will change the reference cell.  For playing around you should just set it to (0,0) -- like this

gBook.change_range( (0,0) )

now lets say you wanted to read the first 10 columns in the first row.  Just type:

data = gBook[0, :9]
or
data = gBook["A1:A:10"]

This will return a generator object.  To change it into your data-type of choice (mine is a tuple) just type

data = tuple(data)

and there you have it!  You have your data. 

pyBusPirateLite Overhaul

Since I just started this blog, I figure I should add the other little project I am working on, the bus pirate.

The bus pirate is a cool little gizmo that allows your computer to behave like a powerful microcontroler, making it able to sense voltages, communicate over I2C, SPI, etc, and even program other microcontrollers!  When I came upon the bus pirate I was just learning python, and I wanted to use python in the bus pirate.  The python library was solid but had very little development: it essentially just provided function bindings to what you would want to do.  I took this base and built a more intuitive class (the UC class) and added recursive member functions so that all the little glitches associated with standard communication would not cause communication to fail.

You can read more about the bus pirate here: http://dangerousprototypes.com/docs/Bus_Pirate

You can see my post and code here: http://dangerousprototypes.com/forum/viewtopic.php?f=28&t=1703&sid=afd2b57c12d3acf8d4d3cd6c3f3dc5b9

development on the code is mostly complete, and I feel it is pretty solid.  Some of the functions are still untested (they are marked in the source code).  I strongly encourage people to report bugs to me by either posting on the forums and dangerous prototypes or here.

Python Addon in Gnumeric

Updates:

The Code has undergone significant revisions and will now always be hosted here:

https://sourceforge.net/projects/pyworkbooks/files/

I recommend you view the documentation included there.

 

 

So I've been desperately looking for a way to use python in spreadsheets, with little luck.  I found the xlrt and xlwt modules that interface with excel, but the idea of doing extensive work to make python work with excel made me sick to my stomach.  I took a long look at open office before I decided it was not for me.  Finally, I looked at the python spreadsheet pyspread.  While this looked interesting, it was still pre-Beta.

Then I stumbled onto Gnumeric.  The tutorial for the python module left an open hole in he number of things that would be difficult to do.  Use this tutorial if you are having trouble installing gnumeric or the modules, but read this blog for everything else :D 

Although the original module allowed you to do a special process to create python functions... how do you actually use them?  How do I extract data?  These questions caused me to create Pygnumeric

Pygnumeric itself interfaces with Gnumeric via the standard method (see the tutorial for details).  This method is clunky (although MUCH more effective than any other spreadsheet I had seen), and reminded me of writing C code (*shiver*).  In order to make writing python more like writing python, I set out to create a few simple functions which can be called from any cell in the worksheet.  The two you should know about now are:

py_import_function(module, function)
allows you to import a function from a named module (and assign a key-binding if you give it a third argument) that you can call with...

py_run( "function", CellRange)
py_run will call the function that you pass in as a string, plus pass an array (or value) to that function.  The array is obtained by converting a range of cells into the array.

Hopefully anyone can see the value of these.  They allow you to create your own functions that can be run inside of any Gnumeric cell.  They can be copy-pasted, have relative indexes -- they have all the benefits of a built in function and they are extremely easy to call.  Attached is the module and all the needed linker files plus a README that tells you what to do.   Also, take a look at the gnumeric file to get a small tutorial on how to do things.

For the future...
I'm looking for ways of interfacing directly with the sheet so that cell macros and outside macros can be created, but there doesn't seem to be any way for python to get the required information (although it CAN directly access sheets and change cells, there is no way to send it that information... hopefully this is fixed soon).  I would like to be able to export the sheet object so that it can be played with from external python interpreters.  I'm thinking of doing this by "registering" the sheet on a virtual server.