Skip to content
Merged

dev #299

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
2e4583d
CLN: cleanup mechanism to keep track of open windows
gdementen Oct 16, 2025
dbaefd5
FEAT/FIX: added usage when using the editor as a command-line program
gdementen Oct 8, 2025
acd9739
FEAT: format large shape sizes using _ as thousands separator
gdementen Oct 16, 2025
a0b5175
FEAT: color compare() max diff label red when != 0
gdementen Oct 15, 2025
accad9b
FEAT: heavily refactored array model, adapter code and widget code
gdementen Oct 16, 2025
66149f2
FEAT: allow plotting mixed type arrays
gdementen Aug 4, 2025
c4189ec
FIX: fixed "Copy to Excel" when an hidden Excel instance exists
gdementen Aug 6, 2025
603ecc2
FEAT: added File Explorer in File menu
gdementen Oct 9, 2025
27c748b
FIX: fixed compare showing all cells white and 0 as maximum diff when…
gdementen Oct 15, 2025
96d34da
ENH/FIX: remember detected column widths & row heights
gdementen Oct 17, 2025
584f007
ENH: made text/csv adapters more robust to decoding errors
gdementen Oct 17, 2025
446c206
CLN: added asserts to make debugging easier
gdementen Oct 20, 2025
05c0a63
FEAT: added adapter for .tsv files
gdementen Oct 20, 2025
8d76c6c
FEAT: add informative error message when trying to activate a file ty…
gdementen Oct 20, 2025
3c43f0b
FEAT: added adapter for .csv.gz files
gdementen Oct 21, 2025
a3670b4
TESTS: added larger test for mixed type Pandas DataFrame
gdementen Oct 22, 2025
0835640
FEAT: added support for mixed types dataframes in H5 files
gdementen Oct 22, 2025
05ccc05
PERF: fixed performance issue on large Pandas DataFrames
gdementen Oct 22, 2025
d320d6d
FEAT: added timings to debug log
gdementen Oct 22, 2025
fb92b83
TESTS: cleaner way to define test dataframes and added test for large…
gdementen Oct 22, 2025
506cf4e
FEAT: finish implementing sort and filters on hlabels
gdementen Oct 23, 2025
211d485
DOC: update release notes
gdementen Oct 23, 2025
8aba711
FEAT: make arraymodel robust to unprintable exceptions messages
gdementen Oct 27, 2025
619ff11
CLN: misc cleanup and debug messages
gdementen Oct 27, 2025
2c9f6e8
FEAT: dispatch parquet paths to different adapters depending on avail…
gdementen Oct 28, 2025
3ec80e8
FIX: fixed CSV files adapter when charset_normalizer package is not i…
gdementen Nov 4, 2025
e9aedc1
CLN: cleanup text file adapter code
gdementen Nov 4, 2025
eeb6b57
CLN: rename for clarity
gdementen Nov 4, 2025
8d35bfc
FEAT: added SQL console when polars is present
gdementen Nov 4, 2025
6395475
FEAT: added adapter for Pandas groupby objects
gdementen Nov 6, 2025
b8ed64b
ENH: consider more extensions as text files
gdementen Nov 6, 2025
33ade6c
FEAT: added adapter for .dta files
gdementen Nov 7, 2025
3a354c9
CLN: moved adapters around for more logical order
gdementen Nov 7, 2025
db67d1e
FIX: fixed assertion in mouse selection code
gdementen Nov 7, 2025
bdc2627
FIX: fixed subtle selection issue after key navigation
gdementen Nov 7, 2025
dff3c92
FIX: fixed several issues with 1D Excel range and sheets
gdementen Nov 7, 2025
70b9ed4
FIX: close adapters when quitting the editor
gdementen Nov 12, 2025
a7d5ce6
CLN: renames for consistency or clarity
gdementen Nov 12, 2025
2ad22fb
DOC: update TODO
gdementen Oct 16, 2025
8f0b96e
FIX: EXAMPLE_EXCEL_TEMPLATES_DIR should not appear in varlist
gdementen Nov 12, 2025
253199b
FIX: updated DirectoryPathAdapter to be more robust to deleted files
gdementen Nov 12, 2025
cba7b6d
FEAT: added Type column in DirectoryPathAdapter
gdementen Nov 12, 2025
cc888b5
FEAT: added line ending detection in text file adapters
gdementen Nov 12, 2025
0256661
FIX: avoid displaying bytes as sequences
gdementen Nov 12, 2025
3d91469
FEAT: detect csv delimiter and quotes
gdementen Nov 12, 2025
3578d2e
DOC: explain why SQL console is always present when polars is available
gdementen Nov 12, 2025
207ac7d
ENH: avoid populating the back bar when going to a directory
gdementen Nov 12, 2025
b313f5e
CLN: removed unused AbstractPathAdapter
gdementen Nov 13, 2025
04b99dc
FEAT: adapters will now return a message explaining why they cannot h…
gdementen Nov 13, 2025
e0c5570
ENH: made error message more consistent with similar messages
gdementen Nov 13, 2025
7a97091
ENH: handle more file extensions using text adapter
gdementen Nov 13, 2025
c0aefa9
ENH: allow registering several suffixes for path adapters in a single…
gdementen Nov 14, 2025
aa232c3
TEST: made polars optional for tests
gdementen Nov 14, 2025
ebd3aa4
ENH: None -> '' in Sheet adapter
gdementen Nov 14, 2025
28fd076
FEAT: warn when trying to save objects we cannot save
gdementen Nov 14, 2025
d19c579
FIX: reset "back" bar when selecting a variable in the list
gdementen Nov 14, 2025
66634f3
CLN: rename for consistency
gdementen Nov 14, 2025
8d58de0
FIX: fixed dispatch_file_suffix_by_available_module requiring submodules
gdementen Nov 17, 2025
543268e
FEAT: added support for pandas index columns in pyarrow.Parquet and m…
gdementen Nov 17, 2025
f2878a5
FIX: fixed adapter for feather files (via pyarrow) with pandas indexes
gdementen Nov 17, 2025
321aee3
DOC: update changelog
gdementen Nov 18, 2025
720e12f
TEST: allow running API tests without xlwings
gdementen Nov 20, 2025
9e2f627
FIX: explicitly import matplotlib.figure
gdementen Nov 20, 2025
06473ce
FEAT: add sort by hlabel to Mapping adapter
gdementen Nov 20, 2025
fe43897
ENH: use real align function from larray 0.35 in compare
gdementen Nov 28, 2025
36ea402
MAINT: added support for Python 3.13
gdementen Dec 1, 2025
73900cc
CLN: moved constant where we use it
gdementen Dec 1, 2025
624c29d
MAINT: update dependencies in setup.py
gdementen Dec 1, 2025
e616d19
FEAT: allow comparing a dict of Arrays or Sessions (closes #230)
gdementen Dec 1, 2025
6313096
FIX: respect nans_equal=False when comparing sessions
gdementen Dec 1, 2025
5e97124
CLN: cleanup ComparatorWidget implementation
gdementen Dec 1, 2025
70b0fd8
FEAT: implemented sas7bdat adapter using Pandas
gdementen Dec 1, 2025
7a24430
FEAT: implemented dta adapter using Pandas
gdementen Dec 2, 2025
303da82
DOC: update changelog for SAS files
gdementen Dec 2, 2025
8cc8768
MAINT: modernize github actions
gdementen Dec 2, 2025
cc0cd6a
FEAT: add drive buttons to File Explorer (closes #296)
gdementen Dec 2, 2025
ab29402
MAINT: added setuptools to host requirements
gdementen Dec 12, 2025
f68f0a8
CLN: only use committed files in tests
gdementen Dec 12, 2025
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
24 changes: 12 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
with:
# Pin ruff version to make sure we do not break our builds at the
# worst times
version: "0.14.0"
version: "0.14.7"

test:
# name: Test (${{ matrix.python-version }}, ${{ matrix.os }})
Expand All @@ -34,14 +34,14 @@ jobs:
shell: bash -l {0}

steps:
- uses: actions/checkout@v5
- name: Set up Python ${{ matrix.python-version }}
uses: conda-incubator/setup-miniconda@v3
with:
auto-update-conda: true
environment-file: environment.yml
python-version: ${{ matrix.python-version }}
- run: conda info
- run: conda list
- run: conda config --show
- run: pytest
- uses: actions/checkout@v5
- name: Set up Python ${{ matrix.python-version }}
uses: conda-incubator/setup-miniconda@v3
with:
auto-update-conda: true
environment-file: environment.yml
python-version: ${{ matrix.python-version }}
- run: conda info
- run: conda list
- run: conda config --show
- run: pytest
9 changes: 7 additions & 2 deletions condarecipe/larray-editor/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@ requirements:
host:
- python >=3.9
- pip
- setuptools

run:
- python >=3.9
# requires larray >= 0.32 because of the LArray -> Array rename
# Technically, we should require larray >=0.35 because we need align_arrays
# for compare(), but to make larray-editor releasable, we cannot depend on
# larray X.Y when releasing larray-editor X.Y (see utils.py for more
# details)
# TODO: require 0.35 for next larray-editor version
- larray >=0.32
# it is indirectly pulled from larray, but let us be explicit about this
- numpy
- numpy >=1.22
- matplotlib
- pyqt >=5
- qtpy >=2 # for Qt6 support
Expand Down
141 changes: 109 additions & 32 deletions doc/source/changes/version_0_35.rst.inc
Original file line number Diff line number Diff line change
@@ -1,25 +1,96 @@
.. py:currentmodule:: larray_editor

Syntax changes
^^^^^^^^^^^^^^

* renamed ``MappingEditor.old_method_name()`` to :py:obj:`MappingEditor.new_method_name()` (closes :editor_issue:`1`).

* renamed ``old_argument_name`` argument of :py:obj:`MappingEditor.method_name()` to ``new_argument_name``.


Backward incompatible changes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* other backward incompatible changes


New features
^^^^^^^^^^^^

* allow displaying *many* more different kinds of objects, and not only arrays
from larray. One specific goal when developing this new feature was speed.
Most of these viewers should be fast (when at all possible), even on (very)
large datasets. We only support displaying (not editing) all the new types.

The following types are supported so far (but adding more is relatively easy):

* Python builtin objects:
- tuple (including named tuple), list (sequences), dict (mappings),
dict views, memoryview and array
- text and binary files
* Python stdlib objects:
- pathlib.Path
* if the path points to a directory, it will display the content of the
directory
* if the path points to a file, it will try to display it, if we
implemented support for that file type (see below for the list
of supported types).
- sqlite3.Connection (and their tables)
- pstats.Stats (results of Python's profiler)
- zipfile.ZipFile and zipfile.Path
* new objects from LArray: Axis, Excel Workbook (what you get from
larray.open_excel()), Sheets and Range
* IODE "collections" objects: Comments, Equations, Identities, Lists, Tables,
Scalars and Variables, as well as Table objects
* Pandas: DataFrame, Series and DataFrameGroupBy
* Polars: DataFrame and LazyFrame
* Numpy: ndarray
* PyArrow: Array, Table, RecordBatchFileReader (reader object for feather
files) and ParquetFile
* Narwhals: DataFrame and LazyFrame
* PyTables: File, Group (with special support for Pandas DataFrames written
in HDF files), Array and Table
* IBIS: Table
* DuckDB: DuckDBPyConnection and DuckDBPyRelation (what you receive from any
query)

File types (extensions) currently supported:
- Iode files: .ac, .ae, .ai, .al, .as, .at, .av, .cmt, .eqs, .idt, .lst,
.scl, .tbl, .var
- Text files: .bat, .c, .cfg, .cpp, .h, .htm, .html, .ini, .log, .md,
.py, .pyx, .pxd, .rep, .rst, .sh, .sql, .toml, .txt, .wsgi,
.yaml, .yml
- HDF5 files: .h5, .hdf
- Parquet files: .parquet
- Stata files: .dta
- Feather files: .feather
- SAS files: .sas7bdat
It is limited to the first few thousand rows (the exact number depends on
the number of columns), because reading later rows get increasingly slow,
to the point of being unusable.
- CSV files: .csv
- Gzipped CSV files: .csv.gz
- Excel files: .xls, .xlsx
- Zip files: .zip
- DuckDB files: .ddb, .duckdb

* the editor now features a new "File Explorer" (accessible from the "File"
menu) so that one can more easily make use of all the above file viewers.

* added a new SQL Console (next to the iPython console) for querying Polars
structures (DataFrame, LazyFrame and Series) as SQL tables. The console
features auto-completion for SQL keywords, table names and column names
and stores the last 1000 queries (even across sessions). Recalling a query
from history is done with the up and down arrows and like in the iPython
console, it searches through history with the current command as prefix.
This console will only be present if the polars module is installed.

* allow sorting some objects by column by pressing on an horizontal label.
This is currently implemented for the following objects:
- python built-in sequences (e.g. tuples and lists)
- python pathlib.Path objects representing directories
- LArray (only for 2D arrays)
- Pandas DataFrame
- Polars DataFrame and LazyFrame
- Narwhals LazyFrame
- SQLite tables
- DuckDB relations

* allow filtering some objects by pressing on an horizontal label.
This is currently implemented for the following objects:
- Pandas DataFrame
- Polars DataFrame and LazyFrame
- DuckDB relations

* allow comparing arrays/sessions with different axes in :py:obj:`compare()`.
The function gained ``align`` and ``fill_value`` arguments and the interface has a new
combobox to change the alignment method during the comparison:
The function gained ``align`` and ``fill_value`` arguments and the interface
has a new combobox to change the alignment method during the comparison:
- outer: will use a label if it is in any array (ordered like the first array).
This is the default as it results in no information loss.
- inner: will use a label if it is in all arrays (ordered like the first array).
Expand All @@ -28,28 +99,30 @@ New features
- exact: raise an error when axes are not equal.
Closes :editor_issue:`214` and :editor_issue:`251`.

* double-clicking on an array name in the list will open it in a new window
* double-clicking on a name in the variable list will open it in a new window
(closes :editor_issue:`143`).

.. note::

- It works for foo bar !
- It does not work for foo baz !


Miscellaneous improvements
^^^^^^^^^^^^^^^^^^^^^^^^^^

* made the editor interruptible by an outside program (i.e. made PyCharm stop & restart buttons work directly
instead of only when the editor receives the focus again). Closes :editor_issue:`257`.
* made the editor interruptible by an outside program (i.e. made PyCharm stop &
restart buttons work directly instead of only when the editor receives the
focus again). Closes :editor_issue:`257`.

* resize axes and vertical label columns automatically

* when comparing sessions via :py:obj:`compare()`, the color of arrays in the list is now updated depending
on the tolerance. To reflect that the tolerance widget moved to the top of the interface.
Closes :editor_issue:`201`.
* string values are left aligned instead of right aligned

* typing the name of a variable holding a matplotlib figure (or axes) in the console shows it
(previously, only expressions were displayed and *not* simple variables).
For example: ::
* when comparing sessions via :py:obj:`compare()`, the color of arrays in the
list is now updated depending on the tolerance. To reflect that the tolerance
widget moved to the top of the interface. Closes :editor_issue:`201`.

* :py:obj:`compare()` max difference is colored red when the difference is not 0

* typing the name of a variable holding a matplotlib figure (or axes) in the
console shows it (previously, only expressions were displayed and *not*
simple variables). For example: ::

>>> arr.plot()

Expand All @@ -66,6 +139,10 @@ Miscellaneous improvements
Fixes
^^^^^

* fixed :py:obj:`compare()` colors when the only difference is nans on either side.
* fixed :py:obj:`compare()` colors when the only difference is nans on either
side.

* fixed :py:obj:`compare()` colors and max difference label when the only
differences are for rows where the value is 0 in the first array.

* fixed something (closes :editor_issue:`1`).
* fixed single column plot in viewer when ticks are not strings
33 changes: 21 additions & 12 deletions larray_editor/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def _get_title(obj, depth=0, maxnames=3):


def create_edit_dialog(parent, obj=None, title='', minvalue=None, maxvalue=None, readonly=False, depth=0,
display_caller_info=True, add_larray_functions=None):
display_caller_info=True, add_larray_functions=None, **kwargs):
"""
Open a new editor window.

Expand Down Expand Up @@ -198,7 +198,7 @@ def create_edit_dialog(parent, obj=None, title='', minvalue=None, maxvalue=None,
return MappingEditorWindow(obj, title=title, readonly=readonly,
caller_info=caller_info,
add_larray_functions=add_larray_functions,
parent=parent)
parent=parent, **kwargs)
else:
return ArrayEditorWindow(obj, title=title, readonly=readonly,
caller_info=caller_info,
Expand All @@ -212,11 +212,10 @@ def create_debug_dialog(parent, stack_summary, title='Debugger', stack_pos=None)


def create_compare_dialog(parent, *args, title='', names=None, depth=0, display_caller_info=True, **kwargs):
caller_frame = sys._getframe(depth + 1)
if display_caller_info:
caller_info = getframeinfo(caller_frame)
else:
caller_info = None
if len(args) == 1 and isinstance(args[0], dict):
if names is None:
names = list(args[0].keys())
args = list(args[0].values())

compare_sessions = any(isinstance(a, (la.Session, str, Path)) for a in args)
default_name = 'session' if compare_sessions else 'array'
Expand All @@ -232,14 +231,21 @@ def get_name(i, obj, depth=0):
# list comprehension used to create their own frame but are now
# inlined in Python 3.12+
extra_frame_for_comprehension = 0 if PY312 else 1
names = [get_name(i, a, depth=depth + 1 + extra_frame_for_comprehension) for i, a in enumerate(args)]
names = [get_name(i, a, depth=depth + 1 + extra_frame_for_comprehension)
for i, a in enumerate(args)]
else:
assert isinstance(names, list) and len(names) == len(args)

if compare_sessions:
args = [la.Session(a) if not isinstance(a, la.Session) else a
for a in args]

if display_caller_info:
caller_frame = sys._getframe(depth + 1)
caller_info = getframeinfo(caller_frame)
else:
caller_info = None

if compare_sessions:
return SessionComparatorWindow(args, names=names, title=title,
caller_info=caller_info, parent=parent,
Expand Down Expand Up @@ -381,7 +387,7 @@ def excepthook(type_, value, tback):
return excepthook


def edit(obj=None, title='', minvalue=None, maxvalue=None, readonly=False, depth=0):
def edit(obj=None, title='', minvalue=None, maxvalue=None, readonly=False, depth=0, **kwargs):
r"""
Open a new editor window.

Expand Down Expand Up @@ -415,7 +421,7 @@ def edit(obj=None, title='', minvalue=None, maxvalue=None, readonly=False, depth
>>> edit(a1) # doctest: +SKIP
"""
_show_dialog("Viewer", create_edit_dialog, obj=obj, title=title, minvalue=minvalue, maxvalue=maxvalue,
readonly=readonly, depth=depth + 1)
readonly=readonly, depth=depth + 1, **kwargs)


def view(obj=None, title='', depth=0):
Expand Down Expand Up @@ -470,8 +476,11 @@ def compare(*args, depth=0, **kwargs):

Parameters
----------
*args : Arrays, Sessions, str or Path.
Arrays or sessions to compare. Strings or Path will be loaded as Sessions from the corresponding files.
*args : Arrays, Sessions, str or Path, or dict of them.
Arrays or sessions to compare. Strings or Path will be loaded as
Sessions from the corresponding files. If arrays or sessions are given
as a single dict, the keys of the dict will be used as names for the
arrays or sessions.
title : str, optional
Title for the window. Defaults to ''.
names : list of str, optional
Expand Down
Loading
Loading