@@ -53,6 +53,138 @@ Please refer to our
5353[ empty-line ] : https://stackoverflow.com/questions/5813311/no-newline-at-end-of-file#5813359
5454[ posix ] : https://stackoverflow.com/questions/729692/why-should-text-files-end-with-a-newline
5555
56+ ### Error messages, warnings, and exception handling
57+
58+ Clear, consistent, and parseable error and warning messages help users
59+ debug problems and allow tooling to parse and filter output.
60+ Follow these conventions in all PyThaiNLP code.
61+
62+ #### Exception types
63+
64+ Use the most specific built-in exception type for each situation:
65+
66+ | Situation | Exception type |
67+ | --- | --- |
68+ | Missing optional dependency at import time | ` ImportError ` or ` ModuleNotFoundError ` |
69+ | Invalid argument value | ` ValueError ` |
70+ | Wrong argument type | ` TypeError ` |
71+ | Required file not found | ` FileNotFoundError ` |
72+ | I/O or OS-level failure | ` OSError ` |
73+ | Runtime failure with no more-specific type | ` RuntimeError ` |
74+ | Feature not yet implemented | ` NotImplementedError ` |
75+
76+ #### Exception message format
77+
78+ Write messages as complete sentences.
79+
80+ - End each sentence with a period.
81+ - Identify the offending value, name, or path explicitly.
82+ - For a missing optional dependency, include the ` pip install ` command:
83+
84+ ``` text
85+ <Package> is not installed. Install it with: pip install <package>
86+ ```
87+
88+ If the package is a PyThaiNLP optional-dependency group, name the extra:
89+
90+ ``` text
91+ <Package> is required for this feature.
92+ Install it with: pip install pythainlp[<extra>]
93+ ```
94+
95+ - For an invalid argument value, name the parameter and show the received value:
96+
97+ ``` text
98+ <param> must be <description>; got {value!r}
99+ ```
100+
101+ #### Exception forwarding (chaining)
102+
103+ Always chain exceptions with ` from ` when raising a new exception inside an
104+ ` except ` block, so the full traceback and original cause are preserved:
105+
106+ ``` python
107+ # Correct: chain to the original exception.
108+ try :
109+ import some_package
110+ except ImportError as e:
111+ raise ImportError (
112+ " some_package is not installed. Install it with: pip install some_package"
113+ ) from e
114+
115+ # Correct: suppress chain with `from None` only when the original
116+ # exception is irrelevant noise that would confuse the user.
117+ raise ValueError (" Invalid configuration value." ) from None
118+ ```
119+
120+ Never use ` raise e ` to re-raise a caught exception. Use bare ` raise ` instead,
121+ which preserves the original traceback:
122+
123+ ``` python
124+ # Correct: bare re-raise preserves traceback.
125+ except Exception :
126+ log_or_print_something()
127+ raise
128+
129+ # Incorrect: `raise e` creates a new traceback starting at this line.
130+ except Exception as e:
131+ log_or_print_something()
132+ raise e # do not do this
133+ ```
134+
135+ When re-raising as a * different* exception type, always supply ` from ` :
136+
137+ ``` python
138+ # Correct.
139+ except OSError as e:
140+ raise RuntimeError (f " Failed to read model file: { e} " ) from e
141+
142+ # Incorrect: original cause is silently discarded.
143+ except OSError as e:
144+ raise RuntimeError (f " Failed to read model file: { e} " )
145+ ```
146+
147+ #### Warnings
148+
149+ Use ` warnings.warn() ` for non-fatal conditions that the caller should know
150+ about. Always pass both ` category ` and ` stacklevel ` explicitly:
151+
152+ ``` python
153+ import warnings
154+
155+ warnings.warn(" Message." , UserWarning , stacklevel = 2 )
156+ ```
157+
158+ Recommended categories:
159+
160+ | Situation | Category |
161+ | --- | --- |
162+ | Deprecated API that will be removed in a future version | ` DeprecationWarning ` |
163+ | Skipped or degraded behavior the caller should review | ` UserWarning ` |
164+
165+ Use ` stacklevel=2 ` so the warning points at the ** caller's** line, not the
166+ internal line that called ` warnings.warn() ` . Increase ` stacklevel ` by one for
167+ each additional layer of indirection between the public API and the
168+ ` warnings.warn() ` call.
169+
170+ Warning messages should be clear, concise, and parseable:
171+
172+ - Write messages as complete sentences ending with a period.
173+ - For deprecations, name the deprecated symbol and its replacement:
174+
175+ ``` text
176+ <old_symbol> is deprecated; use <new_symbol> instead.
177+ ```
178+
179+ - For skipped data or fallback behavior, describe what was skipped and why:
180+
181+ ``` text
182+ Skipping <item> entry with <reason>: {value!r}
183+ ```
184+
185+ Do ** not** rely on the default ` UserWarning ` by omitting ` category ` .
186+ Always supply ` category ` explicitly for clarity and greppability.
187+
56188### Version Control System
57189
58190- We use [ Git] ( https://git-scm.com/ ) as our
0 commit comments