ó
    /j-jöR  ã                   ó°   • S r SSKrSSKrSSKJr  SSKJr  SSKJr  SSKJ	r	  SSK
Jr  SS	K
Jr  SS
K
Jr  SrSS jrS rS r         SS\4S jjrS rg)zBIO related functions to Read the PDF and returns extracted tables.é    N)ÚAnyé   )Ú	TableList)ÚFilepathOrBuffer)Ú
PDFHandler)ÚTemporaryDirectory)Úremove_extra)Úvalidate_inputé   c                 ól  ^ ^^
^^• SSK Jm
  SSKJm  SSKJm  U
UU UU4S jn Uc:  [        5        nU" [        R                  R                  US5      5      nSSS5        O	U" U5      n Wc  gUu  pxU[        :¬  =(       a	    U[        :¬  n	U	(       a  S	$ S$ ! , (       d  f       N:= f! [         a     gf = f)
u¥  Pick the most appropriate flavor for a single PDF page.

Renders ``page``, thresholds it, and counts ruled horizontal and
vertical line segments. Used when the caller passes ``flavor="auto"``
(once per requested page, so a document with text-only cover pages and
ruled tables deeper in is routed correctly per page).

Returns
-------
str
    Either ``"lattice"`` (enough ruled lines on the rendered page) or
    ``"network"`` (else). ``"network"`` is also the fallback when
    rendering itself fails (e.g. unreadable PDF, missing backend
    dependencies) â€” the assumption is that giving the text-based parser
    a chance is more useful than raising before parsing starts.
r   )ÚImageConversionBackend)Úadaptive_threshold)Ú
find_linesc                 óò   >• T" 5       R                  [        T5      U T	S9  [        R                  R	                  U 5      (       d  g T" U SS9u  pT" USSS9u  pT" USSS9u  p[        U5      [        U5      4$ )N)ÚpageF)Úprocess_backgroundÚverticalé   )Ú	directionÚ
line_scaleÚ
horizontal)ÚconvertÚstrÚosÚpathÚexistsÚlen)
Ú
target_pngÚ_Ú	thresholdÚvÚhr   r   Úfilepathr   r   s
        €€€€€ÚG/home/mande/repo/quber/.venv/lib/python3.13/site-packages/camelot/io.pyÚ_probeÚ_detect_flavor.<locals>._probe.   sy   ø€ ñ
 	Ó ×(Ñ(¬¨X«¸
ÈÐ(ÑNÜ�w‰w�~‰~˜j×)Ñ)ØÙ)¨*ÈÑO‰ˆñ ˜)¨zÀbÑI‰ˆÙ˜)¨|ÈÑK‰ˆÜ�1‹v”s˜1“vˆ~Ðó    Nzauto_flavor_probe.pngÚnetworkÚlattice)Úbackendsr   Úimage_processingr   r   r   r   r   ÚjoinÚ	ExceptionÚ_AUTO_FLAVOR_LINE_THRESHOLD)r#   Úpasswordr   Úpng_pathr%   ÚtmpdirÚcountsÚv_countÚh_countÚhas_gridr   r   r   s   ` `       @@@r$   Ú_detect_flavorr6      s´   ü€ õ( 1Ý4Ý,÷ñ ðØÑä#Ô%¨Ù¤§¡§¡¨VÐ5LÓ MÓN�÷ &Ð%ñ
 ˜HÓ%‰Fð �~ØØÑ€GàÔ.Ñ.÷ 	3ØÔ2Ñ2ð ö !ˆ9Ð/ iÐ/÷) &Õ%ûô ó ñ
 ðús4   £B& °'BÁB& Á B& Â
B#ÂB& Â#B& Â&
B3Â2B3c           	      ó<  • U c  0 $ 0 nU R                  5        HX  u  p# [        U5      n[	        U[
        5      (       d%  [        SU< S[        U5      R                   35      e[        U5      X'   MZ     U$ ! [        [        4 a  n[        SU< 35      UeSnAff = f)aB  Coerce ``per_page`` to ``{int: dict}`` form, raising ValueError on bad input.

Accepts None / empty (returns ``{}``), int or str keys, and dict
values. Other shapes raise ``ValueError`` with a precise message
naming the offending entry. Values are shallow-copied so a later
in-place edit doesn't mutate the caller's dict.
Nz(per_page keys must be page numbers, got ú	per_page[z ] must be a dict of kwargs, got )ÚitemsÚintÚ	TypeErrorÚ
ValueErrorÚ
isinstanceÚdictÚtypeÚ__name__)Úper_pageÚper_page_normÚkr!   Úpage_noÚexcs         r$   Ú_normalize_per_pagerF   W   s³   € ð ÑØˆ	Ø/1€MØ—‘Ö ‰ˆð	XÜ˜!“fˆGô ˜!œT×"Ñ"ÜØ˜A™5Ð @ÄÀaÃ×AQÑAQÐ@RÐSóð ô "& a£ˆÓñ !ð Ðøô œ:Ð&ó 	XÜÐGÈÁuÐMÓNÐTWÐWûð	Xús   žA6Á6BÂBÂBc                 ó  • U R                  5        He  u  p#UR                  SU5      nUS;  a  [        SU SU< S35      eUR                  5        VVs0 s H  u  pVUS:w  d  M  XV_M     nnn[        XtS9  Mg     gs  snnf )uQ  Validate each per-page override against its effective flavor.

Each entry's flavor is either an explicit override (must be one of
the four concrete flavors â€” ``"auto"`` doesn't make sense
page-by-page) or the global flavor. All non-flavor kwargs are then
checked with the existing :func:`validate_input` against that
effective flavor.
Úflavor)r)   Ústreamr(   ÚhybridÚmlr8   z	] flavor=zl is not one of: 'lattice', 'stream', 'network', 'hybrid', 'ml'. ('auto' is only valid as the global flavor.)©rH   N)r9   ÚgetÚNotImplementedErrorr
   )rB   Úglobal_flavorrD   Ú	overridesÚpage_flavorrC   r!   Úpage_kwargss           r$   Ú_validate_per_pagerS   o   s’   € ð ,×1Ñ1Ö3ÑˆØ—m‘m H¨mÓ<ˆØÐNÓNÜ%Ø˜G˜9 I¨k©_ð =@ð @óð ð
 )2¯©Ô(9ÔKÒ(9¡ ¸QÀ(¹]“t�q’tÑ(9ˆÑKÜ�{Ô7ò 4ùó Ls   ÁA;Á$A;r#   c
                 óä  • Uc  0 nUS;  a  [        S5      e[        U5      n[        R                  " 5          U(       a  [        R                  " S5        [        XX)S9 nUS:X  a!  [        UU
UUUUUS9sSSS5        sSSS5        $ [        X£S9  [        X£S9n
[        X³5        UR                  " S
UUUUUUS	.U
D6nSSS5        WsSSS5        $ ! , (       d  f       N= f! , (       d  f       g= f)uÎ(  Read PDF and return extracted tables.

Note: kwargs annotated with ^ can only be used with flavor='stream' or flavor='network'
and kwargs annotated with * can only be used with flavor='lattice'.
The hybrid parser accepts kwargs with both annotations.

Parameters
----------
filepath : str, Path, bytes, or binary file-like
    Source PDF. Accepts a filesystem path / URL, a ``bytes``-like
    object, or any binary stream with a ``.read()`` method
    (``io.BytesIO``, an open ``"rb"`` file, ``requests`` response
    ``.raw``, etc). For in-memory inputs the bytes are spilled to
    a temporary file once and cleaned up on context-manager exit,
    so the Lattice OpenCV image-conversion backend keeps working
    unchanged. Originally requested in #170 / #245 / #270.
pages : str, optional (default: '1')
    Comma-separated page numbers.
    Example: '1,3,4' or '1,4-end' or 'all'.
password : str, optional (default: None)
    Password for decryption.
flavor : str (default: 'lattice')
    The parsing method to use. Valid values:

    - ``'lattice'`` (default): line-ruled tables.
    - ``'stream'``: borderless tables with whitespace-separated columns.
    - ``'network'``: borderless tables via text-edge alignment connectivity.
    - ``'hybrid'``: combines layout- and image-based analysis.
    - ``'ml'``: neural table-structure recognition (Table Transformer)
      for the structure, with cell text filled from the PDF's own text
      layer (no hallucinated values). Requires the optional ML
      dependencies: ``pip install 'camelot-py[ml]'``. Best for
      borderless tables where the heuristic parsers plateau.
    - ``'auto'``: detect the flavor **per page** (count ruled lines on
      each rendered page) and parse each group accordingly â€” ruled
      pages via ``lattice`` with ``engine='combined'``, the rest via
      ``network`` â€” then merge. Handles documents that mix text-only
      cover pages with ruled tables deeper in. A ``UserWarning`` reports
      the per-page choices. (More accurate but slower, since it renders
      every page for the probe.)
suppress_stdout : bool, optional (default: False)
    Print all logs and warnings.
parallel : bool, optional (default: False)
    Process pages in parallel using all available cpu cores.
cpu_count : int, optional (default: None)
    Maximum number of worker processes when ``parallel=True``. ``None``
    (default) uses all available cores. Values are clamped to
    ``[1, multiprocessing.cpu_count()]``. Ignored when
    ``parallel=False``.
layout_kwargs : dict, optional (default: {})
    A dict of `pdfminer.layout.LAParams
    <https://pdfminersix.readthedocs.io/en/latest/reference/composable.html#laparams>`_ kwargs.
per_page : dict, optional (default: None)
    Per-page parameter overrides. Maps a 1-indexed page number (int
    or str) to a dict of any keyword argument otherwise valid for
    ``read_pdf``. Values supplied here override the globally-supplied
    kwargs for that one page only â€” every other page keeps the global
    values. Useful for multi-layout PDFs where different pages need
    different ``table_areas``, ``columns``, ``flavor``, etc. The
    per-page ``flavor`` itself may be overridden; the global flavor
    applies otherwise. Originally proposed by @sverma25 in #41.

    Example::

        tables = camelot.read_pdf(
            "report.pdf",
            pages="1-3",
            flavor="stream",
            split_text=True,
            per_page={2: {"table_areas": ["120, 210, 400, 90"]}},
        )

    Here pages 1 and 3 use the global ``flavor="stream", split_text=True``
    only; page 2 uses both *and* the page-specific ``table_areas``.
table_areas : list, optional (default: None)
    List of table area strings of the form x1,y1,x2,y2
    where (x1, y1) -> left-top and (x2, y2) -> right-bottom
    in PDF coordinate space.
columns^ : list, optional (default: None)
    List of column x-coordinates strings where the coordinates
    are comma-separated.
split_text : bool, optional (default: False)
    Split text that spans across multiple cells.
flag_size : bool, optional (default: False)
    Flag text based on font size. Useful to detect
    super/subscripts. Adds <s></s> around flagged text.
strip_text : str or sequence of str, optional (default: '')
    Characters or substrings to strip from each cell before
    assignment. A ``str`` strips per-character â€” every character in
    the string is removed wherever it appears (e.g. ``" \n"`` drops
    all spaces and newlines). A list/tuple of ``str`` strips whole
    substrings (e.g. ``["[1]", "[2]"]`` removes those footnote
    markers but leaves bare ``[``/``]`` alone). Whole-substring
    mode requested in #484.
replace_text : dict, optional (default: None)
    Mapping of substring â†’ replacement applied to every cell's
    text just before it is written into the table. Keys are
    matched as literal substrings (regex metacharacters are
    escaped). Useful for collapsing soft-broken words (e.g.
    ``{" \n": " "}``), normalising abbreviations, or rewriting
    unit names. Distinct from ``strip_text`` which can only
    remove characters; this can replace with arbitrary text.
    Requested in #481. (#482)
row_tol^ : int, optional (default: 2)
    Tolerance parameter used to combine text vertically,
    to generate rows.
column_tol^ : int, optional (default: 0)
    Tolerance parameter used to combine text horizontally,
    to generate columns.
process_background* : bool, optional (default: False)
    Process background lines.
line_scale* : int, optional (default: 15)
    Line size scaling factor. The larger the value the smaller
    the detected lines. Making it very large will lead to text
    being detected as lines.
copy_text* : list, optional (default: None)
    {'h', 'v'}
    Direction in which text in a spanning cell will be copied
    over.
shift_text* : list, optional (default: ['l', 't'])
    {'l', 'r', 't', 'b'}
    Direction in which text in a spanning cell will flow.
line_tol* : int, optional (default: 2)
    Tolerance parameter used to merge close vertical and horizontal
    lines.
joint_tol* : int, optional (default: 2)
    Tolerance parameter used to decide whether the detected lines
    and points lie close to each other.
threshold_blocksize* : int, optional (default: 15)
    Size of a pixel neighborhood that is used to calculate a
    threshold value for the pixel: 3, 5, 7, and so on.

    For more information, refer `OpenCV's adaptiveThreshold
    <https://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html#adaptivethreshold>`_.
threshold_constant* : int, optional (default: -2)
    Constant subtracted from the mean or weighted mean.
    Normally, it is positive but may be zero or negative as well.

    For more information, refer `OpenCV's adaptiveThreshold
    <https://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html#adaptivethreshold>`_.
iterations* : int, optional (default: 0)
    Number of dilation passes applied to close small gaps in the
    line mask.

    For more information, refer `OpenCV's dilate
    <https://docs.opencv.org/2.4/modules/imgproc/doc/filtering.html#dilate>`_.
erode_iterations* : int, optional (default: 0)
    Number of erosion passes applied **after** dilation. Set equal
    to ``iterations`` for a morphological closing â€” bridges gaps
    in ruled lines without thickening the mask overall (which
    avoids the spurious extra-row artefact reported in #363). (#363)
backend* : str, optional by default "pdfium"
    The backend to use for converting the PDF to an image so it can be processed by OpenCV.
use_fallback* : bool, optional
    Fallback to another backend if unavailable, by default True
resolution* : int, optional (default: 300)
    Resolution used for PDF to PNG conversion.
engine* : str, optional (default: 'combined')
    Line-detection engine for ``flavor='lattice'`` (and the lattice
    half of ``flavor='hybrid'``):

    - ``'combined'`` (default): render the page and detect ruled lines
      with OpenCV **and** union in the ruled lines read from the PDF's
      native vector graphics, so tables whose rules render faintly
      (vector strokes, anti-aliasing) are still found. Safe by
      construction â€” raster always runs, vector lines can only add, and
      they're clipped to ``table_regions`` â€” so it never does worse
      than ``'raster'`` (#763).
    - ``'raster'``: render the page and detect ruled lines with OpenCV
      only â€” the pre-#763 behaviour.
    - ``'vector'``: detect tables straight from the PDF's vector ruled
      lines, skipping rasterisation entirely â€” the fastest path, for
      PDFs whose tables are drawn with real vector strokes (#763).

    With ``flavor='hybrid'`` the same choices select how its lattice
    half finds ruled lines; ``engine='vector'`` there is the
    **render-free hybrid** â€” vector ruled lines merged with the network
    text-edge alignment â€” for partial-ruled / borderless tables at
    roughly an order of magnitude less time than the raster path (#39).

Returns
-------
tables : camelot.core.TableList

Notes
-----
**Encrypted PDFs / extraction permissions** (#590). Camelot honours the
``/Encrypt`` dictionary's text-extraction permission: ``read_pdf`` raises
:class:`playa.exceptions.PDFTextExtractionNotAllowed` if the PDF is
encrypted and the user-password permission set forbids text extraction.
The check fires on the document object returned by ``playa.open`` while
the encryption metadata is still attached â€” this is a real behavioural
change vs the pre-1.0 backend, where per-page temp-PDF splitting
silently dropped the metadata so the check was effectively a no-op.
Note: PDF spec only enforces the flag through the encryption layer â€”
for **unencrypted** PDFs that carry a "no extraction" claim via
``/Perms``, there is no enforcement mechanism and Camelot extracts.
Supplying the document owner password through ``password=`` bypasses
the user-password permission set (matches every other PDF tool).

Examples
--------
>>> import camelot
>>> tables = camelot.read_pdf("foo.pdf")  # xdoctest: +SKIP
>>> tables.n  # xdoctest: +SKIP
1
>>> tables[0].df  # xdoctest: +SKIP
>>> tables[0].to_csv("foo.csv")  # xdoctest: +SKIP

Select a parser and restrict extraction to a page range:

>>> tables = camelot.read_pdf(  # xdoctest: +SKIP
...     "foo.pdf", flavor="lattice", pages="1-3"
... )

N)r)   rI   r(   rJ   rK   Úautoz]Unknown flavor specified. Use either 'lattice', 'stream', 'network', 'hybrid', 'ml' or 'auto'Úignore)Úpagesr/   ÚdebugrU   )Úsuppress_stdoutÚparallelÚ	cpu_countÚlayout_kwargsrB   rL   )rH   rY   rZ   r[   r\   rA   © )rN   rF   ÚwarningsÚcatch_warningsÚsimplefilterr   Ú_parse_autor
   r	   rS   Úparse)r#   rW   r/   rH   rY   rZ   r[   r\   rA   rX   ÚkwargsrB   ÚpÚtabless                 r$   Úread_pdfrf   „   s	  € ðJ ÑØˆØÐMÓMÜ!ðSó
ð 	
ô
 (¨Ó1€Mä	×	 Ò	 Õ	"ÞÜ×!Ò! (Ô+ä˜¸ÒNÐRSØ˜ÓÜ"ØØØ$3Ø%Ø'Ø"/Ø"/ñ÷ OÐN÷	 
#Ñ	"ô ˜6Ò1Ü! &Ñ8ˆFä˜}Ô5à—W’Wð ØØ /Ø!Ø#Ø+Ø&ñð ñˆF÷! Oð2 ÷; 
#Ñ	"÷ OÕNú÷	 
#Õ	"ús/   ·(C!ÁCÁ4	C!Â6CÂ=	C!Ã
C	ÃC!Ã!
C/c                ó2  ^• [        5        n0 n0 n	U R                   H†  n
[        R                  R	                  USU
 S35      n[        U R                  U R                  =(       d    SU
US9mTXŠ'   TS:X  d  M\  [        R                  R                  U5      (       d  M‚  X¹U
'   Mˆ     [        R                  " SU 3[        SS9  / nS	 H˜  m[        U4S
 jUR                  5        5       5      nU(       d  M/  [        [        U5      TS9nTS:X  a  UR!                  SS5        [#        UT5        UR%                  U R&                  " STUUUUUUTS:X  a  U	OSS.UD65        Mš     UR)                  S S9  [+        U5      sSSS5        $ ! , (       d  f       g= f)uw  Parse with ``flavor='auto'`` â€” flavor detected **per page**.

Each requested page is probed independently (so a document with a
text-only cover and ruled tables deeper in is routed correctly), then
pages are grouped by detected flavor and parsed in one pass per group:
ruled pages via ``lattice`` with ``engine='combined'`` (the most
accurate detector), the rest via ``network``. Results are merged into a
single page/order-sorted :class:`~camelot.core.TableList`.

The page rendered for each lattice page's probe is kept and handed to
the parser via ``render_cache``, so that page isn't rasterised a second
time during parsing.
zauto-probe-page-z.pngN)r/   r   r0   r)   z1camelot.read_pdf: auto-detected per-page flavors é   )Ú
stacklevel)r)   r(   c              3   ó<   >#   • U  H  u  pUT:X  d  M  Uv •  M     g 7f©Nr]   )Ú.0ÚpgÚfÚfls      €r$   Ú	<genexpr>Ú_parse_auto.<locals>.<genexpr>À  s   øé € Ð PÒ1D©¨ÈÈRÉ§¡Ò1Dùs   ƒ“	rL   ÚengineÚcombined)rH   rY   rZ   r[   r\   rA   rW   Úrender_cachec                 ó2   • U R                   U R                  4$ rk   )r   Úorder)Úts    r$   Ú<lambda>Ú_parse_auto.<locals>.<lambda>×  s   €  a§f¡f¨a¯g©gÑ%6r'   )Úkeyr]   )r   rW   r   r   r,   r6   r#   r/   r   r^   ÚwarnÚUserWarningÚsortedr9   r	   r>   Ú
setdefaultrS   Úextendrb   Úsortr   )Úhandlerrc   rY   rZ   r[   r\   rB   Ú	cache_dirrQ   rt   rm   Ú	probe_pngÚ	collectedÚgroup_pagesÚgroup_kwargsro   s                  @r$   ra   ra   “  s„  ø€ ô. 
Ô	 ØˆØ')ˆØ—-”-ˆBÜŸ™Ÿ™ YÐ2BÀ2À$ÀdÐ0KÓLˆIÜØ× Ñ Ø ×)Ñ)×1¨TØØ"ñ	ˆBð !ˆK‰OØ�Y�¤2§7¡7§>¡>°)×#<Ó#<Ø#,˜RÓ ñ  ô 	�ŠØ?À¸}ÐMÜØò	
ð ˆ	Û(ˆBÜ Ô P°×1BÑ1BÔ1DÓ PÓPˆKÞÙÜ'¬¨V«¸RÑ@ˆLØ�Y‹ð ×'Ñ'¨°*Ô=Ü˜}¨bÔ1Ø×ÑØ—’ð 
ØØ$3Ø%Ø'Ø"/Ø*Ø%Ø13°y³¡Àdñ
ð #ñ
öñ )ð0 	�‰Ñ6ˆÑ7Ü˜Ó#÷] 
×	×	ús   ŒA)FÁ9"FÂCFÆ
F)Nr   N)	Ú1Nr)   FFNNNF)Ú__doc__r   r^   Útypingr   Úcorer   Úhandlersr   r   Úutilsr   r	   r
   r.   r6   rF   rS   rf   ra   r]   r'   r$   Ú<module>r�      sn   ðÙ Hã 	Û Ý å Ý &Ý  Ý %Ý Ý !ð  Ð ô>0òBò08ð. ØØØØØØØØ
ñLØõLó^E$r'   