Pythonic way is to use with. In that case close is automatic as soon as we get outsude of the context:

ClassMethod ReadFileUsingPython(pFile As %String) [ Language = python ]
{
  from datetime import datetime
  import iris
  time1 = datetime.timestamp(datetime.now())
  print(time1)
  if pFile=="":
    raise Exception("filename is required.")

  with open(pFile,"r", encoding="utf-8", errors="ignore") as file:
    log = iris.cls('otw.log.Log')
    for line in file:
      status = log.ImportLine(line)

  time2 = datetime.timestamp(datetime.now())
  print(time2)
  print("Execution time: ",(time2-time1))
}

Also you can simplify your code:

ClassMethod ReadFileUsingPython(pFile As %String) [ Language = python ]
{
  from datetime import datetime
  import iris
  time1 = datetime.timestamp(datetime.now())
  print(time1)
  if pFile=="":
    raise Exception("filename is required.")

  file = open(pFile,"r", encoding="utf-8", errors="ignore")
  log = iris.cls('otw.log.Log')
  for line in file:
    status = log.ImportLine(line)

  time2 = datetime.timestamp(datetime.now())
  print(time2)
  print("Execution time: ",(time2-time1))
}

Interrupt causes rollback, try this code:

Class User.Del Extends (%Persistent, %Populate) [ Final ]
{

ClassMethod HangBool(seconds, id) As %Boolean [ SqlProc ]
{
    hang seconds
    quit $$$YES
}

/// do ##class(User.Del).Test()
ClassMethod Test()
{
    do ..%KillExtent()
    do ..Populate(10,,,,$$$NO)
    
    set start = $zh 
    &sql(DELETE FROM Del WHERE Del_HangBool(1, id)=1)
    set end = $zh
    w "Delete took: ", end-start,!
}
}

Regardless of when you send the interrupt, the ^User.DelD global would have 10 records.

For cross-namespace queries the easiest way is to map packages/globals but that might not be a recommended approach for an audit table.

You can do this:

  1. In your production namespace create a new table with the same structure as your audit select query backed by PPG storage.
  2. Switch to the audit namespace.
  3. Run audit query, iterate the results and write them into the PPG.
  4. Switch into a production namespace.
  5. Run query against your PPG table, joining any local tables.

Use args... to supply a variable number of parameters:

ClassMethod DoCleverStuf(args...) As %Status [ CodeMode = objectgenerator ]
{
    do %code.WriteLine("    For i=1:1:args {")
    do %code.WriteLine("        Write args(i)")
    do %code.WriteLine("    }")
    do %code.WriteLine("    Set tSC = $$$OK")
    ...
}

can I generate a whole method at compile time?

You can use projections to do that. Here's an example.