Commit Graph

80 Commits

Author SHA1 Message Date
ispyisail da3a976b60 Add an event-loop responsiveness watchdog (discussion #644 follow-up)
QetLogger (discussion #644, steps 1-3) captures whatever an explicit
qDebug()/qInfo()/qWarning() call already decided to report. Most of a
session -- painting, dragging, a slow synchronous operation -- produces
no log output at all, so a silent multi-second gap in the log is
indistinguishable from the user simply not doing anything. That gap
came up directly: investigating a user-reported "the program lagged"
required inferring stalls from timestamp gaps between unrelated log
lines, which can't tell a real freeze apart from normal idle time.

EventLoopWatchdog closes that gap directly instead of inferring it. A
QTimer::PreciseTimer repeating tick (every 50ms) measures the *actual*
elapsed time since the previous tick via QElapsedTimer (monotonic,
unaffected by system clock/NTP adjustments). Qt does not queue up
missed fires for a normal repeating timer, so if the main thread is
blocked for 600ms, the timer fires once as soon as the loop frees up,
with ~600ms measured since the last tick -- that gap is the stall,
measured at its source. Only logs (via the existing qWarning() path,
so it reuses QetLogger's file/ring/rotation with no new plumbing) when
a tick is late by more than 200ms, so a healthy session produces zero
output from this class, in keeping with QetLogger's bounded-log design.

Same QET_WATCHDOG_DISABLE=1 escape-hatch convention as QetLogger's own
QET_LOG_DISABLE=1.

Deliberately not included: attributing a stall to what caused it. This
tells you a stall happened and how long -- pairing that timestamp with
gdb attached to a running session (as used for the CLI hang, PR #661)
is still how you get from "it stalled" to a root cause.

Stacked on #647 (feature-diagnostic-logging-crash) for QetLogger/
qWarning() plumbing this depends on -- diff includes its commits until
that merges.

Verified against the compiled binary, not just read: temporarily
injected a QThread::msleep(600) via a one-shot QTimer 2s after
startup, confirmed the exact expected warning
("EventLoopWatchdog: main thread stalled for 620 ms") at the right
severity through the real qWarning()/QetLogger path, then removed the
test hook and reconfirmed a normal run produces no output from this
class at all.
2026-08-06 23:05:05 +12:00
ispyisail 5dec36cb29 Add crash-time ring flush and a diagnostics export UI (discussion #644, steps 4-5)
Stacked on the steps 1-3 branch (feature-diagnostic-logging, PR #646).
Kept as its own PR rather than folded into that one, matching the
discussion's own framing: step 4 is explicitly "the highest-risk piece
... lands last, behind its own switch."

## Step 4 -- crash-time ring flush (CrashHandler)

Installs a handler for SIGSEGV/SIGABRT/SIGBUS/SIGFPE/SIGILL (POSIX) /
SetUnhandledExceptionFilter (Windows) that flushes the in-memory ring to
a fixed crash_dump.log before the process dies.

This required reworking LogRing (step 3) to be genuinely lock-free, not
just mutex-protected: a signal handler that blocks on a lock the
crashing thread (or another thread) already holds turns a clean crash
into a hang -- no ring dump *and* no core dump, worse than doing
nothing. append() now claims a slot with a single atomic fetch-add;
dumpToFd() reads the preallocated entries directly and writes them with
write(2) only, looping on EINTR/short writes. Accepted tradeoff: at most
one entry can be read torn if a crash lands mid-append into that exact
slot -- documented in logring.h, and the alternative (a seqlock to
detect and retry) wasn't judged worth the complexity for that window.

Other invariants implemented per the discussion:
- sigaltstack with a static 64 KiB buffer, SA_ONSTACK -- a stack-
  overflow SIGSEGV has no usable stack for a handler without one.
- Nothing under the actual handler touches Qt, QString or the
  allocator: the dump path and a small header (version/git/OS/Qt) are
  precomputed into fixed char buffers by install(), which runs once at
  startup in normal context.
- Atomic test-and-set so only the first crash writes a dump; a second
  concurrent/nested fault goes straight to restore-and-re-raise.
- After writing, the handler restores SIG_DFL and re-raises (POSIX) /
  returns EXCEPTION_CONTINUE_SEARCH (Windows) so the OS's own crash
  path -- core dump, Windows Error Reporting -- still runs. A handler
  that "fixed" the crash by swallowing the signal would destroy exactly
  the post-mortem evidence this whole design exists to preserve.

Tested in this environment: POSIX/Linux only, all five signals. Sent
each directly to a running process and confirmed (a) crash_dump.log is
written with the correct header and ring contents, mode 0600, and (b)
the process still terminates via the signal with the kernel's own
"core dumped" flag set (exit code 128+signal, confirmed for all five).
The Windows path is implemented per the discussion's guidance but is
untested -- no Windows build available in this sandbox.

## Step 5 -- getting the data back out

- QETApp::checkCrashDump(), called from checkBackupFiles() only when
  there's no stale project file to recover this run (so the two
  prompts never both show, per the discussion), offers an unretrieved
  crash dump via DiagnosticsReportDialog and then deletes it regardless
  of the user's choice -- offered exactly once.
- A new "Aide > Enregistrer un rapport de diagnostic..." action
  (QETMainWindow) builds the same kind of report from the *current*
  session (QetLogger::buildDiagnosticsReport(): header + this session's
  log file) for a manual "attach this to a bug report" flow, not tied
  to a crash.
- Both go through QetLogger::redact() before ever reaching the user:
  the one redaction implemented is a literal replace of the home
  directory with "~", since an absolute path under it leaks the
  account name. The discussion's fancier "optionally redact project
  filenames too" isn't attempted -- reliably telling a project path
  apart from arbitrary log text is a much fuzzier problem than a
  literal prefix match.
- DiagnosticsReportDialog shows the full (already-redacted) content
  before saving, per the discussion: "the user is about to attach this
  to a public tracker."

Verified in a real GUI session (Xvfb): triggered a SIGSEGV, relaunched,
confirmed the crash-report dialog appears with the right header/content,
confirmed it does not reappear on a second relaunch, and confirmed the
manual "Save report" action produces a correctly-formatted report and
saves it to a chosen path.

Built clean, no new warnings.

## Build systems

Registered in both: cmake/qet_compilation_vars.cmake, and
qelectrotech.pro. The .pro needed explicit globs for the new
sources/logging/ui/ subfolder -- sources/logging/*.{h,cpp} was already
globbed, but unlike the other ui/ subfolders that one had no entry of
its own, so diagnosticsreportdialog.{h,cpp} would not have been built
under qmake.
2026-08-06 23:04:27 +12:00
ispyisail ff812f221a Rework diagnostic logging: fix the file writer, add rotation and a ring buffer
Implements steps 1-3 of discussion #644 (deliberately not steps 4/5 --
no signal handler / crash flush, no diagnostics UI; see below).

## Step 1 -- fix the existing logger (bugs, no new behavior)

- One QFile handle held open for the whole session under a mutex,
  instead of opening and closing the log file on every single message.
- The log directory and the session's date-stamped filename are
  resolved exactly once, in the new QetLogger::init() called explicitly
  from main() immediately before qInstallMessageHandler() -- not
  recomputed per message, so a session that runs past midnight now
  stays in one file instead of silently splitting.
- Age-based retention now uses lastModified() instead of lastRead():
  opening a log to attach it to a bug report no longer resets its
  retention clock.
- stderr and file output both encode UTF-8 explicitly (toUtf8()),
  replacing stderr's toLocal8Bit() and the file stream's previously
  Qt5/Qt6-inconsistent default encoding.

## Step 2 -- size-capped rotation + hardening

- The previously-unbounded daily file is now capped at 2 MiB and
  rotated (kMaxFileBytes/kRotationKeep in QetLogger), keeping
  <date>.log plus <date>.1.log .. <date>.4.log; oldest is dropped.
- Each message is truncated to 4 KB with a "...[truncated N bytes]"
  marker before it reaches the ring or the file.
- Control characters (newlines, tabs, other non-printables) in message
  content are escaped, since much of what QET logs is externally
  controlled (file paths, element names, font strings out of a .qet
  file) -- left unescaped, an embedded '\n' could forge log lines.
- The log file is refused if a symlink already exists at that path,
  and is created/rotated owner-read/write only.

## Step 3 -- in-memory ring buffer

- LogRing (sources/logging/logring.h) is a fixed-capacity, always-on
  ring of the last 4096 log lines, preallocated once at construction
  (4096 * 512 B = 2 MiB) so append() never allocates. Entries are
  stored as plain pre-formatted bytes in fixed-size slots -- the shape
  discussion #644 specifies so a *future* crash handler could dump it
  with nothing but write(2), even though no such handler exists yet.
  Thread-safe via a plain QMutex (the lock-free requirement in the
  discussion applies specifically to a signal-handler read path, which
  this step doesn't add).

## Escape hatch

QET_LOG_DISABLE=1 in the environment at startup bypasses all of the
above -- no ring, no file, no rotation -- falling back to a minimal,
self-contained stderr passthrough that doesn't share any code with the
new formatting/sanitization path, so it stays usable even if that path
is what's misbehaving.

## Deliberately not included (per the discussion's own phasing)

- No signal handler / crash-time ring flush (step 4) -- the discussion
  flags this as the highest-risk piece, explicitly meant to land last
  and behind its own switch once the rest is proven.
- No diagnostics export UI (step 5).
- No log categories, session header, repeat collapsing or rate
  limiting -- listed under "best practices worth building in", not
  part of steps 1-3.

## Testing

Built clean, no new warnings.

Verified with real runs (QT_QPA_PLATFORM=offscreen, isolated HOME):
- Log file created at the expected dataDir()/YYYYMMDD.log path, mode
  0600.
- A full startup's worth of real messages (translations, MachineInfo's
  system dump, collection loading) written correctly; every one of the
  231 lines in one run starts with a proper timestamp -- confirmed the
  sanitizer correctly escapes the raw embedded newlines/tabs in
  MachineInfo's multi-line CPU/GPU description fields into visible
  \n/\t sequences rather than letting them fragment the log.
- QET_LOG_DISABLE=1: zero log files created, stderr still worked via
  the independent legacy path.
- Rotation: pre-filled a log to just under the 2 MiB cap, ran a normal
  session, confirmed it rotated to <date>.1.log (still 0600) with a
  byte-clean split (no truncated/duplicated line at the boundary) and
  a fresh <date>.log picked up from the next line.
2026-08-03 14:25:42 +12:00
Laurent Trinques db759344fd Merge pull request #563 from DieterMayerOSS/pr/log-handler-before-startup
Install the log message handler before the application starts
2026-07-28 17:35:11 +02:00
Dieter Mayer 1caa8920ae Harden QDom serialization against invalid data (CVE-2026-15037)
Set QDomImplementation::setInvalidDataPolicy(ReturnNullNode) at startup.
Qt before 6.12 defaults to accepting invalid data when building QDom
nodes, so untrusted text inserted into comments, CDATA sections or
processing instructions could break out of its node on serialization
(XML injection, low severity). Qt 6.12 flips the default to
ReturnNullNode; opting in explicitly gives the same behavior on any
Qt 5/6 version, so no version guard is needed.

Verified: --resave of a 5-folio project produces valid XML with all
folios intact, and --export-pdf still works on the result.

(cherry picked from commit 7804ef3864a0b8643cfe13b68b8e0e6235508ab6)
2026-07-28 13:58:34 +02:00
Dieter Mayer 9a13fef959 Install the log message handler before the application starts
qInstallMessageHandler() ran inside the startup worker thread, which is
scheduled after QETApp construction - but QETApp's constructor performs
the entire startup (collections, editor, opening projects passed on the
command line). Everything logged during that window went to the default
handler, i.e. stderr, which is invisible in a Windows GUI session: the
daily log file ended right after the machine-info block, and exactly
the interesting lines - the elements-collection timer and the project
load timer from #560 - never reached it.

Install the handler synchronously before SingleApplication instead;
the worker keeps the old-log cleanup and machine-info dump. The CLI
path returns earlier and intentionally keeps plain stderr logging.

Verified: a GUI session now logs the full timeline, e.g.
  12:37:03.623 Elements collection reload
  12:37:03.776 ... finished to be loaded in 0.151 seconds
  12:37:04.744 Project "..." (726 KiB) opened in 1.583 seconds
(cherry picked from commit 72b1a1d9ec2e3fd3787224759797978d710880bd)
2026-07-28 13:58:30 +02:00
Dieter Mayer a0f66d22cc Fix remaining Qt6 build warnings (narrowing, nodiscard, qHash)
Clears the 9 non-deprecation warnings from the Qt6 build:
- qHash(QColor): hash rgba() (unambiguous QRgb) instead of name(), and
  use the size_t seed signature on Qt6 (guarded for Qt5). Fixes the
  ambiguous-overload warning in terminalstripmodel.h.
- Two qsizetype->int narrowings in brace-init: explicit static_cast<int>
  (elementscene.cpp, terminalstrip.cpp).
- main.cpp: keep the QtConcurrent::run QFuture in a [[maybe_unused]]
  variable (nodiscard).
- qetapp.cpp: guard the stylesheet load on QFile::open() succeeding
  (nodiscard) instead of ignoring the result.
2026-07-14 19:27:37 +02:00
scorpio810 1c764babd1 macOS: buffer QFileOpenEvent during cold launch before QETApp exists
Follow-up to the eventFilter fix: testing showed double-click works
when QET is already running, but a cold launch (app not running yet)
still opens an empty window. Finder/Launch Services can deliver the
QFileOpenEvent to the QApplication's native event loop before main()
reaches the point where QETApp is constructed and its real eventFilter
is installed -- there's a window between 'SingleApplication app(...)'
and 'QETApp qetapp;' during which the event can arrive and be lost.

Add a minimal EarlyFileOpenCatcher installed on app immediately after
it's constructed (before anything else can run an event loop). It only
buffers the file path. Once QETApp exists, main() swaps it out for the
real QETApp::eventFilter and drains anything that was buffered via
qetapp.openFiles(), so no cold-launch QFileOpenEvent is silently
dropped.

Confirmed by manual testing:
- 'open app --args file' on .qet/.elmt/.titleblock: OK (already worked)
- double-click while app already running: OK (already worked)
- double-click cold launch: previously opened an empty window, this
  buffers and replays the event so it now opens the right editor.
2026-06-21 13:04:07 +02:00
scorpio810 8d76354647 macOS: fix QFileOpenEvent routing for .qet/.elmt/.titleblock double-click
Root cause (see issue #218 discussion):
- QETApp::eventFiltrer (Q_OS_DARWIN) was correct in intent but never
  actually installed as an event filter anywhere, and its name didn't
  match the QObject::eventFilter virtual signature, so even if it had
  been installed it would never have been invoked as an override.
  Confirmed dead code.
- main.cpp instead routed Finder's QFileOpenEvent through
  MacOSXOpenEvent -> SingleApplication::sendMessage(), which is the
  secondary-to-primary IPC channel. Called from within the primary
  instance itself, sendMessage() fails silently and the file path is
  dropped, which is exactly what double-click does (Finder doesn't spawn
  a secondary process, the running instance receives the FileOpen event
  directly).
- openFiles() takes a QETArguments, not a QStringList. The dead code's
  openFiles(QStringList() << filename) only worked via an untested
  implicit QStringList -> QList<QString> -> QETArguments conversion
  chain.

Fix:
- Rename eventFiltrer -> eventFilter (qetapp.h/.cpp) so it's a proper
  override of QObject::eventFilter, and make it public so main.cpp can
  install it on QApplication.
- Build the QETArguments explicitly instead of relying on implicit
  conversion.
- main.cpp: drop MacOSXOpenEvent entirely (include + instantiation),
  install qetapp as the Q_OS_MACOS event filter on app right after
  QETApp qetapp; is constructed and before app.exec(). No race window:
  the event loop hasn't started, so no QFileOpenEvent can be delivered
  before the filter is installed.

QETArguments::handleFileArgument() already sorts files by extension
(.elmt, titleblock, else project) and openFiles() already fans out to
openProjectFiles()/openElementFiles()/openTitleBlockTemplateFiles()
accordingly, so this single fix covers .qet, .elmt and .titleblock
double-click/drag-to-dock on macOS, not just .qet.

SingleApplication's sendMessage/receivedMessage flow (used for CLI args
on all platforms) is untouched; this only touches the Q_OS_MACOS block,
so there is no behavior change on Windows/Linux.

Follow-up (not included here): the macOS Info.plist (misc/Info.plist)
has an empty CFBundleShortVersionString, which may affect macOS's
willingness to retain file associations across app updates.
2026-06-21 12:10:13 +02:00
Shane Ringrose c586a2d3a3 Fix three uninitialised-value bugs found by Valgrind
1. machine_info.h: zero-initialise Screen struct members
   Max_width, Max_height, count, width[] and height[] were bare
   int32_t with no initialiser. The comparisons in
   init_get_Screen_info() read them before any write, producing
   undefined behaviour flagged by Valgrind as 'Conditional jump
   or move depends on uninitialised value(s)'.

2. main.cpp: pre-initialise MachineInfo on the main thread
   MachineInfo::instance() was first called inside QtConcurrent::run(),
   causing its constructor (which calls qApp->screens()) to run on a
   background thread. QScreen methods are not thread-safe in Qt5.
   Calling instance() once on the main thread before the worker
   launches guarantees the singleton is fully built first; subsequent
   calls from the worker just return the cached pointer.

3. qetdiagrameditor.h: move m_first_show before the QActionGroup members
   C++ initialises members in declaration order. m_first_show was
   declared after the QActionGroup members (line 256 vs 168). During
   construction of m_row_column_actions_group(this), Qt dispatches a
   QObject parent-change event that reaches QETDiagramEditor::event(),
   which reads m_first_show before it has been initialised.
   Moving the declaration to the top of the first private: block
   ensures it is initialised before any member that can trigger events.

All three found via Valgrind --tool=memcheck on Ubuntu 22.04 / Qt 5.15.3.
Relates-to: PR #514 (same QtConcurrent thread-safety pattern).
2026-06-20 22:31:06 +12:00
Shane Ringrose 19e99aab02 CLI: disable async crash-recovery backup in headless mode (fixes segfault)
QETProject schedules an asynchronous crash-recovery backup on construction
(writeBackup() -> QtConcurrent::run(QET::writeToFile, ..., &m_backup_file)).
In one-shot CLI mode the QETProject is destroyed as soon as the command
returns, while that background write still references its m_backup_file
member — an intermittent use-after-free segfault during teardown (~1 in 6
runs; observed on --resave and --set-titleblock).

A crash-recovery backup is meaningless for a short-lived headless command,
so add QETProject::setBackupEnabled(false), called from the CLI entry in
main(). writeBackup() then early-returns, so no background write is ever
launched. Fixes the crash for all CLI commands. See #492.
2026-06-12 05:25:44 +12:00
Shane Ringrose 1070179617 Add headless command-line export (PDF/PNG/SVG)
Implements the long-requested batch/headless export
(bugtracker #171, GitHub #309): render a project's diagrams to files
without opening the GUI.

  qelectrotech --export-pdf <project.qet> <output.pdf>   one multi-page PDF
  qelectrotech --export-png <project.qet> <output_dir>   one PNG per diagram
  qelectrotech --export-svg <project.qet> <output_dir>   one SVG per diagram

main.cpp detects an export request before SingleApplication is created (so the
arguments are not forwarded to a running instance), spins up a plain
QApplication for rendering, and exits with the export's status code.

Rendering reuses Diagram::render() over
BorderTitleBlock::borderAndTitleBlockRect(), the same geometry the GUI
print/export path uses, so output matches the editor. Image files are named
NN_Title.<ext>.

New files: sources/cli_export.{h,cpp}, registered in
cmake/qet_compilation_vars.cmake.
2026-06-11 11:10:09 +12:00
Laurent Trinques 4044d04cc5 One year
Auto-build doxygen docs / doxygen (push) Has been cancelled
Auto-build doxygen docs / deploy (push) Has been cancelled
2026-01-16 15:24:35 +01:00
plc-user bd89d3a1b7 no qt version check needed to disable randomisation of hashes 2026-01-14 17:56:02 +01:00
plc-user 72bd4803e6 no random hashes to have more constant order of XML-tags 2026-01-07 20:26:03 +01:00
plc-user ad29893842 use "%" for string-concatenation
Qt-Docs says it's less memory-usage...
2025-05-22 21:33:32 +02:00
Laurent Trinques adcf77e34a Replacing modules includes <QtConcurrent> with QtConcurrentRun and
QtConcurrentMap

Signed-off-by: Laurent Trinques <scorpio@qelectrotech.org>
2025-02-14 14:07:41 +01:00
plc-user ba9cd71816 set config- and data-dir to system-specific paths 2025-01-23 18:47:10 +01:00
Laurent Trinques 77bfe84a4c One year 2025-01-04 13:37:40 +01:00
plc-user 4c52c8c9d0 correct indentations / whitespace 2024-04-10 10:28:58 +02:00
Laurent Trinques e73cf633ce 2023->2024 2024-03-29 10:09:48 +01:00
Laurent Trinques 9afef79629 Update Copyright date 2023-01-01 17:05:57 +01:00
Laurent Trinques 1c99cb5c2d Add Qt::AA_UseHighDpiPixmaps 2022-04-27 09:14:13 +02:00
joshua b94ec0938b Add possibility to user to choose hdpi round policy
Add combo box in general configuration dialog to let user
choose the round policy to use with hdpi screen.
2021-12-04 14:38:41 +01:00
Laurent Trinques 760a1f6c43 Try to improve HIGHDPI_SCALING 2021-04-21 09:38:48 +02:00
joshua d53bb22509 Make MachineInfo a singleton class
Because on windows MachineInfo take a little time to init, we make it to
a singleton.
MachineInfo is build the first time in main.cpp.
Now all other places where we use MachineInfo (aboutqetdialog and
configdialog) gui don't hang anymore in waiting to MachineInfo finish to
build.
2021-03-22 19:20:07 +01:00
joshua 3d25beaea0 Rename class Machine_info to MachinInfo
Rename to follow the code style of QElectroTech
2021-03-22 19:01:46 +01:00
Joshua Claveau 7de810bac4 little fix 2021-03-21 19:06:12 +01:00
Joshua Claveau 6cf79e6e75 Qet start a little more faster (especially on windows)
Machine_Info class take time on windows even in powerful computer.
Run the machine_info in main.cpp in parallel into another thread.
2021-03-21 18:36:03 +01:00
Laurent Trinques ef58f34c14 Update Copyright date 2021-02-20 12:13:46 +01:00
joshua 2513961cd6 Revert "Update Copyright date"
This reverts commit d04bccc384.
2021-02-06 19:00:48 +01:00
Laurent Trinques d04bccc384 Update Copyright date 2021-02-06 18:33:42 +01:00
Simon De Backer 83d802adf7 Mod Cmake first working build 2020-12-11 14:55:11 +01:00
Simon De Backer 10c4c3d528 Wip Fix preprocessor on Cmake 2020-12-08 19:57:35 +01:00
Simon De Backer 9f3c173b9f QT6: No Qt::AA_EnableHighDpiScaling in QT6 2020-10-03 16:08:55 +02:00
David Varley a68386c028 Merge branch 'cborn' of https://github.com/C-Born-Software/qelectrotech-source-mirror into cborn 2020-09-14 11:45:52 +10:00
David Varley 45fb97f410 Start cborn branch - disable annoying startup warning 2020-09-10 00:16:03 +10:00
Simon De Backer 0310cd2610 Revert "Add user warning on startup"
This reverts commit 87c957a062.
2020-09-08 17:53:37 +02:00
Simon De Backer 87c957a062 Add user warning on startup
notify the user of the use of dev software

ToDo: the text still needs to be adjusted
2020-09-05 00:27:24 +02:00
Simon De Backer 81da7c6713 Fix dubbel // on log file dir 2020-08-31 22:26:03 +02:00
Simon De Backer 2482a0bd4c Fix log files in wrong dir
when arguments are used,
the log file change from dir,
result 2 log files,
and 1 log file is not deleted by
void delete_old_log_files(int days)
2020-08-17 19:12:52 +02:00
Simon De Backer 5832e365e9 Fix log file Dir 2020-08-15 21:40:07 +02:00
Simon De Backer de8ccc543d Fix no line number in debug 2020-08-14 18:35:53 +02:00
Simon De Backer 274108d509 Mod debuger to 7 days logs in .qet dir
the user can now read the log files
and/or send them to us for further investigation
2020-08-14 18:31:38 +02:00
Simon De Backer d5b7414b36 Mod Machine_info
add send_info_to_debug
Mod get data PC
send to debuger on startup
2020-08-13 22:50:58 +02:00
Simon De Backer 288737af0d Add Debugging Techniques 2020-08-12 23:54:09 +02:00
Simon De Backer b0df6d3101 Remove code minium QT_VERSION 5.9 2020-08-12 23:53:52 +02:00
Simon De Backer fe4552200b Add compiler message @TODO 2020-07-19 22:06:42 +02:00
Simon De Backer d3b237d06c Mod documentation + wrap code for better readability 2020-07-19 20:28:56 +02:00
Laurent Trinques 534ab19616 Revert "MacOS: try to remove hard coded python PATH"
This reverts commit 36071e9cf5.
2020-06-16 17:36:54 +02:00