deapi 5.3b6__tar.gz → 5.3.1__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.
- {deapi-5.3b6 → deapi-5.3.1}/.github/workflows/build.yaml +2 -2
- deapi-5.3.1/.github/workflows/prepare_release.yml +192 -0
- {deapi-5.3b6 → deapi-5.3.1}/.pre-commit-config.yaml +1 -1
- deapi-5.3.1/CHANGES.rst +92 -0
- {deapi-5.3b6 → deapi-5.3.1}/PKG-INFO +6 -5
- {deapi-5.3b6 → deapi-5.3.1}/deapi/buffer_protocols/__init__.py +1 -2
- deapi-5.3.1/deapi/buffer_protocols/pb_6_33_4.py +47 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/client.py +83 -51
- {deapi-5.3b6 → deapi-5.3.1}/deapi/data_types.py +2 -2
- {deapi-5.3b6 → deapi-5.3.1}/deapi/simulated_server/fake_server.py +20 -2
- {deapi-5.3b6 → deapi-5.3.1}/deapi/simulated_server/initialize_server.py +33 -1
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/conftest.py +16 -2
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_client.py +17 -7
- deapi-5.3.1/deapi/tests/test_fake_server/test_partial_sends.py +92 -0
- deapi-5.3.1/deapi/tests/test_fake_server/test_twin_server.py +96 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_scanning/test_virtual_image_buffers.py +8 -6
- {deapi-5.3b6 → deapi-5.3.1}/deapi/version.py +3 -2
- {deapi-5.3b6 → deapi-5.3.1}/deapi.egg-info/PKG-INFO +6 -5
- {deapi-5.3b6 → deapi-5.3.1}/deapi.egg-info/SOURCES.txt +10 -1
- {deapi-5.3b6 → deapi-5.3.1}/deapi.egg-info/requires.txt +6 -1
- deapi-5.3.1/doc/_static/digital_twin_holes.png +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/help/pyDEServer.rst +24 -1
- deapi-5.3.1/examples/digital_twin/README.rst +6 -0
- deapi-5.3.1/examples/digital_twin/imaging_holes_with_the_digital_twin_sgskip.py +147 -0
- {deapi-5.3b6 → deapi-5.3.1}/pyproject.toml +55 -5
- deapi-5.3.1/upcoming_changes/.gitkeep +0 -0
- deapi-5.3.1/upcoming_changes/README.rst +92 -0
- deapi-5.3b6/CHANGES.rst +0 -48
- {deapi-5.3b6 → deapi-5.3.1}/.github/workflows/documentation.yaml +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/.github/workflows/publish.yaml +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/.github/workflows/test-publish.yaml +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/LICENSE +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/README.md +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/Guide to use mamba.pdf +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/__init__.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/buffer_protocols/pb_2_3_0.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/buffer_protocols/pb_3_11_4.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/buffer_protocols/pb_3_19_3.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/buffer_protocols/pb_3_23_3.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/buffer_protocols/pb_3_6_1.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/conf.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/fake_data/__init__.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/fake_data/base_fake_data.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/fake_data/grains.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/index.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/prop_dump.json +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/python_3_instruction.txt +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/release_notes.txt +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/service/de_service.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/simulated_server/__init__.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/__init__.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/01_fps.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/02_hwRoisize.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/03_hwBinning.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/04_swBinning.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/05_swhwBinning.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/06_patternPixel.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/07_reference.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/08_virtmask.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/09_scanRoi.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/10_imageStatistics.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/__init__.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/func.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/propertyName.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/original_tests/test_legacy.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/speed_tests/__init__.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/speed_tests/test_internal_file_saving.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/speed_tests/test_movie_buffer_transfer.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_binning_rois/__init__.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_binning_rois/test_rois.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_examples.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_fake_server/__init__.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_fake_server/test_server.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_file_saving/__init__.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_file_saving/test_file_loading_libertem.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_file_saving/test_file_loading_rsciio.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_file_saving/test_h5ebsd.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_file_saving/test_scan_pattern_saving.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_insitu/__init__.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_insitu/test_start_stop.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_scanning/__init__.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_scanning/test_continual_scanning.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_utils/__init__.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/tests/test_utils/test_utils.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/utils.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi/wrappers.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi.egg-info/dependency_links.txt +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi.egg-info/entry_points.txt +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/deapi.egg-info/top_level.txt +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/Makefile +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/_static/ScanPatterns.png +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/_static/de_api_icon.svg +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/_templates/autosummary/base.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/_templates/custom-attribute-template.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/_templates/custom-class-template.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/_templates/custom-function-template.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/_templates/custom-module-template.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/_templates/custrom-method-template.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/changes.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/conf.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/help/dev_guide.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/help/help.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/help/index.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/index.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/intro.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/make.bat +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/reference/index.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/doc/reference/scan_design.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/README.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/live_imaging/README.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/live_imaging/bright_spot_intensity.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/live_imaging/taking_an_image_every_minute.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/live_imaging/viewing_the_sensor.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/live_imaging/viewing_the_sensor_tem.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/references/README.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/setting_parameters/README.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/setting_parameters/setting_up_stem.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/virtual_imaging/README.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/virtual_imaging/setting_virtual_masks.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/virtual_imaging/vdf_vbf.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/visualization/README.rst +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/visualization/creating_a_simple_dashboard.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/examples/visualization/using_get_result.py +0 -0
- {deapi-5.3b6 → deapi-5.3.1}/setup.cfg +0 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
name: Prepare Release
|
|
2
|
+
|
|
3
|
+
# Run manually from the Actions tab.
|
|
4
|
+
# Opens a PR that bumps the version in pyproject.toml and builds CHANGES.rst from
|
|
5
|
+
# the towncrier fragments in upcoming_changes/. After merging it, create the GitHub
|
|
6
|
+
# Release by hand (tag v<version>); publishing the release triggers publish.yaml,
|
|
7
|
+
# which uploads to PyPI.
|
|
8
|
+
on:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
inputs:
|
|
11
|
+
bump:
|
|
12
|
+
description: "Version component to bump"
|
|
13
|
+
required: true
|
|
14
|
+
type: choice
|
|
15
|
+
options:
|
|
16
|
+
- pre-release # increments the bN counter on the current base version (5.3b6 -> 5.3.0b7)
|
|
17
|
+
- finalize # drop the bN suffix: release the current beta's base as stable (5.3b6 -> 5.3.0)
|
|
18
|
+
- minor
|
|
19
|
+
- bugfix
|
|
20
|
+
- major
|
|
21
|
+
beta:
|
|
22
|
+
description: "Mark as beta pre-release (adds bN suffix). Ignored for 'pre-release' (always beta) and 'finalize' (always stable)."
|
|
23
|
+
required: false
|
|
24
|
+
type: boolean
|
|
25
|
+
default: false
|
|
26
|
+
|
|
27
|
+
permissions:
|
|
28
|
+
contents: write # push branch
|
|
29
|
+
pull-requests: write # open PR
|
|
30
|
+
|
|
31
|
+
jobs:
|
|
32
|
+
prepare:
|
|
33
|
+
name: Prepare release PR
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
|
|
36
|
+
steps:
|
|
37
|
+
- name: Checkout repository
|
|
38
|
+
uses: actions/checkout@v4
|
|
39
|
+
with:
|
|
40
|
+
fetch-depth: 0
|
|
41
|
+
|
|
42
|
+
- name: Set up uv
|
|
43
|
+
uses: astral-sh/setup-uv@v5
|
|
44
|
+
with:
|
|
45
|
+
python-version: "3.13"
|
|
46
|
+
enable-cache: true
|
|
47
|
+
|
|
48
|
+
# ── Compute the new version ──────────────────────────────────────────
|
|
49
|
+
- name: Compute new version
|
|
50
|
+
id: version
|
|
51
|
+
env:
|
|
52
|
+
BUMP: ${{ inputs.bump }}
|
|
53
|
+
IS_BETA: ${{ inputs.beta }}
|
|
54
|
+
run: |
|
|
55
|
+
CURRENT=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/')
|
|
56
|
+
export CURRENT_VERSION="$CURRENT"
|
|
57
|
+
|
|
58
|
+
NEW_VERSION=$(python3 - <<'PYEOF'
|
|
59
|
+
import re, os
|
|
60
|
+
|
|
61
|
+
current = os.environ["CURRENT_VERSION"]
|
|
62
|
+
bump = os.environ["BUMP"]
|
|
63
|
+
is_beta = os.environ["IS_BETA"].lower() == "true"
|
|
64
|
+
|
|
65
|
+
# deapi's versions have had no patch component (5.3b6); read it as 0 and
|
|
66
|
+
# always write major.minor.patch from here on (5.3b6 == 5.3.0b6 in PEP 440).
|
|
67
|
+
m = re.match(r"^(\d+)\.(\d+)(?:\.(\d+))?(?:b(\d+))?$", current)
|
|
68
|
+
if not m:
|
|
69
|
+
raise SystemExit(f"cannot parse the current version {current!r}")
|
|
70
|
+
major = int(m.group(1))
|
|
71
|
+
minor = int(m.group(2))
|
|
72
|
+
patch = int(m.group(3) or 0)
|
|
73
|
+
beta_n = int(m.group(4)) if m.group(4) else None
|
|
74
|
+
on_beta = beta_n is not None
|
|
75
|
+
|
|
76
|
+
if bump == "finalize":
|
|
77
|
+
# Release the current beta's base as stable: just drop the bN
|
|
78
|
+
# suffix, keep major.minor.patch. e.g. 5.3.0b7 -> 5.3.0.
|
|
79
|
+
if not on_beta:
|
|
80
|
+
raise SystemExit(
|
|
81
|
+
f"'finalize' requires a beta base version, but current "
|
|
82
|
+
f"version {current!r} has no bN suffix. Use minor / bugfix "
|
|
83
|
+
f"/ major to start a new release instead."
|
|
84
|
+
)
|
|
85
|
+
is_beta = False
|
|
86
|
+
elif bump == "pre-release":
|
|
87
|
+
# Keep the same base; just walk the beta counter forward.
|
|
88
|
+
is_beta = True
|
|
89
|
+
beta_n = (beta_n or 0) + 1
|
|
90
|
+
elif on_beta:
|
|
91
|
+
# We are on a beta of the NEXT release (e.g. 5.3.0b7). The base
|
|
92
|
+
# major.minor.patch is that upcoming version, so minor/bugfix/major
|
|
93
|
+
# would skip it entirely. The common intent from a beta is
|
|
94
|
+
# 'finalize', so steer the user there rather than guess.
|
|
95
|
+
raise SystemExit(
|
|
96
|
+
f"Current version {current!r} is a beta of the upcoming "
|
|
97
|
+
f"{major}.{minor}.{patch} release. To ship it, use bump="
|
|
98
|
+
f"'finalize' (-> {major}.{minor}.{patch}). A '{bump}' bump from "
|
|
99
|
+
f"a beta would skip {major}.{minor}.{patch} entirely; "
|
|
100
|
+
f"that is almost never intended."
|
|
101
|
+
)
|
|
102
|
+
elif bump == "major":
|
|
103
|
+
major, minor, patch = major + 1, 0, 0
|
|
104
|
+
elif bump == "minor":
|
|
105
|
+
minor, patch = minor + 1, 0
|
|
106
|
+
elif bump == "bugfix":
|
|
107
|
+
patch += 1
|
|
108
|
+
|
|
109
|
+
if is_beta:
|
|
110
|
+
if bump != "pre-release":
|
|
111
|
+
beta_n = 1 # fresh beta series for the new base
|
|
112
|
+
print(f"{major}.{minor}.{patch}b{beta_n}", end="")
|
|
113
|
+
else:
|
|
114
|
+
print(f"{major}.{minor}.{patch}", end="")
|
|
115
|
+
PYEOF
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Derive is_beta from the COMPUTED version (ends in bN?), not the raw input.
|
|
119
|
+
if [[ "$NEW_VERSION" =~ b[0-9]+$ ]]; then IS_BETA_OUT=true; else IS_BETA_OUT=false; fi
|
|
120
|
+
|
|
121
|
+
echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
|
|
122
|
+
echo "tag=v$NEW_VERSION" >> "$GITHUB_OUTPUT"
|
|
123
|
+
echo "branch=release/v$NEW_VERSION" >> "$GITHUB_OUTPUT"
|
|
124
|
+
echo "is_beta=$IS_BETA_OUT" >> "$GITHUB_OUTPUT"
|
|
125
|
+
echo "Bumping (${{ inputs.bump }}): $CURRENT → $NEW_VERSION"
|
|
126
|
+
|
|
127
|
+
# ── Bump version strings ─────────────────────────────────────────────
|
|
128
|
+
# Only the package version: deapi/version.py holds the client's protocol
|
|
129
|
+
# version (sent to DE-Server), which does not follow package releases.
|
|
130
|
+
- name: Bump version in pyproject.toml
|
|
131
|
+
run: |
|
|
132
|
+
sed -i 's/^version = ".*"/version = "${{ steps.version.outputs.new_version }}"/' pyproject.toml
|
|
133
|
+
|
|
134
|
+
# ── Build changelog ──────────────────────────────────────────────────
|
|
135
|
+
- name: Build changelog with towncrier
|
|
136
|
+
run: |
|
|
137
|
+
FRAGMENT_COUNT=$(find upcoming_changes -maxdepth 1 -name "*.rst" \
|
|
138
|
+
! -name "README.rst" | wc -l)
|
|
139
|
+
if [ "$FRAGMENT_COUNT" -eq 0 ]; then
|
|
140
|
+
echo "⚠ No news fragments found — skipping towncrier (CHANGES.rst unchanged)."
|
|
141
|
+
else
|
|
142
|
+
uvx towncrier build --yes --version "${{ steps.version.outputs.new_version }}"
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
# ── Commit and push ──────────────────────────────────────────────────
|
|
146
|
+
- name: Configure git
|
|
147
|
+
run: |
|
|
148
|
+
git config user.name "github-actions[bot]"
|
|
149
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
150
|
+
|
|
151
|
+
- name: Commit release changes
|
|
152
|
+
run: |
|
|
153
|
+
git checkout -b "${{ steps.version.outputs.branch }}"
|
|
154
|
+
|
|
155
|
+
# Stage the version bump, updated changelog, and consumed fragments.
|
|
156
|
+
git add pyproject.toml CHANGES.rst
|
|
157
|
+
git add -A upcoming_changes/ # stages deleted fragment files
|
|
158
|
+
|
|
159
|
+
git commit -m "chore: prepare release ${{ steps.version.outputs.tag }}"
|
|
160
|
+
git push origin "${{ steps.version.outputs.branch }}"
|
|
161
|
+
|
|
162
|
+
# ── Open pull request ────────────────────────────────────────────────
|
|
163
|
+
- name: Open pull request
|
|
164
|
+
env:
|
|
165
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
166
|
+
TAG: ${{ steps.version.outputs.tag }}
|
|
167
|
+
BRANCH: ${{ steps.version.outputs.branch }}
|
|
168
|
+
IS_BETA: ${{ steps.version.outputs.is_beta }}
|
|
169
|
+
run: |
|
|
170
|
+
if [ "$IS_BETA" = "true" ]; then PRE="tick **Set as a pre-release**"; else PRE="leave **Set as a pre-release** unticked"; fi
|
|
171
|
+
gh pr create \
|
|
172
|
+
--title "Release ${TAG}" \
|
|
173
|
+
--base main \
|
|
174
|
+
--head "${BRANCH}" \
|
|
175
|
+
--body "## Release ${TAG}
|
|
176
|
+
|
|
177
|
+
> Auto-generated by the **Prepare Release** workflow.
|
|
178
|
+
|
|
179
|
+
### What changed
|
|
180
|
+
- Version bumped to \`${TAG#v}\` in \`pyproject.toml\`
|
|
181
|
+
- \`CHANGES.rst\` updated from the towncrier fragments in \`upcoming_changes/\`
|
|
182
|
+
|
|
183
|
+
### Review checklist
|
|
184
|
+
- [ ] \`CHANGES.rst\` reads well — edit the text directly in this PR if needed
|
|
185
|
+
- [ ] The version in \`pyproject.toml\` is correct
|
|
186
|
+
- [ ] CI passes
|
|
187
|
+
|
|
188
|
+
### After merging
|
|
189
|
+
Create the GitHub Release by hand: **Releases → Draft a new release**, tag
|
|
190
|
+
\`${TAG}\` on \`main\`, paste this version's section of \`CHANGES.rst\` as the
|
|
191
|
+
notes, ${PRE}, and publish. Publishing it runs \`publish.yaml\`, which uploads
|
|
192
|
+
to PyPI."
|
deapi-5.3.1/CHANGES.rst
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
.. _changelog:
|
|
2
|
+
|
|
3
|
+
Changelog
|
|
4
|
+
*********
|
|
5
|
+
|
|
6
|
+
This document describes the changes in the DEAPI library.
|
|
7
|
+
|
|
8
|
+
Changes are filed as fragment files in ``upcoming_changes/`` and assembled into this
|
|
9
|
+
file by `towncrier <https://towncrier.readthedocs.io/>`_ when a release is prepared
|
|
10
|
+
(see ``upcoming_changes/README.rst``).
|
|
11
|
+
|
|
12
|
+
.. towncrier release notes start
|
|
13
|
+
|
|
14
|
+
5.3.1 (2026-09-25)
|
|
15
|
+
==================
|
|
16
|
+
|
|
17
|
+
Maintenance
|
|
18
|
+
-----------
|
|
19
|
+
|
|
20
|
+
- Bumped the google protobuf version to 6.33 and dropped support for Python < 3.10. Closes #3691 (`#64 <https://github.com/directelectron/deapi/pull/64>`_)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
5.3.0 (2026-09-24)
|
|
24
|
+
==================
|
|
25
|
+
|
|
26
|
+
New Features
|
|
27
|
+
------------
|
|
28
|
+
|
|
29
|
+
- ``pydeserver --twin`` serves frames rendered by the `de-twin <https://github.com/directelectron/de-twin>`_ digital twin instead of the built-in fake data: a simulated microscope, specimen and detector, with a DE-TEM-Channel (``--soap-port``) so stage and optics changes show up in the images. Install it with ``pip install "deapi[twin]"``. (`#59 <https://github.com/directelectron/deapi/pull/59>`_)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
Bug Fixes
|
|
33
|
+
---------
|
|
34
|
+
|
|
35
|
+
- Fixed virtual masks and XY scan arrays sometimes arriving incomplete, which hung the connection (seen on macOS): the client now sends every byte of them. (`#60 <https://github.com/directelectron/deapi/pull/60>`_)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
Documentation
|
|
39
|
+
-------------
|
|
40
|
+
|
|
41
|
+
- Added an example that moves the stage with ``de_microscope`` and images holes in a grid, run against the digital twin. (`#59 <https://github.com/directelectron/deapi/pull/59>`_)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
Maintenance
|
|
45
|
+
-----------
|
|
46
|
+
|
|
47
|
+
- The simulated server closes a connection after an error, so the client gets an error instead of waiting; the test suite only stops deapi's own simulated server on port 13240, never a real DE-Server. (`#60 <https://github.com/directelectron/deapi/pull/60>`_)
|
|
48
|
+
- Releases are prepared by the **Prepare Release** workflow, and the changelog is assembled from towncrier fragments in ``upcoming_changes/``, as in the other Direct Electron Python packages. (`#61 <https://github.com/directelectron/deapi/pull/61>`_)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
5.3.beta6
|
|
52
|
+
=========
|
|
53
|
+
- Fixed invalid property errors and bugs in set_binning
|
|
54
|
+
- Updated get_property_specifications
|
|
55
|
+
- Do not automatically set attributes.windowWidth and attributes.windowHeight
|
|
56
|
+
- Return pattern index for get_result and get_virtual_image_buffer
|
|
57
|
+
|
|
58
|
+
5.3.beta5
|
|
59
|
+
=========
|
|
60
|
+
- Modify gain acquisition
|
|
61
|
+
|
|
62
|
+
5.3.beta4
|
|
63
|
+
=========
|
|
64
|
+
- Add GetEvent functionality to client.py
|
|
65
|
+
- Fixed bug in set_binning
|
|
66
|
+
|
|
67
|
+
5.3.beta3
|
|
68
|
+
=========
|
|
69
|
+
- Fix the problem that the set_binning function could not set HW binning to 1
|
|
70
|
+
|
|
71
|
+
5.3.beta2
|
|
72
|
+
=========
|
|
73
|
+
- Add access register
|
|
74
|
+
|
|
75
|
+
5.3.beta1
|
|
76
|
+
=========
|
|
77
|
+
- Create a Result Class to handle Result + Histogram
|
|
78
|
+
|
|
79
|
+
5.3.beta0
|
|
80
|
+
=========
|
|
81
|
+
- Add support for binning in x/ y dimensions when returning a result (#19)
|
|
82
|
+
|
|
83
|
+
5.2.2
|
|
84
|
+
==========
|
|
85
|
+
- Initial release
|
|
86
|
+
- Renamed `Client` functions from CamelCase to snake_case (Legacy functions are still available)
|
|
87
|
+
- Added buffer_protocol module for handling different buffer protocol files
|
|
88
|
+
- Added a data_types module for handling different data types
|
|
89
|
+
- Added a python based DEServer for testing purposes
|
|
90
|
+
- Update the Testing to allow for a real DEServer to be used for testing (#7)
|
|
91
|
+
- Add support for `@pytest.mark.server` decorator for tests that require a full DEServer to be running (#7)
|
|
92
|
+
- Add a commandline interface for the pydeserver. (#8) Running `pydeserver --port 13241` will start the server on port 13241
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deapi
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.3.1
|
|
4
4
|
Summary: API for DE Server
|
|
5
5
|
Author: Direct Electron
|
|
6
6
|
Project-URL: Bug Reports, https://github.com/directelectron/deapi/issues
|
|
@@ -12,16 +12,15 @@ Keywords: EELS,STEM,TEM,hyperspy,microscopy,Cryo EM,4D STEM
|
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Intended Audience :: Science/Research
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
19
|
Classifier: Topic :: Scientific/Engineering
|
|
21
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.10
|
|
22
21
|
License-File: LICENSE
|
|
23
22
|
Requires-Dist: numpy>=1.20.0
|
|
24
|
-
Requires-Dist: protobuf
|
|
23
|
+
Requires-Dist: protobuf<7,>=6.33.5
|
|
25
24
|
Requires-Dist: pillow
|
|
26
25
|
Requires-Dist: matplotlib
|
|
27
26
|
Requires-Dist: scipy
|
|
@@ -42,6 +41,8 @@ Requires-Dist: hyperspy; extra == "tests"
|
|
|
42
41
|
Requires-Dist: psutil; extra == "tests"
|
|
43
42
|
Provides-Extra: service
|
|
44
43
|
Requires-Dist: pyqt6; extra == "service"
|
|
44
|
+
Provides-Extra: twin
|
|
45
|
+
Requires-Dist: de-twin>=0.1.1; python_version >= "3.10" and extra == "twin"
|
|
45
46
|
Provides-Extra: doc
|
|
46
47
|
Requires-Dist: sphinx; extra == "doc"
|
|
47
48
|
Requires-Dist: pydata_sphinx_theme; extra == "doc"
|
|
@@ -17,8 +17,7 @@ else:
|
|
|
17
17
|
|
|
18
18
|
long = int # python 3 no longer has int
|
|
19
19
|
if int(pyVersion[1]) >= 10:
|
|
20
|
-
|
|
21
|
-
import deapi.buffer_protocols.pb_3_23_3 as pb
|
|
20
|
+
import deapi.buffer_protocols.pb_6_33_4 as pb
|
|
22
21
|
elif int(pyVersion[1]) >= 8:
|
|
23
22
|
import deapi.buffer_protocols.pb_3_11_4 as pb
|
|
24
23
|
else:
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# NO CHECKED-IN PROTOBUF GENCODE
|
|
4
|
+
# source: DE.proto
|
|
5
|
+
# Protobuf Python Version: 6.33.4
|
|
6
|
+
"""Generated protocol buffer code."""
|
|
7
|
+
|
|
8
|
+
from google.protobuf import descriptor as _descriptor
|
|
9
|
+
from google.protobuf import descriptor_pool as _descriptor_pool
|
|
10
|
+
from google.protobuf import runtime_version as _runtime_version
|
|
11
|
+
from google.protobuf import symbol_database as _symbol_database
|
|
12
|
+
from google.protobuf.internal import builder as _builder
|
|
13
|
+
|
|
14
|
+
_runtime_version.ValidateProtobufRuntimeVersion(
|
|
15
|
+
_runtime_version.Domain.PUBLIC, 6, 33, 4, "", "DE.proto"
|
|
16
|
+
)
|
|
17
|
+
# @@protoc_insertion_point(imports)
|
|
18
|
+
|
|
19
|
+
_sym_db = _symbol_database.Default()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
|
23
|
+
b'\n\x08\x44\x45.proto\x12\x0b\x44\x45Messaging"\xbd\x02\n\x08\x44\x45Packet\x12(\n\x04type\x18\x01 \x01(\x0e\x32\x1a.DEMessaging.DEPacket.Type\x12\x19\n\x11\x63\x61mera_identifier\x18\x02 \x01(\r\x12+\n\x07\x63ommand\x18\x03 \x03(\x0b\x32\x1a.DEMessaging.SingleCommand\x12\x33\n\x0b\x61\x63knowledge\x18\x04 \x03(\x0b\x32\x1e.DEMessaging.SingleAcknowledge\x12,\n\x0b\x64\x61ta_header\x18\x05 \x01(\x0b\x32\x17.DEMessaging.DataHeader\x12\x13\n\x0b\x63\x61mera_name\x18\x06 \x01(\t"G\n\x04Type\x12\n\n\x06P_NULL\x10\x00\x12\r\n\tP_COMMAND\x10\x01\x12\x11\n\rP_ACKNOWLEDGE\x10\x02\x12\x11\n\rP_DATA_HEADER\x10\x03"g\n\rSingleCommand\x12\x12\n\ncommand_id\x18\x01 \x01(\r\x12\x14\n\x0c\x63ommand_name\x18\x02 \x01(\t\x12,\n\tparameter\x18\x03 \x03(\x0b\x32\x19.DEMessaging.AnyParameter"\xf0\x01\n\x0c\x41nyParameter\x12,\n\x04type\x18\x01 \x01(\x0e\x32\x1e.DEMessaging.AnyParameter.Type\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\r\n\x05p_int\x18\x03 \x01(\x11\x12\x0e\n\x06p_bool\x18\x04 \x01(\x08\x12\x10\n\x08p_string\x18\x05 \x01(\t\x12\x0f\n\x07p_float\x18\x06 \x01(\x02\x12\x0f\n\x07p_bytes\x18\x07 \x01(\x0c"Q\n\x04Type\x12\n\n\x06P_NULL\x10\x00\x12\t\n\x05P_INT\x10\x01\x12\n\n\x06P_BOOL\x10\x02\x12\x0c\n\x08P_STRING\x10\x03\x12\x0b\n\x07P_FLOAT\x10\x04\x12\x0b\n\x07P_BYTES\x10\x05"]\n\x0b\x41\x63knowledge\x12\x19\n\x11\x63\x61mera_identifier\x18\x01 \x01(\r\x12\x33\n\x0b\x61\x63knowledge\x18\x02 \x03(\x0b\x32\x1e.DEMessaging.SingleAcknowledge"\x91\x01\n\x11SingleAcknowledge\x12\r\n\x05\x65rror\x18\x01 \x01(\x08\x12\x12\n\ncommand_id\x18\x02 \x01(\r\x12\x14\n\x0c\x63ommand_name\x18\x03 \x01(\t\x12\x15\n\rerror_message\x18\x04 \x01(\t\x12,\n\tparameter\x18\x05 \x03(\x0b\x32\x19.DEMessaging.AnyParameter"2\n\nDataHeader\x12\x10\n\x08\x62ytesize\x18\x01 \x01(\x04\x12\x12\n\nidentifier\x18\x02 \x01(\tb\x06proto3'
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
_globals = globals()
|
|
27
|
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
28
|
+
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "DE_pb2", _globals)
|
|
29
|
+
if not _descriptor._USE_C_DESCRIPTORS:
|
|
30
|
+
DESCRIPTOR._loaded_options = None
|
|
31
|
+
_globals["_DEPACKET"]._serialized_start = 26
|
|
32
|
+
_globals["_DEPACKET"]._serialized_end = 343
|
|
33
|
+
_globals["_DEPACKET_TYPE"]._serialized_start = 272
|
|
34
|
+
_globals["_DEPACKET_TYPE"]._serialized_end = 343
|
|
35
|
+
_globals["_SINGLECOMMAND"]._serialized_start = 345
|
|
36
|
+
_globals["_SINGLECOMMAND"]._serialized_end = 448
|
|
37
|
+
_globals["_ANYPARAMETER"]._serialized_start = 451
|
|
38
|
+
_globals["_ANYPARAMETER"]._serialized_end = 691
|
|
39
|
+
_globals["_ANYPARAMETER_TYPE"]._serialized_start = 610
|
|
40
|
+
_globals["_ANYPARAMETER_TYPE"]._serialized_end = 691
|
|
41
|
+
_globals["_ACKNOWLEDGE"]._serialized_start = 693
|
|
42
|
+
_globals["_ACKNOWLEDGE"]._serialized_end = 786
|
|
43
|
+
_globals["_SINGLEACKNOWLEDGE"]._serialized_start = 789
|
|
44
|
+
_globals["_SINGLEACKNOWLEDGE"]._serialized_end = 934
|
|
45
|
+
_globals["_DATAHEADER"]._serialized_start = 936
|
|
46
|
+
_globals["_DATAHEADER"]._serialized_end = 986
|
|
47
|
+
# @@protoc_insertion_point(module_scope)
|
|
@@ -151,7 +151,7 @@ class Client:
|
|
|
151
151
|
PropertyCollection(client=self, name=collection, properties=props),
|
|
152
152
|
)
|
|
153
153
|
|
|
154
|
-
def connect(self, host: str = "127.0.0.1", port: int = 13240, read_only=
|
|
154
|
+
def connect(self, host: str = "127.0.0.1", port: int = 13240, read_only=None):
|
|
155
155
|
"""Connect to DE-Server
|
|
156
156
|
|
|
157
157
|
Parameters
|
|
@@ -160,20 +160,12 @@ class Client:
|
|
|
160
160
|
The host to connect to, by default "127.0.0.1" for local connection
|
|
161
161
|
port : int, optional
|
|
162
162
|
The port to connect to, by default 13240
|
|
163
|
-
read_only : bool, optional
|
|
163
|
+
read_only : bool, optional (deprecated for command version >= 17)
|
|
164
164
|
If True, the client will be in read-only mode, by default False
|
|
165
|
+
For command version >= 17, the read_only parameter is ignored and
|
|
166
|
+
the client will query the server to determine whether it should be
|
|
167
|
+
read-only or read-write.
|
|
165
168
|
"""
|
|
166
|
-
self.read_only = read_only
|
|
167
|
-
if not read_only and (host == "localhost" or host == "127.0.0.1"):
|
|
168
|
-
tcp_no_delay = 0 # on loopback interface, nodelay causes delay
|
|
169
|
-
|
|
170
|
-
if self.usingMmf:
|
|
171
|
-
self.mmf = mmap.mmap(0, MMF_DATA_BUFFER_SIZE, "ImageFileMappingObject")
|
|
172
|
-
self.mmf[0] = True
|
|
173
|
-
else:
|
|
174
|
-
self.usingMmf = False # Disabled MMF if connected remotely
|
|
175
|
-
tcp_no_delay = 1
|
|
176
|
-
|
|
177
169
|
if logLevel == logging.DEBUG:
|
|
178
170
|
log.debug("Connecting to server: %s", host)
|
|
179
171
|
|
|
@@ -183,7 +175,6 @@ class Client:
|
|
|
183
175
|
self.socket.connect(
|
|
184
176
|
(host, port)
|
|
185
177
|
) # Connect to server reading port for sending data
|
|
186
|
-
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, tcp_no_delay)
|
|
187
178
|
self.socket.setblocking(False)
|
|
188
179
|
self.socket.settimeout(2)
|
|
189
180
|
|
|
@@ -200,15 +191,15 @@ class Client:
|
|
|
200
191
|
self.port = port
|
|
201
192
|
log.info("Connected to server: %s, port: %d", host, port)
|
|
202
193
|
|
|
203
|
-
if cVersion >= 12:
|
|
204
|
-
self.set_client_read_only(read_only)
|
|
205
|
-
|
|
206
194
|
server_version = self.GetProperty("Server Software Version")
|
|
207
195
|
server_version = re.findall(r"\d+", server_version)
|
|
208
196
|
|
|
209
197
|
version = [int(part) for part in server_version[:4]]
|
|
210
198
|
temp = version[2] + version[1] * 1000 + version[0] * 1000000
|
|
211
|
-
if temp >=
|
|
199
|
+
if temp >= 2008003 and version[3] >= 12436:
|
|
200
|
+
## version 2.8.3 build 12436+
|
|
201
|
+
self.commandVersion = 17
|
|
202
|
+
elif temp >= 2008000 and version[3] >= 12073:
|
|
212
203
|
## version 2.8.0 build 12073+ — virtual image buffer support (SDK 5.3.0)
|
|
213
204
|
self.commandVersion = 16
|
|
214
205
|
elif (temp >= 2007005 and version[3] < 11274) or temp >= 2008000:
|
|
@@ -234,6 +225,25 @@ class Client:
|
|
|
234
225
|
self.commandVersion = 3
|
|
235
226
|
else:
|
|
236
227
|
self.commandVersion = commandVersion
|
|
228
|
+
|
|
229
|
+
if self.commandVersion >= 12 and self.commandVersion < 17:
|
|
230
|
+
if read_only is None:
|
|
231
|
+
read_only = False
|
|
232
|
+
self.set_client_read_only(read_only)
|
|
233
|
+
elif self.commandVersion >= 17:
|
|
234
|
+
if read_only is not None:
|
|
235
|
+
log.warning(
|
|
236
|
+
"The `read_only` argument to `connect()` is ignored for servers "
|
|
237
|
+
"with command version >= 17 (DE-MC version >= 2.8.3.12436). "
|
|
238
|
+
"The client now determines read-only status automatically."
|
|
239
|
+
)
|
|
240
|
+
self.get_client_read_only()
|
|
241
|
+
|
|
242
|
+
self.SelectImageTransferMode()
|
|
243
|
+
self.socket.setsockopt(
|
|
244
|
+
socket.IPPROTO_TCP, socket.TCP_NODELAY, self.tcp_no_delay
|
|
245
|
+
)
|
|
246
|
+
|
|
237
247
|
log.info(f"Command Version: {self.commandVersion}")
|
|
238
248
|
self._initialize_attributes()
|
|
239
249
|
self.update_scan_size()
|
|
@@ -245,8 +255,17 @@ class Client:
|
|
|
245
255
|
|
|
246
256
|
def set_client_read_only(self, read_only):
|
|
247
257
|
self.read_only = read_only
|
|
248
|
-
command = self._addSingleCommand(
|
|
258
|
+
command = self._addSingleCommand(
|
|
259
|
+
self.SET_CLIENT_READ_ONLY_DEPRECATED, None, [read_only]
|
|
260
|
+
)
|
|
261
|
+
response = self._sendCommand(command)
|
|
262
|
+
return response
|
|
263
|
+
|
|
264
|
+
def get_client_read_only(self):
|
|
265
|
+
command = self._addSingleCommand(self.GET_CLIENT_READ_ONLY, None)
|
|
249
266
|
response = self._sendCommand(command)
|
|
267
|
+
if response != False:
|
|
268
|
+
self.read_only = self.__getParameters(response.acknowledge[0])[0]
|
|
250
269
|
return response
|
|
251
270
|
|
|
252
271
|
def update_scan_size(self):
|
|
@@ -435,9 +454,11 @@ class Client:
|
|
|
435
454
|
The name of the property to get the specifications for
|
|
436
455
|
"""
|
|
437
456
|
if self.commandVersion < 13:
|
|
438
|
-
log.error(
|
|
457
|
+
log.error(
|
|
458
|
+
"get_property_specifications is only supported for server version 2.7.5 and above."
|
|
459
|
+
)
|
|
439
460
|
return None
|
|
440
|
-
|
|
461
|
+
|
|
441
462
|
command = self._addSingleCommand(
|
|
442
463
|
self.GET_PROPERTY_SPECIFICATIONS, property_name
|
|
443
464
|
)
|
|
@@ -448,9 +469,11 @@ class Client:
|
|
|
448
469
|
values = self.__getParameters(response.acknowledge[0])
|
|
449
470
|
|
|
450
471
|
if not values or len(values) == 0:
|
|
451
|
-
log.error(
|
|
472
|
+
log.error(
|
|
473
|
+
f"get_property_specifications({property_name}) failed, parameter size not matched."
|
|
474
|
+
)
|
|
452
475
|
return None
|
|
453
|
-
|
|
476
|
+
|
|
454
477
|
prop_spec = PropertySpecifications()
|
|
455
478
|
|
|
456
479
|
param_id = 0
|
|
@@ -463,9 +486,11 @@ class Client:
|
|
|
463
486
|
elif data_type == "Integer":
|
|
464
487
|
prop_spec.prop_type = PropertyType.Integer
|
|
465
488
|
else:
|
|
466
|
-
log.error(
|
|
489
|
+
log.error(
|
|
490
|
+
f"get_property_specifications({property_name}) failed, property type not matched."
|
|
491
|
+
)
|
|
467
492
|
return None
|
|
468
|
-
|
|
493
|
+
|
|
469
494
|
prop_allowable_type = values[param_id]
|
|
470
495
|
param_id += 1
|
|
471
496
|
|
|
@@ -477,7 +502,9 @@ class Client:
|
|
|
477
502
|
prop_spec.max_value = values[param_id]
|
|
478
503
|
param_id += 1
|
|
479
504
|
else:
|
|
480
|
-
log.error(
|
|
505
|
+
log.error(
|
|
506
|
+
f"get_property_specifications({property_name}) failed, cannot read the min/max value."
|
|
507
|
+
)
|
|
481
508
|
return None
|
|
482
509
|
elif prop_allowable_type == "Set":
|
|
483
510
|
prop_spec.prop_allowable_type = PropertyAllowableType.Set
|
|
@@ -485,7 +512,9 @@ class Client:
|
|
|
485
512
|
elif prop_allowable_type == "AllowAll":
|
|
486
513
|
prop_spec.prop_allowable_type = PropertyAllowableType.AllowAll
|
|
487
514
|
else:
|
|
488
|
-
log.error(
|
|
515
|
+
log.error(
|
|
516
|
+
f"get_property_specifications({property_name}) failed, unknown allowable type."
|
|
517
|
+
)
|
|
489
518
|
return None
|
|
490
519
|
|
|
491
520
|
prop_spec.category = values[-4]
|
|
@@ -1498,7 +1527,7 @@ class Client:
|
|
|
1498
1527
|
command = self._addSingleCommand(self.SET_SCAN_XY_ARRAY, None, vals_to_send)
|
|
1499
1528
|
try:
|
|
1500
1529
|
packet = struct.pack("I", command.ByteSize()) + command.SerializeToString()
|
|
1501
|
-
self.socket.
|
|
1530
|
+
self.socket.sendall(packet)
|
|
1502
1531
|
ret = self.__ReceiveResponseForCommand(command) != False
|
|
1503
1532
|
log.info(f"response {ret}")
|
|
1504
1533
|
except socket.error:
|
|
@@ -1850,7 +1879,7 @@ class Client:
|
|
|
1850
1879
|
command = self._addSingleCommand(self.SET_VIRTUAL_MASK, None, [id, w, h])
|
|
1851
1880
|
ret = True
|
|
1852
1881
|
packet = struct.pack("I", command.ByteSize()) + command.SerializeToString()
|
|
1853
|
-
self.socket.
|
|
1882
|
+
self.socket.sendall(packet)
|
|
1854
1883
|
|
|
1855
1884
|
if ret:
|
|
1856
1885
|
if mask.dtype != np.uint8:
|
|
@@ -2823,6 +2852,19 @@ class Client:
|
|
|
2823
2852
|
if self.connected:
|
|
2824
2853
|
self.disconnect()
|
|
2825
2854
|
|
|
2855
|
+
def SelectImageTransferMode(self):
|
|
2856
|
+
if not self.read_only and (
|
|
2857
|
+
self.host == "localhost" or self.host == "127.0.0.1"
|
|
2858
|
+
):
|
|
2859
|
+
self.tcp_no_delay = 0 # on loopback interface, nodelay causes delay
|
|
2860
|
+
|
|
2861
|
+
if self.usingMmf:
|
|
2862
|
+
self.mmf = mmap.mmap(0, MMF_DATA_BUFFER_SIZE, "ImageFileMappingObject")
|
|
2863
|
+
self.mmf[0] = True
|
|
2864
|
+
else:
|
|
2865
|
+
self.usingMmf = False # Disabled MMF if connected remotely
|
|
2866
|
+
self.tcp_no_delay = 1
|
|
2867
|
+
|
|
2826
2868
|
# get multiple parameters from a single acknowledge packet
|
|
2827
2869
|
def __getParameters(self, single_acknowledge=None):
|
|
2828
2870
|
output = []
|
|
@@ -3050,29 +3092,17 @@ class Client:
|
|
|
3050
3092
|
return buffer
|
|
3051
3093
|
|
|
3052
3094
|
def __sendToSocket(self, sock, buffer, bytes):
|
|
3095
|
+
"""Send all of *buffer*, or raise.
|
|
3096
|
+
|
|
3097
|
+
``socket.send`` may accept only part of a buffer (routinely on macOS's loopback once
|
|
3098
|
+
the socket has a timeout), so the return value must be honoured: dropping the rest
|
|
3099
|
+
left the server waiting for bytes that never came, and every later command on the
|
|
3100
|
+
connection hung. ``sendall`` loops until every byte is sent and raises
|
|
3101
|
+
``socket.timeout`` if the server stops reading for *timeout* seconds.
|
|
3102
|
+
"""
|
|
3053
3103
|
timeout = self.exposureTime * 10 + 30
|
|
3054
|
-
startTime = self.GetTime()
|
|
3055
3104
|
self.socket.settimeout(timeout)
|
|
3056
|
-
|
|
3057
|
-
retval = True
|
|
3058
|
-
chunkSize = 4096
|
|
3059
|
-
for i in range(0, len(buffer), chunkSize):
|
|
3060
|
-
try:
|
|
3061
|
-
sock.send(buffer[i : min(len(buffer), i + chunkSize)])
|
|
3062
|
-
except socket.timeout:
|
|
3063
|
-
|
|
3064
|
-
log.debug(f" __sendToSocket : timeout in trying to send {bytes} bytes")
|
|
3065
|
-
if self.GetTime() - startTime > timeout:
|
|
3066
|
-
log.error(" __recvFromSocket: max timeout %d seconds", timeout)
|
|
3067
|
-
retval = False
|
|
3068
|
-
break
|
|
3069
|
-
else:
|
|
3070
|
-
pass # continue further
|
|
3071
|
-
except socket.error as e:
|
|
3072
|
-
log.error(f"Error during send: {e}")
|
|
3073
|
-
# Handle the error as needed, e.g., close the connection
|
|
3074
|
-
retval = False
|
|
3075
|
-
break
|
|
3105
|
+
sock.sendall(buffer)
|
|
3076
3106
|
return buffer
|
|
3077
3107
|
|
|
3078
3108
|
def __saveText(self, image, fileName, textSize):
|
|
@@ -3162,6 +3192,7 @@ class Client:
|
|
|
3162
3192
|
height = 0
|
|
3163
3193
|
mmf = 0
|
|
3164
3194
|
usingMmf = True
|
|
3195
|
+
tcp_no_delay = 0
|
|
3165
3196
|
debugImagesFolder = "D:\\DebugImages\\"
|
|
3166
3197
|
connected = False
|
|
3167
3198
|
camera = ""
|
|
@@ -3201,7 +3232,7 @@ class Client:
|
|
|
3201
3232
|
SET_SCAN_ROI = 28
|
|
3202
3233
|
SET_SCAN_SIZE_AND_GET_CHANGED_PROPERTIES = 29
|
|
3203
3234
|
SET_SCAN_ROI__AND_GET_CHANGED_PROPERTIES = 30
|
|
3204
|
-
|
|
3235
|
+
SET_CLIENT_READ_ONLY_DEPRECATED = 31
|
|
3205
3236
|
SET_SCAN_XY_ARRAY = 32
|
|
3206
3237
|
SET_ADAPTIVE_ROI = 33
|
|
3207
3238
|
SET_ADAPTIVE_ROI_AND_GET_CHANGED_PROPERTIES = 34
|
|
@@ -3213,6 +3244,7 @@ class Client:
|
|
|
3213
3244
|
LIST_REGISTERS = 40
|
|
3214
3245
|
GET_VIRTUAL_IMAGE_INFO = 41
|
|
3215
3246
|
GET_VIRTUAL_IMAGE = 42
|
|
3247
|
+
GET_CLIENT_READ_ONLY = 43
|
|
3216
3248
|
|
|
3217
3249
|
|
|
3218
3250
|
MMF_DATA_HEADER_SIZE = 24
|