Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closes #1163 Running Tests on OSX/Windows #1164

Closed
wants to merge 5 commits into from

Conversation

programatt
Copy link

Update documentation for instructions on how to run tests locally on OSX. Fix conftest.py to not error when running pytest on OSX and Windows.

Description

When attempting to run pytest on my macbook, I ran into an issue on startup where the config_server throws a strange error.

W 01-20 03:15:11.281 Problem with get_config: ConnectionError(MaxRetryError("HTTPConnectionPool(host='localhost', port=6563): Max retries exceeded with url: /get-config (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x160521490>: Failed to establish a new connection: [Errno 61] Connection refused'))"))
I 01-20 03:15:11.285 Setting up the config server.
I 01-20 03:15:11.285 Starting panoptes-config-server with  config_file='tests/testing.yaml'
S 01-20 03:15:11.337 Config server Loaded 15 top-level items
S 01-20 03:15:11.337 {'name': 'Testing PANOPTES Unit', 'pan_id': 'PAN000', 'pocs': ordereddict([('INITIALIZED', False), ('CONNECTED', False), ('INTERRUPTED', False)]), 'location': ordereddict([('name', 'Mauna Loa Observatory'), ('latitude', <Quantity 19.54 deg>), ('longitude', <Quantity -155.58 deg>), ('elevation', <Quantity 3400. m>), ('horizon', <Quantity 30. deg>), ('flat_horizon', <Quantity -6. deg>), ('focus_horizon', <Quantity -12. deg>), ('observe_horizon', <Quantity -18. deg>), ('obstructions', []), ('timezone', 'US/Hawaii'), ('gmt_offset', -600)]), 'directories': ordereddict([('base', '/Users/matt/code/POCS'), ('images', '/Users/matt/code/POCS/images'), ('data', '/Users/matt/code/POCS/data'), ('resources', '/Users/matt/code/POCS/resources'), ('fields', '/Users/matt/code/POCS/conf_files/fields'), ('mounts', '/Users/matt/code/POCS/resources/mounts')]), 'db': ordereddict([('name', 'panoptes_testing'), ('type', 'file')]), 'scheduler': ordereddict([('type', 'panoptes.pocs.scheduler.dispatch'), ('fields_file', 'simulator.yaml'), ('check_file', False), ('iers_url', 'https://storage.googleapis.com/panoptes-resources/iers/ser7.dat'), ('constraints', [ordereddict([('name', 'panoptes.pocs.scheduler.constraint.Altitude')]), ordereddict([('name', 'panoptes.pocs.scheduler.constraint.MoonAvoidance'), ('options', ordereddict([('separation', 15)]))]), ordereddict([('name', 'panoptes.pocs.scheduler.constraint.Duration')])])]), 'mount': ordereddict([('brand', 'ioptron'), ('model', 'cem40'), ('driver', 'panoptes.pocs.mount.simulator'), ('serial', ordereddict([('port', '/dev/ttyUSB0'), ('timeout', 0.0), ('baudrate', 9600)])), ('non_sidereal_available', True)]), 'pointing': ordereddict([('auto_correct', True), ('threshold', 500), ('exptime', 30), ('max_iterations', 1)]), 'cameras': ordereddict([('defaults', ordereddict([('primary', 'None'), ('auto_detect', False), ('file_extension', 'fits'), ('compress_fits', True), ('make_pretty_images', True), ('keep_jpgs', False), ('readout_time', 0.5), ('timeout', 10), ('filter_type', 'RGGB'), ('cooling', ordereddict([('enabled', True), ('temperature', ordereddict([('target', 0), ('tolerance', 0.1)])), ('stable_time', 60), ('check_interval', 5), ('timeout', 300)])), ('focuser', ordereddict([('enabled', True), ('autofocus_seconds', 0.1), ('autofocus_size', 500), ('autofocus_keep_files', False)]))])), ('devices', [ordereddict([('model', 'panoptes.pocs.camera.simulator.dslr.Camera'), ('name', 'dslr.00'), ('port', '/dev/fake/dslr.00'), ('readout_time', 0.5)]), ordereddict([('model', 'panoptes.pocs.camera.simulator.dslr.Camera'), ('name', 'dslr.focuser.cooling.00'), ('port', '/dev/fake/dslr.focuser.cooling.00'), ('cooling', ordereddict([('enabled', True), ('target', 1), ('tolerance', 0.1), ('stable_time', 1), ('check_interval', 0.5), ('timeout', 2.5)])), ('focuser', ordereddict([('model', 'panoptes.pocs.focuser.simulator.Focuser'), ('focus_port', '/dev/fake/focuser.00'), ('initial_position', 20000), ('autofocus_range', [40, 80]), ('autofocus_step', [10, 20]), ('autofocus_seconds', 0.1), ('autofocus_size', 500), ('autofocus_keep_files', False)]))]), ordereddict([('model', 'panoptes.pocs.camera.simulator.dslr.Camera'), ('name', 'dslr.filterwheel.cooling.00'), ('port', '/dev/fake/dslr.filterwheel.cooling.00'), ('cooling', ordereddict([('enabled', True), ('target', 0), ('tolerance', 0.1), ('stable_time', 60), ('check_interval', 5), ('timeout', 300)])), ('filterwheel', ordereddict([('model', 'panoptes.pocs.filterwheel.simulator.FilterWheel'), ('filter_names', ['one', 'deux', 'drei', 'quattro', 'blank']), ('move_time', 0.1), ('timeout', 0.5)]))]), ordereddict([('model', 'panoptes.pocs.camera.simulator.ccd.Camera'), ('name', 'ccd.filterwheel.focuser.cooling.00'), ('serial_number', 'ccd.filterwheel.focuser.cooling.00'), ('cooling', ordereddict([('enabled', True), ('target', 0), ('tolerance', 0.1), ('stable_time', 60), ('check_interval', 5), ('timeout', 300)])), ('focuser', ordereddict([('model', 'panoptes.pocs.focuser.simulator.Focuser'), ('focus_port', '/dev/fake/focuser.00'), ('initial_position', 20000), ('autofocus_range', [40, 80]), ('autofocus_step', [10, 20]), ('autofocus_seconds', 0.1), ('autofocus_size', 500), ('autofocus_keep_files', False)])), ('filterwheel', ordereddict([('model', 'panoptes.pocs.filterwheel.simulator.FilterWheel'), ('filter_names', ['one', 'deux', 'drei', 'quattro', 'blank']), ('move_time', 0.1), ('timeout', 0.5), ('dark_position', 'blank'), ('focus_offsets', ordereddict([('one', 0), ('deux', 1), ('drei', 2), ('quattro', 3)]))]))])])]), 'observations': ordereddict([('make_timelapse', True), ('record_observations', True)]), 'panoptes_network': ordereddict([('image_storage', True), ('service_account_key', None), ('project_id', 'panoptes-survey'), ('buckets', ordereddict([('images', 'panoptes-survey')]))]), 'state_machine': 'panoptes', 'environment': ordereddict([('auto_detect', True)]), 'weather': ordereddict([('aag_cloud', ordereddict([('serial_port', '/dev/ttyUSB1')]))]), 'config_server': {'running': True}}
I 01-20 03:15:11.337 Config items saved to flask config-server
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "/Users/matt/code/venvs/pocs/lib/python3.9/site-packages/_pytest/main.py", line 265, in wrap_session
INTERNALERROR>     config._do_configure()
INTERNALERROR>   File "/Users/matt/code/venvs/pocs/lib/python3.9/site-packages/_pytest/config/__init__.py", line 982, in _do_configure
INTERNALERROR>     self.hook.pytest_configure.call_historic(kwargs=dict(config=self))
INTERNALERROR>   File "/Users/matt/code/venvs/pocs/lib/python3.9/site-packages/pluggy/_hooks.py", line 277, in call_historic
INTERNALERROR>     res = self._hookexec(self.name, self.get_hookimpls(), kwargs, False)
INTERNALERROR>   File "/Users/matt/code/venvs/pocs/lib/python3.9/site-packages/pluggy/_manager.py", line 80, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>   File "/Users/matt/code/venvs/pocs/lib/python3.9/site-packages/pluggy/_callers.py", line 60, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>   File "/Users/matt/code/venvs/pocs/lib/python3.9/site-packages/pluggy/_result.py", line 60, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/Users/matt/code/venvs/pocs/lib/python3.9/site-packages/pluggy/_callers.py", line 39, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/Users/matt/code/POCS/conftest.py", line 65, in pytest_configure
INTERNALERROR>     config_server(config_file, host=host, port=port, load_local=False, save_local=False)
INTERNALERROR>   File "/Users/matt/code/venvs/pocs/lib/python3.9/site-packages/panoptes/utils/config/server.py", line 117, in config_server
INTERNALERROR>     server_process.start()
INTERNALERROR>   File "/opt/homebrew/Cellar/python@3.9/3.9.9/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/process.py", line 121, in start
INTERNALERROR>     self._popen = self._Popen(self)
INTERNALERROR>   File "/opt/homebrew/Cellar/python@3.9/3.9.9/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/context.py", line 224, in _Popen
INTERNALERROR>     return _default_context.get_context().Process._Popen(process_obj)
INTERNALERROR>   File "/opt/homebrew/Cellar/python@3.9/3.9.9/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/context.py", line 284, in _Popen
INTERNALERROR>     return Popen(process_obj)
INTERNALERROR>   File "/opt/homebrew/Cellar/python@3.9/3.9.9/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/popen_spawn_posix.py", line 32, in __init__
INTERNALERROR>     super().__init__(process_obj)
INTERNALERROR>   File "/opt/homebrew/Cellar/python@3.9/3.9.9/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/popen_fork.py", line 19, in __init__
INTERNALERROR>     self._launch(process_obj)
INTERNALERROR>   File "/opt/homebrew/Cellar/python@3.9/3.9.9/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/popen_spawn_posix.py", line 47, in _launch
INTERNALERROR>     reduction.dump(process_obj, fp)
INTERNALERROR>   File "/opt/homebrew/Cellar/python@3.9/3.9.9/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/reduction.py", line 60, in dump
INTERNALERROR>     ForkingPickler(file, protocol).dump(obj)
INTERNALERROR> AttributeError: Can't pickle local object 'config_server.<locals>.start_server'

Doing some searching it looks like python 3.8 on OSX changed to use spawn instead of fork for processes by default. See pytest-dev/pytest-flask#104 (comment)

So I modified conftest to detect the OS and change the behavior on windows and osx and the pytest command runs as expected.

Related Issue

#1163

How Has This Been Tested?

The changes allowed pytest to run successfully on a mac

Screenshots (if appropriate):

n/a

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.


# Windows and OSX use spawn instead of fork by default
# which causes the config server to fail to start
if platform == "darwin" or platform == "win32":
Copy link
Author

@programatt programatt Jan 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could make the argument that this belongs in the config server code in panoptes-utils instead. @wtgee let me know if you'd rather see it over there.

Copy link
Member

@wtgee wtgee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @programatt, I just approved your first-time contribution so the tests are running now.

Can you add windows and mac to the matrix.os in .github/workflows/pythontest.yaml as part of this PR?

README.md Outdated Show resolved Hide resolved
@codecov
Copy link

codecov bot commented Jan 20, 2022

Codecov Report

Merging #1164 (9953291) into develop (4908119) will decrease coverage by 4.76%.
The diff coverage is 60.30%.

❗ Current head 9953291 differs from pull request most recent head 402350b. Consider uploading reports for the commit 402350b to get more accurate results
Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1164      +/-   ##
===========================================
- Coverage    83.08%   78.32%   -4.77%     
===========================================
  Files           86       89       +3     
  Lines         7425     7634     +209     
  Branches       635      717      +82     
===========================================
- Hits          6169     5979     -190     
- Misses        1083     1492     +409     
+ Partials       173      163      -10     
Impacted Files Coverage Δ
src/panoptes/pocs/camera/gphoto/remote.py 0.00% <0.00%> (-21.57%) ⬇️
...rc/panoptes/pocs/scheduler/observation/compound.py 0.00% <0.00%> (ø)
src/panoptes/pocs/sensor/power.py 40.23% <0.00%> (-1.74%) ⬇️
...rc/panoptes/pocs/state/states/default/analyzing.py 5.88% <0.00%> (-54.12%) ⬇️
src/panoptes/pocs/state/states/default/tracking.py 6.66% <0.00%> (-76.67%) ⬇️
src/panoptes/pocs/utils/cli/main.py 0.00% <0.00%> (-70.00%) ⬇️
src/panoptes/pocs/utils/logger.py 100.00% <ø> (ø)
src/panoptes/pocs/utils/service/power.py 0.00% <0.00%> (-66.67%) ⬇️
tests/test_observatory.py 96.28% <ø> (+0.66%) ⬆️
...rc/panoptes/pocs/state/states/default/observing.py 14.28% <16.66%> (-61.91%) ⬇️
... and 55 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 64107a4...402350b. Read the comment docs.

programatt and others added 2 commits January 20, 2022 17:58
Co-authored-by: Wilfred Tyler Gee <wtylergee@gmail.com>
@programatt
Copy link
Author

@wtgee anything else needed?

Copy link
Member

@wtgee wtgee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, although the macos tests are failing on install. Looks like they are using python 2.7 by default? Which is odd. Must be how the interpreter needs to be specified or something.

strategy:
matrix:
python-version: [ "3.10" ]
python-version: [ "3.10" ]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Editor not trimming whitespace?

Comment on lines +24 to +25


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were these editor added or intentional?

Suggested change

@programatt
Copy link
Author

@wtgee looks like the mac tests are now failing with this error

___________ ERROR collecting src/panoptes/pocs/filterwheel/libefw.py ___________
src/panoptes/pocs/filterwheel/libefw.py:12: in <module>
    class EFWDriver(AbstractSDKDriver):
src/panoptes/pocs/filterwheel/libefw.py:15: in EFWDriver
    _libudev = load_c_library('udev', mode=ctypes.RTLD_GLOBAL)
/usr/local/lib/python3.9/site-packages/panoptes/utils/library.py:39: in load_c_library
    raise error.NotFound(f"Cound not find {name} library!")
E   panoptes.utils.error.NotFound: NotFound: Cound not find udev library!

Have you seen that before? I'm guessing theres a library that needs to be added to the mac gh action image.

@wtgee
Copy link
Member

wtgee commented Aug 30, 2023

Better late than never?

Fixed this upstream at panoptes/panoptes-utils#304

@wtgee wtgee closed this Aug 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants