I’ve been working on a project that interacts with Microsoft Office SharePoint Server 2007 (MOSS 2007) for the last few months and one of the tools I’ve been using daily to support my work is IronPython. IronPython has made it easy for me to come up to speed quickly on the MOSS 2007 API but what has made my life even easier is the IronPython Console.
*Note: If you have a browser that supports Silverlight, you can try Python in your browser now.
IronPython ships with a console virtually identical to the stand Python console. The IronPython console provides me with a constant live connection directly to the API. It’s very different and somewhat empowering to transition from the standard workflow in Visual Studio of write code/build/run to something more like a conversation with the code. I think the term conversation is a very good analogy because it’s not just looking at classes and methods, it’s also data and interaction. It’s experiencing everything all at once!
Let’s take a look at what I’m talking about. To run these samples, I had IronPython 2.6.1 installed on a server running Windows Server 2003 and MOSS 2007.
When you first start up the console, you need to reference the Microsoft.SharePoint .dll. You SharePoint types probably know to find this in either the 12 Hive or the GAC.
>>> import clr >>> clr.AddReference("Microsoft.SharePoint")
We need to import the SPSite class before we use it too.
>>> from Microsoft.SharePoint import SPSiteNow we can create a connection to a site and open its default SPWeb object.
>>> site = SPSite(baseurl) >>> web = site.OpenWeb() >>> web
We can also navigate around the subwebs of a given web by using the Webs property. You can run into permissions issues though. Here we try to access the first subweb in the Webs collection.
>>> web.Webs[0] Traceback (most recent call last): File "", line 1, in SystemError: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENI ED))
To get around this error, we can just use the SystemAccount token attached to each site. I really don’t know the reason behind the design of this API, but you can use one site reference to give you a connection with elevated privileges on another site.
>>> temp = SPSite(baseurl) >>> site = SPSite(baseurl, temp.SystemAccount.UserToken) >>> web = base_site.OpenWeb()
Now you can start exploring around and seeing what exits. When you want to see
what members a given object has, you just use the dir() method. Let’s take a look at
the first object in the Lists collection.
>>> dir(base_web.Lists[0]) ['AddWorkflowAssociation', 'AlertTemplate', 'AllRolesForCurrentUser', 'AllowCont entTypes', 'AllowDeletion', 'AllowEveryoneViewItems', 'AllowMultiResponses', 'Al lowRssFeeds', 'AnonymousPermMask', 'AnonymousPermMask64', 'Audit', 'Author', 'Ba seTemplate', 'BaseType', 'BreakRoleInheritance', 'CanReceiveEmail', 'CheckPermis sions', 'CheckedOutFiles', 'ContentTypes', 'ContentTypesEnabled', 'Created', 'Cu rrentChangeToken', 'DefaultApprovalWorkflowId', 'DefaultContentApprovalWorkflowI d', 'DefaultItemOpen', 'DefaultView', 'DefaultViewUrl', 'Delete', 'Description', 'Direction', 'DocumentTemplateUrl', 'DoesUserHavePermissions', 'DraftVersionVis ibility', 'EffectiveBasePermissions', 'EffectiveFolderPermissions', 'EmailAlias' , 'EmailInsertsFolder', 'EnableAssignToEmail', 'EnableAttachments', 'EnableDeplo yWithDependentList', 'EnableDeployingList', 'EnableFolderCreation', 'EnableMinor Versions', 'EnableModeration', 'EnableSchemaCaching', 'EnableSyndication', 'Enab leVersioning', 'EnsurePropsFresh', 'EnsureRssSettings', 'Equals', 'EventReceiver s', 'EventSinkAssembly', 'EventSinkClass', 'EventSinkData', 'ExcludeFromTemplate ', 'Fields', 'FirstUniqueAncestor', 'Folders', 'ForceCheckout', 'Forms', 'GetCha nges', 'GetContentTypeIdByUrl', 'GetDefaultViewForContentType', 'GetDirectChildC ontentType', 'GetDistinctFieldValues', 'GetHashCode', 'GetItemById', 'GetItemByU niqueId', 'GetItems', 'GetItemsInFolder', 'GetPropertiesXmlForUncustomizedViews' , 'GetType', 'GetUncustomizedViewByBaseViewId', 'GetView', 'HasUniqueRoleAssignm ents', 'Hidden', 'ID', 'ImageUrl', 'IrmEnabled', 'IrmExpire', 'IrmReject', 'IsCa talog', 'IsContentTypeAllowed', 'ItemCount', 'Items', 'LastItemDeletedDate', 'La stItemModifiedDate', 'Lists', 'MajorVersionLimit', 'MajorWithMinorVersionsLimit' , 'MemberwiseClone', 'MobileDefaultViewUrl', 'MultipleDataList', 'NoCrawl', 'OnQ uickLaunch', 'Ordered', 'ParentWeb', 'ParentWebUrl', 'Permissions', 'PropertiesX ml', 'ReadSecurity', 'Recycle', 'ReferenceEquals', 'RemoveWorkflowAssociation', 'RenderAsHtml', 'RequestAccessEnabled', 'ResetRoleInheritance', 'RestrictedTempl ateList', 'ReusableAcl', 'RoleAssignments', 'RootFolder', 'SaveAsTemplate', 'Sch emaXml', 'SendToLocationName', 'SendToLocationUrl', 'ServerRelativeDocumentTempl ateUrl', 'ServerTemplateCanCreateFolders', 'ServerTemplateCanReceiveEmail', 'Set AttributesForPropertiesXML', 'ShowUser', 'TemplateFeatureId', 'Title', 'ToString ', 'Update', 'UpdateWorkflowAssociation', 'Version', 'Views', 'WorkflowAssociati ons', 'WriteRssFeed', 'WriteSecurity', '__class__', '__delattr__', '__doc__', '_ _format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclas shook__', 'm_ListAttributesDict', 'm_Lists', 'm_Permissions', 'm_arrListProps', 'm_iRow']
Now this may or may not be readable to you. Alot of times when there’s a ton of text to deal with in the console, I’ll iterate through the methods and print them each on their own line.
>>> for method in dir(base_web.Lists[0]): ... print method ... AddWorkflowAssociation AlertTemplate AllRolesForCurrentUser AllowContentTypes AllowDeletion AllowEveryoneViewItems .... [Omitted to save space] __class__ __delattr__ __doc__ __format__ __getattribute__ __hash__ __init__ __new__ __reduce__ __reduce_ex__ __repr__ __setattr__ __sizeof__ __str__ __subclasshook__ m_ListAttributesDict m_Lists m_Permissions m_arrListProps m_iRow
You can inspect classes too. You don’t need an instance. If you inspect the class you’ll just need to import the type first.
>>> for method in dir(SPListCollection): ... print method ... Traceback (most recent call last): NameError: name 'SPListCollection' is not defined >>> from Microsoft.SharePoint import SPListCollection >>> for method in dir(SPListCollection): ... print method ... Add CopyTo ... [Omitted to save space] __add__ __class__ __delattr__ __doc__ __format__ __getattribute__ __getitem__ __hash__ __init__ __iter__ __len__ __new__ __reduce__ __reduce_ex__ __repr__ __setattr__ __sizeof__ __str__ __subclasshook__
If you’re coming from a C# or VB background, you’re probably familiar with the “Using” block. Python has something similar to that with the “with” statement. The with statement is used with ContextManagers. Many of the .Net framework classes support the ContextManager methods so you can use the with statement. You can see the __enter__ and __exit__ methods below that help make this possible.
>>> dir(SPSite) ['AddWorkItem', 'AllWebs', ...[Omitted for space], '__class__', '__delattr__', '__doc__', '__enter__ ', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__new_ _', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__s tr__', '__subclasshook__']
Now we can refactor our earlier sample to use the with statement. This is something I use more in scripts that reference MOSS 2007, but I thought you may find some uses.
>>> web = None >>> with SPSite(baseurl) as temp: ... with SPSite(baseurl, temp.SystemAccount.UserToken) as site: ... web = site.OpenWeb() ...
It’s all pretty basic and the console lends itself well to those who like to explore. I really like this method versus digging around the object browser or Reflector all of the time. I like the instant feedback when exploring and the ability to see data and not just structure. I’ve also successfully used IronPython to create custom event handlers and for some administrative tasks for a 2003 to 2007 upgrade. I highly recommend you try it if you find yourself having to do any development using the SharePoint API.
