How to run SimpleHTTPServer on IronPython on Mono
- Contact:
- tinuviel@sparcs.kaist.ac.kr
- Date:
- 2006-03-18
The purpose of this document is twofold: to show how to run SimpleHTTPServer on IronPython on Mono, and to debunk some myths like:
IronPython doesn't run on Mono
IronPython doesn't support Python standard library
IronPython is a toy
Setting up Mono
Unfortunately, you need the very latest Mono to run the current release of IronPython at the time. As both projects mature, this is expected to be less of the problem.
The author uses the unstable branch of Debian GNU/Linux, and the revision 57777 of Mono SVN trunk (checked out 2006-03-10). I would be interested in your experience on other platforms.
For anonymous access to the Mono SVN repository, refer to this page on Mono project website. For how to compile and install Mono from the source, read this. It's nothing difficult, really. Enjoy your favorite pastime while things are being built.
Throughout this article, Mono is assumed to be installed under prefix /opt/mono.
Setting up IronPython
IronPython development is going on its own workspace at gotdotnet.com. Choose Releases link on the left menu and download IronPython 1.0 Beta 4. Extract the archive and change to the extracted directory. The directory content looks like this:
$ ls Doc IronMath.dll IronPythonConsole.exe License.html Src FAQ.html IronPython.dll Lib Readme.html Tutorial
Let's run the console:
$ /opt/mono/bin/mono IronPythonConsole.exe IronPython 1.0.2258 (Beta) on .NET 2.0.50727.42 Copyright (c) Microsoft Corporation. All rights reserved. >>> 1 + 1 2 >>>
Okay, it works. Exit the console.
IronPython doesn't ship Python standard library as part of the release, but it doesn't mean that IronPython doesn't support Python standard library. On the contrary, IronPython test suite includes the run of Python regression test suite. Current status can be found at Src/Scripts/PythonStdLibBase.log file.
Therefore, let's replace Lib directory with one from CPython. CPython 2.4.2 in my case:
$ rm -rf Lib $ cp -a /usr/lib/python2.4 Lib
Delete site.py, as it makes little sense. IronPython assumes Windows-like directory layout: that is, it adds Lib directory under the directory where the executable is located to the default search path for Python modules:
$ rm Lib/site.py
Let's test this:
$ /opt/mono/bin/mono IronPythonConsole.exe IronPython 1.0.2258 (Beta) on .NET 2.0.50727.42 Copyright (c) Microsoft Corporation. All rights reserved. >>> import os >>> print os.__file__ /home/tinuviel/devel/fepy/IronPython-1.0-Beta4/Lib/os.py >>>
Looks good. The path will differ, for the obvious reason.
Patching and rebuilding IronPython
Above setup should be enough to play with IronPython without touching its C# source. But soon you will want to patch the source to fix or to workaround various bugs, and to rebuild from the source.
Let's start by deleting the binaries:
$ rm IronMath.dll IronPython.dll IronPythonConsole.exe
Change to Src and type make:
$ cd Src $ make csc -t:library -out:../IronMath.dll -recurse:IronMath/*.cs /bin/sh: csc: command not found make: *** [../IronMath.dll] Error 127
Oops, csc is the name of Microsoft C# compiler. This makefile is designed to run on Windows. Let's fix that:
--- makefile.orig 2006-03-08 11:11:58.000000000 +0900
+++ makefile 2006-03-18 23:00:06.000000000 +0900
@@ -1,2 +1,2 @@
-CSC=csc
+CSC=/opt/mono/bin/gmcs -warn:0
@@ -8,3 +8,3 @@
../IronPython.dll: ../IronMath.dll
- $(CSC) -t:library -r:../IronMath.dll -out:../IronPython.dll -recurse:IronPython/*.cs
+ $(CSC) -t:library -r:../IronMath.dll -r:System.Design.dll -r:System.Drawing.dll -out:../IronPython.dll -recurse:IronPython/*.cs
@@ -15,3 +15,3 @@
IronPythonTest/bin/Debug/IronPythonTest.dll: ../IronMath.dll ../IronPython.dll
- mkdir IronPythonTest/bin/Debug
+ mkdir -p IronPythonTest/bin/Debug
$(CSC) -t:library -r:../IronMath.dll -r:../IronPython.dll -out:IronPythonTest/bin/Debug/IronPythonTest.dll -recurse:IronPythonTest/*.cs
There are three changes here:
First change replaces csc with gmcs, Mono C# compiler. Unlike mcs (another Mono C# compiler), gmcs supports C# 2.0 features like generics, which IronPython requires. I added an option to disable warnings, to simplify compilation output below.
Second change adds two assembly references needed to compile IronPython.dll, which was left out by accident in Beta 4. This will be fixed in the next release.
Third change replaces mkdir with mkdir -p. On Windows, bare mkdir command creates parent directories as needed.
Type make again:
$ make /opt/mono/bin/gmcs -warn:0 -t:library -out:../IronMath.dll -recurse:IronMath/*.cs /opt/mono/bin/gmcs -warn:0 -t:library -r:../IronMath.dll -r:System.Design.dll -r:System.Drawing.dll -out:../IronPython.dll -recurse:IronPython/*.cs /opt/mono/bin/gmcs -warn:0 -t:exe -r:../IronPython.dll -out:../IronPythonConsole.exe -recurse:IronPythonConsole/*.cs mkdir -p IronPythonTest/bin/Debug /opt/mono/bin/gmcs -warn:0 -t:library -r:../IronMath.dll -r:../IronPython.dll -out:IronPythonTest/bin/Debug/IronPythonTest.dll -recurse:IronPythonTest/*.cs
Looks good. Now go try examples in Setting up IronPython section again.
Various patches
IronPython doesn't have socket module at the time, which is obviously required to run SimpleHTTPServer. So I wrote it as a thin wrapper around classes in System.Net and System.Net.Sockets namespace. You can get it here.
Replace Lib/socket.py with it.
IronPython can create Python file object from .NET stream. I used this ability to implement makefile method of socket object. However, there is a simple bug preventing use of this technique for streams other than FileStream. Here's the fix:
--- IronPython/Runtime/PythonFile.cs.orig 2006-03-08 11:11:48.000000000 +0900
+++ IronPython/Runtime/PythonFile.cs 2006-03-19 00:07:27.000000000 +0900
@@ -745,3 +745,3 @@
[PythonName("__new__")]
- public static PythonFile Make(object cls, FileStream filestream) {
+ public static PythonFile Make(object cls, Stream filestream) {
string mode;
This will be fixed in the next release. As included makefile lacks any dependency information, you will need to use make -B to rebuild.
IronPython's file object lacks closed attribute. The following patch fixes it:
--- IronPython/Runtime/PythonFile.cs.orig 2006-03-08 11:11:48.000000000 +0900
+++ IronPython/Runtime/PythonFile.cs 2006-03-19 00:48:41.000000000 +0900
@@ -839,2 +839,9 @@
+ public bool closed {
+ [PythonName("closed")]
+ get {
+ return isclosed;
+ }
+ }
+
[PythonName("flush")]
IronPython calls .NET 2.0 method IsDaylightSavingTime in its time module, but this method is not implemented in Mono yet. Here's the workaround:
--- IronPython/Modules/time.cs.orig 2006-03-08 11:11:32.000000000 +0900
+++ IronPython/Modules/time.cs 2006-03-19 00:30:58.000000000 +0900
@@ -40,3 +40,3 @@
public static double altzone = TimeZone.CurrentTimeZone.GetDaylightChanges(DateTime.Now.Year).Delta.TotalSeconds;
- public static bool daylight = DateTime.Now.IsDaylightSavingTime();
+ public static bool daylight = false; // DateTime.Now.IsDaylightSavingTime();
public static double timezone = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).TotalSeconds;
@@ -266,3 +266,3 @@
- return Tuple.MakeTuple(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, doy, dt.DayOfYear, dt.IsDaylightSavingTime() ? 1 : 0);
+ return Tuple.MakeTuple(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, doy, dt.DayOfYear, 0); // dt.IsDaylightSavingTime() ? 1 : 0);
}
The workaround assumes that daylight saving time is not observed, because that's what happened to be the case for the author.
SocketServer assigns sys.exc_traceback to None to "help garbage collection", a rather dubious reason as sys.exc_traceback is deprecated anyway. Currently IronPython raises TypeError for this assignment, which is a bug. But let's fix this on CPython side this time:
--- Lib/SocketServer.py.orig 2005-11-21 01:15:14.000000000 +0900
+++ Lib/SocketServer.py 2006-03-19 00:41:07.000000000 +0900
@@ -523,3 +523,3 @@
finally:
- sys.exc_traceback = None # Help garbage collection
+ pass
Finally, os.fstat is not implemented in IronPython. Let's use os.stat instead for now:
--- Lib/SimpleHTTPServer.py.orig 2005-11-21 01:15:14.000000000 +0900
+++ Lib/SimpleHTTPServer.py 2006-03-19 00:56:15.000000000 +0900
@@ -82,3 +82,3 @@
self.send_header("Content-type", ctype)
- self.send_header("Content-Length", str(os.fstat(f.fileno())[6]))
+ self.send_header("Content-Length", str(os.stat(path)[6]))
self.end_headers()
Running SimpleHTTPServer
Finally...
$ /opt/mono/bin/mono IronPythonConsole.exe Lib/SimpleHTTPServer.py Serving HTTP on 0.0.0.0 port 8000 ...
Ma, look!
You may want to read Readme.html of IronPython, now served by IronPython itself.
Next steps
If you are interested in IronPython, you should subscribe to the IronPython mailing list.
If you have some comments on this howto, you may post it to the mailing list, or mail me directly. Feedbacks are greatly appreciated!