try_execfile.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
  2. # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
  3. """Test file for run_python_file.
  4. This file is executed two ways::
  5. $ coverage run try_execfile.py
  6. and::
  7. $ python try_execfile.py
  8. The output is compared to see that the program execution context is the same
  9. under coverage and under Python.
  10. It is not crucial that the execution be identical, there are some differences
  11. that are OK. This program canonicalizes the output to gloss over those
  12. differences and get a clean diff.
  13. """
  14. import json, os, sys
  15. # sys.path varies by execution environments. Coverage.py uses setuptools to
  16. # make console scripts, which means pkg_resources is imported. pkg_resources
  17. # removes duplicate entries from sys.path. So we do that too, since the extra
  18. # entries don't affect the running of the program.
  19. def same_file(p1, p2):
  20. """Determine if `p1` and `p2` refer to the same existing file."""
  21. if not p1:
  22. return not p2
  23. if not os.path.exists(p1):
  24. return False
  25. if not os.path.exists(p2):
  26. return False
  27. if hasattr(os.path, "samefile"):
  28. return os.path.samefile(p1, p2)
  29. else:
  30. norm1 = os.path.normcase(os.path.normpath(p1))
  31. norm2 = os.path.normcase(os.path.normpath(p2))
  32. return norm1 == norm2
  33. def without_same_files(filenames):
  34. """Return the list `filenames` with duplicates (by same_file) removed."""
  35. reduced = []
  36. for filename in filenames:
  37. if not any(same_file(filename, other) for other in reduced):
  38. reduced.append(filename)
  39. return reduced
  40. cleaned_sys_path = [os.path.normcase(p) for p in without_same_files(sys.path)]
  41. # Eggs seems to go in different places for some reason. I'm going to assume
  42. # it's an OK difference. Sort eggs to the end of the list to canonicalize
  43. # them.
  44. cleaned_sys_path = sorted(cleaned_sys_path, key=lambda p: p.endswith(".egg"))
  45. DATA = "xyzzy"
  46. import __main__
  47. def my_function(a):
  48. """A function to force execution of module-level values."""
  49. return "my_fn(%r)" % a
  50. FN_VAL = my_function("fooey")
  51. loader = globals().get('__loader__')
  52. fullname = getattr(loader, 'fullname', None) or getattr(loader, 'name', None)
  53. globals_to_check = {
  54. '__name__': __name__,
  55. '__file__': __file__,
  56. '__doc__': __doc__,
  57. '__builtins__.has_open': hasattr(__builtins__, 'open'),
  58. '__builtins__.dir': dir(__builtins__),
  59. '__loader__ exists': loader is not None,
  60. '__loader__.fullname': fullname,
  61. '__package__': __package__,
  62. 'DATA': DATA,
  63. 'FN_VAL': FN_VAL,
  64. '__main__.DATA': getattr(__main__, "DATA", "nothing"),
  65. 'argv': sys.argv,
  66. 'path': cleaned_sys_path,
  67. }
  68. print(json.dumps(globals_to_check, indent=4, sort_keys=True))