Пишем клиента для OData на Python

Open Data Protocol

Что это такое и для чего создан очень хорошо рассказано в этом видео: http://www.msteched.com/2010/NorthAmerica/DEV208

Python

Одним из аргументов в пользу OData звучит то, что данный протокол не зависит от платформы, и это очевидно (AtomPub), а так же не привязан к конкретному вендору. Но всё же я решил набросать небольшой пример, в котором эмулировать привычный .NET API для работы с OData

Lets code it

import odata

url = "http://odata.netflix.com/Catalog/"

service = odata.service(url)

service.Languages

languages = service.execute()

print languages

Давайте разбираться, что же написано выше.

http://odata.netflix.com/Catalog/ - netflix является одним из официальных поставщиков OData

Итак, мы импортируем наш модуль OData, который мы реализуем чуть позже, далее создаем сервис, для получения данных и читаем какие языки будет предоставлять нам netflix.

odata.py

import urllib2
import feedparser

version = '0.1'

feedparser — не входит в набор стандартных библиотек python, поэтому её надо будет скачать и установить, как видно из нахвания библиотека предоставляет гибкий API для доступа к различным лентам данных, а следовательно отлично подходит для нашей будущей реализации

class service(interceptor):
    def __init__(self, url):
        self.url = url

Реализация класса service (фактически data-proxy), который будет основной точкой доступа для работы с данными.

Очевидно, что для запроса Languages, это свойство должно присутствовать в нашей реализации, но так же не менее очевидно, что каждая реализация OData ленты может предоставлять свои собственные данные, в связи с этим мы реализуем некоторый механизм формирования запросов на основе полученных от пользователя вызовах.

Внимательный читатель мог заметить, что service наследует от некоторого класса interceptor, вот он:

class interceptor(object):
    def __getattribute__(self, name):
        try:
            return object.__getattribute__(self, name)
        except:
            self.property = name

Из реализации видно, что наш класс занимается тем, что отлавливает вызов несуществующих свойств, к примеру наш Languages и записывает последний в поле property.

Следующей итерацией необходимо имплементировать вызов метода получения данных execute()

class service(interceptor):
    def __init__(self, url):
        self.url = url

    def execute(self):
        proc_url = self.url + "/" + self.property
        result = feedparser.parse(proc_url)
        for entry in result.entries: print entry.title

В данном методе мы формируем url-строку для запроса ленты данных, в последствии пробегаемся по результату и выводим значения клиенту.

Это лишь начальная стадия реализации, многие вопросы не учтены (фильтрация данных, построение запросов и прочее), однако данный пример наглядно указывает на общеупотребимость Open Data Protocol в повседневных нуждах разработки.

Что почитать

Adventures in Meta programming in Python: im_class, __import__, __getattribute__ http://www.lostechies.com/blogs/rssvihla/archive/2010/01/08/adventures-in-meta-programming-in-python-im-class-import-getattribute.aspx

Introducing a Ruby OData Client Library http://blogs.visoftinc.com/archive/2010/06/12/Introducing-a-Ruby-OData-Client-Library.aspx

LINQPad теперь тоже понимает OData http://www.linqpad.net/Beta.aspx

Создание OData API для StackOverflow включая XML и JSON за 30 минут http://blog.zzlab.ru/perevod/sozdanie-odata-api-dlya-stackoverflow-vklyuchaya-xml-i-json-za-30-minut.html

Что такое API данных Google? http://code.google.com/intl/ru-RU/apis/gdata/


REPL WebPart для SharePoint

Intro

logoСегодня я расскажу о прототипе первого компонента под ярлычком Sapphire. Это REPL WebPart. Эта веб-часть предназначенная для производства оперативных изменений на серверной стороне SharePoint, так же для удаленного исполнения скриптов и тестирования некоторых кусков кода.

PreBody

Производство данной веб-части было инициированно в довольно таки частых потребностях исполнения серверного кода с достаточной оперативностью, в недоступности средств разработки под рукой.

Здесь есть небольшая презетнация, в которой я постарался отобразить принципы работы Repl WebPart:

В добавок к слайдам расскажу о том, что веб-часть представляет собой классический хостинг Dynamic Languages Runtime языков, пока из которых доступен только Python.

Body

Далее хотелось поговорить о том, как же всё это у меня получилось, итак проект включает в себе несколько основных модулей:

  • Веб-часть и контролы представления
  • Хостинг языков

Далее о них поподробнее

Language Hosting

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

  public interface ILanguagesFactory
  {
    ILanguage Create(string name);
  }

  public interface ILanguage
  {
    string Name { get}

    object Execute(string input);

    void SetVar(string name, object value);
    
    object GetVar(string name);
  }

Отлично, далее к нашему проекту присоединяются сборки, необходимые для имплементации скриптовых языков:

Всё готово для того, чтобы реализовать Python, как среду для исполнения кода, отлично, приступим:

  public class PythonLanguage : ILanguage
  {
    private readonly ScriptScope _scope;
    
    public string Name
    {
      get { return «Python»}
    }

    public PythonLanguage()
    {
      _scope = Python.CreateEngine().CreateScope();
    }

    public object Execute(string input)
    {
      ScriptSource source = _scope.Engine.CreateScriptSourceFromString(input);
      return source.Execute(_scope);
    }
  }

Далее немного усложним задачу, в связи с тем, что нам будет необходимо реализовать контекст для работы с SharePoint, выглядеть это должно примерно так:

    [Test]
    private void python_should_assume_sharepoint_variables()
    {
      SPWeb fakeWeb = Isolate.Fake.Instance<SPWeb>();
      Isolate.WhenCalled(() => fakeWeb.Title).WillReturn(«I’m fake web»);
      var python = _factory.Create(«Python»);
      python.SetVar(«__x__»«123»);
      python.SetVar(«__web__», fakeWeb);
      python.Execute(«__x__ = __web__.Title»);
      var x = (string)python.GetVar(«__x__»);
      Assert.AreEqual(x, «I’m fake web»);
    }

Для работы с объектами SharePoint в из IronPython, нам необходимо добавить несколько библиотек:

      _scope.Engine.Runtime.LoadAssembly(typeof(string).Assembly);
      _scope.Engine.Runtime.LoadAssembly(typeof(Uri).Assembly);
      _scope.Engine.Runtime.LoadAssembly(typeof(SPList).Assembly); 

Это будет основой нашей работы с динамическими языками

WebPart + WebControls

Создадим проект с помощью SPVisualDev, добавим в него feature, внутри которой создадим веб-часть Repl WebPart, всё остальные действия стандартные, однако есть небольшой нюанс, нам нужен будет объект, с помощью которого можно будет выводить строковые значения после исполнения. Я решил создать для этих целей объект с классическим названием Console, его реализация предельна проста:

  public class Console
  {
    private readonly StringBuilder _messageBuilder = new StringBuilder();

    public void Write(object message)
    {
      _messageBuilder.Append(message);
    }

    public void WriteLine(object message)
    {
      _messageBuilder.AppendLine(message.ToString());
    }

    public string Message
    {
      get
      {
        return _messageBuilder.ToString();
      }
    }
  }

Мы будем передавать его в среду исполнения языков, а после исполнения кода опрашивать его свойство Message и выводить его содержимое в нашу веб-часть.

EndBody

Все исходники проекта доступны на github: http://github.com/butaji/Sapphire

Так же предварительную версию Sapphire.Environment (решение поставляется в WSP) можно слить на CodePlex: http://sapphire.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=34895


Habrahabr, Live Writer и Code Highlighting

Интро

Уже практически полгода я пользуюсь Windows Live Writer в качестве инструмента для написания веб-ориентированных статей. Это отличный инструмент, работающий с большим количеством blogengine’ов, и даже с SharePoint. Но разговор не об этом, в связи с тем, что я разработчик, мне частенько приходится вставлять листинг кода в написанные статьи, на это я и хочу обратить ваше внимание.

Пигменты

Многие представители Python-сообщества наверняка знакомы с дивным проектом под названием Pygments:

Ну так вот, товарищ Harry Pierson (@DevHawk) скомпилировал этот движок под IronPython и написал обертку-плагин для Windows Live Writer (качать здесь не торопиться). Отлично, однако то, что получается в результате его обработки не выделяется цветом на habrahabr, это связанно с некоторыми особенностями ресурса, однако поправимо.

Данными работами я и предлагаю заняться, для этого нам понадобятся:

После того, как мы скачали исходники, стоит разыскать скрипт под именем pygments_package\devhawk_formatter.py и немного его подкоректировать:

            # a style item is a tuple in the following form:
            # colors are readily specified in hex: ’RRGGBB’
            if style[‘color’]:
                start += ‘<span style=»color:#%s«>’ % style[‘color’]
                end = ‘</span>’ + end

заменить на

            # a style item is a tuple in the following form:
            # colors are readily specified in hex: ’RRGGBB’
            if style[‘color’]:
                start += ‘<font color=»#%s«>’ % style[‘color’]
                end = ‘</font>’ + end

Далее пересобрать с помощью скрипта build.bat проект и запустить инсталлер – теперь то что делает данный проект в  цвете отображается на хабре.


Как забыть про ярлыки на рабочем столе?

Введение

image Раньше у меня довольно часто возникала проблема захламления рабочего стола огромным количеством ярлыков, и я начинал теряться в них, соответственно терять время при поиске необходимых мне приложений. В дальнейшем я научился пользоваться сочетанием клавиш win+r, создавая ярлыки с короткими именами в system32. С приходом Windows Vista (7) теперь только кнопки win, однако гибкость и настройка данных методов весьма ограниченна. Имеется так же огромное количество hotkey-менеджеров, однако не с одним из них я так и не сдружился.

Лаунчеры

Недавно (по-моему после прочтения книги «Продуктивный программист. Как сделать сложное простым, а невозможное – возможным» Нила Форда) мой интерес пал на launcher’ы. Для windows-платформы я нашёл несколько:

Ну и герой этого поста:

Немного истории

enso_321[1]

Изложу настолько, насколько я сумел разобраться в ней. Первоначально Enso был строго коммерческим проектом, разрабатываемым компанией Humanized (основанной Джеффри Раскиным, в котрой в последующем работал его сын). В дальнейшем компания начала работу над Mozilla Ubiquity (аналог Enso, являющийся плагином для FireFox), что позволило ей сделать Enso бесплатным.

Enso

Лучше 1 раз увидеть, чем 7 раз прочитать, базовые возможности представлены в следующих роликах:

На настоящий момент на сайте компании есть две версии продукта:

удобна в эксплуатации, но умеет делать лишь базовые вещи.

настройка (как и во второй версии) происходит через embeded веб-сервер

в данной версии появилось огромное количество очень полезных плагинов (к примеру поиск в google, генерация объектов-карт по выделенному адресу) однако юзабили немного упало (с моей точки зрения) в плане того, что после ввода команды начала открываться отдельная строка для ввода параметров, на что уходило время, и приходилось нажимать лишний раз enter

Все отлично, за исключением того, что проект на данном сайте вроде как заброшен, что не совсем воодушевляло к использованию, однако слазив внутрь и посмотрев реализацию, обнаружилось, что всё написано на Python (межплатформенность?), а так же исходники доступны в свободном доступе, что немного приободрило.

В дальнейших поисках упоминаний о Enso я наткнулся на коммунити http://www.ensowiki.com, а так же (самое главное) хостинг нынешей версии Enso https://launchpad.net/enso, итак, что же изменилось с тех времен:

  • настройка больше не через веб-сервер
  • межплатформенность (Windows, Linux, Mac OS X, etc)
  • интерфейс первой версии
  • практически все плагины из второй версии

Используем Enso

Для установки существует инсталлер, поэтому трудности вряд ли могут встретиться. Далее у меня возникла необходимость в настройке (теперь для совершения настроек существует файл enso\config.py) “основной” клавиши (Caps Lock) в режим залипания (Sticky в терминологии создателей программы), для этого я проделал следующее:

# Whether the Quasimode is actually modal («sticky»).

IS_QUASIMODE_MODAL = True

Расширяем Enso

Классно, мой питомец (Enso) теперь стал послушным и ласковым, однако хочется научить его понимать новые команды, ну что ж, пускай это будет Enso hello world.

Я отправился в папку commands в корне, куда добавил файл butaji.py со следующим содержимым:

import enso.config

from enso.messages import displayMessage

def cmd_butaji(ensoapi, cmd):

if cmd == «time»:

ensoapi.display_message(«Hello world»)

cmd_butaji.valid_args = [‘time’]

И у меня получилось следующее:

image

image

Великолепно! я думаю, что мы с Enso очень сдружимся.


Анализ рынка ноутбуков с помощью Python

Введение

В этой статье я расскажу о состоянии на сегодняшнем российском рынке ноутбуков. Всю аналитику мы будем проводить с помощью кода на python. Думаю она будет полезна как тем, кто ищет ноутбук, так и тем, кто хочет потренироваться написанию на python.

Начнём

diy-03-425[1] Для анализа нам необходим набор данных, к сожалению я не смог обнаружить веб-сервисы у российских он-лайн магазинов ноутбуков, поэтому мне пришлось скачать прайс-лист одного из них (я не стану называть его) и вытащить из него цены и основные параметры (по-моему мнению таковыми являются: частота процессора, диагональ монитора, объем оперативной памяти, размер жесткого диска и объем памяти на видео-карточке). Далее я провёл некоторый анализ по следующим вопросам:

  1. Средняя стоимость ноутбука
  2. Усредненные параметры железа на ноутбуках
  3. Самая дорогая/дешевая конфигурация ноутбука
  4. Какой из параметров конфигурации больше всего влияет на его цену
  5. Прогнозирование цены указанной конфигурации
  6. График распределения конфигураций и цен

Lets code

Прайс-лист, который мне удалось заполучить я сохранил в формате CVS, для работы с ним необходимо подключить модуль cvs:

import csv
import re
import random

Так же подключим модуль для работы со случайными числами и регулярными выражениями, которые в последствии нам понадобятся.

Далее создадим метод для чтения и получения ноутбуков:

def get_notebooks():
    reader = csv.reader(open(‘data.csv’), delimiter=‘;’, quotechar=‘|’)
    return filter(lambda x: x != Nonemap(create_notebook, reader))

здесь всё просто, мы читаем на файл с данными data.csv и фильтруем по результату функции create_notebook, т.к. не все позиции в прайсе являются ноутбуками, а вот кстати и она:

def create_notebook(raw):
    try:
        notebook = Notebook()
        notebook.vendor = raw[0].split(‘ ’)[0]
        notebook.model = raw[0].split(‘ ’)[1]
        notebook.cpu = getFloat(r»(\d+)\,(\d+)\s\Г», raw[0].split(‘/’)[0])
        notebook.monitor = getFloat(r»(\d+)\.(\d+)\»», raw[0].split(‘/’)[1])
        notebook.ram = getInt(r»(\d+)\Mb», raw[0].split(‘/’)[2])
        notebook.hdd = getInt(r»(\d+)Gb», raw[0].split(‘/’)[3])
        notebook.video = getInt(r»(\d+)Mb», raw[0].split(‘/’)[4])
        notebook.price = getInt(r»(\d+)\s\руб.», raw[1])
        return notebook
    except Exception, e:
        return None

Как вы можете заметить, я решил не обращать внимания на вендора, модель и тип процессора (здесь конечно не всё так просто, но тем не менее), а и ещё — в данном методе присутствуют мои кастомные функции-помощники:

def getFloat(regex, raw):
    m = re.search(regex, raw).groups()
    return float(m[0+ ‘.’ + m[1])

def getInt(regex, raw):
    m = re.search(regex, raw).groups()
    return int(m[0])

Хочу заметить, что писать для питона лучше всего в стиле наборов данных, а не ООП структур, в связи с тем, что язык больше располагает к такому стилю, однако для наведения некоторого порядка в нашей доменной области (ноутбуки), я ввёл класс, как вы могли заметить выше (notebook = Notebook())

class Notebook:
   pass

Отлично, теперь у нас есть структура в памяти и она готова для анализа (2005 различных конфигураций и их стоимость), что же начнём:

Средняя стоимость ноутбука:

def get_avg_price():
    print sum([n.price for n in get_notebooks()])/len(get_notebooks())

Исполняем код и видим, что 1K$, как стандарт для компьютера всё ещё в силе:

>> get_avg_price()
34574

Усредненные параметры железа на ноутбуках

def get_avg_parameters():
    print «cpu {0}».format(sum([n.cpu for n in get_notebooks()])/len(get_notebooks()))
    print «monitor {0}».format(sum([n.monitor for n in get_notebooks()])/len(get_notebooks()))
    print «ram {0}».format(sum([n.ram for n in get_notebooks()])/len(get_notebooks()))
    print «hdd {0}».format(sum([n.hdd for n in get_notebooks()])/len(get_notebooks()))
    print «video {0}».format(sum([n.video for n in get_notebooks()])/len(get_notebooks()))

Та-да, и в наших руках усредненная конфигурация:

>> get_avg_parameters()
cpu 2.0460798005
monitor 14.6333167082
ram 2448
hdd 243
video 289

Самая дорогая/дешевая конфигурация ноутбука:

Функции идентичны, за исключением функций min/max

def get_max_priced_notebook():
    maxprice = max([n.price for n in get_notebooks()])
    maxconfig = filter(lambda x: x.price == maxprice, get_notebooks())[0]
    print «cpu {0}».format(maxconfig.cpu)
    print «monitor {0}».format(maxconfig.monitor)
    print «ram {0}».format(maxconfig.ram)
    print «hdd {0}».format(maxconfig.hdd)
    print «video {0}».format(maxconfig.video)
    print «price {0}».format(maxconfig.price)
>> get_max_priced_notebook()
cpu 2.26
monitor 18.4
ram 4096
hdd 500
video 1024
price 181660
>> get_min_priced_notebook()
cpu 1.6
monitor 8.9
ram 512
hdd 8
video 128
price 8090

Какой из параметров конфигурации больше всего влияет на его цену

Очень интересно было бы узнать, за какой из параметров конфигурации мы платим больше всего денег. Прикинув, я предположил, что скорее всего это диагональ монитора и частота процессора, ну что же, думаю, что стоит проверить это.

Для начала наш набор параметров конфигурации стоит немного модифицировать. В связи с тем, что единицы измерения различных параметров различны в своём порядке, нам необходимо привести их к одному знаменателю, т.е. нормализовать их. Итак, приступим:

def normalized_set_of_notebooks():
    notebooks = get_notebooks()
    cpu = max([n.cpu for n in notebooks])
    monitor = max([n.monitor for n in notebooks])
    ram = max([n.ram for n in notebooks])
    hdd = max([n.hdd for n in notebooks])
    video = max([n.video for n in notebooks])
    rows = map(lambda n : [n.cpu/cpu, n.monitor/monitor, float(n.ram)/ram, float(n.hdd)/hdd, float(n.video)/video, n.price], notebooks)
    return rows

В данной функции я нахожу максимальные значения для каждого из параметров, после этого формирую результирующий список ноутбуков, в котором каждый из параметров представлен в виде коэффициента (его значение будет колебаться от 0 до 1), показывающего отношение его параметра к максимальному значению в наборе, к примеру память в 2048Mb даст конфигурации коэффициент в ram = 0.5 (2048/4056).

Вклад каждого из параметров мы будем считать в рублях, для наглядности, хранить эти веса мы будет в наборе:

#cpu, monitor, ram, hdd, video
koes = [00000]

Я предлагаю исчислять эти коэффициенты для каждой конфигурации, а после этого определить среднюю величину всех коэффициентов, что даст нам усредненные данные о весе каждого из элементов конфигурации.

def analyze_params(parameters):
    koeshistory = []
    #наши ноутбуки
    notes = normalized_set_of_notebooks()
    for i in range(len(notes)):
        koes = [00000]
        #устанавливаем коэффициенты
        set_koes(notes[i], koes)
        #сохраняем историю коэффициентов
        koeshistory.extend(koes)
        #показываем прогресс выполнения
        if (i % 100 == 0):
            print i
            print koes

Как же мы будет устанавливать коэффициенты для каждого элемента конфигурации? Мой способ заключается в следующем:

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

Вот реализация данного алгоритма:

def set_koes(note, koes, error=500):
    price = get_price(note, koes)
    lasterror = abs(note[5 price)
    while (lasterror > error):
        k = random.randint(0,4)
        #изменяем коэффицинт
        inc = (random.random()*2  1* (error*(1  error/lasterror))
        koes[k] += inc
        #не даём коэффициенту стать меньше нуля
        if (koes[k] < 0): koes[k] = 0
        #получаем цену при учёте коэффициентов
        price = get_price(note, koes)
        #получаем текущую ошибку
        curerror = abs(note[5 price)
        #проверяем, приблизились ли мы к цене, казанной в прайсе
        if (lasterror < curerror):
            koes[k] -= inc
        else:
            lasterror = curerror

inc – переменная отвечающая за цвеличение/уменьшение коэффициента, способ её вычисления объесняется тем, что данное значение должно быть тем больше, чем больше разница в ошибке, для быстрого и более точного приближения к желаемому результату.

Умножение векторов для получения цены выглядит следующим образом:

def get_price(note, koes):
    return sum([note[i]*koes[i] for i in range(5)])

Пришла пора выполнить анализ:

>> analyze_params()
cpu, monitor, ram, hdd, video

[15455.6067566768420980.56048381136112782.53527030428117819.90462958586114677.889529808042]

Данный набор мы получили, благодаря усреднению коэффициентов, полученных для каждой из конфигураций:

def get_avg_koes(koeshistory):
    koes = [00000]
    for row in koeshistory:
        for i in range(5):
            koes[i] += koeshistory[i]
    for i in range(5):
        koes[i] /= len(koeshistory)
    return koes

Итак, у нас получился желаемый набор, что же мы можем сказать из этих цифр, а можем мы составить рейтинг параметров:

  1. Диагональ монитора
  2. Объем жесткого диска
  3. Частота процессора
  4. Объем видео-карточки
  5. Объем оперативной памяти

Хотелось бы отметить, что это далеко не идеальный вариант, и у вас могут получится иные результаты, однако, моё предположение, о том, что частота процессора и диагональ дисплея наиболее важные параметры в конфигурации, частично подтвердились.

Прогнозирование цены указанной конфигурации

Классно бы было, имея такой богатый набор данных, уметь прогнозировать цену на заданную конфигурацию. Этим мы и займемся.

Для начала преобразуем нашу коллекцию ноутбуков в список:

def get_notebooks_list():
    return map(lambda n: [n.cpu, n.monitor, n.ram, n.hdd, n.video, n.price], get_notebooks())

Далее нам понадобиться функция, способная определить расстояние между двумя векторами, хорошим вариантом я вижу функцию эвклидова расстояния:

def euclidean(v1, v2):
    d = 0.0
    for i in range(len(v1)):
        d+=(v1[i]  v2[i])**2;
    return math.sqrt(d)

Корень из суммы квадратов разностей довольно таки наглядно и эффективно показывает нам насколько один вектор различен от другого. Чем же полезна для нас данная функция? Всё просто, когда мы получим вектор, с интересующими нас параметрами, мы пробежимся по всей коллекции нашего набора и найдём ближайшего соседа, а его стоимость мы уже знаем, отлично! Вот как мы это сделаем:

def getdistances(data, vec1):
    distancelist=[]
    for i in range(len(data)):
        vec2 = data[i]
        distancelist.append((euclidean(vec1,vec2),i))
    distancelist.sort()
    return distancelist

Далее, можно немного усложнить задачу, а так же точность предоставляемых данных. Для этого мы введем функцию, использующую классификацию методом k взвешенных ближайших соседей:

K взвешенных ближайших соседей — это метрический алгоритм классификации, основанный на оценивании сходства объектов. Классифицируемый объект относится к тому классу, которому принадлежат ближайшие к нему объекты обучающей выборки.

Ну и взять среднее значение среди некоторого количества ближайших соседей, что сведет на нет влияние цен вендора, либо специфичности конфигурации:

def knnestimate(data,vec1,k=3):
    dlist = getdistances(data, vec1)
    avg = 0.0
    for i in range(k):
        idx = dlist[i][1]
        avg +=data[idx][5]
    avg /= k
    return avg

*последние 3 алгоритма взяты из книги Сегерана Тоби “Программируем коллективный разум”

И что же мы получаем:

>> knnestimate(get_notebooks_list(), [2.4173062250512])
31521.0

>> knnestimate(get_notebooks_list(), [2.0152048160256])
27259.0
>> knnestimate(get_notebooks_list(), [2.0152048160128])
20848.0

Цены рыночные и этого вполне достаточно, хотя мы абсолютно не учитываем в этой реализации, к примеру частоту процессора и диагональ монитора (для этого нам необходимо добавить в функцию сравнения векторов их веса , которые мы вычисляли в предыдущем пункте)

График распределения конфигураций и цен

Хочется объять картину распределения целиком, т.е. нарисовать распределение конфигураций и цен на рынке. Ок, сделаем это.

Для начала надо поставить библиотеку matplotlib. Далее подключить её к нашему проекту:

from pylab import *

Так же нам понадобится создать два набора данных, для оси абсцисс и ординат:

def power_of_notebooks_config():
    return map(lambda x: x[0]*x[1]*x[2]*x[3]*x[4], normalized_set_of_notebooks())
def config_prices():
    return map(lambda x: x[5], normalized_set_of_notebooks())

И функцию, в которой мы построим график распределения:

def draw_market():
    plot(config_prices(),power_of_notebooks_config(),‘bo’, linewidth=1.0)

    xlabel(‘price (Rub)’)
    ylabel(‘config_power’)
    title(‘Russian Notebooks Market’)
    grid(True)
    show()

И что же мы получаем:

notes

В завершение

Итак, у нас получилось провести небольшой анализ российского рынка ноутбуков, а так же немного проиграться с python.

Исходный код проекта доступен по адресу:

http://code.google.com/p/runm/source/checkout


Ruby|Python в браузере, сделай сам

Зачем?

sidebar_gestaltКлиентскую часть в веб-приложениях принято создавать на JavaScript. Я считаю, что большинство разработчиков с огромным удовольствием бы отошли от этого правила и воспользовались своим любимым server-side языком. Ну что же, команда MIX Online предоставила любителям динамических языков такую возможность, подробнее об этом можно прочитать в “Проект Gestalt – пишите на Ruby, Python и XAML прямо в HTML на стороне клиента”. Ниже я предлагаю создать нечто подобное, но уже своими силами.

С помощью чего?

Посмотрев несколько примеров мне стало ясно, что реализован Gestalt на Silverlight + Dynamic Languages Runtime. Далее я прикинул, а на сколько сложно создать нечто своими руками? И сразу же решение: Silverlight умеет  взаимодействовать с DOM – значит я смогу получить код и интерпритировать его – дело за малым – реализация.

Приступим

Нам понадобятся:

  • Visual Studio >2008SP1 (при желании можно и другие IDE или средства редактирования текста)
  • Silverlight >2.0 Tools
  • Dynamic Languages SDK >0.5.0 (download)
  • 10 мин времени

Lets code

image

Открываем Visual Studio, создаём Silverlight Application, я назову проект “mygestalt”. Теперь я осознаю, что писать та надо будет совсем не много, мне понадобится экспериментальный Client-Script и его интерпритатор. Открываем страничку, на которой будет хоститься наш Silverlight, в моём случаем это mygestaltTestPage.aspx и добавляем туда наш client-side python code. Выглядеть это должно примерно так:

  1. <script type="python">
  2. def func():
  3.     HtmlPage.Window.Alert("Hello world!")
  4.    
  5. func()
  6. </script>

* This source code was highlighted with Source Code Highlighter.

Далее отправляемся в MainPage.xaml.cs, где будем заниматься поисками нашего скрипта:

  1. using System.Linq;
  2. using System.Windows.Browser;
  3.  
  4. namespace mygestalt
  5. {
  6.   public partial class MainPage
  7.   {
  8.     public MainPage()
  9.     {
  10.       InitializeComponent();
  11.       FindAndRunScript();
  12.     }
  13.  
  14.     private void FindAndRunScript()
  15.     {
  16.       var scripts = HtmlPage.Document.GetElementsByTagName("script");
  17.       var pythonScript = scripts.Where(x => x.GetProperty("type").ToString() == "python").First();
  18.       PythonEngine.Run(pythonScript.GetProperty("innerHtml").ToString());
  19.     }
  20.   }
  21. }

* This source code was highlighted with Source Code Highlighter.

Ну и реализация PythonEngine:

  1. using Microsoft.Scripting;
  2. using Microsoft.Scripting.Hosting;
  3. using Microsoft.Scripting.Silverlight;
  4.  
  5. namespace mygestalt
  6. {
  7.   public static class PythonEngine
  8.   {
  9.     public static ScriptScope Run(string source)
  10.     {
  11.       var setup = Configuration.LoadFromAssemblies(Package.GetManifestAssemblies());
  12.       setup.HostType = typeof(BrowserScriptHost);
  13.       setup.DebugMode = true;
  14.       var runtime = new ScriptRuntime(setup);
  15.       var engine = runtime.GetEngine("IronPython");
  16.       var scope = engine.CreateScope();
  17.       const string init = @"
  18. import clr
  19. clr.AddReference('System.Windows.Browser')
  20.  
  21. from System.Windows.Browser import *
  22.  
  23. "
  24. ;

  25.  
  26.       ScriptSource initSource = engine.CreateScriptSourceFromString(init, SourceCodeKind.Statements);
  27.       initSource.Execute(scope);
  28.       var script = engine.CreateScriptSourceFromString(source, SourceCodeKind.Statements);
  29.       script.Execute(scope);
  30.  
  31.       return scope;
  32.     }
  33.   }
  34. }

* This source code was highlighted with Source Code Highlighter.

Запускаем приложение и видим:

image

 

 

 

 

В заключение

Вот у нас и получился свой собственный Gestalt, самое интересное в том, что я посмотрел его исходники и нашёл там примерно такую же реализацию.

Мой проект можно найти на http://code.google.com/p/mygestalt/.

Всем спасибо!


Звучит заманчиво: Django на IronPython

def Introduce():

Дорогие мальчики и девочки, меня (как позже оказалось не только меня) интересует веб-индустрия и всё, что с ней связано, соответственно хочется вкусить разнообразных технологий, одной из них является известный фреймворк DjangoimageИм и хочется заняться. Думаю, не стоит говорить, о том, что я .NET-разработчик, в связи с чем Python в чистом виде использовать не очень хочется, но хочется попробовать IronPython в деле. Тогда вполне очевидно, что Django на .NET должен являться ASP.NET приложением.

def WSGI():

Здесь нам нужно знать, что такое WSGI:

WSGI (англ. Web Server Gateway Interface, произносится виски) — стандарт взаимодействия между Python-программой, выполняющейся на стороне сервера, обычно из каталога cgi-bin, и самим веб-сервером, например, Apache.

Дополнительная информация: PEP 333

И нам безусловно повезло, т.к. есть готовая имплементация WSGI для ASP.NET: NWSGI – выполнена как ASP.NET 2.0 HttpHandler на IronPython.

Что примечательно, мало того, что NWSGI интегрируется с IIS и позволяет работать с сессиями, кешем и управлением пользователями, он интегрируется даже с графической средой управления IIS 7!

Это ещё не всё, NWGSI умеет также работать с Cassini (веб-сервер Visual Studio).

Думаю Вам, ровно как и мне, не терпится поработать с этим.

def PrepareIIS():

Итак, что нам необходимо:

  • IronPython 2.0
  • NWSGI 1.0
  • Огромное желание сделать что-нибудь особенное на этом.

Для установки из пакета NWSGI копируем пример HelloWorld в папку C:\inetpub\wwwroot\HelloWorld (либо другой путь для ваших IIS приложений). Из этого же пакета копируем NWSGI.dll в папочку HelloWorld\bin (если пользовались инсталлятором, то в этом нет необходимости, т.к. она уже в GAC’е).

Далее из пакета IronPython 2.0 копируем в каталог HelloWorld\bin следующие сборки:

  • IronPython.dll
  • IronPython.Modules.dll
  • Microsoft.Scripting.Core.dll
  • Microsoft.Scripting.dll

Наша папочка HelloWorld должна выглядеть следующим образом:

HelloWorld\

  • bin\
    • NWSGI.dll (optional)
    • IronPython.dll
    • IronPYthon.Modules.dll
    • Microsoft.Scripting.Core.dll
    • Microsoft.Scripting.dll
  • hello.wsgi
  • Web.Classic.config
  • Web.Integrated.config

Далее, если у нас ISS 7.0, то тогда копируем Web.Integrated.config в Web.config, иначе Web.Classic.config в Web.config.

Далее добавляем приложение на IIS, это можно сделать, как через графическое меню, так и воспользоваться консолью:

%systemroot%\system32\inetsrv\appcmd add app /site.name:"Default Web Site" /path:/hello /physicalPath:C:\inetpub\wwwroot\HelloWorld

Если же у вас IIS 6, то путь один – через графическое меню, а так же необходимо будет ассоциировать *.wsgi с ASP.NET ISAPI фильтром (по аналогии с *.aspx)

Теперь идём по адресу http://localhost/hello/hello.wsgi. И видим грациозное: "Hello, World!", yeah!

def InstallDjango():

Установить Django можно с помощью команды:

ipy setup.py install

Далее можно добавить проект и сгенерировать приложения:

ipy manage.py startapp AppName

ipy manage.py startproject ProjName

К сожалению, мне не хватило навыков для того, чтобы запустить django-приложение под NWSGI.

def SqlServer():

Подключить Django к Microsft SQL Server 2005 и выше можно с помощью следующей библиотеки:

http://code.google.com/p/django-mssql/

Так же можно почитать о подключении здесь: http://blogs.msdn.com/dinoviehland/archive/2008/03/17/ironpython-ms-sql-and-pep-249.aspx

def GetGratitude():

Огромную благодарность за выполненную работу хочу выразить Jeff Hardy и советую ознакомиться с его работами:


Codeplex: Очередной Add-In для Reflector’а

Сегодня на Codeplex нашёл плагин, который позволяет рефлектору интерпритировать сборки в IronPython. Довольно таки интересно.

image

На рисунке интерпретирована сборка Boo в IronPython.

Ссылка на релиз http://www.codeplex.com/ipreflector.


Что такое ALT.NET?

Введение

По многочисленным WTF от коллег, хотел бы вкратце прояснить, а что же это такое. А дальше решайте сами, интересно Вам это или нет.

Содержание

 

ALT.NET — Альтернативные инструменты и подходы к разработке на .NET.

Инструменты и подходы перечислены ниже в табличке HOTorNOT.

Hot Not
Castle, ActiveRecord,
NHibernate
DataSets, Dataset Designer, Entity Framework, MS Application Blocks
MVC,NUnit,MonoRail Web Forms, SCSF, VSTS, MSTest
XP, TDD, Scrum MSF Agile, MSF For CMMI
Evolutionary Design and Development Big Design Up Front
Ruby + IronRuby, Python + IronPyton, DLR, Silverlight(?) ?
OR\M (NHibernate, LLBLGen  etc..) DLinq, Data Access Block, DataSets, Plain ADO. NET
Open Source (Mono, SourceForge) Application Blocks, CodePlex
MVC and MVP (RoR, MonoRail..) Web Forms, CAB, Smart Client Factory
CVS, SVN VSS, VSTS Source Control
Build Automation and CI
(CI Factory, NAnt, FinalBuilder, CruiseControl..)
Team Build
TDD and Unit Testing
NUnit, MbUnit, RhinoMocks, NMock, TypeMock
MSTest for unit testing, VSTS
Subtext, DasBlog, WordPress, TypePad, Blogger, FeedBurner Microsoft MSN Spaces, Community Server(?)
Simplicity in Design P&P
Working at Google Working at MS
Google Gears Smart Client, MS Ajax
.NET 3.X (WF, WPF. Silverlight) .NET 2.0
DI, IoC, Spring for .NET Object Builder
Conferences:
OSCon, RubyCon, Code Camps, DevTeach..
VSLive, TechEd, DevConnections..

Считаю, что необходимо как минимум ознакомиться со всеми перечисленными понятиями как в правой, так и в левой колонках, следуя принципу анализ-синтез-best practices.

Материалы по теме

 

  1. Табличка любезно позаимствована здесь http://weblogs.asp.net/rosherove/archive/2007/06/04/alt-net-alternative-tools-and-approaches-to-mainstream-net.aspx
  2. Страница сообщества ALT.NET http://altdotnet.org/
  3. Статья в журнале MSDN “Что такое ALT .NET?” by Джереми Д. Миллер (Jeremy D. Miller) http://msdn.microsoft.com/ru-ru/magazine/cc337902.aspx
  4. Активно развивающаяся группа ALT.NET на Yahoo Groups http://tech.groups.yahoo.com/group/altdotnet/

Обзор языка Boo! – как средства организации DSL Вашего приложения

boo-logo-128_med

Одна из вещей, как известно, способная помочь вам стать лучше в качестве разработчика, заключается в изучении нового языка. Даже если Вы никогда не будете пользоваться этим языком в Вашей повседневной трудовой деятельности, он поможет Вам лучше понять языки, с которыми Вы работаете.

В последнее время меня так и тянет насесть на какой-нибудь новенький язык программирования, особенно что-нибудь на типа Ruby или Python, но в связи с моей привязанностью среде разработки (Visual Studio, неверно это не очень хорошо – зависеть от IDE ;)) и затруднительной ситуацией с разработкой на ней на динамических языках (надеюсь это временное затруднение) от них пока пришлось отказаться. В то же время меня интересуют такие области как метапрограммирование и реализация DSL (Domain-Specific Language == проблемно-ориентированный язык приложения), и в этой связи видится мне, что Boo является весьма интересным языком. К тому же Boo — язык CLR, что очень даже не плохо для изучения.

Поэтому я решил, что когда я узнаю Boo и когда почувствую уверенность в Boo, я попробую реализовать DSL и реализовать именно на Boo для своего ближайшего проекта.

Что такое Boo?

Boo представляет собой open-source объектно-ориентированный статически типизированный язык программирования для CLR с Python’о-подобным синтаксисом, язык увидел свет в 2004 году из-под рук Rodrigo B. de Oliveira. В настоящее время последняя версия 0.8.2, но даже если нет еще версии 1.0, это действительно очень стабильной и зрелый язык, который можно использовать на производстве.

Основные концепции в Boo:

  1. Дать компилятору сделать большую часть работы, для того чтобы помочь языку выглядеть более динамическим с автоматическим объявлением переменных, выводом и приведением типов.
  2. В то же время он предоставляет возможности для выполнения статической компиляции, проверку ошибок во время компиляции.
  3. Boo также предоставляет функциональную составляющую в том, что функции могут использоваться в качестве возвращаемого значения, как аргументы, хранимые в переменных, а так же как объекты.
  4. Boo имеет первоклассные генераторы, это конструкций, способные производить более одного значения при использовании итерации цикла (“return a for a in apples if a.IsRipe”).
  5. Boo также поддерживает утиную типизацию (Duck Typing), которая позволяет отказаться от обеспечения безопасности статических типов и принимать любой объект, который просто имеет соответствующие методы и свойства, определяемые во время выполнения.
  6. Boo также имеет расширения методов и свойств (extension methods and extension properties).

Одним из наиболее интересных функций Boo является расширяемость процесса компиляции, которая позволяет управлять компиляцией и изменять или добавлять функции. Можно добавить подпрограмм для проверки конвенции кода, генерирования отчётов или преобразовывания кода. То, что Вы сможете сделать в C# с помощью тулзы посткомпиляции такой, как PostSharp и только ограниченный набор действий. В Boo Вы могли бы например автоматически преобразовать класс в одноэкземплярный (pattern Singleton), просто добавив атрибут следующим образом:

[singleton]
class MySingleton: pass

PostSharp просто не смог бы сделать этого, свойство экземпляра было бы обработано поздно. Это действительно открывает множество возможностей и Вы ограничиваетесь только Вашим пониманием внутренней функциональности компилятора и набора его возможностей.

В Boo пробелы имеют важное значение как в python, но есть возможность включить режим “Whitespace Agnostic”, позволяющий оканчивать выражение с помощью “end”, который избавит Вас от возможных проблем с пробелами.

Что нужно для начала работы с Boo?

Главным образом если Вы хотите узнать Boo, достаточно иметь последнюю версию Boo . В папке bin, Вы найдете файл “Booish.exe”, являющийся интерпретатором командной строки Boo, которая позволяет проиграться с синтаксисом языка.image

Для разработки нам необходима IDE, и следовательно у нас два варианта.

Большинство Boo разработчиков работают с SharpDevelop , и если Вы скачаете последнюю версию, в ней будет Boo полностью готовый к использованию. Эта IDE имеет преимущество, с точки зрения создания DSL, так как в ней легче добавить функции автозавершения кода и подсветки синтаксиса, в Visual Studio же потребуются написать лексер и парсер; в SharpDevelop можно сделать это с помощью XML-файла.

Но с другой стороны Visual Studio является зрелой IDE, и с BooLangStudio вы получите Boo интегрированный в Visual Studio. Люди жалуются, что проект является нестабильным и это лишь альфа выпуск, так же я встретился в нём с проблемами уникода (UTF8), которые пока не смог разрешить, но у меня пока нет весомых замечаний.

В настоящее время я буду пользоваться Visual Studio в силу привычки, но я могу изменить свой взгляд при продолжении этой статьи.

При написании данного поста я руководствовался данной работой, можно даже сказать переводил, но перевод очень личный и свободный.

Продолжение следует…