Записки программиста, обо всем и ни о чем. Но, наверное, больше профессионального.

2012-04-26

Олдскульный Zope Product 2 egg

Не корысти ради а токмо волею пославшей мя жены! © Ильф и Петров.

В продолжение темы «Заготовка Zope Product» и, если точнее, в продолжение подтемы «Тестирование/отладка Zope Product». Некоторые детали нынешнего поста раскрываются в подробностях там, раньше.

Тенденция, однако. Я по наивности своей полагал, что заворачивать Zope Product в яйцо (egg) придется еще не скоро. Ошибся. Нынче настали такие времена, когда яйцепоклонники победили со всей очевидностью. Во всяком случае в теме Zope/Plone.

Такой факт — начиная с Zope 2.12.8 пропала возможность запускать
zopectl test
Теперь, чтобы автоматизировать тестирование своего продукта, надо заворачивать продукт в яйцо и добавлять zc.recipe.testrunner в билдаут. Иначе, разумеется, можно. Но не нужно.

Что поделать, яйцо, так яйцо, тестировать-то надо. В конце концов, делов-то: раз — сделать яйцо, два — поправить билдаут для включения этого яйца. Понеслась. Брюки продукты превращаются ... в egg.

Сперва добудем инструменты — paster & zopeskel.

Чтобы сделать яйцо, нужен paster. Рекомендуют получить его через билдаут, хотя можно и через virtualenv организовать.
Добавил в C:\d\Zope\zope213\buildout.cfg
строки про zopeskel & paster, получилось так
[buildout]
parts =
  zopeskel
  paster
  instance
extends = http://download.zope.org/Zope2/index/2.13.13/versions.cfg

[zopeskel]
recipe = zc.recipe.egg
eggs =
  ZopeSkel<2.99

[paster]
recipe = zc.recipe.egg
eggs =
  PasteScript
  ZopeSkel<2.99

[instance]
recipe = zc.recipe.egg
eggs =
  Zope2
  Products.ZSQLMethods
interpreter = zopepy
scripts = runzope zopectl
initialization =
  import sys
  sys.argv[1:1] = ['-C', r'${buildout:directory}\etc\zope.conf']
и запустил перестройку
C:\d\Zope>call setenv.cmd
C:\d\Zope>cd zope213
C:\d\Zope\zope213>bin\buildout.exe
как и обещали (collective-docs.readthedocs.org/en/latest/tutorials/paste), появились команды
c:\d\Zope\zope213\bin\paster.exe
c:\d\Zope\zope213\bin\zopeskel.exe

Дополнительно стОит заметить, что в доках рекомендуют конфиг писать немного иначе. К примеру, секция zopeskel изначально выглядела так
...
[zopeskel]
recipe = zc.recipe.egg
eggs =
        ZopeSkel<2.99
        zopeskel.dexterity
        ${instance:eggs}
...
Декстерити я убрал, потому как он мне не нужен. А вот с подключением яиц инстанса (${instance:eggs}) уже интереснее. Если сделать как рекомендуют, перестают работать скрипты запуска Zope. Отваливаются с сообщением
C:\d\Zope\zope213>bin\runzope.exe
Traceback (most recent call last):
  File "C:\d\Zope\zope213\bin\runzope-script.py", line 92, in <module>
    Zope2.Startup.run.run()
  File "c:\d\zope\zope213\eggs\zope2-2.13.13-py2.7.egg\Zope2\Startup\run.py", line 19, in run
    opts = _setconfig()
  File "c:\d\zope\zope213\eggs\zope2-2.13.13-py2.7.egg\Zope2\Startup\run.py", line 50, in _setconfig
    handlers.handleConfig(opts.configroot, opts.confighandlers)
  File "c:\d\zope\zope213\eggs\zope2-2.13.13-py2.7.egg\Zope2\Startup\handlers.py", line 193, in handleConfig
    return multihandler(handlers)
TypeError: 'NoneType' object is not callable
Как я выяснил, это из-за того, что в скриптах запуска пропадают строки
import sys
sys.argv[1:1] = ['-C', r'C:\d\Zope\zope213\etc\zope.conf']
Так что рекомендуемый конфиг я подправил, убрав подключение инстансовых яиц.


ОК, paster и zopeskel у меня есть. Создаю яйцо (weblion.psu.edu/trac/weblion/wiki/EggifyAnExistingProduct).

По инструкции опять не очень хорошо
c:\d\Zope\zope213\bin\paster create -t plone3_theme Products.vcufile
повис...отвис.
bin\paster.exe create -t plone Products.vcufile

Попробую так:
C:\d\Zope\zope213>bin\zopeskel.exe basic_zope Products.vcufile
Говорят, что на вопросы надо отвечать так, чтобы получилось
  namespace_package: Products
  package: vcufile
  zip_safe: False
Но мне таких вопросов не задавали, сессия выглядела вот как
basic_zope: A Zope project
This creates a Zope project without any specific Plone features.
If at any point, you need additional help for a question, you can enter
'?' and press RETURN.
Expert Mode? (What question mode would you like? (easy/expert/all)?) ['easy']:
Version (Version number for project) ['1.0']: 3.0.0
Description (One-line description of the project) ['']: Zope2 Product for huge files chunked upload
Creating directory .\Products.vcufile
c:\d\zope\zope213\eggs\cheetah-2.2.1-py2.7.egg\Cheetah\Compiler.py:1523: UserWarning:
You don't have the C version of NameMapper installed! I'm disabling Cheetah's useStackFrames
option as it is painfully slow with the Python version of NameMapper.
You should get a copy of Cheetah with the compiled C version of NameMapper.
  "\nYou don't have the C version of NameMapper installed! "
Replace 0 bytes with 2 bytes (0/0 lines changed; 1 lines added)
Replace 244 bytes with 2 bytes (6/6 lines changed; 5 lines removed)
и в результате получилось такое
c:\d\Zope\zope213\Products.vcufile
│   Products.vcufile-configure.zcml
│   README.txt
│   setup.py
│
├───docs
│       HISTORY.txt
│
├───Products
│   │   __init__.py
│   │
│   └───vcufile
│           configure.zcml
│           README.txt
│           tests.py
│           zope2.py
│           __init__.py
│
└───Products.vcufile.egg-info
        dependency_links.txt
        entry_points.txt
        namespace_packages.txt
        not-zip-safe
        PKG-INFO
        requires.txt
        SOURCES.txt
        top_level.txt
Согласно руководству по обяичиванию, заменил содержимое папки
c:\d\Zope\zope213\Products.vcufile\Products\vcufile
содержимым своего продукта. Получилось так
c:\d\Zope\zope213\Products.vcufile
│   Products.vcufile-configure.zcml
│   README.txt
│   setup.py
│
├───docs
│       HISTORY.txt
│
├───Products
│   │   vcufile.egg.template.rar
│   │   __init__.py
│   │
│   └───vcufile
│       │   CHANGES.txt
│       │   configure.zcml
│       │   DEPENDENCIES.txt
│       │   HISTORY.txt
│       │   INSTALL.txt
│       │   LICENSE.txt
│       │   README.txt
│       │   TODO.txt
│       │   uploads_const.py
│       │   vcufile.py
│       │   vcufileproduct.py
│       │   VERSION.txt
│       │   __init__.py
│       │
│       ├───help
│       │       VCUFile.stx
│       │
│       ├───static
│       │       vcu.sl.client.js
│       │
│       ├───tests
│       │       testVCUFile.py
│       │       __init__.py
│       │
│       └───wwwvcufile.pngvcufile16.pngvcuFileAdd.dtmlvcuFileEdit.dtmlvcuFileView.zpt
│
└───Products.vcufile.egg-info
        dependency_links.txt
        entry_points.txt
        namespace_packages.txt
        not-zip-safe
        PKG-INFO
        requires.txt
        SOURCES.txt
        top_level.txt
Жирным я выделил свои файлы, остальное нагенерировано роботом.
Как и положено, теперь продукт Zope выполнен в формате egg, что несколько меняет способ его подключения к Zope.


Подключаю Product egg к Zope.

Сперва нужно удалить старый продукт, в виде папки
c:\d\Zope\zope213\Products\vcufile
если она еще не удалена на предыдущем шаге.
Теперь разместить яйцо в разработческой папке
c:\d\Zope\zope213\src\Products.vcufile
Поправить конфиг билдаута
[buildout]
parts =
  zopeskel
  paster
  instance
extends = http://download.zope.org/Zope2/index/2.13.13/versions.cfg
develop =
  src/Products.vcufile

[zopeskel]
recipe = zc.recipe.egg
eggs =
  ZopeSkel<2.99

[paster]
recipe = zc.recipe.egg
eggs =
  PasteScript
  ZopeSkel<2.99

[instance]
recipe = zc.recipe.egg
eggs =
  Zope2
  Products.ZSQLMethods
  Products.vcufile
interpreter = zopepy
scripts = runzope zopectl
initialization =
  import sys
  sys.argv[1:1] = ['-C', r'${buildout:directory}\etc\zope.conf']
и пересобрать
C:\d\Zope\zope213>bin\buildout.exe
Работает, проверил.

Поставленная на сегодня задача выполнена — продукт Zope завернут в яйцо (egg) и подключен к Zope в таком виде.


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

Как сказано в руководстве (collective-docs.readthedocs.org/en/latest/testing_and_debugging/unit_testing) надо подключить zc.testrunner.
Правлю конфиг билдаута
[buildout]
parts =
  zopeskel
  paster
  test
  instance
extends = http://download.zope.org/Zope2/index/2.13.13/versions.cfg
develop =
  src/Products.vcufile

[zopeskel]
recipe = zc.recipe.egg
eggs =
  ZopeSkel<2.99

[paster]
recipe = zc.recipe.egg
eggs =
  PasteScript
  ZopeSkel<2.99

[test]
recipe = zc.recipe.testrunner
defaults = ['--auto-color', '--auto-progress']
eggs =
  ${instance:eggs}

[instance]
recipe = zc.recipe.egg
eggs =
  Zope2
  Products.ZSQLMethods
  Products.vcufile
interpreter = zopepy
scripts = runzope zopectl
initialization =
  import sys
  sys.argv[1:1] = ['-C', r'${buildout:directory}\etc\zope.conf']
после перестройки, как и обещали, появляется утилита
c:\d\Zope\zope213\bin\test.exe

Запускаю (барабанная дробь....)
C:\d\Zope\zope213>bin\test -s Products.vcufile
Running zope.testing.testrunner.layer.UnitTests tests:
  Set up zope.testing.testrunner.layer.UnitTests in 0.000 seconds.
  Running:
  Ran 1 tests with 0 failures and 0 errors in 0.000 seconds.
Tearing down left over layers:
  Tear down zope.testing.testrunner.layer.UnitTests in 0.000 seconds.
Ура, товарищи! Unit tests запустились и отработали.

Вот ради этого события и проделана вся вышеописанная работа — многоэтапная переделка «старорежимного» Zope Product в формат egg.

Чисто для справки, на текущий момент юнит-тесты выглядят так
c:\d\Zope\zope213\src\Products.vcufile\Products\vcufile\tests\__init__.py
# This file is needed to make this a package.

c:\d\Zope\zope213\src\Products.vcufile\Products\vcufile\tests\testVCUFile.py
import os
import unittest

import ZODB # dead goat
import Products.vcufile.tests
from Products.vcufile.vcufileproduct import VCUFileProduct
import App.config

class testVCUFile(unittest.TestCase):

    def setUp(self):
        self._old = App.config.getConfiguration()
        cfg = App.config.DefaultConfiguration()
        cfg.instancehome = os.path.dirname(
            Products.vcufile.tests.__file__)
        App.config.setConfiguration(cfg)

    def tearDown(self):
        App.config.setConfiguration(self._old)

    def testFID(self):
        vf = VCUFileProduct('123', '456')
        self.assertEqual(vf.getFID(), '')
        state = vf.__getstate__()
        vf2 = VCUFileProduct.__basicnew__()
        vf2.__setstate__(state)
        self.assertEqual(vf2.getFID(), '')
        self.failIf(state.has_key('func_defaults'))

def test_suite():
    return unittest.makeSuite(testVCUFile)

def package_home(globals_dict):
    __name__=globals_dict['__name__']
    m=sys.modules[__name__]
    if hasattr(m,'__path__'):
        r=m.__path__[0]
    elif "." in __name__:
        r=sys.modules[__name__.split('.',1)[0]].__path__[0]
    else:
        r=__name__
    return os.path.abspath(r)

if __name__=='__main__':
    unittest.main(defaultTest='test_suite')
Заготовка по шаблону, зато работает.

Вот и сказочке конец, кто дослушал — молодец.

Что было полезно
pypi.python.org/pypi/Zope2/2.12.8 Removed the test command from zopectl. The test.py script it was relying on does no longer exist.

Комментариев нет:

Отправить комментарий

Архив блога

Ярлыки

linux (241) python (191) citation (186) web-develop (170) gov.ru (159) video (124) бытовуха (115) sysadm (100) GIS (97) Zope(Plone) (88) бурчалки (84) Book (83) programming (82) грабли (77) Fun (76) development (73) windsurfing (72) Microsoft (64) hiload (62) internet provider (57) opensource (57) security (57) опыт (55) movie (52) Wisdom (51) ML (47) driving (45) hardware (45) language (45) money (42) JS (41) curse (40) bigdata (39) DBMS (38) ArcGIS (34) history (31) PDA (30) howto (30) holyday (29) Google (27) Oracle (27) tourism (27) virtbox (27) health (26) vacation (24) AI (23) Autodesk (23) SQL (23) humor (23) Java (22) knowledge (22) translate (20) CSS (19) cheatsheet (19) hack (19) Apache (16) Klaipeda (15) Manager (15) web-browser (15) Никонов (15) functional programming (14) happiness (14) music (14) todo (14) PHP (13) course (13) scala (13) weapon (13) HTTP. Apache (12) SSH (12) frameworks (12) hero (12) im (12) settings (12) HTML (11) SciTE (11) USA (11) crypto (11) game (11) map (11) HTTPD (9) ODF (9) Photo (9) купи/продай (9) benchmark (8) documentation (8) 3D (7) CS (7) DNS (7) NoSQL (7) cloud (7) django (7) gun (7) matroska (7) telephony (7) Microsoft Office (6) VCS (6) bluetooth (6) pidgin (6) proxy (6) Donald Knuth (5) ETL (5) NVIDIA (5) Palanga (5) REST (5) bash (5) flash (5) keyboard (5) price (5) samba (5) CGI (4) LISP (4) RoR (4) cache (4) car (4) display (4) holywar (4) nginx (4) pistol (4) spark (4) xml (4) Лебедев (4) IDE (3) IE8 (3) J2EE (3) NTFS (3) RDP (3) holiday (3) mount (3) Гоблин (3) кухня (3) урюк (3) AMQP (2) ERP (2) IE7 (2) NAS (2) Naudoc (2) PDF (2) address (2) air (2) british (2) coffee (2) fitness (2) font (2) ftp (2) fuckup (2) messaging (2) notify (2) sharepoint (2) ssl/tls (2) stardict (2) tests (2) tunnel (2) udev (2) APT (1) Baltic (1) CRUD (1) Canyonlands (1) Cyprus (1) DVDShrink (1) Jabber (1) K9Copy (1) Matlab (1) Portugal (1) VBA (1) WD My Book (1) autoit (1) bike (1) cannabis (1) chat (1) concurrent (1) dbf (1) ext4 (1) idioten (1) join (1) krusader (1) license (1) life (1) migration (1) mindmap (1) navitel (1) pneumatic weapon (1) quiz (1) regexp (1) robot (1) science (1) seaside (1) serialization (1) shore (1) spatial (1) tie (1) vim (1) Науру (1) крысы (1) налоги (1) пианино (1)