19
19
import enum
20
20
import inspect
21
21
import os
22
+ import pathlib
22
23
import posixpath
23
24
import pprint
24
25
import re
@@ -601,26 +602,25 @@ def get_defined_in(
601
602
base_dirs_and_prefixes = zip (parser_config .base_dir ,
602
603
parser_config .code_url_prefix )
603
604
try :
604
- obj_path = inspect .getfile (_unwrap_obj (py_object ))
605
+ obj_path = pathlib . Path ( inspect .getfile (_unwrap_obj (py_object ) ))
605
606
except TypeError : # getfile throws TypeError if py_object is a builtin.
606
607
return None
607
608
608
- if not obj_path .endswith (( '.py' , '.pyc' ) ):
609
+ if obj_path .suffix not in ( '.py' , '.pyc' ):
609
610
return None
610
611
611
612
code_url_prefix = None
612
613
for base_dir , temp_prefix in base_dirs_and_prefixes :
613
- rel_path = os .path .relpath (path = obj_path , start = base_dir )
614
- # A leading ".." indicates that the file is not inside `base_dir`, and
615
- # the search should continue.
616
- if rel_path .startswith ('..' ):
614
+ try :
615
+ rel_path = obj_path .relative_to (base_dir )
616
+ except ValueError :
617
617
continue
618
- else :
619
- code_url_prefix = temp_prefix
620
- # rel_path is currently a platform-specific path, so we need to convert
621
- # it to a posix path (for lack of a URL path).
622
- rel_path = posixpath . join ( * rel_path . split ( os . path . sep ))
623
- break
618
+
619
+ code_url_prefix = temp_prefix
620
+ # rel_path is currently a platform-specific path, so we need to convert
621
+ # it to a posix path (for lack of a URL path).
622
+ posix_rel_path_str = str ( pathlib . PurePosixPath ( rel_path ))
623
+ break
624
624
625
625
# No link if the file was not found in a `base_dir`, or the prefix is None.
626
626
if code_url_prefix is None :
@@ -637,30 +637,31 @@ def get_defined_in(
637
637
end_line = None
638
638
639
639
# In case this is compiled, point to the original
640
- if rel_path .endswith ('.pyc' ):
640
+ if posix_rel_path_str .endswith ('.pyc' ):
641
641
# If a PY3 __pycache__/ subdir is being used, omit it.
642
- rel_path = rel_path .replace ('__pycache__' + os . sep , '' )
642
+ posix_rel_path_str = posix_rel_path_str .replace ('__pycache__/' , '' )
643
643
# Strip everything after the first . so that variants such as .pyc and
644
644
# .cpython-3x.pyc or similar are all handled.
645
- rel_path = rel_path .partition ('.' )[0 ] + '.py'
645
+ posix_rel_path_str = posix_rel_path_str .partition ('.' )[0 ] + '.py'
646
646
647
- if re .search (r'<[\w\s]+>' , rel_path ):
647
+ if re .search (r'<[\w\s]+>' , posix_rel_path_str ):
648
648
# Built-ins emit paths like <embedded stdlib>, <string>, etc.
649
649
return None
650
- if '<attrs generated' in rel_path :
650
+ if '<attrs generated' in posix_rel_path_str :
651
651
return None
652
652
653
- if re .match (r'.*/gen_[^/]*\.py$' , rel_path ):
653
+ if re .match (r'.*/gen_[^/]*\.py$' , posix_rel_path_str ):
654
654
return FileLocation ()
655
- if 'genfiles' in rel_path :
655
+ if 'genfiles' in posix_rel_path_str :
656
656
return FileLocation ()
657
- elif re . match ( r'.* _pb2\ .py$' , rel_path ):
657
+ elif posix_rel_path_str . endswith ( ' _pb2.py' ):
658
658
# The _pb2.py files all appear right next to their defining .proto file.
659
- rel_path = rel_path [:- 7 ] + '.proto'
660
- return FileLocation (base_url = posixpath .join (code_url_prefix , rel_path ))
659
+ posix_rel_path_str = posix_rel_path_str [:- 7 ] + '.proto'
660
+ return FileLocation (
661
+ base_url = posixpath .join (code_url_prefix , posix_rel_path_str ))
661
662
else :
662
663
return FileLocation (
663
- base_url = posixpath .join (code_url_prefix , rel_path ),
664
+ base_url = posixpath .join (code_url_prefix , posix_rel_path_str ),
664
665
start_line = start_line ,
665
666
end_line = end_line )
666
667
0 commit comments