88import pathlib
99import shlex
1010from types import TracebackType
11- from typing import Literal , Protocol , Self , TextIO , cast
11+ from typing import Literal , Protocol , Self , TextIO , cast , runtime_checkable
1212import uuid
1313import re
1414import warnings
@@ -86,10 +86,25 @@ def prev(self) -> Self:
8686 ...
8787
8888
89+ @runtime_checkable
90+ class PBufPosition (Protocol ):
91+ @property
92+ def line_number (self ) -> int :
93+ """Current line number."""
94+ ...
95+
96+ @property
97+ def current_file (self ) -> pathlib .Path :
98+ """Current file."""
99+ ...
100+
101+
89102def _load_string (
90103 keyword_spec : SpecificationType | None , buf : PReadBuf
91104) -> str | pd .Timestamp :
105+ start_line = buf .line_number if isinstance (buf , PBufPosition ) else None
92106 line = next (buf )
107+
93108 if "'" in line :
94109 split = re .split (r"'(.*)'" , line )
95110 elif '"' in line :
@@ -113,7 +128,11 @@ def _load_string(
113128 val = line
114129 line = next (buf )
115130 if not line .startswith ('/' ):
116- warnings .warn ('Data was not properly terminated.' )
131+ warnings .warn (
132+ _format_warning_messsage (
133+ 'Data was not properly terminated.' , start_line , buf
134+ )
135+ )
117136 _ = buf .prev ()
118137 val = re .sub (r'"(.*?)"' , r'\1' , val )
119138 val = re .sub (r'\'(.*?)\'' , r'\1' , val )
@@ -682,6 +701,7 @@ def _load_statement_list(keyword_spec: SpecificationType, buf: PReadBuf):
682701
683702
684703def _load_no_data (keyword_spec : SpecificationType | None , buf : PReadBuf ):
704+ start_line = buf .line_number if isinstance (buf , PBufPosition ) else None
685705 if keyword_spec is None :
686706 return None
687707 if not isinstance (keyword_spec , NoDataSpecification ):
@@ -692,7 +712,11 @@ def _load_no_data(keyword_spec: SpecificationType | None, buf: PReadBuf):
692712 return None
693713 line = next (buf )
694714 if not line .startswith ('/' ):
695- raise ValueError ('Data is not properly terminated.' )
715+ raise ValueError (
716+ _format_warning_messsage (
717+ 'Data is not properly terminated.' , start_line , buf
718+ )
719+ )
696720 return None
697721
698722
@@ -728,6 +752,14 @@ def _load_no_data(keyword_spec: SpecificationType | None, buf: PReadBuf):
728752}
729753
730754
755+ def _format_warning_messsage (message : str , start_line : int | None , buf : PReadBuf ):
756+ if not isinstance (buf , PBufPosition ):
757+ return message
758+ if start_line is None :
759+ warnings .warn ('`start_line` is None. Return original message.' )
760+ return ' ' .join ((message , f'{ buf .current_file } { start_line } :{ buf .line_number } ' ))
761+
762+
731763class StringIteratorIO :
732764 """String iterator for text files."""
733765
@@ -1001,9 +1033,16 @@ def load(
10011033 logger .info (
10021034 f'Start reading keyword { firstword } : line { lines .line_number } .'
10031035 )
1004- data = LOADERS [keyword_spec .type ](
1005- keyword_spec .specification , lines , res
1006- )
1036+ with warnings .catch_warnings (record = True ) as captured :
1037+ warnings .simplefilter ('always' )
1038+
1039+ data = LOADERS [keyword_spec .type ](
1040+ keyword_spec .specification , lines , res
1041+ )
1042+ for w in captured :
1043+ warnings .warn (
1044+ f'While reading keyword { firstword } : ' + str (w .message )
1045+ )
10071046 if cur_section not in res :
10081047 res [cur_section ] = []
10091048 res [cur_section ].append ((firstword , data ))
0 commit comments