docstr: Compile a Python source file to frozen bytecode.
  
  Append the result to `self.frozen_modules`.
docstr_tok: ["Compile","a","Python","source","file","to","frozen","bytecode",".","Append","the","result","to","`","self.frozen_modules","`","."]
code: def compile_file(self, path: Path, top_package_path: Path):
      """
      Compile a Python source file to frozen bytecode.
  
      Append the result to `self.frozen_modules`.
      """
      assert path.is_file()
      if path.suffix != ".py":
          self.msg(path, "N")
          return
  
      if path.name in DENY_LIST:
          self.msg(path, "X")
          return
  
      self.msg(path, "F")
      module_qualname = self.get_module_qualname(path, top_package_path)
      module_mangled_name = "__".join(module_qualname)
      c_name = "M_" + module_mangled_name
  
      with open(path) as src_file:
          co = self.compile_string(src_file.read())
  
      bytecode = marshal.dumps(co)
      size = len(bytecode)
      if path.name == "__init__.py":
          # Python packages are signified by negative size.
          size = -size
      self.frozen_modules.append(
          FrozenModule(
              ".".join(module_qualname), c_name, size, bytecode
          )
      )
  
imports: import argparse
  import functools
  import itertools
  import marshal
  import os
  import types
  from dataclasses import dataclass
  from pathlib import Path
  from typing import List
label_desc: Use image node_id 10 for calling the Freezer obj's underlying member method code with example usage: obj.compile_file(path, top_package_path) without return types