style: format with ruff
Build and Publish / test (pull_request) Failing after 1m23s
Build and Publish / build (pull_request) Skipped
Build and Publish / Build and Deploy Docs (pull_request) Skipped

This commit is contained in:
2026-07-06 11:53:49 +02:00
parent 13bddd43c7
commit b0863e5ddb
181 changed files with 2237 additions and 5272 deletions
+19 -11
View File
@@ -1,6 +1,9 @@
import cv2
#%%
bkg_old = cv2.imread("/home/leonarski_f/aaredaq/daq/src/aaredaq/alc_test_images/bkg280_50_50_old.jpg")
# %%
bkg_old = cv2.imread(
"/home/leonarski_f/aaredaq/daq/src/aaredaq/alc_test_images/bkg280_50_50_old.jpg"
)
bkg_new = cv2.imread("/home/leonarski_f/aaredaq/daq/src/aaredaq/alc_test_images/bkg280_50_50.jpg")
grey_old = cv2.cvtColor(bkg_old, cv2.COLOR_RGB2GRAY)
grey_new = cv2.cvtColor(bkg_new, cv2.COLOR_RGB2GRAY)
@@ -8,17 +11,22 @@ diff_image = cv2.absdiff(grey_old, grey_new)
_, thresh_diff = cv2.threshold(diff_image, 1, 255, cv2.THRESH_BINARY)
# Display the results
cv2.imshow('Original Image 1', bkg_old)
cv2.imshow('Original Image 2', bkg_new)
cv2.imshow('Grayscale 1', grey_old)
cv2.imshow('Grayscale 2', grey_new)
cv2.imshow('Difference Image', diff_image)
cv2.imshow('Thresholded Difference', thresh_diff)
cv2.imshow("Original Image 1", bkg_old)
cv2.imshow("Original Image 2", bkg_new)
cv2.imshow("Grayscale 1", grey_old)
cv2.imshow("Grayscale 2", grey_new)
cv2.imshow("Difference Image", diff_image)
cv2.imshow("Thresholded Difference", thresh_diff)
# Save the difference image
cv2.imwrite('/home/leonarski_f/aaredaq/daq/src/aaredaq/alc_test_images/bkg_difference_image.jpg', diff_image)
cv2.imwrite('/home/leonarski_f/aaredaq/daq/src/aaredaq/alc_test_images/bkg_thresholded_difference.jpg', thresh_diff)
cv2.imwrite(
"/home/leonarski_f/aaredaq/daq/src/aaredaq/alc_test_images/bkg_difference_image.jpg", diff_image
)
cv2.imwrite(
"/home/leonarski_f/aaredaq/daq/src/aaredaq/alc_test_images/bkg_thresholded_difference.jpg",
thresh_diff,
)
# Wait for a key press and close all windows
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.destroyAllWindows()
+114 -90
View File
@@ -58,10 +58,16 @@ class ImageStatsReceiver:
x_coords = np.arange(len(x_projection))
y_coords = np.arange(len(y_projection))
x_centroid = np.sum(x_coords * x_projection) / np.sum(x_projection) if np.sum(x_projection) > 0 else len(
x_projection) / 2
y_centroid = np.sum(y_coords * y_projection) / np.sum(y_projection) if np.sum(y_projection) > 0 else len(
y_projection) / 2
x_centroid = (
np.sum(x_coords * x_projection) / np.sum(x_projection)
if np.sum(x_projection) > 0
else len(x_projection) / 2
)
y_centroid = (
np.sum(y_coords * y_projection) / np.sum(y_projection)
if np.sum(y_projection) > 0
else len(y_projection) / 2
)
# Calculate FWHM (Full Width at Half Maximum) approximation
def calculate_fwhm(profile):
@@ -76,20 +82,20 @@ class ImageStatsReceiver:
y_fwhm = calculate_fwhm(y_projection)
return {
'x_projection': x_projection.tolist(),
'y_projection': y_projection.tolist(),
'x_projection_max': x_projection_max.tolist(),
'y_projection_max': y_projection_max.tolist(),
'x_peak_position': int(x_peak_idx),
'y_peak_position': int(y_peak_idx),
'x_peak_value': float(x_peak_value),
'y_peak_value': float(y_peak_value),
'x_centroid': float(x_centroid),
'y_centroid': float(y_centroid),
'x_fwhm': float(x_fwhm),
'y_fwhm': float(y_fwhm),
'x_coords': list(range(len(x_projection))),
'y_coords': list(range(len(y_projection)))
"x_projection": x_projection.tolist(),
"y_projection": y_projection.tolist(),
"x_projection_max": x_projection_max.tolist(),
"y_projection_max": y_projection_max.tolist(),
"x_peak_position": int(x_peak_idx),
"y_peak_position": int(y_peak_idx),
"x_peak_value": float(x_peak_value),
"y_peak_value": float(y_peak_value),
"x_centroid": float(x_centroid),
"y_centroid": float(y_centroid),
"x_fwhm": float(x_fwhm),
"y_fwhm": float(y_fwhm),
"x_coords": list(range(len(x_projection))),
"y_coords": list(range(len(y_projection))),
}
def calculate_radial_integration(self, image: np.ndarray, num_bins: int = 50) -> Dict[str, Any]:
@@ -104,7 +110,7 @@ class ImageStatsReceiver:
center_y, center_x = np.array(gray_image.shape) // 2
# Create coordinate grids
y_coords, x_coords = np.ogrid[:gray_image.shape[0], :gray_image.shape[1]]
y_coords, x_coords = np.ogrid[: gray_image.shape[0], : gray_image.shape[1]]
# Calculate distance from center for each pixel
distances = np.sqrt((x_coords - center_x) ** 2 + (y_coords - center_y) ** 2)
@@ -137,13 +143,13 @@ class ImageStatsReceiver:
pixel_counts.append(0)
return {
'r_centers': r_centers.tolist(),
'radial_profile': radial_profile,
'radial_std': radial_std,
'pixel_counts': pixel_counts,
'max_radius': float(max_radius),
'center': [int(center_x), int(center_y)],
'num_bins': num_bins
"r_centers": r_centers.tolist(),
"radial_profile": radial_profile,
"radial_std": radial_std,
"pixel_counts": pixel_counts,
"max_radius": float(max_radius),
"center": [int(center_x), int(center_y)],
"num_bins": num_bins,
}
def calculate_image_stats(self, image: np.ndarray) -> Dict[str, Any]:
@@ -151,30 +157,30 @@ class ImageStatsReceiver:
image_float = image.astype(np.float64)
stats = {
'timestamp': time.time(),
'shape': image.shape,
'dtype': str(image.dtype),
'mean': float(np.mean(image_float)),
'std': float(np.std(image_float)),
'median': float(np.median(image_float)),
'min': float(np.min(image_float)),
'max': float(np.max(image_float)),
'message_count': self.message_count
"timestamp": time.time(),
"shape": image.shape,
"dtype": str(image.dtype),
"mean": float(np.mean(image_float)),
"std": float(np.std(image_float)),
"median": float(np.median(image_float)),
"min": float(np.min(image_float)),
"max": float(np.max(image_float)),
"message_count": self.message_count,
}
# Calculate per-channel stats if color image
if len(image.shape) == 3 and image.shape[2] > 1:
for channel in range(image.shape[2]):
channel_data = image_float[:, :, channel]
stats[f'mean_ch{channel}'] = float(np.mean(channel_data))
stats[f'std_ch{channel}'] = float(np.std(channel_data))
stats[f'median_ch{channel}'] = float(np.median(channel_data))
stats[f"mean_ch{channel}"] = float(np.mean(channel_data))
stats[f"std_ch{channel}"] = float(np.std(channel_data))
stats[f"median_ch{channel}"] = float(np.median(channel_data))
radial_data = self.calculate_radial_integration(image)
stats['radial'] = radial_data
stats["radial"] = radial_data
#projection_data = self.calculate_projections(image)
#stats['projections'] = projection_data
# projection_data = self.calculate_projections(image)
# stats['projections'] = projection_data
return stats
@@ -200,7 +206,7 @@ class ImageStatsReceiver:
rgb_image = rgb_image[:, ::-1, :].copy()
stats = self.calculate_image_stats(rgb_image)
stats['image_type'] = 'rgb_from_bayer'
stats["image_type"] = "rgb_from_bayer"
with self.stats_lock:
self.latest_stats = stats
@@ -213,7 +219,7 @@ class ImageStatsReceiver:
rgb_image = rgb_image.reshape(header_shape)
stats = self.calculate_image_stats(rgb_image)
stats['image_type'] = 'rgb_direct'
stats["image_type"] = "rgb_direct"
with self.stats_lock:
self.latest_stats = stats
@@ -245,45 +251,53 @@ class ImageStatsReceiver:
def print_formatted_stats(self, stats: Dict[str, Any]):
"""Print formatted statistics in a compact terminal format"""
timestamp = time.strftime('%H:%M:%S', time.localtime(stats['timestamp']))
timestamp = time.strftime("%H:%M:%S", time.localtime(stats["timestamp"]))
# Compact one-line format
print(f"[{timestamp}] #{stats['message_count']:4d} | "
f"Shape: {stats['shape']} | "
f"Mean: {stats['mean']:6.1f} | "
f"Std: {stats['std']:6.1f} | "
f"Median: {stats['median']:6.1f} | "
f"Range: [{stats['min']:3.0f}-{stats['max']:3.0f}]",
flush=True)
print(
f"[{timestamp}] #{stats['message_count']:4d} | "
f"Shape: {stats['shape']} | "
f"Mean: {stats['mean']:6.1f} | "
f"Std: {stats['std']:6.1f} | "
f"Median: {stats['median']:6.1f} | "
f"Range: [{stats['min']:3.0f}-{stats['max']:3.0f}]",
flush=True,
)
if 'radial' in stats:
radial = stats['radial']
center_intensity = radial['radial_profile'][0] if radial['radial_profile'] else 0
edge_intensity = radial['radial_profile'][-1] if radial['radial_profile'] else 0
peak_radius_idx = np.argmax(radial['radial_profile']) if radial['radial_profile'] else 0
peak_radius = radial['r_centers'][peak_radius_idx] if radial['r_centers'] else 0
if "radial" in stats:
radial = stats["radial"]
center_intensity = radial["radial_profile"][0] if radial["radial_profile"] else 0
edge_intensity = radial["radial_profile"][-1] if radial["radial_profile"] else 0
peak_radius_idx = np.argmax(radial["radial_profile"]) if radial["radial_profile"] else 0
peak_radius = radial["r_centers"][peak_radius_idx] if radial["r_centers"] else 0
print(f"{'':21} Radial: Center={center_intensity:.1f} | "
f"Edge={edge_intensity:.1f} | "
f"Peak@r={peak_radius:.1f} | "
f"Center=({radial['center'][0]},{radial['center'][1]})",
flush=True)
print(
f"{'':21} Radial: Center={center_intensity:.1f} | "
f"Edge={edge_intensity:.1f} | "
f"Peak@r={peak_radius:.1f} | "
f"Center=({radial['center'][0]},{radial['center'][1]})",
flush=True,
)
# Print projection summary
if 'projections' in stats:
proj = stats['projections']
print(f"{'':21} X-Profile: Peak@{proj['x_peak_position']}({proj['x_peak_value']:.1f}) | "
f"Centroid={proj['x_centroid']:.1f} | FWHM={proj['x_fwhm']:.1f}",
flush=True)
print(f"{'':21} Y-Profile: Peak@{proj['y_peak_position']}({proj['y_peak_value']:.1f}) | "
f"Centroid={proj['y_centroid']:.1f} | FWHM={proj['y_fwhm']:.1f}",
flush=True)
if "projections" in stats:
proj = stats["projections"]
print(
f"{'':21} X-Profile: Peak@{proj['x_peak_position']}({proj['x_peak_value']:.1f}) | "
f"Centroid={proj['x_centroid']:.1f} | FWHM={proj['x_fwhm']:.1f}",
flush=True,
)
print(
f"{'':21} Y-Profile: Peak@{proj['y_peak_position']}({proj['y_peak_value']:.1f}) | "
f"Centroid={proj['y_centroid']:.1f} | FWHM={proj['y_fwhm']:.1f}",
flush=True,
)
# Optional: Print per-channel stats if available
if any(k.startswith('mean_ch') for k in stats.keys()):
if any(k.startswith("mean_ch") for k in stats.keys()):
channels = []
i = 0
while f'mean_ch{i}' in stats:
while f"mean_ch{i}" in stats:
channels.append(f"Ch{i}({stats[f'mean_ch{i}']:.1f})")
i += 1
if channels:
@@ -292,16 +306,23 @@ class ImageStatsReceiver:
def get_radial_profile_summary(self):
"""Get a summary of the current radial profile"""
with self.stats_lock:
if self.latest_stats and 'radial' in self.latest_stats:
radial = self.latest_stats['radial']
if self.latest_stats and "radial" in self.latest_stats:
radial = self.latest_stats["radial"]
return {
'r_centers': radial['r_centers'],
'radial_profile': radial['radial_profile'],
'center_intensity': radial['radial_profile'][0] if radial['radial_profile'] else 0,
'edge_intensity': radial['radial_profile'][-1] if radial['radial_profile'] else 0,
'max_intensity_radius': radial['r_centers'][np.argmax(radial['radial_profile'])] if radial[
'radial_profile'] else 0,
'max_intensity_value': max(radial['radial_profile']) if radial['radial_profile'] else 0
"r_centers": radial["r_centers"],
"radial_profile": radial["radial_profile"],
"center_intensity": radial["radial_profile"][0]
if radial["radial_profile"]
else 0,
"edge_intensity": radial["radial_profile"][-1]
if radial["radial_profile"]
else 0,
"max_intensity_radius": radial["r_centers"][np.argmax(radial["radial_profile"])]
if radial["radial_profile"]
else 0,
"max_intensity_value": max(radial["radial_profile"])
if radial["radial_profile"]
else 0,
}
return None
@@ -311,21 +332,23 @@ class ImageStatsReceiver:
filename = f"radial_profile_{int(time.time())}.txt"
with self.stats_lock:
if self.latest_stats and 'radial' in self.latest_stats:
radial = self.latest_stats['radial']
if self.latest_stats and "radial" in self.latest_stats:
radial = self.latest_stats["radial"]
with open(filename, 'w') as f:
with open(filename, "w") as f:
f.write("# Radial Integration Profile\n")
f.write(f"# Timestamp: {time.ctime(self.latest_stats['timestamp'])}\n")
f.write(f"# Image shape: {self.latest_stats['shape']}\n")
f.write(f"# Center: {radial['center']}\n")
f.write("# Radius(pixels)\tMean_Intensity\tStd_Intensity\tPixel_Count\n")
for i in range(len(radial['r_centers'])):
f.write(f"{radial['r_centers'][i]:.2f}\t"
f"{radial['radial_profile'][i]:.2f}\t"
f"{radial['radial_std'][i]:.2f}\t"
f"{radial['pixel_counts'][i]}\n")
for i in range(len(radial["r_centers"])):
f.write(
f"{radial['r_centers'][i]:.2f}\t"
f"{radial['radial_profile'][i]:.2f}\t"
f"{radial['radial_std'][i]:.2f}\t"
f"{radial['pixel_counts'][i]}\n"
)
print(f"Radial profile saved to {filename}")
return filename
@@ -419,6 +442,7 @@ def save_current_radial_profile(filename: str = None):
return stats_receiver.save_radial_profile_to_file(filename)
return None
# # Auto-start when daq.py is imported/run
# if __name__ == "__main__":
# # If running daq.py directly
@@ -444,4 +468,4 @@ def save_current_radial_profile(filename: str = None):
#
# else:
# # If daq.py is imported as a module, auto-start the receiver
# start_image_stats_receiver()
# start_image_stats_receiver()
+2 -1
View File
@@ -1,4 +1,5 @@
from aaredaq.config import BeamlineConfig
from aaredaqlib.beamline import MXBeamline
c = BeamlineConfig(MXBeamline.X06DA)
c.state_busy = False
c.state_busy = False
+43 -42
View File
@@ -1,13 +1,17 @@
from PySide6.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QFrame, QPushButton, QScrollArea, QStackedWidget,
QApplication,
QWidget,
QVBoxLayout,
QHBoxLayout,
QLabel,
QFrame,
QPushButton,
QScrollArea,
QStackedWidget,
QSizePolicy,
)
from PySide6.QtCore import Qt, QPointF, QRectF
from PySide6.QtGui import (
QPainter, QColor, QPen, QLinearGradient,
QFont, QFontMetrics,
)
from PySide6.QtGui import QPainter, QColor, QPen, QLinearGradient, QFont, QFontMetrics
import sys
import math
@@ -15,15 +19,15 @@ import math
# ---------------------------------------------------------------------------
# Colour palette
# ---------------------------------------------------------------------------
BG = "#071018"
CARD_BG = "#0E1A26"
ACCENT = "#62D8C8"
ACCENT_DIM = "#1A3A36"
TEXT = "#F5F7FA"
SUBTEXT = "#8A9BB0"
BUTTON_BG = "#132131"
LED_OFF = "#1C2E3E"
LED_ON = ACCENT
BG = "#071018"
CARD_BG = "#0E1A26"
ACCENT = "#62D8C8"
ACCENT_DIM = "#1A3A36"
TEXT = "#F5F7FA"
SUBTEXT = "#8A9BB0"
BUTTON_BG = "#132131"
LED_OFF = "#1C2E3E"
LED_ON = ACCENT
ACTIVE_STEP = "#FFFFFF"
@@ -147,10 +151,7 @@ class LEDStages(QWidget):
line_color = QColor(ACCENT) if i < self._active else QColor(LED_OFF)
pen = QPen(line_color, 2)
p.setPen(pen)
p.drawLine(
QPointF(cx + led_r + 3, cy),
QPointF(next_cx - led_r - 3, cy),
)
p.drawLine(QPointF(cx + led_r + 3, cy), QPointF(next_cx - led_r - 3, cy))
# --- LED circle ---
p.setPen(Qt.NoPen)
@@ -162,14 +163,8 @@ class LEDStages(QWidget):
pen = QPen(QColor(BG), 2)
pen.setCapStyle(Qt.RoundCap)
p.setPen(pen)
p.drawLine(
QPointF(cx - 4, cy),
QPointF(cx - 1, cy + 3),
)
p.drawLine(
QPointF(cx - 1, cy + 3),
QPointF(cx + 4, cy - 3),
)
p.drawLine(QPointF(cx - 4, cy), QPointF(cx - 1, cy + 3))
p.drawLine(QPointF(cx - 1, cy + 3), QPointF(cx + 4, cy - 3))
elif i == self._active:
# active — bright with glow ring
glow_pen = QPen(QColor(ACCENT + "55"), 4)
@@ -194,9 +189,7 @@ class LEDStages(QWidget):
fm = QFontMetrics(font)
text_w = fm.horizontalAdvance(name)
p.drawText(
QRectF(cx - text_w / 2 - 4, 0, text_w + 8, label_y + 2),
Qt.AlignCenter,
name,
QRectF(cx - text_w / 2 - 4, 0, text_w + 8, label_y + 2), Qt.AlignCenter, name
)
@@ -317,7 +310,9 @@ class QueueItemCard(QFrame):
text_col.setContentsMargins(0, 0, 0, 0)
title_lbl = QLabel(self._title)
title_lbl.setStyleSheet(f"color: {TEXT}; font-size: 13px; font-weight: 600; background: transparent;")
title_lbl.setStyleSheet(
f"color: {TEXT}; font-size: 13px; font-weight: 600; background: transparent;"
)
sub_lbl = QLabel(self._subtitle)
sub_lbl.setStyleSheet(f"color: {SUBTEXT}; font-size: 11px; background: transparent;")
@@ -399,7 +394,9 @@ class SampleCamera(QWidget):
# ── Title ──────────────────────────────────────────────────────
title = QLabel("S A M C A M E R A")
title.setAlignment(Qt.AlignCenter)
title.setStyleSheet(f"color: {ACCENT}; font-size: 13px; letter-spacing: 3px; font-weight: 600;")
title.setStyleSheet(
f"color: {ACCENT}; font-size: 13px; letter-spacing: 3px; font-weight: 600;"
)
layout.addWidget(title)
# ── Camera card ────────────────────────────────────────────────
@@ -422,7 +419,7 @@ class SampleCamera(QWidget):
layout.addWidget(sub_lbl)
# ── LED step indicator ─────────────────────────────────────────
self._leds = LEDStages(active_step=1) # 0=Mount done, 1=Centre active
self._leds = LEDStages(active_step=1) # 0=Mount done, 1=Centre active
layout.addWidget(self._leds)
# ── Transport controls ─────────────────────────────────────────
@@ -435,7 +432,7 @@ class SampleCamera(QWidget):
buttons = [
("", False),
("", False),
("", True), # primary / highlighted
("", True), # primary / highlighted
("", False),
("", False),
]
@@ -449,7 +446,9 @@ class SampleCamera(QWidget):
# ── Up next header ─────────────────────────────────────────────
up_next_row = QHBoxLayout()
up_next_lbl = QLabel("UP NEXT")
up_next_lbl.setStyleSheet(f"color: {ACCENT}; font-size: 11px; letter-spacing: 2px; font-weight: 700;")
up_next_lbl.setStyleSheet(
f"color: {ACCENT}; font-size: 11px; letter-spacing: 2px; font-weight: 700;"
)
samples_lbl = QLabel("5 SAMPLES")
samples_lbl.setStyleSheet(f"color: {SUBTEXT}; font-size: 11px; letter-spacing: 1px;")
up_next_row.addWidget(up_next_lbl)
@@ -459,11 +458,11 @@ class SampleCamera(QWidget):
# ── Queue preview cards ────────────────────────────────────────
queue_items = [
("Crystal Plate 14 · Well C8", "Serial MX · 1 kHz", 4100, 6000, True),
("Crystal Plate 15 · Grid Scan", "Raster · 10 Hz", 0, 2000, False),
("Crystal Plate 13 · Well A1", "Serial MX · 1 kHz", 0, 5000, False),
("Crystal Plate 13 · Well B3", "Serial MX · 1 kHz", 0, 4500, False),
("Crystal Plate 14 · Well D5", "Serial MX · 1 kHz", 0, 6000, False),
("Crystal Plate 14 · Well C8", "Serial MX · 1 kHz", 4100, 6000, True),
("Crystal Plate 15 · Grid Scan", "Raster · 10 Hz", 0, 2000, False),
("Crystal Plate 13 · Well A1", "Serial MX · 1 kHz", 0, 5000, False),
("Crystal Plate 13 · Well B3", "Serial MX · 1 kHz", 0, 4500, False),
("Crystal Plate 14 · Well D5", "Serial MX · 1 kHz", 0, 6000, False),
]
queue_widget = QWidget()
@@ -502,7 +501,9 @@ class SampleCamera(QWidget):
title = QLabel("SAMPLE QUEUE")
title.setAlignment(Qt.AlignCenter)
title.setStyleSheet(f"color: {ACCENT}; font-size: 13px; letter-spacing: 3px; font-weight: 700;")
title.setStyleSheet(
f"color: {ACCENT}; font-size: 13px; letter-spacing: 3px; font-weight: 700;"
)
layout.addWidget(title)
scroll = QScrollArea()
@@ -583,4 +584,4 @@ if __name__ == "__main__":
app = QApplication(sys.argv)
ui = SampleCamera()
ui.show()
sys.exit(app.exec())
sys.exit(app.exec())
+11 -4
View File
@@ -175,7 +175,8 @@ class PShellClient:
"""
return self._get_response(
requests.put(
url=self.url + "/run", json={"script": script, "pars": pars, "background": background, "async": False}
url=self.url + "/run",
json={"script": script, "pars": pars, "background": background, "async": False},
)
)
@@ -191,7 +192,9 @@ class PShellClient:
Command id (int), which is used to retrieve command execution status/result (get_result).
"""
statement = quote(statement)
return int(self._get_response(requests.get(url=self.url + "/evalAsync/" + statement), False))
return int(
self._get_response(requests.get(url=self.url + "/evalAsync/" + statement), False)
)
def start_run(self, script, pars=None, background=False):
"""Starts execution of a script in the interpreter.
@@ -279,9 +282,13 @@ class PShellClient:
if type == "json":
return self._get_response(requests.get(url=self.url + "/data-json/" + path), True)
elif type == "bin":
return self._get_binary_response(requests.get(url=self.url + "/data-bin/" + path, stream=True))
return self._get_binary_response(
requests.get(url=self.url + "/data-bin/" + path, stream=True)
)
return self._get_response(requests.get(url=self.url + "/data" + ("" if path is None else ("/" + path))), False)
return self._get_response(
requests.get(url=self.url + "/data" + ("" if path is None else ("/" + path))), False
)
def print_logs(self):
for log_line in self.get_logs():
+3 -8
View File
@@ -99,15 +99,10 @@ def main(argv=None):
help="Key pattern for SCAN (e.g., 'user:*'). If omitted, all keys are scanned.",
)
parser.add_argument(
"--scan-count",
type=int,
default=1000,
help="Hint for SCAN per iteration (not a limit).",
"--scan-count", type=int, default=1000, help="Hint for SCAN per iteration (not a limit)."
)
parser.add_argument(
"--include-ttl",
action="store_true",
help="Include TTL (seconds) for each key.",
"--include-ttl", action="store_true", help="Include TTL (seconds) for each key."
)
args = parser.parse_args(argv)
@@ -125,4 +120,4 @@ def main(argv=None):
if __name__ == "__main__":
sys.exit(main())
sys.exit(main())