
    ʆh9                        S r SSKJr  SSKrSSKrSSKrSSKJr  SSKJ	r	  \	(       a  SSK
Jr  SSKJrJr   " S S	5      r " S
 S5      r " S S\5      rg)u  :module: watchdog.utils.dirsnapshot
:synopsis: Directory snapshots and comparison.
:author: yesudeep@google.com (Yesudeep Mangalapilly)
:author: contact@tiger-222.fr (Mickaël Schoentgen)

.. ADMONITION:: Where are the moved events? They "disappeared"

        This implementation does not take partition boundaries
        into consideration. It will only work when the directory
        tree is entirely on the same file system. More specifically,
        any part of the code that depends on inode numbers can
        break if partition boundaries are crossed. In these cases,
        the snapshot diff will represent file/directory movement as
        created and deleted events.

Classes
-------
.. autoclass:: DirectorySnapshot
   :members:
   :show-inheritance:

.. autoclass:: DirectorySnapshotDiff
   :members:
   :show-inheritance:

.. autoclass:: EmptyDirectorySnapshot
   :members:
   :show-inheritance:

    )annotationsN)S_ISDIR)TYPE_CHECKING)Iterator)AnyCallablec                      \ rS rSrSrSS.       SS jjrSS jrSS jr\SS j5       r	\SS	 j5       r
\SS
 j5       r\SS j5       r\SS j5       r\SS j5       r\SS j5       r\SS j5       r " S S5      rSrg)DirectorySnapshotDiff-   a}  Compares two directory snapshots and creates an object that represents
the difference between the two snapshots.

:param ref:
    The reference directory snapshot.
:type ref:
    :class:`DirectorySnapshot`
:param snapshot:
    The directory snapshot which will be compared
    with the reference snapshot.
:type snapshot:
    :class:`DirectorySnapshot`
:param ignore_device:
    A boolean indicating whether to ignore the device id or not.
    By default, a file may be uniquely identified by a combination of its first
    inode and its device id. The problem is that the device id may (or may not)
    change between system boots. This problem would cause the DirectorySnapshotDiff
    to think a file has been deleted and created again but it would be the
    exact same file.
    Set to True only if you are sure you will always use the same device.
:type ignore_device:
    :class:`bool`
Fignore_devicec                  UR                   UR                   -
  nUR                   UR                   -
  nU(       a  SS jnOSS jnUR                   UR                   -   H9  nU" X5      U" X'5      :w  d  M  UR                  U5        UR                  U5        M;     [        5       n[        U5       HQ  nUR                  U5      n	UR	                  U	5      n
U
(       d  M.  UR                  U5        UR                  Xz45        MS     [        U5       HQ  nUR                  U5      n	UR	                  U	5      nU(       d  M.  UR                  U5        UR                  X45        MS     [        5       nUR                   UR                   -   Hr  nU" X5      U" X'5      :X  d  M  UR                  U5      UR                  U5      :w  d&  UR                  U5      UR                  U5      :w  d  Ma  UR                  U5        Mt     U H`  u  pUR                  U5      UR                  U
5      :w  d&  UR                  U5      UR                  U
5      :w  d  MO  UR                  U5        Mb     U Vs/ s H  orR                  U5      (       d  M  UPM     snU l	        U Vs/ s H  oqR                  U5      (       d  M  UPM     snU l
        U Vs/ s H  oqR                  U5      (       d  M  UPM     snU l        U VVs/ s H   u  pUR                  U5      (       d  M  X4PM"     snnU l        [        U[        U R                  5      -
  5      U l        [        U[        U R                  5      -
  5      U l        [        U[        U R                  5      -
  5      U l        [        U[        U R                  5      -
  5      U l        g s  snf s  snf s  snf s  snnf )Nc                *    U R                  U5      S   $ )Nr   inode	directory	full_paths     R/opt/services/DDDS/venv/lib/python3.13/site-packages/watchdog/utils/dirsnapshot.py	get_inode1DirectorySnapshotDiff.__init__.<locals>.get_inodeR   s     y1!44    c                $    U R                  U5      $ Nr   r   s     r   r   r   W   s     y11r   )r   DirectorySnapshotr   bytes | strreturnzint | tuple[int, int])pathsaddsetr   pathremovemtimesizeisdir_dirs_created_dirs_deleted_dirs_modified_dirs_movedlist_files_created_files_deleted_files_modified_files_moved)selfrefsnapshotr   createddeletedr   r!   movedr   new_pathold_pathmodifiedfrmtos                  r   __init__DirectorySnapshotDiff.__init__F   s    ..399,))hnn,5
2 II.D#y'@@D!D! / 7:eLDIIdOE}}U+Hxt$		4*+ ! LDNN4(ExxHxt$		8*+ ! &)UII.D#y'@@		$8>>$#77388D>X]][_M`;`T"	 / #(Hyy"hnnX&>>#((8BTX`XeXefnXoBoX& #( 07Owt..:NdwO/6Jwt))D/dwJ08LIIdOtL7<Ou)3		#ISIuO"7S1C1C-D#DE"7S1C1C-D#DE#Hs43F3F/G$GH T-=-=)>!>? PJLOs0   (N?N?O4OO	#O	6OOc                "    U R                  5       $ r   __repr__r/   s    r   __str__DirectorySnapshotDiff.__str__       }}r   c                   SnUR                  [        U 5      R                  [        U R                  5      [        U R
                  5      [        U R                  5      [        U R                  5      [        U R                  5      [        U R                  5      [        U R                  5      [        U R                  5      5	      $ )Nzz<{0} files(created={1}, deleted={2}, modified={3}, moved={4}), folders(created={5}, deleted={6}, modified={7}, moved={8})>)formattype__name__lenr+   r,   r-   r.   r&   r'   r(   r)   )r/   fmts     r   r>   DirectorySnapshotDiff.__repr__   s    K 	 zzJ##$##$$$%!!"""#""###$  !

 
	
r   c                    U R                   $ )z List of files that were created.)r+   r?   s    r   files_created#DirectorySnapshotDiff.files_created        """r   c                    U R                   $ )z List of files that were deleted.)r,   r?   s    r   files_deleted#DirectorySnapshotDiff.files_deleted   rM   r   c                    U R                   $ )z!List of files that were modified.)r-   r?   s    r   files_modified$DirectorySnapshotDiff.files_modified   s     ###r   c                    U R                   $ )zList of files that were moved.

Each event is a two-tuple the first item of which is the path
that has been renamed to the second item in the tuple.
)r.   r?   s    r   files_moved!DirectorySnapshotDiff.files_moved   s        r   c                    U R                   $ )z'List of directories that were modified.)r(   r?   s    r   dirs_modified#DirectorySnapshotDiff.dirs_modified   rM   r   c                    U R                   $ )zList of directories that were moved.

Each event is a two-tuple the first item of which is the path
that has been renamed to the second item in the tuple.
)r)   r?   s    r   
dirs_moved DirectorySnapshotDiff.dirs_moved   s     r   c                    U R                   $ )z&List of directories that were deleted.)r'   r?   s    r   dirs_deleted"DirectorySnapshotDiff.dirs_deleted        !!!r   c                    U R                   $ )z&List of directories that were created.)r&   r?   s    r   dirs_created"DirectorySnapshotDiff.dirs_created   r`   r   c                      \ rS rSrSrS\R                  \R                  SS.           SS jjrSS jr	SS jr
SS	 jrS
rg)$DirectorySnapshotDiff.ContextManager   a  Context manager that creates two directory snapshots and a
diff object that represents the difference between the two snapshots.

:param path:
    The directory path for which a snapshot should be taken.
:type path:
    ``str``
:param recursive:
    ``True`` if the entire directory tree should be included in the
    snapshot; ``False`` otherwise.
:type recursive:
    ``bool``
:param stat:
    Use custom stat function that returns a stat structure for path.
    Currently only st_dev, st_ino, st_mode and st_mtime are needed.

    A function taking a ``path`` as argument which will be called
    for every entry in the directory tree.
:param listdir:
    Use custom listdir function. For details see ``os.scandir``.
:param ignore_device:
    A boolean indicating whether to ignore the device id or not.
    By default, a file may be uniquely identified by a combination of its first
    inode and its device id. The problem is that the device id may (or may not)
    change between system boots. This problem would cause the DirectorySnapshotDiff
    to think a file has been deleted and created again but it would be the
    exact same file.
    Set to True only if you are sure you will always use the same device.
:type ignore_device:
    :class:`bool`
TF)	recursivestatlistdirr   c               @    Xl         X l        X0l        X@l        XPl        g r   )r!   rg   rh   ri   r   )r/   r!   rg   rh   ri   r   s         r   r:   -DirectorySnapshotDiff.ContextManager.__init__   s     I&NI"L!.r   c                .    U R                  5       U l        g r   )get_snapshotpre_snapshotr?   s    r   	__enter__.DirectorySnapshotDiff.ContextManager.__enter__   s     $ 1 1 3Dr   c                    U R                  5       U l        [        U R                  U R                  U R                  S9U l        g )Nr   )rm   post_snapshotr
   rn   r   diff)r/   argss     r   __exit__-DirectorySnapshotDiff.ContextManager.__exit__   s:    !%!2!2!4D-!!"""00DIr   c                j    [        U R                  U R                  U R                  U R                  S9$ )N)r!   rg   rh   ri   )r   r!   rg   rh   ri   r?   s    r   rm   1DirectorySnapshotDiff.ContextManager.get_snapshot  s+    $YY..YY	 r   )rs   r   ri   r!   rr   rn   rg   rh   N)r!   strrg   boolrh   Callable[[str], os.stat_result]ri   -Callable[[str | None], Iterator[os.DirEntry]]r   rz   r   Noner   r}   )rt   objectr   r}   )r   r   )rF   
__module____qualname____firstlineno____doc__osrh   scandirr:   ro   ru   rm   __static_attributes__ r   r   ContextManagerre      sm    	H #46GGEGZZ"'	/	/ 		/
 2	/ C	/  	/ 	/	4		r   r   )r&   r'   r(   r)   r+   r,   r-   r.   N)r0   r   r1   r   r   rz   r   r}   r   ry   )r   zlist[bytes | str])r   z%list[tuple[bytes | str, bytes | str]])rF   r   r   r   r   r:   r@   r>   propertyrK   rO   rR   rU   rX   r[   r^   rb   r   r   r   r   r   r
   r
   -   s    : $@@@@ $@@
 @@ 
@@D
" # # # # $ $ ! ! # #     " " " "A Ar   r
   c                      \ rS rSrSrS\R                  \R                  S.         SS jjrSS jr	\
SS j5       rSS jrSS	 jrSS
 jrSS jrSS jrSS jrSS jrSS jrSS jrSrg)r   i  a  A snapshot of stat information of files in a directory.

:param path:
    The directory path for which a snapshot should be taken.
:type path:
    ``str``
:param recursive:
    ``True`` if the entire directory tree should be included in the
    snapshot; ``False`` otherwise.
:type recursive:
    ``bool``
:param stat:
    Use custom stat function that returns a stat structure for path.
    Currently only st_dev, st_ino, st_mode and st_mtime are needed.

    A function taking a ``path`` as argument which will be called
    for every entry in the directory tree.
:param listdir:
    Use custom listdir function. For details see ``os.scandir``.
T)rg   rh   ri   c               f   X l         X0l        X@l        0 U l        0 U l        U R                  U5      nXPR                  U'   XR                  UR
                  UR                  4'   U R                  U5       H9  u  peUR
                  UR                  4nX`R                  U'   XPR                  U'   M;     g r   )rg   rh   ri   
_stat_info_inode_to_pathst_inost_devwalk)r/   r!   rg   rh   ri   stpis           r   r:   DirectorySnapshot.__init__&  s     #	=?BDYYt_ "6:RYY		23YYt_EABII&A%&"!#OOA %r   c              #  0  #     U R                  U5       Vs/ s H,  n[        R                  R                  XR                  5      PM.     nn/ nU HM  n[        R                  " [
        5         X`R                  U5      4nUR                  U5        Uv   S S S 5        MO     U R                  (       ab  U H[  u  px[        R                  " [        5         [!        UR"                  5      (       a  U R%                  U5       S h  vN   S S S 5        M]     g g s  snf ! [
         aH  nUR                  [        R                  [        R                  [        R                  4;   a   S nAg e S nAff = f! , (       d  f       GM/  = f N! , (       d  f       M  = f7fr   )ri   r   r!   joinnameOSErrorerrnoENOENTENOTDIREINVAL
contextlibsuppressrh   appendrg   PermissionErrorr   st_moder   )	r/   rootentryr   eentriesr   r!   r   s	            r   r   DirectorySnapshot.walk>  s%    
	AEdASTASRWW\\$

3ASET A$$W-IIaL)u% .-  >>#((9rzz**#'99T?22 :9 $ % U 	
 ww5<<EE	 .- 3 :9s   FD 3D
D !F-(E/>F/FFFFD 
E,$=E'!F&E''E,,F/
E?	9	FF
F	Fc                H    [        U R                  R                  5       5      $ )z,Set of file/directory paths in the snapshot.)r    r   keysr?   s    r   r   DirectorySnapshot.pathsX  s     4??'')**r   c                8    U R                   R                  U5      $ )z<Returns path for id. None if id is unknown to this snapshot.)r   get)r/   uids     r   r!   DirectorySnapshot.path]  s    ""&&s++r   c                P    U R                   U   nUR                  UR                  4$ )zReturns an id for path.)r   r   r   )r/   r!   r   s      r   r   DirectorySnapshot.inodea  s#    __T"		299%%r   c                F    [        U R                  U   R                  5      $ r   )r   r   r   r/   r!   s     r   r%   DirectorySnapshot.isdirf  s    tt,4455r   c                4    U R                   U   R                  $ r   )r   st_mtimer   s     r   r#   DirectorySnapshot.mtimei  s    t$---r   c                4    U R                   U   R                  $ r   )r   st_sizer   s     r   r$   DirectorySnapshot.sizel  s    t$,,,r   c                     U R                   U   $ )aD  Returns a stat information object for the specified path from
the snapshot.

Attached information is subject to change. Do not use unless
you specify `stat` in constructor. Use :func:`inode`, :func:`mtime`,
:func:`isdir` instead.

:param path:
    The path for which stat information should be obtained
    from a snapshot.
)r   r   s     r   	stat_infoDirectorySnapshot.stat_infoo  s     t$$r   c                    [        X5      $ )z|Allow subtracting a DirectorySnapshot object instance from
another.

:returns:
    A :class:`DirectorySnapshotDiff` object.
)r
   )r/   previous_dirsnaps     r   __sub__DirectorySnapshot.__sub__}  s     %%5<<r   c                "    U R                  5       $ r   r=   r?   s    r   r@   DirectorySnapshot.__str__  rB   r   c                ,    [        U R                  5      $ r   )ry   r   r?   s    r   r>   DirectorySnapshot.__repr__  s    4??##r   )r   r   ri   rg   rh   N)
r!   ry   rg   rz   rh   r{   ri   r|   r   r}   )r   ry   r   z$Iterator[tuple[str, os.stat_result]])r   zset[bytes | str])r   tuple[int, int]r   zbytes | str | None)r!   r   r   r   )r!   r   r   rz   )r!   r   r   float)r!   r   r   int)r!   r   r   zos.stat_result)r   r   r   r
   r   )rF   r   r   r   r   r   rh   r   r:   r   r   r   r!   r   r%   r#   r$   r   r   r@   r>   r   r   r   r   r   r     s    2 02AC$$ 	$
 .$ ?$ 
$034 + +,&
6.-%=$r   r   c                  J    \ rS rSrSrSS jr\S	S j5       r\S
S j5       r	Sr
g)EmptyDirectorySnapshoti  zClass to implement an empty snapshot. This is used together with
DirectorySnapshot and DirectorySnapshotDiff in order to get all the files/folders
in the directory as created.
c                    g r   r   r?   s    r   r:   EmptyDirectorySnapshot.__init__  s    r   c                    g)zMock up method to return the path of the received inode. As the snapshot
is intended to be empty, it always returns None.

:returns:
    None.
Nr   )_s    r   r!   EmptyDirectorySnapshot.path  s     	r   c                    [        5       $ )zMock up method to return a set of file/directory paths in the snapshot. As
the snapshot is intended to be empty, it always returns an empty set.

:returns:
    An empty set.
)r    r?   s    r   r   EmptyDirectorySnapshot.paths  s     ur   r   Nr~   )r   r   r   r}   )r   r    )rF   r   r   r   r   r:   staticmethodr!   r   r   r   r   r   r   r   r     s4    
    r   r   )r   
__future__r   r   r   r   rh   r   typingr   collections.abcr   r   r   r
   r   r   r   r   r   <module>r      sN   > #   	   ($` `Fz$ z$z. r   