tag:blogger.com,1999:blog-5972617539777812024-02-20T20:35:53.944-07:00Jeff Hardy's BlogWritings on IronPython and NWSGI.jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comBlogger65125tag:blogger.com,1999:blog-597261753977781.post-35994562249563671462013-06-27T00:46:00.001-06:002013-06-27T00:46:21.385-06:00Anonymous Function Blocks in Python<p>Python has anonymous functions in the form of lambdas, but they are limited to a single expression. For the most part, this is enough (especially now that print() is a function in Python 3), but there are cases where being able to have multiple statements would be useful. Right now, the way to do this in Python is to use a named, nested function:</p><pre>def upload_data(dest, *urls):
def _fetch(x):
data = fetch_url(url)
sent = 0
for line in data:
sent += send_data(dest, line)
return sent
return map(_fetch, urls)
</pre>
<p>Now, this could be rewritten as a set of expressions, but what if we had multi-statement anonymous functions?</p>
<h3>The Idea</h3>
<p>I’m not calling this a proposal because, quite frankly, I’m not sure it’s worth the effort, and I certainly don’t have the time or energy to try and champion it. I also haven’t looked to see if someone else has already had the same idea: it just occurred to me and I thought I’d write it down. The thought of wading through python-ideas to see if someone already had the same does not strike me as a good use of time.</p>
<p>Anyway, I was working on implementing <a href="http://www.python.org/dev/peps/pep-3107/">function annotations</a> for IronPython, and I realized that the arrow operator (->) was not used anywhere else in the grammar, and as far as I could tell was completely unambiguous – there’s no existing Python code that would contain the arrow. So, rather than being able to put multi-line lambdas anywhere (like C# or C++), what if they were restricted, like Ruby’s blocks? Python can’t use <tt>do</tt> like Ruby does, but maybe it could use the arrow instead?</p>
<p>Then, because no existing Python functions expect blocks, there needs to be a way to refer to a block in a statement. I decided to copy Ruby’s use of &, but in a slightly different way – as a placeholder for the block attached to that statement. A bare & is also not valid Python code, and I could not think of anything it could combine with that would be currently valid code.</p>
<h3></h3>
<h3>Syntax</h3>
<p>The result is something like this:</p><pre>def upload_data(dest, *urls):
return map(&, urls) -> (url):
data = fetch_url(url)
sent = 0
for line in data:
sent += send_data(dest, line)
return sent
</pre>
<p>The <tt>–></tt> is used to introduce the block; it’s followed by a <a href="http://docs.python.org/3.3/reference/compound_stmts.html#grammar-token-parameter_list">parameter list</a>, a :, and a <a href="http://docs.python.org/3.3/reference/compound_stmts.html#grammar-token-suite">suite</a>, just like a normal <a href="http://docs.python.org/3.3/reference/compound_stmts.html#function-definitions">funcdef</a>. In fact, even the type annotations would be usable, although the resulting double arrow (<tt>map(&, foo) –> (f : int) –> str:</tt>) looks a bit weird.</p>
<p>OK, so it’s workable within the grammar (I actually implemented in IronPython’s parser, just to be sure). What does it mean?</p>
<h3></h3>
<h3>Semantics</h3>
<p>Semantically, these blocks are just a prettied-up version of the first function. The block is transformed into a nested function immediately before the statement with a generated name, and any block references (&) are replaced with the generated name. Some tricks would have to be played with line numbers to make debugging make sense, but that’s not insurmountable. </p>
<p>Multiple references would be allowed, and although I can’t think of a use case for that, it makes no sense to disallow it.</p>
<p>Even decorators (which are just functions, after all) can still be used:</p><pre>map(my_decorator(&), foos) -> (foo):
pass
</pre>
<p>There’s no reason they couldn’t be generators, either:</p><pre>list(&()) -> ():
i = 0
while i < 10:
yield i
i += 1
</pre>
<p>The idea is to make them as close to named Python function as possible. The object passed to map is still a function instance, so all existing Python functions that take a callable should be immediately usable.</p>
<h3>Implicit Blocks</h3>
<p>Explicitly passing around block references is necessary to deal with existing Python functions (and we all know “explicit is better than implicit”) but it’s kind of ugly. Borrowing, again, from Ruby, it would be nice to have blocks be implicit:</p><pre>def map(&func, iterable):
return [func(e) for e in iterable]
map(foos) -> (foo):
pass
</pre>
<p>This gets a lot trickier to implement in the general case, where there might be multiple functions with implicit blocks in the same statement. A rule of “outermost-rightmost” would probably work. I’m not exactly sure what restrictions Ruby imposes.</p>
<h3>Use Cases</h3>
<p>Blocks are possible to implement, and probably not too hard either. However, that doesn’t mean they’re worth doing. There aren’t too many situations where you can’t use list comprehensions, generator expressions, or lambdas, and nested name functions already exist to handle the remaining cases.</p>
<p>There are a couple of things that they do make nicer, though. Implementing decorators that take arguments, for one:</p><pre>def timed(name):
return & -> (func):
return functools.wraps(func)(&) -> (*args, **kwargs):
with timer(name):
return func(*args, **kwargs)
</pre>
<p>Speaking of with statements, they wouldn’t be necessary with blocks:</p><pre>def with_(obj, &func):
obj.__enter__()
try:
return func(obj)
finally:
obj.__exit__()
with(open("foo.txt")) -> (f):
upload(f)</pre>
<p>It’s not exactly the same, since the block cannot return from the enclosing function, and you’d need nonlocal to modify variables in the outer scope. A similar treatment could be applied to <tt>for</tt> as well.</p>
<p>Finally, there’s the many things Ruby does with its own blocks, such as <a href="http://www.sinatrarb.com/">Sinatra</a>:</p><pre>get('/hi') -> ():
return 'Hello, World'
</pre>
<p>But <a href="http://flask.pocoo.org/">Flask</a> does basically the same thing in the confines of existing Python. Still, it is very nice syntax sugar.</p>
<h3>The Verdict</h3>
<p>I think the idea is sound – if blocks are added to Python, they should look something like this. The work required for blocks using explicit block references should be relatively simple for someone familiar with CPython. Implicit block references are harder, but probably still doable.</p>
<p>That said, the use cases aren’t enough to motivate me to want to implement it (except for possibly the decorator – I can never figure out what to name those nested functions). If anyone else wants to, feel free to reuse the syntax. And if someone else already had the same idea, my apologies.</p>
<p>Now that I’ve written it down, I can page this idea out and never think of it again.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-81865341282062212552013-06-25T22:54:00.001-06:002013-06-25T22:54:49.597-06:00IronPython 3 TODO<p>This is my own list of things I want to see in IronPython 3 (after I get 2.7.4 out). It’s unlikely all of them will make 3.0 (which I’m targeting for PyCon 2014 next April), but hopefully most of them will.</p> <h3>Python 3 Features</h3> <p>Obviously, this is the most important thing. A couple are already implemented in branches (function annotations and part of keyword-only args), a few are relativelyeasy (metaclass changes, removal of old-style classes), and a few are hard (nonlocal, super(), yield from).</p> <p>The first step will be to bring the new standard library and work from there. In addition, any changes needed to make the 3.x stdlib work on IronPython will be rolled into CPython so that we don’t have to maintain our own fork, with all of the work that that entails.</p> <h3>Better Test Coverage</h3> <p>IronPython’s test are currently a mess: they take too long to run and a huge number don’t even pass. Also, the test runner only works on Windows. It will need to be heavily modified (or probably replaced) with one that is more portable. It would also be nice to be able to generate coverage metrics, and be able to mark tests as “expected failure” so that TeamCity will actually build and run the tests successfully.</p> <h3>More Platforms</h3> <p>Windows desktop/server is no longer the only game in town. IronPython already works well on Mono, but without test coverage it’s hard to know how well. On top of that, the tablet/phone market is huge and getting bigger. Xamarin’s wonderful tools will make Android and iOS ports possible, and I’ve seen several requests for Windows Phone 8 and Windows Store (“Metro”) support as well, but they may not happen without someone volunteering to maintain them. Likewise, support for Silverlight will probably be dropped unless someone volunteers to maintain it.</p> <p>The current code base is a mess of FEATURE_ and platform #ifdefs that is rather hard to maintain. There is the concept of a Platform Adaptation Layer (PAL), but it doesn’t get used everywhere. I’m going to see how feasible it is to expand the PAL to get rid of as many #ifdefs as possible.</p> <p>At first each platform will only support embedding IronPython, but will eventually be extended to support building apps in pure Python.</p> <h3>“Static” Compilation and MSBuild support</h3> <p>IronPython currently has pyc.py to generate executables and DLLs, but it’s a bit clunky, only supports .NET 4, and is missing some useful features like arbitrary resources. Improvements to pyc.py will add those missing features to generate truly standalone executables.</p> <p>The other issue is that the DLLs it generates are not usable from any .NET language; they must be loaded in an IronPython host. “Static” compilation will allow DLLs to be generated with actual .NET classes that can be reflected over and thus will be useful as plugins (for e.g. MSBuild or IIS) or to build pure-Python Andoid/iOS/WP8/Metro apps, all of which are basically plugins as well. Python classes just need some special adornment and pyc.py will pick them up and compile them to real types (or something similar):</p><pre>import clr
of = clr.of
class RealClass(metaclass=clr.object):
@clr.method(visibility="public")
def Foo(self, x : of(int), y : of(str)) -> float:
pass
</pre>
<p>This is both a lot and a little bit of work; the code to do the type generation is already there, but it makes some assumptions about global state that need to be pulled apart and refactored.</p>
<h3></h3>
<h3>Yikes</h3>
<p>OK, so there’s a lot there for nine months. And, keep in mind, this is just what <em>I</em> want to work on. However, I think this list will make sure that IronPython stays viable in the future. If you have any other suggestions, let me know. </p>
<p>As always, if you’re interested in helping, get in touch. I’m more then willing to help anyone get started. The codebase is intimidating at first, but once you got over the initial learning wall it’s not so bad.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-4010846362633495222012-09-16T00:22:00.001-06:002012-09-16T00:22:07.452-06:00Changing .NET Assembly Platforms with Mono.Cecil<p>By default, .NET assemblies can only be loaded by the platform they are built for, or potentially anything later in the same stream (.NET 4 can load .NET 2 assemblies, Silverlight 5 can load Silverlight 4 assemblies, etc.). However, some of the stuff I’ve been working on for IronPython would be a lot easier if I could just build one assembly and use it anywhere. While it’s not possible with just one assembly, I can generate all of the other assemblies from the base one, with a few caveats.</p> <p>The problem is caused by Reflection.Emit. IronPython uses RefEmit to generate .NET classes at runtime, and has the ability to store those on disk. However, RefEmit will only generate assemblies for the .NET runtime it is currently running under, which is usually .NET 4. Not all platforms support RefEmit, and re-running the compilation on every platform that needed it would be a pain anyway.</p> <p><a href="http://weblog.ikvm.net/PermaLink.aspx?guid=d0dc2476-471b-45f3-96bf-a90bc2f5800b">IKVM.Reflection</a> offers a RefEmit-compatible API that can target any platform, but using it would require changing IronPython’s output code to use IKVM RefEmit instead of standard RefEmit when compiling, which is a fairly large change I didn’t want to make right now (maybe for 3.0). </p> <p><a href="http://www.mono-project.com/Cecil">Mono.Cecil</a> is a library for manipulating .NET assemblies. It’s often used to inject code into assemblies and other mundane tasks. What I wanted to know was whether I could take a .NET 4 assembly generated by IronPython and produce a .NET 2 assembly that would run on IronPython for .NET 2. The answer turns out to be yes, but it’s a bit of a pain.</p> <h3>Rewriting assemblies for fun and profit(?)</h3> <p>There are a few things in an assembly that may have to change to get it to work on a different runtime. The first is simple: change the target platform, which is part of the assembly metadata. The next is a bit trickier, but not too bad: change the versions of referenced assemblies to match the platform you are targeting. The third part requires some tedious cataloguing: find any types that are located in different assemblies and change them to point at the correct ones for that target platform. The final piece is the most difficult: potentially, rewrite the actual IL code so that it works on any platform.</p> <p>The first part, changing the assembly version, is trivial:</p><pre>ad.Modules[0].Runtime = TargetRuntime.Net_2_0</pre>
<p>The second part is not much harder, but requires some extra setup: we need to know what version to change it to. This is potentially an impossible problem, because you don’t always know what types might be present, and any references that aren’t to framework assemblies could break. Right now, I’m just hardcoding everything, but it would be better to pull this from whatever version of <tt>mscorlib.dll</tt> is being targeted.</p><pre>{
"mscorlib": (2,0,0,0),
"System": (2,0,0,0),
"System.Core": (3,5,0,0),
}</pre>
<p>The next part of the process is changing the assembly a type belongs in. It’s not actually that hard to do in Mono.Cecil, it just takes a low of upfront knowledge about how things have moved around. In the .NET 2 version of IronPython, the DLR is in <tt>Microsoft.Scripting.Core</tt>; in .NET 4, it’s in <tt>System.Core</tt>. Successfully loading a generated assembly means changing the relevant types from <tt>System.Core</tt> to <tt>Microsoft.Scripting.Core</tt>. In some cases, the namespace has also changed; the expression trees are in <tt>System.Linq.Expressions</tt> in .NET 4 but in <tt>Microsoft.Scripting.Ast</tt> for .NET 2.</p>
<p>The key here is to use <tt>Module.GetTypeReferences()</tt> to get all of the types an assembly references, and then change the <tt>Scope</tt> property to point to the new assembly and the <tt>Namespace</tt> property to the new namespace.</p>
<p>The final part (which is actually done first) is having to rewrite the IL code to replace any unsupported functions with ones that are. Thankfully, there is only one case of that so far: <tt><a href="http://msdn.microsoft.com/en-us/library/dd287766.aspx">StrongBox<T>()</a></tt>, which exists in .NET 4 (and is used by <tt><a href="http://msdn.microsoft.com/en-us/library/dd728224.aspx">LambdaExpression.CompileToMethod()</a></tt>) but does not exist in .NET 3.5. The paramaterless constructor call gets replaced by passing null to the constructor that takes an initial value, which is all the paramaterless one does. This is actually pretty straightforward:</p><pre>strongbox_ctor_v2 = clr.GetClrType(StrongBox).MakeGenericType(Array[object]).GetConstructor((Array[object],))
strongbox_ctor_v4 = clr.GetClrType(StrongBox).MakeGenericType(Array[object]).GetConstructor(Type.EmptyTypes)
method = dcc.Methods[0]
il = method.Body.GetILProcessor()
instr = method.Body.Instructions[4] # This is specific to my use; YMMV
il.InsertBefore(instr, il.Create(OpCodes.Ldnull))
il.Replace(instr,
il.Create(OpCodes.Newobj,
method.Module.Import(strongbox_ctor_v2)))
</pre>
<p>There is one caveat here: because of how assembly references work, the IL rewriting should be done before the reference versions are changed, so that there are no stray references to 4.0 assemblies.</p>
<h3>Next Steps</h3>
<p>This is all just a proof of concept; there’s a few more things to do to make it usable. For example, it needs to be able to look at a set of references and work out which types moved where based on that (this is really important for Windows 8, which moved <em>everything</em>, it seems). Still, the approach seems promising; hopefully there aren’t anymore landmines to deal with.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-72330881786259300032012-04-04T21:37:00.000-06:002012-04-04T21:37:57.274-06:00IronPython Samples<span style="font-family: inherit;">One thing that I think has been missing from IronPython for a while now is a set of embedding samples. There are many host environments that IronPython can run in, and while they are all similar they have some differences to.</span><br />
<span style="font-family: inherit;"><br /></span><br />
To correct this, I put together a set of <a href="https://github.com/jdhardy/IronPythonSamples">IronPython Samples</a> demonstrating how to embed IronPython in a console, WinForms, and WPF app, as well as writing a complete WPF app in IronPython.<br />
<br />
Any feedback (and pull requests!) is welcome. In particular, I'd like to know what other platforms people are interested: Android, Windows Phone, Silverlight, ASP.NET, etc.jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-48593916136299551172012-03-13T01:28:00.001-06:002012-03-13T01:28:51.332-06:00Mea Culpa<p>I was so excited about getting IronPython 2.7.2 out the door, I briefly dropped my common sense and made a change to IronPython that never should have been made without triggering another RC release. So what the hell happened?</p> <p>The change in question is <a href="https://github.com/IronLanguages/main/commit/f8cce37420838b8197f31eedb1e04ae3a2e102ac">f8cce37</a>. The correction is <a href="https://github.com/IronLanguages/main/commit/4a764976adb8753a524b06d2926824850d97a491">4a76497</a>.</p> <h3>What Broke?</h3> <p>The property in question – <tt>MaybeNotImplemented</tt> – checks to see if a method’s return type has the <tt>MaybeNotImplemented</tt> attribute, which tells IronPython that the operator may return <tt><a href="http://docs.python.org/library/constants.html#NotImplemented">NotImplemented</a></tt>; this indicates that the attempted operation doesn’t work and that other options should be tried. Without specifying <tt>[return:MaybeNotImplemented]</tt> on a native method, IronPython won’t generate code to perform the other operations.</p> <h3>Windows Phone Fixes</h3> <p>The issue that triggered the initial change was <a href="http://ironpython.codeplex.com/workitem/32374">#32374</a>. This is interesting in itself, as it turns out that <tt><a href="http://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.returnparameter(v=vs.95).aspx">MethodInfo.ReturnParameter</a></tt> is not supported on Windows Phone 7 – it <em>exists</em>, and it <em>compiles</em>, but it throws <tt>NotSupportException</tt>. Joy.</p> <p>Since mobile support was new, I figured that making a change specific to Windows Phone should be OK. And it probably would have been, had I done what I originally intended and put the new WP7 code in an <tt>#if</tt> block and left the original code intact. But instead I decided that if the new code worked for both, why not use it?</p> <h3>Static Typing is Not Enough</h3> <p>Notice how small <a href="https://github.com/IronLanguages/main/commit/4a764976adb8753a524b06d2926824850d97a491">the fix</a> is? <tt><a href="http://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.returntypecustomattributes.aspx">MethodInfo.ReturnTypeCustomAttributes</a></tt> returns an <tt><a href="http://msdn.microsoft.com/en-us/library/system.reflection.icustomattributeprovider.aspx">ICustomAttributeProvider</a></tt>, which has the <tt><a href="http://msdn.microsoft.com/en-us/library/system.reflection.icustomattributeprovider.isdefined.aspx">IsDefined</a></tt> method. As it turns out, <tt>MethodInfo</tt> also <em>implements</em> <tt>ICustomAttributeProvider</tt>. This means that the original fix compiled, ran, and worked for most cases, but failed on others. And they failed in the worst possible way – silently (except for the part where the program breaks).</p> <h3>But but but … TESTS!</h3> <p>Yes, the tests should have caught it. Unfortunately IronPython has been running for a while without paying much attention to the state of the tests, and there’s really no one to blame for this except me. Most of the CPython standard library tests fail at some point or another, which drowns out the useful failures in a sea of noise. This, of course, has to change, so for 2.7.3 I’m focusing on the much smaller set of tests specifically for IronPython (not those inherited from CPython).</p> <p>After this, there’s no way 2.7.3 is going out without at least that baseline set of tests green, and once I get them in order all new contributions will have to pass the relevant tests. This should be the only time that I have to do an emergency release.</p> <p>In the meantime, <a href="http://ironpython.codeplex.com/releases/view/74478">IronPython 2.7.2.1</a> is available, which fixes this issue.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-49693480376103018382011-12-17T13:33:00.001-07:002011-12-17T13:33:10.922-07:00Setting environment variables for MSBuild Exec tasks<p>MSBuild has an <a href="http://msdn.microsoft.com/en-us/library/x8zx72cd.aspx" target="_blank"><Exec> task</a> for calling external programs, but (bafflingly) it doesn’t allow you to set the environment the program runs in. In my case, I need to run a Python script with certain directories in the <tt>PYTHONPATH</tt>.</p> <h3>The Short Way</h3> <p>On Unix machines, this is trivial:</p><pre>PYTHONPATH=”~/foo” python script.py</pre>
<p>For Windows’ wonderful cmd.exe shell (which MSBuild uses to run Exec) it’s a little longer:</p><pre>(set PYTHONPATH=C:\Foo) & python script.py</pre>
<p>If you want, you can chain multiple set commands together to set multiple variables:</p><pre>(set PYTHONPATH=C:\Foo) & (set FOO=42) & python script.py</pre>
<p>To actually use this in the MSBuild file, you’ll need to escape it like so:</p><pre><Exec Command=”(set PYTHONPATH=C:\Foo) &amp; python script.py” /></pre>
<p>Getting the quoting right for <Exec> can be tricky; I use the <Message> task for debugging the command line. Remember to use <tt>&quot;</tt> instead of double quotes.</p>
<h3>The Long Way</h3>
<p>This method takes more typing but is a bit more clear, especially if you have multiple variables to set. Actually, it can be used to store whole batch files inside the MSBuild file, if necessary.</p><pre><PropertyGroup>
<PythonExec><![CDATA[
set PYTHONPATH=C:\Foo
set FOO=42
python script.py
]]></PythonExec>
</PropertyGroup>
<Exec Command="$(PythonExec)" />
</pre>
<p>A CDATA section is required because the newlines need to be preserved. When running an <Exec> task, all MSBuild does is write the contents of Command to a temporary batch file an execute. This just provides more than the usual single line command.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-29781733722049145182011-12-12T20:55:00.001-07:002011-12-12T20:55:19.164-07:00IronPython 2011 Survey<p>The IronPython team would like to know more about how IronPython is being used and what improvements people would like to see in 2012.</p> <p><a href="http://bit.ly/ipy-2011-survey" target="_blank">Take the IronPython 2011 survey!</a></p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-52020965337441768312011-06-12T14:25:00.001-06:002011-06-12T14:25:20.750-06:00NWSGI 2.1 Now Available<p>I’ve finally updated <a href="http://nwsgi.codeplex.com/">NWSGI</a> to use IronPython 2.7: <a href="http://nwsgi.codeplex.com/releases/view/33909">NWSGI 2.1</a>. The only other change is that NWSGI.dll will be added to the GAC by default by the installer.</p> <h3>NWSGI 3 Update</h3> <p>The big feature of NWSGI 3 is decoupling it from IIS and ASP.NET, which involved creating an abstraction layer for web servers (which is funny, because that’s what WSGI is). Shortly after I started that, the <a href="http://owin.org/">OWIN</a> project started, which has essentially the same goal. Since I hate duplicating effort, NWSGI 3 is on hold until OWIN stabilizes, which hopefully shouldn’t be too much longer.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-717248292978109592011-02-10T23:45:00.001-07:002011-02-11T11:14:42.275-07:00First IronPython Bug Weekend Coming Up<p>The first IronPython Bug Weekend is this weekend, February 12-13, 2011. The purpose of the bug weekend is to get as many issues as possible looked at and fixed before the next pre-release of 2.7. There are a large number of issues in the issue tracker that need to checked to see if they are still valid (based on what I've seen, probably half of them are already fixed). If they're not reproducible, they can be closed; if they are reproducible, then patches are always welcome!</p> <p>In particular, we'd like to get people who haven't contributed to IronPython before to chip in. It's really not that scary, I promise! To get started, check out <a href="http://ironpython.codeplex.com/wikipage?title=Respository%20Instructions&referringTitle=Home">how to get and build the source code</a> and <a href="http://ironpython.codeplex.com/wikipage?title=Contributing%20to%20IronPython&referringTitle=Home">how to handle issues</a>. If you have any questions, just ask – everyone is willing to help out.</p> <p>To get in touch with the other bug weekend participants, there are two primary channels: the mailing list (<a href="http://lists.ironpython.com/listinfo.cgi/users-ironpython.com">sign up</a>, <a href="http://lists.ironpython.com/pipermail/users-ironpython.com">view the archives</a>) and the #ironpython IRC channel on freenode.net. If you're looking at a particular bug, make an update to the <a href="https://spreadsheets.google.com/ccc?key=0AlhyN5J6eVpldEFlcEhETjlRRnB0TnZ2RDNBLTMzdlE&hl=en">Bug Weekend spreadsheet</a>, and make sure no one else is working on it either. It's a good idea to send a message on IRC or the mailing list as well.</p> <p>Here's to a good bug-fixing weekend!</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-9398037813062917132011-02-07T01:40:00.001-07:002011-02-07T01:40:01.587-07:00IronPython 2.7 Beta 2 Now Available<p>At long (long) last, the first community release of IronPython is now available – <a href="http://ironpython.codeplex.com/releases/view/60193">IronPython 2.7 Beta 2</a>. The highlights of this release are the new zlib (which also enables gzip) and subprocess modules. There have also been a number of bug fixes.</p> <p>Since Beta 1, we've moved all development to the Github <a href="https://github.com/IronLanguages/main">IronLanguages project</a>, although the <a href="http://ironpython.codeplex.com/workitem/list/basic">issue tracker</a> is still on CodePlex. This meant learning the build system, learning how to package a release (something that needs some work), and various other odds 'n ends. There are definitely some stumbling blocks that new people might trip over, so those should be taken care of as soon as possible.</p> <p>The next release is <a href="http://www.google.com/calendar/embed?src=i72rkrajdpshnj17rvmqatmp88%40group.calendar.google.com&ctz=America/Edmonton">scheduled for</a> February 20th. The first IronPython Bug Weekend is scheduled for February 12-13th; more on that coming soon.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-85997150878651912012010-11-23T08:00:00.000-07:002010-11-23T08:00:05.594-07:00Developing IronPython with Mercurial<p>While the informal poll of the IronPython community favoured <a href="http://mercurial.selenic.com/">Mercurial</a>, Miguel de Icaza had some good arguments for using github to develop IronPython and IronRuby (and I figured it was best to heed the advice of someone who's been running OSS projects since I was in elementary school). In particular, there was already an up-to-date git repo available.</p> <p>However! All is not lost, thanks to the wonderful <a href="http://hg-git.github.com/">hg-git</a> plugin. With it, you can push and pull from a git repository, but still use the Mercurial commands you know and love. To save everyone the hassle, though, I've set up a read-only mirror on bitbucket that is synchronized with the github repo. You can find it at <a href="http://bitbucket.org/ironpython/ironlanguages">http://bitbucket.org/ironpython/ironlanguages</a>.</p> <p>I assume you have some familiarity with Mercurial. If not, take a look at <a href="http://hginit.com/">Hg Init</a> and then give <a href="http://hgbook.red-bean.com/read/">the Mercurial book</a> a quick read to get a handle on the basic concepts.</p> <p>In this post I'll show how to work with the IronPython repository on bitbucket. In a later post, I'll cover how to work directly with the github repository as well as a more advanced use of bitbucket.</p> <h4>Initial Setup</h4> <p>Before doing anything else, you'll need the latest version of Mercurial. On Windows, I strongly recommend <a href="http://tortoisehg.bitbucket.org/">TortoiseHG</a> because it already includes almost everything you'll need.</p> <p>Now, make sure the following sections are in your <a href="http://www.selenic.com/mercurial/hgrc.5.html">Mercurial.ini</a> file:</p><pre>[extensions]
mq=
rebase=
bookmarks=
[diff]
git=1
</pre>
<p>While none of these are strictly required, the <a href="http://mercurial.selenic.com/wiki/BookmarksExtension">bookmarks extension</a> is needed if you want to work with git directly, and <a href="http://mercurial.selenic.com/wiki/RebaseExtension">rebase</a> and <a href="http://mercurial.selenic.com/wiki/MqExtension">mq</a> are just really nice to have. You'll want them later anyway, so you might as well turn them all on now. Git diffs are more useful than the unified diffs Mercurial generates by default, so turn those on as well.</p>
<h4><strong>Working With a Bitbucket Fork</strong></h4>
<p>To use bitbucket forks, you'll need a bitbucket account. If you don't already have one, go to <a href="http://bitbucket.org">bitbucket.org</a> and create an account. For all of the details on creating a fork, I'll just point at <a href="http://confluence.atlassian.com/display/BITBUCKET/Forking+a+Bitbucket+Repository">Bitbucket's own documentation</a>, which is very good. In short, go to <a href="http://bitbucket.org/ironpython/ironlanguages">http://bitbucket.org/ironpython/ironlanguages</a>, click on "fork", and give the fork a descriptive name and create it.</p>
<p>Now, create a clone of your fork:</p><pre>> hg clone <a href="https://yourname@bitbucket.org/yourname/yourfork">https://yourname@bitbucket.org/yourname/yourfork</a></pre>
<p>With your own fork you can push to it so that others can see your changes. However, pulling will (by default) pull from your fork, which <strong>is not</strong> automatically kept in sync with the original repository. To get any changes from the original repository, you'll need to pull from it directly:</p><pre>> hg pull --update <a href="http://bitbucket.org/ironpython/ironlanguages">http://bitbucket.org/ironpython/ironlanguages
</a></pre>
<p>To save a bit of typing, add an alias to the [paths] section of the <tt>.hg\hgrc file</tt> of your clone:</p><pre>[paths]
ironlanguages=http://bitbucket.org/ironpython/ironlanguages
</pre>
<p>And then you can do a pull from the alias instead of the URL:</p><pre>> hg pull --update ironlanguages</pre>
<p>You'll probably need to do a <a href="http://hgbook.red-bean.com/read/a-tour-of-mercurial-merging-work.html">merge</a> at this point. If you haven't pushed any changes publically, you could use <tt>hg rebase</tt> as well, but in this case I highly recommend using <tt>hg merge</tt> because it's safer. You should merge from upstream only as often as you need to, as too many merge commits can clutter the history. However, <strong>always</strong> merge in the upstream changes just before you send a pull request. It will make my life much easier.</p>
<p>Now you can use Mercurial as you normally would to track whatever changes you are making.</p>
<p>Once your changes are done, you'll need to send a pull request. First, if you haven't already, commit and push your changes to your fork:</p><pre>> hg commit
> hg push
</pre>
<p>Then, go to the original repository (<a href="http://bitbucket.org/ironpython/ironlanguages">http://bitbucket.org/ironpython/ironlanguages</a>), click "pull request", and enter a quick explanatory message. One of the IronPython coordinators (most likely me) will pull the request into our local repo, review it, and then push it to the main repo on github; this will trigger a synchronization, which will then pull your changes into the bitbucket mirror. Phew.</p>
<h4>Working Directly With the Bitbucket Mirror</h4>
<p>While using your own fork is highly recommended (because pull requests make integrating the changes very easy), you may want to work with the mirror repository directly. In particular, you don't need a bitbucket account to work with the mirror directly. However, the mirror is read-only, so if you choose to work this way, you'll need to submit patches (described below). For minor changes -- basically, a single commit -- this is fine, but for larger changes I strongly recommend using a fork or MQ, or it will make creating the patch extremely difficult.</p>
<p>First, clone the mirror repository:</p><pre>> hg clone <a href="http://bitbucket.org/ironpython/ironlanguages">http://bitbucket.org/ironpython/ironlanguages</a></pre>
<p>You can now use hg as usual to track your changes. I recommend using rebase to stay up to date, to keep the history free of merges:</p><pre>> hg pull --rebase</pre>
<blockquote>
<p><strong>Rebase Warning</strong></p>
<p>For the most part, the <a href="http://mercurial.selenic.com/wiki/RebaseProject">rebase extension</a> is safe to use, with one exception: <strong>do not</strong> use rebase on a repo that you've made public unless you want to break every other clone of that repo. The only time I recommend using it is when you <strong>only</strong> have a local clone, because it will make the resulting patches cleaner than repeated merges.</p>
<p>If you want rebase-like functionality that is safe to push publically, you should use <a href="http://hgbook.red-bean.com/read/managing-change-with-mercurial-queues.html">MQ</a>.</p></blockquote>
<p>When your changes are complete, you'll need to create a patch and submit it.</p>
<h4>Submitting a Patch</h4>
<p>First, either <a href="http://ironpython.codeplex.com/workitem/list/basic/">find the corresponding issue</a> that your patch is resolving or <a href="http://ironpython.codeplex.com/WorkItem/Create">create a new one</a>. Next, do an <tt>hg pull --rebase</tt> to make sure that you're up–to-date with the latest changes, which will make the patch easier to apply.</p>
<p>Now you need to determine which revisions are needed for the patch using <tt>hg log</tt>. Ideally, this is only the most recent revision (tip), or the last few revisions. Once you know what revisions comprise your changes, you can use <tt>hg export</tt> to create a patch (which can then be applied using <tt>hg import</tt> – funny, that).</p>
<p>If your fix is only the most recent commit, it's fairly easy:</p><pre>> hg export tip –-output 12345-fix-broken-foo.patch
</pre>
<p>When naming the patch file, please include the issue number and a very brief description in the name of the file.</p>
<p>If the patch has more than one commit, you'll need to <a href="http://www.selenic.com/mercurial/hg.1.html#specifying-multiple-revisions">specify the revisions</a> to export. In this example, we take all of the commits from revision 123 and to the tip:</p><pre>> hg export 123: –-output 12346-fix-broken-bar.patch</pre>
<p>If there are other revisions (such as merge commits) intermixed with work commits, it is still possible to produce a clean patch, but you'll need to use the <a href="http://www.selenic.com/mercurial/hg.1.html#specifying-revision-sets">full revision set query language</a> to do it. In that case you're probably better off creating a fork, merging it in, pushing to it, and sending a pull request.</p>
<p>Once the patch is created, attach it to the appropriate issue and someone should pick it up. If we miss it (sorry!), just send an email to <a href="http://ironpython.net/support/">the mailing list</a> to remind us.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-67523412470460415142010-10-31T08:59:00.001-06:002010-10-31T08:59:01.194-06:00Combining stdout, stderr, and pipes on Windows<p>This post is as much for my own reference as anyone else's. I need to capture the output of a program that outputs to both stdout and stderr in a file, but I also want it to display on the console so I can track its progress. The trick, of course, is to use <a href="http://en.wikipedia.org/wiki/Tee_(command)">tee</a> (in this case, from <a href="http://unxutils.sourceforge.net/">UnxUtils</a>). The only issue is how combine the streams, which cmd.exe is perfectly capable of doing, if you get the incantation correct:</p><pre>runtests.cmd 2>&1 | tee django-tests-201010301352.log</pre>
<p>What "2>&1" does is redirect stderr (2) into stdout (1), which is then piped into tee, which will write its input to the specified file as well as the console. With this, I can monitor the Django test runs while still keeping a log to review later.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-81526756227317947472010-10-29T08:00:00.001-06:002010-10-31T22:15:44.686-06:00Running the Django Test Suite on IronPythonI know, I know, <a href="http://jdhardy.blogspot.com/2010/01/running-django-test-suite-on-ironpython.html">I've written this post before</a>. However, it's a lot easier now than it was back then, and as a bonus it actually runs to completion! This is, by far, the best way to gauge the status of <a href="http://www.djangoproject.com/">Django</a> on <a href="http://ironpython.net/">IronPython</a>. Once the test suite passes (except for stuff that cannot be supported, like GeoDjango), then this project will be basically complete.<br />
<br />
There is one major hitch: <a href="http://docs.python.org/library/doctest.html">doctest</a>. Doctest is an interesting Python library that tests code by comparing it to expected output (by converting the result to a string). The problem is that certain constructs (especially dictionaries) will output differently in different implementation of Python. Thus, because Django relies on doctest, many tests would fail even though they were actually correct, just because the output was different. Thankfully, the Django project is working to get rid of doctest (I smile every time I see one of Alex Gaynor’s “we have always been at war with doctest” commits go in).<br />
<br />
I covered the setup of the environment in my post on <a href="http://jdhardy.blogspot.com/2010/10/running-django-tutorial-on-ironpython.html">running the Django tutorial on IronPython</a>, this may be familiar.<br />
<br />
First, you'll need to install IronPython. Using the latest (<a href="http://ironpython.codeplex.com/releases/view/48818">IronPython 2.7 Beta 1</a> as of this writing) is recommended. The MSI installer is best, but you can use the zip as well. You'll just need to remember where it's unpacked, as you'll need that path later.<br />
<br />
Next, you'll need to get Django/IronPython. Because Django requires some IronPython-specific patches, you'll need to download the entire source tree. To do this, you'll need <a href="http://mercurial.selenic.com/">Mercurial</a> (I recommend <a href="http://tortoisehg.bitbucket.org/">TortoiseHG</a>). Create an empty directory to work in, as well. I find Mercurial easier to work with from the command line, even with TortoiseHG installed, but you can do all of this from TortoiseHG as well. You’ll also need to enable <a href="http://mercurial.selenic.com/wiki/MqExtension">MQ</a> and, if you’re new to Mercurial, check out this <a href="http://confluence.atlassian.com/display/BITBUCKET/Getting+Started+with+Bitbucket">quick tour of bibucket</a> and this <a href="http://hginit.com/">great Mercurial tutorial</a>.<br />
<br />
To get the Django/IronPython sources, from your empty directory:<br />
<pre>> hg qclone <a href="http://bitbucket.org/jdhardy/django-ipy-patches">http://bitbucket.org/jdhardy/django-ipy-patches</a> django-ironpython
> pushd django-ironpython && hg qpush --all && popd
> hg clone <a href="http://jdhardy@bitbucket.org/jdhardy/django-ironpython-tests">http://bitbucket.org/jdhardy/django-ironpython-tests
</a>> cd django-ironpython-tests
</pre><br />
The first line pulls the sources from bitbucket into the 'django-ironpython' folder, the second line applies all of the Django/IronPython patches, and – <strong>here’s where it’s different from the tutorial!</strong> – the next-to-last line clones the <a href="http://bitbucket.org/jdhardy/django-ironpython-tests">django-ironpython-tests</a> repository, which contains a bunch of helpers for running the Django tests. The last line just switches to the django-ironpython-tests folder.<br />
<br />
Now you’ll need to open testenv.cmd in a text editor and possibly make some changes. In particular, change _ipy_root to point to your IronPython installation if you didn’t use the MSI installer.<br />
Now you can run the runtests.cmd file, which will run the entire Django test suite. There will be errors and failures, but the results are promising, with about 66% of the tests passing:<br />
<br />
<pre>Ran 2595 tests in 3022.324s
FAILED (failures=405, errors=468, skipped=16, expected failures=1)
</pre>jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-75623937907356463362010-10-28T08:05:00.000-06:002010-10-28T08:05:00.050-06:00The elephant in the room: source control for IronPython<p>Currently, IronPython is hosted in a TFS repository on CodePlex (<a href="http://ironpython.codeplex.com/)">http://ironpython.codeplex.com/)</a>, which was a copy of MS's internal TFS repository. CodePlex also provides Subversion access, which makes it much more bearable. CodePlex also hosts our issue tracking and wiki pages, which probably won't change any time soon. <p>IronRuby's source code is hosted on github (<a href="http://github.com/ironruby/ironruby)">http://github.com/ironruby/ironruby)</a>. It's also a copy of MS's internal TFS repository, but in git. <p>The interesting part is that IronRuby, IronPython, and the DLR are hosted in the *same* repository, since they evolved together. Thus, both the IronPython CodePlex repo and the IronRuby github repo are basically the same.<br></history-lesson> <p>What this is going to look like in the future is an open question, as is the timeline. Originally, I wanted to focus on the 2.7 release and deal with the source control question later. However, it's been raised in a few places, so I think it's better to get some more feedback on whether we should switch source control methods (and if so, to what?) or just stay on TFS/SVN for the time being. Also up for consideration is whether you consider being part of the same repo as IronRuby is valuable, or whether IronPython should split out on its own. <p>We could, for example, drop the source control from CodePlex and just use the IronRuby github repo - it's already set up and we could start developing tomorrow (although it would probably be renamed 'ironlanguages' or something like that). It's also probably the only option if IronPython and IronRuby are to share a repo, as, so far as I know, the IronRuby guys have no plans on leaving github, which makes sense for them - git is the de facto choice in the Ruby community. <p>In Python, however, it's not so clear-cut - Python itself will be moving to Mercurial soon, and there are plans afoot to eventually put the Python stdlib in a separate repo from Python itself, which will likely also be a Mercurial repository. Thus there are advantages (subrepos, in particular) to being on the same DVCS. On top of that, both Michael Foord and I strongly dislike git - I prefer Mercurial, and I imagine the coffee at Canonical will have Michael singing the praises of bzr fairly soon :). Finally, CodePlex supports Mercurial, and thus everything could remain there if we so wish. <p>However, converting the repo to Mercurial could be a difficult task - the fate of the 1.1, 2.0, and 2.6 branches would have to be decided (include them in the repo, or not? Their structure is radically different from the Main branch). There are folders that could very well be stripped (WiX, Ruby, and *3* CPython installations, not to mention IronRuby) to save space, and with a DVCS once they're in the history everyone has to pay that cost in disk space, forever, even if we later remove them. The fate of the DLR would need to be decided - do we keep a local copy, pull from IronRuby's copy, or make it a third repo altogether? <p>My preference is to stick with TFS/SVN for the time being, get 2.7 out the door (manually syncing up the DLR sources with IronRuby in the meantime), and then look at converting to Mercurial. My second choice would be to work out of IronRuby's git repository, get 2.7 released, and then look at converting to Mercurial. Anything that doesn't eventually involve Mercurial is a lot further down my list :). <p>I would like to see the DLR become a separate project, of which IronRuby and IronPython are just clients, along with IronJS, Clojure-CLR, and any others. I don't think the DLR will change too drastically, but the MS guys who are more familiar might have other plans, and Tomas has said he would prefer them to be together for ease of testing. <p>While the coordinators have discussed this already, I think we need more feedback to get an idea of what we should do, so <a href="http://lists.ironpython.com/pipermail/users-ironpython.com/2010-October/013921.html">please share your thoughts</a>. This has a direct bearing on how you will be contributing to IronPython.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-52879921896058578812010-10-28T08:00:00.001-06:002010-10-28T08:00:07.686-06:00The Road to 2.7 (Or: The Future of IronPython)<p>There have been a few people asking what they can contribute to IronPython. Right now, we need to identify what's not working in 2.7B1 that needs to be in 2.7 final. The best thing to do would be to identify any issues that are causing you pain and bring them up on the list. Then we can decide what meets the bar for a 2.7 release (with issues that have patches getting priority, of course!). Dino, are there any issues that you know are in 2.7B1 that must be fixed for 2.7 final? <p>Dino has provided some <a href="http://ironpython.codeplex.com/wikipage?title=Respository%20Instructions&referringTitle=Home">instructions on contributing to IronPython</a>. We need people to run through that and if there's anything it doesn't cover (I do intend to add subversion instructions directly at some point), and run the test suite as well. Also, doing all of that on Mono, to see what work needs to be done there. <p>Besides knowing what needs to be done, we need a rough timeline. I would like to see a release before the end of the year, or at least a solid release candidate with a possible release early next year. The idea behind an aggressive schedule is to focus on getting the features we have solid and not worry about adding new features or libraries (with the possible exception of zlib). That said, this all just my desires, and I really want to get an idea of what every one else is thinking. Please <a href="http://lists.ironpython.com/pipermail/users-ironpython.com/2010-October/013920.html">send feedback to the IronPython list</a> on what you want to see.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-61647389653821765012010-10-24T08:00:00.001-06:002010-11-19T12:08:47.069-07:00Running the Django Tutorial on IronPythonThe <a href="http://docs.djangoproject.com/en/1.2/intro/tutorial01/">Django tutorial</a> is fantastic. It's a great way to get a feel for Django, and a great test for how it will work on IronPython. Getting it working will give you pretty good idea of how to setup Django/IronPython for most things.<br />
First, you'll need to install IronPython. Using the latest (<a href="http://ironpython.codeplex.com/releases/view/48818">IronPython 2.7 Beta 1</a> as of this writing) is recommended. The MSI installer is best, but you can use the zip as well. You'll just need to remember where it's unpacked, as you'll need that path later.<br />
Next, you'll need to get Django/IronPython. Because Django requires some IronPython-specific patches, you'll need to download the entire source tree. To do this, you'll need <a href="http://mercurial.selenic.com/">Mercurial</a> (I recommend <a href="http://tortoisehg.bitbucket.org/">TortoiseHG</a>). Create an empty directory to work in, as well. I find Mercurial easier to work with from the command line, even with TortoiseHG installed, but you can do all of this from TortoiseHG as well. You’ll also need to enable <a href="http://mercurial.selenic.com/wiki/MqExtension">MQ</a> and, if you’re new to Mercurial, check out this <a href="http://confluence.atlassian.com/display/BITBUCKET/Getting+Started+with+Bitbucket">quick tour of bibucket</a> and this <a href="http://hginit.com/">great Mercurial tutorial</a>.<br />
To get the Django/IronPython sources, from your empty directory:<br />
<pre>> hg qclone <a href="http://bitbucket.org/jdhardy/django-ipy-patches">http://bitbucket.org/jdhardy/django-ipy-patches</a> django-ironpython
> pushd django-ironpython && hg qpush --all && popd
> md django-tutorial && cd django-tutorial
</pre>The first line pulls the sources from bitbucket into the 'django-ironpython' folder, the second line applies all of the Django/IronPython patches, and the last line creates a directory ('django-tutorial') to hold the tutorial files, and switches into it. If you're not already using the command line, open a command window and switch to the 'django-tutorial' directory.<br />
Now we need to set up some environment variables, which are a simple way to configure some settings for IronPython and Django. I usually copy these into a file called 'tutenv.cmd', which is easier than typing them each time (the variables are lost when the command window is closed):<br />
<pre class="cmd" name="code">@echo off
rem Get the folder this file is in
set _root=%~dp0
rem Add the IronPython installation paths to PATH; change these if you used
rem the .zip version of IronPython
set PATH=C:\Program Files\IronPython 2.7;C:\Program Files (x86)\IronPython 2.7;%PATH%
rem Add the django path and current paths to IronPython's search list
set IRONPYTHONPATH=%_root%..\django-ironpython;%_root%;%_root%deps
rem Tell Django when the its settings are
set DJANGO_SETTINGS_MODULE=mysite.settings
</pre>If you created a file, run it to set up the tutorial environment. Now, do a quick sanity check:<br />
<pre>> ipy
IronPython 2.7 Beta 1 (2.7.0.10) on .NET 4.0.30319.1
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> ^Z
</pre>If that doesn't work, you need to make sure that the PATH variable includes your IronPython installation, and that IRONPYTHONPATH includes the path to the 'django-ironpython' folder created back at the beginning of the post. <br />
Now we need to add in some dependencies (namely, sqlite and zlib support). These are in another bitbucket repository, <a href="http://bitbucket.org/jdhardy/django-ipy-tutorial-deps">django-ipy-tutorial-deps</a>:<br />
<pre>> hg clone <a href="http://bitbucket.org/jdhardy/django-ipy-tutorial-deps">http://bitbucket.org/jdhardy/django-ipy-tutorial-deps</a> deps</pre>Now you can start the tutorial. The first step, creating the project requires using django-admin.py; you can run it with IronPython like so:<br />
<pre>> ipy ..\django-ironpython\django\bin\django-admin.py startproject mysite</pre>Besides that, you can follow the tutorial almost exactly as written – just remember to substitute 'ipy' for 'python'! If you have any issues, please file them in the <a href="http://bitbucket.org/jdhardy/django-ipy-patches/issues">issue tracker</a>.jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-33713450917920281912010-10-22T00:33:00.001-06:002010-10-22T00:47:02.290-06:00Contributing to Django/IronPython<p>Since the new Django/IronPython repository (<a href="http://bitbucket.org/jdhardy/django-ipy-patches">django-ipy-patches</a>) is based on <a href="http://mercurial.selenic.com/wiki/MqExtension">MQ</a>, I thought I'd give a quick intro into what MQ is and how to work with it on <a href="http://bitbucket.org">bitbucket</a>. First off, MQ is short "Mercurial Queues". The queue, in this case, is a queue of patches to be applied to a repo that can be versioned separately from the repo itself. These patches live independent of the history and can be easily added and removed as changes are made. You can find a lot more detailed information in <a href="http://hgbook.red-bean.com/read/managing-change-with-mercurial-queues.html">the Mercurial book</a>.</p> <h4>Using Bitbucket</h4> <p>The initial setup is a bit weird, but it works quite well after that. First off, get <a href="http://mercurial.selenic.com/">Mercurial</a> – I prefer <a href="http://tortoisehg.bitbucket.org/">TortoiseHG</a>, myself. Next, get a bitbucket account. Finally, go to the <a href="https://bitbucket.org/jdhardy/django-ipy-patches">django-ipy-patches</a> page and click the "fork" button. You can name your fork whatever you want. Once it's created, make a note of the URL in the "hg clone" line. For this example, it's <a href="https://bitbucket.org/jdhardy/django-ipy-patches-test">https://bitbucket.org/jdhardy/django-ipy-patches-test</a>.</p> <p>Next, clone the django-trunk repository, but name it after your fork, and then switch to that directory:</p><pre>> hg clone <a href="http://bitbucket.org/jdhardy/django-ipy-patches-test">http://bitbucket.org/jdhardy/django-ipy-patches-test
</a>> cd django-ipy-patches-test</pre>
<p>Now, clone the fork you created earlier and pull in all of the patches. Note that we're pulling it into a specific directory (.hg\patches):</p><pre>> hg clone <a href="http://bitbucket.org/jdhardy/django-ipy-patches-test">http://bitbucket.org/jdhardy/django-ipy-patches-test</a> .hg\patches
> hg qpush --all
</pre>
<p>You can now use MQ to manage patches as usual.</p><pre>> hg qnew fix-1 -m "Fix issue #1"
> hg ci --mq
> hg push --mq
</pre>
<p>Now you can go back to the bitbucket page for your fork, click "pull request", and send me a request to pull your changes back into django-ipy-patches. Please do a pull from django-ipy-patches first to sync things up as much as possible.</p>
<h4>Without Bitbucket</h4>
<p>If you don't want to use bitbucket, you can get the django-ipy-patches queue directly:</p><pre>> hg qclone <a href="http://bitbucket.org/jdhardy/django-ipy-patches">http://bitbucket.org/jdhardy/django-ipy-patches</a></pre>
<p>Make your changes using MQ as usual, but instead of doing a push, export the changes instead:</p><pre>> hg log --mq
> hg export –mq –r ...</pre>
<p>The trick here is figuring out which changes you need to export using hg log and then export them. You should then post the bundle to the <a href="http://bitbucket.org/jdhardy/django-ipy-patches/issues">issue tracker</a>, and I'll apply it as soon as I can.</p>
<h4>MQ Shortcut</h4>
<p>You may have noticed that most of the normal hg commands take an --mq parameter that causes them to operate on the MQ repository instead of the actual repository. I use a simple batch file as a shortcut so that I can use `mq push` instead of `hg push --mq`:</p><pre>@hg %1 --mq %2 %3 %4 %5 %6 %7 %8 %9</pre>
<p>Put that line in a file named "mq.cmd" somewhere in your PATH and you can save yourself a little bit of typing.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-37968283953282914402010-10-21T17:10:00.000-06:002010-10-21T17:10:05.313-06:00The End of the BeginningWell, the shoe has finally dropped: <a href="http://blogs.msdn.com/b/jasonz/archive/2010/10/21/new-components-and-contributors-for-ironpython-and-ironruby.aspx">IronPython and IronRuby have been axed</a>. Jimmy Schementi <a href="http://blog.jimmy.schementi.com/2010/08/start-spreading-news-future-of-jimmy.html">spilled the beans</a> back in August, and despite <a href="http://jdhardy.blogspot.com/2010/08/fate-of-ironpython.html">my thoughts to the contrary</a>, the fate of the DLR team was already sealed. As best I can gather, the team was officially kaput on September 1st, or thereabouts. I found out in late September, and since then the former DLR team has been working to make the handoff as smooth as possible.<br />
<br />
As of today, myself, <a href="http://jimmy.schementi.com/">Jimmy Schementi</a>, <a href="http://www.voidspace.org.uk/">Michael Foord</a>, and <a href="http://tirania.org/blog/">Miguel de Icaza</a> have become the coordinators of the <a href="http://ironpython.net/">IronPython</a>, <a href="http://ironruby.net/">IronRuby</a>, and <a href="http://dlr.codeplex.com/">DLR</a> projects. Bill Chiles and <a href="http://blogs.msdn.com/b/dinoviehland/">Dino Viehland</a>, who worked on IronPython, will continue to work in an unofficial (i.e. spare time) role as well. Some of the old IronRuby team will probably continue to run the show over there as well. But officially, Microsoft is completely hands-off.<br />
<br />
<span class="Apple-style-span" style="font-size: x-large;">Why?</span><br />
<span class="Apple-style-span" style="font-weight: normal;">Why end one of the few teams that was actually doing something new and different and interesting at Microsoft? The official word is that it's because of "resource constraints" and "a shift in priorities". Now, I realize that even Microsoft has to choose where to spend their dollars, but I have a hard time believing that the half-dozen staff on the DLR team were that big a deal compared to the </span><span class="Apple-style-span" style="font-weight: normal;"><a href="http://twitter.com/scottgu/status/24369560605">200+ working on WPF and SL</a></span><span class="Apple-style-span" style="font-weight: normal;">, or the </span><span class="Apple-style-span" style="font-weight: normal;"><a href="http://arstechnica.com/microsoft/news/2010/07/a-post-mortem-of-kins-tragic-demise.ars">billion-dollar KIN debacle</a></span><span class="Apple-style-span" style="font-weight: normal;">. Maybe that's why I only make the small-to-medium dollars instead of the big bucks.</span><br />
<br />
It's also a bit mystifying that Microsoft would do this after promoting the <tt>dynamic</tt> keyword so heavily in .NET 4.0. That part of the DLR (the "inner ring") isn't going anywhere – it's in the .NET framework, which means it will be supported more or less forever. The hosting APIs, or the "outer ring", is now in the hands of the community. Hopefully the people working on projects like <a href="http://ironscheme.codeplex.com/">IronScheme</a>, <a href="http://ironjs.com/">IronJS</a>, and <a href="http://github.com/richhickey/clojure-clr">Clojure-CLR</a> will contribute what they want to see out of the DLR, although getting changes into the "inner ring" is likely to be impossible.<br />
<br />
<span class="Apple-style-span" style="font-size: x-large;">The Future</span><br />
I know there are companies and software using IronPython and (I believe) IronRuby in production: <a href="http://www.resolversystems.com/products/resolver-one/">Resolver One</a> is completely built around IronPython; it's built-in to <a href="http://umbraco.org/">Umbraco</a>; Jimmy has said that's its in use at <a href="http://lab49.com/">Lab49</a>. I hope that these companies will step up by offering some of their employees' time to help a project that they use. Other than that, there's at least a few Python programmers like myself who have to work in .NET, and hopefully they will also help out. The future of IronPython and IronRuby is entirely in the hands of those who use it, which is a new experience for those used to Microsoft calling all the shots.<br />
<br />
So what's next? As a group, we're still hashing that out. Now that the cat is out of the bag, we're going to involve the community as well. My goal is to get a production-ready IronPython 2.7 released before the end of the year. To do that, we'll need continuous integration infrastructure. After that, all sorts of decisions will need to be made, from boring stuff like managing infrastructure, to setting a roadmap for 3.2, to deciding what cool .NET stuff we want to include (such as LINQ support or static compilation).<br />
<br />
I want to see Django running on IronPython. I want to see the DLR be <strong>the</strong> system for embedding scripting into .NET applications, supporting a multitude of languages. I want the Iron* languages to become so popular that Microsoft regrets ever cutting them off. But I and other coordinators can't do it alone. We need help. We need people to contribute code, libraries, documentation - anything. From this point on, IronPython and IronRuby will live or die by their communities.<br />
<br />
Come join the mailing lists (<a href="http://ironpython.net/">IronPython</a>, <a href="http://rubyforge.org/mailman/listinfo/ironruby-core">IronRuby</a>) and help us decide where we are going to go from here. This isn't the beginning of the end. Far from it.jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-81933453465415185282010-10-20T15:55:00.001-06:002010-10-20T15:55:08.073-06:00Restarting Django/IronPython<p>Once again, I'm trying to work on Django/IronPython. This time around, I've finally found a workflow I'm happy with (for now) using <a href="http://mercurial.selenic.com/wiki/MqExtension">MQ</a>. Using MQ is a bit tricky to understand, but it has the distinct advantage that Django/IronPython patches are distinct from normal development and thus much easier to submit back to the Django project – which I also plan to start doing.</p> <p>Of course, the repo has changed again – it's now <a href="http://bitbucket.org/jdhardy/django-ipy-patches">django-ipy-patches</a>. It's a patch queue (which <a href="http://bitbucket.org/">bitbucket</a> handles quite nicely) instead of a fork because using a fork mixed the IronPython changes in with normal development and made them hard to find amongst all the merge changesets (and you can't rebase a public repository). Forks are better for very short-lived branches, but I think patch queues are the better option for long-lived projects like this. I'll move the issues from the old repository over and then shut it down fairly soon.</p> <p>I'll post some instructions soon on how to contribute and use MQ, and an update running the tests.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-59757345068594245432010-10-16T16:27:00.001-06:002010-10-16T16:27:29.708-06:00Using Extensions with a Custom IronPython Build<p>I tripped over this today – if you're using a custom build of IronPython (such as one built in debug mode), then any extensions have to be rebuilt against that build of IronPython.</p> <p>This occurs because the references in the extensions are against the official builds, which are signed (strong-named), but a custom IronPython build is not signed (or signed with a different key).</p> <p>Another option would be to build the extensions with a non-strong-named reference to IronPython, but I don't if this is possible or how to do it. If anyone else does, please let me know!</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-63572834648926741962010-10-16T08:00:00.000-06:002010-10-16T08:00:03.266-06:00Thoughts on Diversification<p>I recently watched <a href="http://blog.wekeroad.com/2010/06/21/i-smell-smoke">Rob Conery's talk from NDC2010</a> on his concerns about Microsoft. It's a good talk, and if you work with Microsoft tech at all (especially it it's your main technology, as it is mine), then you owe it to yourself to <a href="http://streaming.ndc2010.no/tcs/?id=D75877EB-3F20-4A9A-8B39-B016EE0419D5">watch it</a>.</p> <p>Done? Good.</p> <p>Rod describes the talk as 'incendiary'; I disagree. Personally, I didn't think anything in there was off the mark (although he should have left out his Twitter fight over Azure pricing, but whatever). He's right – Microsoft, overall, is not nearly as interesting as they used to be. He implores 'Microsoft developers' to look outside of Microsoft at what else is out there, and wants Microsoft to start pushing boundaries again.</p> <p>None of this is really a surprise to those of us who have always had a foot outside of the Microsoft world; hell, the only reason I got a foot <em>in</em> the Microsoft world is because it paid the bills. I've been a Python fan since the first time I saw it, 7 or 8 years ago; one of my co-op jobs in University was working for a (sadly, now defunct) company that integrated Jython into the management software for their hardware platform. Before that I taught myself C++ after cutting my teeth on QBasic. I used Java and Ruby in University courses; the OS of choice was mainly Linux.</p> <p>Knowing only one tech stack is extremely limiting and, honestly, foolish. <em>Focusing</em> on one is often a necessity dictated by needing to eat, but you should be keeping an eye on what other communities are doing, because you never know when it might be useful. It's truly unfortunate that many programmers didn't know about the beauty of functional programming until Microsoft introduced LINQ and F#; I've been using those techniques in Python for years and missed them horribly when working in pre-3.5 C#.</p> <p>This doesn't just apply to programming. Some people recommend learning one new programming language a year; I agree, almost. I think you should learn one new <em>skill</em> a year. Last year I built myself an office, doing all of the carpentry, drywall, and electrical myself (with a little help from friends and family, of course). This year I'm learning how to cook properly (and have developed an unhealthy obsession with <a href="http://www.foodnetwork.com/good-eats/index.html">Alton Brown</a>). Next year I plan to finally learn how to play the guitar and understand music theory (we'll see how that goes). Someday I hope to rebuild a car.</p> <p>Step outside your comfort zone. Learn something new. What you find just might surprise you.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-45507774462742999722010-09-12T15:51:00.002-06:002011-07-13T09:46:48.618-06:00Using Downloaded IronPython ModulesOne of Internet Explorer’s many “helpful” features is one that will “taint” any downloaded files as so that the system knows they are from the internet. Honestly, I can’t see what value this feature adds other than <a href="http://www.jeff.wilcox.name/2008/11/unblock-chms/">breaking CHM files</a>, and preventing IronPython from using downloaded modules.<br />
This was brought to my attention by <a href="http://www.ironshay.com/">Shay Friedman</a>, who was trying to use <a href="https://bitbucket.org/jdhardy/ironpythonzlib">IronPython.Zlib</a> but couldn’t get it to work. In particular, the error message was misleading:<br />
<pre>IronPython 2.6.1 (2.6.10920.0) on .NET 4.0.30319.1
Type "help", "copyright", "credits" or "license" for more information.
>>> import clr
>>> clr.AddReferenceToFileAndPath('C:\Users\Jeff\Downloads\IronPython.Zlib-2.6-clr4\IronPython.Zlib.dll')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: System.IO.IOException: file does not exist: C:\Users\Jeff\Downloads\IronPython.Zlib-2.6-clr4\IronPython.Zlib.dll
at Microsoft.Scripting.Actions.Calls.MethodCandidate.Caller.Call(Object[] args, Boolean& shouldOptimize)
...
>>></module></stdin></pre>The file, of course, does exist, so why can’t IronPython find it?<br />
There are actually a few things that interplay here: first, it must be downloaded with a browser that taints the file (which I believe are just IE and Chrome), and second, it must be unzipped with Windows’ built in unzipping tools. The built in tools have the interesting property that when unzipping a tainted zip file will also taint all of the unzipped files. Finally, the punchline: .NET will not load an assembly that is tainted.<br />
So how do we get around this? Well, you can:<br />
<ul><li>use a different browser</li>
<li>use a different unzipping tool (I highly recommend <a href="http://www.7-zip.org/">7-zip</a>)</li>
<li>unblock the zip file prior to unzipping</li>
</ul>To unblock the file, just right click on the zip file, click “Properties”, and click “Unblock”:<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpW597urwyefX7Hfybq4zu8G1I2n1JCib4lAYdUsoW3JCYNyhwjySAc3jPUHN57crGcbr0lkEiQnbcBmJg_J0tKgk81ML6Xv-y7RxZ3jafSDf46GTpxphbgyI1rqkUFulxRFWzuFxxtg/s1600-h/unblock-file%5B4%5D.png"><img alt="unblock-file" border="0" height="519" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKx2ZHGEi_jcDUSJBFV2xpHo0GXO-yMiargP3DLIfBSkbr3-TQ8_jKO7wJn2Yg2Zn6Ec5fH0zlPWmzNv8ZYSeQ3MwqjOkQZuofdNVceKSpgzcWQ_ZR7a2N96zx9qLGx2x9tG-myi1IyA/?imgmax=800" style="border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline;" title="unblock-file" width="414" /></a> <br />
If you’ve already unzipped the file, you can just unblock the DLL. Depending on where you unzipped the file to, you my need to use an elevated Explorer window. You can also <a href="http://www.elijahmanor.com/2009/09/recursively-unblock-assemblies-with.html">unblock multiple files from the command line.</a><br />
This may well affect applications other than IronPython, so it’s just one more thing to watch for.jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-47086397073883878952010-08-11T09:00:00.000-06:002010-08-11T09:00:00.519-06:00NWSGI 3.0 Plans<p>It looks like it's just about time for another major release of <a href="http://nwsgi.codeplex.com/" target="_blank">NWSGI</a> - the last two Decembers have had major releases, and I see no need to break the trend this year. There are going to be a few major changes this time around, so if anyone has any objections, let me know as soon as possible.</p> <p>Most importantly, it will only support IronPython 2.7 and thus will require .NET 4.0. Like the IronPython team, I'm not going out of my way to break compatibility with .NET 2.0 (or IronPython 2.6, for that matter), but I won't be distributing anything but IronPython 2.7/.NET 4.0 binaries.</p> <p>Similarly, I will not be supporting IIS 6 (Windows Server 2003) anymore. Again, I won't go out of my way to break it, but I won't be testing against it either. This means I can get rid of the wildcard handling for good, since IIS 7 has a good URL rewriter available.</p> <p>The biggest change is that I am decoupling the WSGI processing from the ASP.NET pipeline. All of the functionality is currently part of an IHttpHandler implementation, which restricts it to be used with IIS (and Cassini) only. NWSGI 3.0, on the other hand, will allow NWSGI to be used with <a href="http://msdn.microsoft.com/en-us/library/system.net.httplistener.aspx">HttpListener</a> or other servers such as <a href="http://kayakhttp.com/">Kayak</a> by moving all WSGI processing into a separate class with no ASP.NET dependencies. The redesign will also allow me to improve the test coverage from zero to, well, something.</p> <p>Finally, the licence will change to the <a href="http://www.apache.org/licenses/LICENSE-2.0.html">Apache Licence 2.0</a> to match IronPython. The basic terms are identical to the Ms-PL licence that was used previously; the Apache licence is just more explicit and also more widely used.</p> <p>As with the previous versions, I expect to release the final version shortly after IronPython 2.7 is released.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-7142619817250231032010-08-09T08:47:00.001-06:002010-08-09T09:57:56.070-06:00The fate of IronPython?It appears that <a href="http://blog.jimmy.schementi.com/2010/08/start-spreading-news-future-of-jimmy.html">Microsoft will not continue to fund IronRuby</a>. Hopefully it will continue to flourish as a community project; I wish them luck. This does raise the question of whether IronPython will meet the same "fate"; in the absence of word from the IronPython team (it is the weekend, after all), I think I'll indulge in some wild speculation.<br />
<br />
Mr. Schementi's last day at MS was July 23, meaning he probably gave his two weeks' notice an July 9. Thus, the writing was on the wall by the and of June/beginning of July. That's my rough timeline. But, something doesn't fit. <br />
<br />
On July 1, Enthought announced that they would be porting NumPy and SciPy to IronPython and .NET. I would imagine that they would have gotten some assurance from Microsoft that the IronPython project would continue. Or, they've gotten shafted - it happens. <br />
<br />
My hypothesis - that IronPython will continue to be funded, for now. The team has said that there are/were potential customers within Microsoft (the Dynamics team was one, I believe), which is critical for continued support. However, I believe there may be one other unexpected saviour - the Windows High-Performance Computing (HPC) team. <br />
<br />
Python is the scripting language of choice in the HPC community, largely because of the NumPy/SciPy libraries mentioned earlier. I wouldn't be surprised if Microsoft was making a push to get Windows and .NET deeper into that space (it's small but profitable), and IronPython with NumPY/SciPy support could be a key part of that play.<br />
<br />
Also, both teams had releases on July 16th – IronRuby 1.1 and IronPython 2.7 <strong>Alpha</strong> 1. I think that Alpha is an important signal of the team's expectations.<br />
<br />
This is what happens when I have insomnia. Hopefully this will still make sense in the morning.jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.comtag:blogger.com,1999:blog-597261753977781.post-59407612412308082112010-06-27T00:09:00.000-06:002010-06-27T00:10:11.908-06:00Changes to builds for IronPython.SQLite and IronPython.Zlib<p>I've done some work on the builds for both IronPython.SQLite and IronPython.ZLib; with IronPython 2.7 on the way, the number of variants I need to build is going up. IronPython 2.7 will require .NET 4.0, so that saves me having to build a IronPython 2.7/.NET 2.0 version of everything as well.</p> <p>Still, three variants is too many to build manually through Visual Studio, which is how I've built everything up to this point. The packaging into a zip file was also done manually. To save the effort, I've adopted <a href="http://github.com/JamesKovacs/psake">psake</a> as a build automation tool. It's based on PowerShell, which is a very nice administrative language (I actually prefer to Python for quick & dirty admin tasks – the horror!). The actually builds are still handled by MSBuild so that I can manage the files in Visual Studio; the psake script calls msbuild to build the library. I also have tasks to clean the source tree and build the .zip packages.</p> <h4></h4> <h4>The MSBuild Files</h4> <p>The real trick in this is building an .csproj file that can handle being built for both .NET 2.0 and .NET 4.0. The key to it all is the TargetFrameworkVersion property; by default, it is hardcoded to a specific .NET version (v2.0, v3.5, or v4.0) in the .csproj file. To change it during the build, msbuild needs to know that we might provide it on the command line. If you've ever opened a .csproj file, you make recognize these lines:</p> <pre class="xml" name="code"><Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform></pre>
<p>These lines will set the Configuration and Platform properties <em>if they are not already</em> set from the command line; that's what that Condition attribute does. We just need to do the same thing for the TargetFrameworkVersion property:</p>
<pre class="xml" name="code"><TargetFrameworkVersion Condition=" '$(TargetFrameworkVersion)' == '' ">v2.0</TargetFrameworkVersion></pre>
<p>This allows us to change the TargetFrameworkVersion from the command line. For a little future proofing, I add a property for the IronPython version as well:</p>
<pre class="xml" name="code"><IronPythonVersion Condition=" '$(IronPythonVersion)' == '' ">2.6</IronPythonVersion></pre>
<h4>The psake file</h4>
<p>The psake build script is (by convention) default.ps1; I would have preferred build.ps1, but whatever. The core task is the Build task; all it does is call MSBuild:</p>
<pre class="powershell" name="code">task Build -Depends GenVersion {
exec {
msbuild /nologo /verbosity:minimal "$ProjectPath" `
/t:Build `
/p:Configuration=$Configuration `
/p:TargetFrameworkVersion=$TargetFrameworkVersion `
/p:OutputPath="..\$OutputPath" `
/p:IronPythonVersion=$IronPythonVersion
}
}</pre>
<p>There are also tasks to build the zip files (requires <a href="http://www.7-zip.org/">7-zip</a> on the build system) and run the tests for the given project. All in all, using psake has been a great move, and while I have a few minor issues with it, I highly recommend it.</p>
<h4>Building the Damn Thing</h4>
<p>This is all well and good, but how do you actually use it to build it the library? Switch to the build directory, and, in a PwoerShell window, run:</p>
<pre class="cmd" name="code">.\psake</pre>
<p>That's it, if a default .NET 2.0 Debug build is what you want; it will also run the tests. To build a Release build for .NET 4:</p>
<pre class="cmd" name="code">.\psake build –framework 4.0 –parameters @{config='Release'}</pre>
<p>Finally, you can build the zip packages:</p>
<pre class="cmd" name="code">.\psake package</pre>
<p>It's all much simpler than firing up Visual Studio and building zip files by hand.</p>
<h4>Visual Studio 2010 Upgrade</h4>
<p>I've also upgraded the IronPython.SQLite and IronPython.Zlib solution files to Visual Studio 2010. You can use the free Express editions to build them. Also, none of these changes affect <a href="http://nwsgi.codeplex.com/" target="_blank">NWSGI</a>, yet.</p> jdhardyhttp://www.blogger.com/profile/00222070640958234371noreply@blogger.com