четверг, 22 июля 2010 г.

Python: How to check syntax before run script

В очередной раз опечатался в названии переменной в питоне и пришлось повторять пробный запуск скрипта. Опечатки - ошибки детские, но требуют много времени на отладку. А в случаях кода, который редко выполняется, например обработка ошибок, опечатка может вылезти в самый неподходящий момент.
Решения два, правильное - писать тесты покрывающие всё и вся, ну или чем то проверять синтаксис. Проверка синтаксиса не помешает даже при наличии тестов, т.к. выполняется очень быстро и не требует, специальных телодвижений.

Мне понравился модуль Pyflakes. Всё очень просто и лаконично.

Вот в таком коде:
import unusedlib

def func():
 res = unused * 5 
 return res

находит:
test.py:2: 'unusedlib' imported but unused
test.py:5: undefined name 'unused'


Меня очень даже устраивает.

понедельник, 19 июля 2010 г.

SharePoint and PowerShell: How to delete all empty lists

Решил я попрактиковаться в PowerShell'е и в качестве темы для экспериментов взял просьбу одного пользователя удалить пустые листы на всех подсайтах одного сайта:

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

function Get-SPAllSubWebs($web)
{
 Write-Output $web;
 foreach($w in $web.Webs)
 {
  Get-SPAllSubWebs($w);
  $w.Dispose();
 }
}

$url = "http://server/myroot"
$site = new-Object Microsoft.SharePoint.SPSite($url)

Get-SPAllSubWebs $site.OpenWeb() | 
  foreach { $_.Lists} |
   where {$_.ItemCount -eq 0 -and  $_.Hidden -eq 0 -and $_.AllowDeletion -eq 1 } |
    foreach { Write-host $_.RootFolder.ServerRelativeUrl , $_.Delete()}


PS: Для пробы можете убрать строчку , $_.Delete() чтобы отключить реальное удаление

понедельник, 12 июля 2010 г.

SharePoint 2010 CSOM: How to set MultiLookUp field values

Господа из микрософта почему то не оттопырили в клиентской модели тип SPFieldLookupValueCollection, и я уж было подумал что установить множество значении для таких полей используя клиентскую модель нельзя. Но великий рефлектор показал мне в серверной модели вот такое вот объявление:

  1. [Serializable, SharePointPermission(SecurityAction.LinkDemand, ObjectModel=true), SharePointPermission(SecurityAction.InheritanceDemand, ObjectModel=true)]
  2. public class SPFieldLookupValueCollection : List<SPFieldLookupValue>, ISerializable
  3. {
  4.     // Fields
  5.     private const string delimiter = ";#";
  6.  
  7.     // Methods
  8.     public SPFieldLookupValueCollection();
  9.     public SPFieldLookupValueCollection(string fieldValue);
  10.     protected SPFieldLookupValueCollection(SerializationInfo info, StreamingContext context);
  11.     [SharePointPermission(SecurityAction.Demand, ObjectModel=true), SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
  12.     public virtual void GetObjectData(SerializationInfo info, StreamingContext context);
  13.     [SharePointPermission(SecurityAction.Demand, ObjectModel=true)]
  14.     public override string ToString();
  15. }
  16.  
  17.  

Ну я и подумал что прокатит самодельный лист из FieldLookupValue и это работает.

  1. using (var clientContext = new ClientContext(@"http://server"))
  2. {
  3.     var web = clientContext.Web;
  4.     var lst = web.Lists.GetByTitle("LookUp1");
  5.  
  6.     var fld = lst.Fields.GetByInternalNameOrTitle("TiListField");
  7.     clientContext.Load(fld, f => f.SchemaXml);
  8.     clientContext.ExecuteQuery();
  9.  
  10.     var lci = new ListItemCreationInformation();
  11.  
  12.     lci.FolderUrl = @"/Lists/LookUp1";
  13.     lci.UnderlyingObjectType = FileSystemObjectType.File;
  14.  
  15.     List<FieldLookupValue> vals = new List<FieldLookupValue>();
  16.  
  17.     var l1 = new FieldLookupValue();
  18.     l1.LookupId = 1;
  19.     vals.Add(l1);
  20.     var l2 = new FieldLookupValue();
  21.     l2.LookupId = 2;
  22.     vals.Add(l2);
  23.     var l3 = new FieldLookupValue();
  24.     l3.LookupId = 3;
  25.     vals.Add(l3);
  26.  
  27.     var item = lst.AddItem(lci);
  28.  
  29.     item["Title"] = "test";
  30.     item["TiListField"] = vals;
  31.     item.Update();
  32.     clientContext.Load(item);
  33.     clientContext.ExecuteQuery();
  34. }
  35.  

вторник, 6 июля 2010 г.

SharePoint 2007: LookUp site collumn

Сегодня сделал для себя небольшое открытие связанное с SharePoint 2007. Всем, думаю, известно что LookUp поля в SharePoint листах могут указывать лишь на листы находящиеся на том же уровне (на том же сайте). Оказывается из этого правила есть исключения. На сайте верхнего уровня можно создать Сайтовую Колонку ,указывающую на лист в саите этого самого верхнего уровня, и при этом, если использовать эту колонку в подсайтах она будет прекрасно лукапится на тот самый сайт на верхнем уровне.
Секрет кроется в том что для лукапов можно указывать атрибут WebId в схеме.
Из этого следует то что при должном умении можно создавать лукапные поля на любой сайт, просто изменяя схему листа.

  1. <Field
  2. Type="Lookup" DisplayName="SuperSiteLookUp" Required="FALSE"
  3. List="{9f471bab-8847-4fab-8fef-8f9f4eb4260f}"
  4. WebId="2cb19ced-0834-4e5d-ba7f-7bfae1450254"
  5. ShowField="Title"
  6. UnlimitedLengthInDocumentLibrary="FALSE"
  7. Group="Custom Columns"
  8. ID="{75a1689c-2c09-40e6-ba3d-2224751a3e51}"
  9. SourceID="{2cb19ced-0834-4e5d-ba7f-7bfae1450254}"
  10. StaticName="SuperSiteLookUp"
  11. Name="SuperSiteLookUp" ColName="int2" RowOrdinal="0" />

четверг, 1 июля 2010 г.

SharePoint 2010 CSOM: ServerException - Item does not exist. It may have been deleted by another user.

Оказывается если при работе с клиентской моделью между вызовами AddItem() и Update() для item'а произойдет вызов ExecuteQuery() то вылетит "ServerException - Item does not exist. It may have been deleted by another user."

Столкнулся с этим когда при создании Item мне потребовалось заполнить поля на основании уже существующей информации. Вариантов решения я вижу два, либо сразу после AddItem() делать Update() (это может привести к проблемам с некоторыми типами листов , например с Disucssion), либо получать все необходимое перед созданием.

Примерчик вызывающий ошибку:
using (var clientContext = new ClientContext(@"http://server"))
{
    var lst = clientContext.Web.Lists.GetByTitle("Tasks");

    var lci = new ListItemCreationInformation();
    lci.UnderlyingObjectType = FileSystemObjectType.File;
    var it = lst.AddItem(lci);
    //it1.Update(); 
    clientContext.Load(it);
    clientContext.ExecuteQuery();

    it["Title"] = "check1";

    it.Update();
    clientContext.ExecuteQuery();

    Console.WriteLine(it.Id);
}