Sometimes when I am review, this randomly pops up Enable tracemalloc to get the object allocation traceback
. Then, I enabled traceback
:
c:\python>.\python.exe --version
Python 3.8.0
...
import tracemalloc
tracemalloc.start()
And I got this:
\\?\F:\bazel\anki\rybdqld5\execroot\ankidesktop\bazel-out\x64_windows-fastbuild\bin\qt\runanki.exe.runfiles\ankidesktop\qt\aqt\sound.py:316: ResourceWarning: unclosed file <_io.BufferedWriter name=5> self._process = None Object allocated at (most recent call last): File "c:\python\lib\subprocess.py", lineno 838 self.stdin = io.open(p2cwrite, 'wb', bufsize)
Appointed code on sound.py:316
File: anki2/qt/aqt/sound.py
306: def _wait_for_termination(self, tag: AVTag) -> None:
307: self._taskman.run_on_main(
308: lambda: gui_hooks.av_player_did_begin_playing(self, tag)
309: )
310:
311: while True:
312: # should we abort playing?
313: if self._terminate_flag:
314: self._process.terminate()
315: self._process.wait(1)
316: self._process = None
317: return
318:
319: # wait for completion
320: try:
321: self._process.wait(0.1)
322: if self._process.returncode != 0:
323: print(f"player got return code: {self._process.returncode}")
324: self._process = None
325: return
326: except subprocess.TimeoutExpired:
327: # process still running, repeat loop
328: pass
329:
330: def _on_done(self, ret: Future, cb: OnDoneCallback) -> None:
Appointed code on subprocess.py:838
File: C:/python/Lib/subprocess.py
684: class Popen(object):
685: """ Execute a child program in a new process.
686:
687: For a complete description of the arguments see the Python documentation.
688:
689: Arguments:
690: args: A string, or a sequence of program arguments.
691:
692: bufsize: supplied as the buffering argument to the open() function when
693: creating the stdin/stdout/stderr pipe file objects
694:
695: executable: A replacement program to execute.
696:
697: stdin, stdout and stderr: These specify the executed programs' standard
698: input, standard output and standard error file handles, respectively.
699:
700: preexec_fn: (POSIX only) An object to be called in the child process
701: just before the child is executed.
702:
703: close_fds: Controls closing or inheriting of file descriptors.
704:
705: shell: If true, the command will be executed through the shell.
706:
707: cwd: Sets the current directory before the child is executed.
708:
709: env: Defines the environment variables for the new process.
710:
711: text: If true, decode stdin, stdout and stderr using the given encoding
712: (if set) or the system default otherwise.
713:
714: universal_newlines: Alias of text, provided for backwards compatibility.
715:
716: startupinfo and creationflags (Windows only)
717:
718: restore_signals (POSIX only)
719:
720: start_new_session (POSIX only)
721:
722: pass_fds (POSIX only)
723:
724: encoding and errors: Text mode encoding and error handling to use for
725: file objects stdin, stdout and stderr.
726:
727: Attributes:
728: stdin, stdout, stderr, pid, returncode
729: """
730: _child_created = False # Set here since __del__ checks it
731:
732: def __init__(self, args, bufsize=-1, executable=None,
733: stdin=None, stdout=None, stderr=None,
734: preexec_fn=None, close_fds=True,
735: shell=False, cwd=None, env=None, universal_newlines=None,
736: startupinfo=None, creationflags=0,
737: restore_signals=True, start_new_session=False,
738: pass_fds=(), *, encoding=None, errors=None, text=None):
739: """Create new Popen instance."""
740: _cleanup()
741: # Held while anything is calling waitpid before returncode has been
742: # updated to prevent clobbering returncode if wait() or poll() are
743: # called from multiple threads at once. After acquiring the lock,
744: # code must re-check self.returncode to see if another thread just
745: # finished a waitpid() call.
746: self._waitpid_lock = threading.Lock()
747:
748: self._input = None
749: self._communication_started = False
750: if bufsize is None:
751: bufsize = -1 # Restore default
752: if not isinstance(bufsize, int):
753: raise TypeError("bufsize must be an integer")
754:
755: if _mswindows:
756: if preexec_fn is not None:
757: raise ValueError("preexec_fn is not supported on Windows "
758: "platforms")
759: else:
760: # POSIX
761: if pass_fds and not close_fds:
762: warnings.warn("pass_fds overriding close_fds.", RuntimeWarning)
763: close_fds = True
764: if startupinfo is not None:
765: raise ValueError("startupinfo is only supported on Windows "
766: "platforms")
767: if creationflags != 0:
768: raise ValueError("creationflags is only supported on Windows "
769: "platforms")
770:
771: self.args = args
772: self.stdin = None
773: self.stdout = None
774: self.stderr = None
775: self.pid = None
776: self.returncode = None
777: self.encoding = encoding
778: self.errors = errors
779:
780: # Validate the combinations of text and universal_newlines
781: if (text is not None and universal_newlines is not None
782: and bool(universal_newlines) != bool(text)):
783: raise SubprocessError('Cannot disambiguate when both text '
784: 'and universal_newlines are supplied but '
785: 'different. Pass one or the other.')
786:
787: # Input and output objects. The general principle is like
788: # this:
789: #
790: # Parent Child
791: # ------ -----
792: # p2cwrite ---stdin---> p2cread
793: # c2pread <--stdout--- c2pwrite
794: # errread <--stderr--- errwrite
795: #
796: # On POSIX, the child objects are file descriptors. On
797: # Windows, these are Windows file handles. The parent objects
798: # are file descriptors on both platforms. The parent objects
799: # are -1 when not using PIPEs. The child objects are -1
800: # when not redirecting.
801:
802: (p2cread, p2cwrite,
803: c2pread, c2pwrite,
804: errread, errwrite) = self._get_handles(stdin, stdout, stderr)
805:
806: # We wrap OS handles *before* launching the child, otherwise a
807: # quickly terminating child could make our fds unwrappable
808: # (see #8458).
809:
810: if _mswindows:
811: if p2cwrite != -1:
812: p2cwrite = msvcrt.open_osfhandle(p2cwrite.Detach(), 0)
813: if c2pread != -1:
814: c2pread = msvcrt.open_osfhandle(c2pread.Detach(), 0)
815: if errread != -1:
816: errread = msvcrt.open_osfhandle(errread.Detach(), 0)
817:
818: self.text_mode = encoding or errors or text or universal_newlines
819:
820: # How long to resume waiting on a child after the first ^C.
821: # There is no right value for this. The purpose is to be polite
822: # yet remain good for interactive users trying to exit a tool.
823: self._sigint_wait_secs = 0.25 # 1/xkcd221.getRandomNumber()
824:
825: self._closed_child_pipe_fds = False
826:
827: if self.text_mode:
828: if bufsize == 1:
829: line_buffering = True
830: # Use the default buffer size for the underlying binary streams
831: # since they don't support line buffering.
832: bufsize = -1
833: else:
834: line_buffering = False
835:
836: try:
837: if p2cwrite != -1:
838: self.stdin = io.open(p2cwrite, 'wb', bufsize)
839: if self.text_mode:
840: self.stdin = io.TextIOWrapper(self.stdin, write_through=True,
841: line_buffering=line_buffering,
842: encoding=encoding, errors=errors)
843: if c2pread != -1:
844: self.stdout = io.open(c2pread, 'rb', bufsize)
845: if self.text_mode:
846: self.stdout = io.TextIOWrapper(self.stdout,
847: encoding=encoding, errors=errors)
848: if errread != -1:
849: self.stderr = io.open(errread, 'rb', bufsize)
850: if self.text_mode:
851: self.stderr = io.TextIOWrapper(self.stderr,
852: encoding=encoding, errors=errors)
853:
854: self._execute_child(args, executable, preexec_fn, close_fds,
855: pass_fds, cwd, env,
856: startupinfo, creationflags, shell,
857: p2cread, p2cwrite,
858: c2pread, c2pwrite,
859: errread, errwrite,
860: restore_signals, start_new_session)
861: except:
862: # Cleanup if the child failed starting.
863: for f in filter(None, (self.stdin, self.stdout, self.stderr)):
864: try:
865: f.close()
866: except OSError:
867: pass # Ignore EBADF or other errors.
868:
869: if not self._closed_child_pipe_fds:
870: to_close = []
871: if stdin == PIPE:
872: to_close.append(p2cread)
873: if stdout == PIPE:
874: to_close.append(c2pwrite)
875: if stderr == PIPE:
876: to_close.append(errwrite)
877: if hasattr(self, '_devnull'):
878: to_close.append(self._devnull)
879: for fd in to_close:
880: try:
881: if _mswindows and isinstance(fd, Handle):
882: fd.Close()
883: else:
884: os.close(fd)
885: except OSError:
886: pass
887:
888: raise
889: