temscript 2.1.0__tar.gz → 2.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. {temscript-2.1.0/temscript.egg-info → temscript-2.2.0}/PKG-INFO +4 -3
  2. {temscript-2.1.0 → temscript-2.2.0}/docs/changelog.rst +16 -0
  3. {temscript-2.1.0 → temscript-2.2.0}/docs/conf.py +1 -1
  4. {temscript-2.1.0 → temscript-2.2.0}/docs/restrictions.rst +4 -0
  5. temscript-2.2.0/scripts/test_com.py +34 -0
  6. {temscript-2.1.0 → temscript-2.2.0}/scripts/test_microscope.py +2 -0
  7. {temscript-2.1.0 → temscript-2.2.0}/setup.py +1 -1
  8. {temscript-2.1.0 → temscript-2.2.0}/temscript/_instrument_com.py +1 -1
  9. {temscript-2.1.0 → temscript-2.2.0}/temscript/base_microscope.py +50 -6
  10. {temscript-2.1.0 → temscript-2.2.0}/temscript/microscope.py +31 -4
  11. {temscript-2.1.0 → temscript-2.2.0}/temscript/null_microscope.py +0 -4
  12. {temscript-2.1.0 → temscript-2.2.0}/temscript/remote_microscope.py +5 -2
  13. {temscript-2.1.0 → temscript-2.2.0}/temscript/server.py +14 -14
  14. temscript-2.2.0/temscript/version.py +1 -0
  15. {temscript-2.1.0 → temscript-2.2.0/temscript.egg-info}/PKG-INFO +4 -3
  16. {temscript-2.1.0 → temscript-2.2.0}/temscript.egg-info/SOURCES.txt +1 -0
  17. temscript-2.1.0/temscript/version.py +0 -1
  18. {temscript-2.1.0 → temscript-2.2.0}/LICENSE +0 -0
  19. {temscript-2.1.0 → temscript-2.2.0}/MANIFEST.in +0 -0
  20. {temscript-2.1.0 → temscript-2.2.0}/README.md +0 -0
  21. {temscript-2.1.0 → temscript-2.2.0}/docs/Makefile +0 -0
  22. {temscript-2.1.0 → temscript-2.2.0}/docs/about.rst +0 -0
  23. {temscript-2.1.0 → temscript-2.2.0}/docs/index.rst +0 -0
  24. {temscript-2.1.0 → temscript-2.2.0}/docs/instrument.rst +0 -0
  25. {temscript-2.1.0 → temscript-2.2.0}/docs/make.bat +0 -0
  26. {temscript-2.1.0 → temscript-2.2.0}/docs/microscope.rst +0 -0
  27. {temscript-2.1.0 → temscript-2.2.0}/docs/requirements.txt +0 -0
  28. {temscript-2.1.0 → temscript-2.2.0}/docs/server.rst +0 -0
  29. {temscript-2.1.0 → temscript-2.2.0}/pyproject.toml +0 -0
  30. {temscript-2.1.0 → temscript-2.2.0}/scripts/run_null_server.py +0 -0
  31. {temscript-2.1.0 → temscript-2.2.0}/scripts/test_camera_acquisition.py +0 -0
  32. {temscript-2.1.0 → temscript-2.2.0}/scripts/test_instrument.py +0 -0
  33. {temscript-2.1.0 → temscript-2.2.0}/scripts/test_json_encoder.py +0 -0
  34. {temscript-2.1.0 → temscript-2.2.0}/setup.cfg +0 -0
  35. {temscript-2.1.0 → temscript-2.2.0}/temscript/__init__.py +0 -0
  36. {temscript-2.1.0 → temscript-2.2.0}/temscript/_com.py +0 -0
  37. {temscript-2.1.0 → temscript-2.2.0}/temscript/_instrument_stubs.py +0 -0
  38. {temscript-2.1.0 → temscript-2.2.0}/temscript/enums.py +0 -0
  39. {temscript-2.1.0 → temscript-2.2.0}/temscript/instrument.py +0 -0
  40. {temscript-2.1.0 → temscript-2.2.0}/temscript/marshall.py +0 -0
  41. {temscript-2.1.0 → temscript-2.2.0}/temscript.egg-info/dependency_links.txt +0 -0
  42. {temscript-2.1.0 → temscript-2.2.0}/temscript.egg-info/entry_points.txt +0 -0
  43. {temscript-2.1.0 → temscript-2.2.0}/temscript.egg-info/requires.txt +0 -0
  44. {temscript-2.1.0 → temscript-2.2.0}/temscript.egg-info/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: temscript
3
- Version: 2.1.0
4
- Summary: TEM Scripting adapter for FEI microscopes
3
+ Version: 2.2.0
4
+ Summary: TEM Scripting adapter for TFS/FEI transmission electron microscopes
5
5
  Home-page: https://github.com/niermann/temscript
6
6
  Author: Tore Niermann
7
7
  Author-email: tore.niermann@tu-berlin.de
@@ -29,6 +29,7 @@ Dynamic: description
29
29
  Dynamic: description-content-type
30
30
  Dynamic: home-page
31
31
  Dynamic: license
32
+ Dynamic: license-file
32
33
  Dynamic: platform
33
34
  Dynamic: project-url
34
35
  Dynamic: requires-dist
@@ -1,6 +1,22 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ Version 2.2.0
5
+ ^^^^^^^^^^^^^
6
+
7
+ * Added get_instrument_id(), which returns the microscope's serial number (D-number, without "D" prefix) from the
8
+ Windows registry (or an empty string if unavailable).
9
+ * Added get_computer_name(), which returns the hostname of the microscope computer.
10
+ * Deprecated get_microscope_id() as the term is ambiguous, use get_computer_name() or get_instrument_id() instead.
11
+ * Added "instrument_id" and "computer_name" entries to the dictionary returned by get_state(). The "microscope_id"
12
+ entry is deprecated and will be removed in future versions.
13
+
14
+ Version 2.1.1
15
+ ^^^^^^^^^^^^^
16
+
17
+ * Fixed error handling in server
18
+ * Don't throw error for get_stage_holder(), if no holder inserted
19
+
4
20
  Version 2.1.0
5
21
  ^^^^^^^^^^^^^
6
22
 
@@ -125,7 +125,7 @@ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
125
125
  # Add any paths that contain custom static files (such as style sheets) here,
126
126
  # relative to this directory. They are copied after the builtin static files,
127
127
  # so a file named "default.css" will overwrite the builtin "default.css".
128
- html_static_path = ['_static']
128
+ #html_static_path = ['_static']
129
129
 
130
130
  # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
131
131
  # using the given strftime format.
@@ -8,6 +8,10 @@ to this scripting interface, thus these issues also occur using `temscript`. As
8
8
  with the scripting interfaces by FEI or Thermo Fisher Scientific themself, known issues are listed here for the user's
9
9
  reference.
10
10
 
11
+ * The standard scripting interface does not expose the microscope's serial number (D-number).
12
+ ``get_instrument_id()`` reads the ``Instrument Key`` DWORD from ``HKEY_LOCAL_MACHINE\SOFTWARE\FEI\Configuration``
13
+ instead (verified on Titan 1.1), returning the number as decimal string without "D" prefix. If the value is
14
+ missing, inaccessible, not a DWORD, or zero, an empty string is returned.
11
15
  * Changing the projection mode from IMAGING to DIFFRACTION and back again changes the magnification in imaging
12
16
  mode (Titan 1.1).
13
17
  * :attr:`Projection.Magnification` does not return the actual magnification, but always 0.0 (Titan 1.1)
@@ -0,0 +1,34 @@
1
+ from temscript._com import CLSCTX_ALL, IUnknown, co_create_instance
2
+ from temscript._instrument_com import LongProperty, ObjectProperty
3
+ from uuid import UUID
4
+
5
+ # This test requires the TemscriptMockObject.dll to be registered
6
+ # Use "regsvr32.exe TemscriptMockObject.dll" with admin privileges to register it, before running this script
7
+ CLSID_MockObject = UUID('e5766dfa-303e-48a9-983e-352fa4a5a408')
8
+
9
+ class IChildObject(IUnknown):
10
+ IID = UUID('bbbd2968-4b93-49a9-b1ae-16d1d6b563eb')
11
+
12
+ value = LongProperty(get_index=3, put_index=4)
13
+
14
+
15
+ class IMockObject(IUnknown):
16
+ IID = UUID('bbbd2968-4b93-49a9-b1ae-16d1d6b563eb')
17
+
18
+ value = LongProperty(get_index=3, put_index=4)
19
+ child = ObjectProperty(IChildObject, get_index=5)
20
+
21
+
22
+ def test_mock_object():
23
+ obj = co_create_instance(CLSID_MockObject, CLSCTX_ALL, IMockObject)
24
+
25
+ obj.value = 123
26
+ assert obj.value == 123
27
+
28
+ child = obj.child
29
+ child.value = 321
30
+ assert child.value == 321
31
+ assert obj.value == 123
32
+
33
+
34
+ test_mock_object()
@@ -31,6 +31,8 @@ else:
31
31
 
32
32
  print("Microscope.get_family():", microscope.get_family())
33
33
  print("Microscope.get_microscope_id():", microscope.get_microscope_id())
34
+ print("Microscope.get_computer_name():", microscope.get_computer_name())
35
+ print("Microscope.get_instrument_id():", microscope.get_instrument_id())
34
36
  print("Microscope.get_version():", microscope.get_version())
35
37
  print("Microscope.get_voltage():", microscope.get_voltage())
36
38
  print("Microscope.get_vacuum():", microscope.get_vacuum())
@@ -14,7 +14,7 @@ with open("temscript/version.py") as fp:
14
14
 
15
15
  setup(name='temscript',
16
16
  version=__version__,
17
- description='TEM Scripting adapter for FEI microscopes',
17
+ description='TEM Scripting adapter for TFS/FEI transmission electron microscopes',
18
18
  author='Tore Niermann',
19
19
  author_email='tore.niermann@tu-berlin.de',
20
20
  long_description=long_description,
@@ -28,7 +28,7 @@ class LongProperty(BaseProperty):
28
28
  if self._get_index is None:
29
29
  raise AttributeError("Attribute %s is not readable" % self._name)
30
30
  result = ctypes.c_long(-1)
31
- prototype = ctypes.WINFUNCTYPE(ctypes.HRESULT, ctypes.c_void_p)(self._get_index, "get_property")
31
+ prototype = ctypes.WINFUNCTYPE(ctypes.HRESULT, ctypes.POINTER(ctypes.c_long))(self._get_index, "get_property")
32
32
  prototype(obj.get(), ctypes.byref(result))
33
33
  return result.value
34
34
 
@@ -84,14 +84,48 @@ class BaseMicroscope(ABC):
84
84
  """Return product family (see :class:`ProductFamily` for values): "TITAN", "TECNAI", ..."""
85
85
  raise NotImplementedError
86
86
 
87
- @abstractmethod
88
87
  def get_microscope_id(self):
89
88
  """
90
- Return microscope ID.
89
+ Return hostname of microscope's computer.
91
90
 
92
- There is no way to read this via the scripting adapter directly, thus this method uses hostname instead.
91
+ .. deprecated:: 2.2.0
92
+ The term "microscope ID" is ambiguous. FEI/TFS instruments identify themselves by the computer name
93
+ and the instrument ID (as also stored in Velox metadata), use :meth:`get_computer_name` or
94
+ :meth:`get_instrument_id` instead.
93
95
  """
94
- raise NotImplementedError
96
+ import warnings
97
+ warnings.warn("Microscope.get_microscope_id() is deprecated. "
98
+ "Use get_computer_name() and/or get_instrument_id() instead.",
99
+ category=DeprecationWarning, stacklevel=2)
100
+ return self.get_computer_name()
101
+
102
+ def get_computer_name(self):
103
+ """
104
+ Return name (hostname) of the microscope computer.
105
+
106
+ This corresponds to the computer name stored by FEI/TFS software, e.g. in Velox metadata.
107
+
108
+ .. versionadded:: 2.2.0
109
+ """
110
+ import socket
111
+ return socket.gethostname()
112
+
113
+ def get_instrument_id(self):
114
+ """
115
+ Return serial number of the microscope as string of decimal digits (without the "D" prefix,
116
+ e.g. "1234" for D1234).
117
+
118
+ :class:`Microscope` reads the ``Instrument Key`` DWORD from
119
+ ``HKEY_LOCAL_MACHINE\\SOFTWARE\\FEI\\Configuration`` in the Windows registry. If the serial number
120
+ is not available, an empty string is returned. See :ref:`restrictions` for details.
121
+
122
+ This corresponds to the instrument ID stored by FEI/TFS software, e.g. in Velox metadata.
123
+
124
+ The default implementation returns an empty string.
125
+
126
+ .. versionadded:: 2.2.0
127
+ """
128
+ return ""
95
129
 
96
130
  @abstractmethod
97
131
  def get_version(self):
@@ -1131,10 +1165,19 @@ class BaseMicroscope(ABC):
1131
1165
 
1132
1166
  .. versionchanged:: 2.0
1133
1167
  The method was renamed from get_optics_state() to get_state()
1168
+
1169
+ .. versionchanged:: 2.2.0
1170
+ Added "instrument_id" and "computer_name" entries.
1171
+
1172
+ .. deprecated:: 2.2.0
1173
+ The "microscope_id" entry is deprecated and will be removed in future versions. It contains the
1174
+ same value as "computer_name", use that entry instead. See :meth:`get_microscope_id`.
1134
1175
  """
1135
1176
  state = {
1136
1177
  "family": self.get_family(),
1137
- "microscope_id": self.get_microscope_id(),
1178
+ "microscope_id": self.get_computer_name(),
1179
+ "instrument_id": self.get_instrument_id(),
1180
+ "computer_name": self.get_computer_name(),
1138
1181
  "temscript_version": self.get_version(),
1139
1182
  "voltage(kV)": self.get_voltage(),
1140
1183
  "stage_holder": self.get_stage_holder(),
@@ -1182,5 +1225,6 @@ class BaseMicroscope(ABC):
1182
1225
  use :meth:`get_state` instead.
1183
1226
  """
1184
1227
  import warnings
1185
- warnings.warn("Microscope.get_optics_state() is deprecated. Use get_state() instead.", DeprecationWarning)
1228
+ warnings.warn("Microscope.get_optics_state() is deprecated. Use get_state() instead.",
1229
+ category=DeprecationWarning, stacklevel=2)
1186
1230
  return self.get_state()
@@ -1,3 +1,4 @@
1
+ import functools
1
2
  import math
2
3
 
3
4
  from temscript.base_microscope import set_enum_attr_from_dict, set_attr_from_dict
@@ -7,6 +8,27 @@ from .instrument import CCDCamera, GetInstrument, STEMDetector
7
8
  from .enums import *
8
9
 
9
10
 
11
+ # Computer name and instrument ID are properties of the machine, thus cached at module level
12
+ # (and not per instance, which would keep instances alive).
13
+ @functools.lru_cache(maxsize=None)
14
+ def _get_computer_name():
15
+ import socket
16
+ return socket.gethostname()
17
+
18
+
19
+ @functools.lru_cache(maxsize=None)
20
+ def _get_instrument_id():
21
+ import winreg
22
+ try:
23
+ with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\FEI\Configuration") as key:
24
+ value, value_type = winreg.QueryValueEx(key, "Instrument Key")
25
+ if value_type == winreg.REG_DWORD and value > 0:
26
+ return str(value)
27
+ except OSError:
28
+ pass # Missing key/value or access denied.
29
+ return ""
30
+
31
+
10
32
  class Microscope(BaseMicroscope):
11
33
  """
12
34
  Hich level interface to local microscope.
@@ -38,9 +60,11 @@ class Microscope(BaseMicroscope):
38
60
  def get_family(self):
39
61
  return ProductFamily(self._family).name
40
62
 
41
- def get_microscope_id(self):
42
- import socket
43
- return socket.gethostname()
63
+ def get_computer_name(self):
64
+ return _get_computer_name()
65
+
66
+ def get_instrument_id(self):
67
+ return _get_instrument_id()
44
68
 
45
69
  def get_version(self):
46
70
  from .version import __version__
@@ -79,7 +103,10 @@ class Microscope(BaseMicroscope):
79
103
  self._tem_vacuum.ColumnValvesOpen = state
80
104
 
81
105
  def get_stage_holder(self):
82
- return self._tem_stage.Holder.name
106
+ try:
107
+ return self._tem_stage.Holder.name
108
+ except OSError:
109
+ return ""
83
110
 
84
111
  def get_stage_status(self):
85
112
  return self._tem_stage.Status.name
@@ -122,10 +122,6 @@ class NullMicroscope(BaseMicroscope):
122
122
  def get_family(self):
123
123
  return "NULL"
124
124
 
125
- def get_microscope_id(self):
126
- import socket
127
- return socket.gethostname()
128
-
129
125
  def get_version(self):
130
126
  from .version import __version__
131
127
  return __version__
@@ -130,8 +130,11 @@ class RemoteMicroscope(BaseMicroscope):
130
130
  def get_family(self):
131
131
  return self._request("GET", "/v1/family")[1]
132
132
 
133
- def get_microscope_id(self):
134
- return self._request("GET", "/v1/microscope_id")[1]
133
+ def get_computer_name(self):
134
+ return self._request("GET", "/v1/computer_name")[1]
135
+
136
+ def get_instrument_id(self):
137
+ return self._request("GET", "/v1/instrument_id")[1]
135
138
 
136
139
  def get_version(self):
137
140
  return self._request("GET", "/v1/version")[1]
@@ -8,15 +8,15 @@ from .marshall import ExtendedJsonEncoder, gzip_encode, MIME_TYPE_PICKLE, MIME_T
8
8
 
9
9
 
10
10
  class MicroscopeHandler(BaseHTTPRequestHandler):
11
- GET_V1_FORWARD = ("family", "microscope_id", "version", "voltage", "vacuum", "stage_holder",
12
- "stage_status", "stage_position", "stage_limits", "detectors", "cameras", "stem_detectors",
13
- "stem_acquisition_param", "image_shift", "beam_shift", "beam_tilt", "projection_sub_mode",
14
- "projection_mode", "projection_mode_string", "magnification_index", "indicated_camera_length",
15
- "indicated_magnification", "defocus", "objective_excitation", "intensity", "objective_stigmator",
16
- "condenser_stigmator", "diffraction_shift", "screen_current", "screen_position",
17
- "illumination_mode", "condenser_mode", "illuminated_area", "probe_defocus", "convergence_angle",
18
- "stem_magnification", "stem_rotation", "spot_size_index", "dark_field_mode", "beam_blanked",
19
- "instrument_mode", 'optics_state', 'state', 'column_valves_open')
11
+ GET_V1_FORWARD = ("family", "microscope_id", "instrument_id", "computer_name", "version", "voltage", "vacuum",
12
+ "stage_holder", "stage_status", "stage_position", "stage_limits", "detectors", "cameras",
13
+ "stem_detectors", "stem_acquisition_param", "image_shift", "beam_shift", "beam_tilt",
14
+ "projection_sub_mode", "projection_mode", "projection_mode_string", "magnification_index",
15
+ "indicated_camera_length", "indicated_magnification", "defocus", "objective_excitation",
16
+ "intensity", "objective_stigmator", "condenser_stigmator", "diffraction_shift", "screen_current",
17
+ "screen_position", "illumination_mode", "condenser_mode", "illuminated_area", "probe_defocus",
18
+ "convergence_angle", "stem_magnification", "stem_rotation", "spot_size_index", "dark_field_mode",
19
+ "beam_blanked", "instrument_mode", 'optics_state', 'state', 'column_valves_open')
20
20
 
21
21
  PUT_V1_FORWARD = ("image_shift", "beam_shift", "beam_tilt", "projection_mode", "magnification_index",
22
22
  "defocus", "intensity", "diffraction_shift", "objective_stigmator", "condenser_stigmator",
@@ -58,7 +58,7 @@ class MicroscopeHandler(BaseHTTPRequestHandler):
58
58
  else:
59
59
  content_encoding = None
60
60
  except Exception as exc:
61
- self.log_error("Exception raised during encoding of response: %s" % repr(exc))
61
+ self.log_error("Exception raised during encoding of response: %s", repr(exc))
62
62
  self.send_error(500, "Error handling request '%s': %s" % (self.path, str(exc)))
63
63
  else:
64
64
  self.send_response(200)
@@ -146,10 +146,10 @@ class MicroscopeHandler(BaseHTTPRequestHandler):
146
146
  else:
147
147
  raise KeyError('Unknown API version: %s' % self.path)
148
148
  except KeyError as exc:
149
- self.log_error("KeyError raised during handling of GET request '%s': %s" % (self.path, repr(exc)))
149
+ self.log_error("KeyError raised during handling of GET request '%s': %s", self.path, repr(exc))
150
150
  self.send_error(404, str(exc))
151
151
  except Exception as exc:
152
- self.log_error("Exception raised during handling of GET request '%s': %s" % (self.path, repr(exc)))
152
+ self.log_error("Exception raised during handling of GET request '%s': %s", self.path, repr(exc))
153
153
  self.send_error(500, "Error handling request '%s': %s" % (self.path, str(exc)))
154
154
  else:
155
155
  self.build_response(response)
@@ -163,10 +163,10 @@ class MicroscopeHandler(BaseHTTPRequestHandler):
163
163
  else:
164
164
  raise KeyError('Unknown API version: %s' % self.path)
165
165
  except KeyError as exc:
166
- self.log_error("KeyError raised during handling of GET request '%s': %s" % (self.path, repr(exc)))
166
+ self.log_error("KeyError raised during handling of GET request '%s': %s" , self.path, repr(exc))
167
167
  self.send_error(404, str(exc))
168
168
  except Exception as exc:
169
- self.log_error("Exception raised during handling of GET request '%s': %s" % (self.path, repr(exc)))
169
+ self.log_error("Exception raised during handling of GET request '%s': %s" , self.path, repr(exc))
170
170
  self.send_error(500, "Error handling request '%s': %s" % (self.path, str(exc)))
171
171
  else:
172
172
  self.build_response(response)
@@ -0,0 +1 @@
1
+ __version__ = '2.2.0'
@@ -1,7 +1,7 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: temscript
3
- Version: 2.1.0
4
- Summary: TEM Scripting adapter for FEI microscopes
3
+ Version: 2.2.0
4
+ Summary: TEM Scripting adapter for TFS/FEI transmission electron microscopes
5
5
  Home-page: https://github.com/niermann/temscript
6
6
  Author: Tore Niermann
7
7
  Author-email: tore.niermann@tu-berlin.de
@@ -29,6 +29,7 @@ Dynamic: description
29
29
  Dynamic: description-content-type
30
30
  Dynamic: home-page
31
31
  Dynamic: license
32
+ Dynamic: license-file
32
33
  Dynamic: platform
33
34
  Dynamic: project-url
34
35
  Dynamic: requires-dist
@@ -16,6 +16,7 @@ docs/restrictions.rst
16
16
  docs/server.rst
17
17
  scripts/run_null_server.py
18
18
  scripts/test_camera_acquisition.py
19
+ scripts/test_com.py
19
20
  scripts/test_instrument.py
20
21
  scripts/test_json_encoder.py
21
22
  scripts/test_microscope.py
@@ -1 +0,0 @@
1
- __version__ = '2.1.0'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes