LINUX.ORG.RU

Сообщения energyclab

 

pytest и python setup.py test

Форум — Development

Всем добрый день, есть проблема, никак не могу написать stup.py чтобы тесты работыли. Итого, имеем: Структура проекта

/bin
/project
/tests
setup.cfg
setup.py

setup.cfg

[aliases]
test=pytest

[tool:pytest]
addopts = --verbose -s --cov=project --cov-report term-missing

setup.py

import os
import sys

from setuptools import setup, find_packages

PY_VER = sys.version_info

PACKAGE_TYPE = 'service'
PACKAGE_NAME = 'project'
PACKAGE_DESC = 'Service for tracking call info into DB'

if PY_VER < (3, 5):
    raise RuntimeError(
        "{} doesn't suppport Python earlier than 3.5".format(PACKAGE_NAME),
    )


# Что нужно для запуска python setup.py <any_cmd>
setup_requires = ['pytest-runner']

# Что нужно для установки
install_requires = []

# Что нужно для запуска python setup.py test
tests_require = ['pytest', 'pytest-cov', 'asynctest']

# Зависимости
dependency_links = []

# Скрипты
scripts = []

if PACKAGE_TYPE == 'service':
    scripts.append('bin/{}'.format(PACKAGE_NAME))

setup(
    name=PACKAGE_NAME,
    version='1.0',
    description=PACKAGE_DESC,
    long_description="",
    url='https://git.dev.uiscom.ru/{}/{}'.format(PACKAGE_TYPE, PACKAGE_NAME),
    author="...",
    author_email="...",
    license="Nodefined",
    classifiers=[
        'Development Status :: 5 - Production/Stable',
        'Environment :: Console',
        'Framework :: AsyncIO',
        'Framework :: Pytest',
        'Intended Audience :: Customer Service',
        'Intended Audience :: Information Technology',
        'License :: Other/Proprietary License',
        'Natural Language :: Russian',
        'Natural Language :: English',
        'Operating System :: POSIX',
        'Programming Language :: Python :: 3.5',
        'Topic :: Microservices',
    ],
    zip_safe=False,
    packages=find_packages(exclude=['tests']),
    scripts=scripts,
    python_requires='>=3.5',
    setup_requires=setup_requires,
    install_requires=install_requires,
    tests_require=tests_require,
    dependency_links=dependency_links,
)

Все это разворачивается в virtualenv. Если в нем установлены зависимости для тестов ('pytest', 'pytest-cov', 'asynctest') то тесты работают. Но на продакшене они мне не нужны, по-этому определил их в секцию tests_require. В итоге, когда проверяю

python setup.py test

Имею ошибку:

E       fixture 'event_loop' not found
>       available fixtures: bus, cache, capfd, capsys, cdr, cfg, cov, doctest_namespace, monkeypatch, pytestconfig, record_xml_property, recwarn, redis_pool, s_cdr, s_service, s_session, service, session, tmpdir, tmpdir_factory
>       use 'pytest --fixtures [testpath]' for help on them.

т.е. почему то не видит фикстуры event_loop... Не знаю что с этим делать...(пробовал вызывать python setup.py test после python setup.py [build|...] - не помогло)

 

energyclab
()

gstreamer1 транслирование rtp потока с кешированием

Форум — Development

Други, добрый день! Нужна помощь знатаков. Есть сервер генерации аудио потока по тексту (Разработка ЦРТ). Я ему запрос с текстом «Привет Мир!» а он мне по rtp играет мой текст. Этот сервак играет одновременно не более 10 потоков. У меня задача - закешировать rtp потоки. Написал сервер на python и заюзал gstreameer. Pipeline такие

play_rtp (когда не нашли в кеше текста, играем с сервака и кешируем)
caps такие: 'application/x-rtp,media=(string)audio, clock-rate=(int)8000, encoding-name=(string)PCMU, payload=(int)0'

udpsrc -> capsfilter(caps) -> tee -> queue -> udpsink  - транслируем
                         +  -> queue -> rtppcmudepay -> mulawdec -> audioconvert -> audioresample -> lamemp3enc -> filesink  - кешируем
play_file (когда нашли текст в кеше, играем из него)

здесь допом установлен mtu

filesrc -> mad -> audioconvert -> audioresample -> mulawenc -> rtppcmupay(mtu=172) -> udpsink

Проблема в том, что играю я все это в железку. Так первый pipeline проигрывается хорошо и сохраняется в файл. Второй (уже из файла) - проигрывается с некоторыми заиканиями... Я снял дамп на приемной стороне для обоих pipeline. Для первого каждый кадр всегда 172 байта. Во твором творился бардак от 10 до 1500 байт, в итоге, добавил параметр mtu = 172, качество проигрывания значительно улучшилось, но заикания все же есть. Дамп второго пайплайна показал 90% пакетов размером в 172 но есть и меньше (больших нет)... Подскажите, куда копать... может формат кеширования другой (пробовал с wav - еще хуже)

Вот код pipline

class Pipeline:

    def __init__(self, *a, **kw):
        self.pipeline = None
        self.current_elem = None

    @property
    def elements(self):
        ''' has to be iterable '''
        raise NotImplementedError()

    def configure(self, pipeline):
        self.current_elem = None
        for element in self.elements:
            pipeline.add(element)
            if self.current_elem:
                self.current_elem.link(element)
            self.current_elem = element
        return pipeline

    def start(self):
        self.pipeline = self.configure(Gst.Pipeline())
        ...


class PlayRtp(Pipeline):
    log = logging.getLogger('Play')
    caps = 'application/x-rtp,media=(string)audio, clock-rate=(int)8000, ' \
           'encoding-name=(string)PCMU, payload=(int)0'

    def __init__(self, in_host, in_port, out_host, out_port, tmp_path=None, *a, **kw):
        super().__init__(*a, **kw)
        self.in_host = in_host
        self.in_port = in_port
        self.out_host = out_host
        self.out_port = out_port
        self.tmp_path = tmp_path

    @property
    def elements(self):
        udpsrc = Gst.ElementFactory.make('udpsrc', 'udpsrc')
        udpsrc.set_property('address', self.in_host)
        udpsrc.set_property('port', self.in_port)
        yield udpsrc

        capsfilter = Gst.ElementFactory.make('capsfilter', 'capsfilter')
        capsfilter.set_property('caps', Gst.caps_from_string(self.caps))
        yield capsfilter

        udpsink = Gst.ElementFactory.make('udpsink', 'udpsink')
        udpsink.set_property('host', self.out_host)
        udpsink.set_property('port', self.out_port)
        if self.tmp_path:
            # transmit
            tee = Gst.ElementFactory.make('tee', 'tee')
            yield tee
            yield Gst.ElementFactory.make('queue', 'udp_queue')
            yield udpsink

            # save
            self.current_elem = tee
            yield Gst.ElementFactory.make('queue', 'write_queue')
            yield Gst.ElementFactory.make('rtppcmudepay', 'rtppcmudepay')
            yield Gst.ElementFactory.make('mulawdec', 'mulawdec')
            yield Gst.ElementFactory.make('audioconvert', 'audioconvert')
            yield Gst.ElementFactory.make('audioresample', 'audioresample')
            yield Gst.ElementFactory.make('lamemp3enc', 'lamemp3enc')
            filesink = Gst.ElementFactory.make('filesink', 'filesink')
            filesink.set_property('location', self.tmp_path)
            yield filesink
        else:
            # transmit
            yield udpsink

class PlayFile(Pipeline):
    log = logging.getLogger('Play')

    def __init__(self, host, port, path, mtu, *a, **kw):
        super().__init__(*a, **kw)
        self.host = host
        self.port = port
        self.path = path
        self.mtu = mtu

    @property
    def elements(self):
        filesrc = Gst.ElementFactory.make('filesrc', 'filesrc')
        filesrc.set_property('location', self.path)
        yield filesrc
        yield Gst.ElementFactory.make('mad', 'mad')
        yield Gst.ElementFactory.make('audioconvert', 'audioconvert')
        yield Gst.ElementFactory.make('audioresample', 'audioresample')
        yield Gst.ElementFactory.make('mulawenc', 'mulawenc')

        rtppcmupay = Gst.ElementFactory.make('rtppcmupay', 'rtppcmupay')
        rtppcmupay.set_property('mtu', self.mtu)
        yield rtppcmupay

        udpsink = Gst.ElementFactory.make('udpsink', 'udpsink')
        udpsink.set_property('host', self.host)
        udpsink.set_property('port', self.port)
        yield udpsink

 ,

energyclab
()

Неблокирующее логирование в python2

Форум — Development

Всем добрый день. Использую logging для логирования в продкшене. Но из-за нагрузки cpu подбирается к 100%, путем отладки выяснил, что больше всего тратится на IO операции. У меня все операции IO асинхронные (tornado), из синхронных только логирование (StreamHandler (stdout) и SyslogHandler) - они то и грузят cpu. Логов очень много, урезать не могу. В инете только nonblockingloghandler, но он не подходит, т.к. работает на тредах. Кто сталкивался с данной проблемой, как решал. Хотелось бы логи асинхронно писать либо вообще в другом процессе, но с наименьшими затратами на реализацию...

 

energyclab
()

Python, падение приложения

Форум — Development

Всем привет. Столкнулся с проблемой падения своего сервера.

Сервер это комбайн, который в зависимости от событий создает объекты (У них общий базовый класс) и передает между ними события. Все объекты создаются в одном и тоже потоке - uthread, функционируют они в нем же. Так же имеются несколько других потоков (одни для tornado (основной), другой для синхронного взаимодействия с платой (Queue) и третий для (входящих запросов))

Из удаленной консольки вижу мои потоки:

>>> >threading.enumerate()
'[<_MainThread(MainThread, started -1208498496)>,
 <Thread(uthread_0, started daemon 25316240)>,
 <Thread(Queue_0, started daemon 38382480)>,
 <Server(NetServer, started daemon 72010640)>]'

Для логирования использую logging где в конфиге указываю выводить имя потока, в котором производится вывод. 99 % нагрузки обрабатывается в uthread, там же объекты и удаляются сборщиком (__del__ показывет точное время удаления). Сервер долго крутиться, но иногда падает, и последнее, что я вижу в логах - это (смотри строки с Dummy-1)

 2016-02-03 12:11:19,145     INFO                <12:06:20 0xb4c59becL VA>   uthread_0            <12:06:27 0xb4c6a8acL Switch>  L{64:127} <- L{17:07}
 2016-02-03 12:11:19,146     INFO                <12:06:20 0xb4c59becL VA>   uthread_0            <12:06:27 0xb4c6a8acL Switch>  L{64:150} <- L{21:00}
 2016-02-03 12:11:19,147     INFO                <12:06:20 0xb4c59becL VA>   uthread_0  <12:11:19 0xb579944cL PostConversation>  Create post conversation:
 2016-02-03 12:11:19,148     INFO                <12:06:20 0xb4c59becL VA>   uthread_0  <12:11:19 0xb579944cL PostConversation>  {'a_call': <12:06:20 0xb4f0612cL Call_0x2c8c012f>,
 2016-02-03 12:11:19,148     INFO                <12:06:20 0xb4c59becL VA>   uthread_0  <12:11:19 0xb579944cL PostConversation>   'b_call': None,
 2016-02-03 12:11:19,149     INFO                <12:06:20 0xb4c59becL VA>   uthread_0  <12:11:19 0xb579944cL PostConversation>   'parent_operation_id': 37533}
 2016-02-03 12:11:19,149     INFO                <12:06:20 0xb4c59becL VA>   uthread_0  <12:11:19 0xb579944cL PostConversation>  a_call.state = connected
 2016-02-03 12:11:19,153     INFO                <12:06:20 0xb4c59becL VA>   uthread_0  <12:11:19 0xb579944cL PostConversation>  CREATED SUCCESSFULLY, parent = <12:06:20 0xb4c59becL VA>
 2016-02-03 12:11:19,153     INFO                <12:06:20 0xb4c59becL VA>   uthread_0            <12:06:27 0xb4c6a8acL Switch>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:11:19,154     INFO                <12:06:20 0xb4c59becL VA>   uthread_0              <12:06:26 0xb4cae7ecL Talk>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:11:19,164     INFO                <12:06:20 0xb4c59becL VA>   uthread_0  <12:11:19 0xb579944cL PostConversation>  Post session complete
 2016-02-03 12:11:19,297     INFO                <12:06:20 0xb4c59becL VA>   uthread_0   <22:58:23 0xb70b7decL 000408_IsdnLine>  NCCEVN_CALL_DISCONNECTED, value: 0 (call_hd = 0x2c8c012f) --> ['12:06:20 0xb4f0612cL Call_0x2c8c012f']
 2016-02-03 12:11:19,298     INFO                <12:06:20 0xb4c59becL VA>   uthread_0   <12:06:20 0xb4f0612cL Call_0x2c8c012f>  release_cause 16: Normal call clearing
 2016-02-03 12:11:19,301     INFO                <12:06:20 0xb4c59becL VA>   uthread_0   <22:58:23 0xb70b7decL 000408_IsdnLine>  NCCEVN_CALL_RELEASED, value: 0 (call_hd = 0x2c8c012f) --> ['12:06:20 0xb4f0612cL Call_0x2c8c012f']
 2016-02-03 12:11:19,313     INFO                <12:06:20 0xb4c59becL VA>   uthread_0  <12:11:19 0xb579944cL PostConversation>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:11:19,313     INFO                <12:06:20 0xb4c59becL VA>   uthread_0                <12:06:20 0xb4c59becL VA>  event stop_session: {'release_desc': 'no_operation', 'uuid': '64515124ca5511e5a114003048f81a82', 'release_cause_id': 16}
 2016-02-03 12:11:20,721     INFO                <12:06:20 0xb4c59becL VA>   uthread_0    <12:06:27 0xb4c5e6ecL TalkRecordTalk>  mix wave success: result = tmp/18926_talk_2016-02-03_12_06_27.081_talk.wav
 2016-02-03 12:11:22,767     INFO                <12:06:20 0xb4c59becL VA>   uthread_0    <12:06:27 0xb4c5e6ecL TalkRecordTalk>  Convert audio success: /var/comagic_storage/18926/talk/2016-02-03_12_06_27.081_from_74957885699_to_067685_talk.mp3
 2016-02-03 12:11:22,780     INFO                <12:06:20 0xb4c59becL VA>   uthread_0    <12:06:27 0xb4c5e6ecL TalkRecordTalk>  Save record success
 2016-02-03 12:11:22,781     INFO                <12:06:20 0xb4c59becL VA>   uthread_0                <12:06:20 0xb4c59becL VA>  event stop_talk_option: {'uuid': '6804443eca5511e5a114003048f81a82'}
 2016-02-03 12:11:22,783     INFO                <12:06:20 0xb4c59becL VA>   uthread_0   <12:06:21 0xb4f0e66cL Call_0x2c98013e>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:11:22,783     INFO                <12:06:20 0xb4c59becL VA>   uthread_0         <12:06:27 0xb4f006ccL ARecorder>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:11:22,784     INFO                <12:06:20 0xb4c59becL VA>   uthread_0         <12:06:27 0xb4c68eacL BRecorder>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:11:22,784     INFO                <12:06:20 0xb4c59becL VA>   uthread_0                <12:06:20 0xb4c59becL VA>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:11:22,784     INFO                <12:06:20 0xb4c59becL VA>   uthread_0   <12:06:20 0xb4f0612cL Call_0x2c8c012f>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:11:22,784     INFO                <12:06:20 0xb4c59becL VA>   uthread_0        <12:06:20 0xb4c6d68cL CrmHandler>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:11:22,785     INFO                <12:06:20 0xb4c59becL VA>   uthread_0    <12:06:27 0xb4c5e6ecL TalkRecordTalk>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:12:28,445     INFO                <12:06:20 0xb4c59becL VA>     Dummy-1            <12:06:20 0xb4c6deecL Dialer>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:12:28,447     INFO                <12:06:20 0xb4c59becL VA>     Dummy-1      <12:06:20 0xb4c4e1ccL dialer_timer>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:12:28,450     INFO                <12:06:20 0xb4c59becL VA>     Dummy-1            <12:06:20 0xb4c6e42cL Dialer>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:12:28,451     INFO                <12:06:20 0xb4c59becL VA>     Dummy-1      <12:06:20 0xb53fddccL dialer_timer>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:12:28,452     INFO                <12:06:20 0xb4c59becL VA>     Dummy-1            <12:06:20 0xb4c6d10cL Dialer>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:12:28,453     INFO                <12:06:20 0xb4c59becL VA>     Dummy-1      <12:06:21 0xb531a64cL dialer_timer>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:12:28,454     INFO                <12:06:20 0xb4c59becL VA>     Dummy-1            <12:06:20 0xb4c6e64cL Dialer>  DESTRUCTED SUCCESSFULLY
 2016-02-03 12:12:28,455     INFO                <12:06:20 0xb4c59becL VA>     Dummy-1      <12:06:20 0xb4e34facL dialer_timer>  DESTRUCTED SUCCESSFULLY

Поток с именем Dummy-1 у меня вообще не существует. В run time потоки не создаются (только при запуске 4 шт, которые я указал выше.)

Ума не приложу что делать и куда копать, прошу помощи.

 

energyclab
()

Переход от QScrollArea к QGraphicsView (Продолжение)

Форум — Development

Напомню проблему, которую решал в прошлый раз

Все стало очень круто работать, но вот наткнулся на проблему, которую никак не могу решить, итак, есть код

substrate = new QFrame();
substrate -> setObjectName("visitorListSubstrate");
areaFrameLay = new QVBoxLayout(substrate);
areaFrameLay -> setMargin(0);
areaFrameLay -> setSpacing(0);
areaFrameLay -> addStretch();

scene = new QGraphicsScene(this);
proxySubstrate = scene -> addWidget(substrate);
proxySubstrate -> setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

area = new QGraphicsView(scene, this);
area -> setObjectName("VisitorListArea");
area -> setAlignment(Qt::AlignLeft | Qt::AlignTop);
area -> setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
area -> verticalScrollBar() -> setObjectName("chatsScrollBar");

...


void MyClass::resizeEvent(QResizeEvent *e) {
    QFrame::resizeEvent(e);
    QSizeF  size = proxySubstrate -> size();
    size.setWidth(area -> width() - 9);
    proxySubstrate -> resize(size);
}

...
areaFrameLay -> insertWidget(index, item);

Вот в таком режиме все хорошо отображается, а содержимое подложки растягивается вместе с приложением, однако, в этом случае при добавлении ~ 1000 ячеек приложение падает с ошибкой

invalid parameter passed to c runtime function qt
Вижу, что происходит это в QtCore -> msvcr. Причем, если убрать обработку resizeEvent, то приложение работает отлично, но тогда у меня ячейки не растягиваются (а мне без этого никак)... М.б. есть какой то другой способ указать виджету на сцене, чтобы он занял все свободное пространство...

 

energyclab
()

Переход от QScrollArea к QGraphicsView

Форум — Development

Всем привет. Есть приложение, которое отображает большое кол-во (>1000) наследников QFrame. Для их отображения я выбрал QScrollArea, вот код

QFrame *substrate = new QFrame();
substrate -> setObjectName("visitorListSubstrate");
areaFrameLay = new QVBoxLayout(substrate);
areaFrameLay -> setMargin(0);
areaFrameLay -> setSpacing(1);
areaFrameLay -> addStretch();

area = new MyScrollArea();
area -> setObjectName("VisitorListArea");
area -> setWidget(substrate);
area -> setWidgetResizable(true);
area -> setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
area -> verticalScrollBar() -> setObjectName("chatsScrollBar");

...
for(auto item : items) {
    ...
    areaFrameLay -> insertWidget(index, item);
}
Пока ячеек было ~100, все было норм, но вот когда нагрузка возросла, то все стало тормозить. В итоге я начал профайлить приложение, сделал пару оптимизаций. Все стало как бы ок, но вот при добавлении 1000 ячеек, содержимое QScrollArea как бы прыгает... Стал гуглить и нагуглил, что лучше использовать QGraphicsView и QGraphicsScene, т.к. они перерисовывают только видимую часть... Пытался сделать переход на них, но у меня не получилось, точнее, после этого дергания пропали, все стало красиво и быстро, но получил две проблемы:

  • CSS не применяются к элементам внутри сцены (пришлось явно вызывать setStyleSheet для объектов). parent указать не смог объектам сцены, наткнулся на runtime ошибку
  • Ячейки приняли статический размер и не растягиваются вместе с самим QGraphicsView (а мне это нужно..)

Вот код, который я пробовал

scene = new QGraphicsScene(this);
area = new QGraphicsView(scene, this);

QFrame *substrate = new QFrame();
substrate -> setObjectName("visitorListSubstrate");
areaFrameLay = new QVBoxLayout(substrate);
areaFrameLay -> setMargin(0);
areaFrameLay -> setSpacing(1);
areaFrameLay -> addStretch();

scene -> addWidget(substrate)
Вот скрины, чтобы было понятно о чем речь было и стало Подскажите, что я делаю не так

 ,

energyclab
()

QTextEdit, Изменение высоты в зависимости от введенного текста

Форум — Development

Всем привет. Есть QTextEdit, размер высота которого позволяет вместить 3 строки введенного текста. Мне необходимо сделать так: до 10 строк необходимо увеличивать высоту едита, при числе строк > 10 высоту необходимо зафиксировать и показать скролбар... Вот код, который был изначально

text = textEdit -> toPlainText();
    int         endlCount = text.split("\n").size();
    if(endlCount < 3) {
        textEdit -> setFixedHeight(text_edit_height * 3 + text_edit_dist);
        textEdit -> setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    }
    if(endlCount >= 3 && endlCount <= 10) {
        int new_height = text_edit_height * endlCount + text_edit_dist;
        if(textEdit -> height() != new_height) {
            QScrollBar *bar = textBrowser -> verticalScrollBar();
            textEdit -> setFixedHeight(text_edit_height * endlCount + text_edit_dist);
            bar -> setSliderPosition(bar -> maximum());
        }
        textEdit -> setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    }
    if(endlCount > 10) {
        textEdit -> setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
    }
Беда в том, что, при вводе длинного текста без явного ввода \n, этот метод не работает. После, пробовал нагугленное решение, document() -> lineCount() и document() -> blockCount() в качестве кол-ва строк. Они тоже не отслеживают, когда новая появляется строка. т.е. если зажать какую-нибудь клавишу, то, по достижении границы эдита появится вторая строка, но этот факт я отследить не могу...Более того, окно можно растягивать и сужать, в этом случае тоже нужно выставлять правильный размер эдита... Подскажите, люди добрые!

 ,

energyclab
()

Расшариная очередь redis

Форум — Development

Всем привет. Собственно сабж:

#client.py

import redis
from pickle import dumps

r = redis.StrictRedis(host='localhost', port=6379)

r.publish('my-test-channel', dumps('some data1'))
r.publish('my-test-channel', dumps('some data2'))
r.publish('my-test-channel', dumps('some data3'))
r.publish('my-test-channel', dumps('some data4'))
r.publish('my-test-channel', dumps('some data5'))
и
# server.py

import redis
from pickle import loads

r = redis.StrictRedis(host='localhost', port=6379)
p = r.pubsub()
p.subscribe('my-test-channel')

try:
    for message in p.listen():
        if message['type'] == 'message':
            print loads(message['data']), type(loads(message['data']))
except KeyboardInterrupt:
    p.close()

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

 ,

energyclab
()

Celery, проверка результатов асинхронных задач

Форум — Development

Все привет. Собираюсь использовать в своем проекте celery, для выполнения некоторых задач. Хочется работы с объектами AsyncResult как с futures. Вот так я работаю с future

def future_wait(f, on_succ=None,
        on_failed=None, on_completed=None):
    def done_callback(f):
        if f.exception():
            if on_failed:
                on_failed(f.exception())
        else:
            if on_succ:
                on_succ(f.result())
        if on_completed:
            on_completed(f)

    f.add_done_callback(done_callback)
    return f

def done_callback(res):
    print res

def failed_callback(res):
    print res

f = do_some_task(...) # f - объект Future

future_wait(f, on_succ=done_callback, on_failed=failed_callback)
Если у future вызвать add_done_callback, то, как только результат таска будет получен, future сам вызовет мой callback. Таким образом, у меня все выполняется асинхронно. А вот в celery такой функции нету, и мне приходится писать некоторый костыль
class ResultKeeper(object):
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(ResultKeeper, cls).__new__(cls, *args, **kwargs)
        return cls._instance

    def __init__(self):
        self.lock = Lock()
        self.results = list()
        self.thread = Thread(target=self.loop)
        self.thread.daemon = True
        self.thread.start()

    def __call__(self, async_res, on_success=None, on_failue=None):
        with self.lock:
            async_res._callback = {states.SUCCESS: on_success,
                                   states.FAILURE: on_failue}
            self.results.append(async_res)

    @property
    def is_alive(self):
        return True

    def process_result(self, async_res):
        callback = async_res._callback.get(async_res.state)
        self.results.remove(async_res)
        if callable(callback):
            callback(async_res.result)

    def loop(self):
        while self.is_alive:
            with self.lock:
                for async_res in iter(self.results):
                    if async_res.ready():
                        self.process_result(async_res)
            sleep(0.2)

    def _remove(self, async_res):
        with self.lock:
            try:
                self.results.remove(async_res)
            except:
                pass


rk = ResultKeeper()
res=convert_audio.delay(src='dfbxdfb', dst='serg')
rk(res,
   on_success=done_callback,
   on_failue=failed_callback)

В loop мне приходится вызывать для каждого результата read(), и потом делать sleep на некоторое время... Мне этот sleep не нравится. Собственно сам вопрос, как избавиться от этого sleep?

 , ,

energyclab
()

Пункты в doc панели или что то сделать с треем

Форум — Development

Всем привет. Сортирую приложение под mac. Да вот выяснилась одна беда. В приложении у меня есть QSystemTrayIcon. Как выяснилось, в qt5.3 есть баг в этом классе. Трей показывается с глюками, в следствие для сборки под Мак я просто скрыл иконку трея (понадеялся на doc панель). У меня предопределено метрод closeEvent

void MainWindow::closeEvent(QCloseEvent * event) {
    if(!sender()) {
        // hide();
        windowHandle() -> hide();
        event -> ignore();
        notificationManager -> notify(QPixmap(":/notify/attention"),
                                      tr("<b>Программа переведена в фоновый режим</b>"),
                                      BG_ERROR,
                                      5,
                                      new BaseNotify());
        return;
    }

    for(auto component : components) {
        if(!component.instance -> canQuit()) {
            event -> ignore();
            return;
        }
    }
    event -> accept();
    qApp -> quit();
}

Когда был трей, я по двойному клику на него просто разворачивал приложение, если оно было спрятано... В стандартном doc меню моего приложения есть пункт «Скрыть», который меняется на «Показать», если я скрыл приложение через этот пункт мышкой... Но если я программно вызвал hide(), то этот пункт не меняется на «Показать», а остается «Скрыть», причем, если нажать «скрыть» а потом «Показать"Б то приложение так и не появляется... Уважаемые знатоки, подскажите как это побороть. Я думал, что можно как то программно вызвать метод скрыть, который дергает меню из doc панели, но не нашел такого

 , ,

energyclab
()

Пятница, QRegExp телефоны и email в тексте

Форум — Development

Все привет! Заранее извиняюсь за изъезженную тему, но что то мой мозг коротит, и я не понимаю как и что делать...

хочу примерно так:

QStringList Cls::findAllOccurrances(QString pattern, QString &text) {
    QRegExp rx(pattern);
    QStringList list;
    int pos = 0;

    while ((pos = rx.indexIn(text, pos)) != -1) {
        list << rx.cap(1);
        pos += rx.matchedLength();
    }
    return list;
}

QString text = "qewr asd@rty.com xdfgb\n sergseg serg 89993332211? xdf\n";  // Вообщем любой текст, где есть email и телефоны в разных форматах (беру из textEdit -> toPlainText())

qDebug() << findAllOccurrances("^([0-9\\(\\)\\/\\+ \\-]*)$", text);
qDebug() << findAllOccurrances(".+@.+\\..+", text);

1 - пусто 2 - выдает весь текст

А мне нужно список с самими значениями...

 , ,

energyclab
()

Qt elidedtext html

Форум — Development

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

QFontMetrics    fm = label -> fontMetrics()
QString elided = fm.elidedText("<span style='background-color: #fff200;'>He</span>llo wor<span style='background-color: #fff200;'>ld</span>", Qt::ElidedRight, label -> width());

отображался как в браузере (He - желтым, llo wor - обычным, ld - желтым), причем, если все не влазит, то обрезать и добавлять многоточия... Сейчас это так, а потом так

 

energyclab
()

Оптоволоконные сети, 100Мб на 1000Мб

Форум — Admin

Всем день добрый! Господа знатоки, просвятите пожалуйста в сетевых вопросах. Вообщем есть заказчик, у которого имеется где то 4000 рабочих мест, и, по ТЗ, ЛВС должна быть 100 мб-й оптикой. На такое количество машин они умудрились найти только карточки на чипсете BCM, обслуживаемым tg3 драйвером. Есть и другие карточки, но их не могут найти в нужном количестве. Нам же, как исполнителю, необходимы карточки на интеловском чипсете и 1000Мб (в силу определенных обстоятельств). Так вот, мы предложили им эти карты, но они нам заявили, что у них сеть не работает с 1Gb картами, мол оптику 1Gb сложно подружить с оптикой 100Mb. Подскажите пожалуйста, по какой схеме все-таки возможно сопряжение таких карт и подключение их в одну ЛВС? Понимаю,что наверное медиаконвертеры могут помочь, но ставить на каждую машину свой медиаконвертер - дорого...Может быть какие-нибудь свичи или их связка с каким-лиюо оборудованием...Повторю еще раз, все, что нам нужно: чтобы наши 1GB работали в их 100Mb сети...

energyclab
()

QTcpSocket win и странное поведение

Форум — Development

Все доброе утро! Столкнулся со следующей проблемой. Есть приложение, работающее на tcp сокетах. Все по классике: Подключение, прием/передача команд. После каждой выданной команды делаю flush. На 95% машин работает без проблем, однако есть машины, на которых каждый запуск приложения ведет себя по разному, поясню. Примерно каждый 3-4 запуск на запрос connect может не прийти никакого ответа -> как следствие, приложение не может подключиться, либо, прилетает конект, но следующая команда почему то дублируется, т.е. я выдаю одну строчку hello а в сеть улетает hellohello (смотрел через wireshark). Из-за таких проблем клиентам приходится запускать приложение на несколько раз... С чем это может быть связано? Работа с сокетом происходит следующим образом:

class TcpSocket : public QTcpSocket
{
    Q_OBJECT

    public:
        explicit TcpSocket(QObject *parent = 0);
        void sendData(QString, QMap<QString, QVariant> &, QString = "rpc", QString id = "", bool = true);
...

    public slots:
        void slotRecvData();

    private:
        void parseHeader(QString &);

    private:
        QString     data;
        int         totalSize;
        Logger      *log;
};

TcpSocket :: TcpSocket(QObject *parent) :
    QTcpSocket(parent),
    log(LogManager::get_logging()->get_logger("Network")) {
    connect(this, SIGNAL(readyRead()), SLOT(slotRecvData()));
    init_error_map();
}

void TcpSocket :: slotRecvData() {
    QString                     buf;
    QMap<QString, QVariant>     map;
    QJsonDocument               doc;

    log -> set_param("SESSION", "Server");

    while(this -> bytesAvailable())
        try {
            buf = this -> readAll();
            if(!data.isEmpty()) {
                data += buf;
            }
            else {
                parseHeader(buf);
            }

            while(true) {
                if(data.size() < totalSize) {
                    break;
                }
                else if(data.size() > totalSize) {
                    doc = QJsonDocument::fromJson(data.left(totalSize).toLocal8Bit().data());
                    log -> debug() << totalSize << "|" << doc.toJson().data() << '\n';
                    map = doc.toVariant().toMap();
                    emit dataReceived(map);
                    data = data.mid(totalSize);
                    parseHeader(data);
                }
                else {
                    doc = QJsonDocument::fromJson(data.toLocal8Bit().data());
                    log -> debug() << totalSize << "|" << doc.toJson().data() << '\n';
                    map = doc.toVariant().toMap();
                    emit dataReceived(map);
                    data.clear();
                    totalSize = 0;
                    break;
                }
            }
        }
        catch (NetworkHeaderException &s) {
            log -> error() << "Error while recv cmd: " << s.what() << '\n';
            log -> error() << "Ошибка данных сети: " << buf.toStdString() << "\n";
            data.clear();
            totalSize = 0;
            setSocketError(QAbstractSocket::ProxyConnectionRefusedError);
            disconnectFromHost();
            break;
        }
}

void TcpSocket :: sendData(QString cmd,
                           QMap<QString, QVariant> &params,
                           QString type,
                           QString id,
                           bool log_cmd) {
    QMap<QString, QVariant>     map;

    map["name"] = cmd;
    map["params"] = params;
    map["id"] = id;
    map["type"] = type;

    log -> set_param("SESSION", "Client");

    try {
        QVariant        jsonVariant(map);
        QString         jsonStr = QJsonDocument::fromVariant(jsonVariant).toJson();

        QByteArray      _data = jsonStr.toUtf8().data();

        _data.prepend("|");
        _data.prepend(QString::number(_data.size() - 1).toStdString().data());
        if(log_cmd) {
            log -> debug() << _data.data();
        }
        write(_data);
        flush();
    }
    catch (exception &e) {
        log -> error() << "Error while send cmd: " << e.what() << '\n';
    }
}

void TcpSocket :: parseHeader(QString &buf) {
    int index = buf.indexOf('|');
    if(index == -1) {
        throw NetworkHeaderException();
    }
    bool    res;
    totalSize = buf.left(index).toInt(&res);
    if(!res) {
        throw NetworkHeaderException();
    }
    data = buf.mid(index + 1);
}

 , ,

energyclab
()

QTextCursor и QProgressBar

Форум — Development

Есть QTextBrowser, заполняется он через QTextCursor методами insertText, insertHtml, insertBlock... Нужно добавить возможность отображать передавачу файла. Т.е. нужно сделать по аналогии со скайпом:

<время> <иконка> <название файла> <индикатор загрузки> <кол-во байт>

Я не понимаю, как впилить в QTextBrowser (через QTextCursor) этот индикатор. Кто подскажет?

 

energyclab
()

QTcpSocket и прозрачный прокси

Форум — Development

Все доброе утро! Недавно переписал свое приложение с pyqt4 на C++/Qt5. В своем приложении как и раньше использую унаследованный класс от QTcpSocket. Вот пример функции приема:

void TcpSocket :: slotRecvData() {
    QString                     buf;
    QMap<QString, QVariant>     map;
    QJsonDocument               doc;

    log -> set_param("SESSION", "Server");

    while(this -> bytesAvailable())
        try {
            buf = this -> readAll();
            if(!data.isEmpty()) {
                data += buf;
            }
            else {
                parseHeader(buf);
            }

            while(true) {
                if(data.size() < totalSize) {
                    break;
                }
                else if(data.size() > totalSize) {
                    doc = QJsonDocument::fromJson(data.left(totalSize).toLocal8Bit().data());
                    log -> debug() << totalSize << "|" << doc.toJson().data() << '\n';
                    map = doc.toVariant().toMap();
                    emit dataReceived(map);
                    data = data.mid(totalSize);
                    parseHeader(data);
                }
                else {
                    doc = QJsonDocument::fromJson(data.toLocal8Bit().data());
                    log -> debug() << totalSize << "|" << doc.toJson().data() << '\n';
                    map = doc.toVariant().toMap();
                    emit dataReceived(map);
                    data.clear();
                    totalSize = 0;
                    break;
                }
            }
        }
        catch (NetworkHeaderException &s) {
            log -> error() << "Error while recv cmd: " << s.what() << '\n';
            log -> error() << "Ошибка данных сети: " << buf.toStdString() << "\n";
            data.clear();
            totalSize = 0;
            setSocketError(QAbstractSocket::ProxyConnectionRefusedError);
            disconnectFromHost();
            break;
        }
}

void TcpSocket :: parseHeader(QString &buf) {
    int index = buf.indexOf('|');
    if(index == -1) {
        throw NetworkHeaderException();
    }
    bool    res;
    totalSize = buf.left(index).toInt(&res);
    if(!res) {
        throw NetworkHeaderException();
    }
    data = buf.mid(index + 1);
}

На питоне эта функция имеет такой же вид, но только синтаксис другой (Я это функцию просто переписал на плюсы). Проблема в следующем. Когда начали деплоить приложение, выяснилось, что у многих наших клиентов включен прозрачный прокси. Наше приложение работает по портам 80, 8080 и 443. Так вот, приложение подключается нормально, далее следует выдача первой команды, а в ответ прилетает http ответ 404. Но у нас свой протокол (не http - <size>|<payload>). Из-за этого приложение не может нормально работать. Если запускать тоже самое, но написанное на питоне, то приложение работает как надо...Совсем не понимаю в чем дело

 , , ,

energyclab
()

Qt deploy QMediaPlayer

Форум — Development

Всем привет. Прикрутил к своему приложению проигрывание wav файлов посредством QMediaPlayer (все как в примере в документации). Если запускаю приложение на машине с установленным qt (windows 7), то звук проигрывается как надо. Как только переношу прилжение на другую машину, получаю ошибку:

The QMediaPlayer object does not have a valid service

Qt-5.3.1. Пробовал помещать папку mediaservice рядом с приложением, не помогло...

 

energyclab
()

Qt5 QPainter и сглаживание

Форум — Development

Все привет!

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

Делаю так

    int count = get_new_messages_count();
    if(count) {
        QPixmap     pixmap(":/general/app_icon");
        QPainter    painter(&pixmap);
        QFont       font;
        QRect       rect;

        rect.setRect(pixmap.width() - 12, 0, 12, 12);
        painter.setRenderHint(QPainter::Antialiasing, true);
        painter.setRenderHint(QPainter::TextAntialiasing, true);
        font = painter.font();
        font.setPixelSize(7);
        painter.setFont(font);
        painter.setBrush(QColor(240, 58, 87));
        painter.setPen(Qt::NoPen);
        painter.drawEllipse(rect);
        painter.setPen(Qt::white);
        painter.drawText(rect, Qt::AlignCenter, QString::number(count));
        setWindowIcon(QIcon(pixmap));
    }
    else {
        setWindowIcon(QIcon(":/general/app_icon"));
    }

Иконка приложения в формате ico, залита в ресурсы. В меню «Пуск» отображается 16х16. Когда сообщений нет (т.е. я не рисую поверх иконки) иконка отображается отлично, однако, когда я рисую поверх нее круг с цыфрой, то новая иконка получается какая-то «пиксельная» (видно, что нет никакого сглаживания). Кто что может сказать, за раннее спасибо

 

energyclab
()

Новый синтаксис signal - slot не работает под виндой

Форум — Development

В продолжении моей предыдущей темы (которая кстати тоже пока не закрыта)

В процессе переноса qt приложения с linux под окна выяснились некоторые проблемы: QObject::connect не может теперь найти сигналы объектов, но только в том случае, если я свой сигнал определил в классе, унаследованном от QObject или его детей, и эта проблема касается только нового синтаксиса, т.е.

connect(btn, &QPushButton::clicked, this, &MainWindow::close);
Эта ситуация работает, а вот эта:
connect(obj, &MyObject::mySignal, this, &MainWindow::close);
не работает с ошибкой

qobject connect signal not found

А если заменить этот синтаксис на старый с макросами SIGNAL и SLOT, то все работает

Где то мне кажется я видел что это баг, но что то мне не верится , что к выходу 5.3.1 релиза эту штуку не пофиксили...

 ,

energyclab
()

Qt сборка проекта

Форум — Development

Всем привет, очень нужна помощь

Проект следующий

kernel - исполняемый, через qpluginloader грузит main_window: main_window - плагин (главное окно)? через qlugin_loader грузит различные плагины для работы: plugin1 ... pluginN - плагины, несущие бизнес логику приложения.

Ситуация следующая. Ядро загружается, выкачивает обновления, если они были (т.е. сами плагины) и запускает главный плагин main_window. Плагин main_window в зависимости от настроек загружает различные плагины для работы. Все это делается в реалтайме. Разработку вел на Linux Mint. Версия Qt 5.3.1.

Теперь пришло время собрать все под окнами. Открыл креатор, открыл все проекты, скомпилил (все без ошибки и с первого раза). Запускаю kernel, он грузится, что то выводит, но вот загрузить главный плагин не может со словами

Cannot load library path_to_plugin_main_window.dll не найден указанный модуль
После сборки дерево проектов такое
./app.exe
  log/
  plugins/
    libmain_window.a
    main_window.dll
    lib/
       libcommon.a
       common.dll
    components/
       component1/
          libcomponent1.a
          component1.dll
       ...
Под линухом все работает. Я посмотрел зависимости main_window.dll там не оказалось qt библиотек а так же dcomp.dll и библиотек msvcr... (хотя они стоят у меня и ядро загружается)

Кто подскажет куда мне смотреть? З.Ы. Все плагины юзают либу common.dll

energyclab
()

RSS подписка на новые темы