class_docstr:     A parser that scans a file lurking for lines such as the one below.
  
      It then generates a pythran-compatible signature to inject into compile.
  #pythran export a((float,(int, uint8),str list) list list)
  #pythran export a(str)
  #pythran export a( (str,str), int, int16 list list)
  #pythran export a( {str} )
class_docstr_tok: ["A","parser","that","scans","a","file","lurking","for","lines","such","as","the","one","below",".","It","then","generates","a","pythran-compatible","signature","to","inject","into","compile",".","#","pythran","export","a","(","(","float",",","(","int",",","uint8",")",",","str","list",")","list","list",")","#","pythran","export","a","(","str",")","#","pythran","export","a","(","(","str",",","str",")",",","int",",","int16","list","list",")","#","pythran","export","a","(","{","str","}",")"]
code: def __call__(self, text, input_file=None):
      self.exports = defaultdict(tuple)
      self.native_exports = defaultdict(tuple)
      self.export_info = defaultdict(tuple)
      self.input_text = text
      self.input_file = input_file
  
      lines = []
      in_pythran_export = False
      for line in text.split("\n"):
          if re.match(r"\s*#\s*pythran", line):
              in_pythran_export = True
              lines.append(re.sub(r"\s*#\s*pythran", "#pythran", line))
          elif in_pythran_export:
              stripped = line.strip()
              if stripped.startswith("#"):
                  lines.append(line.replace("#", ""))
              else:
                  in_pythran_export = not stripped
                  lines.append("")
          else:
              in_pythran_export &= not line.strip()
              lines.append("")
  
      pythran_data = "\n".join(lines)
      self.parser.parse(pythran_data, lexer=self.lexer, debug=False)
  
      for key, overloads in self.native_exports.items():
          if len(overloads) > 1:
              msg = "Overloads not supported for capsule '{}'".format(
                  key
              )
              loc = self.export_info[key][-1]
              raise self.PythranSpecError(msg, loc)
          self.native_exports[key] = overloads[0]
  
      for key, overloads in self.exports.items():
          if len(overloads) > cfg.getint(
              "typing", "max_export_overloads"
          ):
              raise self.PythranSpecError(
                  "Too many overloads for function '{}', probably due to "
                  "automatic generation of C-style and Fortran-style memory "
                  "layout. Please force a layout using `order(C)` or "
                  "`order(F)` in the array signature".format(key)
              )
  
          for i, ty_i in enumerate(overloads):
              sty_i = spec_to_string(key, ty_i)
              for ty_j in overloads[i + 1 :]:
                  sty_j = spec_to_string(key, ty_j)
                  if sty_i == sty_j:
                      msg = "Duplicate export entry {}.".format(sty_i)
                      loc = self.export_info[key][-1]
                      raise self.PythranSpecError(msg, loc)
                  if ambiguous_types(ty_i, ty_j):
                      msg = "Ambiguous overloads\n\t{}\n\t{}.".format(
                          sty_i, sty_j
                      )
                      loc = self.export_info[key][i]
                      raise self.PythranSpecError(msg, loc)
  
      return Spec(self.exports, self.native_exports)
  
imports: from pythran.types.conversion import pytype_to_pretty_type
  from collections import defaultdict
  from itertools import product
  import re
  import ply.lex
  import ply.yacc
  from pythran.typing import List, Set, Dict, NDArray, Tuple, Pointer, Fun
  from pythran.syntax import PythranSyntaxError
  from pythran.config import cfg
label_desc: Use image node_id 26 for calling the SpecParser obj's underlying member method code with example usage: obj.__call__(text, input_file) and returns: Spec