# pytimber with NXCALS R. De Maria, P. Sowinski, P. Elson Thanks to L. Coyle, T. Ytterdal, M. Hostletter, NXCALS team --- ## pytimber * pytimber is simple wrapper to Logging Service APIs (CALS and now NXCALS) * pytimber development is community driven and officially supported by CO * contacts: [mattermost acc-py channel](https://mattermost.web.cern.ch/acc-py/channels/town-square), acc-logging-support@cern.ch * Version 3.0.x is being released and brings: * First NXCALS support using the backport API and experimental native API * Drop support for Python <3.6 and jpype <0.7.1 * Various fixes and improvements * pytimber 3.0.x will be proposed for installation in the next LCG release (LCG98 probably) --- ## pytimber installation * In a recent own-managed python stack: ``` pip install pytimber ``` In SWAN or acc-py the instruction are more complex due to some specific feature of the LCG stack, but it will be simpler in the future. --- ## pytimber installation: Swan (1) * In Swan (stack "96 Python3"): ``` !curl -s https://gitlab.cern.ch/snippets/1130/raw -o .install_pytimber.py %run .install_pytimber.py ``` This will not be needed whenever the new pytimber version will be installed in the distribution. --- ## pytimber installation: Swan (2) (second recipe depracated) * In Swan (stack "96 Python3"): ```python #Always on the top of your notebooks# import sys, site; sys.path.insert(0, site.USER_SITE) import os os.environ['PYTHONPATH'] = f"{site.USER_SITE}:{os.environ['PYTHONPATH']}" #Install modules: only once# !pip install --upgrade pip --user !~/.local/bin/pip install pytimber --user # end installation import pytimber ``` This will not be needed whenever the new pytimber version will be installed in the distribution. --- ## pytimber installation: lxplus * In lxplus terminal: ``` source /cvmfs/sft.cern.ch/lcg/views/LCG_97python3/x86_64-centos7-gcc9-opt/setup.sh VENV_PATH=~/pytimber3-env python -m venv $VENV_PATH source $VENV_PATH/bin/activate export PYTHONPATH=$VENV_PATH/lib/python3.7/site-packages:$PYTHONPATH python -m pip install -U pytimber ``` --- ## pytimber installation: technical network * In technical network terminal: ``` source /acc/local/share/python/acc-py/pro/setup.sh VENV_PATH=~/pytimber3-env acc-py venv $VENV_PATH source $VENV_PATH/bin/activate python -m pip install -U pytimber export LD_LIBRARY_PATH=$ACC_PY_PREFIX/lib:$ACC_PY_COMPILER_PREFIX/lib64 ``` --- ## pytimber installation: dev version For the development version of pytimber use instead: ``` pip install -U git+https://gitlab.cern.ch/scripting-tools/pytimber/ ``` --- ## pytimber with NXCALS (1) 1. Request acc-logging-support@cern.ch for permission to use NXCALS as explained at: http://nxcals-docs.web.cern.ch/current/user-guide/data-access/nxcals-access-request/ --- ## pytimber with NXCALS (2) 2. Using backport API: `import pytimber` `pytimber.check_kerberos() #For Swan only` `ldb=pytimber.LoggingDB(source='nxcals')` Your existing scripts should work without modifications (if not, contact support). --- ## pytimber with NXCALS (3) 3. Using native Java API from Python (experimental) to access spark queries: `import pytimber` `pytimber.check_kerberos() #For Swan only` `nxcals=pytimber.NXCALS()` See https://github.com/rdemaria/pytimber/blob/master/examples/nxcals_example.py This functionality was implemented when the backport API was not avaialable. It is not clear if there is still an use case, since it overlaps with pyspark. --- ## Using Backport API in pytimber * Backport API mimics CALS API but it is not a full drop-in replacement * pytimber porting triggered Backport API improvements (thanks to NXCALS team) * Main differences with CALS * needs a kerberos token * requires similarly named packages * returns similarly named objects * still missing methods (e.g. hierarchy) * ~~nxcals returns extra nulls~~ (fixed from NXCALS 0.4.20) --- ## Using Backport API in pytimber * In pytimber we needed to duplicate and modify a fraction of the code: * Java: 84 LOC for CALS -> extra 132 LOC * Python: 5 LOC for CALS -> extra 60 LOC * About 20 person x days required for the process over the last three months --- ## Code differences: Java (1) CALS ```Java public static double[] doubleData(TimeseriesDataSet dataSet) { return dataSet.stream().map(NumericDoubleData.class::cast) .mapToDouble(NumericDoubleData::getDoubleValue) .toArray(); } ``` NXCALS ```Java public static double[] doubleData(TimeseriesDataSet dataSet) { return dataSet.stream().filter(BackPortDataSets::isNotNullValue) .mapToDouble(timeseriesData -> { try { return timeseriesData.getDoubleValue(); } catch (NoSuchMethodException ex) { throw new RuntimeException(ex); } } ).toArray(); } ``` same for other types --- ## Code differences: Python (1) Initialization of the service ```python if source == "nxcals": check_kerberos() self._System = jpype.java.lang.System self._System.setProperty( "service.url", "https://cs-ccr-nxcals6.cern.ch:19093," "https://cs-ccr-nxcals7.cern.ch:19093," "https://cs-ccr-nxcals8.cern.ch:19093", ) ServiceBuilder = jpype.JPackage( "cern" ).nxcals.api.backport.client.service.ServiceBuilder builder = ServiceBuilder.getInstance() self._md = builder.createMetaService() self._ts = builder.createTimeseriesService() self._FillService = builder.createLHCFillService() self._VariableDataType = jpype.JPackage( "cern" ).nxcals.api.backport.domain.core.constants.VariableDataType else: #CALS DataLocPrefs = jpype.JPackage( "cern" ).accsoft.cals.extr.domain.core.datasource.DataLocationPreferences loc = { "mdb": DataLocPrefs.MDB_PRO, "ldb": DataLocPrefs.LDB_PRO, "all": DataLocPrefs.MDB_AND_LDB_PRO, }[source] ServiceBuilder = jpype.JPackage( "cern" ).accsoft.cals.extr.client.service.ServiceBuilder builder = ServiceBuilder.getInstance(appid, clientid, loc) self._builder = builder self._md = builder.createMetaService() self._ts = builder.createTimeseriesService() self._FillService = builder.createLHCFillService() self._VariableDataType = jpype.JPackage( "cern" ).accsoft.cals.extr.domain.core.constants.VariableDataType ```` --- ## Code differences Python (2) Differentiating classes ```python def toTimescale(self, timescale_list): if self._source == "nxcals": Timescale = jpype.JPackage( "cern" ).nxcals.api.backport.domain.core.constants.TimescalingProperties else: Timescale = jpype.JPackage( "cern" ).accsoft.cals.extr.domain.core.constants.TimescalingProperties ``` --- ## Code differences (3) Differentiating classes ```python if self._source == "nxcals": PrimitiveDataSets = jpype.JPackage( "org" ).pytimber.utils.BackPortDataSets else: PrimitiveDataSets = jpype.JPackage( "org" ).pytimber.utils.PrimitiveDataSets ``` --- ## Code differences (4) Different approach for data unpacking ```python if self._source == "nxcals": ds = dataset if datatype == "NUMERIC": try: ds = np.array([d.getDoubleValue() for d in ds]) except jpype.java.lang.NoSuchMethodException: try: ds = np.array([d.getLongValue() for d in ds]) except jpype.java.lang.NoSuchMethodException: self._log.warning("unsupported datatype, returning the java object") elif datatype == "VECTORNUMERIC": try: ds = np.array([d.getDoubleValues() for d in ds]) except jpype.java.lang.NoSuchMethodException: try: ds = np.array([d.getLongValues() for d in ds]) except jpype.java.lang.NoSuchMethodException: self._log.warning("unsupported datatype, returning the java object") elif datatype == "TEXTUAL": try: ds = np.array([d.getVarcharValue() for d in ds]) except jpype.java.lang.NoSuchMethodException: self._log.warning("unsupported datatype, returning the java object") elif datatype == "VECTORSTRING": try: ds = np.array([d.getStringValues() for d in ds]) except jpype.java.lang.NoSuchMethodException: self._log.warning("unsupported datatype, returning the java object") else: self._log.warning("unsupported datatype, returning the java object") return (timestamps, ds) ```
{"title":"pytimber and nxcals experience","tags":"presentation","slideOptions":{"theme":"cern2","transition":"fade"},"slideNumber":true}