Структура проекта

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

    crawlersinfo/
    ├── conf
    ├── crawlersinfo
    │   ├── __init__.py
    │   ├── multitasking.py
    ├── crawlersinfo.egg-info
    │   ├── PKG-INFO
    │   ├── SOURCES.txt
    │   ├── dependency_links.txt
    │   ├── entry_points.txt
    │   ├── not-zip-safe
    │   └── top_level.txt
    ├── data
    │   └── countries.txt
    ├── scripts
    │   └── threading_worker.py
    ├── setup.cfg
    ├── setup.py
    └── tests
каталог содержание
conf файлы конфигурации
data входные и выходные данные; в нашем проекте там лежит файл с названиями стран countries.txt
scripts исполняемые скрипты
tests юнит-тесты
crawlersinfo библиотечные пакеты, название каталога совпадает с именем проекта
crawlersinfo.egg-info генерируется утилитой setuptools

Сгенерировать "болванку" проекта, совместимого с setuptools и pip, помогает утилита paster 1. Вот как выглядела сессия для проекта crawlersinfo:

Сессия Paster

$ paster create crawlersinfo
Selected and implied templates:
  PasteScript#basic_package  A basic setuptools-enabled package

Variables:
  egg:      crawlersinfo
  package:  crawlersinfo
  project:  crawlersinfo
Enter version (Version (like 0.1)) ['']: 0.1
Enter description (One-line description of the package) ['']: Uilities for scraping web pages
Enter long_description (Multi-line description (in reST)) ['']: Utilities for scraping web pages based on Requests library.   
Enter keywords (Space-separated keywords/tags) ['']: scraper web-crawler
Enter author (Author name) ['']: Sergey Krushinsky
Enter author_email (Author email) ['']: МОЙ ИМЕЙЛ
Enter url (URL of homepage) ['']: http://crawlers.info
Enter license_name (License name) ['']: Apache 2
Enter zip_safe (True/False: if the package can be distributed as a .zip file) [False]: 
Creating template basic_package
Creating directory ./crawlersinfo
  Recursing into +package+
    Creating ./crawlersinfo/crawlersinfo/
    Copying __init__.py to ./crawlersinfo/crawlersinfo/__init__.py
  Copying setup.cfg to ./crawlersinfo/setup.cfg
  Copying setup.py_tmpl to ./crawlersinfo/setup.py
Running /Users/sergey/env/bin/python setup.py egg_info

Теперь надо создать каталоги tests, conf и data 2.

$ cd crawlersinfo/
$ mkdir scripts tests conf data

Установочный скрипт setup.py

Сразу же редактируем файл setup.py. Он понадобится для установки пакета и обновления его версий.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from setuptools import setup, find_packages
import sys, os

version = '0.1'

setup(name='crawlersinfo',
      version=version,
      description="Uilities foer scraping web pages",
      long_description="""\
Utilities for scraping web pages based on Requests library.""",
      classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
      keywords='scraper web-crawler',
      author='Sergey Krushinsky',
      author_email='krushinsky@gmail.com',
      url='http://crawlers.info',
      license='Apache 2',
      packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
      include_package_data=True,
      zip_safe=False,
      install_requires=[
          # -*- Extra requirements: -*-
          'requests',
          'beautifulsoup4',          
      ],
      tests_require=['nose>=1.0'],
      scripts=['scripts/threading_worker.py',],
      entry_points="""
      # -*- Entry points: -*-
      """,
      )

Зависимости

Первое, что необходимо сделать — это прописать зависимости. Для этого служит список install_requires. В число зависимостей входят, как минимум, BeautifulSoup и Requests. По мере добавления новых внешних библиотек к модулям проекта, их надо будет регистрировать в том же списке.

Список tests_requires содержит библиотеки, которые потребуются для тестирования. В нашем случае это nose.

Исполняемые файлы

В списке scripts прописываются скрипты, которыми люди могут пользоваться. Если создается библиотека, том могут быть демонстрационные программки, наподобие threading_worker.py.

Для того, чтобы скрипт "видел" библиотеки проекта, в sys.path нужно добавить путь к crawlersinfo.

Стандартный прием: использовать его свойство __file__ и методы модуля os. Например:

import sys, os

ROOTDIR = os.path.dirname(os.path.dirname(__file__)) 
sys.path.append(ROOTDIR)

Но такой подход не сработает если модуль установлен в системе посредством setuptools. Надежнее использовать специальные методы setuptools. См. Package Discovery and Resource Access....

Поэтому предыдущий фрагмент лучше заменить вот таким заклинанием:

import sys
from pkg_resources import resource_filename

ROOTDIR = resource_filename(__name__, '../')
sys.path.append(ROOTDIR)

...То же самое относится к каждому скрипту юнит-теста, созданному в каталоге tests.

Установка

Из директории проекта:

$ sudo pip install -e .
Password:
Obtaining file:///.../crawlersinfo
Requirement already satisfied (use --upgrade to upgrade): requests in /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages (from crawlersinfo===0.1dev-r0)
Collecting beautifulsoup4 (from crawlersinfo===0.1dev-r0)
  Downloading beautifulsoup4-4.4.1-py2-none-any.whl (81kB)
    100% |████████████████████████████████| 81kB 1.8MB/s 
Installing collected packages: beautifulsoup4, crawlersinfo
  Running setup.py develop for crawlersinfo
Successfully installed beautifulsoup4-4.4.1 crawlersinfo

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

Обратите внимание на ключ -e. Он оставляет файлы проекта на месте вместо того, чтобы копировать их в системные каталоги, как при стандартной установке. В последних создаются лишь линки на текущие файлы. Это избавляет от необходимости многократно переустанавливать пакет в ходе работы над проектом.

    

...Здесь сказано далеко не все, что необходимо знать о работе с setuptools. Но достаточно, чтобы создать проект с нуля. В дальнейшем, какие бы проекты ни создавались, я буду придерживаться аналогичной схемы.

        


  1. В разных дистрибутивах эта утилита называется по-разному. В Debian-овских пакетах: python-pastescript

  2. Мне надоело делать это руками, но создание шаблонов для Paster-а — задача нетривиальная. 

social

Яндекс.Метрика