Как распространять программы на python

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

Распределение инструментов setuptools

Когда-то инструментом распространения для Python был distutils, но он не мог определить зависимости между пакетами. Setuptools — это его расширенная версия, которая может помочь нам лучше создавать и распространять пакеты Python, особенно пакеты со сложными зависимостями. Это восполняет этот недостаток, добавляя базовую зависимую систему и множество связанных функций. Он также предоставляет программу автоматического запроса пакетов для автоматического получения зависимостей между пакетами и завершения установки этих пакетов, что значительно снижает сложность установки различных пакетов и делает ее более удобной.

Обычная установка Python идет с setuptools, если нет, вы можете использовать pip для установки:

$ pip install setuptools

setuptools прост и удобен в использовании, просто напишите короткий установочный файл setup.py, чтобы упаковать приложение Python.

Первый установочный файл

Создайте новый установочный файл setup.py в каталоге learn_setup, а затем создайте пакет myapp для имитации пакета с исходным кодом:

. ├── myapp │ └── __init__.py └── setup.py

Содержимое простого файла setup.py выглядит следующим образом:

from setuptools import setup setup( name=’firstApp’, # Имя приложения version=’0.0.1′, # номер версии packages=[‘myapp’], # Python пакет включен в установочный пакет )

Создать колесо с установочным файлом

С помощью вышеуказанного файла setup.py мы можем открыть различные установочные пакеты, которые в основном делятся на две категории: sdist и bdist.

Source distribution

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

Format Description Notes
zip zip file (.zip) Windows по умолчанию
gztar gzip’ed tar file (.tar.gz) Unix по умолчанию
bztar bzip2’ed tar file (.tar.bz2)
xztar xz’ed tar file (.tar.xz)
ztar compressed tar file (.tar.Z)
tar tar file (.tar)

$ python setup.py sdist —formats=gztar,zip

Теперь в каталоге больше каталогов dist и * .egg-info. Сохраненные нами пакеты хранятся в dist. Приведенная выше команда использует —formats Назначенная игра .tar.gz с .zip Пакет, если он не указан, будет упакован в соответствии с форматом по умолчанию для конкретной платформы, как показано в приведенной выше таблице.

Название пакета setup.py Определено в name , version И указанный формат пакета, например: firstApp-0.0.1.tar.gz.

Built distribution

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

Календарь на python (питон) #short

Format Description Notes
gztar gzipped tar file (.tar.gz) Unix по умолчанию
bztar bzipped tar file (.tar.bz2)
xztar xzipped tar file (.tar.xz)
ztar compressed tar file (.tar.Z)
tar tar file (.tar)
zip zip file (.zip) Windows по умолчанию
rpm RPM
pkgtool Solaris pkgtool
sdux HP-UX swinstall
wininst self-extracting ZIP file for Windows
msi Microsoft Installer.

В использовании, как sdist, вы можете использовать —formats Укажите формат пакета. Такие как:

$ python setup.py bdist —formats=rpm

Чтобы упростить операцию, setuptools предоставляет следующие команды:

Command Formats Notes
bdist_dumb tar, gztar, bztar, xztar, ztar, zip Zip по умолчанию для Windows, gztar по умолчанию для Unix
bdist_rpm rpm, srpm
bdist_wininst wininst
bdist_msi msi

Таким образом, вышеупомянутый пакет rpm может быть использован:

$ python setup.py bdist_rpm

Если вы используете bdist_wininst, распечатывается установочный файл exe, вы можете нажать для установки.

Wheel

Колесо также является встроенной упаковкой и является официально рекомендованным способом упаковки. Может быть, вы встречали или использовали упаковку для яиц, но теперь рекомендуемый метод упаковки — колесо (https://wheel.readthedocs.io/en/stable/)。

Преимущества колесного пакета:

  • Faster installation for pure Python and native C extension packages.
  • Avoids arbitrary code execution for installation. (Avoids setup.py)
  • Installation of a C extension does not require a compiler on Windows or macOS.
  • Allows better caching for testing and continuous integration.
  • Creates .pyc files as part of installation to ensure they match the Python interpreter used.
  • More consistent installs across platforms and machines.

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

$ pip install wheel

Затем используйте bdist_wheel для упаковки:

$ python setup.py bdist_wheel

После успешного выполнения, в дополнение к каталогам dist и * .egg-info, существует также каталог сборки для хранения и упаковки промежуточных данных.

Имя пакета wheel — firstApp-0.0.1-py3-none-any.whl, где py3 указывает, что поддерживается только Python3.

Можно использовать параметры —universal , Имя пакета — mfirstApp-0.0.1-py2.py3-none-any.whl, что указывает на то, что пакет wheel поддерживает как Python2, так и Python3.

Читайте также:
Ошибка прекращена работа программы com surrogate

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

Установите колесо

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

# greet.py def hello(): print(‘Hello, welcome to setuptools!’)

После повторной упаковки с помощью bdist_wheel, мы можем использовать pip для установки в локальный каталог сайтов-пакетов Python.

$ pip install dist/fisrtApp-0.0.1-py3-none-any.whl

Теперь он используется так же, как и другие сторонние библиотеки, установленные с помощью pip:

from myapp.greet import hello hello()

Процесс разработки приложений будет часто меняться, и сначала сложно удалить старую версию для каждой установки. При установке с использованием режима разработки, сам код будет скопирован не в пакеты сайта, а на ссылку на текущее приложение (* .egg-link). Таким образом, изменения исходного кода в текущем местоположении будут немедленно отражены в пакетах сайта. Используйте следующим образом:

$ pip install -e. # или python setup.py development

Чтобы удалить, используйте pip uninstall 。

Загрузить Колесо в PyPI

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

Зарегистрировать учетную запись PyPI

авторизоваться https://pypi.python.org/pypiДля входа в учетную запись.

Установить шпагат

Хотя setuptools поддерживает использование setup.py upload Загружайте файлы пакетов в PyPI, но поддерживает только HTTP и заменяет новый шпагат.

Точно так же сначала нужно установить шпагат:

$ pip install twine

Загрузить с помощью шпагата

$ twine upload dist/*

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

[distutils] index-servers = pypi pypitest [pypi] username: password: [pypitest] repository: https://test.pypi.org/legacy/ username: password:

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

Вернитесь на домашнюю страницу PyPI, чтобы увидеть загруженное firstApp.

这里写图片描述

这里写图片描述

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

Выше приведено все содержимое упаковки и распространения Python, конечно же, самая простая функция. Более сложные упаковки, такие как фильтрация модулей, не-py-упаковка файлов, информация об авторах и другие общие требования, реализованы в setup() Внутри. Поэтому следующим шагом является подробное описание setup ().

параметры настройки ()

这里写图片描述

这里写图片描述

В приведенном выше установочном файле setup.py мы использовали некоторые параметры setup (): имя, версия, пакеты.

name

Имя проекта — это также имя, которое окончательно ищется в PyPI.

name = ‘firstApp’

version

Номер версии проекта, как правило, состоит из трех частей: ОСНОВНОЙ, МЕНЬШИЙ, ОБСЛУЖИВАНИЕ.
— MAJOR version when they make incompatible API changes,
— MINOR version when they add functionality in a backwards-compatible manner, and
— MAINTENANCE version when they make backwards-compatible bug fixes.

version=’0.0.1′

packages

Перечислите все пакеты, которые должны быть упакованы в проекте. Общего пользования setuptools.find_packages() Автоматическое обнаружение.

packages=find_packages(exclude=[‘contrib’, ‘docs’, ‘tests*’])

exclude Используется для исключения неупакованных пакетов.

description

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

description=’My first Python project’

Для полного описания проекта используйте long_description , Если эта строка в первом формате, PyPI автоматически отобразит ее в формате HTML. Уценку также можно указать.

long_description=long_description, long_description_content_type=’text/x-rst’

url

Обычно это ссылка на GitHub или ссылка на readthedocs. ,

url=’https://github.com/pypa/sampleproject’

Источник: russianblogs.com

Выбор интерпретатора для автономных приложений Python.

Обратите внимание, что если вы указываете интерпретатор, а затем распространяете архив приложения, то необходимо убедиться, что используемый интерпретатор является переносимым. Средство запуска Python для Windows поддерживает наиболее распространенные формы POSIX строки shebang — #! , но есть и другие вопросы для рассмотрения:

  • Если вы используете в исполняемом архиве строку интерпретатора /usr/bin/env python или другие формы команды python , такие как /usr/bin/python , то следует учитывать, что у пользователей по умолчанию может быть как Python 2, так и Python 3. В этом случае необходимо писать код для работы под обеими версиями.
  • Если вы используете явную версию, например /usr/bin/env python3 , ваше приложение не будет работать для пользователей, у которых нет этой версии. В этом случае необходимо сделать код совместимым с Python 2.
  • В исполняемом архиве невозможно указать интерпретатор как » python XY или более поздняя версия», поэтому нужно быть осторожным с использованием точной версии, например /usr/bin/env python3.7 , так как нужно будет менять строку shebang для того, чтобы запустить приложение для пользователей, у которых по умолчанию стоит Python 3.5.

Как правило, в исполняемых приложениях нужно использовать с качестве интерпретатора строку запуска /usr/bin/env python3 или /usr/bin/env python2 , в зависимости от того, написан ли ваш код для Python 3 или 2.

Напомним, что строка shebang в исполняемых архивах приложений указывается следующими способами.

Читайте также:
Графический планшет для cad программ

Из командной строки добавить строку #! в архив с указанием интерпретатора в качестве команды для запуска:

$ python -m zipapp myapp -o myapp.pyz -p «/usr/bin/env python3» $ ./myapp.pyz

Чтобы заменить строку shebang в существующем архиве, создайте измененный архив с помощью функции zipapp.create_archive() :

>>> import zipapp >>> zipapp.create_archive(‘old_archive.pyz’, ‘new_archive.pyz’, ‘/usr/bin/python3’)

  • КРАТКИЙ ОБЗОР МАТЕРИАЛА.
  • Интерфейс командной строки модуля zipapp.
  • Функции create_archive() модуля zipapp.
  • Функция get_interpreter() модуля zipapp.
  • Тонкости распространения исполняемых приложений Python.
  • Автономное приложение на Python с помощью zipapp.
  • Создание исполняемого Python файла для Windows.

Источник: docs-python.ru

Как написать, упаковать и распространить библиотеку на Python

Python — отличный язык программирования, но упаковка — одно из его самых слабых мест. Это общеизвестный факт в обществе. Установка, импорт, использование и создание пакетов значительно улучшились за эти годы, но они все еще не соответствуют новым языкам, таким как Go и Rust, которые многому научились в борьбе с Python и другими зрелыми языками.

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

Как написать библиотеку Python

В Python 3 есть отличный объект Path , который является огромным улучшением по сравнению с неудобным модулем os.path в Python 2. Но ему не хватает одной важной возможности — поиска пути к текущему сценарию. Это очень важно, если вы хотите найти файлы доступа относительно текущего скрипта.

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

Вот как вы это делаете в Python:

import pathlib script_dir = pathlib.Path(__file__).parent.resolve()

Чтобы получить доступ к файлу с именем «file.txt» в подкаталоге «data» каталога текущего скрипта, вы можете использовать следующий код:

print(open(str(script_dir/’data/file.txt’).read())

В пакете pathology у вас есть встроенный метод script_dir, и вы используете его следующим образом:

from pathology.Path import script_dir print(open(str(script_dir()/’data/file.txt’).read())

Да, это полный рот. Пакет патологии очень прост. Он наследует свой собственный класс Path от Pathlib библиотеки path и добавляет статический script_dir(), который всегда возвращает путь вызывающего скрипта.

Из-за кросс-платформенной реализации pathlib.Path вы можете наследовать непосредственно от него и должны наследовать от определенного подкласса ( PosixPath или WindowsPath ). Разрешение script_dir использует модуль проверки, чтобы найти вызывающую программу, а затем ее атрибут имени файла.

Более 2 миллионов тем и плагинов WordPress, веб-шаблонов и шаблонов электронной почты, наборов пользовательского интерфейса и многого другого

Загрузите тысячи тем и плагинов WordPress, веб-шаблонов, элементов пользовательского интерфейса и многое другое с членством в Envato Elements. Получите неограниченный доступ к растущей библиотеке из миллионов творческих и кодовых ресурсов.

Тестирование пакета патологии

import os import shutil from unittest import TestCase from pathology.path import Path class PathTest(TestCase): def test_script_dir(self): expected = os.path.abspath(os.path.dirname(__file__)) actual = str(Path.script_dir()) self.assertEqual(expected, actual) def test_file_access(self): script_dir = os.path.abspath(os.path.dirname(__file__)) subdir = os.path.join(script_dir, ‘test_data’) if Path(subdir).is_dir(): shutil.rmtree(subdir) os.makedirs(subdir) file_path = str(Path(subdir)/’file.txt’) content = ‘123’ open(file_path, ‘w’).write(content) test_path = Path.script_dir()/subdir/’file.txt’ actual = open(str(test_path)).read() self.assertEqual(content, actual)

Путь Python

Пакеты Python должны быть установлены где-то на пути поиска Python, чтобы их можно было импортировать модулями Python. Путь поиска Python представляет собой список каталогов и всегда доступен в sys.path . Вот мой текущий sys.path :

>>> print(‘n’.join(sys.path)) /Users/gigi.sayfan/miniconda3/envs/py3/lib/python36.zip /Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6 /Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/lib-dynload /Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/site-packages /Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/site-packages/setuptools-27.2.0-py3.6.egg

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

Вы также можете определить переменную среды PYTHONPATH и несколько других способов управления ею. Стандартные site-packages включены по умолчанию, и именно сюда идут пакеты, которые вы устанавливаете с помощью pip.

Как упаковать библиотеку Python

Теперь, когда у нас есть код и тесты, давайте упакуем их в соответствующую библиотеку. Python предоставляет простой способ через модуль установки. Вы создаете файл с именем setup.py в корневом каталоге вашего пакета.

Файлы setup.py содержат множество метаданных, таких как автор, лицензия, сопровождающие и другую информацию о пакете. Это в дополнение к элементу пакетов ( packages ), который использует функцию find_packages() , импортированную из setuptools , для поиска подпакетов.

Вот файл setup.py пакета патологии:

Исходный дистрибутив

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

Чтобы создать исходный дистрибутив (sdist), запустите: python setup.py sdist

Давайте создадим исходный дистрибутив:

$ python setup.py sdist running sdist running egg_info creating pathology.egg-info writing pathology.egg-info/PKG-INFO writing dependency_links to pathology.egg-info/dependency_links.txt writing top-level names to pathology.egg-info/top_level.txt writing manifest file ‘pathology.egg-info/SOURCES.txt’ reading manifest file ‘pathology.egg-info/SOURCES.txt’ writing manifest file ‘pathology.egg-info/SOURCES.txt’ warning: sdist: standard file not found: should have one of README, README.rst, README.txt running check creating pathology-0.1 creating pathology-0.1/pathology creating pathology-0.1/pathology.egg-info copying files to pathology-0.1. copying setup.py -> pathology-0.1 copying pathology/__init__.py -> pathology-0.1/pathology copying pathology/path.py -> pathology-0.1/pathology copying pathology.egg-info/PKG-INFO -> pathology-0.1/pathology.egg-info copying pathology.egg-info/SOURCES.txt -> pathology-0.1/pathology.egg-info copying pathology.egg-info/dependency_links.txt -> pathology-0.1/pathology.egg-info copying pathology.egg-info/not-zip-safe -> pathology-0.1/pathology.egg-info copying pathology.egg-info/top_level.txt -> pathology-0.1/pathology.egg-info Writing pathology-0.1/setup.cfg creating dist Creating tar archive removing ‘pathology-0.1’ (and everything under it)

Читайте также:
Лучшие программы для создания интеллект карт

Предупреждение связано с тем, что я использовал нестандартный файл README.md. Безопасно игнорировать. Приведенная выше команда создаст файл архива в формате по умолчанию для текущей операционной системы. Для систем Unix будет сгенерирован сжатый tar-файл в каталоге dist:

$ ls -la dist total 8 drwxr-xr-x 3 gigi.sayfan gigi.sayfan 102 Apr 18 21:20 . drwxr-xr-x 12 gigi.sayfan gigi.sayfan 408 Apr 18 21:20 .. -rw-r—r— 1 gigi.sayfan gigi.sayfan 1223 Apr 18 21:20 pathology-0.1.tar.gz

Если вы используете Windows, создается zip-файл.

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

python setup.py sdist —formats=gztar,zip

Например, приведенная выше команда создаст tar-архив, сжатый gzip, и zip-файл.

Доступны следующие форматы:

Бинарное распространение

Чтобы создать двоичный дистрибутив, называемый колесом, запустите: python setup.py bdist_wheel

$ python setup.py bdist_wheel running bdist_wheel running build running build_py creating build creating build/lib creating build/lib/pathology copying pathology/__init__.py -> build/lib/pathology copying pathology/path.py -> build/lib/pathology installing to build/bdist.macosx-10.7-x86_64/wheel running install running install_lib creating build/bdist.macosx-10.7-x86_64 creating build/bdist.macosx-10.7-x86_64/wheel creating build/bdist.macosx-10.7-x86_64/wheel/pathology copying build/lib/pathology/__init__.py -> build/bdist.macosx-10.7-x86_64/wheel/pathology copying build/lib/pathology/path.py -> build/bdist.macosx-10.7-x86_64/wheel/pathology running install_egg_info running egg_info writing pathology.egg-info/PKG-INFO writing dependency_links to pathology.egg-info/dependency_links.txt writing top-level names to pathology.egg-info/top_level.txt reading manifest file ‘pathology.egg-info/SOURCES.txt’ writing manifest file ‘pathology.egg-info/SOURCES.txt’ Copying pathology.egg-info to build/bdist.macosx-10.7-x86_64/wheel/pathology-0.1-py3.6.egg-info running install_scripts creating build/bdist.macosx-10.7-x86_64/wheel/pathology-0.1.dist-info/WHEEL

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

$ ls -la dist total 16 drwxr-xr-x 4 gigi.sayfan gigi.sayfan 136 Apr 18 21:24 . drwxr-xr-x 13 gigi.sayfan gigi.sayfan 442 Apr 18 21:24 .. -rw-r—r— 1 gigi.sayfan gigi.sayfan 2695 Apr 18 21:24 pathology-0.1-py3-none-any.whl -rw-r—r— 1 gigi.sayfan gigi.sayfan 1223 Apr 18 21:20 pathology-0.1.tar.gz

Чтобы глубже погрузиться в тему упаковки библиотек Python, можно ознакомиться информацией как писать собственные пакеты Python.

Как распространять пакет Python

Python имеет центральный репозиторий пакетов под названием PyPI (Python Packages Index). PyPI упрощает управление различными версиями пакетов. Например, если пользователю нужно установить определенную версию пакета, pip знает, где ее искать.

Когда вы устанавливаете пакет Python с помощью pip, он загружает пакет из PyPI (если вы не укажете другой репозиторий). Чтобы распространить наш пакет патологии, нам нужно загрузить его в PyPI и предоставить некоторые дополнительные метаданные, которые требуются PyPI. Шаги:

  • Обновите версию вашего пипса.
  • Создайте учетную запись на PyPI (только один раз).
  • Зарегистрируйте свой пакет.
  • Загрузите свой пакет.

Обновите версию вашего pip

Убедитесь, что в вашей операционной системе установлена последняя версия pip. Чтобы обновить pip, введите следующую команду

python3 -m pip install —upgrade pip

Завести аккаунт

Вы можете создать учетную запись на веб-сайте PyPI. Затем создайте файл .pypirc в своем домашнем каталоге:

[distutils] index-servers=pypi [pypi] repository = https://pypi.python.org/pypi username = the_gigi

В целях тестирования вы можете добавить индексный сервер pypitest в свой файл .pypirc:

[distutils] index-servers= pypi pypitest [pypitest] repository = https://testpypi.python.org/pypi username = the_gigi [pypi] repository = https://pypi.python.org/pypi username = the_gigi

Зарегистрируйте свой пакет

Если это первый выпуск вашего пакета, вам необходимо зарегистрировать его в PyPI. Используйте команду регистрации файла setup.py. Он попросит вас ввести пароль. Обратите внимание, что я указываю на тестовый репозиторий здесь:

$ python setup.py register -r pypitest running register running egg_info writing pathology.egg-info/PKG-INFO writing dependency_links to pathology.egg-info/dependency_links.txt writing top-level names to pathology.egg-info/top_level.txt reading manifest file ‘pathology.egg-info/SOURCES.txt’ writing manifest file ‘pathology.egg-info/SOURCES.txt’ running check Password: Registering pathology to https://testpypi.python.org/pypi Server response (200): OK

Загрузите свой пакет

Теперь, когда пакет зарегистрирован, мы можем его загрузить. Я рекомендую использовать twine, который более надежен. Установите его как обычно, используя pip install twine . Затем загрузите свой пакет с помощью twine и укажите свой пароль (отредактировано ниже):

$ twine upload -r pypitest -p dist/* Uploading distributions to https://testpypi.python.org/pypi Uploading pathology-0.1-py3-none-any.whl [================================] 5679/5679 — 00:00:02 Uploading pathology-0.1.tar.gz [================================] 4185/4185 — 00:00:01

Пакет теперь доступен на официальном сайте Pypi, как показано ниже.

Чтобы установить его с помощью pip, просто введите следующую команду:

pip install pathology

Чтобы глубже погрузиться в тему распространения ваших пакетов, необходимо ознакомьться с информацией как поделиться своими пакетами Python.

Вывод

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

Источник: dev-gang.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru