Giter VIP home page Giter VIP logo

pyvisa-sim's Introduction

PyVISA

Continuous integration Documentation building Keysight assisted testing Code Coverage Documentation Status PyPI - License PyPI

A Python package for support of the "Virtual Instrument Software Architecture" (VISA), in order to control measurement devices and test equipment via GPIB, RS232, Ethernet or USB.

Description

The programming of measurement instruments can be real pain. There are many different protocols, sent over many different interfaces and bus systems (GPIB, RS232, USB). For every programming language you want to use, you have to find libraries that support both your device and its bus system.

In order to ease this unfortunate situation, the Virtual Instrument Software Architecture (VISA) specification was defined in the middle of the 90's. Today VISA is implemented on all significant operating systems. A couple of vendors offer VISA libraries, partly with free download. These libraries work together with arbitrary peripheral devices, although they may be limited to certain interface devices, such as the vendor’s GPIB card.

The VISA specification has explicit bindings to Visual Basic, C, and G (LabVIEW’s graphical language). Python can be used to call functions from a VISA shared library (.dll, .so, .dylib) allowing to directly leverage the standard implementations. In addition, Python can be used to directly access most bus systems used by instruments which is why one can envision to implement the VISA standard directly in Python (see the PyVISA-Py project for more details). PyVISA is both a Python wrapper for VISA shared libraries but can also serve as a front-end for other VISA implementation such as PyVISA-Py.

VISA and Python

Python has a couple of features that make it very interesting for controlling instruments:

  • Python is an easy-to-learn scripting language with short development cycles.
  • It represents a high abstraction level [2], which perfectly blends with the abstraction level of measurement programs.
  • It has a rich set of native libraries, including numerical and plotting modules for data analysis and visualisation.
  • A large set of books (in many languages) and on-line publications is available.

Requirements

  • Python (tested with 3.6+)
  • VISA (tested with NI-VISA 17.5, Win7, from www.ni.com/visa and Keysight-VISA )

Installation

Using pip:

$ pip install pyvisa

or easy_install:

$ easy_install pyvisa

or download and unzip the source distribution file and:

$ python setup.py install

Documentation

The documentation can be read online at https://pyvisa.readthedocs.org

Citing

If you are using this package, you can cite the PyVISA publication

Grecco et al., (2023). PyVISA: the Python instrumentation package. Journal of Open Source Software, 8(84), 5304, https://doi.org/10.21105/joss.05304

pyvisa-sim's People

Contributors

bors[bot] avatar croesnick avatar dependabot[bot] avatar dougthor42 avatar famish99 avatar hgrecco avatar jtilahun avatar lawsongu avatar matteotondelli avatar matthieudartiailh avatar satertek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyvisa-sim's Issues

Remove raising errors from SimVisaLibrary

In order to allow an homogeneous and user customizable policy about errors and warnings the proposal is to remove raising error and logging warnings from SimVisaLibrary. Instead, these functions should return the status code (i.e a member of constants.StatusCode or constants.VI_SUCCESS_* / constants.VI_WARN_* / constants.VI_ERROR_*).

Another layer will take care of raising the appropriate error and log warnings. An open question is how to implement this layer. I see the following options:

  1. add a decorator to the functions (maybe via a class or metaclass, to make it easier). There is a stub for such decorator here.
  2. prefix all current 2 level functions with an underscore (_) and change VISALibraryBase to dispatch to those functions.

@famish99 @MatthieuDartiailh

New features

You suggested discussing features and implementation. Here seems to be a good place to start.

Instruments archive

Hi guys, I would like to test my procedure with simulated instruments... i use various nation instruments like oscilloscope etc.

Is there an archive of yaml to simulate the most common instruments?

Thanks!

Invalid signature for load in get_device_dict

When referencing external yaml files for device definitions, load fails in parser.py, line 265 because of signature mismatch.

data = self.load(filename, bundled, required_version)

Change to:

data = self.load(filename, bundled, None, required_version)

PyVISA 1.12.0 and GPIB Secondary Addresses

PyVISA 1.12.0 introduced a change to how GPIB secondary addresses are handled. An undefined secondary address is now returned as a None instead of "0". This breaks pyvisa-sim when loading a GPIB instrument address that does not contain a secondary address, raising TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'

I'm not sure what the best solution would be for pyvisa-sim. My personal workaround is to just define a secondary address in my test cases.

Example:

> rm = pyvisa.highlevel.ResourceManager("@sim")
> inst = rm.open_resource("GPIB::1::INSTR")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>  
  File "./python3.10/site-packages/pyvisa/highlevel.py", line 3284, in open_resource
    res.open(access_mode, open_timeout)  
  File "./python3.10/site-packages/pyvisa/resources/resource.py", line 278, in open
    self.session, status = self._resource_manager.open_bare_resource(
  File "./python3.10/site-packages/pyvisa/highlevel.py", line 3209, in open_bare_resource
    return self.visalib.open(self.session, resource_name, access_mode, open_timeout)  
  File "./python3.10/site-packages/pyvisa_sim/highlevel.py", line 121, in open
    sess = cls(session, resource_name, parsed)
  File "./python3.10/site-packages/pyvisa_sim/sessions.py", line 79, in __init__
    self.after_parsing()
  File "./python3.10/site-packages/pyvisa_sim/gpib.py", line 33, in after_parsing
    self.attrs[constants.VI_ATTR_GPIB_SECONDARY_ADDR] = int(self.parsed.secondary_address)
TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'

Allow basing a simulated device in another

It is common that multiple devices will share a large part of the commands. Here, we propose a syntax to facilitate this.

We will add to the device dict a new key (bases) with the value specifying a list of devices used as bases. Multiple bases are allowed. Bases first in the list have precedence.

Each element of the list is dictionary specifying the device like it is done in the resources section.

    <device name>:
        bases: 
             - device: base 1
             - device: base 2
               filename: myfile.yaml
             - device: base 3
               filename: default.yaml
               bundled: true
        <here goes the device definition>

Implementation

For each base, its dictionary is loaded and merged with the derived device.

Feature suggestion: Connecting instruments

I've been tasked with implementing a way to connect multiple simulated instruments with inputs and outputs. Would this be appreciated as part of PyVISA-sim? Otherwise I will create it as a separate layer.

If yes, do you have any suggestions on how to do this?

Add support for TCPIP SOCKET instrument

I will need that for some instrument (Attocube driver for lantz). Could you please indicate me the procedure to follow ? Can I simply duplicate the the TCPIP INSTR implementation or should I be wary of some points ?

ResourceManager needs to be closed to clear instrument buffer

I observe weird problems running pytest tests with pyvisa-sim backed fixture objects, in that replies remain in a read buffer despite the objects + resource managers being destroyed:

>>> import pyvisa
>>> rm = pyvisa.ResourceManager(visa_library='@sim')
>>> instr = rm.open_resource('ASRL2::INSTR')
>>> instr.write('*IDN?')
7
>>> instr.read()
'SCPI,MOCK,VERSION_1.0\n'  # OK, that's what I expect
>>> instr.write('*IDN?')  # we don't fetch that response from the instrument
7
>>> id(instr)
140011221241280
>>> del instr  # Kill the instrument (or instr.close())
>>> del rm  # (or rm.close())
>>> rm = pyvisa.ResourceManager(visa_library='@sim')
>>> instr = rm.open_resource('ASRL2::INSTR')
>>> instr.read()  # Why is this response in this different instrument object?
'SCPI,MOCK,VERSION_1.0\n'
>>> id(instr)
140011221241472  # the IDs of the instr objects are different, so it's not somehow the same

To fix/avoid this, one needs to call rm.close(). instr.close() is neither sufficient nor necessary.

Matthieu said:

The fact that closing the instrument does not solve the issue still says that something is off. Instruments do not share outgoing buffers between connections and we should mimic that.

Originally posted by @bilderbuchi in #68 (comment)

Add support for instrument with channels.

I think the idea would simply be to store the parameters in different dictionaries according to the channel. Two main mechanism should supported :

  • the active channel is defined through a command
  • the channel is specified as part of the command (the string parser might be of help here).

getting command_error ERROR for simple instrument query...

Can someone explain to me why this simple test does not seem to work?

pyvisa-sim version: 0.5.1

error:

    def test_get_identification():
        identifier = get_osp320_instrument().get_identification()
>       assert identifier == "OSP320, 12345, 00000001, 23.1.1/3"
E       AssertionError: assert 'ERROR' == 'OSP320, 1234...001, 23.1.1/3'
E         - OSP320, 12345, 00000001, 23.1.1/3
E         + null_response

tests/drivers/switch/rs/test_osp320.py:64: AssertionError

test_file.py

def get_osp320_instrument(
    config: OSP320Configuration = OSP320Configuration(
        read_termination="\n" # somehow need to add this even in TCPIP::INSTR otherwise a VisaIOError gets triggered...
    )
) -> OSP320Instrument:
    MockInstrument = OSP320Instrument
    # Use mocked resource manager
    MockInstrument.resource_manager = "<path>/test_file.yaml@sim"
    # MockInstrument.connection.read_termination = "\n"
    return MockInstrument(
        connection_string="TCPIP::localhost::inst0::INSTR",
        config=config,
    )

# ...

def test_get_identification():
    identifier = get_osp320_instrument().get_identification()
    assert identifier == "OSP320, 12345, 00000001, 23.1.1/3"

test_file.yaml

spec: "1.1"
devices:
  OSP320:
    eom:
      TCPIP INSTR:
        q: "\r\n"
        r: "\n"
      TCPIP SOCKET:
        q: "\r\n"
        r: "\n"
    dialogues:
      - q: "*IDN?"
        r: "OSP320, 12345, 00000001, 23.1.1/3"
      - q: "*OPC?"
        r: "1"
      - q: "*CLS"
    error:
      response:
        command_error: ERROR
      status_register:
        - q: "*ESR?"
          command_error: 32
          query_error: 4
    properties:
      status:
        default: 0
        getter:
          q: "*STB?"
          r: "{:d}"
        setter:
          q: "*STB {:d}"
        specs:
          type: int
      system_error:
        default: ""
        getter:
          q: "SYSTem:ERRor:NEXT?"
          r: "{:s}"
        setter:
          q: "SYSTem:ERRor:NEXT {:s}"

resources:
  TCPIP::localhost::inst0::INSTR:
    device: OSP320
  TCPIP::localhost::1001::SOCKET:
    device: OSP320

instrument.py

class OSP320Configuration(BaseModel):
    default_timeout: Optional[int] = None
    read_termination: Optional[str] = None


class OSP320Instrument(Instrument):
    name = "cka.instrument.rs.switch.osp320.v1"
    config: OSP320Configuration
    resource_manager: str = "@py"
    connection: pyvisa.resources.Resource

    @validate_call
    def __init__(
        self,
        connection_string: str,
        config: OSP320Configuration,
    ) -> None:
        self.config = config
        logger.info("Connecting to: `%s`", connection_string)
        rm = pyvisa.ResourceManager(self.resource_manager)
        self.connection = rm.open_resource(connection_string)

        if "SOCKET" in connection_string:
            self.connection.read_termination = "\n"
        elif self.config.read_termination is not None:
            self.connection.read_termination = self.config.read_termination

        self.connection.write("*CLS")
        self.connection.query("*OPC?")
        logger.info("Validated the connection!")
        self.write("CONFigure:COMPatible 0") # do not accept legacy commands (OSP1xx)

        if self.config.default_timeout is not None:
            self.connection.timeout = self.config.default_timeout
        super().__init__()

    def __exit__(self, *args):
        self.connection.close()

    def write(self, command: str):
        return self.connection.write(command)

    def try_write(self, command: str):
        data = self.connection.write(command)
        logger.info("OSP320 write: %s", command)
        if int(self.connection.query("*STB?")) != 0:
            try:
                error_messages = self.connection.query("SYSTEM:ERRor:NEXT?")
                logger.error("Error message: `%s`", error_messages)
                raise RuntimeError(f"Failed to write command: `{command}`. {error_messages}")
            finally:
                self.connection.write("*CLS")
        return data

    def query(self, command: str, timeout: Optional[int] = None):
        old_timeout = None
        logger.info("OSP320 query: %s", command)
        if timeout is not None:
            old_timeout = self.connection.timeout
            self.connection.timeout = timeout
        try:
            return self.connection.query(command)
        finally:
            if old_timeout is not None:
                self.connection.timeout = old_timeout

    @logged
    def get_identification(self):
        return self.query("*IDN?")
# ...

What am I missing?

Thanks

pyvisa doesn't found pyvisa-sim with pyvisa 1.11.0

With the new PyVisa 1.11.0, pyvisa is not able to load pyvisa-sim backend.

import visa

rm = visa.ResourceManager('@sim')
inst = rm.open_resource('ASRL1::INSTR', read_termination='\n')

Stacktrace :

>       rm = visa.ResourceManager('@sim')

visa_wrapper.py:21: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
venv/lib/python3.6/site-packages/pyvisa/highlevel.py:3005: in __new__
    visa_library = open_visa_library(visa_library)
venv/lib/python3.6/site-packages/pyvisa/highlevel.py:2919: in open_visa_library
    return cls(argument)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

cls = <class 'pyvisa-sim.highlevel.SimVisaLibrary'>, library_path = ''

    def __new__(
        cls: Type[T], library_path: Union[str, LibraryPath] = ""
    ) -> "VisaLibraryBase":
        """Create a new VISA library from the specified path.
    
        If a library was already created using the same path and class this
        library object is returned instead.
    
        Parameters
        ----------
        library_path : str | LibraryPath
            Path to the VISA library to use in the backend.
    
        Raises
        ------
        OSError
            Raised if the VISA library object could not be created.
    
        """
        if library_path == "":
            errs = []
            for path in cls.get_library_paths():
                try:
                    return cls(path)
                except OSError as e:
                    logger.debug("Could not open VISA library %s: %s", path, str(e))
                    errs.append(str(e))
                except Exception as e:
                    errs.append(str(e))
            else:
>               raise OSError("Could not open VISA library:\n" + "\n".join(errs))
E               OSError: Could not open VISA library:

venv/lib/python3.6/site-packages/pyvisa/highlevel.py:173: OSError

It works as expected with 1.10.1

Installed versions :

pyvisa==1.11.0
pyvisa-sim==0.3

Ubuntu 18.04 (x64)
Python 3.6 (x64)

No other VISA backends installed

Parser: defining properties

Syntax:

@property <property name>[: <specification>]
get >>> <get string>
get <<< <return format using stringparser>
set >>> <set string using PEP 3101>
[set <<< <return string when everything is ok using stringparser>]
[err <<< <return string when an error is  found using stringparser>]

Things between brackets are optional.
If set <<< or err <<< are not given, it is assumed that nothing is returned.
If the specification is not given, any value is possible.

For example:

@property frequency
get >>> FREQ?
get <<< {.3f}
set >>> FREQ {.3f}
set <<< OK
err <<< ERROR
@end 

How to write the specification

A using lantz-like kwargs Feat.
Range: limits = min, max, step value
Valid values: values = value1, value2, value3

B using a more texty way:
Range: min < value < max
Step: step = step value
Valid values: value1 | value2 | value3

See #3

Multiple getters and setters for a property?

The Keysight and Agilent instrument lines typically implement commands that can have various forms. For example, all of these are the same command:

# Definition:
[:SOURce[c]]:FUNCtion[:SHAPe] shape
shape: PULSe|DC

# Accepted:
:SOURCE1:FUNCTION:SHAPE DC
:SOURCE1:FUNC:SHAP PULS
:SOURCE:FUNC:SHAPE PULSE
:FUNCTION dc
:func:shape pulse
... and many more.

Is there support for multiple getters and setters for a property? A naive implementation would allow just repeating the property name:

properties:
  source_function_shape:
    getter:
      q: ":SOURCE:FUNCTION:SHAPE?"
      r: {}
    setter:
      q: ":SOURCE:FUCTION:SHAPE {}"
    valid: ["DC", "PULS", "PULSE"]
  source_function_shape:  # same property name so that ":SOUR:FUNC:SHAP?" returns the same as ":SOURCE:FUNCTION:SHAPE?"
    getter:
      q: ":SOUR:FUNC:SHAP?"
      r: {}
    setter:
      q: ":SOUR:FUCN:SHAP {}"
    valid: ["DC", "PULS", "PULSE"]

But this ends up being very verbose.

Can regex be used for getter and setter commands?

properties:
  source_function_shape:
    getter:
      q: ':(SOUR(CE)?\d?)?:FUNC(TION)?:SHAPE?\?'
      r: {}
    setter:
      q: ':(SOUR(CE)?\d?)?:FUNC(TION)?:SHAP(E)? \{\}'
    valid: ["DC", "PULS", "PULSE"]

Conda installs version 0.3 -- Get no package pyvisa_sim found.

Hi, would love to use this package.
I'm using python version 3.9 w/ conda.
My env list shows version 0.3 is installed.
When I run:

>>> import pyvisa
>>> pyvisa.ResourceManager("@sim")

I get ValueError: Wrapper not found: No package named pyvisa_sim

If I uninstall then use pip to install, it downloads version 0.5.1 and that code works.

Any chance this can be fixed? Would love to help if I can.

Communication fails for simulated GPIB/USB/TCPIP devices

I am trying to communicate to the simulated devices that the pyvisa-sim backend provides. However only if I talk to the device over the (simulated) serial it works. All other interfaces result in a timeout error. I am using the default.yaml configuration for the pyvisa backend.

Below example code with which I tested it:

import visa

rm = visa.ResourceManager('@sim')

device1_serial = rm.open_resource('ASRL1::INSTR')
device1_gpib = rm.open_resource('GPIB0::8::65535::INSTR')
device1_usb = rm.open_resource('USB0::0x1111::0x2222::0x1234::0::INSTR')
device1_tcp = rm.open_resource('TCPIP0::localhost::inst0::INSTR')

device1_serial.query('?IDN') # this works, returns 'LSG Serial #1234\n'
device1_gpib.query('?IDN') # this raises a 'VI_ERROR_TMO' error
device1_tcp.query('?IDN') # this raises a 'VI_ERROR_TMO' error
device1_usb.query('?IDN') # this raises a 'VI_ERROR_TMO' error

gist of the error: https://gist.github.com/StefanD986/830ede22e5a2bad067862874eaef777e

bytes_in_buffers does not work in simulation

I am woking on a testbench with pyvisa-sim, and I found with the sim backend, instr.bytes_in_buffer for a simulate serial conenction does not work:

$python builds/locl/sim/sim_test.py 
LSG Serial #1234
Traceback (most recent call last):
  File "/home/robby/builds/locl/sim/sim_test.py", line 17, in <module>
    print(instr.bytes_in_buffer)
          ^^^^^^^^^^^^^^^^^^^^^
  File "/home/robby/builds/pyvisa/pyvisa/attributes.py", line 175, in __get__
    return self.post_get(instance.get_visa_attribute(self.attribute_id))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/robby/builds/pyvisa/pyvisa/attributes.py", line 286, in post_get
    return int(value)
           ^^^^^^^^^^
TypeError: int() argument must be a string, a bytes-like object or a real number, not 'object'

minimalist setup to reproduce:
sim_test.py.txt

Is there an easy way to have this functional in pyvisa-sim?

`main` branch no longer allows dialog-without-response

In v0.5.1, a dialog that does not have a response is valid:

dialogues:
  - q: "*RST"

And when trying to read() after write("*RST") will result in a visa timeout error ('cause there's nothing in the read buffer).

instr.write("*RST")
instr.query()  # raises VisaIOError timeout error

But in main (b0c2282), it's no longer valid and raises an error when parsing the yaml:

    def update_component(
        name: str, comp: Component, component_dict: Dict[str, Any]
    ) -> None:
        """Get a component from a component dict."""
        for dia in component_dict.get("dialogues", ()):
            try:
                comp.add_dialogue(*_get_pair(dia))
            except Exception as e:
                msg = "In device %s, malformed dialogue %s\n%r"
>               raise Exception(msg % (name, dia, e))
E               Exception: In device SMU, malformed dialogue {'q': '*RST'}
E               KeyError('r')

My main question is: Is this intentional?

It looks like the change happened in 970c18d, specifically here: 970c18d#diff-00ae6e38b897e23f5d5f4ba58764e2de759b6e39ab2db9ea9c57d9315a20def4L62-R72

Yes it's intentional

How should we define a command that shouldn't put anything in the read buffer?

The docs say to use a special null_response value, but that ends up actually getting returned:

dialogues:
  - q: "*RST"
    r: null_response
instr.write("*RST")
instr.query()  # expected: timeout error. Actual: "null_response"

Same with using null and the empty string `` in the yaml file:

dialogues:
  - q: "*RST"
    r: null
dialogues:
  - q: "*RST"
    r:

No, it's not intentional and is a bug

I'd be happy to add a test case for it and see if I can't resolve it.

"error: package directory 'pyvisa-sim/testsuite' does not exist"

Hi,

I'm getting the following error (I assume it's not critical, but wanted to report it nevertheless):

$ pip3.4 install --user --upgrade -v https://github.com/hgrecco/pyvisa-sim/zipball/master
Downloading/unpacking https://github.com/hgrecco/pyvisa-sim/zipball/master
Downloading master (unknown size):
Downloading from URL https://github.com/hgrecco/pyvisa-sim/zipball/master
...Downloading master (unknown size): 19kB downloaded
Running setup.py (path:/tmp/pip-dkcvbvbj-build/setup.py) egg_info for package from https://github.com/hgrecco/pyvisa-sim/zipball/master
running egg_info
creating pip-egg-info/PyVISA_sim.egg-info
writing requirements to pip-egg-info/PyVISA_sim.egg-info/requires.txt
writing pip-egg-info/PyVISA_sim.egg-info/PKG-INFO
writing top-level names to pip-egg-info/PyVISA_sim.egg-info/top_level.txt
writing dependency_links to pip-egg-info/PyVISA_sim.egg-info/dependency_links.txt
writing manifest file 'pip-egg-info/PyVISA_sim.egg-info/SOURCES.txt'
warning: manifest_maker: standard file '-c' not found

error: package directory 'pyvisa-sim/testsuite' does not exist
Complete output from command python setup.py egg_info:
running egg_info

creating pip-egg-info/PyVISA_sim.egg-info

writing requirements to pip-egg-info/PyVISA_sim.egg-info/requires.txt

writing pip-egg-info/PyVISA_sim.egg-info/PKG-INFO

writing top-level names to pip-egg-info/PyVISA_sim.egg-info/top_level.txt

writing dependency_links to pip-egg-info/PyVISA_sim.egg-info/dependency_links.txt

writing manifest file 'pip-egg-info/PyVISA_sim.egg-info/SOURCES.txt'

warning: manifest_maker: standard file '-c' not found

error: package directory 'pyvisa-sim/testsuite' does not exist


Cleaning up...
Removing temporary dir /tmp/pip_build_marquardt...
Command python setup.py egg_info failed with error code 1 in /tmp/pip-dkcvbvbj-build
Exception information:
Traceback (most recent call last):
File "/sw/python/anaconda3-2.0.1/lib/python3.4/site-packages/pip/basecommand.py", line 122, in main
status = self.run(options, args)
File "/sw/python/anaconda3-2.0.1/lib/python3.4/site-packages/pip/commands/install.py", line 278, in run
requirement_set.prepare_files(finder, force_root_egg_info=self.bundle, bundle=self.bundle)
File "/sw/python/anaconda3-2.0.1/lib/python3.4/site-packages/pip/req.py", line 1229, in prepare_files
req_to_install.run_egg_info()
File "/sw/python/anaconda3-2.0.1/lib/python3.4/site-packages/pip/req.py", line 325, in run_egg_info
command_desc='python setup.py egg_info')
File "/sw/python/anaconda3-2.0.1/lib/python3.4/site-packages/pip/util.py", line 697, in call_subprocess
% (command_desc, proc.returncode, cwd))
pip.exceptions.InstallationError: Command python setup.py egg_info failed with error code 1 in /tmp/pip-dkcvbvbj-build

Storing debug log for failure in /home/marquardt/.pip/pip.log

Support for concatenated commands

Numerous instrument support to receive several commands separated by a special character (';' most of the time). It would be nice to support that feature. (I often use it in instrument with channel when the channel selection must be done before hand using a special command, by concatenating both channel selection command and the actual command I can always be sure that the right channel is selected).

Parser: decouple resource definition from assignment to resource name

# Text file example
@instrument somename
# Here goes the defintions instrument definition from  
@end

@resource ASRL1::INSTR somename

And inserting an instrument from another file:

# In a file my_instrument.text 
@instrument somename
# Here goes the defintions
@end

# In another file
@resource ASRL1::INSTR from my_instrument.txt:instrument

See #3

Debug logging spits out each character individually

Debug logging prints every character individually, rather than just the sent command string:

INFO:root:Testing with simulated instrument.
DEBUG:pyvisa:Created library wrapper for mysim.yaml
DEBUG:pyvisa:Created ResourceManager with session 9128214
DEBUG:pyvisa:USB0::2391::35608::MY51144553::0::INSTR - opening ...
DEBUG:pyvisa:USB0::2391::35608::MY51144553::0::INSTR - is open with session 4172433
DEBUG:pyvisa:Writing into device input buffer: b':'
DEBUG:pyvisa:Writing into device input buffer: b'M'
DEBUG:pyvisa:Writing into device input buffer: b'E'
DEBUG:pyvisa:Writing into device input buffer: b'A'
DEBUG:pyvisa:Writing into device input buffer: b'S'
DEBUG:pyvisa:Writing into device input buffer: b'U'
DEBUG:pyvisa:Writing into device input buffer: b'R'
DEBUG:pyvisa:Writing into device input buffer: b'E'
DEBUG:pyvisa:Writing into device input buffer: b'?'
DEBUG:pyvisa:Writing into device input buffer: b'\r'
DEBUG:pyvisa:Writing into device input buffer: b'\n'
DEBUG:pyvisa:Found response in queries: b'1.23,2.34,3.45,4.56,5.67,6.78'
DEBUG:pyvisa:USB0::2391::35608::MY51144553::0::INSTR - reading 20480 bytes (last status <StatusCode.success_max_count_read: 1073676294>)
DEBUG:pyvisa:Closing ResourceManager (session: 9128214)
DEBUG:pyvisa:USB0::2391::35608::MY51144553::0::INSTR - closing
DEBUG:pyvisa:USB0::2391::35608::MY51144553::0::INSTR - is closed

Whereas running with a real instrument via the pyvisa-py backend logs nothing:

INFO:root:Testing with real instrument.
DEBUG:pyvisa:SerialSession was correctly imported.
DEBUG:pyvisa:USBSession and USBRawSession were correctly imported.
DEBUG:pyvisa:TCPIPSession was correctly imported.
DEBUG:pyvisa:GPIBSession was not imported No module named 'gpib'.
DEBUG:pyvisa:Created library wrapper for py
DEBUG:pyvisa:Created ResourceManager with session 8612875
DEBUG:pyvisa:USB0::2391::35608::MY51144553::0::INSTR - opening ...
DEBUG:pyvisa:USB0::2391::35608::MY51144553::0::INSTR - is open with session 2142339
DEBUG:pyvisa:USB0::2391::35608::MY51144553::0::INSTR - reading 20480 bytes (last status <StatusCode.success_max_count_read: 1073676294>)
DEBUG:pyvisa:Closing ResourceManager (session: 8612875)
DEBUG:pyvisa:USB0::2391::35608::MY51144553::0::INSTR - closing
DEBUG:pyvisa:USB0::2391::35608::MY51144553::0::INSTR - is closed

Steps to Reproduce:

  1. Create the mysim.yaml file and example.py files found below.
  2. Run example.py
  3. See the logs.

Actual Behavior

Each character is written in a separate log message.

Expected (Desired) Behavior

The full string is written in a single log message:

DEBUG:pyvisa:USB0::2391::35608::MY51144553::0::INSTR - is open with session 4172433
DEBUG:pyvisa:Writing into device input buffer: b':MEASURE?\r\n'
DEBUG:pyvisa:Found response in queries: b'1.23,2.34,3.45,4.56,5.67,6.78'

mysim.yaml

# mysim.yaml
---
spec: "1.1"

devices:
  # Keysight B2901A SMU
  SMU:
    eom:
      USB INSTR:
        q: "\r\n"
        r: "\n"
    dialogues:
      - q: "*IDN?"
        r: "Fake SMU"
      - q: ":MEASURE?"
        r: "1.23,2.34,3.45,4.56,5.67,6.78"

resources:
  "USB0::2391::35608::MY51144553::0::INSTR":
    device: "SMU"

example.py

import pyvisa

import logging

logging.basicConfig(level=logging.DEBUG)

addr = "USB0::2391::35608::MY51144553::0::INSTR"

logging.info("Testing with simulated instrument.")
rm = pyvisa.ResourceManager("mysim.yaml@sim")
instr = rm.open_resource(addr, read_termination="\n", write_termination="\r\n")
instr.query(":MEASURE?")
rm.close()

logging.info("")
logging.info("Testing with real instrument.")
rm = pyvisa.ResourceManager("@py")
instr = rm.open_resource(addr, read_termination="\n", write_termination="\r\n")
instr.query(":MEASURE?")
rm.close()

Add support for more complex dialogs

The idea would be to allow the following kind of dialog definition :
"M{mode}R{range}A{amplitude:+E6}"
The system would automatically query the values of the named properties (only properties should be allowed) and format the response string.
We could store a callable in the _dialogues dictionary and choose how to treat the response depending on whether or not it is a callable.

PyVISA has moved

PyVISA and its related project (pyvisa-py and pyvisa-sim) has been moved to its own organization.

Test for loading non-default config files

I'm not familiar enough with the CI build process to add such a fix, but it would be good to add tests that ensure non-default config loads work. This would also let us add intentionally broken config files to test error handling in that regard as well.

Add support for error queue

Some instrument write errors to an error queue which can be queried using a special command. I would need this for some instruments. Any idea @hgrecco about how to make error handling flexible enough to allow and say that a command need to hook into a device function ?

First attempt to create ResourceManager fails

Doing this fails :

>>> import pyvisa
>>> pyvisa.ResourceManager('@sim')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\takis\Desktop\Madar\Anaconda\lib\site-packages\pyvisa\highlevel.py", line 1477, in __new__
    visa_library = open_visa_library(visa_library)
  File "C:\Users\takis\Desktop\Madar\Anaconda\lib\site-packages\pyvisa\highlevel.py", line 1449, in open_visa_library
    return cls(argument)
  File "C:\Users\takis\Desktop\Madar\Anaconda\lib\site-packages\pyvisa\highlevel.py", line 95, in __new__
    raise OSError('Could not open VISA library:\n' + '\n'.join(errs))
OSError: Could not open VISA library:
While opening u
[Errno 2] No such file or directory: u'u'
While opening n
[Errno 2] No such file or directory: u'n'
While opening s
[Errno 2] No such file or directory: u's'
While opening e
[Errno 2] No such file or directory: u'e'
While opening t
[Errno 2] No such file or directory: u't'
>>>ResourceManager('@sim')
<ResourceManager(<VisaLibrary(u'u')>)>

I don't get why this happens.

multiple instances of ResourceMaganer

when I create multiple instance of ResourceManager, dialogue response is wrong.
Is it not recommended?

my environment:

  • python 3.8.10
  • PyVISA 1.11.3
  • PyVISA-py 0.5.2
  • PyVISA-sim 0.4.0

Random values as response

Is is possibile do define a query that return random values, for example random string or radom number?

for example:

  • q: "TRIGGER:A:MODE?"
    r: RANDOM("AUTO", "NORMAL", "ETC")

Thanks!

How to simulate binary write and query

Hello.

My setup version:
PyVISA-sim==0.4.0

  • pyvisa [required: >=1.11.0, installed: 1.11.3]
    • typing-extensions [required: Any, installed: 4.2.0]
  • PyYAML [required: Any, installed: 6.0]
  • stringparser [required: Any, installed: 0.5]

I am trying to simulate in unit test binary write (file transfer) command.
PyVisa command:
self._resource.write_binary_values(message, values, datatype=datatype)
The device is Rohde&Schwarz SMBV100B Vector Signal Generator.
The command should send the file to the virtual device, without raising system errors.

message = 'MMEM:DATA "/var/user/flight-plan.txt"'
values = b'RESOLUTION: 161897\n64.846910, 12.197980, 100\n64.882251, 12.197944, 100\n'
datatype = 'B'

But I don't know what to write to YAML file, or even if the pyvisa-sim has support for binary write.
The YAML file looks like that:

`spec: "1.0"

resources:
TCPIP0::gps-simulator::5025::SOCKET:
device: device 1

devices:
device 1:
eom:
TCPIP SOCKET:
q: "\n"
r: "\n"
error: ERROR
dialogues:
- q: "*CLS"
- q: "*RST"
- q: "*IDN?"
r: "TCPIP,MOCK,VERSION_1.0"
- q: "*OPC?"
r: 1
- q: "SYST:ERR?"
r: "+0,No error."
- q: 'MMEM:DATA "/var/user/flight-plan.txt" RESOLUTION: 161897\n64.846910, 12.197980, 100\n64.882251, 12.197944, 100\n'
properties:
frequency:
default: "1000"
getter:
q: "FREQ?"
r: "{:s}000000"
setter:
q: "FREQuency {:s} MHz"
e: "FREQ_ERROR"
specs:
type: str
`

Any ideas?

Allow writes with no expected response

Most of the SCPI based equipment I use (Agilent DMM, DAQ, etc.) if the command is write-only, will not allow you to do a read afterwards. The mocks must be queried (write+read) in order to flush the newline response. There should be some way to make the writes work without having to do a read.

Current workaround is overwriting my write() function with query() for the unittests, but I'd like a way to do this more cleanly.

New tag?

Hi,

it looks like there have been quite a few changes since the last tag was made and pushed to PyPi. I'm using 0.5.1 and am getting deprecation warnings about import pkg_resources which was removed in commit 434a4cf.

Any chance you could tag the latest and push to PyPi?

Is there a "reset instrument to defaults from yaml file" function or similar?

Is there a function/method that will reset a simulated instrument to the defaults defined in the yaml file?

What I'd like to be able to do is basically:

import pyvisa
rm = pyvisa.ResourceManager("myfile.yaml@sim")
instr = rm.OpenResource("ASRL1::INSTR")

instr.query("volt")  # 5, the default defined by myfile.yaml
instr.write("volt 10")
instr.query("volt")  # 10
instr.reset_to_defaults()  # magic function that I'm asking about
instr.query("volt")  # 5, the default defined by myfile.yaml

Does such a method exist? Closing the resource and/or the resource manager does not reset things (this might be related to #82).

Steps to Reproduce

Create this YAML file. I called it "doug_example.yaml":
---
spec: "1.1"

devices:

  MyDevice:
    eom:
      ASRL INSTR:
        q: "\r"
        r: "\r\n"
    error:
      response:
        command_error: "invalid command. Update the yaml file."
        query_error: "empty buffer"
    dialogues:
      - q: ";LC:DONE?"
        r: "done"
    properties:
      echo:
        default: "0"
        setter:
          q: "echo {}"
          r: "OK"
        getter:
          q: "echo?"
          r: "{}"

resources:
  "ASRL1::INSTR":
    device: "MyDevice"
Create this Python file. I called it "doug_example.py":
import pathlib

import pyvisa

VISA_ADDR = "ASRL1::INSTR"
SIM_BACKEND = str(pathlib.Path(__file__).parent / "doug_example.yaml@sim")


def create_instr() -> tuple[pyvisa.ResourceManager, pyvisa.Resource]:
    rm = pyvisa.ResourceManager(visa_library=SIM_BACKEND)

    instr = rm.open_resource(VISA_ADDR)
    instr.read_termination = "\r\n"
    instr.write_termination = "\r"

    print(f"ResourceManager session: {rm.session}")

    return rm, instr


rm, instr = create_instr()


want = "0"
got = instr.query("echo?")
correct = got == want
print(f"{got = }\t{want = }\t{correct = }")

want = "OK"
got = instr.query("echo 1")
correct = got == want
print(f"{got = }\t{want = }\t{correct = }")


want = "1"
got = instr.query("echo?")
correct = got == want
print(f"{got = }\t{want = }\t{correct = }")


# Magic reset command
print("Running reset")
rm.close()
print("Creating new resource manager and instrument")
rm, instr = create_instr()


want = "0"
got = instr.query("echo?")
correct = got == want
print(f"{got = }\t{want = }\t{correct = }")

Run python doug_example.py and get this output:

$ python doug_example.py 
ResourceManager session: 5282223
got = '0'       want = '0'      correct = True
got = 'OK'      want = 'OK'     correct = True
got = '1'       want = '1'      correct = True
Running reset
Creating new resource manager and instrument
ResourceManager session: 1299675
got = '1'       want = '0'      correct = False

Timeout when response termination character is None

I can successfully talk to my real device using the default termination characters of read: None, write: CRLF.

> pyvisa-shell

Welcome to the VISA shell. Type help or ? to list commands.

(visa) list
( 0) USB0::0x2A8D::0x5F01::MY54100878::0::INSTR
     alias: USBInstrument1
(visa) open 0
USB0::0x2A8D::0x5F01::MY54100878::0::INSTR has been opened.
You can talk to the device using "write", "read" or "query".
The default end of message is added to each message.
(open) termchar
Termchar read: None write: CRLF
(open) query *IDN?
Response: Keysight Technologies,E4990A,MY54100878,A.03.02

I'm trying to create a YAML file with the same termination characters to simulate the device.

With a response termination character of None, pyvisa-sim times out in USBInstrumentSession.read. It is pretty clear why this is the case, as the logic dictates it will continue sleeping when a falsey value is read from the device (see code here):

        while time.time() - start <= timeout:
            last = self.device.read()

            if not last:
                time.sleep(.01)
                continue

To reproduce, edit default.yaml and run the pyvisa-shell session below.

diff --git a/pyvisa-sim/default.yaml b/pyvisa-sim/default.yaml
index ecf6e59..6893031 100644
--- a/pyvisa-sim/default.yaml
+++ b/pyvisa-sim/default.yaml
@@ -7,7 +7,7 @@ devices:
         r: "\n"
       USB INSTR:
         q: "\n"
-        r: "\n"
+        r: ""
       TCPIP INSTR:
         q: "\n"
         r: "\n"
$ pyvisa-shell -b sim

Welcome to the VISA shell. Type help or ? to list commands.

(visa) list
( 0) ASRL1::INSTR
( 1) USB0::0x1111::0x2222::0x1234::0::INSTR
( 2) TCPIP0::localhost::inst0::INSTR
( 3) GPIB0::8::0::INSTR
( 4) ASRL2::INSTR
( 5) USB0::0x1111::0x2222::0x2468::0::INSTR
( 6) TCPIP0::localhost:2222::inst0::INSTR
( 7) GPIB0::9::0::INSTR
( 8) ASRL3::INSTR
( 9) USB0::0x1111::0x2222::0x3692::0::INSTR
(10) TCPIP0::localhost:3333::inst0::INSTR
(11) GPIB0::10::0::INSTR
(12) ASRL4::INSTR
(13) USB0::0x1111::0x2222::0x4444::0::INSTR
(14) TCPIP0::localhost:4444::inst0::INSTR
(15) GPIB0::4::0::INSTR
(visa) open 1
USB0::0x1111::0x2222::0x1234::0::INSTR has been opened.
You can talk to the device using "write", "read" or "query".
The default end of message is added to each message.
(open) termchar
Termchar read: None write: CRLF
(open) query ?IDN
VI_ERROR_TMO (-1073807339): Timeout expired before operation completed.

Consider renaming project

pyvisa-sim is not importable in a standard python interpreter. Even if most of the time people don't need to import it, I find it chocking to be enable to import. But I can live with it.

Add support for USB RAW

This is currently missing but is needed to fully test Lantz. Can we just copy/paste the INSTR version ?

How to work with multi-element properties?

Some of the instruments I'd like to simulate have settings that contain multiple elements/variables. For example, if I want to set the ramp rate of a heater, I send the following:

RAMP {output_idx}, {enable}, {rate}

{output_idx} is the output channel, {enable} is whether or not the heater should be turned on, and {rate} is what rate you want the heating to proceed at. All three need to be specified at once. How do I store all three settings in one property?

I currently have {output_id} set up as a channel, since the examples show how to retrieve channel ids, and that works elsewhere in my file. However, my attempts to set parameters such as default and boundary values do not work by putting the separate values in as tuples, dicts, or lists.

my setup (using lists) is:

spec: "1.1"
devices:
    device1:
        eom:
            GPIB INSTR:
                q: "\n"
                r: "\r\n"
        error: ERROR
        channels:
            out:
                ids: [1, 2]
                can_select: True
                properties:
                    ramp:
                        default: [0, 0]
                        getter:
                            q: "RAMP? {ch_id}"
                            r: "{0:d}, {1:.1f"}
                        setter:
                            q: "RAMP {ch_id}, {0:d}, {1:.1f}"
                            r: "Output {ch_id} set to {1:.1f} K/min"
                        specs:
                            min: [0, 0]
                            max: [1, 100]
                            type: [int, float]
resources:
    GPIB:01::INSTR:
        device: device1

The error is:

TypeError: Could not parse definitions file. 'Traceback (most recent call last):
  File "C:\path\to\pyvisa-sim\parser.py", line 144, in update_component
    getter, setter, prop_dict.get(\'specs\', {}))
  File "C:\path\to\pyvisa-sim\channels.py", line 112, in add_property
    default_value, specs)
  File "C:\path\to\pyvisa-sim\channels.py", line 28, in __init__
    super(ChannelProperty, self).__init__(name, default_value, specs)
  File "C:\path\to\pyvisa-sim\component.py", line 50, in __init__
    specs[key] = t(specs[key])
TypeError: \'str\' object is not callable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\path\to\pyvisa-sim\highlevel.py", line 65, in _init
    self.devices = parser.get_devices(self.library_path, False)
  File "C:\path\to\pyvisa-sim\parser.py", line 296, in get_devices
    get_device(device_name, dd, loader, resource_dict))
  File "C:\path\to\pyvisa-sim\parser.py", line 205, in get_device
    loader, resource_dict))
  File "C:\path\to\pyvisa-sim\parser.py", line 179, in get_channel
    update_component(ch_name, channels, channel_dict)
  File "C:\path\to\pyvisa-sim\parser.py", line 147, in update_component
    raise type(e)(msg % (name, prop_name, format_exc()))
TypeError: In device out, malformed property ramp
\'Traceback (most recent call last):
  File "C:\path\to\pyvisa-sim\parser.py", line 144, in update_component
    getter, setter, prop_dict.get(\'specs\', {}))
  File "C:\path\to\pyvisa-sim\channels.py", line 112, in add_property
    default_value, specs)
  File "C:\path\to\pyvisa-sim\channels.py", line 28, in __init__
    super(ChannelProperty, self).__init__(name, default_value, specs)
  File "C:\path\to\pyvisa-sim\component.py", line 50, in __init__
    specs[key] = t(specs[key])
TypeError: \'str\' object is not callable
\'
'

I cannot send the settings to the instrument as a list (i.e., no q: "RAMP {ch_id}, [{enable}, {rate}]"). Am I just wrong about how to specify/index entries to stringparser, or is this an absent feature?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.