Skip to content

Commit

Permalink
Merge branch 'master' into update-sofb2
Browse files Browse the repository at this point in the history
  • Loading branch information
fernandohds564 committed May 16, 2024
2 parents cbcbfde + bc2235e commit b48d6e1
Show file tree
Hide file tree
Showing 48 changed files with 5,456 additions and 1,978 deletions.
2 changes: 1 addition & 1 deletion siriuspy/siriuspy/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.83.1
2.87.1
28 changes: 26 additions & 2 deletions siriuspy/siriuspy/clientarch/client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#!/usr/bin/env python-sirius
"""Fetcher module.
See https://slacmshankar.github.io/epicsarchiver_docs/userguide.html
See
https://slacmshankar.github.io/epicsarchiver_docs/userguide.html
http://slacmshankar.github.io/epicsarchiver_docs/details.html
http://slacmshankar.github.io/epicsarchiver_docs/api/mgmt_scriptables.html
"""

from threading import Thread as _Thread
Expand All @@ -16,6 +18,7 @@

from .. import envars as _envars
from . import exceptions as _exceptions
from .time import Time as _Time


class ClientArchiver:
Expand Down Expand Up @@ -134,6 +137,27 @@ def getPausedPVsReport(self):
resp = self._make_request(url, return_json=True)
return None if not resp else resp

def getRecentlyModifiedPVs(self, limit=None, epoch_time=True):
"""Get list of PVs with recently modified PVTypeInfo.
Currently version of the epics archiver appliance returns pvname
list from oldest to newest modified timestamps."""
method = 'getRecentlyModifiedPVs'
# get data
if limit is not None:
method += f'?limit={str(limit)}'
url = self._create_url(method=method)
resp = self._make_request(url, return_json=True)

# convert to epoch, if the case
if resp and epoch_time:
for item in resp:
modtime = item['modificationTime'][:-7] # remove ISO8601 offset
epoch_time = _Time.conv_to_epoch(modtime, '%b/%d/%Y %H:%M:%S')
item['modificationTime'] = epoch_time

return None if not resp else resp

def pausePVs(self, pvnames):
"""Pause PVs."""
if not isinstance(pvnames, (list, tuple)):
Expand Down
12 changes: 9 additions & 3 deletions siriuspy/siriuspy/clientarch/pvarch.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,11 @@ def is_archived(self):
return False
return True

def update(self):
def update(self, timeout=None):
"""."""
self.connect()
if timeout is not None:
self.timeout = timeout
data = self.connector.getPVDetails(self.pvname)
if not data:
return False
Expand Down Expand Up @@ -280,9 +282,11 @@ def severity(self):
"""Severity data."""
return self._severity

def update(self, mean_sec=None, parallel=True):
def update(self, mean_sec=None, parallel=True, timeout=None):
"""Update."""
self.connect()
if timeout is not None:
self.timeout = timeout
if None in (self.timestamp_start, self.timestamp_stop):
print('Start and stop timestamps not defined! Aborting.')
return
Expand Down Expand Up @@ -493,9 +497,11 @@ def parallel_query_bin_interval(self, new_intvl):
self._pvdata[pvname].parallel_query_bin_interval = \
self._parallel_query_bin_interval

def update(self, mean_sec=None, parallel=True):
def update(self, mean_sec=None, parallel=True, timeout=None):
"""Update."""
self.connect()
if timeout is not None:
self.timeout = None
if None in (self.timestamp_start, self.timestamp_stop):
print('Start and stop timestamps not defined! Aborting.')
return
Expand Down
8 changes: 8 additions & 0 deletions siriuspy/siriuspy/clientarch/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from . import exceptions as _exceptions
from datetime import datetime as _datetime, timedelta as _timedelta
from calendar import timegm as _timegm


class Time(_datetime):
Expand Down Expand Up @@ -94,6 +95,13 @@ def __sub__(self, other):
sub = super().__sub__(other)
return Time(timestamp=sub.timestamp())

@staticmethod
def conv_to_epoch(time, datetime_format):
"""get epoch from datetime."""
utc_time = _datetime.strptime(time, datetime_format)
epoch_time = _timegm(utc_time.timetuple())
return epoch_time


def get_time_intervals(
time_start, time_stop, interval, return_isoformat=False):
Expand Down
39 changes: 39 additions & 0 deletions siriuspy/siriuspy/clientconfigdb/configdb_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import json as _json
import datetime as _datetime
import re as _re
from urllib import parse as _parse
from urllib.request import Request as _Request, urlopen as _urlopen
from urllib.error import URLError as _URLError
Expand Down Expand Up @@ -170,6 +171,44 @@ def check_valid_value(self, value, config_type=None):
config_type = self._process_config_type(config_type)
return _templates.check_value(config_type, value)

@staticmethod
def compare_configs(config1, config2, pos_pattern=None, neg_pattern=None):
"""Compare "pvs" attribute of configs 1 and 2.
Print the differences.
Args:
config1 (dict): Valid configuration with "pvs" attribute.
config2 (dict): Valid configuration with "pvs" attribute.
pos_pattern (str, optional): Only PVs with this pattern will be
checked. Defaults to None. None means all PVs will be compared.
neg_pattern (_type_, optional): PVs which match this pattern will
not be checked. Defaults to None. None means no PV will be
excluded from comparison. In case of conflict with
`pos_pattern`, it will take precedence.
"""
pos_re = _re.compile('' if pos_pattern is None else pos_pattern)
# In case of None in neg_pattern, create a regexp that never matches:
# https://stackoverflow.com/questions/1723182/a-regex-that-will-never-be-matched-by-anything
neg_re = _re.compile(r'(?!x)x' if neg_pattern is None else neg_pattern)

cf1pvs = {n: v for n, v, _ in config1['pvs']}
cf2pvs = {n: v for n, v, _ in config2['pvs']}

lines = []
for pv in cf1pvs.keys() | cf2pvs.keys():
if not pos_re.match(pv) or neg_re.match(pv):
continue
val1 = str(cf1pvs.get(pv, 'Not present'))
val2 = str(cf2pvs.get(pv, 'Not present'))
if val1 != val2:
lines.append(f'{pv:50s} {val1[:30]:30s} {val2[:30]:30s}')

# sort and print lines
lines = sorted(lines)
for line in lines:
print(line)

@classmethod
def check_valid_configname(cls, name):
"Check if `name` is a valid name for configurations."
Expand Down
Loading

0 comments on commit b48d6e1

Please sign in to comment.