xtgeo 4.14.1__cp313-cp313-win_amd64.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.
- cxtgeo.py +558 -0
- cxtgeoPYTHON_wrap.c +19537 -0
- xtgeo/__init__.py +248 -0
- xtgeo/_cxtgeo.cp313-win_amd64.pyd +0 -0
- xtgeo/_internal.cp313-win_amd64.pyd +0 -0
- xtgeo/common/__init__.py +19 -0
- xtgeo/common/_angles.py +29 -0
- xtgeo/common/_xyz_enum.py +50 -0
- xtgeo/common/calc.py +396 -0
- xtgeo/common/constants.py +30 -0
- xtgeo/common/exceptions.py +42 -0
- xtgeo/common/log.py +93 -0
- xtgeo/common/sys.py +166 -0
- xtgeo/common/types.py +18 -0
- xtgeo/common/version.py +34 -0
- xtgeo/common/xtgeo_dialog.py +604 -0
- xtgeo/cube/__init__.py +9 -0
- xtgeo/cube/_cube_export.py +214 -0
- xtgeo/cube/_cube_import.py +532 -0
- xtgeo/cube/_cube_roxapi.py +180 -0
- xtgeo/cube/_cube_utils.py +287 -0
- xtgeo/cube/_cube_window_attributes.py +273 -0
- xtgeo/cube/cube1.py +1023 -0
- xtgeo/grid3d/__init__.py +15 -0
- xtgeo/grid3d/_ecl_grid.py +778 -0
- xtgeo/grid3d/_ecl_inte_head.py +152 -0
- xtgeo/grid3d/_ecl_logi_head.py +71 -0
- xtgeo/grid3d/_ecl_output_file.py +81 -0
- xtgeo/grid3d/_egrid.py +1004 -0
- xtgeo/grid3d/_find_gridprop_in_eclrun.py +625 -0
- xtgeo/grid3d/_grdecl_format.py +309 -0
- xtgeo/grid3d/_grdecl_grid.py +400 -0
- xtgeo/grid3d/_grid3d.py +29 -0
- xtgeo/grid3d/_grid3d_fence.py +284 -0
- xtgeo/grid3d/_grid3d_utils.py +228 -0
- xtgeo/grid3d/_grid_boundary.py +76 -0
- xtgeo/grid3d/_grid_etc1.py +1683 -0
- xtgeo/grid3d/_grid_export.py +222 -0
- xtgeo/grid3d/_grid_hybrid.py +50 -0
- xtgeo/grid3d/_grid_import.py +79 -0
- xtgeo/grid3d/_grid_import_ecl.py +101 -0
- xtgeo/grid3d/_grid_import_roff.py +135 -0
- xtgeo/grid3d/_grid_import_xtgcpgeom.py +375 -0
- xtgeo/grid3d/_grid_refine.py +258 -0
- xtgeo/grid3d/_grid_roxapi.py +292 -0
- xtgeo/grid3d/_grid_translate_coords.py +154 -0
- xtgeo/grid3d/_grid_wellzone.py +165 -0
- xtgeo/grid3d/_gridprop_export.py +202 -0
- xtgeo/grid3d/_gridprop_import_eclrun.py +164 -0
- xtgeo/grid3d/_gridprop_import_grdecl.py +132 -0
- xtgeo/grid3d/_gridprop_import_roff.py +52 -0
- xtgeo/grid3d/_gridprop_import_xtgcpprop.py +168 -0
- xtgeo/grid3d/_gridprop_lowlevel.py +171 -0
- xtgeo/grid3d/_gridprop_op1.py +272 -0
- xtgeo/grid3d/_gridprop_roxapi.py +301 -0
- xtgeo/grid3d/_gridprop_value_init.py +140 -0
- xtgeo/grid3d/_gridprops_import_eclrun.py +344 -0
- xtgeo/grid3d/_gridprops_import_roff.py +83 -0
- xtgeo/grid3d/_roff_grid.py +470 -0
- xtgeo/grid3d/_roff_parameter.py +303 -0
- xtgeo/grid3d/grid.py +3010 -0
- xtgeo/grid3d/grid_properties.py +699 -0
- xtgeo/grid3d/grid_property.py +1313 -0
- xtgeo/grid3d/types.py +15 -0
- xtgeo/interfaces/rms/__init__.py +18 -0
- xtgeo/interfaces/rms/_regular_surface.py +460 -0
- xtgeo/interfaces/rms/_rms_base.py +100 -0
- xtgeo/interfaces/rms/_rmsapi_package.py +69 -0
- xtgeo/interfaces/rms/rmsapi_utils.py +438 -0
- xtgeo/io/__init__.py +1 -0
- xtgeo/io/_file.py +603 -0
- xtgeo/metadata/__init__.py +17 -0
- xtgeo/metadata/metadata.py +435 -0
- xtgeo/roxutils/__init__.py +7 -0
- xtgeo/roxutils/_roxar_loader.py +54 -0
- xtgeo/roxutils/_roxutils_etc.py +122 -0
- xtgeo/roxutils/roxutils.py +207 -0
- xtgeo/surface/__init__.py +20 -0
- xtgeo/surface/_regsurf_boundary.py +26 -0
- xtgeo/surface/_regsurf_cube.py +210 -0
- xtgeo/surface/_regsurf_cube_window.py +391 -0
- xtgeo/surface/_regsurf_cube_window_v2.py +297 -0
- xtgeo/surface/_regsurf_cube_window_v3.py +360 -0
- xtgeo/surface/_regsurf_export.py +388 -0
- xtgeo/surface/_regsurf_grid3d.py +275 -0
- xtgeo/surface/_regsurf_gridding.py +347 -0
- xtgeo/surface/_regsurf_ijxyz_parser.py +278 -0
- xtgeo/surface/_regsurf_import.py +347 -0
- xtgeo/surface/_regsurf_lowlevel.py +122 -0
- xtgeo/surface/_regsurf_oper.py +538 -0
- xtgeo/surface/_regsurf_utils.py +81 -0
- xtgeo/surface/_surfs_import.py +43 -0
- xtgeo/surface/_zmap_parser.py +138 -0
- xtgeo/surface/regular_surface.py +3043 -0
- xtgeo/surface/surfaces.py +276 -0
- xtgeo/well/__init__.py +24 -0
- xtgeo/well/_blockedwell_roxapi.py +241 -0
- xtgeo/well/_blockedwells_roxapi.py +68 -0
- xtgeo/well/_well_aux.py +30 -0
- xtgeo/well/_well_io.py +327 -0
- xtgeo/well/_well_oper.py +483 -0
- xtgeo/well/_well_roxapi.py +304 -0
- xtgeo/well/_wellmarkers.py +486 -0
- xtgeo/well/_wells_utils.py +158 -0
- xtgeo/well/blocked_well.py +220 -0
- xtgeo/well/blocked_wells.py +134 -0
- xtgeo/well/well1.py +1516 -0
- xtgeo/well/wells.py +211 -0
- xtgeo/xyz/__init__.py +6 -0
- xtgeo/xyz/_polygons_oper.py +272 -0
- xtgeo/xyz/_xyz.py +758 -0
- xtgeo/xyz/_xyz_data.py +646 -0
- xtgeo/xyz/_xyz_io.py +737 -0
- xtgeo/xyz/_xyz_lowlevel.py +42 -0
- xtgeo/xyz/_xyz_oper.py +613 -0
- xtgeo/xyz/_xyz_roxapi.py +766 -0
- xtgeo/xyz/points.py +698 -0
- xtgeo/xyz/polygons.py +827 -0
- xtgeo-4.14.1.dist-info/METADATA +146 -0
- xtgeo-4.14.1.dist-info/RECORD +122 -0
- xtgeo-4.14.1.dist-info/WHEEL +5 -0
- xtgeo-4.14.1.dist-info/licenses/LICENSE.md +165 -0
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for basic XTGeo dialog, basic interaction with user,
|
|
3
|
+
including logging for debugging.
|
|
4
|
+
|
|
5
|
+
Logging is enabled by setting a environment variable::
|
|
6
|
+
|
|
7
|
+
export XTG_LOGGING_LEVEL=INFO # if bash; will set logging to INFO level
|
|
8
|
+
setenv XTG_LOGGING_LEVEL INFO # if tcsh; will set logging to INFO level
|
|
9
|
+
|
|
10
|
+
Other levels are DEBUG and CRITICAL. CRITICAL is default (cf. Pythons logging)
|
|
11
|
+
|
|
12
|
+
Usage of logging in scripts::
|
|
13
|
+
|
|
14
|
+
import xtgeo
|
|
15
|
+
xtg = xtgeo.common.XTGeoDialog()
|
|
16
|
+
logger = xtg.basiclogger(__name__)
|
|
17
|
+
logger.info('This is logging of %s', something)
|
|
18
|
+
|
|
19
|
+
Other than logging, there is also a template for user interaction, which shall
|
|
20
|
+
be used in client scripts::
|
|
21
|
+
|
|
22
|
+
xtg.echo('This is a message')
|
|
23
|
+
xtg.warn('This is a warning')
|
|
24
|
+
xtg.error('This is an error, will continue')
|
|
25
|
+
xtg.critical('This is a big error, will exit')
|
|
26
|
+
|
|
27
|
+
In addition there are other classes:
|
|
28
|
+
|
|
29
|
+
* XTGShowProgress()
|
|
30
|
+
|
|
31
|
+
* XTGDescription()
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
from __future__ import annotations
|
|
36
|
+
|
|
37
|
+
import getpass
|
|
38
|
+
import inspect
|
|
39
|
+
import logging
|
|
40
|
+
import os
|
|
41
|
+
import platform
|
|
42
|
+
import re
|
|
43
|
+
import sys
|
|
44
|
+
import timeit
|
|
45
|
+
import warnings
|
|
46
|
+
from datetime import datetime as dtime
|
|
47
|
+
from typing import Any, Literal
|
|
48
|
+
|
|
49
|
+
from .log import null_logger
|
|
50
|
+
from .version import __version__
|
|
51
|
+
|
|
52
|
+
DEBUG = 0
|
|
53
|
+
MLS = 10000000.0
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
HEADER = "\033[1;96m"
|
|
57
|
+
OKBLUE = "\033[94m"
|
|
58
|
+
OKGREEN = "\033[92m"
|
|
59
|
+
WARN = "\033[93;43m"
|
|
60
|
+
ERROR = "\033[93;41m"
|
|
61
|
+
CRITICAL = "\033[1;91m"
|
|
62
|
+
ENDC = "\033[0m"
|
|
63
|
+
BOLD = "\033[1m"
|
|
64
|
+
UNDERLINE = "\033[4m"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _printdebug(*args: Any) -> None:
|
|
68
|
+
"""local unction to print debugging while initializing logging"""
|
|
69
|
+
|
|
70
|
+
if DEBUG:
|
|
71
|
+
print("XTG DEBUG:", *args)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class XTGShowProgress:
|
|
75
|
+
"""Class for showing progress of a computation to the terminal.
|
|
76
|
+
|
|
77
|
+
Example::
|
|
78
|
+
|
|
79
|
+
# assuming 30 steps in calculation
|
|
80
|
+
theprogress = XTGShowProgress(30, info='Compute stuff')
|
|
81
|
+
for i in range(30):
|
|
82
|
+
do_slow_computation()
|
|
83
|
+
theprogress.flush(i)
|
|
84
|
+
theprogress.finished()
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def __init__(
|
|
88
|
+
self,
|
|
89
|
+
maxiter: int,
|
|
90
|
+
info: str = "",
|
|
91
|
+
leadtext: str = "",
|
|
92
|
+
skip: int = 1,
|
|
93
|
+
show: bool = True,
|
|
94
|
+
):
|
|
95
|
+
self._max = maxiter
|
|
96
|
+
self._info = info
|
|
97
|
+
self._show = show
|
|
98
|
+
self._leadtext = leadtext
|
|
99
|
+
self._skip = skip
|
|
100
|
+
self._next = 0
|
|
101
|
+
|
|
102
|
+
def flush(self, step: int) -> None:
|
|
103
|
+
if not self._show:
|
|
104
|
+
return
|
|
105
|
+
progress = int(float(step) / float(self._max) * 100.0)
|
|
106
|
+
if progress >= self._next:
|
|
107
|
+
print(f"{self._leadtext}{progress}% {self._info}")
|
|
108
|
+
self._next += self._skip
|
|
109
|
+
|
|
110
|
+
def finished(self) -> None:
|
|
111
|
+
if not self._show:
|
|
112
|
+
return
|
|
113
|
+
print(f"{self._leadtext}{100}% {self._info}")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class XTGDescription:
|
|
117
|
+
"""Class for making desciptions of object instances"""
|
|
118
|
+
|
|
119
|
+
def __init__(self) -> None:
|
|
120
|
+
self._txt: list[str] = []
|
|
121
|
+
|
|
122
|
+
def title(self, atitle: str) -> None:
|
|
123
|
+
fmt = "=" * 99
|
|
124
|
+
self._txt.append(fmt)
|
|
125
|
+
fmt = f"{atitle}"
|
|
126
|
+
self._txt.append(fmt)
|
|
127
|
+
fmt = "=" * 99
|
|
128
|
+
self._txt.append(fmt)
|
|
129
|
+
|
|
130
|
+
def txt(self, *atxt: Any) -> None:
|
|
131
|
+
fmt = self._smartfmt(list(atxt))
|
|
132
|
+
self._txt.append(fmt)
|
|
133
|
+
|
|
134
|
+
def flush(self) -> None:
|
|
135
|
+
fmt = "=" * 99
|
|
136
|
+
self._txt.append(fmt)
|
|
137
|
+
|
|
138
|
+
for line in self._txt:
|
|
139
|
+
print(line)
|
|
140
|
+
|
|
141
|
+
def astext(self) -> str:
|
|
142
|
+
thetext = ""
|
|
143
|
+
fmt = "=" * 99
|
|
144
|
+
self._txt.append(fmt)
|
|
145
|
+
|
|
146
|
+
for line in self._txt:
|
|
147
|
+
thetext += line + "\n"
|
|
148
|
+
|
|
149
|
+
return thetext[:-1] # skip last \n
|
|
150
|
+
|
|
151
|
+
@staticmethod
|
|
152
|
+
def _smartfmt(atxt: list[str]) -> str:
|
|
153
|
+
# f-string does not work with starred
|
|
154
|
+
alen = len(atxt)
|
|
155
|
+
atxt.insert(1, "=>")
|
|
156
|
+
if alen == 1:
|
|
157
|
+
fmt = "{:40s}".format(*atxt)
|
|
158
|
+
elif alen == 2:
|
|
159
|
+
fmt = "{:40s} {:>2s} {}".format(*atxt)
|
|
160
|
+
elif alen == 3:
|
|
161
|
+
fmt = "{:40s} {:>2s} {} {}".format(*atxt)
|
|
162
|
+
elif alen == 4:
|
|
163
|
+
fmt = "{:40s} {:>2s} {} {} {}".format(*atxt)
|
|
164
|
+
elif alen == 5:
|
|
165
|
+
fmt = "{:40s} {:>2s} {} {} {} {}".format(*atxt)
|
|
166
|
+
elif alen == 6:
|
|
167
|
+
fmt = "{:40s} {:>2s} {} {} {} {} {}".format(*atxt)
|
|
168
|
+
elif alen == 7:
|
|
169
|
+
fmt = "{:40s} {:>2s} {} {} {} {} {} {}".format(*atxt)
|
|
170
|
+
else:
|
|
171
|
+
fmt = "{:40s} {:>2s} {} {} {} {} {} {} {}".format(*atxt)
|
|
172
|
+
return fmt
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class _TimeFilter(logging.Filter):
|
|
176
|
+
"""handling difftimes in logging..."""
|
|
177
|
+
|
|
178
|
+
# cf https://stackoverflow.com/questions/31521859/
|
|
179
|
+
# \python-logging-module-time-since-last-log
|
|
180
|
+
|
|
181
|
+
def filter(self, record: logging.LogRecord) -> bool:
|
|
182
|
+
try:
|
|
183
|
+
last: float = self.last # type: ignore
|
|
184
|
+
except AttributeError:
|
|
185
|
+
last = record.relativeCreated
|
|
186
|
+
|
|
187
|
+
dlt = dtime.fromtimestamp(
|
|
188
|
+
record.relativeCreated / 1000.0
|
|
189
|
+
) - dtime.fromtimestamp(last / 1000.0)
|
|
190
|
+
|
|
191
|
+
record.relative = f"{dlt.seconds + dlt.microseconds / MLS:7.3f}"
|
|
192
|
+
|
|
193
|
+
self.last = record.relativeCreated
|
|
194
|
+
return True
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class _Formatter(logging.Formatter):
|
|
198
|
+
"""Override record.pathname to truncate strings"""
|
|
199
|
+
|
|
200
|
+
# https://stackoverflow.com/questions/14429724/
|
|
201
|
+
# python-logging-how-do-i-truncate-the-pathname-to-just-the-last-few-characters
|
|
202
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
203
|
+
filename = "unset_filename"
|
|
204
|
+
|
|
205
|
+
if "pathname" in record.__dict__:
|
|
206
|
+
# truncate the pathname
|
|
207
|
+
filename = record.pathname
|
|
208
|
+
if len(filename) > 40:
|
|
209
|
+
filename = re.sub(r".*src/", "", filename)
|
|
210
|
+
record.pathname = filename
|
|
211
|
+
|
|
212
|
+
return super().format(record)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class XTGeoDialog:
|
|
216
|
+
"""System for handling dialogs and messages in XTGeo.
|
|
217
|
+
|
|
218
|
+
This module cooperates with Python logging module.
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
def __init__(self) -> None:
|
|
222
|
+
"""Initializing XTGeoDialog."""
|
|
223
|
+
self._callclass = None
|
|
224
|
+
self._caller = None
|
|
225
|
+
self._rootlogger = logging.getLogger()
|
|
226
|
+
self._lformat = None
|
|
227
|
+
self._lformatlevel = 1
|
|
228
|
+
self._logginglevel = "CRITICAL"
|
|
229
|
+
self._logginglevel_fromenv = None
|
|
230
|
+
self._loggingname = ""
|
|
231
|
+
self._showrtwarnings = True
|
|
232
|
+
|
|
233
|
+
# a string, for Python logging:
|
|
234
|
+
self._logginglevel_fromenv = os.environ.get("XTG_LOGGING_LEVEL", None)
|
|
235
|
+
|
|
236
|
+
# a number, for format, 1 is simple, 2 is more info etc
|
|
237
|
+
loggingformat = os.environ.get("XTG_LOGGING_FORMAT")
|
|
238
|
+
|
|
239
|
+
_printdebug("Logging format is", loggingformat)
|
|
240
|
+
|
|
241
|
+
if self._logginglevel_fromenv:
|
|
242
|
+
self.logginglevel = self._logginglevel_fromenv
|
|
243
|
+
|
|
244
|
+
if loggingformat is not None:
|
|
245
|
+
self._lformatlevel = int(loggingformat)
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
def logginglevel(self) -> str:
|
|
249
|
+
"""Set or return a logging level property, e.g. logging.CRITICAL"""
|
|
250
|
+
|
|
251
|
+
return self._logginglevel
|
|
252
|
+
|
|
253
|
+
@logginglevel.setter
|
|
254
|
+
def logginglevel(self, level: str) -> None:
|
|
255
|
+
validlevels = ("INFO", "WARNING", "DEBUG", "CRITICAL")
|
|
256
|
+
if level in validlevels:
|
|
257
|
+
self._logginglevel = level
|
|
258
|
+
else:
|
|
259
|
+
raise ValueError(
|
|
260
|
+
f"Invalid level given, must be one of: {', '.join(validlevels)}"
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def numericallogginglevel(self) -> int:
|
|
265
|
+
"""Return a numerical logging level (read only)"""
|
|
266
|
+
llo = logging.CRITICAL
|
|
267
|
+
if self._logginglevel == "INFO":
|
|
268
|
+
llo = logging.INFO
|
|
269
|
+
elif self._logginglevel == "WARNING":
|
|
270
|
+
llo = logging.WARNING
|
|
271
|
+
elif self._logginglevel == "DEBUG":
|
|
272
|
+
llo = logging.DEBUG
|
|
273
|
+
|
|
274
|
+
return llo
|
|
275
|
+
|
|
276
|
+
@property
|
|
277
|
+
def loggingformatlevel(self) -> int:
|
|
278
|
+
return self._lformatlevel
|
|
279
|
+
|
|
280
|
+
@property
|
|
281
|
+
def loggingformat(self) -> str | None:
|
|
282
|
+
"""Returns the format string to be used in logging"""
|
|
283
|
+
|
|
284
|
+
_printdebug("Logging format is", self._lformatlevel)
|
|
285
|
+
|
|
286
|
+
if self._lformatlevel <= 1:
|
|
287
|
+
fmt = logging.Formatter(fmt="%(levelname)8s: (%(relative)ss) \t%(message)s")
|
|
288
|
+
|
|
289
|
+
elif self._lformatlevel == 2:
|
|
290
|
+
fmt = _Formatter(
|
|
291
|
+
fmt="%(levelname)8s (%(relative)ss) %(pathname)44s "
|
|
292
|
+
"[%(funcName)40s()] %(lineno)4d >> \t%(message)s"
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
else:
|
|
296
|
+
fmt = logging.Formatter(
|
|
297
|
+
fmt="%(asctime)s Line: %(lineno)4d %(name)44s "
|
|
298
|
+
"(Delta=%(relative)ss) "
|
|
299
|
+
"[%(funcName)40s()]"
|
|
300
|
+
"%(levelname)8s:"
|
|
301
|
+
"\t%(message)s"
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
log = self._rootlogger
|
|
305
|
+
for h in log.handlers:
|
|
306
|
+
h.addFilter(_TimeFilter())
|
|
307
|
+
h.setFormatter(fmt)
|
|
308
|
+
|
|
309
|
+
self._lformat = fmt._fmt # private attribute in Formatter()
|
|
310
|
+
return self._lformat
|
|
311
|
+
|
|
312
|
+
@staticmethod
|
|
313
|
+
def get_xtgeo_info(variant: Literal["clibinfo"] = "clibinfo") -> str:
|
|
314
|
+
"""Prints a banner for a XTGeo app to STDOUT.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
variant (str): Variant of info
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
info (str): A string with XTGeo system info
|
|
321
|
+
|
|
322
|
+
"""
|
|
323
|
+
|
|
324
|
+
if variant == "clibinfo":
|
|
325
|
+
return (
|
|
326
|
+
f"XTGeo version {__version__} (Python "
|
|
327
|
+
f"{platform.python_version()} on {platform.system()})"
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
return "Invalid"
|
|
331
|
+
|
|
332
|
+
@staticmethod
|
|
333
|
+
def print_xtgeo_header(
|
|
334
|
+
appname: str,
|
|
335
|
+
appversion: str | None,
|
|
336
|
+
info: str | None = None,
|
|
337
|
+
) -> None:
|
|
338
|
+
"""Prints a banner for a XTGeo app to STDOUT.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
appname (str): Name of application.
|
|
342
|
+
appversion (str): Version of application on form '3.2.1'
|
|
343
|
+
info (str, optional): More info, e.g. if beta release
|
|
344
|
+
|
|
345
|
+
Example::
|
|
346
|
+
|
|
347
|
+
xtg.print_xtgeo_header('myapp', '0.2.1', info='Beta release!')
|
|
348
|
+
"""
|
|
349
|
+
|
|
350
|
+
cur_version = "Python " + str(sys.version_info[0]) + "."
|
|
351
|
+
cur_version += str(sys.version_info[1]) + "." + str(sys.version_info[2])
|
|
352
|
+
|
|
353
|
+
app = appname + ", version " + str(appversion)
|
|
354
|
+
if info:
|
|
355
|
+
app = app + " (" + info + ")"
|
|
356
|
+
print("")
|
|
357
|
+
print(HEADER)
|
|
358
|
+
print("#" * 79)
|
|
359
|
+
print(f"#{app.center(77)}#")
|
|
360
|
+
print("#" * 79)
|
|
361
|
+
nowtime = dtime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
362
|
+
ver = f"Using XTGeo version {__version__}"
|
|
363
|
+
cur_version += f" @ {nowtime} on {platform.node()} by {getpass.getuser()}"
|
|
364
|
+
print(f"#{ver.center(77)}#")
|
|
365
|
+
print(f"#{cur_version.center(77)}#")
|
|
366
|
+
print("#" * 79)
|
|
367
|
+
print(ENDC)
|
|
368
|
+
print("")
|
|
369
|
+
|
|
370
|
+
def basiclogger(
|
|
371
|
+
self,
|
|
372
|
+
name: str,
|
|
373
|
+
logginglevel: str | None = None,
|
|
374
|
+
loggingformat: int | None = None,
|
|
375
|
+
info: bool = False,
|
|
376
|
+
) -> logging.Logger:
|
|
377
|
+
"""Initiate the logger by some default settings."""
|
|
378
|
+
|
|
379
|
+
if logginglevel is not None and self._logginglevel_fromenv is None:
|
|
380
|
+
self.logginglevel = logginglevel
|
|
381
|
+
|
|
382
|
+
if loggingformat is not None and isinstance(loggingformat, int):
|
|
383
|
+
self._lformatlevel = loggingformat
|
|
384
|
+
|
|
385
|
+
logging.basicConfig(stream=sys.stdout)
|
|
386
|
+
fmt = self.loggingformat
|
|
387
|
+
self._loggingname = name
|
|
388
|
+
if info:
|
|
389
|
+
print(
|
|
390
|
+
f"Logginglevel is {self.logginglevel}, formatlevel is "
|
|
391
|
+
f"{self._lformatlevel}, and format is {fmt}"
|
|
392
|
+
)
|
|
393
|
+
self._rootlogger.setLevel(self.numericallogginglevel)
|
|
394
|
+
|
|
395
|
+
logging.captureWarnings(True)
|
|
396
|
+
|
|
397
|
+
return logging.getLogger(self._loggingname)
|
|
398
|
+
|
|
399
|
+
@staticmethod
|
|
400
|
+
def functionlogger(name: str) -> logging.Logger:
|
|
401
|
+
"""
|
|
402
|
+
Deprecated: Get the logger for functions (not top level).
|
|
403
|
+
|
|
404
|
+
This method is deprecated and will be removed in a future version.
|
|
405
|
+
Use the `null_logger` function instead for creating loggers with a NullHandler.
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
name (str): The name of the logger.
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
logging.Logger: A logger object with a NullHandler.
|
|
412
|
+
|
|
413
|
+
Example:
|
|
414
|
+
# Deprecated usage
|
|
415
|
+
logger = XTGeoDialog.functionlogger(__name__)
|
|
416
|
+
|
|
417
|
+
# Recommended usage
|
|
418
|
+
logger = null_logger(__name__)
|
|
419
|
+
"""
|
|
420
|
+
|
|
421
|
+
warnings.warn(
|
|
422
|
+
"functionlogger is deprecated and will be removed in a future version. "
|
|
423
|
+
"Use null_logger instead.",
|
|
424
|
+
DeprecationWarning,
|
|
425
|
+
)
|
|
426
|
+
return null_logger(name)
|
|
427
|
+
|
|
428
|
+
@staticmethod
|
|
429
|
+
def timer(*args: float) -> float:
|
|
430
|
+
"""Without args; return the time, with a time as arg return the
|
|
431
|
+
difference.
|
|
432
|
+
"""
|
|
433
|
+
time1 = timeit.default_timer()
|
|
434
|
+
|
|
435
|
+
if args:
|
|
436
|
+
return time1 - args[0]
|
|
437
|
+
|
|
438
|
+
return time1
|
|
439
|
+
|
|
440
|
+
def show_runtimewarnings(self, flag: bool = True) -> None:
|
|
441
|
+
"""Show warnings issued by xtg.warn, if flag is True."""
|
|
442
|
+
self._showrtwarnings = flag
|
|
443
|
+
|
|
444
|
+
def insane(self, string: str) -> None:
|
|
445
|
+
level = 4
|
|
446
|
+
idx = 0
|
|
447
|
+
|
|
448
|
+
caller = sys._getframe(1).f_code.co_name
|
|
449
|
+
frame = inspect.stack()[1][0]
|
|
450
|
+
self.get_callerinfo(caller, frame)
|
|
451
|
+
|
|
452
|
+
self._output(idx, level, string)
|
|
453
|
+
|
|
454
|
+
def trace(self, string: str) -> None:
|
|
455
|
+
level = 3
|
|
456
|
+
idx = 0
|
|
457
|
+
|
|
458
|
+
caller = sys._getframe(1).f_code.co_name
|
|
459
|
+
frame = inspect.stack()[1][0]
|
|
460
|
+
self.get_callerinfo(caller, frame)
|
|
461
|
+
|
|
462
|
+
self._output(idx, level, string)
|
|
463
|
+
|
|
464
|
+
def debug(self, string: str) -> None:
|
|
465
|
+
level = 2
|
|
466
|
+
idx = 0
|
|
467
|
+
|
|
468
|
+
caller = sys._getframe(1).f_code.co_name
|
|
469
|
+
frame = inspect.stack()[1][0]
|
|
470
|
+
self.get_callerinfo(caller, frame)
|
|
471
|
+
|
|
472
|
+
self._output(idx, level, string)
|
|
473
|
+
|
|
474
|
+
def speak(self, string: str) -> None:
|
|
475
|
+
level = 1
|
|
476
|
+
idx = 1
|
|
477
|
+
|
|
478
|
+
caller = sys._getframe(1).f_code.co_name
|
|
479
|
+
frame = inspect.stack()[1][0]
|
|
480
|
+
self.get_callerinfo(caller, frame)
|
|
481
|
+
|
|
482
|
+
self._output(idx, level, string)
|
|
483
|
+
|
|
484
|
+
info = speak
|
|
485
|
+
|
|
486
|
+
def say(self, string: str) -> None:
|
|
487
|
+
level = -5
|
|
488
|
+
idx = 3
|
|
489
|
+
|
|
490
|
+
caller = sys._getframe(1).f_code.co_name
|
|
491
|
+
frame = inspect.stack()[1][0]
|
|
492
|
+
self.get_callerinfo(caller, frame)
|
|
493
|
+
|
|
494
|
+
self._output(idx, level, string)
|
|
495
|
+
|
|
496
|
+
def warn(self, string: str) -> None:
|
|
497
|
+
"""Show warnings at Runtime (pure user info/warns)."""
|
|
498
|
+
level = 0
|
|
499
|
+
idx = 6
|
|
500
|
+
|
|
501
|
+
if self._showrtwarnings:
|
|
502
|
+
caller = sys._getframe(1).f_code.co_name
|
|
503
|
+
frame = inspect.stack()[1][0]
|
|
504
|
+
self.get_callerinfo(caller, frame)
|
|
505
|
+
|
|
506
|
+
self._output(idx, level, string)
|
|
507
|
+
|
|
508
|
+
warning = warn
|
|
509
|
+
|
|
510
|
+
@staticmethod
|
|
511
|
+
def warndeprecated(string: str) -> None:
|
|
512
|
+
"""Show Deprecation warnings using Python warnings"""
|
|
513
|
+
|
|
514
|
+
warnings.simplefilter("default", DeprecationWarning)
|
|
515
|
+
warnings.warn(string, DeprecationWarning, stacklevel=2)
|
|
516
|
+
|
|
517
|
+
@staticmethod
|
|
518
|
+
def warnuser(string: str) -> None:
|
|
519
|
+
"""Show User warnings, using Python warnings"""
|
|
520
|
+
|
|
521
|
+
warnings.simplefilter("default", UserWarning)
|
|
522
|
+
warnings.warn(string, UserWarning, stacklevel=2)
|
|
523
|
+
|
|
524
|
+
def error(self, string: str) -> None:
|
|
525
|
+
level = -8
|
|
526
|
+
idx = 8
|
|
527
|
+
|
|
528
|
+
caller = sys._getframe(1).f_code.co_name
|
|
529
|
+
frame = inspect.stack()[1][0]
|
|
530
|
+
self.get_callerinfo(caller, frame)
|
|
531
|
+
|
|
532
|
+
self._output(idx, level, string)
|
|
533
|
+
|
|
534
|
+
def critical(self, string: str) -> None:
|
|
535
|
+
level = -9
|
|
536
|
+
idx = 9
|
|
537
|
+
|
|
538
|
+
caller = sys._getframe(1).f_code.co_name
|
|
539
|
+
frame = inspect.stack()[1][0]
|
|
540
|
+
self.get_callerinfo(caller, frame)
|
|
541
|
+
|
|
542
|
+
self._output(idx, level, string)
|
|
543
|
+
|
|
544
|
+
def get_callerinfo(self, caller: Any, frame: Any) -> tuple[Any, str]:
|
|
545
|
+
the_class = self._get_class_from_frame(frame)
|
|
546
|
+
|
|
547
|
+
# just keep the last class element
|
|
548
|
+
x = str(the_class).split(".")
|
|
549
|
+
the_class = x[-1]
|
|
550
|
+
|
|
551
|
+
self._caller = caller
|
|
552
|
+
self._callclass = the_class
|
|
553
|
+
|
|
554
|
+
return (self._caller, self._callclass)
|
|
555
|
+
|
|
556
|
+
# =============================================================================
|
|
557
|
+
# Private routines
|
|
558
|
+
# =============================================================================
|
|
559
|
+
|
|
560
|
+
@staticmethod
|
|
561
|
+
def _get_class_from_frame(fr: Any) -> Any:
|
|
562
|
+
args, _, _, value_dict = inspect.getargvalues(fr)
|
|
563
|
+
|
|
564
|
+
# we check the first parameter for the frame function is
|
|
565
|
+
# named 'self'
|
|
566
|
+
if args and args[0] == "self":
|
|
567
|
+
instance = value_dict.get("self", None)
|
|
568
|
+
if instance:
|
|
569
|
+
# return its class
|
|
570
|
+
return getattr(instance, "__class__", None)
|
|
571
|
+
# return None otherwise
|
|
572
|
+
return None
|
|
573
|
+
|
|
574
|
+
def _output(self, idx: int, level: int, string: str) -> None:
|
|
575
|
+
prefix = ""
|
|
576
|
+
endfix = ""
|
|
577
|
+
|
|
578
|
+
if idx == 0:
|
|
579
|
+
prefix = "++"
|
|
580
|
+
elif idx == 1:
|
|
581
|
+
prefix = "**"
|
|
582
|
+
elif idx == 3:
|
|
583
|
+
prefix = ">>"
|
|
584
|
+
elif idx == 6:
|
|
585
|
+
prefix = WARN + "##"
|
|
586
|
+
endfix = ENDC
|
|
587
|
+
elif idx == 8:
|
|
588
|
+
prefix = ERROR + "!#"
|
|
589
|
+
endfix = ENDC
|
|
590
|
+
elif idx == 9:
|
|
591
|
+
prefix = CRITICAL + "!!"
|
|
592
|
+
endfix = ENDC
|
|
593
|
+
|
|
594
|
+
ulevel = str(level)
|
|
595
|
+
if level == -5:
|
|
596
|
+
ulevel = "M"
|
|
597
|
+
if level == -8:
|
|
598
|
+
ulevel = "E"
|
|
599
|
+
if level == -9:
|
|
600
|
+
ulevel = "W"
|
|
601
|
+
print(
|
|
602
|
+
f"{prefix} <{ulevel}> [{self._callclass:23s}-> "
|
|
603
|
+
f"{self._caller:>33s}] {string}{endfix}"
|
|
604
|
+
)
|