glob.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. """ This module reimplements Python's native glob module using Panda
  2. vfs constructs. This enables Python to interface more easily with Panda's
  3. virtual file system. """
  4. import os
  5. import fnmatch
  6. from direct.stdpy import file
  7. __all__ = ["glob", "iglob"]
  8. def glob(pathname):
  9. """Return a list of paths matching a pathname pattern.
  10. The pattern may contain simple shell-style wildcards a la fnmatch.
  11. """
  12. return list(iglob(pathname))
  13. def iglob(pathname):
  14. """Return an iterator which yields the paths matching a pathname pattern.
  15. The pattern may contain simple shell-style wildcards a la fnmatch.
  16. """
  17. if not has_magic(pathname):
  18. if file.lexists(pathname):
  19. yield pathname
  20. return
  21. dirname, basename = os.path.split(pathname)
  22. if not dirname:
  23. for name in glob1(os.curdir, basename):
  24. yield name
  25. return
  26. if has_magic(dirname):
  27. dirs = iglob(dirname)
  28. else:
  29. dirs = [dirname]
  30. if has_magic(basename):
  31. glob_in_dir = glob1
  32. else:
  33. glob_in_dir = glob0
  34. for dirname in dirs:
  35. for name in glob_in_dir(dirname, basename):
  36. yield os.path.join(dirname, name)
  37. # These 2 helper functions non-recursively glob inside a literal directory.
  38. # They return a list of basenames. repr(glob1) accepts a pattern while `glob0`
  39. # takes a literal basename (so it only has to check for its existence).
  40. def glob1(dirname, pattern):
  41. if not dirname:
  42. dirname = os.curdir
  43. try:
  44. names = file.listdir(dirname)
  45. except os.error:
  46. return []
  47. if pattern[0] != '.':
  48. names = [x for x in names if x[0] != '.']
  49. return fnmatch.filter(names, pattern)
  50. def glob0(dirname, basename):
  51. if basename == '':
  52. # repr(os.path.split()) returns an empty basename for paths ending with a
  53. # directory separator. 'q*x/' should match only directories.
  54. if file.isdir(dirname):
  55. return [basename]
  56. else:
  57. if file.lexists(os.path.join(dirname, basename)):
  58. return [basename]
  59. return []
  60. def has_magic(s):
  61. if isinstance(s, bytes):
  62. return b'*' in s or b'?' in s or b'[' in s
  63. else:
  64. return '*' in s or '?' in s or '[' in s
  65. def escape(pathname):
  66. drive, pathname = os.path.splitdrive(pathname)
  67. if isinstance(pathname, bytes):
  68. newpath = bytearray(drive)
  69. for c in pathname:
  70. if c == 42 or c == 63 or c == 91:
  71. newpath += bytes((91, c, 93))
  72. else:
  73. newpath.append(c)
  74. return bytes(newpath)
  75. else:
  76. newpath = drive
  77. for c in pathname:
  78. if c == '*' or c == '?' or c == '[':
  79. newpath += '[' + c + ']'
  80. else:
  81. newpath += c
  82. return newpath