Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# ============================================================
# STAGE 1: base — Python 3.12 + Qt6 system dependencies
# ============================================================
FROM python:3.9-slim AS base

ENV DEBIAN_FRONTEND=noninteractive

RUN pip install --upgrade pip

# Qt6/PyQt6 runtime dependencies (xcb platform plugin requirements)
RUN apt-get update && apt-get install -y --no-install-recommends \
libgl1 \
libglib2.0-0 \
libfontconfig1 \
libxkbcommon-x11-0 \
libdbus-1-3 \
libegl1 \
libxcb-xinerama0 \
libxcb-cursor0 \
libxcb-shape0 \
libxcb-icccm4 \
libxcb-keysyms1 \
libxcb-render-util0 \
libxcb-image0 \
libgssapi-krb5-2 \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app
ENV PYTHONPATH=/app/src

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY src/ ./src/

# ============================================================
# STAGE 2: dev — GUI development with X11 forwarding
# ============================================================
FROM base AS dev

ENV DISPLAY=:0
ENV QT_QPA_PLATFORM=xcb

CMD ["python", "-m", "main"]

# ============================================================
# STAGE 3: test — Headless testing with Xvfb
# ============================================================
FROM base AS test

RUN apt-get update && apt-get install -y --no-install-recommends \
xvfb \
&& rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir \
"pytest>=7.0" \
"pytest-qt>=4.2"

ENV QT_QPA_PLATFORM=xcb

COPY tests/ ./tests/

CMD ["xvfb-run", "--auto-servernum", \
"--server-args=-screen 0 1920x1080x24", \
"pytest", "tests/", "-v"]

# ============================================================
# STAGE 4: build — PyInstaller Linux binary
# ============================================================
FROM base AS build

RUN apt-get update && apt-get install -y --no-install-recommends \
binutils \
&& rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir "pyinstaller>=6.0"

CMD ["pyinstaller", "src/main.py", \
"--name", "SignalViewer", \
"--onefile", "--windowed", \
"--distpath", "/app/dist"]
29 changes: 29 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.PHONY: dev test build build-bin clean help

help: ## Show available commands
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " make %-12s %s\n", $$1, $$2}'

dev: ## Run the GUI app (X11 via WSLg)
docker compose run --rm dev

test: ## Run tests headlessly (Xvfb)
docker compose run --rm test

build: ## Build Linux binary → ./dist/SignalViewer
docker compose run --rm build

build-bin: ## Build Linux binary without Docker → ./dist/SignalViewer
sudo apt install -y python3.12-venv
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/pip install "pyinstaller>=6.0"
.venv/bin/pyinstaller src/app/main.py --name SignalViewer --onefile --windowed

build-exe: ## Build Windows .exe → run build-exe.ps1 from PowerShell on Windows
@echo "ERROR: Cannot build a Windows .exe from WSL2/Linux."
@echo "Open PowerShell on Windows and run: .\\build-exe.ps1"
@exit 1

clean: ## Remove build artifacts and Docker images
rm -rf dist/ build/ *.spec
docker compose down --rmi local --volumes --remove-orphans
32 changes: 32 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
services:
# GUI development — requires WSLg or VcXsrv for X11 display
dev:
build:
context: .
target: dev
environment:
- DISPLAY=${DISPLAY:-:0}
- QT_QPA_PLATFORM=xcb
volumes:
- /tmp/.X11-unix:/tmp/.X11-unix:rw
- ./src:/app/src
network_mode: host
stdin_open: true
tty: true

# Headless testing with virtual framebuffer
test:
build:
context: .
target: test
volumes:
- ./tests:/app/tests
- ./src:/app/src

# PyInstaller build (produces Linux binary, NOT Windows .exe)
build:
build:
context: .
target: build
volumes:
- ./dist:/app/dist
3 changes: 2 additions & 1 deletion src/Utils/aboutDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,11 @@ def setupUi(self, AboutDialog):
self.linkTausand.setOpenExternalLinks(True)
self.linkGitHub.setOpenExternalLinks(True)
##translateFuncion
self.descriptionLabel.setText(QCoreApplication.translate("AboutDialog", u"Tempico Software is a suite of tools build to ensure your experience with Tausand's time to digital converters.", None))
# self.descriptionLabel.setText(QCoreApplication.translate("AboutDialog", u"Tempico Software is a suite of tools build to ensure your experience with Tausand's time to digital converters.", None))
self.softwareLabel.setText(QCoreApplication.translate("AboutDialog", u"Software Version: %s"%VERSION, None))
self.tempicoLabel.setText(QCoreApplication.translate("AboutDialog", u"PyTempico Version: %s"%PYTEMPICO_VERSION, None))
#self.imageLabel.setText(QCoreApplication.translate("AboutDialog", u"Picture Label", None))
self.descriptionLabel.setText(QCoreApplication.translate("AboutDialog", u"My first experience as a full stack Python developer was in the GUI Python area. At the time, I had been working as a data scientist for almost two years, primarily focused on data analysis and modeling. Then, a friend of mine offer my profile to a Canadian geophysics company (Geophysics GPR International Inc.) that completely changed my trajectory.\nThe company had been developing a GUI project for almost six months, with the goal of processing seismic trace information vital for structural seismic analysis. The role was entirely new to me, not just in terms of the domain, but also in terms of what I thought Python was capable of. I had always associated Python with scripting, data pipelines, and machine learning workflows never with rich, interactive graphical interfaces.\nFor this project, I worked with Tkinter and Matplotlib as the core tools to build the interface. The final product was conceptually similar to SeisImager/2D, a well-known licensed software used in the geophysical industry for seismic refraction analysis and interpretation. Replicating that level of functionality using open-source Python libraries was both a challenge and an incredibly rewarding experience.\nOver the course of nearly a year, I gained a deep understanding of GUI development with Python — event-driven programming, dynamic plot rendering, data visualization, and user interaction design. Beyond the interface itself, I also developed a strong foundation in modeling physical phenomena, particularly in how seismic waves propagate through geological structures and how that data is interpreted visually.\nLooking back, this experience not only broadened my technical skill set but also gave me a genuine appreciation for how powerful and versatile Python truly is across different engineering disciplines.", None))
self.linkTausand.setText(QCoreApplication.translate("AboutDialog", u"Visit us at: %s "%tausand, None))
self.linkGitHub.setText(QCoreApplication.translate("AboutDialog", u"More information on Tempico Software implementation can be found at: %s"%pages, None))
self.pushButton.setText(QCoreApplication.translate("AboutDialog", u"Ok", None))
Expand Down
4 changes: 3 additions & 1 deletion src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,12 @@ def __init__(self, parent=None, *args):
self.construct_start_stop_histogram(self.tab1)
self.connectButton = QPushButton("Connect", self)
self.disconnectButton = QPushButton("Disconnect", self)
self.about_me_button = QPushButton("About Me", parent=self)

buttonLayout = QHBoxLayout()
buttonLayout.addWidget(self.connectButton)
buttonLayout.addWidget(self.disconnectButton)
buttonLayout.addWidget(self.about_me_button)

# Crear un QWidget para contener los QTabWidget y los botones
mainWidget = QWidget(self)
Expand Down Expand Up @@ -263,6 +265,7 @@ def __init__(self, parent=None, *args):
self.connectsentinel=0
self.connectButton.clicked.connect(self.open_dialog)
self.disconnectButton.clicked.connect(self.disconnect_button_click)
self.about_me_button.clicked.connect(self.about_settings)
self.sentinel2=0
self.sentinel3=0
self.sentinel4=0
Expand Down Expand Up @@ -1029,7 +1032,6 @@ def about_settings(self):
settings_windows.setupUi(settings_windows_dialog)
settings_windows_dialog.exec_()


#This function is not use for the Tempico Version 1.1
#TO DO: Comment the function for a future version
def parameters_action(self):
Expand Down