How to run SimpleHTTPServer on IronPython on Mono ================================================= :Author: Seo Sanghyeon :Contact: tinuviel@sparcs.kaist.ac.kr :Date: 2006-03-18 .. note:: (2006-04-27) This document is out of date. It was written for IronPython 1.0 Beta 4 and Mono SVN trunk as of March. I believe some of the information here is still useful, but you shouldn't really expect this document to be up-to-date. .. contents:: 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 .. _SimpleHTTPServer: http://docs.python.org/lib/module-SimpleHTTPServer.html .. _IronPython: http://workspaces.gotdotnet.com/ironpython .. _Mono: http://www.mono-project.com/ 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``. .. _Debian GNU/Linux: http://www.debian.org/ __ http://www.mono-project.com/AnonSVN __ http://www.mono-project.com/Compiling_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 .. _workspace: http://workspaces.gotdotnet.com/ironpython 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 patch: :: --- 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. __ http://lists.ironpython.com/pipermail/users-ironpython.com/2006-March/001922.html 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__. __ http://sparcs.kaist.ac.kr/~tinuviel/fepy/lib/socket.py 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: .. _FileStream patch: :: --- 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. __ http://lists.ironpython.com/pipermail/users-ironpython.com/2006-March/001944.html IronPython's file object lacks ``closed`` attribute. The following patch fixes it: .. _file.closed patch: :: --- 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: .. _IsDaylightSavingTime patch: :: --- 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__! __ http://localhost:8000/ 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`_. .. _IronPython mailing list: http://lists.ironpython.com/listinfo.cgi/users-ironpython.com If you have some comments on this howto, you may post it to the mailing list, or mail me directly. Feedbacks are greatly appreciated!