Skip to content

Commit

Permalink
Add asyncio dispatcher_callback
Browse files Browse the repository at this point in the history
  • Loading branch information
coretl committed May 14, 2021
1 parent e801a50 commit 4fb500e
Show file tree
Hide file tree
Showing 14 changed files with 366 additions and 152 deletions.
46 changes: 29 additions & 17 deletions .github/workflows/code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,36 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
python: [cp27, cp37, cp38, cp39]

include:
- os: macos-latest
TEST_REQUIRES: pytest-cov cothread
# Put coverage straight in the dist dir
COV_FILE: '{project}/dist/coverage.xml'
exclude:
- os: windows-latest
# No cothread or asyncio so doesn't work
python: cp27

include:
- os: ubuntu-latest
TEST_REQUIRES: pytest-cov cothread
# Put coverage in the output dir mounted in docker
COV_FILE: '/output/coverage.xml'
cov_file: /output/coverage.xml
test_requires: cothread pytest-asyncio aioca

- os: windows-latest
cov_file: '{project}/dist/coverage.xml'
# cothread doesn't work on windows
TEST_REQUIRES: pytest-cov
# Put coverage straight in the dist dir
COV_FILE: '{project}/dist/coverage.xml'
test_requires: pytest-asyncio aioca

- os: macos-latest
cov_file: '{project}/dist/coverage.xml'
test_requires: cothread pytest-asyncio aioca

- os: ubuntu-latest
python: cp27
# asyncio doesn't work on Python2.7
test_requires: cothread

- os: macos-latest
python: cp27
# asyncio doesn't work on Python2.7
test_requires: cothread


steps:
- name: Checkout Source
Expand All @@ -70,15 +84,16 @@ jobs:
run: cibuildwheel --output-dir dist
env:
CIBW_BUILD: ${{ matrix.python }}*64
CIBW_TEST_REQUIRES: ${{ matrix.TEST_REQUIRES }}
CIBW_TEST_COMMAND: pytest --cov=softioc {project}/tests --cov-report xml:${{ matrix.COV_FILE }}
CIBW_TEST_REQUIRES: pytest-cov ${{ matrix.test_requires }}
CIBW_TEST_COMMAND: pytest --cov=softioc {project}/tests --cov-report xml:${{ matrix.cov_file }}
# Disable auditwheel as it isn't compatible with setuptools_dso approach
# https://github.com/mdavidsaver/setuptools_dso/issues/17
CIBW_REPAIR_WHEEL_COMMAND: ''

- name: Upload Wheel and Sdist
uses: actions/upload-artifact@v2
with:
name: dist
path: dist/softioc*

- name: Upload coverage to Codecov
Expand All @@ -91,17 +106,14 @@ jobs:
needs: [build]
runs-on: ubuntu-latest
# upload to PyPI on every tag
#if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
steps:
- uses: actions/download-artifact@v2
with:
name: dist
path: dist

- name: Display structure of downloaded files
run: ls -R

- name: Publish to PyPI
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.pypi_token }}
Expand Down
2 changes: 2 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ sphinx-rtd-theme = "*"
sphinx-multiversion = {editable = true,git = "https://github.com/dls-controls/sphinx-multiversion.git",ref = "only-arg"}
setuptools-dso = "*"
aioca = "*"
pytest-asyncio = "*"

[packages]
# All other package requirements from setup.py
Expand All @@ -20,6 +21,7 @@ epicscorelibs = "*"
# Add some other useful extras
cothread = "*"
scipy = "*"
aioca = "*"

[scripts]
# Put coverage here so we don't interfere with debugging in the IDE
Expand Down
142 changes: 84 additions & 58 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions softioc/asyncio_callback.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import asyncio
import inspect
import threading


class AsyncioCallback(threading.Thread):
def __init__(self):
super().__init__()
self.loop = asyncio.new_event_loop()

def run(self):
self.loop.run_forever()

def __call__(self, func, *args):
async def async_wrapper():
ret = func(*args)
if inspect.isawaitable(ret):
await ret
asyncio.run_coroutine_threadsafe(async_wrapper(), self.loop)
28 changes: 20 additions & 8 deletions softioc/device.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
import os
import time
import traceback
import inspect
from ctypes import *
import numpy

import cothread

from . import alarm
from .fields import DbfCodeToNumpy, DbrToDbfCode
from .imports import dbLoadDatabase, recGblResetAlarms, db_put_field
from .device_core import DeviceSupportCore, RecordLookup


dispatcher_callback = None


def use_cothread():
import cothread
# Create our own cothread callback queue so that our callbacks
# processing doesn't interfere with other callback processing.
global dispatcher_callback
dispatcher_callback = cothread.cothread._Callback()


def use_asyncio():
from .asyncio_callback import AsyncioCallback
global dispatcher_callback
dispatcher_callback = AsyncioCallback()
dispatcher_callback.start()


class ProcessDeviceSupportCore(DeviceSupportCore, RecordLookup):
'''Implements canonical default processing for records with a _process
method. Processing typically either copies a locally set value into the
Expand Down Expand Up @@ -79,10 +95,6 @@ def get(self):
class ProcessDeviceSupportOut(ProcessDeviceSupportCore):
_link_ = 'OUT'

# Create our own cothread callback queue so that our callbacks processing
# doesn't interfere with other callback processing.
__Callback = cothread.cothread._Callback()

def __init__(self, name, **kargs):
on_update = kargs.pop('on_update', None)
on_update_name = kargs.pop('on_update_name', None)
Expand Down Expand Up @@ -133,7 +145,7 @@ def _process(self, record):

self._value = value
if self.__on_update and self.__enable_write:
self.__Callback(self.__on_update, value)
dispatcher_callback(self.__on_update, value)
return 0


Expand Down
Loading

0 comments on commit 4fb500e

Please sign in to comment.