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

CI and tests fixed. Preparing version 1.1.1. #45

Merged
merged 8 commits into from
Feb 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Python package

on: [push, pull_request]

jobs:
test_code:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
max-parallel: 12
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
pip install -r test-requirements.txt
- name: Install package and dependencies
run: |
pip install .
- name: Build package from source
run: |
python -m build
- name: Run tests
run: |
py.test --capture=sys --cov=lightlab --cov-config .coveragerc
- name: Run linting
run: |
py.test --pylint --flake8 --pylint-rcfile=pylintrc lightlab
continue-on-error: true
11 changes: 0 additions & 11 deletions dev-requirements.txt

This file was deleted.

File renamed without changes.
File renamed without changes.
55 changes: 21 additions & 34 deletions lightlab/equipment/abstract_drivers/TekScopeAbstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,8 @@ def timebaseConfig(self, avgCnt=None, duration=None, position=None, nPts=None):
self.setConfigParam('DATA:START', 1)
self.setConfigParam('DATA:STOP', nPts)

presentSettings = {
'avgCnt': self.getConfigParam('ACQUIRE:NUMAVG', forceHardware=True)
}

presentSettings = dict()
presentSettings['avgCnt'] = self.getConfigParam('ACQUIRE:NUMAVG', forceHardware=True)
presentSettings['duration'] = self.getConfigParam('HORIZONTAL:MAIN:SCALE', forceHardware=True)
presentSettings['position'] = self.getConfigParam('HORIZONTAL:MAIN:POSITION', forceHardware=True)
presentSettings['nPts'] = self.getConfigParam(self._recLenParam, forceHardware=True)
Expand Down Expand Up @@ -103,19 +101,13 @@ def acquire(self, chans=None, timeout=None, **kwargs):

for c in chans:
if c > self.totalChans:
raise Exception(
(
f'Received channel: {str(c)}'
+ '. Max channels of this scope is '
)
+ str(self.totalChans)
)

raise Exception('Received channel: ' + str(c) +
'. Max channels of this scope is ' + str(self.totalChans))

# Channel select
for ich in range(1, 1 + self.totalChans):
thisState = 1 if ich in chans else 0
self.setConfigParam(f'SELECT:CH{str(ich)}', thisState)
self.setConfigParam('SELECT:CH' + str(ich), thisState)

isSampling = kwargs.get('avgCnt', 0) == 1
self._setupSingleShot(isSampling)
Expand Down Expand Up @@ -184,11 +176,12 @@ def __transferData(self, chan):
Todo:
Make this binary transfer to go even faster
'''
chStr = f'CH{str(chan)}'
chStr = 'CH' + str(chan)
self.setConfigParam('DATA:ENCDG', 'ASCII')
self.setConfigParam('DATA:SOURCE', chStr)

return self.query_ascii_values('CURV?')
voltRaw = self.query_ascii_values('CURV?')
return voltRaw

def __scaleData(self, voltRaw):
''' Scale to second and voltage units.
Expand All @@ -209,10 +202,7 @@ def __scaleData(self, voltRaw):
YZERO, the reference voltage, YOFF, the offset position, and
YSCALE, the conversion factor between position and voltage.
'''
get = lambda param: float(
self.getConfigParam(f'WFMOUTPRE:{param}', forceHardware=True)
)

get = lambda param: float(self.getConfigParam('WFMOUTPRE:' + param, forceHardware=True))
voltage = (np.array(voltRaw) - get('YOFF')) \
* get(self._yScaleParam) \
+ get('YZERO')
Expand Down Expand Up @@ -273,13 +263,10 @@ def setMeasurement(self, measIndex, chan, measType):
'''
if measIndex == 0:
raise ValueError('measIndex is 1-indexed')
measSubmenu = f'MEASUREMENT:MEAS{str(measIndex)}:'
self.setConfigParam(
measSubmenu + self._measurementSourceParam, f'CH{str(chan)}'
)

self.setConfigParam(f'{measSubmenu}TYPE', measType.upper())
self.setConfigParam(f'{measSubmenu}STATE', 1)
measSubmenu = 'MEASUREMENT:MEAS' + str(measIndex) + ':'
self.setConfigParam(measSubmenu + self._measurementSourceParam, 'CH' + str(chan))
self.setConfigParam(measSubmenu + 'TYPE', measType.upper())
self.setConfigParam(measSubmenu + 'STATE', 1)

def measure(self, measIndex):
'''
Expand All @@ -289,16 +276,16 @@ def measure(self, measIndex):
Returns:
(float)
'''
measSubmenu = f'MEASUREMENT:MEAS{str(measIndex)}:'
return float(self.getConfigParam(f'{measSubmenu}VALUE', forceHardware=True))
measSubmenu = 'MEASUREMENT:MEAS' + str(measIndex) + ':'
return float(self.getConfigParam(measSubmenu + 'VALUE', forceHardware=True))

def autoAdjust(self, chans):
''' Adjusts offsets and scaling so that waveforms are not clipped '''
# Save the current measurement status. They will be restored at the end.
self.saveConfig(dest='+autoAdjTemp', subgroup='MEASUREMENT')

for ch in chans:
chStr = f'CH{str(ch)}'
chStr = 'CH' + str(ch)

# Set up measurements
self.setMeasurement(1, ch, 'pk2pk')
Expand All @@ -312,8 +299,8 @@ def autoAdjust(self, chans):
pk2pk = self.measure(1)
mean = self.measure(2)

span = float(self.getConfigParam(f'{chStr}:SCALE'))
offs = float(self.getConfigParam(f'{chStr}:OFFSET'))
span = float(self.getConfigParam(chStr + ':SCALE'))
offs = float(self.getConfigParam(chStr + ':OFFSET'))

# Check if scale is correct within the tolerance
newSpan = None
Expand All @@ -323,7 +310,7 @@ def autoAdjust(self, chans):
elif pk2pk > 0.8 * span:
newSpan = 2 * span
if newSpan < 0.1 or newSpan > 100:
raise Exception(f'Scope channel {chStr} could not be adjusted.')
raise Exception('Scope channel ' + chStr + ' could not be adjusted.')

# Check if offset is correct within the tolerance
if abs(mean) > 0.05 * span:
Expand All @@ -334,8 +321,8 @@ def autoAdjust(self, chans):
break

# Adjust settings
self.setConfigParam(f'{chStr}:SCALE', newSpan / 10)
self.setConfigParam(f'{chStr}:OFFSET', newOffs)
self.setConfigParam(chStr + ':SCALE', newSpan / 10)
self.setConfigParam(chStr + ':OFFSET', newOffs)

# Recover the measurement setup from before adjustment
self.loadConfig(source='+autoAdjTemp', subgroup='MEASUREMENT')
Expand Down
73 changes: 43 additions & 30 deletions lightlab/equipment/abstract_drivers/configurable.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from lightlab import visalogger as logger
from pyvisa import VisaIOError
from contextlib import contextmanager
import dpath.util
import dpath
import json
from numpy import floor
from pathlib import Path
Expand Down Expand Up @@ -32,7 +32,7 @@ class TekConfig(object):

def __init__(self, initDict=None):
if initDict is None:
initDict = {}
initDict = dict()
self.dico = initDict.copy()

def __str__(self):
Expand All @@ -55,18 +55,21 @@ def get(self, cStr, asCmd=True):
asCmd (bool): if true, returns a tuple representing a command. Otherwise returns just the value
'''
try:
val = dpath.util.get(self.dico, cStr, separator=self.separator)
val = dpath.get(self.dico, cStr, separator=self.separator)
except KeyError:
raise KeyError(f'{cStr} is not present in this TekConfig instance')
raise KeyError(cStr + ' is not present in this TekConfig instance')
if type(val) is dict and '&' in val.keys():
val = val['&']
return (cStr, str(val)) if asCmd else val
if not asCmd:
return val
else:
return (cStr, str(val))

def set(self, cStr, val):
''' Takes the value only, not a dictionary '''
# First check that it does not exist as a subdir
try:
ex = dpath.util.get(self.dico, cStr, separator=self.separator)
ex = dpath.get(self.dico, cStr, separator=self.separator)
except KeyError:
# doesn't exist, we are good to go
pass
Expand All @@ -76,20 +79,20 @@ def set(self, cStr, val):
cStr = cStr + self.separator + '&'

cmd = (cStr, val)
success = dpath.util.set(self.dico, *cmd, separator=self.separator)
success = dpath.set(self.dico, *cmd, separator=self.separator)
if success != 1: # it doesn't exist yet
try:
dpath.util.new(self.dico, *cmd, separator=self.separator)
dpath.new(self.dico, *cmd, separator=self.separator)
except (ValueError, dpath.exceptions.PathNotFound):
# We probably have an integer leaf where we would also like to have a directory
parent = self.separator.join(cmd[0].split(self.separator)[:-1])
try:
oldV = self.get(parent, asCmd=False)
except KeyError:
print(f'dpath did not take {cmd}')
print('dpath did not take ' + str(cmd))
raise
dpath.util.set(self.dico, parent, {'&': oldV}, separator=self.separator)
dpath.util.new(self.dico, *cmd, separator=self.separator)
dpath.set(self.dico, parent, {'&': oldV}, separator=self.separator)
dpath.new(self.dico, *cmd, separator=self.separator)

def getList(self, subgroup='', asCmd=True):
''' Deep crawler that goes in and generates a command for every leaf.
Expand All @@ -102,7 +105,7 @@ def getList(self, subgroup='', asCmd=True):
list: list of valid commands (cstr, val) on the subgroup subdirectory
'''
cList = []
children = dpath.util.search(
children = dpath.search(
self.dico, f'{subgroup}*', yielded=True, separator=self.separator
)

Expand All @@ -116,13 +119,14 @@ def getList(self, subgroup='', asCmd=True):
cList += self.getList(subgroup=cmd[0] + self.separator)
if asCmd:
return cList
writeList = [None] * len(cList)
for i, cmd in enumerate(cList):
cStr, val = cmd
if cStr[-1] == '&': # check for tokens
cStr = cStr[:-2]
writeList[i] = f'{cStr} {str(val)}'
return writeList
else:
writeList = [None] * len(cList)
for i, cmd in enumerate(cList):
cStr, val = cmd
if cStr[-1] == '&': # check for tokens
cStr = cStr[:-2]
writeList[i] = cStr + ' ' + str(val)
return writeList

def setList(self, cmdList):
''' The inverse of getList '''
Expand All @@ -144,7 +148,7 @@ def transfer(self, source, subgroup=''):
elif type(source) is type(self):
sCon = source
else:
raise Exception(f'Invalid source for transfer. Got {str(type(source))}')
raise Exception('Invalid source for transfer. Got ' + str(type(source)))
commands = sCon.getList(subgroup=subgroup)
self.setList(commands)
return self
Expand All @@ -169,7 +173,7 @@ def __parseShorthand(cls, setResponse):
cmdGrp = None
for i in range(len(pairs)):
words = pairs[i].split(' ')
cmdLeaf, val = words[:2]
cmdLeaf, val = words[0:2]
if len(words) > 2:
print('Warning 2-value returns not handled by TekConfig class. Ignoring...')
print(*words)
Expand All @@ -192,9 +196,10 @@ def fromSETresponse(cls, setResponse, subgroup=''):
full.setList(commandList)
if subgroup == '':
return full
ret = cls()
ret.transfer(full, subgroup=subgroup)
return ret
else:
ret = cls()
ret.transfer(full, subgroup=subgroup)
return ret

def save(self, fname, subgroup='', overwrite=False):
''' Saves dictionary parameters in json format. Merges if there's something already there, unless overwrite is True.
Expand Down Expand Up @@ -247,7 +252,8 @@ def __init__(self, headerIsOptional=True, verboseIsOptional=False, precedingColo
self.colon = precedingColon
self.space = interveningSpace

self.config = {'default': None}
self.config = dict()
self.config['default'] = None
self.config['init'] = TekConfig()
self.config['live'] = TekConfig()
self.separator = self.config['live'].separator
Expand Down Expand Up @@ -347,7 +353,8 @@ def getDefaultFilename(self):
(str): the default filename
'''
info = self.instrID().split(',')
return defaultFileDir / '-'.join(info[:3]) + '.json'
deffile = defaultFileDir / '-'.join(info[:3]) + '.json'
return deffile

def saveConfig(self, dest='+user', subgroup='', overwrite=False):
'''
Expand Down Expand Up @@ -441,14 +448,17 @@ def _getHardwareConfig(self, cStrList):
cStr = cStr[:-2]

try:
ret = self.query(f'{cStr}?')
ret = self.query(cStr + '?')
except VisaIOError:
logger.error('Problematic parameter was %s.\n'
'Likely it does not exist in this instrument command structure.', cStr)
raise
logger.debug('Queried %s, got %s', cStr, ret)

val = ret.split(' ')[-1] if self.header else ret
if self.header:
val = ret.split(' ')[-1]
else:
val = ret
# Type detection
try:
val = float(val)
Expand Down Expand Up @@ -501,9 +511,12 @@ def generateDefaults(self, filename=None, overwrite=False):
cfgBuild = TekConfig()

for cmd in allSetCmds:
cStr = cmd[0] if cmd[0][-1] != '&' else cmd[0][:-2]
if cmd[0][-1] != '&': # handle the sibling subdir token
cStr = cmd[0]
else:
cStr = cmd[0][:-2]
try:
val = self.query(f'{cStr}?', withTimeout=1000)
val = self.query(cStr + '?', withTimeout=1000)
cfgBuild.set(cStr, val)
logger.info(cStr, '<--', val)
except VisaIOError:
Expand Down
Loading