K i9dZddlmZddlZddlZddlZddlmZddlm Z e rddl m Z ddlm Z m Z Gdd ZGd d ZGd d eZy)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)AnyCallableceZdZdZdd ddZddZddZeddZeddZ edd Z edd Z edd Z edd Z edd ZeddZGddZy)DirectorySnapshotDiffaCompares 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*|j|jz }|j|jz }|rdd}ndd}|j|jzD]8}||||||k7s|j||j|:t}t|D]K}|j|} |j | } | s(|j ||j|| fMt|D]K}|j|} |j | } | s(|j ||j| |fMt} |j|jzD]n}||||||k(s|j ||j |k7s$|j||j|k7s^| j|p|D]]\} } |j | |j | k7s$|j| |j| k7sM| j| _|Dcgc]}|j|s|c}|_ |Dcgc]}|j|s|c}|_ | Dcgc]}|j|s|c}|_ |D cgc]\} }|j| s| |fc}} |_ t|t|jz |_t|t|jz |_t| t|jz |_t|t|jz |_ycc}wcc}wcc}wcc}} w)Nc*|j|dS)Nrinode directory full_paths `/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/watchdog/utils/dirsnapshot.py get_inodez1DirectorySnapshotDiff.__init__..get_inodeRs y1!44c$|j|SNrrs rrz1DirectorySnapshotDiff.__init__..get_inodeWs y11r)rDirectorySnapshotr bytes | strreturnzint | tuple[int, int])pathsaddsetrpathremovemtimesizeisdir _dirs_created _dirs_deleted_dirs_modified _dirs_movedlist_files_created_files_deleted_files_modified _files_moved)selfrefsnapshotr createddeletedrrmovedrnew_pathold_pathmodifiedfrmtos r__init__zDirectorySnapshotDiff.__init__Fs..399,))hnn,  5  2II. "Dd#y4'@@ D! D! " 7:eL ,DIIdOE}}U+Ht$ 4*+  ,L ,DNN4(ExxHt$ 8T*+  ,&)UII. #Dd#y4'@@ $8>>$#77388D>X]][_M`;` T"  # #( ' Hhyy"hnnX&>>#((8BTX`XeXefnXoBo X& '07Ot(..:NdO/6Jt#))D/dJ08LCIIdOtL7<O)3 #S"IO"7S1C1C-D#DE"7S1C1C-D#DE#Hs43F3F/G$GH T-=-=)>!>?PJLOs0NN/NNN -N >NNc"|jSr__repr__r-s r__str__zDirectorySnapshotDiff.__str__}}rc d}|jt|jt|jt|j t|j t|jt|jt|jt|jt|j S)Nzz<{0} files(created={1}, deleted={2}, modified={3}, moved={4}), folders(created={5}, deleted={6}, modified={7}, moved={8})>) formattype__name__lenr)r*r+r,r$r%r&r')r-fmts rr;zDirectorySnapshotDiff.__repr__s K zz J   ## $ ## $ $$ % !! " "" # "" # ## $   !  rc|jS)z List of files that were created.)r)r<s r files_createdz#DirectorySnapshotDiff.files_created"""rc|jS)z List of files that were deleted.)r*r<s r files_deletedz#DirectorySnapshotDiff.files_deletedrGrc|jS)z!List of files that were modified.)r+r<s rfiles_modifiedz$DirectorySnapshotDiff.files_modifieds###rc|jS)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_movedz!DirectorySnapshotDiff.files_moveds   rc|jS)z'List of directories that were modified.)r&r<s r dirs_modifiedz#DirectorySnapshotDiff.dirs_modifiedrGrc|jS)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_movedz DirectorySnapshotDiff.dirs_movedsrc|jS)z&List of directories that were deleted.)r%r<s r dirs_deletedz"DirectorySnapshotDiff.dirs_deleted!!!rc|jS)z&List of directories that were created.)r$r<s r dirs_createdz"DirectorySnapshotDiff.dirs_createdrTrczeZdZdZdej ej dd d dZd dZd dZ d dZ y )$DirectorySnapshotDiff.ContextManageraContext 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) recursivestatlistdirr cJ||_||_||_||_||_yr)rrYrZr[r )r-rrYrZr[r s rr8z-DirectorySnapshotDiff.ContextManager.__init__s(DI&DNDI"DL!.D rc.|j|_yr) get_snapshot pre_snapshotr<s r __enter__z.DirectorySnapshotDiff.ContextManager.__enter__s $ 1 1 3D rc|j|_t|j|j|j|_y)Nr )r^ post_snapshotr r_r diff)r-argss r__exit__z-DirectorySnapshotDiff.ContextManager.__exit__s:!%!2!2!4D -!!"""00DIrcpt|j|j|j|jS)N)rrYrZr[)rrrYrZr[r<s rr^z1DirectorySnapshotDiff.ContextManager.get_snapshots+$YY..YY  rN) rstrrYboolrZCallable[[str], os.stat_result]r[-Callable[[str | None], Iterator[os.DirEntry]]r rhrNonerrk)rdobjectrrk)rr) rB __module__ __qualname____doc__osrZscandirr8r`rer^rrContextManagerrXsm H#46GGEGZZ"' / / / 2 / C /  / / 4  rrtN)r.rr/rr rhrrkrrg)rzlist[bytes | str])rz%list[tuple[bytes | str, bytes | str]])rBrnrorpr8r=r;propertyrFrIrKrMrOrQrSrVrtrsrrr r -s:$ @@ @@$@@  @@  @@D "####$$!!##  """"AArr ceZdZdZdej ej d ddZddZe ddZ ddZ ddZ dd Z dd Zdd Zdd Zdd ZddZddZy)raA 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)rYrZr[cr||_||_||_i|_i|_|j|}||j|<||j|j |j f<|j|D];\}}|j |j f}||j|<||j|<=yr)rYrZr[ _stat_info_inode_to_pathst_inost_devwalk)r-rrYrZr[stpis rr8zDirectorySnapshot.__init__&s#  =?BD YYt_ "6:RYY 23YYt_ $EArBII&A%&D   "!#DOOA  $rc#K |j|Dcgc],}tjj||j.}}g}|D]L}tjt 5||j|f}|j||dddN|jr[|D]U\}}tjt5t!|j"r|j%|Ed{dddWyycc}w#t $rF}|j t jt jt jfvrYd}~yd}~wwxYw#1swYxYw7t#1swYxYwwr)r[rqrjoinnameOSErrorerrnoENOENTENOTDIREINVAL contextlibsuppressrZappendrYPermissionErrorrst_moder}) r-rootentryreentriesrrr~s rr}zDirectorySnapshot.walk>sC AEdASTRWW\\$ 3TET A$$W- DIIaL)u%     >># 3b((93rzz*#'99T?2233 3 %U  ww5<< EE   333sE7D 1DD E7*)E7E7 *E+4E)5E+9 E7D E;EE7EEE7E& !E7)E++E4 0E7cHt|jjS)z,Set of file/directory paths in the snapshot.)rrykeysr<s rrzDirectorySnapshot.pathsXs4??'')**rc8|jj|S)zrc,t|jSr)rgryr<s rr;zDirectorySnapshot.__repr__s4??##rN) rrgrYrhrZrir[rjrrk)rrgrz$Iterator[tuple[str, os.stat_result]])rzset[bytes | str])rtuple[int, int]rzbytes | str | None)rrrr)rrrrh)rrrfloat)rrrint)rrrzos.stat_result)rrrr ru)rBrnrorprqrZrrr8r}rvrrrr#r!r"rrr=r;rsrrrrs202AC $$ $ . $ ? $ $034++,& 6.- %=$rrc<eZdZdZddZeddZeddZy) EmptyDirectorySnapshotzClass 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. cyrrsr<s rr8zEmptyDirectorySnapshot.__init__s rcy)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. Nrs)_s rrzEmptyDirectorySnapshot.paths rctS)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. )rr<s rrzEmptyDirectorySnapshot.pathss u rNrl)rrrrk)rr) rBrnrorpr8 staticmethodrrvrrsrrrrs4  rr)rp __future__rrrrqrZrtypingrcollections.abcrrrr rrrsrrrsN>#  ($``Fz$z$z.r