Reporting new USB storage devices on Linux and macOS with Python












8












$begingroup$


Synopsis:



I wanted something for macOS (and Linux; maybe eventually Windows) that would simply wait for the user to connect a storage device and automatically select, or otherwise output the information to be used, read, manipulated, etc.



In its current form, it just prints to the shell, but you could assign the output to a list or variable for read/write operations and so on. It will respond to any new entries in the /dev system directory, including most USB devices, SD Cards, Webcams, and so on. You can test it by running the script in one window, and running something like sudo touch /dev/{x,y,z} in another.



I plan to use it to help people (those of us who are less technically inclined) migrate to Linux by automating the creation of bootable flash drives, but you can do what you like with it.



Open-ended feedback and suggestions are welcome. Please try to post example code pertaining to your suggestions, and don't be afraid to say something positive.



Usage:



user@macOS:~$ ./devlisten.py
/dev/disk2
/dev/rdisk2
/dev/disk2s1
/dev/rdisk2s1


Code:



#!/usr/bin/env python3

import os
import re
import time
import difflib

try:
os.mkdir('/tmp/dev')
except FileExistsError:
pass
except FileNotFoundError:
print('No /tmp directory found.')
exit()
except OSError:
print('Read-only file system.')
exit()

file1 = open('/tmp/dev/1', 'w')
for x in os.listdir('/dev'):
file1.write(x + 'n')
file1.close()

try:

diff = False
while diff == False:
time.sleep(0.25)

file2 = open('/tmp/dev/2', 'w')
for x in os.listdir('/dev'):
file2.write(x + 'n')
file2.close()

text1 = open('/tmp/dev/1').readlines()
text2 = open('/tmp/dev/2').readlines()

for line in difflib.unified_diff(text1, text2):
for line in re.finditer(r'(?<=^+)w.*$', line, re.MULTILINE):
print('/dev/' + line.group(0))
diff = True

except KeyboardInterrupt:

print()
exit()









share|improve this question











$endgroup$

















    8












    $begingroup$


    Synopsis:



    I wanted something for macOS (and Linux; maybe eventually Windows) that would simply wait for the user to connect a storage device and automatically select, or otherwise output the information to be used, read, manipulated, etc.



    In its current form, it just prints to the shell, but you could assign the output to a list or variable for read/write operations and so on. It will respond to any new entries in the /dev system directory, including most USB devices, SD Cards, Webcams, and so on. You can test it by running the script in one window, and running something like sudo touch /dev/{x,y,z} in another.



    I plan to use it to help people (those of us who are less technically inclined) migrate to Linux by automating the creation of bootable flash drives, but you can do what you like with it.



    Open-ended feedback and suggestions are welcome. Please try to post example code pertaining to your suggestions, and don't be afraid to say something positive.



    Usage:



    user@macOS:~$ ./devlisten.py
    /dev/disk2
    /dev/rdisk2
    /dev/disk2s1
    /dev/rdisk2s1


    Code:



    #!/usr/bin/env python3

    import os
    import re
    import time
    import difflib

    try:
    os.mkdir('/tmp/dev')
    except FileExistsError:
    pass
    except FileNotFoundError:
    print('No /tmp directory found.')
    exit()
    except OSError:
    print('Read-only file system.')
    exit()

    file1 = open('/tmp/dev/1', 'w')
    for x in os.listdir('/dev'):
    file1.write(x + 'n')
    file1.close()

    try:

    diff = False
    while diff == False:
    time.sleep(0.25)

    file2 = open('/tmp/dev/2', 'w')
    for x in os.listdir('/dev'):
    file2.write(x + 'n')
    file2.close()

    text1 = open('/tmp/dev/1').readlines()
    text2 = open('/tmp/dev/2').readlines()

    for line in difflib.unified_diff(text1, text2):
    for line in re.finditer(r'(?<=^+)w.*$', line, re.MULTILINE):
    print('/dev/' + line.group(0))
    diff = True

    except KeyboardInterrupt:

    print()
    exit()









    share|improve this question











    $endgroup$















      8












      8








      8


      3



      $begingroup$


      Synopsis:



      I wanted something for macOS (and Linux; maybe eventually Windows) that would simply wait for the user to connect a storage device and automatically select, or otherwise output the information to be used, read, manipulated, etc.



      In its current form, it just prints to the shell, but you could assign the output to a list or variable for read/write operations and so on. It will respond to any new entries in the /dev system directory, including most USB devices, SD Cards, Webcams, and so on. You can test it by running the script in one window, and running something like sudo touch /dev/{x,y,z} in another.



      I plan to use it to help people (those of us who are less technically inclined) migrate to Linux by automating the creation of bootable flash drives, but you can do what you like with it.



      Open-ended feedback and suggestions are welcome. Please try to post example code pertaining to your suggestions, and don't be afraid to say something positive.



      Usage:



      user@macOS:~$ ./devlisten.py
      /dev/disk2
      /dev/rdisk2
      /dev/disk2s1
      /dev/rdisk2s1


      Code:



      #!/usr/bin/env python3

      import os
      import re
      import time
      import difflib

      try:
      os.mkdir('/tmp/dev')
      except FileExistsError:
      pass
      except FileNotFoundError:
      print('No /tmp directory found.')
      exit()
      except OSError:
      print('Read-only file system.')
      exit()

      file1 = open('/tmp/dev/1', 'w')
      for x in os.listdir('/dev'):
      file1.write(x + 'n')
      file1.close()

      try:

      diff = False
      while diff == False:
      time.sleep(0.25)

      file2 = open('/tmp/dev/2', 'w')
      for x in os.listdir('/dev'):
      file2.write(x + 'n')
      file2.close()

      text1 = open('/tmp/dev/1').readlines()
      text2 = open('/tmp/dev/2').readlines()

      for line in difflib.unified_diff(text1, text2):
      for line in re.finditer(r'(?<=^+)w.*$', line, re.MULTILINE):
      print('/dev/' + line.group(0))
      diff = True

      except KeyboardInterrupt:

      print()
      exit()









      share|improve this question











      $endgroup$




      Synopsis:



      I wanted something for macOS (and Linux; maybe eventually Windows) that would simply wait for the user to connect a storage device and automatically select, or otherwise output the information to be used, read, manipulated, etc.



      In its current form, it just prints to the shell, but you could assign the output to a list or variable for read/write operations and so on. It will respond to any new entries in the /dev system directory, including most USB devices, SD Cards, Webcams, and so on. You can test it by running the script in one window, and running something like sudo touch /dev/{x,y,z} in another.



      I plan to use it to help people (those of us who are less technically inclined) migrate to Linux by automating the creation of bootable flash drives, but you can do what you like with it.



      Open-ended feedback and suggestions are welcome. Please try to post example code pertaining to your suggestions, and don't be afraid to say something positive.



      Usage:



      user@macOS:~$ ./devlisten.py
      /dev/disk2
      /dev/rdisk2
      /dev/disk2s1
      /dev/rdisk2s1


      Code:



      #!/usr/bin/env python3

      import os
      import re
      import time
      import difflib

      try:
      os.mkdir('/tmp/dev')
      except FileExistsError:
      pass
      except FileNotFoundError:
      print('No /tmp directory found.')
      exit()
      except OSError:
      print('Read-only file system.')
      exit()

      file1 = open('/tmp/dev/1', 'w')
      for x in os.listdir('/dev'):
      file1.write(x + 'n')
      file1.close()

      try:

      diff = False
      while diff == False:
      time.sleep(0.25)

      file2 = open('/tmp/dev/2', 'w')
      for x in os.listdir('/dev'):
      file2.write(x + 'n')
      file2.close()

      text1 = open('/tmp/dev/1').readlines()
      text2 = open('/tmp/dev/2').readlines()

      for line in difflib.unified_diff(text1, text2):
      for line in re.finditer(r'(?<=^+)w.*$', line, re.MULTILINE):
      print('/dev/' + line.group(0))
      diff = True

      except KeyboardInterrupt:

      print()
      exit()






      python beginner python-3.x linux macos






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 15 at 17:34









      200_success

      129k15153416




      129k15153416










      asked Jan 15 at 13:48









      tjt263tjt263

      34639




      34639






















          4 Answers
          4






          active

          oldest

          votes


















          12












          $begingroup$

          This script might get the job done, but it is a rather crude and inefficient hack. Ideally, you should avoid polling every quarter second (or polling at all). Also, I see no reason to write any files to /tmp.





          The ideal way to do it in Linux is to use udev. If you don't want to write a persistent udev rule, or you don't have root access, you can run /sbin/udevadm monitor --udev --property as a child process, and trigger your test whenever udevadm offers output. For a smarter script, you can can look for the ACTION=add line and take advantage of the information in the SUBSYSTEM=… and DEVPATH=… lines. DEVPATH tells you path to the device within /sys. But, even if you simply trigger your script only when any output appears, that would be a huge improvement over polling four times a second.



          import itertools
          from subprocess import Popen, PIPE
          import re
          import sys

          KEYVALUE_RE = re.compile(r'([^=]+)=(.*)')

          def events(stream):
          """
          Read udev events from the stream, yielding them as dictionaries.
          """
          while True:
          event = dict(
          KEYVALUE_RE.match(line).groups()
          for line in itertools.takewhile(KEYVALUE_RE.match, stream)
          )
          if event:
          yield event

          try:
          UDEVADM = ['/sbin/udevadm', 'monitor', '--udev', '--property']
          with Popen(UDEVADM, stdout=PIPE, encoding='UTF-8') as udevadm:
          for event in events(udevadm.stdout):
          if event['ACTION'] == 'add' and event.get('DRIVER') == 'usb-storage':
          print(event)
          break
          except KeyboardInterrupt:
          sys.exit(1)




          On macOS, you can get similar information by running and monitoring the output of /usr/sbin/diskutil activity, if you are interested in storage devices. Look for lines starting with ***DiskAppeared.



          from subprocess import Popen, PIPE
          import sys

          try:
          DISKUTIL = ['/usr/sbin/diskutil', 'activity']
          with Popen(DISKUTIL, stdout=PIPE, encoding='UTF-8') as diskutil:
          # Ignore events that describe the present state
          for line in diskutil.stdout:
          if line.startswith('***DAIdle'):
          break
          # Detect the first subsequent "Disk Appeared" event
          for line in diskutil.stdout:
          if line.startswith('***DiskAppeared'):
          print(line)
          break
          except KeyboardInterrupt:
          sys.exit(1)


          If you are interested in non-storage devices as well, then you could take advantage of the File System Events API, possibly through the MacFSEvents Python package or the cross-platform fswatch program.






          share|improve this answer











          $endgroup$





















            5












            $begingroup$

            Prefer to use $TMPDIR if set, and /tmp only as a fallback. That's the standard practice that allows users to have separate, private temporary directories, for example, so don't subvert it! You probably ought to consider tempfile.​TemporaryDirectory() as an alternative.



            Error messages should go to standard error channel, not standard output.



            I don't know Mac OS, but on Linux I'd expect you to wait on inotify, rather than polling the dev directory. There's a choice of Python interface to inotify, but I'm not in a position to recommend any in particular.






            share|improve this answer









            $endgroup$









            • 2




              $begingroup$
              macOS has FSEvents (en.wikipedia.org/wiki/FSEvents). I don't know much about it.
              $endgroup$
              – tjt263
              Jan 15 at 18:17



















            5












            $begingroup$



            • context managers



              You should really open and close files with the with statement see PEP343




            • if __name__ == '__main__': guard



              Python idiom is to use a guard to ensure main is not run when being imported by another script




            • tempfile



              As mentioned by @Toby already, there is module for creating Temporary files/directories




            • Why does it need to be in a file though?



              You could create a list of filenames and poll for changes



              And compare the lists instead of the files








            share|improve this answer









            $endgroup$













            • $begingroup$
              It doesn't have to be stored in a file. I just thought it would be better than storing it in RAM the whole time.
              $endgroup$
              – tjt263
              Jan 15 at 18:01






            • 3




              $begingroup$
              @tjt263 Why would it?
              $endgroup$
              – Konrad Rudolph
              Jan 16 at 0:46



















            4












            $begingroup$

            Another point I didn't see mentioned:



            try:
            os.mkdir('/tmp/dev')
            except FileExistsError:
            pass


            except blocks with pass are usually a sign that there is probably a better way. In this case, assuming you are using Python 3.2 or later, is to use os.makedirs with the exist_ok argument set to True:



            os.makedirs('/tmp/dev', exist_ok=True)





            share|improve this answer









            $endgroup$













            • $begingroup$
              Why's that better? What's the difference?
              $endgroup$
              – tjt263
              Jan 15 at 22:48











            Your Answer





            StackExchange.ifUsing("editor", function () {
            return StackExchange.using("mathjaxEditing", function () {
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            });
            });
            }, "mathjax-editing");

            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "196"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211546%2freporting-new-usb-storage-devices-on-linux-and-macos-with-python%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            4 Answers
            4






            active

            oldest

            votes








            4 Answers
            4






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            12












            $begingroup$

            This script might get the job done, but it is a rather crude and inefficient hack. Ideally, you should avoid polling every quarter second (or polling at all). Also, I see no reason to write any files to /tmp.





            The ideal way to do it in Linux is to use udev. If you don't want to write a persistent udev rule, or you don't have root access, you can run /sbin/udevadm monitor --udev --property as a child process, and trigger your test whenever udevadm offers output. For a smarter script, you can can look for the ACTION=add line and take advantage of the information in the SUBSYSTEM=… and DEVPATH=… lines. DEVPATH tells you path to the device within /sys. But, even if you simply trigger your script only when any output appears, that would be a huge improvement over polling four times a second.



            import itertools
            from subprocess import Popen, PIPE
            import re
            import sys

            KEYVALUE_RE = re.compile(r'([^=]+)=(.*)')

            def events(stream):
            """
            Read udev events from the stream, yielding them as dictionaries.
            """
            while True:
            event = dict(
            KEYVALUE_RE.match(line).groups()
            for line in itertools.takewhile(KEYVALUE_RE.match, stream)
            )
            if event:
            yield event

            try:
            UDEVADM = ['/sbin/udevadm', 'monitor', '--udev', '--property']
            with Popen(UDEVADM, stdout=PIPE, encoding='UTF-8') as udevadm:
            for event in events(udevadm.stdout):
            if event['ACTION'] == 'add' and event.get('DRIVER') == 'usb-storage':
            print(event)
            break
            except KeyboardInterrupt:
            sys.exit(1)




            On macOS, you can get similar information by running and monitoring the output of /usr/sbin/diskutil activity, if you are interested in storage devices. Look for lines starting with ***DiskAppeared.



            from subprocess import Popen, PIPE
            import sys

            try:
            DISKUTIL = ['/usr/sbin/diskutil', 'activity']
            with Popen(DISKUTIL, stdout=PIPE, encoding='UTF-8') as diskutil:
            # Ignore events that describe the present state
            for line in diskutil.stdout:
            if line.startswith('***DAIdle'):
            break
            # Detect the first subsequent "Disk Appeared" event
            for line in diskutil.stdout:
            if line.startswith('***DiskAppeared'):
            print(line)
            break
            except KeyboardInterrupt:
            sys.exit(1)


            If you are interested in non-storage devices as well, then you could take advantage of the File System Events API, possibly through the MacFSEvents Python package or the cross-platform fswatch program.






            share|improve this answer











            $endgroup$


















              12












              $begingroup$

              This script might get the job done, but it is a rather crude and inefficient hack. Ideally, you should avoid polling every quarter second (or polling at all). Also, I see no reason to write any files to /tmp.





              The ideal way to do it in Linux is to use udev. If you don't want to write a persistent udev rule, or you don't have root access, you can run /sbin/udevadm monitor --udev --property as a child process, and trigger your test whenever udevadm offers output. For a smarter script, you can can look for the ACTION=add line and take advantage of the information in the SUBSYSTEM=… and DEVPATH=… lines. DEVPATH tells you path to the device within /sys. But, even if you simply trigger your script only when any output appears, that would be a huge improvement over polling four times a second.



              import itertools
              from subprocess import Popen, PIPE
              import re
              import sys

              KEYVALUE_RE = re.compile(r'([^=]+)=(.*)')

              def events(stream):
              """
              Read udev events from the stream, yielding them as dictionaries.
              """
              while True:
              event = dict(
              KEYVALUE_RE.match(line).groups()
              for line in itertools.takewhile(KEYVALUE_RE.match, stream)
              )
              if event:
              yield event

              try:
              UDEVADM = ['/sbin/udevadm', 'monitor', '--udev', '--property']
              with Popen(UDEVADM, stdout=PIPE, encoding='UTF-8') as udevadm:
              for event in events(udevadm.stdout):
              if event['ACTION'] == 'add' and event.get('DRIVER') == 'usb-storage':
              print(event)
              break
              except KeyboardInterrupt:
              sys.exit(1)




              On macOS, you can get similar information by running and monitoring the output of /usr/sbin/diskutil activity, if you are interested in storage devices. Look for lines starting with ***DiskAppeared.



              from subprocess import Popen, PIPE
              import sys

              try:
              DISKUTIL = ['/usr/sbin/diskutil', 'activity']
              with Popen(DISKUTIL, stdout=PIPE, encoding='UTF-8') as diskutil:
              # Ignore events that describe the present state
              for line in diskutil.stdout:
              if line.startswith('***DAIdle'):
              break
              # Detect the first subsequent "Disk Appeared" event
              for line in diskutil.stdout:
              if line.startswith('***DiskAppeared'):
              print(line)
              break
              except KeyboardInterrupt:
              sys.exit(1)


              If you are interested in non-storage devices as well, then you could take advantage of the File System Events API, possibly through the MacFSEvents Python package or the cross-platform fswatch program.






              share|improve this answer











              $endgroup$
















                12












                12








                12





                $begingroup$

                This script might get the job done, but it is a rather crude and inefficient hack. Ideally, you should avoid polling every quarter second (or polling at all). Also, I see no reason to write any files to /tmp.





                The ideal way to do it in Linux is to use udev. If you don't want to write a persistent udev rule, or you don't have root access, you can run /sbin/udevadm monitor --udev --property as a child process, and trigger your test whenever udevadm offers output. For a smarter script, you can can look for the ACTION=add line and take advantage of the information in the SUBSYSTEM=… and DEVPATH=… lines. DEVPATH tells you path to the device within /sys. But, even if you simply trigger your script only when any output appears, that would be a huge improvement over polling four times a second.



                import itertools
                from subprocess import Popen, PIPE
                import re
                import sys

                KEYVALUE_RE = re.compile(r'([^=]+)=(.*)')

                def events(stream):
                """
                Read udev events from the stream, yielding them as dictionaries.
                """
                while True:
                event = dict(
                KEYVALUE_RE.match(line).groups()
                for line in itertools.takewhile(KEYVALUE_RE.match, stream)
                )
                if event:
                yield event

                try:
                UDEVADM = ['/sbin/udevadm', 'monitor', '--udev', '--property']
                with Popen(UDEVADM, stdout=PIPE, encoding='UTF-8') as udevadm:
                for event in events(udevadm.stdout):
                if event['ACTION'] == 'add' and event.get('DRIVER') == 'usb-storage':
                print(event)
                break
                except KeyboardInterrupt:
                sys.exit(1)




                On macOS, you can get similar information by running and monitoring the output of /usr/sbin/diskutil activity, if you are interested in storage devices. Look for lines starting with ***DiskAppeared.



                from subprocess import Popen, PIPE
                import sys

                try:
                DISKUTIL = ['/usr/sbin/diskutil', 'activity']
                with Popen(DISKUTIL, stdout=PIPE, encoding='UTF-8') as diskutil:
                # Ignore events that describe the present state
                for line in diskutil.stdout:
                if line.startswith('***DAIdle'):
                break
                # Detect the first subsequent "Disk Appeared" event
                for line in diskutil.stdout:
                if line.startswith('***DiskAppeared'):
                print(line)
                break
                except KeyboardInterrupt:
                sys.exit(1)


                If you are interested in non-storage devices as well, then you could take advantage of the File System Events API, possibly through the MacFSEvents Python package or the cross-platform fswatch program.






                share|improve this answer











                $endgroup$



                This script might get the job done, but it is a rather crude and inefficient hack. Ideally, you should avoid polling every quarter second (or polling at all). Also, I see no reason to write any files to /tmp.





                The ideal way to do it in Linux is to use udev. If you don't want to write a persistent udev rule, or you don't have root access, you can run /sbin/udevadm monitor --udev --property as a child process, and trigger your test whenever udevadm offers output. For a smarter script, you can can look for the ACTION=add line and take advantage of the information in the SUBSYSTEM=… and DEVPATH=… lines. DEVPATH tells you path to the device within /sys. But, even if you simply trigger your script only when any output appears, that would be a huge improvement over polling four times a second.



                import itertools
                from subprocess import Popen, PIPE
                import re
                import sys

                KEYVALUE_RE = re.compile(r'([^=]+)=(.*)')

                def events(stream):
                """
                Read udev events from the stream, yielding them as dictionaries.
                """
                while True:
                event = dict(
                KEYVALUE_RE.match(line).groups()
                for line in itertools.takewhile(KEYVALUE_RE.match, stream)
                )
                if event:
                yield event

                try:
                UDEVADM = ['/sbin/udevadm', 'monitor', '--udev', '--property']
                with Popen(UDEVADM, stdout=PIPE, encoding='UTF-8') as udevadm:
                for event in events(udevadm.stdout):
                if event['ACTION'] == 'add' and event.get('DRIVER') == 'usb-storage':
                print(event)
                break
                except KeyboardInterrupt:
                sys.exit(1)




                On macOS, you can get similar information by running and monitoring the output of /usr/sbin/diskutil activity, if you are interested in storage devices. Look for lines starting with ***DiskAppeared.



                from subprocess import Popen, PIPE
                import sys

                try:
                DISKUTIL = ['/usr/sbin/diskutil', 'activity']
                with Popen(DISKUTIL, stdout=PIPE, encoding='UTF-8') as diskutil:
                # Ignore events that describe the present state
                for line in diskutil.stdout:
                if line.startswith('***DAIdle'):
                break
                # Detect the first subsequent "Disk Appeared" event
                for line in diskutil.stdout:
                if line.startswith('***DiskAppeared'):
                print(line)
                break
                except KeyboardInterrupt:
                sys.exit(1)


                If you are interested in non-storage devices as well, then you could take advantage of the File System Events API, possibly through the MacFSEvents Python package or the cross-platform fswatch program.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jan 15 at 20:19

























                answered Jan 15 at 18:48









                200_success200_success

                129k15153416




                129k15153416

























                    5












                    $begingroup$

                    Prefer to use $TMPDIR if set, and /tmp only as a fallback. That's the standard practice that allows users to have separate, private temporary directories, for example, so don't subvert it! You probably ought to consider tempfile.​TemporaryDirectory() as an alternative.



                    Error messages should go to standard error channel, not standard output.



                    I don't know Mac OS, but on Linux I'd expect you to wait on inotify, rather than polling the dev directory. There's a choice of Python interface to inotify, but I'm not in a position to recommend any in particular.






                    share|improve this answer









                    $endgroup$









                    • 2




                      $begingroup$
                      macOS has FSEvents (en.wikipedia.org/wiki/FSEvents). I don't know much about it.
                      $endgroup$
                      – tjt263
                      Jan 15 at 18:17
















                    5












                    $begingroup$

                    Prefer to use $TMPDIR if set, and /tmp only as a fallback. That's the standard practice that allows users to have separate, private temporary directories, for example, so don't subvert it! You probably ought to consider tempfile.​TemporaryDirectory() as an alternative.



                    Error messages should go to standard error channel, not standard output.



                    I don't know Mac OS, but on Linux I'd expect you to wait on inotify, rather than polling the dev directory. There's a choice of Python interface to inotify, but I'm not in a position to recommend any in particular.






                    share|improve this answer









                    $endgroup$









                    • 2




                      $begingroup$
                      macOS has FSEvents (en.wikipedia.org/wiki/FSEvents). I don't know much about it.
                      $endgroup$
                      – tjt263
                      Jan 15 at 18:17














                    5












                    5








                    5





                    $begingroup$

                    Prefer to use $TMPDIR if set, and /tmp only as a fallback. That's the standard practice that allows users to have separate, private temporary directories, for example, so don't subvert it! You probably ought to consider tempfile.​TemporaryDirectory() as an alternative.



                    Error messages should go to standard error channel, not standard output.



                    I don't know Mac OS, but on Linux I'd expect you to wait on inotify, rather than polling the dev directory. There's a choice of Python interface to inotify, but I'm not in a position to recommend any in particular.






                    share|improve this answer









                    $endgroup$



                    Prefer to use $TMPDIR if set, and /tmp only as a fallback. That's the standard practice that allows users to have separate, private temporary directories, for example, so don't subvert it! You probably ought to consider tempfile.​TemporaryDirectory() as an alternative.



                    Error messages should go to standard error channel, not standard output.



                    I don't know Mac OS, but on Linux I'd expect you to wait on inotify, rather than polling the dev directory. There's a choice of Python interface to inotify, but I'm not in a position to recommend any in particular.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jan 15 at 14:08









                    Toby SpeightToby Speight

                    24.5k740115




                    24.5k740115








                    • 2




                      $begingroup$
                      macOS has FSEvents (en.wikipedia.org/wiki/FSEvents). I don't know much about it.
                      $endgroup$
                      – tjt263
                      Jan 15 at 18:17














                    • 2




                      $begingroup$
                      macOS has FSEvents (en.wikipedia.org/wiki/FSEvents). I don't know much about it.
                      $endgroup$
                      – tjt263
                      Jan 15 at 18:17








                    2




                    2




                    $begingroup$
                    macOS has FSEvents (en.wikipedia.org/wiki/FSEvents). I don't know much about it.
                    $endgroup$
                    – tjt263
                    Jan 15 at 18:17




                    $begingroup$
                    macOS has FSEvents (en.wikipedia.org/wiki/FSEvents). I don't know much about it.
                    $endgroup$
                    – tjt263
                    Jan 15 at 18:17











                    5












                    $begingroup$



                    • context managers



                      You should really open and close files with the with statement see PEP343




                    • if __name__ == '__main__': guard



                      Python idiom is to use a guard to ensure main is not run when being imported by another script




                    • tempfile



                      As mentioned by @Toby already, there is module for creating Temporary files/directories




                    • Why does it need to be in a file though?



                      You could create a list of filenames and poll for changes



                      And compare the lists instead of the files








                    share|improve this answer









                    $endgroup$













                    • $begingroup$
                      It doesn't have to be stored in a file. I just thought it would be better than storing it in RAM the whole time.
                      $endgroup$
                      – tjt263
                      Jan 15 at 18:01






                    • 3




                      $begingroup$
                      @tjt263 Why would it?
                      $endgroup$
                      – Konrad Rudolph
                      Jan 16 at 0:46
















                    5












                    $begingroup$



                    • context managers



                      You should really open and close files with the with statement see PEP343




                    • if __name__ == '__main__': guard



                      Python idiom is to use a guard to ensure main is not run when being imported by another script




                    • tempfile



                      As mentioned by @Toby already, there is module for creating Temporary files/directories




                    • Why does it need to be in a file though?



                      You could create a list of filenames and poll for changes



                      And compare the lists instead of the files








                    share|improve this answer









                    $endgroup$













                    • $begingroup$
                      It doesn't have to be stored in a file. I just thought it would be better than storing it in RAM the whole time.
                      $endgroup$
                      – tjt263
                      Jan 15 at 18:01






                    • 3




                      $begingroup$
                      @tjt263 Why would it?
                      $endgroup$
                      – Konrad Rudolph
                      Jan 16 at 0:46














                    5












                    5








                    5





                    $begingroup$



                    • context managers



                      You should really open and close files with the with statement see PEP343




                    • if __name__ == '__main__': guard



                      Python idiom is to use a guard to ensure main is not run when being imported by another script




                    • tempfile



                      As mentioned by @Toby already, there is module for creating Temporary files/directories




                    • Why does it need to be in a file though?



                      You could create a list of filenames and poll for changes



                      And compare the lists instead of the files








                    share|improve this answer









                    $endgroup$





                    • context managers



                      You should really open and close files with the with statement see PEP343




                    • if __name__ == '__main__': guard



                      Python idiom is to use a guard to ensure main is not run when being imported by another script




                    • tempfile



                      As mentioned by @Toby already, there is module for creating Temporary files/directories




                    • Why does it need to be in a file though?



                      You could create a list of filenames and poll for changes



                      And compare the lists instead of the files









                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jan 15 at 14:29









                    LudisposedLudisposed

                    8,06222160




                    8,06222160












                    • $begingroup$
                      It doesn't have to be stored in a file. I just thought it would be better than storing it in RAM the whole time.
                      $endgroup$
                      – tjt263
                      Jan 15 at 18:01






                    • 3




                      $begingroup$
                      @tjt263 Why would it?
                      $endgroup$
                      – Konrad Rudolph
                      Jan 16 at 0:46


















                    • $begingroup$
                      It doesn't have to be stored in a file. I just thought it would be better than storing it in RAM the whole time.
                      $endgroup$
                      – tjt263
                      Jan 15 at 18:01






                    • 3




                      $begingroup$
                      @tjt263 Why would it?
                      $endgroup$
                      – Konrad Rudolph
                      Jan 16 at 0:46
















                    $begingroup$
                    It doesn't have to be stored in a file. I just thought it would be better than storing it in RAM the whole time.
                    $endgroup$
                    – tjt263
                    Jan 15 at 18:01




                    $begingroup$
                    It doesn't have to be stored in a file. I just thought it would be better than storing it in RAM the whole time.
                    $endgroup$
                    – tjt263
                    Jan 15 at 18:01




                    3




                    3




                    $begingroup$
                    @tjt263 Why would it?
                    $endgroup$
                    – Konrad Rudolph
                    Jan 16 at 0:46




                    $begingroup$
                    @tjt263 Why would it?
                    $endgroup$
                    – Konrad Rudolph
                    Jan 16 at 0:46











                    4












                    $begingroup$

                    Another point I didn't see mentioned:



                    try:
                    os.mkdir('/tmp/dev')
                    except FileExistsError:
                    pass


                    except blocks with pass are usually a sign that there is probably a better way. In this case, assuming you are using Python 3.2 or later, is to use os.makedirs with the exist_ok argument set to True:



                    os.makedirs('/tmp/dev', exist_ok=True)





                    share|improve this answer









                    $endgroup$













                    • $begingroup$
                      Why's that better? What's the difference?
                      $endgroup$
                      – tjt263
                      Jan 15 at 22:48
















                    4












                    $begingroup$

                    Another point I didn't see mentioned:



                    try:
                    os.mkdir('/tmp/dev')
                    except FileExistsError:
                    pass


                    except blocks with pass are usually a sign that there is probably a better way. In this case, assuming you are using Python 3.2 or later, is to use os.makedirs with the exist_ok argument set to True:



                    os.makedirs('/tmp/dev', exist_ok=True)





                    share|improve this answer









                    $endgroup$













                    • $begingroup$
                      Why's that better? What's the difference?
                      $endgroup$
                      – tjt263
                      Jan 15 at 22:48














                    4












                    4








                    4





                    $begingroup$

                    Another point I didn't see mentioned:



                    try:
                    os.mkdir('/tmp/dev')
                    except FileExistsError:
                    pass


                    except blocks with pass are usually a sign that there is probably a better way. In this case, assuming you are using Python 3.2 or later, is to use os.makedirs with the exist_ok argument set to True:



                    os.makedirs('/tmp/dev', exist_ok=True)





                    share|improve this answer









                    $endgroup$



                    Another point I didn't see mentioned:



                    try:
                    os.mkdir('/tmp/dev')
                    except FileExistsError:
                    pass


                    except blocks with pass are usually a sign that there is probably a better way. In this case, assuming you are using Python 3.2 or later, is to use os.makedirs with the exist_ok argument set to True:



                    os.makedirs('/tmp/dev', exist_ok=True)






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jan 15 at 19:21









                    DeepSpaceDeepSpace

                    29519




                    29519












                    • $begingroup$
                      Why's that better? What's the difference?
                      $endgroup$
                      – tjt263
                      Jan 15 at 22:48


















                    • $begingroup$
                      Why's that better? What's the difference?
                      $endgroup$
                      – tjt263
                      Jan 15 at 22:48
















                    $begingroup$
                    Why's that better? What's the difference?
                    $endgroup$
                    – tjt263
                    Jan 15 at 22:48




                    $begingroup$
                    Why's that better? What's the difference?
                    $endgroup$
                    – tjt263
                    Jan 15 at 22:48


















                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Code Review Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    Use MathJax to format equations. MathJax reference.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211546%2freporting-new-usb-storage-devices-on-linux-and-macos-with-python%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

                    Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

                    A Topological Invariant for $pi_3(U(n))$