I found a post in one of the Google groups (linked at the bottom) that discussed it but was either somewhat wrong or just out of date.
So the following worked for me:
The following was done with the standard Python 2.5 install for OS X, along with the AppEngine SDK for OS X.
It turns out that in addition to the imports I was using for my code I needed:
from google.appengine.api import apiproxy_stub_map from google.appengine.api import datastore_file_stub from google.appengine.api import mail_stub from google.appengine.api import urlfetch_stub from google.appengine.api import user_service_stub
I also had to adjust the python path so I could get my unit tests to run outside of the dev_appserver instance.
export PYTHONPATH=/usr/local/google_appengine/:/usr/local/google_appengine/lib/django/:/usr/local/google_appengine/lib/webob/:/usr/local/google_appengine/lib/yaml/lib/
Keep in mind that the export above would be needed to be explicitly added to any startup scripts you’re using in order for it to be persistent.
Then the, hopefully, obvious import:
import unittest
Then there’s the step of setting up the environment for each test to run my setUp method follows:
def setUp(self): # Ensure we're in UTC. os.environ['TZ'] = 'UTC' time.tzset() # Start with a fresh api proxy. apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap() # Use a fresh stub datastore. stub = datastore_file_stub.DatastoreFileStub(APP_ID, '/dev/null', '/dev/null') apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', stub) # Use a fresh stub UserService. apiproxy_stub_map.apiproxy.RegisterStub('user', user_service_stub.UserServiceStub()) os.environ['AUTH_DOMAIN'] = AUTH_DOMAIN os.environ['USER_EMAIL'] = LOGGED_IN_USER # Use a fresh urlfetch stub. apiproxy_stub_map.apiproxy.RegisterStub('urlfetch', urlfetch_stub.URLFetchServiceStub()) # Use a fresh mail stub. apiproxy_stub_map.apiproxy.RegisterStub('mail', mail_stub.MailServiceStub()) self.current_user = users.get_current_user()
The setup method was borrowed from this groups post
]]>def timeThis startTime = Time.now() yield endTime = Time.now() endTime.to_f() - startTime.to_f() end puts(timeThis{sleep(0.25)})
Displays (standard out)0.25
]]>// Used to store the matched node, if found. var _jsMatchedNode; function jsFindChildByName(pvNodeName, pvParent) { if (pvParent.nodeName.toLowerCase() == pvNodeName.toLowerCase()) { _jsMatchedNode = pvParent; return; } if (!pvParent.childNodes) return; if (pvParent.childNodes.length == 0) return; var nodeList = pvParent.childNodes; for(var x=0;x<nodeList.length;x++) { jsFindChildByName(pvNodeName, nodeList[x]); } }
Of course if you use this repeatedly it would behoove you to reset the _jsMatchedNode variable before each use.
]]>See:
Do you use Page.DataBind?
Avoid calling Page.DataBind and bind each control individually to optimize your data binding. Calling Page.DataBind recursively calls DataBind on each control on the page.
You’re best bet is to override DataBind and call base.DataBind()
]]>From the 1.2 language spec:
The new operator automatically initializes the elements of an array to their default value, which, for example, is zero for all numeric types and null for all reference types.
Important notes about Array.Initialize()
It must not be used on reference-type arrays.
…
You can use this method only on value types that have constructors; however, value types that are native to C# do not have constructors.
And of course, if you don’t trust me, see for yourself.
]]>public static List<telement> Interleave<telement>(params List<telement>[] pvParamLists) { // if nothing is provided we'll simply return an empty list if (pvParamLists == null) return new List<telement>(); int listCount = pvParamLists.Length; // offset map indicating current position in a given list int[] pointerMap = new int[listCount]; // count total elements int resultSize = 0; foreach(List<telement> list in pvParamLists) { if (list != null) { resultSize += list.Count; } } // create our result list List<telement> interleavedList = new List<telement>(resultSize); // will quit when finished while (interleavedList.Count < resultSize) { for (int x = 0; x < listCount; x++) { if (pointerMap[x] != -1) { List<telement> currentList = pvParamLists[x]; // skip null or empty lists if ((currentList == null) || (currentList.Count == 0) || (pointerMap[x] >= currentList.Count)) { pointerMap[x] = -1; continue; } interleavedList.Add(currentList[pointerMap[x]++]); } } } return interleavedList; }
The whole file, including some unit tests is here.
]]>public static Object XmlSerializationCopy(Object pvValue) { if (pvValue == null) return null; XmlSerializer ser = new XmlSerializer(pvValue.GetType()); // most are probably small. MemoryStream serStream = new MemoryStream(512); using(serStream) { ser.Serialize(serStream, pvValue); serStream.Position = 0; return ser.Deserialize(serStream); } }
Here is where it is called out.
Specifically:
When writing to a file, the last write time is not fully updated until all handles used for writing have been closed. Therefore, to ensure an accurate last write time, close the file handle immediately after writing to the file.
The part that is extra sucky is that this update of the Last Write Time does seem to take place on local files (not accessed via a remote UNC path), that is the Last Write Time does seem to change on local files even while the stream changing it is still open.
]]>The XmlSerializer can serialize an object to a stream, any stream. If the stream you are searializing your object to already contains data, and the length of that data is longer than the length of the data you are currently writing (your about-to-be serialized object) you get artifacts.
This is to say that if you open a stream without clearing it in some manner, and then write less data than what was already there…. You get your new data at the begining, and leftovers from what was there before at the end.
So in the case of serializing to a file, the easiest thing to do is use a StreamWriter and provide the path of the file to which you wish to write. The StreamWriter overwrites any existing file for you by default.
As per msdn documentation:
StreamWriter Constructor (String)
The path parameter can be a file name, including a file on a Universal Naming Convention (UNC) share. If the file exists, it is overwritten; otherwise, a new file is created.