Skip to content

Commit f97b4b6

Browse files
committed
Improves logging settings and Python path resolution
1 parent 3721f28 commit f97b4b6

File tree

4 files changed

+267
-8
lines changed

4 files changed

+267
-8
lines changed

pixi.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ PYTHONIOENCODING = "utf-8"
1616

1717
# Unix/macOS
1818
[target.unix.activation.env]
19-
PYTHONPATH = "src${PYTHONPATH:+:${PYTHONPATH}}" # removes ":" if needed
19+
PYTHONPATH = "${PIXI_PROJECT_ROOT}/src${PYTHONPATH:+:${PYTHONPATH}}"
2020

2121
# Windows
2222
[target.win.activation.env]
23-
PYTHONPATH = "src;%PYTHONPATH%"
23+
PYTHONPATH = "${PIXI_PROJECT_ROOT}/src;%PYTHONPATH%"
2424

2525
###########
2626
# WORKSPACE

src/easydiffraction/utils/logging.py

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ def configure(
105105
reaction = cls.Reaction[env_reaction.upper()]
106106

107107
if mode is None:
108-
mode = cls.Mode.COMPACT if cls._in_jupyter() else cls.Mode.VERBOSE
108+
# Default to VERBOSE even in Jupyter unless explicitly set
109+
mode = cls.Mode.VERBOSE
109110
if level is None:
110111
level = cls.Level.INFO
111112
if reaction is None:
@@ -123,15 +124,36 @@ def configure(
123124

124125
from rich.console import Console
125126

126-
console = Console(width=120)
127+
# Enable rich tracebacks inside Jupyter environments
128+
if cls._in_jupyter():
129+
from rich import traceback
130+
131+
traceback.install(
132+
show_locals=False,
133+
suppress=['easydiffraction'],
134+
# max_frames=10 if mode == cls.Mode.VERBOSE else 1,
135+
# word_wrap=False,
136+
# extra_lines=0, # no extra context lines
137+
# locals_max_length=0, # no local vars shown
138+
# locals_max_string=0, # no local string previews
139+
)
140+
console = Console(
141+
width=120,
142+
# color_system="truecolor",
143+
force_jupyter=False,
144+
# force_terminal=False,
145+
# force_interactive=True,
146+
# legacy_windows=False,
147+
# soft_wrap=True,
148+
)
127149
handler = RichHandler(
128150
rich_tracebacks=rich_tracebacks,
129151
markup=True,
130-
show_time=True,
131-
show_path=True,
152+
show_time=False,
153+
show_path=False,
132154
tracebacks_show_locals=False,
133155
tracebacks_suppress=['easydiffraction'],
134-
tracebacks_max_frames=10, # <-- LIMIT TO LAST 5 FRAMES
156+
tracebacks_max_frames=10,
135157
console=console,
136158
)
137159
handler.setFormatter(logging.Formatter('%(message)s'))
@@ -162,6 +184,8 @@ def _aligned_excepthook(
162184

163185
sys.excepthook = _aligned_excepthook # type: ignore[assignment]
164186
elif mode == cls.Mode.COMPACT:
187+
import sys
188+
165189
if not hasattr(cls, '_orig_excepthook'):
166190
cls._orig_excepthook = sys.excepthook # type: ignore[attr-defined]
167191

@@ -170,14 +194,44 @@ def _compact_excepthook(
170194
exc: BaseException,
171195
_tb: TracebackType | None,
172196
) -> None:
197+
# Use Rich logger to keep formatting in terminal
173198
cls._logger.error(str(exc))
174199
raise SystemExit(1)
175200

176201
sys.excepthook = _compact_excepthook # type: ignore[assignment]
202+
203+
# Disable Jupyter/IPython tracebacks properly
204+
cls._install_jupyter_traceback_suppressor()
177205
else:
178206
if hasattr(cls, '_orig_excepthook'):
179207
sys.excepthook = cls._orig_excepthook # type: ignore[attr-defined]
180208

209+
@classmethod
210+
def _install_jupyter_traceback_suppressor(cls) -> None:
211+
"""Install traceback suppressor in Jupyter, safely and lint-
212+
clean.
213+
"""
214+
try:
215+
from IPython import get_ipython
216+
217+
ip = get_ipython()
218+
if ip is not None:
219+
220+
def _suppress_jupyter_traceback(
221+
_shell,
222+
_etype,
223+
_evalue,
224+
_tb,
225+
_tb_offset=None,
226+
):
227+
cls._logger.error(str(_evalue))
228+
return None
229+
230+
ip.set_custom_exc((BaseException,), _suppress_jupyter_traceback)
231+
except Exception as err:
232+
msg = f'Failed to install Jupyter traceback suppressor: {err!r}'
233+
cls._logger.debug(msg)
234+
181235
# ---------------- helpers ----------------
182236
@classmethod
183237
def set_mode(cls, mode: 'Logger.Mode') -> None:

tutorials-drafts/Untitled.ipynb

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 55,
6+
"id": "2b4ff90d-5a58-4202-ac2a-874168a2c6a2",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"from easydiffraction.core.categories import CategoryItem, CategoryCollection\n",
11+
"from easydiffraction.core.datablocks import DatablockItem, DatablockCollection\n",
12+
"from easydiffraction.core.guards import RangeValidator, \\\n",
13+
" ListValidator, RegexValidator\n",
14+
"from easydiffraction.core.parameters import DescriptorStr, Parameter\n",
15+
"from easydiffraction.crystallography.cif import CifHandler\n",
16+
"from easydiffraction.utils.logging import log # type: ignore\n",
17+
"from easydiffraction.sample_models.components.cell import Cell # type: ignore\n",
18+
"from easydiffraction.sample_models.components.space_group import SpaceGroup # type: ignore\n",
19+
"from easydiffraction.sample_models.collections.atom_sites import AtomSite, AtomSites # type: ignore\n",
20+
"from easydiffraction.sample_models.sample_model import BaseSampleModel, SampleModel\n",
21+
"from easydiffraction.sample_models.sample_models import SampleModels\n",
22+
"from easydiffraction.analysis.collections.constraints import Constraint\n",
23+
"from easydiffraction.analysis.collections.constraints import Constraints"
24+
]
25+
},
26+
{
27+
"cell_type": "code",
28+
"execution_count": 56,
29+
"id": "1100c5b2-e00c-4513-bd2e-e30742d47e67",
30+
"metadata": {},
31+
"outputs": [],
32+
"source": [
33+
"from easydiffraction.utils.logging import Logger\n",
34+
"\n",
35+
"Logger.configure(\n",
36+
" level=Logger.Level.INFO,\n",
37+
" mode=Logger.Mode.COMPACT,\n",
38+
" reaction=Logger.Reaction.WARN,\n",
39+
")"
40+
]
41+
},
42+
{
43+
"cell_type": "code",
44+
"execution_count": 57,
45+
"id": "a1a30af4-91c9-4015-9c96-a571fd1a711a",
46+
"metadata": {
47+
"scrolled": true
48+
},
49+
"outputs": [],
50+
"source": [
51+
"s1 = AtomSite(label='La', type_symbol='La')"
52+
]
53+
},
54+
{
55+
"cell_type": "code",
56+
"execution_count": 58,
57+
"id": "5f8217f7-e8cf-4202-8369-ced7438657f2",
58+
"metadata": {},
59+
"outputs": [],
60+
"source": [
61+
"s1.fract_x.value = 1.234"
62+
]
63+
},
64+
{
65+
"cell_type": "code",
66+
"execution_count": 59,
67+
"id": "4c9cf2fe-7f72-4b9d-a574-5eb8c40223c4",
68+
"metadata": {},
69+
"outputs": [
70+
{
71+
"name": "stdout",
72+
"output_type": "stream",
73+
"text": [
74+
"\u001b[33mWARNING \u001b[0m Type mismatch for \u001b[1m<\u001b[0m\u001b[1;95matom_site.La.fract_x\u001b[0m\u001b[1m>\u001b[0m. Provided \u001b[32m'xyz'\u001b[0m \u001b[1m(\u001b[0mstr\u001b[1m)\u001b[0m is not float. \n"
75+
]
76+
}
77+
],
78+
"source": [
79+
"s1.fract_x.value = 'xyz'"
80+
]
81+
},
82+
{
83+
"cell_type": "code",
84+
"execution_count": 60,
85+
"id": "cba23ca5-a865-428b-b1c8-90e38787e593",
86+
"metadata": {},
87+
"outputs": [
88+
{
89+
"name": "stdout",
90+
"output_type": "stream",
91+
"text": [
92+
"\u001b[33mWARNING \u001b[0m Type mismatch for \u001b[1m<\u001b[0m\u001b[1;95matom_site.La.fract_x\u001b[0m\u001b[1m>\u001b[0m. Provided \u001b[32m'qwe'\u001b[0m \u001b[1m(\u001b[0mstr\u001b[1m)\u001b[0m is not float. \n"
93+
]
94+
}
95+
],
96+
"source": [
97+
"s1.fract_x = 'qwe'"
98+
]
99+
},
100+
{
101+
"cell_type": "code",
102+
"execution_count": 61,
103+
"id": "3ba30971-177b-40e4-b477-e79a00341f87",
104+
"metadata": {},
105+
"outputs": [
106+
{
107+
"name": "stdout",
108+
"output_type": "stream",
109+
"text": [
110+
"\u001b[33mWARNING \u001b[0m Type mismatch for \u001b[1m<\u001b[0m\u001b[1;95mfract_x\u001b[0m\u001b[1m>\u001b[0m. Provided \u001b[32m'uuuu'\u001b[0m \u001b[1m(\u001b[0mstr\u001b[1m)\u001b[0m is not float. \n"
111+
]
112+
}
113+
],
114+
"source": [
115+
"s1 = AtomSite(label='Si', type_symbol='Si', fract_x='uuuu')"
116+
]
117+
},
118+
{
119+
"cell_type": "code",
120+
"execution_count": 62,
121+
"id": "992966e7-6bb7-4bc7-bbff-80acfea6fd2c",
122+
"metadata": {},
123+
"outputs": [],
124+
"source": [
125+
"s1.fract_x.free = True"
126+
]
127+
},
128+
{
129+
"cell_type": "code",
130+
"execution_count": 63,
131+
"id": "50ef6ebd-097d-4df2-93dc-39243bdba6fd",
132+
"metadata": {},
133+
"outputs": [
134+
{
135+
"name": "stdout",
136+
"output_type": "stream",
137+
"text": [
138+
"\u001b[33mWARNING \u001b[0m Type mismatch for \u001b[1m<\u001b[0m\u001b[1;95matom_site.Si.fract_x.free\u001b[0m\u001b[1m>\u001b[0m. Provided \u001b[32m'abc'\u001b[0m \u001b[1m(\u001b[0mstr\u001b[1m)\u001b[0m is not bool \n"
139+
]
140+
}
141+
],
142+
"source": [
143+
"s1.fract_x.free = 'abc'"
144+
]
145+
},
146+
{
147+
"cell_type": "code",
148+
"execution_count": 64,
149+
"id": "2c46e9ca-f68d-4b71-b783-6660f357322c",
150+
"metadata": {},
151+
"outputs": [],
152+
"source": [
153+
"c = Cell()"
154+
]
155+
},
156+
{
157+
"cell_type": "code",
158+
"execution_count": 65,
159+
"id": "8e3fee6f-dc71-49a0-bf67-6f85f4ba83cd",
160+
"metadata": {},
161+
"outputs": [
162+
{
163+
"name": "stdout",
164+
"output_type": "stream",
165+
"text": [
166+
"\u001b[33mWARNING \u001b[0m Value mismatch for \u001b[1m<\u001b[0m\u001b[1;95mlength_b\u001b[0m\u001b[1m>\u001b[0m. Provided \u001b[1;36m-8.8\u001b[0m is outside of \u001b[1m[\u001b[0m\u001b[1;36m0\u001b[0m, \u001b[1;36m1000\u001b[0m\u001b[1m]\u001b[0m. \n"
167+
]
168+
}
169+
],
170+
"source": [
171+
"c = Cell(length_b=-8.8)"
172+
]
173+
},
174+
{
175+
"cell_type": "code",
176+
"execution_count": null,
177+
"id": "749e3f57-1097-4939-b853-4c67148fb831",
178+
"metadata": {},
179+
"outputs": [],
180+
"source": []
181+
}
182+
],
183+
"metadata": {
184+
"kernelspec": {
185+
"display_name": "Python (Pixi)",
186+
"language": "python",
187+
"name": "pixi-kernel-python3"
188+
},
189+
"language_info": {
190+
"codemirror_mode": {
191+
"name": "ipython",
192+
"version": 3
193+
},
194+
"file_extension": ".py",
195+
"mimetype": "text/x-python",
196+
"name": "python",
197+
"nbconvert_exporter": "python",
198+
"pygments_lexer": "ipython3",
199+
"version": "3.13.7"
200+
}
201+
},
202+
"nbformat": 4,
203+
"nbformat_minor": 5
204+
}

tutorials-drafts/short5.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@
7878
assert getattr(c.length_b, 'qwe', None) is None
7979
c.length_b.description = 'desc' # type: ignore
8080
assert c.length_b.description == 'Length of the b axis of the unit cell.' # type: ignore
81-
assert c.length_b._public_readonly_attrs() == {'as_cif', 'constrained', 'description',
81+
assert c.length_b._public_readonly_attrs() == {'as_cif', 'cif_uid', 'constrained',
82+
'description',
8283
'unique_name', 'name', 'parameters',
8384
'uid', 'units'}
8485
assert c.length_b._public_writable_attrs() == {'fit_max', 'fit_min', 'free', 'uncertainty',

0 commit comments

Comments
 (0)