execsql2 2.0.0a2__py3-none-any.whl → 2.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. execsql/cli.py +322 -108
  2. execsql/config.py +134 -114
  3. execsql/db/access.py +89 -65
  4. execsql/db/base.py +97 -68
  5. execsql/db/dsn.py +45 -29
  6. execsql/db/duckdb.py +4 -5
  7. execsql/db/factory.py +27 -27
  8. execsql/db/firebird.py +30 -18
  9. execsql/db/mysql.py +38 -14
  10. execsql/db/oracle.py +58 -33
  11. execsql/db/postgres.py +68 -28
  12. execsql/db/sqlite.py +36 -27
  13. execsql/db/sqlserver.py +45 -30
  14. execsql/exceptions.py +68 -64
  15. execsql/exporters/__init__.py +1 -1
  16. execsql/exporters/base.py +42 -17
  17. execsql/exporters/delimited.py +60 -59
  18. execsql/exporters/duckdb.py +8 -12
  19. execsql/exporters/feather.py +32 -24
  20. execsql/exporters/html.py +33 -30
  21. execsql/exporters/json.py +18 -17
  22. execsql/exporters/latex.py +11 -13
  23. execsql/exporters/ods.py +50 -46
  24. execsql/exporters/parquet.py +32 -0
  25. execsql/exporters/pretty.py +16 -15
  26. execsql/exporters/raw.py +9 -11
  27. execsql/exporters/sqlite.py +38 -38
  28. execsql/exporters/templates.py +15 -72
  29. execsql/exporters/values.py +13 -12
  30. execsql/exporters/xls.py +26 -26
  31. execsql/exporters/xml.py +12 -12
  32. execsql/exporters/zip.py +0 -3
  33. execsql/gui/__init__.py +2 -2
  34. execsql/gui/console.py +0 -1
  35. execsql/gui/desktop.py +6 -7
  36. execsql/gui/tui.py +8 -14
  37. execsql/importers/base.py +6 -9
  38. execsql/importers/csv.py +10 -17
  39. execsql/importers/feather.py +16 -22
  40. execsql/importers/ods.py +3 -4
  41. execsql/importers/xls.py +5 -6
  42. execsql/metacommands/__init__.py +8 -8
  43. execsql/metacommands/conditions.py +41 -33
  44. execsql/metacommands/connect.py +113 -99
  45. execsql/metacommands/control.py +38 -26
  46. execsql/metacommands/data.py +35 -33
  47. execsql/metacommands/debug.py +13 -9
  48. execsql/metacommands/io.py +288 -229
  49. execsql/metacommands/prompt.py +179 -157
  50. execsql/metacommands/script_ext.py +11 -9
  51. execsql/metacommands/system.py +44 -25
  52. execsql/models.py +9 -16
  53. execsql/parser.py +10 -10
  54. execsql/script.py +183 -157
  55. execsql/state.py +173 -215
  56. execsql/types.py +46 -81
  57. execsql/utils/auth.py +114 -14
  58. execsql/utils/crypto.py +31 -4
  59. execsql/utils/datetime.py +7 -7
  60. execsql/utils/errors.py +34 -29
  61. execsql/utils/fileio.py +90 -55
  62. execsql/utils/gui.py +22 -23
  63. execsql/utils/mail.py +15 -17
  64. execsql/utils/numeric.py +2 -3
  65. execsql/utils/regex.py +9 -12
  66. execsql/utils/strings.py +10 -12
  67. execsql/utils/timer.py +0 -2
  68. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/execsql.conf +1 -1
  69. execsql2-2.1.1.dist-info/METADATA +295 -0
  70. execsql2-2.1.1.dist-info/RECORD +96 -0
  71. execsql2-2.0.0a2.dist-info/METADATA +0 -406
  72. execsql2-2.0.0a2.dist-info/RECORD +0 -95
  73. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/READ_ME.rst +0 -0
  74. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/config_settings.sqlite +0 -0
  75. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
  76. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/make_config_db.sql +0 -0
  77. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/md_compare.sql +0 -0
  78. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/md_glossary.sql +0 -0
  79. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/md_upsert.sql +0 -0
  80. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/pg_compare.sql +0 -0
  81. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/pg_glossary.sql +0 -0
  82. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/pg_upsert.sql +0 -0
  83. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/script_template.sql +0 -0
  84. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/ss_compare.sql +0 -0
  85. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/ss_glossary.sql +0 -0
  86. {execsql2-2.0.0a2.data → execsql2-2.1.1.data}/data/execsql2_extras/ss_upsert.sql +0 -0
  87. {execsql2-2.0.0a2.dist-info → execsql2-2.1.1.dist-info}/WHEEL +0 -0
  88. {execsql2-2.0.0a2.dist-info → execsql2-2.1.1.dist-info}/entry_points.txt +0 -0
  89. {execsql2-2.0.0a2.dist-info → execsql2-2.1.1.dist-info}/licenses/LICENSE.txt +0 -0
  90. {execsql2-2.0.0a2.dist-info → execsql2-2.1.1.dist-info}/licenses/NOTICE +0 -0
@@ -13,15 +13,17 @@ Implements metacommands that extend or augment a running script:
13
13
  from typing import Any
14
14
 
15
15
  import execsql.state as _state
16
+ from execsql.exceptions import ErrInfo
17
+ from execsql.script import MetacommandStmt, ScriptCmd, ScriptExecSpec, SqlStmt, current_script_line
16
18
 
17
19
 
18
20
  def x_extendscript(**kwargs: Any) -> None:
19
21
  script1 = kwargs["script1"].lower()
20
22
  if script1 not in _state.savedscripts:
21
- raise _state.ErrInfo("cmd", other_msg=f"There is no SCRIPT named {script1}.")
23
+ raise ErrInfo("cmd", other_msg=f"There is no SCRIPT named {script1}.")
22
24
  script2 = kwargs["script2"].lower()
23
25
  if script2 not in _state.savedscripts:
24
- raise _state.ErrInfo("cmd", other_msg=f"There is no SCRIPT named {script2}.")
26
+ raise ErrInfo("cmd", other_msg=f"There is no SCRIPT named {script2}.")
25
27
  s1 = _state.savedscripts[script1]
26
28
  s2 = _state.savedscripts[script2]
27
29
  for cmd in s1.cmdlist:
@@ -37,20 +39,20 @@ def x_extendscript(**kwargs: Any) -> None:
37
39
  def x_extendscript_metacommand(**kwargs: Any) -> None:
38
40
  script = kwargs["script"].lower()
39
41
  if script not in _state.savedscripts:
40
- raise _state.ErrInfo("cmd", other_msg=f"There is no SCRIPT named {script}.")
41
- script_file, script_line_no = _state.current_script_line()
42
+ raise ErrInfo("cmd", other_msg=f"There is no SCRIPT named {script}.")
43
+ script_file, script_line_no = current_script_line()
42
44
  _state.savedscripts[script].add(
43
- _state.ScriptCmd(script_file, script_line_no, "cmd", _state.MetacommandStmt(kwargs["cmd"])),
45
+ ScriptCmd(script_file, script_line_no, "cmd", MetacommandStmt(kwargs["cmd"])),
44
46
  )
45
47
 
46
48
 
47
49
  def x_extendscript_sql(**kwargs: Any) -> None:
48
50
  script = kwargs["script"].lower()
49
51
  if script not in _state.savedscripts:
50
- raise _state.ErrInfo("cmd", other_msg=f"There is no SCRIPT named {script}.")
51
- script_file, script_line_no = _state.current_script_line()
52
+ raise ErrInfo("cmd", other_msg=f"There is no SCRIPT named {script}.")
53
+ script_file, script_line_no = current_script_line()
52
54
  _state.savedscripts[script].add(
53
- _state.ScriptCmd(script_file, script_line_no, "sql", _state.SqlStmt(kwargs["sql"])),
55
+ ScriptCmd(script_file, script_line_no, "sql", SqlStmt(kwargs["sql"])),
54
56
  )
55
57
 
56
58
 
@@ -58,4 +60,4 @@ def x_executescript(**kwargs: Any) -> None:
58
60
  exists = kwargs["exists"]
59
61
  script_id = kwargs["script_id"].lower()
60
62
  if exists is None or (exists is not None and script_id in _state.savedscripts):
61
- _state.ScriptExecSpec(**kwargs).execute()
63
+ ScriptExecSpec(**kwargs).execute()
@@ -14,20 +14,39 @@ import subprocess
14
14
  from typing import Any
15
15
 
16
16
  import execsql.state as _state
17
+ from execsql.exceptions import ErrInfo
18
+ from execsql.exporters.base import WriteSpec
19
+ from execsql.script import ScriptExecSpec, current_script_line
20
+ from execsql.utils.errors import exception_desc
21
+ from execsql.utils.fileio import filewriter_close_all_after_write
22
+ from execsql.utils.gui import (
23
+ gui_console_height,
24
+ gui_console_hide,
25
+ gui_console_off,
26
+ gui_console_on,
27
+ gui_console_progress,
28
+ gui_console_save,
29
+ gui_console_show,
30
+ gui_console_status,
31
+ gui_console_wait_user,
32
+ gui_console_width,
33
+ )
34
+ from execsql.utils.mail import MailSpec, Mailer
35
+ from execsql.utils.strings import is_doublequoted
17
36
 
18
37
 
19
38
  def x_system_cmd(**kwargs: Any) -> None:
20
39
  syscmd = kwargs["command"]
21
40
  cont = kwargs["continue"]
22
- script, lno = _state.current_script_line()
41
+ script, lno = current_script_line()
23
42
  _state.exec_log.log_user_msg(f"System command on line {lno} of script {script}: {syscmd}")
24
- _state.filewriter_close_all_after_write()
43
+ filewriter_close_all_after_write()
25
44
  if os.name != "posix":
26
45
  syscmd = syscmd.replace("\\", "\\\\")
27
46
  cmdlist = shlex.split(syscmd)
28
47
  else:
29
48
  cmdlist = shlex.split(syscmd, posix=True)
30
- cmdargs = ['"' + cmd + '"' if "&" in cmd and not _state.is_doublequoted(cmd) else cmd for cmd in cmdlist]
49
+ cmdargs = ['"' + cmd + '"' if "&" in cmd and not is_doublequoted(cmd) else cmd for cmd in cmdlist]
31
50
  if cont is None:
32
51
  returncode = subprocess.call(cmdargs)
33
52
  _state.subvars.add_substitution("$SYSTEM_CMD_EXIT_STATUS", str(returncode))
@@ -43,7 +62,7 @@ def x_email(**kwargs: Any) -> None:
43
62
  msg = kwargs["msg"]
44
63
  msg_file = kwargs["msg_file"]
45
64
  att_file = kwargs["att_file"]
46
- m = _state.Mailer()
65
+ m = Mailer()
47
66
  m.sendmail(from_addr, to_addr, subject, msg, msg_file, att_file)
48
67
 
49
68
 
@@ -73,9 +92,9 @@ def x_log_datavars(**kwargs: Any) -> None:
73
92
  def x_console(**kwargs: Any) -> None:
74
93
  onoff = kwargs["onoff"].lower()
75
94
  if onoff == "on":
76
- _state.gui_console_on()
95
+ gui_console_on()
77
96
  else:
78
- _state.gui_console_off()
97
+ gui_console_off()
79
98
 
80
99
 
81
100
  def x_consoleprogress(**kwargs: Any) -> None:
@@ -83,12 +102,12 @@ def x_consoleprogress(**kwargs: Any) -> None:
83
102
  total = kwargs["total"]
84
103
  if total:
85
104
  num = 100 * num / float(total)
86
- _state.gui_console_progress(num)
105
+ gui_console_progress(num)
87
106
 
88
107
 
89
108
  def x_consolewait(**kwargs: Any) -> None:
90
109
  message = kwargs["message"]
91
- _state.gui_console_wait_user(message)
110
+ gui_console_wait_user(message)
92
111
 
93
112
 
94
113
  def x_consolewait_onerror(**kwargs: Any) -> None:
@@ -104,39 +123,39 @@ def x_consolewait_whendone(**kwargs: Any) -> None:
104
123
  def x_console_hideshow(**kwargs: Any) -> None:
105
124
  hideshow = kwargs["hideshow"].lower()
106
125
  if hideshow == "hide":
107
- _state.gui_console_hide()
126
+ gui_console_hide()
108
127
  else:
109
- _state.gui_console_show()
128
+ gui_console_show()
110
129
 
111
130
 
112
131
  def x_consolewidth(**kwargs: Any) -> None:
113
132
  width = kwargs["width"]
114
133
  _state.conf.gui_console_width = int(width)
115
- _state.gui_console_width(width)
134
+ gui_console_width(width)
116
135
 
117
136
 
118
137
  def x_consoleheight(**kwargs: Any) -> None:
119
138
  height = kwargs["height"]
120
139
  _state.conf.gui_console_height = int(height)
121
- _state.gui_console_height(height)
140
+ gui_console_height(height)
122
141
 
123
142
 
124
143
  def x_consolestatus(**kwargs: Any) -> None:
125
144
  message = kwargs["message"]
126
- _state.gui_console_status(message)
145
+ gui_console_status(message)
127
146
 
128
147
 
129
148
  def x_consolesave(**kwargs: Any) -> None:
130
149
  fn = kwargs["filename"]
131
150
  ap = kwargs["append"]
132
151
  append = ap is not None
133
- _state.gui_console_save(fn, append)
152
+ gui_console_save(fn, append)
134
153
 
135
154
 
136
155
  def x_cancel_halt(**kwargs: Any) -> None:
137
156
  flag = kwargs["onoff"].lower()
138
157
  if flag not in ("on", "off", "yes", "no", "true", "false"):
139
- raise _state.ErrInfo(
158
+ raise ErrInfo(
140
159
  type="cmd",
141
160
  command_text=kwargs["metacommandline"],
142
161
  other_msg=f"Unrecognized flag for handling GUI cancellations: {flag}",
@@ -152,9 +171,9 @@ def x_cancel_halt_write_clear(**kwargs: Any) -> None:
152
171
  def x_cancel_halt_write(**kwargs: Any) -> None:
153
172
  msg = f"{kwargs['text']}\n"
154
173
  tee = kwargs["tee"]
155
- tee = False if not tee else True
174
+ tee = bool(tee)
156
175
  outf = kwargs["filename"]
157
- _state.cancel_halt_writespec = _state.WriteSpec(message=msg, dest=outf, tee=tee)
176
+ _state.cancel_halt_writespec = WriteSpec(message=msg, dest=outf, tee=tee)
158
177
 
159
178
 
160
179
  def x_cancel_halt_email_clear(**kwargs: Any) -> None:
@@ -168,11 +187,11 @@ def x_cancel_halt_email(**kwargs: Any) -> None:
168
187
  msg = kwargs["msg"]
169
188
  msg_file = kwargs["msg_file"]
170
189
  att_file = kwargs["att_file"]
171
- _state.cancel_halt_mailspec = _state.MailSpec(from_addr, to_addr, subject, msg, msg_file, att_file)
190
+ _state.cancel_halt_mailspec = MailSpec(from_addr, to_addr, subject, msg, msg_file, att_file)
172
191
 
173
192
 
174
193
  def x_cancel_halt_exec(**kwargs: Any) -> None:
175
- _state.cancel_halt_exec = _state.ScriptExecSpec(**kwargs)
194
+ _state.cancel_halt_exec = ScriptExecSpec(**kwargs)
176
195
 
177
196
 
178
197
  def x_cancel_halt_exec_clear(**kwargs: Any) -> None:
@@ -186,9 +205,9 @@ def x_error_halt_write_clear(**kwargs: Any) -> None:
186
205
  def x_error_halt_write(**kwargs: Any) -> None:
187
206
  msg = f"{kwargs['text']}\n"
188
207
  tee = kwargs["tee"]
189
- tee = False if not tee else True
208
+ tee = bool(tee)
190
209
  outf = kwargs["filename"]
191
- _state.err_halt_writespec = _state.WriteSpec(message=msg, dest=outf, tee=tee)
210
+ _state.err_halt_writespec = WriteSpec(message=msg, dest=outf, tee=tee)
192
211
 
193
212
 
194
213
  def x_error_halt_email_clear(**kwargs: Any) -> None:
@@ -202,11 +221,11 @@ def x_error_halt_email(**kwargs: Any) -> None:
202
221
  msg = kwargs["msg"]
203
222
  msg_file = kwargs["msg_file"]
204
223
  att_file = kwargs["att_file"]
205
- _state.err_halt_email = _state.MailSpec(from_addr, to_addr, subject, msg, msg_file, att_file)
224
+ _state.err_halt_email = MailSpec(from_addr, to_addr, subject, msg, msg_file, att_file)
206
225
 
207
226
 
208
227
  def x_error_halt_exec(**kwargs: Any) -> None:
209
- _state.err_halt_exec = _state.ScriptExecSpec(**kwargs)
228
+ _state.err_halt_exec = ScriptExecSpec(**kwargs)
210
229
 
211
230
 
212
231
  def x_error_halt_exec_clear(**kwargs: Any) -> None:
@@ -230,8 +249,8 @@ def x_execute(**kwargs: Any) -> None:
230
249
  try:
231
250
  db.exec_cmd(sql)
232
251
  db.commit()
233
- except _state.ErrInfo:
252
+ except ErrInfo:
234
253
  raise
235
254
  except Exception:
236
- raise _state.ErrInfo("db", command_text=sql, exception_msg=_state.exception_desc())
255
+ raise ErrInfo("db", command_text=sql, exception_msg=exception_desc())
237
256
  return None
execsql/models.py CHANGED
@@ -18,9 +18,8 @@ This module provides:
18
18
  ``"string"``, etc.).
19
19
  """
20
20
 
21
- import copy
22
21
  import re
23
- from typing import Any, List, Optional
22
+ from typing import Any
24
23
 
25
24
  from execsql.exceptions import ColumnError, DataTableError
26
25
  from execsql.types import (
@@ -60,15 +59,9 @@ class Column:
60
59
  self.varscale = False
61
60
 
62
61
  def __repr__(self) -> str:
63
- return "Data type %s; failed=%s; count=%d; maxlen=%d; varlen=%s, precision=%s, scale=%s, varscale=%s" % (
64
- self.dt.data_type_name,
65
- self.failed,
66
- self.count,
67
- self.maxlen,
68
- self.varlen,
69
- self.maxprecision,
70
- self.scale,
71
- self.varscale,
62
+ return (
63
+ f"Data type {self.dt.data_type_name}; failed={self.failed}; count={self.count}; maxlen={self.maxlen};"
64
+ f" varlen={self.varlen}, precision={self.maxprecision}, scale={self.scale}, varscale={self.varscale}"
72
65
  )
73
66
 
74
67
  def check(self, datavalue: Any) -> None:
@@ -160,7 +153,7 @@ class Column:
160
153
  if conf.trim_strings:
161
154
  column_value = column_value.strip()
162
155
  if conf.replace_newlines:
163
- column_value = re.sub(r"\s\t]*[\r\n]+[\s\t]*", " ", column_value)
156
+ column_value = re.sub(r"[\s\t]*[\r\n]+[\s\t]*", " ", column_value)
164
157
  if column_value is None or (
165
158
  not conf.empty_strings and isinstance(column_value, str) and len(column_value.strip()) == 0
166
159
  ):
@@ -202,7 +195,7 @@ class Column:
202
195
  self.dt = (
203
196
  self.name,
204
197
  sel_type.dt.__class__,
205
- None if not sel_type.dt.lenspec else ac.maxlen,
198
+ None if not sel_type.dt.lenspec else sel_type.maxlen,
206
199
  self.nullrows > 0,
207
200
  sel_type.maxprecision,
208
201
  sel_type.scale,
@@ -212,7 +205,7 @@ class Column:
212
205
 
213
206
 
214
207
  class DataTable:
215
- def __init__(self, column_names: List[str], rowsource: Any) -> None:
208
+ def __init__(self, column_names: list[str], rowsource: Any) -> None:
216
209
  import execsql.state as _state
217
210
 
218
211
  self.inputrows = 0 # Total number of rows in the row source.
@@ -263,7 +256,7 @@ class DataTable:
263
256
  def __repr__(self) -> str:
264
257
  return f"DataTable({[col.name for col in self.cols]!r}, rowsource)"
265
258
 
266
- def column_declarations(self, database_type: DbType) -> List[str]:
259
+ def column_declarations(self, database_type: DbType) -> list[str]:
267
260
  # Returns a list of column specifications.
268
261
  spec = []
269
262
  for col in self.cols:
@@ -273,7 +266,7 @@ class DataTable:
273
266
  def create_table(
274
267
  self,
275
268
  database_type: DbType,
276
- schemaname: Optional[str],
269
+ schemaname: str | None,
277
270
  tablename: str,
278
271
  pretty: bool = False,
279
272
  ) -> str:
execsql/parser.py CHANGED
@@ -23,7 +23,7 @@ Classes:
23
23
  """
24
24
 
25
25
  import re
26
- from typing import Any, List, Optional
26
+ from typing import Any
27
27
 
28
28
  from execsql.exceptions import CondParserError, NumericParserError
29
29
 
@@ -42,7 +42,7 @@ class SourceString:
42
42
  while not self.eoi() and self.str[self.currpos] in [" ", "\t", "\n"]:
43
43
  self.currpos += 1
44
44
 
45
- def match_str(self, str: str) -> Optional[str]:
45
+ def match_str(self, str: str) -> str | None:
46
46
  # Tries to match the 'str' argument at the current position in the
47
47
  # source string. Matching is case-insensitive. If matching succeeds,
48
48
  # the matched string is returned and the internal pointer is incremented.
@@ -59,7 +59,7 @@ class SourceString:
59
59
  else:
60
60
  return None
61
61
 
62
- def match_regex(self, regex: Any) -> Optional[dict]:
62
+ def match_regex(self, regex: Any) -> dict | None:
63
63
  # Tries to match the 'regex' argument at the current position in the
64
64
  # source string. If it succeeds, a dictionary of all of the named
65
65
  # groups is returned, and the internal pointer is incremented.
@@ -74,7 +74,7 @@ class SourceString:
74
74
  else:
75
75
  return None
76
76
 
77
- def match_metacommand(self, commandlist: Any) -> Optional[tuple]:
77
+ def match_metacommand(self, commandlist: Any) -> tuple | None:
78
78
  # Tries to match text at the current position to any metacommand
79
79
  # in the specified commandlist.
80
80
  # If it succeeds, the return value is a tuple of the MetaCommand object
@@ -185,21 +185,21 @@ class CondParser(CondTokens):
185
185
  self.condexpr = condexpr
186
186
  self.cond_expr = SourceString(condexpr)
187
187
 
188
- def match_not(self) -> Optional[int]:
188
+ def match_not(self) -> int | None:
189
189
  # Try to match 'NOT' operator. If not found, return None
190
190
  m1 = self.cond_expr.match_str("NOT")
191
191
  if m1 is not None:
192
192
  return self.NOT
193
193
  return None
194
194
 
195
- def match_andop(self) -> Optional[int]:
195
+ def match_andop(self) -> int | None:
196
196
  # Try to match 'AND' operator. If not found, return None
197
197
  m1 = self.cond_expr.match_str("AND")
198
198
  if m1 is not None:
199
199
  return self.AND
200
200
  return None
201
201
 
202
- def match_orop(self) -> Optional[int]:
202
+ def match_orop(self) -> int | None:
203
203
  # Try to match 'OR' operator. If not found, return None
204
204
  m1 = self.cond_expr.match_str("OR")
205
205
  if m1 is not None:
@@ -270,7 +270,7 @@ class NumericParser(NumTokens):
270
270
  self.rxint = re.compile(r"(?P<int_num>[+-]?[0-9]+)")
271
271
  self.rxfloat = re.compile(r"(?P<float_num>[+-]?(?:(?:[0-9]*\.[0-9]+)|(?:[0-9]+\.[0-9]*)))")
272
272
 
273
- def match_number(self) -> Optional[Any]:
273
+ def match_number(self) -> Any | None:
274
274
  # Try to match a number in the source string.
275
275
  # Return it if matched, return None if unmatched.
276
276
  m1 = self.num_expr.match_regex(self.rxfloat)
@@ -282,7 +282,7 @@ class NumericParser(NumTokens):
282
282
  return int(m2["int_num"])
283
283
  return None
284
284
 
285
- def match_mulop(self) -> Optional[int]:
285
+ def match_mulop(self) -> int | None:
286
286
  # Try to match a multiplication or division operator in the source string.
287
287
  # if found, return the matching operator type. If not found, return None.
288
288
  m1 = self.num_expr.match_str("*")
@@ -294,7 +294,7 @@ class NumericParser(NumTokens):
294
294
  return self.DIV
295
295
  return None
296
296
 
297
- def match_addop(self) -> Optional[int]:
297
+ def match_addop(self) -> int | None:
298
298
  # Try to match an addition or subtraction operator in the source string.
299
299
  # if found, return the matching operator type. If not found, return None.
300
300
  m1 = self.num_expr.match_str("+")