Skip to content

Commit

Permalink
Improve code quality. Use pathlib. Use pytest for tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
sdiemer committed May 10, 2023
1 parent 263e6d3 commit 5d1a351
Show file tree
Hide file tree
Showing 24 changed files with 463 additions and 155 deletions.
6 changes: 3 additions & 3 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Run flake8 (pycodestyle + pyflakes) check.
# https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes
# Ignored errors:
# - E501: line too long
# - E265: block comment should start with '# ' (makes it easier to enable/disable code)
# - W503: line break before binary operator (deprecated rule)
# - W505: doc line too long

[flake8]
ignore = E501,E265,W503,W505
exclude = .git/,.virtualenv/,__pycache__/,build/,dist/
ignore = E265,W503,W505
max-line-length = 120
exclude = .git/,.virtualenv/,.eggs/,__pycache__/,build/,dist/,submodules/
11 changes: 5 additions & 6 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,12 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python3 -m pip install --upgrade pip
python3 -m pip install flake8
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install -e '.[dev]'
python3 setup.py install
- name: Lint code with Python ${{ matrix.python-version }}
- name: Check code with Python ${{ matrix.python-version }}
run: |
make lint
make lint_local
make deadcode_local
- name: Test code with Python ${{ matrix.python-version }}
run: |
make test
make test_local
19 changes: 14 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
PYFILES = mm_client/ examples/

all:

lint:
flake8 ${PYFILES}
docker run -v ${CURDIR}:/apps registry.ubicast.net/docker/flake8:latest make lint_local

lint_local:
flake8 .

deadcode:
docker run -v ${CURDIR}:/apps registry.ubicast.net/docker/vulture:latest make deadcode_local

deadcode_local:
vulture --exclude .eggs --min-confidence 90 .

test:
python3 -m unittest discover tests/ -v
docker run -v ${CURDIR}:/apps registry.ubicast.net/docker/pytest:latest make test_local

test_local:
pytest tests/ -vv --color=yes --log-level=DEBUG --cov=mm_client ${PYTEST_ARGS}

build: clean
python setup.py sdist bdist_wheel
Expand Down
43 changes: 35 additions & 8 deletions examples/fake_mediacoder.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
Fake MediaCoder client for tests.
'''
Expand All @@ -17,37 +16,65 @@ class FakeMediaCoder(MirisManagerClient):
DEFAULT_CONF = {
'CAPABILITIES': ['record', 'network_record', 'web_control', 'screenshot'],
}
PROFILES = {'main': {'has_password': False, 'can_live': False, 'name': 'main', 'label': 'Main', 'type': 'recorder'}}
PROFILES = {
'main': {
'has_password': False,
'can_live': False,
'name': 'main',
'label': 'Main',
'type': 'recorder'
}
}

def handle_action(self, action, params):
if action == 'START_RECORDING':
logger.info('Starting recording with params %s', params)
self.set_status(status='initializing', status_message='', remaining_space='auto')
self.set_status(
status='initializing',
status_message='',
remaining_space='auto'
)
time.sleep(3)
self.set_status(status='running', status_message='', status_info='{"playlist": "/videos/BigBuckBunny_320x180.m3u8"}', remaining_space='auto')
self.set_status(
status='running',
status_message='',
status_info='{"playlist": "/videos/BigBuckBunny_320x180.m3u8"}',
remaining_space='auto'
)

elif action == 'STOP_RECORDING':
logger.info('Stopping recording.')
self.set_status(status='ready', status_message='', remaining_space='auto')
self.set_status(
status='ready',
status_message='',
remaining_space='auto'
)

elif action == 'LIST_PROFILES':
logger.info('Returning list of profiles.')
return json.dumps(self.PROFILES)

elif action == 'GET_SCREENSHOT':
self.set_status(remaining_space='auto') # Send remaining space to Miris Manager
self.set_screenshot('/var/lib/AccountsService/icons/%s' % (os.environ.get('USER') or 'root'), file_name='screen.png')
self.set_screenshot(
path='/var/lib/AccountsService/icons/%s' % (os.environ.get('USER') or 'root'),
file_name='screen.png'
)
logger.info('Screenshot sent.')

else:
raise Exception('Unsupported action: %s.' % action)
raise NotImplementedError('Unsupported action: %s.' % action)


if __name__ == '__main__':
local_conf = sys.argv[1] if len(sys.argv) > 1 else None
client = FakeMediaCoder(local_conf)
client.update_capabilities()
client.set_status(status='ready', status_message='Ready to record', remaining_space='auto')
client.set_status(
status='ready',
status_message='Ready to record',
remaining_space='auto'
)
try:
client.long_polling_loop()
except KeyboardInterrupt:
Expand Down
8 changes: 5 additions & 3 deletions examples/miris_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,26 @@
}

# GENERATE ONE TIME TOKEN
# Data will be passed to the recorder and also prevents another user
# from accessing the system if a recording is already in progress
url = MM_URL + '/api/v3/users/create-token/'
data = {
'purpose': 'control',
'system': SYSTEM,
'data': json.dumps(user_info), # will be passed to the recorder and also prevents another user from accessing the system if a recording is already in progress
'data': json.dumps(user_info),
}
r = requests.post(url, headers=headers, data=data).json()
token = r['token']
#{'token': 'c8pse0v0gv312eg07m3vb29u6c78fcrlg5c1roo1', 'expires': '2022-01-14 02:56:13'}

# GENERATE FULL URL THE USER SHOULD BE 302ed to
# GENERATE FULL URL THE USER SHOULD BE REDIRECTED TO
params = {
'profile': 'myprofile',
'title': 'my title',
'location': 'Room A',
'live_title': 'my live title',
'channel': 'mscspeaker',
'logout_url': 'http://www.ubicast.eu', # you should probably redirect to the custom login page
'logout_url': 'https://example.com', # you should probably redirect to the custom login page
'token': token,
}

Expand Down
68 changes: 58 additions & 10 deletions examples/netcapture.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,48 @@


def get_status(session):
status_dict = s.get(URL + '/api/v3/fleet/systems/get-status/', headers=headers, params={'profile': PROFILE}).json()
status_dict = session.get(
URL + '/api/v3/fleet/systems/get-status/',
headers=headers,
params={'profile': PROFILE}
).json()
'''
status dict: {'last_status_update': '20200227112959', 'last_status_update_display': '2020-02-27 11:29:59', 'last_connection': '2020-02-27 11:29:57', 'profile': 'ndi', 'status': 'RUNNING', 'status_info': {'status_message': 'Recording in progress', 'audio': {'master': {'volume': 1.0, 'muted': False}}, 'video': [{'type': 'ndivsource', 'name': 'source-f41f', 'device': 'v4l-HDMI-1-pci-0000:01:00.0', 'capture': '1280x720@25', 'signal': 'fake'}], 'playlist': '/hls/944d/adaptive.m3u8', 'time_in_sec': 2, 'timecode': '0:00:02', 'record_folder': '/home/ubicast/mediacoder/media/20200227-112957-09bd'}, 'status_display': 'Recording in progress (profile: ndi)', 'remaining_space': 911891, 'remaining_time': 0, 'online': True, 'auto_refresh': False, 'screenshot_name': 'screenshots/ubi-box-e0d55ec52008_2020-02-27_10-30-00.jpg', 'screenshot_date': '2020-02-27 11:30:00', 'screenshot_outdated': False, 'messages_info': 20, 'messages_warning': 2, 'messages_error': 17, 'last_error_message': None, 'last_error_date': None}
status dict sample:
{
'last_status_update': '20200227112959',
'last_status_update_display': '2020-02-27 11:29:59',
'last_connection': '2020-02-27 11:29:57',
'profile': 'ndi',
'status': 'RUNNING',
'status_info': {
'status_message': 'Recording in progress',
'audio': {'master': {'volume': 1.0, 'muted': False}},
'video': [{
'type': 'ndivsource',
'name': 'source-f41f',
'device': 'v4l-HDMI-1-pci-0000:01:00.0',
'capture': '1280x720@25',
'signal': 'fake'
}],
'playlist': '/hls/944d/adaptive.m3u8',
'time_in_sec': 2,
'timecode': '0:00:02',
'record_folder': '/home/ubicast/mediacoder/media/20200227-112957-09bd'
},
'status_display': 'Recording in progress (profile: ndi)',
'remaining_space': 911891,
'remaining_time': 0,
'online': True,
'auto_refresh': False,
'screenshot_name': 'screenshots/ubi-box-e0d55ec52008_2020-02-27_10-30-00.jpg',
'screenshot_date': '2020-02-27 11:30:00',
'screenshot_outdated': False,
'messages_info': 20,
'messages_warning': 2,
'messages_error': 17,
'last_error_message': None,
'last_error_date': None
}
status_dict["status"] can contain:
"READY": idle
Expand All @@ -23,18 +62,23 @@ def get_status(session):
return status_dict.get('status')


with requests.Session() as s:
params = {
with requests.Session() as session:
data = {
'profile': PROFILE,
'async': 'no',
'action': 'START_RECORDING',
'speaker_email': 'user@domain.com',
'course_id': 'mscspeaker'
}
# list of mediaserver supported parameters here: https://sandbox.ubicast.tv/static/mediaserver/docs/api/api.html#api-v2-medias-add
# list of mediaserver supported parameters here:
# https://ubicast.tv/static/mediaserver/docs/api/api.html#api-v2-medias-add

print('Start recording')
response = s.post(URL + '/api/v3/fleet/control/run-command/', headers=headers, data=params).json()
response = session.post(
URL + '/api/v3/fleet/control/run-command/',
headers=headers,
data=data
).json()
#{'uid': '89b15583-7528-4c0c-a18e-28155be08d21', 'status': 'DONE', 'message': 'Recording started'}

if response.get('error'):
Expand All @@ -45,13 +89,17 @@ def get_status(session):
print(response.get('message'))
# can be UNAVAILABLE, READY, INITIALIZING, RUNNING
# https://mirismanager.ubicast.eu/static/docs/api/values.html
while not get_status(s) == 'RUNNING':
while not get_status(session) == 'RUNNING':
time.sleep(1)
if get_status(s) == 'UNAVAILABLE':
if get_status(session) == 'UNAVAILABLE':
print('Profile does not exist or no system is online')
sys.exit(1)
print('System is recording, stopping now')

print('Stop recording')
params['action'] = 'STOP_RECORDING'
s.post(URL + '/api/v3/fleet/control/run-command/', headers=headers, data=params)
data['action'] = 'STOP_RECORDING'
session.post(
URL + '/api/v3/fleet/control/run-command/',
headers=headers,
data=data
)
5 changes: 2 additions & 3 deletions examples/ping_server.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
Script to ping a Miris Manager server.
'''
import os
import sys
from pathlib import Path


if __name__ == '__main__':
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(str(Path(__file__).resolve().parent.parent))
from mm_client.client import MirisManagerClient

local_conf = sys.argv[1] if len(sys.argv) > 1 else None
Expand Down
5 changes: 2 additions & 3 deletions examples/poll_profile.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
Script to poll a profile status in a Miris Manager server.
The script is intended to be used with a user API key and not a system API key.
'''
import os
import sys
import time
from pathlib import Path


if __name__ == '__main__':
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(str(Path(__file__).resolve().parent.parent))
from mm_client.client import MirisManagerClient

local_conf = sys.argv[1] if len(sys.argv) > 1 else None
Expand Down
1 change: 0 additions & 1 deletion examples/recorder_controller.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
An example of Miris Manager client usage.
This script is intended to control a recorder.
Expand Down
6 changes: 4 additions & 2 deletions examples/screen_controller.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
An example of Miris Manager client usage.
This script is intended to send screenshot and handle click requests.
Expand Down Expand Up @@ -28,7 +27,10 @@ def handle_action(self, action, params):

elif action == 'GET_SCREENSHOT':
self.set_status(remaining_space='auto') # Send remaining space to Miris Manager
self.set_screenshot('/var/lib/AccountsService/icons/%s' % (os.environ.get('USER') or 'root'), file_name='screen.png')
self.set_screenshot(
path='/var/lib/AccountsService/icons/%s' % (os.environ.get('USER') or 'root'),
file_name='screen.png'
)
logger.info('Screenshot sent.')

elif action == 'SIMULATE_CLICK':
Expand Down
1 change: 0 additions & 1 deletion examples/send_message.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
Script to send a message
'''
Expand Down
1 change: 0 additions & 1 deletion examples/wol_relay.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
An example of Miris Manager client usage.
This script is intended to create devices acting as wake on lan relay and video displayer.
Expand Down
2 changes: 1 addition & 1 deletion mm_client/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '5.5'
__version__ = '6.0'
Loading

0 comments on commit 5d1a351

Please sign in to comment.