python


27
Mar 07

PyPN: Upload to FTP

Over in the forums, MurphyMc shows a sample bit of script that will upload your current file to FTP using Python via a PyPN script. It currently hard-codes site/user/pass etc. but these could easily be retrieved from elsewhere (potentially even project properties in the future).

Save To FTP Script

It’s easy to imagine how this could be extended in lots of directions, for example a script could retrieve a file from FTP, store it in a temporary location and then re-upload when the user is finished. That’s FTP integration done, what next!

Obviously I understand that many requests are for a fully-integrated FTP browser/editor, but this example really shows what can be achieved with the scripting integration.


27
Mar 07

PyPN: Validate Your Xml

Have you tried playing with PyPN and PN’s scripts system yet? If not, then perhaps you should. A large number of requests on PN’s Feature Requests tracker could be implemented as scripts. Some perhaps not so elegantly as if they were built in, others perfectly.

To start looking at ways that PyPN enhances Programmer’s Notepad, let’s look at a very early feature request: Validate XML.

Here is a simple PyPN script that does just this, adding a command to the scripts window called Validate in the XML group. This can, of course, be mapped to a keyboard shortcut.

The script simply runs the contents of your document through expat. When your Xml is valid no output is printed, where there’s an error the output window will show you the details.

To use this code, just drop it in a file called something like pnxml.py in the scripts directory. You’ll need PyPN installed, along with Python 2.4 and the PyXml package. As of Python 2.5 expat is bundled so the extra package won’t be necessary.


import pn
import scintilla
from pypn.decorators import script
import xml.parsers.expat as expat

@script("Validate", "Xml")
def ValidateXml():
	editor = scintilla.Scintilla(pn.CurrentDoc())
	text = editor.GetText(0, editor.Length)

	parser = expat.ParserCreate()

	try:
		parser.Parse(text, True)
	except expat.ExpatError, ex:
		pn.AddOutput("Error: " + str(ex))

22
Sep 06

PN 2.0.7.610 and PyPN 0.3 Released

I’m pleased to announce that the current development build on SourceForge of PN 2 is now 2.0.7.610 which contains just minor fixes from .609 to make working with extensions better. PyPN 0.3 adds a number of features over the first two releases and also several bugfixes.

Download PN 2.0.7.610

Download PyPN 0.3

Remember you’ll need Python 2.4 installed to use PyPN.


17
Aug 06

Announcing pyPN-0.1

I finally got some time to clean up and zip up the current pyPN bits and have uploaded them to the web site:

http://www.pnotepad.org/files/pypn-0.1.zip

You will need the latest development build of PN (2.0.7.608 at the time of writing) and Python 2.4 to use this.

What is pyPN?

pyPN is the first extension for Programmer’s Notepad 2, and provides support for scripting PN using Python! You can already do a lot, but there’s also a lot of functionality yet to be exposed.

Other extensions can be provided using the same mechanism pyPN uses, see http://www.pnotepad.org/plugindoc/ for the gory C++ details (not as scary as you might think!).

Version 0.1

This is definitely beta software, so please experiment and report plenty of feedback! Extract the files into your PN folder and restart PN. If you already have a config.xml file you’ll need to merge the two files.

There will be more documentation as time goes on, but the code includes one very simple sample script showing how scripts can be built in to the scripts window. You can turn any python file or buffer into a runnable script by right-clicking and selecting “Use as Script” – this will add the window to the scripts window from where you can double-click to run.

So, some simple examples:

import pn
pn.AddOutput(“Hello!\n”)

This will add text to the output window (you’ll need to show the window first).

To work with scintilla (the text editing component) try something like this:

import pn, scintilla
s = scintilla.Scintilla(pn.CurrentDoc())
s.AppendText(6, “Hello!”)

When you make a mistake in your script at runtime the traceback will be shown in the output window (again, you need to manually show this).

Note that if you put broken scripts in the scripts directory this will currently crash PN on startup – this will  be fixed in future versions.

Finally note that you get some automatic indenting when writing Python code now, the code for this is in the init.py file. You can write indenters for other languages in a similar style. The indenting isn’t perfect, but I love it!

Let me know how you get on, and post anything that works for others to see as either a comment or on the forums!


12
May 06

Bits and Pieces

I’ve been working on various web interfaces at work over the last month or so, here are some interesting links that I’ve been looking at:

  • Turbogears – Turbogears is an excellent Python web framework tying together lots of open source components. There is a new version just out, 0.9a6.
  • Yahoo UI Grids – Easy grid layouts for web pages with free CSS from Yahoo!
  • Twisted – Excellent event-driven networking framework written in Python.
  • More Nifty Corners – Yet another rounded corner technique
  • Grey Box – Nice javascript pop-up windows
  • CSS List Formatting

ps. After an insanely busy few months dealing with buying a house (still ongoing), a lot of upheaval at work and lots of busy projects I’m trying to ease myself back into blogging and developing PN.


20
Apr 06

Turbogears Local Widget Links

When writing a widget that you’re only going to use in your own project, you might still want to take advantage of the automatic javascript link insertion. This little class lets you do that:

from turbogears import startup
from turbogears.widgets.base import JSLink

class LocalJSLink(JSLink):
    register = False

    def __init__(self, name):
        self.mod = None
        self.name = name

    def update_data(self, d):
        super(JSLink, self).update_data(d)
        d["link"] = "/%sstatic/javascript/%s" % (startup.webpath, self.name)

To use this, just place your javascript in your /static/javascript directory and add a LocalJSLink for the file you want to your widget:

javascript = [LocalJSLink("myjsfile.js")]


31
Mar 06

Installing setuptools with no network connection

…and I mean really no network or internet connection!

The setuptools instructions do suggest that you can do this using ez_setup.py and passing it the .egg file for setuptools. However, I found that doing this got me a stacktrace for my efforts:

Traceback (most recent call last):
  File "ez_setup.py", line 228, in ?
    main(sys.argv[1:])
  File "ez_setup.py", line 161, in main
    egg = download_setuptools(version, to_dir=tmpdir, delay=0)
  File "ez_setup.py", line 142, in download_setuptools
    src = urllib2.urlopen(url)
  File "c:\python24\lib\urllib2.py", line 130, in urlopen
    return _opener.open(url, data)
  File "c:\python24\lib\urllib2.py", line 358, in open
    response = self._open(req, data)
  File "c:\python24\lib\urllib2.py", line 376, in _open
    '_open', req)
  File "c:\python24\lib\urllib2.py", line 337, in _call_chain
    result = func(*args)
  File "c:\python24\lib\urllib2.py", line 1021, in http_open
    return self.do_open(httplib.HTTPConnection, req)
  File "c:\python24\lib\urllib2.py", line 996, in do_open
    raise URLError(err)
urllib2.URLError: <urlopen error (11001, 'getaddrinfo failed')>

I eventually found that if I changed the egg to a zip file, extracted its contents, renamed back to an egg and then ran ez_setup.py setuptools.egg that it would work.

Hope this helps someone else!


27
Mar 06

Building PyPN

For those that are working with PN from subversion at the moment, you may need a bit of help getting the python extension going properly:

First you need to build boost_python. I did this using visual studio (too lazy to work out bjam) and so my lib is boost_python.lib. If you use bjam you’ll end up with something like “boost_python-vc71-mt-gd-1_33_1.lib” (!) so you’ll need to change the name of the link target for that to work.

Once you have got everything to build, you also need some python files in place in the bin directory. These are in the source tree under pypn\scripts, so just copy the contents of that directory to bin (so you have init.py directly in bin and new pypn and scripts subdirectories) and you should be all set to go.

I’ll follow this up shortly with a “how PyPN works” post. I’m looking for feedback on this because it’s not finished yet and I think some parts are maybe too complex – I feel there are bits that could do with paying more attention to the KISS principle.


6
Mar 06

Form attributes with Turbogears Widgets

The Widgets features in Turbogears allow you to easily insert forms in your page. But what if you want to control the behaviour and look of the form tag?

You need the “form_attrs” parameter:

importConfigForm = widgets.TableForm(
    fields = [
        widgets.TextField(name="name", label="Configuration Name:")
    ],
    submit_text="Import",
    form_attrs={'style':'display:none', 'id':'importForm'})

The above code creates a form and sets the “style” attribute to “display:none” and the “id” attribute to “importForm”.


3
Mar 06

Writing XML with namespaces from minidom

Although python’s minidom XML DOM implementation supports namespaces when you parse and create nodes, it bizarrely has no way to write out XML including the proper declarations:

>>> import xml.dom.minidom
>>> from xml.dom import minidom
>>> impl = minidom.getDOMImplementation()
>>> doc = impl.createDocument("urn:tempuri", "e", None)
>>> doc.toprettyxml()
'<?xml version="1.0" ?>\n<e/>\n'

Look, no namespace!

Fortunately, you can use the PyXML package to write out the xml properly. Install PyXML from sourceforge and then use like this:

>>> from xml.dom.ext import PrettyPrint
>>> PrettyPrint(doc)
<?xml version='1.0' encoding='UTF-8'?>
<e xmlns='urn:tempuri'/>

Note that if you don’t want pretty printing you can use “Print” instead of “PrettyPrint“.

If you want to store the XML in a string instead of just printing it to stdout (imagine that – actually wanting to use the result of PrettyPrint!) then you need to provide a stream:

>>> import StringIO
>>> s = StringIO.StringIO()
>>> PrettyPrint(doc, s)
>>> s.getvalue()
"<?xml version='1.0' encoding='UTF-8'?>\n<e xmlns='urn:tempuri'/>\n"