Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

541

542

543

544

545

546

547

548

549

550

551

552

553

554

555

556

557

558

559

560

561

562

563

564

565

566

567

568

569

570

571

572

573

574

575

576

577

578

579

580

581

582

583

584

585

586

587

588

589

590

591

592

593

594

595

596

597

598

599

600

601

602

603

604

605

606

607

608

609

610

611

612

613

614

615

616

617

618

619

620

621

622

623

624

625

626

627

628

629

630

631

632

633

634

635

636

637

638

639

640

641

642

643

644

645

646

647

648

649

650

651

652

653

654

655

656

657

658

659

660

661

662

663

664

665

666

667

668

669

670

671

672

673

674

675

676

677

678

679

680

681

682

683

684

685

686

687

688

689

690

691

692

693

694

695

696

697

698

699

700

701

702

703

704

705

706

707

708

709

710

711

712

713

714

715

716

717

718

719

720

721

722

723

724

725

726

727

728

729

730

731

732

733

734

735

736

737

738

739

740

741

742

743

744

745

746

747

748

749

750

751

752

753

754

755

756

757

758

759

760

761

762

763

764

765

766

767

768

769

770

771

772

773

774

775

776

777

778

779

780

781

782

783

784

785

786

787

788

789

790

791

792

793

794

795

796

797

798

799

800

801

802

803

804

805

806

807

808

809

810

811

812

813

814

815

816

817

818

819

820

821

822

823

824

825

826

827

828

829

830

831

832

833

834

835

836

837

838

839

840

841

842

843

844

845

846

847

848

849

850

851

852

853

854

855

856

857

858

859

860

861

862

863

864

865

866

867

868

869

870

871

872

873

874

875

876

877

878

879

880

881

882

883

884

885

886

887

888

889

890

891

892

893

894

895

896

897

898

899

900

901

902

903

904

905

906

907

908

909

910

911

912

913

914

915

916

917

918

919

920

921

922

923

924

925

926

927

928

929

930

931

932

933

934

935

936

937

938

939

940

941

942

943

944

945

946

947

948

949

950

951

952

953

954

955

956

957

958

959

960

961

962

963

964

965

966

967

968

969

970

971

972

973

974

975

976

977

978

979

980

981

982

983

984

985

986

987

988

989

990

991

992

993

994

""" 

local path implementation. 

""" 

from __future__ import with_statement 

 

from contextlib import contextmanager 

import sys, os, atexit, io, uuid 

import py 

from py._path import common 

from py._path.common import iswin32, fspath 

from stat import S_ISLNK, S_ISDIR, S_ISREG 

 

from os.path import abspath, normpath, isabs, exists, isdir, isfile, islink, dirname 

 

if sys.version_info > (3,0): 

def map_as_list(func, iter): 

return list(map(func, iter)) 

else: 

map_as_list = map 

 

class Stat(object): 

def __getattr__(self, name): 

return getattr(self._osstatresult, "st_" + name) 

 

def __init__(self, path, osstatresult): 

self.path = path 

self._osstatresult = osstatresult 

 

@property 

def owner(self): 

if iswin32: 

raise NotImplementedError("XXX win32") 

import pwd 

entry = py.error.checked_call(pwd.getpwuid, self.uid) 

return entry[0] 

 

@property 

def group(self): 

""" return group name of file. """ 

if iswin32: 

raise NotImplementedError("XXX win32") 

import grp 

entry = py.error.checked_call(grp.getgrgid, self.gid) 

return entry[0] 

 

def isdir(self): 

return S_ISDIR(self._osstatresult.st_mode) 

 

def isfile(self): 

return S_ISREG(self._osstatresult.st_mode) 

 

def islink(self): 

st = self.path.lstat() 

return S_ISLNK(self._osstatresult.st_mode) 

 

class PosixPath(common.PathBase): 

def chown(self, user, group, rec=0): 

""" change ownership to the given user and group. 

user and group may be specified by a number or 

by a name. if rec is True change ownership 

recursively. 

""" 

uid = getuserid(user) 

gid = getgroupid(group) 

if rec: 

for x in self.visit(rec=lambda x: x.check(link=0)): 

if x.check(link=0): 

py.error.checked_call(os.chown, str(x), uid, gid) 

py.error.checked_call(os.chown, str(self), uid, gid) 

 

def readlink(self): 

""" return value of a symbolic link. """ 

return py.error.checked_call(os.readlink, self.strpath) 

 

def mklinkto(self, oldname): 

""" posix style hard link to another name. """ 

py.error.checked_call(os.link, str(oldname), str(self)) 

 

def mksymlinkto(self, value, absolute=1): 

""" create a symbolic link with the given value (pointing to another name). """ 

if absolute: 

py.error.checked_call(os.symlink, str(value), self.strpath) 

else: 

base = self.common(value) 

# with posix local paths '/' is always a common base 

relsource = self.__class__(value).relto(base) 

reldest = self.relto(base) 

n = reldest.count(self.sep) 

target = self.sep.join(('..', )*n + (relsource, )) 

py.error.checked_call(os.symlink, target, self.strpath) 

 

def getuserid(user): 

import pwd 

if not isinstance(user, int): 

user = pwd.getpwnam(user)[2] 

return user 

 

def getgroupid(group): 

import grp 

if not isinstance(group, int): 

group = grp.getgrnam(group)[2] 

return group 

 

FSBase = not iswin32 and PosixPath or common.PathBase 

 

class LocalPath(FSBase): 

""" object oriented interface to os.path and other local filesystem 

related information. 

""" 

class ImportMismatchError(ImportError): 

""" raised on pyimport() if there is a mismatch of __file__'s""" 

 

sep = os.sep 

class Checkers(common.Checkers): 

def _stat(self): 

try: 

return self._statcache 

except AttributeError: 

try: 

self._statcache = self.path.stat() 

except py.error.ELOOP: 

self._statcache = self.path.lstat() 

return self._statcache 

 

def dir(self): 

return S_ISDIR(self._stat().mode) 

 

def file(self): 

return S_ISREG(self._stat().mode) 

 

def exists(self): 

return self._stat() 

 

def link(self): 

st = self.path.lstat() 

return S_ISLNK(st.mode) 

 

def __init__(self, path=None, expanduser=False): 

""" Initialize and return a local Path instance. 

 

Path can be relative to the current directory. 

If path is None it defaults to the current working directory. 

If expanduser is True, tilde-expansion is performed. 

Note that Path instances always carry an absolute path. 

Note also that passing in a local path object will simply return 

the exact same path object. Use new() to get a new copy. 

""" 

if path is None: 

self.strpath = py.error.checked_call(os.getcwd) 

else: 

try: 

path = fspath(path) 

except TypeError: 

raise ValueError("can only pass None, Path instances " 

"or non-empty strings to LocalPath") 

if expanduser: 

path = os.path.expanduser(path) 

self.strpath = abspath(path) 

 

def __hash__(self): 

return hash(self.strpath) 

 

def __eq__(self, other): 

s1 = fspath(self) 

try: 

s2 = fspath(other) 

except TypeError: 

return False 

if iswin32: 

s1 = s1.lower() 

try: 

s2 = s2.lower() 

except AttributeError: 

return False 

return s1 == s2 

 

def __ne__(self, other): 

return not (self == other) 

 

def __lt__(self, other): 

return fspath(self) < fspath(other) 

 

def __gt__(self, other): 

return fspath(self) > fspath(other) 

 

def samefile(self, other): 

""" return True if 'other' references the same file as 'self'. 

""" 

other = fspath(other) 

if not isabs(other): 

other = abspath(other) 

if self == other: 

return True 

if iswin32: 

return False # there is no samefile 

return py.error.checked_call( 

os.path.samefile, self.strpath, other) 

 

def remove(self, rec=1, ignore_errors=False): 

""" remove a file or directory (or a directory tree if rec=1). 

if ignore_errors is True, errors while removing directories will 

be ignored. 

""" 

if self.check(dir=1, link=0): 

if rec: 

# force remove of readonly files on windows 

if iswin32: 

self.chmod(0o700, rec=1) 

import shutil 

py.error.checked_call( 

shutil.rmtree, self.strpath, 

ignore_errors=ignore_errors) 

else: 

py.error.checked_call(os.rmdir, self.strpath) 

else: 

if iswin32: 

self.chmod(0o700) 

py.error.checked_call(os.remove, self.strpath) 

 

def computehash(self, hashtype="md5", chunksize=524288): 

""" return hexdigest of hashvalue for this file. """ 

try: 

try: 

import hashlib as mod 

except ImportError: 

if hashtype == "sha1": 

hashtype = "sha" 

mod = __import__(hashtype) 

hash = getattr(mod, hashtype)() 

except (AttributeError, ImportError): 

raise ValueError("Don't know how to compute %r hash" %(hashtype,)) 

f = self.open('rb') 

try: 

while 1: 

buf = f.read(chunksize) 

if not buf: 

return hash.hexdigest() 

hash.update(buf) 

finally: 

f.close() 

 

def new(self, **kw): 

""" create a modified version of this path. 

the following keyword arguments modify various path parts:: 

 

a:/some/path/to/a/file.ext 

xx drive 

xxxxxxxxxxxxxxxxx dirname 

xxxxxxxx basename 

xxxx purebasename 

xxx ext 

""" 

obj = object.__new__(self.__class__) 

if not kw: 

obj.strpath = self.strpath 

return obj 

drive, dirname, basename, purebasename,ext = self._getbyspec( 

"drive,dirname,basename,purebasename,ext") 

if 'basename' in kw: 

if 'purebasename' in kw or 'ext' in kw: 

raise ValueError("invalid specification %r" % kw) 

else: 

pb = kw.setdefault('purebasename', purebasename) 

try: 

ext = kw['ext'] 

except KeyError: 

pass 

else: 

if ext and not ext.startswith('.'): 

ext = '.' + ext 

kw['basename'] = pb + ext 

 

if ('dirname' in kw and not kw['dirname']): 

kw['dirname'] = drive 

else: 

kw.setdefault('dirname', dirname) 

kw.setdefault('sep', self.sep) 

obj.strpath = normpath( 

"%(dirname)s%(sep)s%(basename)s" % kw) 

return obj 

 

def _getbyspec(self, spec): 

""" see new for what 'spec' can be. """ 

res = [] 

parts = self.strpath.split(self.sep) 

 

args = filter(None, spec.split(',') ) 

append = res.append 

for name in args: 

if name == 'drive': 

append(parts[0]) 

elif name == 'dirname': 

append(self.sep.join(parts[:-1])) 

else: 

basename = parts[-1] 

if name == 'basename': 

append(basename) 

else: 

i = basename.rfind('.') 

if i == -1: 

purebasename, ext = basename, '' 

else: 

purebasename, ext = basename[:i], basename[i:] 

if name == 'purebasename': 

append(purebasename) 

elif name == 'ext': 

append(ext) 

else: 

raise ValueError("invalid part specification %r" % name) 

return res 

 

def dirpath(self, *args, **kwargs): 

""" return the directory path joined with any given path arguments. """ 

if not kwargs: 

path = object.__new__(self.__class__) 

path.strpath = dirname(self.strpath) 

if args: 

path = path.join(*args) 

return path 

return super(LocalPath, self).dirpath(*args, **kwargs) 

 

def join(self, *args, **kwargs): 

""" return a new path by appending all 'args' as path 

components. if abs=1 is used restart from root if any 

of the args is an absolute path. 

""" 

sep = self.sep 

strargs = [fspath(arg) for arg in args] 

strpath = self.strpath 

if kwargs.get('abs'): 

newargs = [] 

for arg in reversed(strargs): 

if isabs(arg): 

strpath = arg 

strargs = newargs 

break 

newargs.insert(0, arg) 

# special case for when we have e.g. strpath == "/" 

actual_sep = "" if strpath.endswith(sep) else sep 

for arg in strargs: 

arg = arg.strip(sep) 

if iswin32: 

# allow unix style paths even on windows. 

arg = arg.strip('/') 

arg = arg.replace('/', sep) 

strpath = strpath + actual_sep + arg 

actual_sep = sep 

obj = object.__new__(self.__class__) 

obj.strpath = normpath(strpath) 

return obj 

 

def open(self, mode='r', ensure=False, encoding=None): 

""" return an opened file with the given mode. 

 

If ensure is True, create parent directories if needed. 

""" 

if ensure: 

self.dirpath().ensure(dir=1) 

if encoding: 

return py.error.checked_call(io.open, self.strpath, mode, encoding=encoding) 

return py.error.checked_call(open, self.strpath, mode) 

 

def _fastjoin(self, name): 

child = object.__new__(self.__class__) 

child.strpath = self.strpath + self.sep + name 

return child 

 

def islink(self): 

return islink(self.strpath) 

 

def check(self, **kw): 

if not kw: 

return exists(self.strpath) 

if len(kw) == 1: 

if "dir" in kw: 

return not kw["dir"] ^ isdir(self.strpath) 

if "file" in kw: 

return not kw["file"] ^ isfile(self.strpath) 

return super(LocalPath, self).check(**kw) 

 

_patternchars = set("*?[" + os.path.sep) 

def listdir(self, fil=None, sort=None): 

""" list directory contents, possibly filter by the given fil func 

and possibly sorted. 

""" 

if fil is None and sort is None: 

names = py.error.checked_call(os.listdir, self.strpath) 

return map_as_list(self._fastjoin, names) 

if isinstance(fil, py.builtin._basestring): 

if not self._patternchars.intersection(fil): 

child = self._fastjoin(fil) 

if exists(child.strpath): 

return [child] 

return [] 

fil = common.FNMatcher(fil) 

names = py.error.checked_call(os.listdir, self.strpath) 

res = [] 

for name in names: 

child = self._fastjoin(name) 

if fil is None or fil(child): 

res.append(child) 

self._sortlist(res, sort) 

return res 

 

def size(self): 

""" return size of the underlying file object """ 

return self.stat().size 

 

def mtime(self): 

""" return last modification time of the path. """ 

return self.stat().mtime 

 

def copy(self, target, mode=False, stat=False): 

""" copy path to target. 

 

If mode is True, will copy copy permission from path to target. 

If stat is True, copy permission, last modification 

time, last access time, and flags from path to target. 

""" 

if self.check(file=1): 

if target.check(dir=1): 

target = target.join(self.basename) 

assert self!=target 

copychunked(self, target) 

if mode: 

copymode(self.strpath, target.strpath) 

if stat: 

copystat(self, target) 

else: 

def rec(p): 

return p.check(link=0) 

for x in self.visit(rec=rec): 

relpath = x.relto(self) 

newx = target.join(relpath) 

newx.dirpath().ensure(dir=1) 

if x.check(link=1): 

newx.mksymlinkto(x.readlink()) 

continue 

elif x.check(file=1): 

copychunked(x, newx) 

elif x.check(dir=1): 

newx.ensure(dir=1) 

if mode: 

copymode(x.strpath, newx.strpath) 

if stat: 

copystat(x, newx) 

 

def rename(self, target): 

""" rename this path to target. """ 

target = fspath(target) 

return py.error.checked_call(os.rename, self.strpath, target) 

 

def dump(self, obj, bin=1): 

""" pickle object into path location""" 

f = self.open('wb') 

import pickle 

try: 

py.error.checked_call(pickle.dump, obj, f, bin) 

finally: 

f.close() 

 

def mkdir(self, *args): 

""" create & return the directory joined with args. """ 

p = self.join(*args) 

py.error.checked_call(os.mkdir, fspath(p)) 

return p 

 

def write_binary(self, data, ensure=False): 

""" write binary data into path. If ensure is True create 

missing parent directories. 

""" 

if ensure: 

self.dirpath().ensure(dir=1) 

with self.open('wb') as f: 

f.write(data) 

 

def write_text(self, data, encoding, ensure=False): 

""" write text data into path using the specified encoding. 

If ensure is True create missing parent directories. 

""" 

if ensure: 

self.dirpath().ensure(dir=1) 

with self.open('w', encoding=encoding) as f: 

f.write(data) 

 

def write(self, data, mode='w', ensure=False): 

""" write data into path. If ensure is True create 

missing parent directories. 

""" 

if ensure: 

self.dirpath().ensure(dir=1) 

if 'b' in mode: 

if not py.builtin._isbytes(data): 

raise ValueError("can only process bytes") 

else: 

if not py.builtin._istext(data): 

if not py.builtin._isbytes(data): 

data = str(data) 

else: 

data = py.builtin._totext(data, sys.getdefaultencoding()) 

f = self.open(mode) 

try: 

f.write(data) 

finally: 

f.close() 

 

def _ensuredirs(self): 

parent = self.dirpath() 

if parent == self: 

return self 

if parent.check(dir=0): 

parent._ensuredirs() 

if self.check(dir=0): 

try: 

self.mkdir() 

except py.error.EEXIST: 

# race condition: file/dir created by another thread/process. 

# complain if it is not a dir 

if self.check(dir=0): 

raise 

return self 

 

def ensure(self, *args, **kwargs): 

""" ensure that an args-joined path exists (by default as 

a file). if you specify a keyword argument 'dir=True' 

then the path is forced to be a directory path. 

""" 

p = self.join(*args) 

if kwargs.get('dir', 0): 

return p._ensuredirs() 

else: 

p.dirpath()._ensuredirs() 

if not p.check(file=1): 

p.open('w').close() 

return p 

 

def stat(self, raising=True): 

""" Return an os.stat() tuple. """ 

if raising == True: 

return Stat(self, py.error.checked_call(os.stat, self.strpath)) 

try: 

return Stat(self, os.stat(self.strpath)) 

except KeyboardInterrupt: 

raise 

except Exception: 

return None 

 

def lstat(self): 

""" Return an os.lstat() tuple. """ 

return Stat(self, py.error.checked_call(os.lstat, self.strpath)) 

 

def setmtime(self, mtime=None): 

""" set modification time for the given path. if 'mtime' is None 

(the default) then the file's mtime is set to current time. 

 

Note that the resolution for 'mtime' is platform dependent. 

""" 

if mtime is None: 

return py.error.checked_call(os.utime, self.strpath, mtime) 

try: 

return py.error.checked_call(os.utime, self.strpath, (-1, mtime)) 

except py.error.EINVAL: 

return py.error.checked_call(os.utime, self.strpath, (self.atime(), mtime)) 

 

def chdir(self): 

""" change directory to self and return old current directory """ 

try: 

old = self.__class__() 

except py.error.ENOENT: 

old = None 

py.error.checked_call(os.chdir, self.strpath) 

return old 

 

 

@contextmanager 

def as_cwd(self): 

""" return context manager which changes to current dir during the 

managed "with" context. On __enter__ it returns the old dir. 

""" 

old = self.chdir() 

try: 

yield old 

finally: 

old.chdir() 

 

def realpath(self): 

""" return a new path which contains no symbolic links.""" 

return self.__class__(os.path.realpath(self.strpath)) 

 

def atime(self): 

""" return last access time of the path. """ 

return self.stat().atime 

 

def __repr__(self): 

return 'local(%r)' % self.strpath 

 

def __str__(self): 

""" return string representation of the Path. """ 

return self.strpath 

 

def chmod(self, mode, rec=0): 

""" change permissions to the given mode. If mode is an 

integer it directly encodes the os-specific modes. 

if rec is True perform recursively. 

""" 

if not isinstance(mode, int): 

raise TypeError("mode %r must be an integer" % (mode,)) 

if rec: 

for x in self.visit(rec=rec): 

py.error.checked_call(os.chmod, str(x), mode) 

py.error.checked_call(os.chmod, self.strpath, mode) 

 

def pypkgpath(self): 

""" return the Python package path by looking for the last 

directory upwards which still contains an __init__.py. 

Return None if a pkgpath can not be determined. 

""" 

pkgpath = None 

for parent in self.parts(reverse=True): 

if parent.isdir(): 

if not parent.join('__init__.py').exists(): 

break 

if not isimportable(parent.basename): 

break 

pkgpath = parent 

return pkgpath 

 

def _ensuresyspath(self, ensuremode, path): 

if ensuremode: 

s = str(path) 

if ensuremode == "append": 

if s not in sys.path: 

sys.path.append(s) 

else: 

if s != sys.path[0]: 

sys.path.insert(0, s) 

 

def pyimport(self, modname=None, ensuresyspath=True): 

""" return path as an imported python module. 

 

If modname is None, look for the containing package 

and construct an according module name. 

The module will be put/looked up in sys.modules. 

if ensuresyspath is True then the root dir for importing 

the file (taking __init__.py files into account) will 

be prepended to sys.path if it isn't there already. 

If ensuresyspath=="append" the root dir will be appended 

if it isn't already contained in sys.path. 

if ensuresyspath is False no modification of syspath happens. 

""" 

if not self.check(): 

raise py.error.ENOENT(self) 

 

pkgpath = None 

if modname is None: 

pkgpath = self.pypkgpath() 

if pkgpath is not None: 

pkgroot = pkgpath.dirpath() 

names = self.new(ext="").relto(pkgroot).split(self.sep) 

if names[-1] == "__init__": 

names.pop() 

modname = ".".join(names) 

else: 

pkgroot = self.dirpath() 

modname = self.purebasename 

 

self._ensuresyspath(ensuresyspath, pkgroot) 

__import__(modname) 

mod = sys.modules[modname] 

if self.basename == "__init__.py": 

return mod # we don't check anything as we might 

# be in a namespace package ... too icky to check 

modfile = mod.__file__ 

if modfile[-4:] in ('.pyc', '.pyo'): 

modfile = modfile[:-1] 

elif modfile.endswith('$py.class'): 

modfile = modfile[:-9] + '.py' 

if modfile.endswith(os.path.sep + "__init__.py"): 

if self.basename != "__init__.py": 

modfile = modfile[:-12] 

try: 

issame = self.samefile(modfile) 

except py.error.ENOENT: 

issame = False 

if not issame: 

ignore = os.getenv('PY_IGNORE_IMPORTMISMATCH') 

if ignore != '1': 

raise self.ImportMismatchError(modname, modfile, self) 

return mod 

else: 

try: 

return sys.modules[modname] 

except KeyError: 

# we have a custom modname, do a pseudo-import 

import types 

mod = types.ModuleType(modname) 

mod.__file__ = str(self) 

sys.modules[modname] = mod 

try: 

py.builtin.execfile(str(self), mod.__dict__) 

except: 

del sys.modules[modname] 

raise 

return mod 

 

def sysexec(self, *argv, **popen_opts): 

""" return stdout text from executing a system child process, 

where the 'self' path points to executable. 

The process is directly invoked and not through a system shell. 

""" 

from subprocess import Popen, PIPE 

argv = map_as_list(str, argv) 

popen_opts['stdout'] = popen_opts['stderr'] = PIPE 

proc = Popen([str(self)] + argv, **popen_opts) 

stdout, stderr = proc.communicate() 

ret = proc.wait() 

if py.builtin._isbytes(stdout): 

stdout = py.builtin._totext(stdout, sys.getdefaultencoding()) 

if ret != 0: 

if py.builtin._isbytes(stderr): 

stderr = py.builtin._totext(stderr, sys.getdefaultencoding()) 

raise py.process.cmdexec.Error(ret, ret, str(self), 

stdout, stderr,) 

return stdout 

 

def sysfind(cls, name, checker=None, paths=None): 

""" return a path object found by looking at the systems 

underlying PATH specification. If the checker is not None 

it will be invoked to filter matching paths. If a binary 

cannot be found, None is returned 

Note: This is probably not working on plain win32 systems 

but may work on cygwin. 

""" 

if isabs(name): 

p = py.path.local(name) 

if p.check(file=1): 

return p 

else: 

if paths is None: 

if iswin32: 

paths = os.environ['Path'].split(';') 

if '' not in paths and '.' not in paths: 

paths.append('.') 

try: 

systemroot = os.environ['SYSTEMROOT'] 

except KeyError: 

pass 

else: 

paths = [path.replace('%SystemRoot%', systemroot) 

for path in paths] 

else: 

paths = os.environ['PATH'].split(':') 

tryadd = [] 

if iswin32: 

tryadd += os.environ['PATHEXT'].split(os.pathsep) 

tryadd.append("") 

 

for x in paths: 

for addext in tryadd: 

p = py.path.local(x).join(name, abs=True) + addext 

try: 

if p.check(file=1): 

if checker: 

if not checker(p): 

continue 

return p 

except py.error.EACCES: 

pass 

return None 

sysfind = classmethod(sysfind) 

 

def _gethomedir(cls): 

try: 

x = os.environ['HOME'] 

except KeyError: 

try: 

x = os.environ["HOMEDRIVE"] + os.environ['HOMEPATH'] 

except KeyError: 

return None 

return cls(x) 

_gethomedir = classmethod(_gethomedir) 

 

# """ 

# special class constructors for local filesystem paths 

# """ 

@classmethod 

def get_temproot(cls): 

""" return the system's temporary directory 

(where tempfiles are usually created in) 

""" 

import tempfile 

return py.path.local(tempfile.gettempdir()) 

 

@classmethod 

def mkdtemp(cls, rootdir=None): 

""" return a Path object pointing to a fresh new temporary directory 

(which we created ourself). 

""" 

import tempfile 

if rootdir is None: 

rootdir = cls.get_temproot() 

return cls(py.error.checked_call(tempfile.mkdtemp, dir=str(rootdir))) 

 

def make_numbered_dir(cls, prefix='session-', rootdir=None, keep=3, 

lock_timeout=172800): # two days 

""" return unique directory with a number greater than the current 

maximum one. The number is assumed to start directly after prefix. 

if keep is true directories with a number less than (maxnum-keep) 

will be removed. If .lock files are used (lock_timeout non-zero), 

algorithm is multi-process safe. 

""" 

if rootdir is None: 

rootdir = cls.get_temproot() 

 

nprefix = prefix.lower() 

def parse_num(path): 

""" parse the number out of a path (if it matches the prefix) """ 

nbasename = path.basename.lower() 

if nbasename.startswith(nprefix): 

try: 

return int(nbasename[len(nprefix):]) 

except ValueError: 

pass 

 

def create_lockfile(path): 

""" exclusively create lockfile. Throws when failed """ 

mypid = os.getpid() 

lockfile = path.join('.lock') 

if hasattr(lockfile, 'mksymlinkto'): 

lockfile.mksymlinkto(str(mypid)) 

else: 

fd = py.error.checked_call(os.open, str(lockfile), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644) 

with os.fdopen(fd, 'w') as f: 

f.write(str(mypid)) 

return lockfile 

 

def atexit_remove_lockfile(lockfile): 

""" ensure lockfile is removed at process exit """ 

mypid = os.getpid() 

def try_remove_lockfile(): 

# in a fork() situation, only the last process should 

# remove the .lock, otherwise the other processes run the 

# risk of seeing their temporary dir disappear. For now 

# we remove the .lock in the parent only (i.e. we assume 

# that the children finish before the parent). 

if os.getpid() != mypid: 

return 

try: 

lockfile.remove() 

except py.error.Error: 

pass 

atexit.register(try_remove_lockfile) 

 

# compute the maximum number currently in use with the prefix 

lastmax = None 

while True: 

maxnum = -1 

for path in rootdir.listdir(): 

num = parse_num(path) 

if num is not None: 

maxnum = max(maxnum, num) 

 

# make the new directory 

try: 

udir = rootdir.mkdir(prefix + str(maxnum+1)) 

if lock_timeout: 

lockfile = create_lockfile(udir) 

atexit_remove_lockfile(lockfile) 

except (py.error.EEXIST, py.error.ENOENT, py.error.EBUSY): 

# race condition (1): another thread/process created the dir 

# in the meantime - try again 

# race condition (2): another thread/process spuriously acquired 

# lock treating empty directory as candidate 

# for removal - try again 

# race condition (3): another thread/process tried to create the lock at 

# the same time (happened in Python 3.3 on Windows) 

# https://ci.appveyor.com/project/pytestbot/py/build/1.0.21/job/ffi85j4c0lqwsfwa 

if lastmax == maxnum: 

raise 

lastmax = maxnum 

continue 

break 

 

def get_mtime(path): 

""" read file modification time """ 

try: 

return path.lstat().mtime 

except py.error.Error: 

pass 

 

garbage_prefix = prefix + 'garbage-' 

 

def is_garbage(path): 

""" check if path denotes directory scheduled for removal """ 

bn = path.basename 

return bn.startswith(garbage_prefix) 

 

# prune old directories 

udir_time = get_mtime(udir) 

if keep and udir_time: 

for path in rootdir.listdir(): 

num = parse_num(path) 

if num is not None and num <= (maxnum - keep): 

try: 

# try acquiring lock to remove directory as exclusive user 

if lock_timeout: 

create_lockfile(path) 

except (py.error.EEXIST, py.error.ENOENT, py.error.EBUSY): 

path_time = get_mtime(path) 

if not path_time: 

# assume directory doesn't exist now 

continue 

if abs(udir_time - path_time) < lock_timeout: 

# assume directory with lockfile exists 

# and lock timeout hasn't expired yet 

continue 

 

# path dir locked for exclusive use 

# and scheduled for removal to avoid another thread/process 

# treating it as a new directory or removal candidate 

garbage_path = rootdir.join(garbage_prefix + str(uuid.uuid4())) 

try: 

path.rename(garbage_path) 

garbage_path.remove(rec=1) 

except KeyboardInterrupt: 

raise 

except: # this might be py.error.Error, WindowsError ... 

pass 

if is_garbage(path): 

try: 

path.remove(rec=1) 

except KeyboardInterrupt: 

raise 

except: # this might be py.error.Error, WindowsError ... 

pass 

 

# make link... 

try: 

username = os.environ['USER'] #linux, et al 

except KeyError: 

try: 

username = os.environ['USERNAME'] #windows 

except KeyError: 

username = 'current' 

 

src = str(udir) 

dest = src[:src.rfind('-')] + '-' + username 

try: 

os.unlink(dest) 

except OSError: 

pass 

try: 

os.symlink(src, dest) 

except (OSError, AttributeError, NotImplementedError): 

pass 

 

return udir 

make_numbered_dir = classmethod(make_numbered_dir) 

 

 

def copymode(src, dest): 

""" copy permission from src to dst. """ 

import shutil 

shutil.copymode(src, dest) 

 

 

def copystat(src, dest): 

""" copy permission, last modification time, 

last access time, and flags from src to dst.""" 

import shutil 

shutil.copystat(str(src), str(dest)) 

 

 

def copychunked(src, dest): 

chunksize = 524288 # half a meg of bytes 

fsrc = src.open('rb') 

try: 

fdest = dest.open('wb') 

try: 

while 1: 

buf = fsrc.read(chunksize) 

if not buf: 

break 

fdest.write(buf) 

finally: 

fdest.close() 

finally: 

fsrc.close() 

 

 

def isimportable(name): 

if name and (name[0].isalpha() or name[0] == '_'): 

name = name.replace("_", '') 

return not name or name.isalnum()