ó
    �2¨j<  ã                  ó:  • S r SSKJr  SSKrSSKrSSKrSSKrSSKrSSKrSSK	r	SSK
r
\R                  " \5      R                  R                  r\S-  r\S-  r\S-  S-  r\R$                  " S5      r\R$                  " S5      r\R$                  " S	5      r\R$                  " S
5      rSr\R0                  " \5      r      SS jrSS jrSSS jjr      SS jrSS jr      SS jr SS jr!\S:X  a"  \RD                  " \RF                  S9  \" 5         gg)aP  Command-line interface for the ``portalocker`` package.

Invoked as ``python -m portalocker``. The only subcommand is `combine`,
which bundles the package into a single vendorable ``portalocker.py``
file; see `combine` for what that transform does and why it exists.

Every file this module reads while doing that -- the package's own
modules, ``README.md`` and ``LICENSE`` -- is opened with
``encoding='ascii'`` (see `_read_file` and `combine`). That means the
entire ``portalocker`` source tree, plus ``README.md`` and ``LICENSE``,
must stay ASCII-only: a non-ASCII character in any of them makes this
module raise `UnicodeDecodeError` instead of silently mis-decoding it.
``portalocker_tests/test_combined.py`` asserts the combined output can
still be produced, which is how a stray non-ASCII character elsewhere in
the package would be caught.
é    )ÚannotationsNÚportalockerÚdistzportalocker.pyz(?P<names>[^()]+)$z=^from \.(?P<from>.*?) import (?P<paren>\(?)(?P<names>[^()]+)$z^(?P<name>\w+) = \1\n$z!if (?:typing\.)?TYPE_CHECKING\s*:z'''
{}
'''

c                ó˜   • UR                   u  p#pEnSnU[        XG-
  S5      XW-    n[        R                  SU  SU SU SU SU< 3
5        g)	a  Log a snippet of `path` around the bytes that failed to decode.

Shared by every ASCII read in this module (see `_read_text_ascii`),
so a stray non-ASCII byte in a source file, ``README.md`` or
``LICENSE`` always produces an error naming the offending file and
showing the surrounding context instead of a bare traceback.

Args:
    path: The file that failed to decode, named in the log message.
    exception: The decode failure. Its ``args`` carry the undecoded
        bytes and the offset range of the offending byte(s).
éd   r   zInvalid encoding for z: z
 at byte (Ú:z)
Snippet: N)ÚargsÚmaxÚloggerÚerror)	ÚpathÚ	exceptionÚ_ÚtextÚ
start_byteÚend_byter   ÚoffsetÚsnippets	            Ú¢C:\Users\johnn\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\portalocker/__main__.pyÚ_log_decode_errorr   2   sj   € ð  ,5¯>©>Ñ(€AˆZ 5à€FØ”3�zÑ*¨AÓ.°Ñ1BÐC€GÜ
‡L�LØ
 ˜v R¨ wð /Øˆ<�q˜˜
ð #Ø‘;ð	 õó    c                óÀ   •  U R                  SS9$ ! [         a  n[        X5        e SnAf[         a)  n[        R                  SU  35        [        S5      UeSnAff = f)a%  Read `path` as ASCII, logging a clear error on failure.

Args:
    path: The file to read.

Returns:
    The file's text, decoded as ASCII with universal newlines.

Raises:
    UnicodeDecodeError: `path` contains a byte that is not valid
        ASCII. The offending snippet is logged through
        `_log_decode_error` before this is re-raised.
    SystemExit: `path` does not exist. The missing file is named in
        a logged error and the exit status is 1, instead of the raw
        ``FileNotFoundError`` traceback the CLI used to die with.
Úascii)ÚencodingNzInput file not found: é   )Ú	read_textÚUnicodeDecodeErrorr   ÚFileNotFoundErrorr   r   Ú
SystemExit)r   r   s     r   Ú_read_text_asciir    M   s\   € ð"+Ø�~‰~ wˆ~Ð/Ð/øÜó Ü˜$Ô*ØûÜó +Ü�‰Ð-¨d¨VÐ4Ô5Ü˜‹m Ð*ûð+ús   ‚ ‘
A›'§A´$AÁAc                ó  • [         R                  " 5       nUR                  SS9nUR                  SSS9nUR	                  SS[
        R                  [        S9  UR                  [        S	9  UR                  U 5      nUR                  U5        g
)aÎ  Parse CLI arguments and dispatch to the selected subcommand.

Currently the only subcommand is ``combine`` (see `combine`).

Args:
    argv: Argument vector to parse, excluding the program name.
        Forwarded to `argparse.ArgumentParser.parse_args`, so it
        defaults to `sys.argv[1:]` when `None`. Tests pass an
        explicit list, e.g. ``['combine', '--output-file', ...]``,
        instead of relying on `sys.argv`.

Raises:
    SystemExit: Argument parsing failed, or no subcommand was
        given -- the ``combine`` subparser is marked required.

Example:
    .. code-block:: console

        $ python -m portalocker combine
        $ python -m portalocker combine --output-file dist/portalocker.py
T)ÚrequiredÚcombinezZCombine all Python files into a single unified `portalocker.py` file for easy distribution)Úhelpz--output-filez-o)ÚtypeÚdefault)ÚfuncN)ÚargparseÚArgumentParserÚadd_subparsersÚ
add_parserÚadd_argumentÚpathlibÚPathÚ_default_output_pathÚset_defaultsr#   Ú
parse_argsr'   )ÚargvÚparserÚ
subparsersÚcombine_parserr	   s        r   Úmainr6   h   s•   € ô, ×$Ò$Ó&€Fà×&Ñ&°Ð&Ð5€JØ×*Ñ*Øð%ð +ð €Nð
 ×ÑØØÜ�\‰\Ü$ð	  ñ ð ×Ñ¤WÐÑ-Ø×Ñ˜TÓ"€DØ‡I�Iˆd…Or   c           	   #  ó¦  #   • X;   a  g[        5       nUR                  U 5        SnSnSnSn[        R                  " [	        U 5      5       GHü  nSU;   a  M  UR                  5       nUS[        U5      [        U5      -
   n	U(       a3  UR                  5       (       a  [        U	5      U:”  a  [        Xr5      v •  Mp  SnU(       d6  [        R                  U5      (       a  Sn[        U	5      n[        Xr5      v •  M¯  U(       a5  SU;   a  UR                  SS5      S   nSnMÕ  [        R                  U5      n
O[        R                  U5      n
U
(       aè  U(       d+  [        U
R                  S5      5      nU
R                  S	5      nU(       a<  UR                  U5        [!        [#        [$        U S
3-  U5      U	5       Sh  v•N   GM|  U
R                  S5      R                  S5       HL  nUR                  5       nUR                  U5        [!        [#        [$        U S
3-  U5      U	5       Sh  v•N   MN     GMï  [        Xr5      v •  GMÿ     g N� N 7f)a†  Yield ``path``'s lines with relative imports inlined recursively.

Reads ``path`` with ``encoding='ascii'`` (see the module docstring
for why every source file under `src_path` must be ASCII). A line
matching a relative import -- ``from .foo import bar`` or its
parenthesised multi-line form -- is not emitted as-is; instead, the
module(s) it names are read in turn (recursively, through this same
function) and their lines are yielded in its place, re-indented to
match if the import itself was indented. This is what lets `combine`
produce a single file: a relative import would not resolve once the
referenced module is no longer a separate file.

``if TYPE_CHECKING:`` blocks are the one exception: they are emitted
verbatim rather than inlined, so the runtime guard their else-branch
relies on is preserved. ``from __future__ import ...`` lines are
dropped, since `combine` writes a single
``from __future__ import annotations`` once for the whole output.

Args:
    path: The module to read.
    seen_files: Modules already emitted, keyed by resolved path.
        Mutated in place: `path` is added to it on entry, and a
        module reached through an inlined import is skipped (this
        generator yields nothing and returns) once its path is
        already present here, so a module referenced from more than
        one place is only inlined once.

Yields:
    Lines of `path`'s source, in order, with relative imports
    replaced by the recursively inlined source of the module(s)
    they named.

Raises:
    UnicodeDecodeError: `path` contains a byte that is not valid
        ASCII. The offending snippet is logged before this is
        re-raised.
NFr   Ú
__future__TÚ)r   ÚparenÚfromz.pyÚnamesÚ,)ÚsetÚaddÚioÚStringIOr    ÚlstripÚlenÚstripÚ_clean_lineÚ_TYPE_CHECKING_REÚmatchÚsplitÚ	_NAMES_REÚ_RELATIVE_IMPORT_REÚboolÚgroupÚ	_reindentÚ
_read_fileÚsrc_path)r   Ú
seen_filesr<   r:   Úfrom_Úin_type_checkingÚtype_checking_indentÚlineÚstrippedÚindentrG   Únames               r   rN   rN   ’   s  é € ðR ÓØä“e€EØ‡N�N�4ÔØ€EØ€EØÐØÐÜ—’Ô,¨TÓ2×3ˆØ˜4ÓÙà—;‘;“=ˆØÐ1œ˜D›	¤C¨£MÑ1Ð2ˆö Ø—‘× Ñ ¤C¨£KÐ2FÓ$Fä˜dÓ*Ò*ÙØ ÐÞÔ*×0Ñ0°×:Ñ:Ø#ÐÜ#& v£;Ð Ü˜dÓ*Ò*ÙæØ�d‹{Ø—z‘z # qÓ)¨!Ñ,�Ø�Ùä—O‘O DÓ)‰Eä'×-Ñ-¨hÓ7ˆEæÞÜ˜UŸ[™[¨Ó1Ó2�ØŸ™ FÓ+�ö
 Ø—	‘	˜%Ô Ü$Üœx¨U¨G°3¨-Ñ7¸ÓDØó÷ ó ð
 "ŸK™K¨Ó0×6Ñ6°sÖ;�DØŸ:™:›<�DØ—I‘I˜d”OÜ(Ü"¤8°°°c¨lÑ#:¸JÓGØó ÷ ò ô <ô ˜dÓ*Õ*òq 4ñVñùs%   ‚F=IÆ?IÇ A.IÈ.IÈ/IÉIc                ó–   • U(       a-  SR                  U5      n[        R                  " SU S3SU 5      n [        R                  SU 5      $ )aš  Strip inlined-module qualifiers and useless self-assignments.

For example, with ``names={'constants'}``, the line
``x = constants.LockFlags.EXCLUSIVE\n`` becomes
``x = LockFlags.EXCLUSIVE\n``; with ``names=set()``, the line
``spam = spam\n`` becomes ``''``.

Note:
    Not a doctest: pytest's ``--doctest-modules`` collector never
    imports files named ``__main__.py``, so an executable example
    here would silently never run.

Args:
    line: A source line being emitted as-is (i.e. it did not itself
        match a relative import) into the combined output.
    names: Names of modules that `_read_file` has already inlined
        into the current output, for this line's source module.
        Used to turn a qualified reference such as
        ``constants.LockFlags`` into ``LockFlags``, since once a
        module has been inlined it is no longer a separate module
        to qualify names against.

Returns:
    `line`, with any ``<name>.`` prefix removed for every `name` in
    `names`, and then with a resulting useless self-assignment
    (``spam = spam``, left behind when a qualified name turned out
    to equal its own unqualified form) removed entirely.
Ú|z\b(z)\.Ú )ÚjoinÚreÚsubÚ_USELESS_ASSIGNMENT_RE)rT   r<   Újoined_namess      r   rE   rE   ÿ   sD   € ö< Ø—x‘x “ˆÜ�vŠv˜˜\˜N¨#Ð.°°DÓ9ˆô "×%Ñ% b¨$Ó/Ð/r   c              #  ó„   #   • U(       d  U  Sh  v•N   gU  H"  nUR                  5       (       a  U U 3OUv •  M$     g N.7f)a  Prefix each non-blank inlined line with ``indent``.

Used when a relative import is itself indented (e.g. the optional-redis
guard's ``try`` block): the inlined module is emitted at that indentation
so it stays inside the guard while preserving its own relative structure.
N)rD   )ÚlinesrV   rT   s      r   rM   rM   %  s@   é € ö Ø×ÐØÛˆØ#'§:¡:§<¡<��˜˜Ñ°TÔ9ò ñ 	ùs   ‚A �>�/A c           	     óà  • U R                   nS[        R                  [        [        S-  5      5      [        R                  [        [        S-  5      5      /n[        5       nUR                  [        [        S-  U5      5        UR                  R                  SSS9  UR                  SR                  U5      5        [        R                  SU 35         [        R                   " S	S
[#        U5      /SS9  [        R                   " S	SSS[#        U5      /SS9  [        R                   " [(        R*                  [#        U5      /5        g! [$         a    [        R'                  S5         NQf = f)a)
  Bundle the package into a single vendorable ``portalocker.py`` file.

This is the ``combine`` subcommand's implementation (see `main`). It
exists for projects that cannot add ``portalocker`` as a dependency
-- for example a vendoring or single-file-deployment constraint --
and instead copy one generated file with the same public API into
their own tree.

Starting from ``portalocker/__init__.py``, the package's modules are
read with `_read_file`, which inlines every relative import
recursively (so the result has none left) while leaving
``TYPE_CHECKING`` blocks intact. That includes the optional
``try: from .redis import RedisLock`` guard in ``__init__.py``:
``redis.py`` is inlined the same way as any other sibling module,
re-indented to stay inside the ``try``, so the combined file binds
`RedisLock` the same way the package does -- to the stub class that
raises ``ImportError`` on construction if importing it fails.

Every module under `src_path`, plus ``README.md`` and ``LICENSE``,
is read with ``encoding='ascii'`` (see the module docstring): all of
them must be ASCII-only or this raises `UnicodeDecodeError`.
``README.md`` and ``LICENSE`` are also written near the top of the
output, each wrapped in a triple-quoted string, for reference; they
are not the output file's docstring, since the single
``from __future__ import annotations`` line this function writes
first has to stay the first statement.

All inputs are read and assembled in memory first, and the output
file is only opened once the assembly has succeeded. Writing first
used to truncate ``--output-file`` before the first input was read,
so a decode failure destroyed a pre-existing build. A plain write is
deliberate here: ``--output-file`` legitimately overwrites its
previous build, which is exactly the no-replace semantic
`portalocker.utils.open_atomic` exists to forbid.

If the ``ruff`` command is available, the output is formatted and
lint-fixed in place; if not, that step is skipped with a warning.
Either way, the output is then executed once with `sys.executable`.
That run's exit status is not checked, so it surfaces problems in
the log rather than failing `combine` itself.

Args:
    args: Parsed CLI namespace; only `args.output_file` is used.
        Populated by `main` via the ``combine`` subparser, whose
        ``--output-file``/``-o`` option defaults to
        `_default_output_path` (``dist/portalocker.py``).

Note:
    The combined file still needs the ``redis`` package installed
    for `RedisLock` to work: combining inlines the code that binds
    to ``redis``, not ``redis`` itself.
z#from __future__ import annotations
z	README.mdÚLICENSEz__init__.pyT)ÚparentsÚexist_okrZ   zWrote combined file to ÚruffÚformaté   )ÚtimeoutÚcheckz--fixz
--fix-onlyz<Ruff is not installed. Skipping linting and formatting step.N)Úoutput_fileÚ_TEXT_TEMPLATErg   r    Ú	base_pathr>   ÚextendrN   rO   ÚparentÚmkdirÚ
write_textr[   r   ÚinfoÚ
subprocessÚrunÚstrr   ÚwarningÚsysÚ
executable)r	   Úoutput_pathÚpartsrP   s       r   r#   r#   5  s/  € ðj !%× 0Ñ 0€Kð 	/Ü×ÑÔ.¬y¸;Ñ/FÓGÓHÜ×ÑÔ.¬y¸9Ñ/DÓEÓFð€Eô %(£E€JØ	‡L�L”œH }Ñ4°jÓAÔBà×Ñ×Ñ T°DÐÑ9Ø×Ñ˜2Ÿ7™7 5›>Ô*ä
‡K�KÐ)¨+¨Ð7Ô8ð	
Ü�Š˜ ¬#¨kÓ*:Ð;ÀQÒGÜ�ŠØ�W˜g |´S¸Ó5EÐFØò	
ô ‡N‚N”C—N‘N¤C¨Ó$4Ð5Õ6øô	 ó 
Ü�‰ØJö	
ð
ús   ÃAE ÅE-Å,E-Ú__main__)Úlevel)r   úpathlib.Pathr   r   ÚreturnÚNone)r   r}   r~   ru   )N)r2   ztyping.Sequence[str] | Noner~   r   )r   r}   rP   zset[pathlib.Path]r~   útyping.Iterator[str])rT   ru   r<   zset[str]r~   ru   )ra   r€   rV   ru   r~   r€   )r	   zargparse.Namespacer~   r   )$Ú__doc__r8   r   r(   r@   Úloggingr-   r\   rs   rw   Útypingr.   Ú__file__ro   rm   rO   Ú	dist_pathr/   ÚcompilerI   rJ   r^   rF   rl   Ú	getLoggerÚ__name__r   r   r    r6   rN   rE   rM   r#   ÚbasicConfigÚINFO© r   r   Ú<module>rŒ      s`  ðñõ" #ã Û 	Û Û Û 	Û Û 
Û à�LŠL˜Ó"×)Ñ)×0Ñ0€	Ø�}Ñ$€Ø˜Ñ€	Ø  6Ñ)Ð,<Ñ<Ð à�JŠJÐ,Ó-€	Ø—j’jØDóÐ ð ŸšÐ$=Ó>Ð Ø—J’JÐCÓDÐ ð€ð 
×	Ò	˜8Ó	$€ðØ
ðà!ðð 
ôô6+ö6'ðTj+Ø
ðj+à!ðj+ð ôj+ôZ#0ðL:Øð:Ø),ð:àô:ô S7ðl ˆzÓØ×Ò˜gŸl™lÒ+Ù…Fð r   