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

995

996

997

998

999

1000

1001

1002

1003

1004

1005

1006

1007

1008

1009

1010

1011

1012

1013

1014

1015

1016

1017

1018

1019

1020

1021

1022

1023

1024

1025

1026

1027

1028

1029

1030

1031

1032

1033

1034

1035

1036

1037

1038

1039

1040

1041

1042

1043

1044

1045

1046

1047

1048

1049

1050

1051

1052

1053

1054

1055

1056

1057

1058

1059

1060

1061

1062

1063

1064

1065

1066

1067

1068

1069

1070

1071

1072

1073

1074

1075

1076

1077

1078

1079

1080

1081

1082

1083

1084

1085

1086

1087

1088

1089

1090

1091

1092

1093

1094

1095

1096

1097

1098

1099

1100

1101

1102

1103

1104

1105

1106

1107

1108

1109

1110

1111

1112

1113

1114

1115

1116

1117

1118

1119

1120

1121

1122

1123

1124

1125

1126

1127

1128

1129

1130

1131

1132

1133

1134

1135

1136

1137

1138

1139

1140

1141

1142

1143

1144

1145

1146

1147

1148

1149

1150

1151

1152

1153

1154

1155

1156

1157

1158

1159

1160

1161

1162

1163

1164

1165

1166

1167

1168

1169

1170

1171

1172

1173

1174

1175

1176

1177

1178

1179

1180

1181

1182

1183

1184

1185

1186

1187

1188

1189

1190

1191

1192

1193

1194

1195

1196

1197

1198

1199

1200

1201

1202

1203

1204

1205

1206

1207

1208

1209

1210

1211

1212

1213

1214

1215

1216

1217

1218

1219

1220

1221

1222

1223

1224

1225

1226

1227

1228

1229

1230

1231

1232

1233

1234

1235

1236

1237

1238

1239

1240

1241

1242

1243

1244

1245

1246

1247

1248

1249

1250

1251

1252

1253

1254

1255

1256

1257

1258

1259

1260

1261

1262

1263

1264

1265

1266

1267

1268

1269

1270

1271

1272

1273

1274

1275

1276

1277

1278

1279

1280

1281

1282

1283

1284

1285

1286

1287

1288

1289

1290

1291

1292

1293

1294

1295

1296

1297

1298

1299

1300

1301

1302

1303

1304

1305

1306

1307

1308

1309

1310

1311

1312

1313

1314

1315

1316

1317

1318

1319

1320

1321

1322

1323

1324

1325

1326

1327

1328

1329

1330

1331

1332

1333

1334

1335

1336

1337

1338

1339

1340

1341

1342

1343

1344

1345

1346

1347

1348

1349

1350

1351

1352

1353

1354

1355

1356

1357

1358

1359

1360

1361

1362

1363

1364

1365

1366

1367

1368

1369

1370

1371

1372

1373

1374

1375

1376

1377

1378

1379

1380

1381

1382

1383

1384

1385

1386

1387

1388

1389

1390

1391

1392

1393

1394

1395

1396

1397

1398

1399

1400

1401

1402

1403

1404

1405

1406

1407

1408

1409

1410

1411

1412

1413

1414

1415

1416

1417

1418

1419

1420

1421

1422

1423

1424

1425

1426

1427

1428

1429

1430

1431

1432

1433

1434

1435

1436

1437

1438

1439

1440

1441

1442

1443

1444

1445

1446

1447

1448

1449

1450

1451

1452

1453

1454

1455

1456

1457

1458

1459

1460

1461

1462

1463

1464

1465

1466

1467

1468

1469

1470

1471

1472

1473

1474

1475

1476

1477

1478

1479

1480

1481

1482

1483

1484

1485

1486

1487

1488

1489

1490

1491

1492

1493

1494

1495

1496

1497

# -*- coding: utf-8 -*- 

""" 

Common Interface Functionality through Pexpect 

 

See the examples in the other sections for how to use specific 

interfaces. The interface classes all derive from the generic 

interface that is described in this section. 

 

AUTHORS: 

 

- William Stein (2005): initial version 

 

- William Stein (2006-03-01): got rid of infinite loop on startup if 

client system missing 

 

- Felix Lawrence (2009-08-21): edited ._sage_() to support lists and float exponents in foreign notation. 

 

- Simon King (2010-09-25): Expect._local_tmpfile() depends on 

Expect.pid() and is cached; Expect.quit() clears that cache, 

which is important for forking. 

 

- Jean-Pierre Flori (2010,2011): Split non Pexpect stuff into a parent class. 

 

- Simon King (2010-11-23): Ensure that the interface is started again 

after a crash, when a command is executed in _eval_line. Allow 

synchronisation of the GAP interface. 

 

- François Bissey, Bill Page, Jeroen Demeyer (2015-12-09): Upgrade to 

pexpect 4.0.1 + patches, see :trac:`10295`. 

""" 

 

#***************************************************************************** 

# Copyright (C) 2005 William Stein <wstein@gmail.com> 

# 

# This program is free software: you can redistribute it and/or modify 

# it under the terms of the GNU General Public License as published by 

# the Free Software Foundation, either version 2 of the License, or 

# (at your option) any later version. 

# http://www.gnu.org/licenses/ 

#***************************************************************************** 

from __future__ import print_function, absolute_import 

from six import string_types 

 

import os 

import signal 

import sys 

import weakref 

import time 

import gc 

from . import quit 

from . import cleaner 

from random import randrange 

 

import pexpect 

from pexpect import ExceptionPexpect 

from sage.interfaces.sagespawn import SageSpawn 

from sage.interfaces.interface import (Interface, InterfaceElement, 

InterfaceFunction, InterfaceFunctionElement, AsciiArtString) 

 

from sage.structure.element import RingElement 

 

from sage.misc.misc import SAGE_TMP_INTERFACE 

from sage.env import SAGE_EXTCODE, LOCAL_IDENTIFIER 

from sage.misc.object_multiplexer import Multiplex 

from sage.docs.instancedoc import instancedoc 

 

from six import reraise as raise_ 

 

BAD_SESSION = -2 

 

# The subprocess is a shared resource. In a multi-threaded 

# environment, there would have to be a lock to control access to the 

# subprocess. Fortunately, Sage does not use Python threads. 

# Unfortunately, the combination of the garbage collector and __del__ 

# methods gives rise to the same issues. So, in places where we need 

# to do a sequence of operations on the subprocess and make sure 

# nothing else intervenes (for example, when we write a command and 

# then read back the result) we need to disable the garbage collector. 

# See TRAC #955 for a more detailed description of this problem. 

 

# To turn off the garbage collector for a particular region of code, 

# do: 

# with gc_disabled(): 

# ... your code goes here ... 

# The garbage collector will be returned to its original state 

# whenever the code exits by any means (falling off the end, executing 

# "return", "break", or "continue", raising an exception, ...) 

 

 

class gc_disabled(object): 

""" 

This is a "with" statement context manager. Garbage collection is 

disabled within its scope. Nested usage is properly handled. 

 

EXAMPLES:: 

 

sage: import gc 

sage: from sage.interfaces.expect import gc_disabled 

sage: gc.isenabled() 

True 

sage: with gc_disabled(): 

....: print(gc.isenabled()) 

....: with gc_disabled(): 

....: print(gc.isenabled()) 

....: print(gc.isenabled()) 

False 

False 

False 

sage: gc.isenabled() 

True 

""" 

def __enter__(self): 

self._enabled = gc.isenabled() 

gc.disable() 

 

def __exit__(self, ty, val, tb): 

if self._enabled: 

gc.enable() 

return False 

 

 

class Expect(Interface): 

""" 

Expect interface object. 

""" 

def __init__(self, name, prompt, command=None, env={}, server=None, 

server_tmpdir=None, 

ulimit = None, maxread=None, 

script_subdirectory=None, restart_on_ctrlc=False, 

verbose_start=False, init_code=[], max_startup_time=None, 

logfile = None, eval_using_file_cutoff=0, 

do_cleaner=True, remote_cleaner=False, path=None, 

terminal_echo=True): 

 

Interface.__init__(self, name) 

 

# Read environment variables 

env_name = 'SAGE_%s_{}'%self.name().upper() 

import os 

if server is None: 

server = os.getenv(env_name.format('SERVER')) 

if server_tmpdir is None: 

server_tmpdir = os.getenv(env_name.format('TMPDIR')) 

if command is None: 

command = os.getenv(env_name.format('COMMAND')) 

if script_subdirectory is None: 

script_subdirectory = os.getenv(env_name.format('SCRIPT_SUBDIRECTORY')) 

self.__is_remote = False 

self.__remote_cleaner = remote_cleaner 

self._expect = None 

self._eval_using_file_cutoff = eval_using_file_cutoff 

self.__verbose_start = verbose_start 

self.set_server_and_command(server, command, server_tmpdir, ulimit) 

self._env = env 

self.__do_cleaner = do_cleaner 

self._prompt = prompt 

self._restart_on_ctrlc = restart_on_ctrlc 

if path is not None: 

self.__path = os.path.abspath(path) 

elif script_subdirectory is None: 

self.__path = os.getcwd() 

else: 

self.__path = os.path.join(SAGE_EXTCODE, name, script_subdirectory) 

if not os.path.isdir(self.__path): 

raise EnvironmentError("path %r does not exist" % self.__path) 

self.__initialized = False 

self.__seq = -1 

self._session_number = 0 

self.__init_code = init_code 

 

#Handle the log file 

if isinstance(logfile, string_types): 

self.__logfile = None 

self.__logfilename = logfile 

else: 

self.__logfile = logfile 

self.__logfilename = None 

 

quit.expect_objects.append(weakref.ref(self)) 

self._available_vars = [] 

self._terminal_echo = terminal_echo 

 

def set_server_and_command(self, server=None, command=None, server_tmpdir=None, ulimit=None): 

""" 

Changes the server and the command to use for this interface. 

This raises a Runtime error if the interface is already started. 

 

EXAMPLES:: 

 

sage: magma.set_server_and_command(server = 'remote', command = 'mymagma') # indirect doctest 

No remote temporary directory (option server_tmpdir) specified, using /tmp/ on remote 

sage: magma.server() 

'remote' 

sage: magma.command() 

"sage-native-execute ssh -t remote 'mymagma'" 

""" 

if self._expect: 

raise RuntimeError("interface has already started") 

if command is None: 

command = self.name() 

self._server = server 

if server is not None: 

if ulimit: 

command = "sage-native-execute ssh -t %s 'ulimit %s; %s'"%(server, ulimit, command) 

else: 

command = "sage-native-execute ssh -t %s '%s'"%(server, command) 

self.__is_remote = True 

self._eval_using_file_cutoff = 0 # don't allow this! 

if self.__verbose_start: 

print("Using remote server") 

print(command) 

if server_tmpdir is None: 

# TO DO: Why default to /tmp/? Might be better to use the expect process itself to get a tmp folder 

print("No remote temporary directory (option server_tmpdir) specified, using /tmp/ on "+server) 

self.__remote_tmpdir = "/tmp/" 

else: 

self.__remote_tmpdir = server_tmpdir 

else: 

self.__is_remote = False 

self.__command = command 

 

def server(self): 

""" 

Returns the server used in this interface. 

 

EXAMPLES:: 

 

sage: magma.set_server_and_command(server = 'remote') 

No remote temporary directory (option server_tmpdir) specified, using /tmp/ on remote 

sage: magma.server() # indirect doctest 

'remote' 

""" 

return self._server 

 

def command(self): 

""" 

Returns the command used in this interface. 

 

EXAMPLES:: 

 

sage: magma.set_server_and_command(command = 'magma-2.19') 

sage: magma.command() # indirect doctest 

'magma-2.19' 

""" 

return self.__command 

 

def _get(self, wait=0.1, alternate_prompt=None): 

if self._expect is None: 

self._start() 

E = self._expect 

wait = float(wait) 

try: 

if alternate_prompt is None: 

E.expect(self._prompt, timeout=wait) 

else: 

E.expect(alternate_prompt, timeout=wait) 

except pexpect.TIMEOUT: 

return False, E.before 

except pexpect.EOF: 

return True, E.before 

except Exception: # weird major problem! 

return True, E.before 

return True, E.before 

 

def _send(self, cmd): 

if self._expect is None: 

self._start() 

E = self._expect 

self.__so_far = '' 

E.sendline(cmd) 

 

def is_running(self): 

""" 

Return True if self is currently running. 

""" 

if self._expect is None: 

return False 

try: 

os.kill(self._expect.pid,0) 

except OSError: 

# This means the process is not running 

return False 

return True 

 

def _so_far(self, wait=0.1, alternate_prompt=None): 

""" 

Return whether done and output so far and new output since last 

time called. 

""" 

done, new = self._get(wait=wait, alternate_prompt=alternate_prompt) 

try: 

if done: 

#if new is not None: 

X = self.__so_far + new 

del self.__so_far 

return True, X, new 

#new = self._expect.before 

try: 

self.__so_far += new 

except (AttributeError, TypeError): 

self.__so_far = new 

return False, self.__so_far, new 

except AttributeError as msg: # no __so_far 

raise RuntimeError(msg) 

 

def is_remote(self): 

return self.__is_remote 

 

def is_local(self): 

return not self.__is_remote 

 

def user_dir(self): 

return self.__path 

 

def _change_prompt(self, prompt): 

self._prompt = prompt 

 

def path(self): 

return self.__path 

 

def expect(self): 

if self._expect is None: 

self._start() 

return self._expect 

 

def pid(self): 

""" 

Return the PID of the underlying sub-process. 

 

REMARK: 

 

If the interface terminates unexpectedly, the original 

PID will still be used. But if it was terminated using 

:meth:`quit`, a new sub-process with a new PID is 

automatically started. 

 

EXAMPLES:: 

 

sage: pid = gap.pid() 

sage: gap.eval('quit;') 

'' 

sage: pid == gap.pid() 

True 

sage: gap.quit() 

sage: pid == gap.pid() 

False 

 

""" 

if self._expect is None: 

self._start() 

return self._expect.pid 

 

def _install_hints(self): 

r""" 

Hints for installing needed slave program on your computer. 

 

There are no hints by default. 

""" 

return '' 

 

def _install_hints_ssh(self): 

r""" 

Hints for installing passwordless authentication on your 

computer... 

""" 

# Written by Paul-Olivier Dehaye 2007/08/23 

return """ 

In order for Sage (on "local") to launch a "slave" process on "remote", the following command needs to work from local's console, without the need to enter any password: 

 

"ssh -t remote slave", 

 

where "slave" could be "math" (for text-mode Mathematica), "gap", "magma", "sage", "maple", etc. 

 

This thus requires passwordless authentication to be setup, which can be done with commands like these: 

cd; ssh-keygen -t rsa; scp .ssh/id_rsa.pub remote:.ssh/authorized_keys2\n 

(WARNING: this would overwrite your current list of authorized keys on "remote") 

 

In many cases, the server that can actually run "slave" is not accessible from the internet directly, but you have to hop through an intermediate trusted server, say "gate". 

If that is your case, get help with _install_hints_ssh_through_gate(). 

 

""" 

 

def _install_hints_ssh_through_gate(self): 

r""" 

Hints for installing passwordless authentication through a gate 

""" 

# Written by Paul-Olivier Dehaye 2007/08/23 

return """ 

 

We assume you would like to run a "slave" process on a machine called "remote" from a machine running Sage called "local". We also assume "remote" can only be accessed from "local" by ssh'ing first to "gate" (this is a fairly common setup). Sometimes, "gate" and "remote" have a shared filesystem, and this helps a bit. 

 

Note: You cannot just create shell scripts on "local" and "gate" that would use two successive SSH connections to "remote" in order to simulate running "slave" locally. This is because Sage will sometimes use files (and scp) to communicate with "remote", which shell scripts would not take care of. 

 

You need to setup: 

* passwordless authentication to "gate" from "local" 

* add passwordless authentication to "remote" from "local", 

for instance by appending the file local:~/.ssh/id_rsa.pub to remote:~/.ssh/authorized_keys2 and logging in once 

(this is only needed if "remote" and "gate" don\'t share filesystem) 

* add a few lines to your local:~/.ssh/ssh_config. Mine look like 

 

Host remote_for_sage 

ProxyCommand ssh gate nc -w 1 remote 22 

 

That's it, normally. 

 

The last step tells ssh that whenever an ssh connection is required to 

the host "remote_for_sage", it should tunnel it through "gate". Any 

attempt to scp-connect to "remote_for_sage" will use ssh and thus 

this configuration file, and properly channel those file transfers 

through the tunnel. 

 

A good test is to attempt an scp connection from the command-line 

of "local" to "remote_for_sage" as if no tunnel through "gate" was 

required. No password should be asked for the second time around. 

 

Finally, we created the new name "remote_for_sage" for "remote", 

but this name only exists locally. this is to avoid interfering 

with any other program that might already ssh to "remote" in 

their own way. 

 

If this all works, you can then make calls like: 

math = Mathematica(server="remote_for_sage") 

 

""" 

 

 

def _do_cleaner(self): 

try: 

return self.__do_cleaner 

except AttributeError: 

return False 

 

def _start(self, alt_message=None, block_during_init=True): 

from sage.misc.misc import sage_makedirs 

self.quit() # in case one is already running 

 

self._session_number += 1 

 

if self.__logfile is None: 

# If the 'SAGE_PEXPECT_LOG' environment variable is set and 

# there is no logfile already defined, then create a 

# logfile in .sage/pexpect_logs/ 

if self.__logfilename is None and 'SAGE_PEXPECT_LOG' in os.environ: 

from sage.env import DOT_SAGE 

logs = os.path.join(DOT_SAGE, 'pexpect_logs') 

sage_makedirs(logs) 

 

self.__logfilename = '%s/%s-%s-%s-%s.log'%(logs, self.name(), os.getpid(), id(self), self._session_number) 

if self.__logfilename is not None: 

self.__logfile = open(self.__logfilename, 'w') 

 

cmd = self.__command 

 

if self.__verbose_start: 

print(cmd) 

print("Starting %s" % cmd.split()[0]) 

 

if self.__remote_cleaner and self._server: 

c = 'sage-native-execute ssh %s "nohup sage -cleaner" &'%self._server 

os.system(c) 

 

# Unset some environment variables for the children to 

# reduce the chances they do something complicated breaking 

# the terminal interface. 

# See Trac #12221 and #13859. 

pexpect_env = dict(os.environ) 

pexpect_env.update(self._env) 

pexpect_del_vars = ['TERM', 'COLUMNS'] 

for i in pexpect_del_vars: 

try: 

del pexpect_env[i] 

except KeyError: 

pass 

 

# Run child from self.__path 

currentdir = os.getcwd() 

os.chdir(self.__path) 

try: 

try: 

self._expect = SageSpawn(cmd, 

logfile=self.__logfile, 

timeout=None, # no timeout 

env=pexpect_env, 

name=self._repr_(), 

echo=self._terminal_echo, 

# Work around https://bugs.python.org/issue1652 

preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL), 

quit_string=self._quit_string()) 

except (ExceptionPexpect, pexpect.EOF) as e: 

# Change pexpect errors to RuntimeError 

raise RuntimeError("unable to start %s because the command %r failed: %s\n%s" % 

(self.name(), cmd, e, self._install_hints())) 

except BaseException: 

self._expect = None 

self._session_number = BAD_SESSION 

raise 

finally: 

os.chdir(currentdir) 

 

if self._do_cleaner(): 

cleaner.cleaner(self._expect.pid, cmd) 

 

try: 

self._expect.expect(self._prompt) 

except (pexpect.TIMEOUT, pexpect.EOF): 

self._expect = None 

self._session_number = BAD_SESSION 

raise RuntimeError("unable to start %s" % self.name()) 

self._expect.timeout = None 

 

with gc_disabled(): 

if block_during_init: 

for X in self.__init_code: 

self.eval(X) 

else: 

for X in self.__init_code: 

self._send(X) 

 

 

def clear_prompts(self): 

while True: 

try: 

self._expect.expect(self._prompt, timeout=0.1) 

except pexpect.TIMEOUT: 

return 

 

def _reset_expect(self): 

""" 

Delete ``self._expect`` and reset any state. 

 

This is called by :meth:`quit` and :meth:`detach`. 

 

EXAMPLES:: 

 

sage: gp("eulerphi(49)") 

42 

sage: print(gp._expect) 

PARI/GP interpreter with PID ... 

sage: gp._reset_expect() 

sage: print(gp._expect) 

None 

sage: gp("eulerphi(49)") 

42 

""" 

self._session_number += 1 

try: 

del self.__local_tmpfile 

except AttributeError: 

pass 

self._expect = None 

 

def quit(self, verbose=False): 

""" 

Quit the running subprocess. 

 

INPUT: 

 

- ``verbose`` -- (boolean, default ``False``) print a message 

when quitting this process? 

 

EXAMPLES:: 

 

sage: a = maxima('y') 

sage: maxima.quit(verbose=True) 

Exiting Maxima with PID ... running .../bin/maxima ... 

sage: a._check_valid() 

Traceback (most recent call last): 

... 

ValueError: The maxima session in which this object was defined is no longer running. 

 

Calling ``quit()`` a second time does nothing:: 

 

sage: maxima.quit(verbose=True) 

""" 

if self._expect is not None: 

if verbose: 

if self.is_remote(): 

print("Exiting %r (running on %s)" % (self._expect, self._server)) 

else: 

print("Exiting %r" % (self._expect,)) 

self._expect.close() 

self._reset_expect() 

 

def detach(self): 

""" 

Forget the running subprocess: keep it running but pretend that 

it's no longer running. 

 

EXAMPLES:: 

 

sage: a = maxima('y') 

sage: saved_expect = maxima._expect # Save this to close later 

sage: maxima.detach() 

sage: a._check_valid() 

Traceback (most recent call last): 

... 

ValueError: The maxima session in which this object was defined is no longer running. 

sage: saved_expect.close() # Close child process 

 

Calling ``detach()`` a second time does nothing:: 

 

sage: maxima.detach() 

""" 

try: 

self._expect._keep_alive() 

except AttributeError: 

pass 

self._reset_expect() 

 

def _quit_string(self): 

""" 

Return the string which will be used to quit the application. 

 

EXAMPLES:: 

 

sage: gp._quit_string() 

'\\q' 

sage: maxima._quit_string() 

'quit();' 

""" 

return 'quit' 

 

def _send_interrupt(self): 

""" 

Send an interrupt to the application. This is used internally 

by :meth:`interrupt`. 

 

First CTRL-C to stop the current command, then quit. 

""" 

self._expect.sendline(chr(3)) 

self._expect.sendline(self._quit_string()) 

 

def _local_tmpfile(self): 

""" 

Return a filename that is used to buffer long command lines for this interface 

 

INPUT: 

 

``e`` -- an expect interface instance 

 

OUTPUT: 

 

A string that provides a temporary filename and is unique for the 

given interface. 

 

TESTS: 

 

The filename is cached:: 

 

sage: gap._local_tmpfile() is gap._local_tmpfile() 

True 

 

The following two problems were fixed in :trac:`10004`. 

 

1. Different interfaces have different temp-files:: 

 

sage: gap._local_tmpfile() != singular._local_tmpfile() 

True 

 

2. Interface instances in different branches of a parallelised 

function have different temp-files:: 

 

sage: @parallel 

....: def f(n): 

....: return gap._local_tmpfile() 

sage: L = [t[1] for t in f(list(range(5)))] 

sage: len(set(L)) 

5 

 

The following used to fail:: 

 

sage: s = gap._local_tmpfile() 

sage: L = [t[1] for t in f(list(range(5)))] 

sage: len(set(L)) 

5 

 

AUTHOR: 

 

- Simon King (2010-09): Making the tmp-file unique for the interface instance 

 

""" 

try: 

return self.__local_tmpfile 

except AttributeError: 

self.__local_tmpfile = os.path.join(SAGE_TMP_INTERFACE, 'tmp' + str(self.pid())) 

return self.__local_tmpfile 

 

def _remote_tmpdir(self): 

return self.__remote_tmpdir 

 

def _remote_tmpfile(self): 

try: 

return self.__remote_tmpfile 

except AttributeError: 

self.__remote_tmpfile = self._remote_tmpdir()+"/interface_%s:%s"%(LOCAL_IDENTIFIER,self.pid()) 

return self.__remote_tmpfile 

 

def _send_tmpfile_to_server(self, local_file=None, remote_file=None): 

if local_file is None: 

local_file = self._local_tmpfile() 

if remote_file is None: 

remote_file = self._remote_tmpfile() 

cmd = 'scp "%s" %s:"%s" 1>&2 2>/dev/null'%(local_file, self._server, remote_file) 

os.system(cmd) 

 

def _get_tmpfile_from_server(self, local_file=None,remote_file=None): 

if local_file is None: 

local_file = self._local_tmpfile() 

if remote_file is None: 

remote_file = self._remote_tmpfile() 

cmd = 'scp %s:"%s" "%s" 1>&2 2>/dev/null'%( self._server, remote_file, local_file) 

os.system(cmd) 

 

def _remove_tmpfile_from_server(self): 

if not (self.__remote_tmpfile is None): 

raise NotImplementedError 

 

def _eval_line_using_file(self, line, restart_if_needed=True): 

""" 

Evaluate a line of commands, using a temporary file. 

 

REMARK: 

 

By default, this is called when a long command is 

evaluated in :meth:`eval`. 

 

If the command can not be evaluated since the interface 

has crashed, it is automatically restarted and tried 

again *once*. 

 

INPUT: 

 

- ``line`` -- (string) a command. 

- ``restart_if_needed`` - (optional bool, default ``True``) -- 

If it is ``True``, the command evaluation is evaluated 

a second time after restarting the interface, if an 

``EOFError`` occured. 

 

TESTS:: 

 

sage: singular._eval_line_using_file('def a=3;') 

'' 

sage: singular('a') 

3 

sage: singular.eval('quit;') 

'' 

sage: singular._eval_line_using_file('def a=3;') 

Singular crashed -- automatically restarting. 

'' 

sage: singular('a') 

3 

sage: singular.eval('quit;') 

'' 

sage: singular._eval_line_using_file('def a=3;', restart_if_needed=False) 

Traceback (most recent call last): 

... 

RuntimeError: Singular terminated unexpectedly while reading in a large line... 

 

We end by triggering a re-start of Singular, since otherwise 

the doc test of another method would fail by a side effect. 

:: 

 

sage: singular(3) 

Singular crashed -- automatically restarting. 

3 

 

""" 

with open(self._local_tmpfile(), 'w') as F: 

F.write(line + '\n') 

 

tmp_to_use = self._local_tmpfile() 

if self.is_remote(): 

self._send_tmpfile_to_server() 

tmp_to_use = self._remote_tmpfile() 

try: 

s = self._eval_line(self._read_in_file_command(tmp_to_use), allow_use_file=False, restart_if_needed=False) 

except pexpect.EOF as msg: 

if self._quit_string() in line: 

# we expect to get an EOF if we're quitting. 

return '' 

elif restart_if_needed: # the subprocess might have crashed 

try: 

self._synchronize() 

return self._post_process_from_file(self._eval_line_using_file(line, restart_if_needed=False)) 

except RuntimeError as msg: 

raise RuntimeError('%s terminated unexpectedly while reading in a large line:\n%s'%(self,msg[0])) 

except TypeError: 

pass 

raise RuntimeError('%s terminated unexpectedly while reading in a large line'%self) 

except RuntimeError as msg: 

if self._quit_string() in line: 

if self._expect is None or not self._expect.isalive(): 

return '' 

raise 

if restart_if_needed and (self._expect is None or not self._expect.isalive()): 

try: 

self._synchronize() 

return self._post_process_from_file(self._eval_line_using_file(line, restart_if_needed=False)) 

except TypeError: 

pass 

except RuntimeError as msg: 

raise RuntimeError('%s terminated unexpectedly while reading in a large line'%self) 

if "Input/output error" in msg[0]: # This occurs on non-linux machines 

raise RuntimeError('%s terminated unexpectedly while reading in a large line'%self) 

raise RuntimeError('%s terminated unexpectedly while reading in a large line:\n%s'%(self,msg[0])) 

return self._post_process_from_file(s) 

 

def _post_process_from_file(self, s): 

return s 

 

def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=True): 

""" 

Evaluate a line of commands. 

 

REMARK: 

 

By default, a long command (length exceeding ``self._eval_using_file_cutoff``) 

is evaluated using :meth:`_eval_line_using_file`. 

 

If the command can not be evaluated since the interface 

has crashed, it is automatically restarted and tried 

again *once*. 

 

If the optional ``wait_for_prompt`` is ``False`` then even a very 

long line will not be evaluated by :meth:`_eval_line_using_file`, 

since this does not support the ``wait_for_prompt`` option. 

 

INPUT: 

 

- ``line`` -- (string) a command. 

- ``allow_use_file`` (optional bool, default ``True``) -- 

allow to evaluate long commands using :meth:`_eval_line_using_file`. 

- ``wait_for_prompt`` (optional bool, default ``True``) -- 

wait until the prompt appears in the sub-process' output. 

- ``restart_if_needed`` (optional bool, default ``True``) -- 

If it is ``True``, the command evaluation is evaluated 

a second time after restarting the interface, if an 

``EOFError`` occured. 

 

TESTS:: 

 

sage: singular._eval_line('def a=3;') 

'' 

sage: singular('a') 

3 

sage: singular.eval('quit;') 

'' 

sage: singular._eval_line('def a=3;') 

Singular crashed -- automatically restarting. 

'' 

sage: singular('a') 

3 

sage: singular.eval('kill a') 

'' 

 

We are now sending a command that would run forever. But since 

we declare that we are not waiting for a prompt, we can interrupt 

it without a KeyboardInterrupt. At the same time, we test that 

the line is not forwarded to :meth:`_eval_line_using_file`, since 

that method would not support the ``wait_for_prompt`` option. 

For reasons which are currently not understood, the ``interrupt`` 

test usually returns immediately, but sometimes it takes a very 

long time on the same system. :: 

 

sage: cutoff = singular._eval_using_file_cutoff 

sage: singular._eval_using_file_cutoff = 4 

sage: singular._eval_line('for(int i=1;i<=3;i++){i=1;};', wait_for_prompt=False) 

'' 

sage: singular.interrupt() 

True 

sage: singular._eval_using_file_cutoff = cutoff 

 

The interface still works after this interrupt:: 

 

sage: singular('2+3') 

5 

 

Last, we demonstrate that by default the execution of a command 

is tried twice if it fails the first time due to a crashed 

interface:: 

 

sage: singular.eval('quit;') 

'' 

sage: singular._eval_line_using_file('def a=3;', restart_if_needed=False) 

Traceback (most recent call last): 

... 

RuntimeError: Singular terminated unexpectedly while reading in a large line... 

 

Since the test of the next method would fail, we re-start 

Singular now. :: 

 

sage: singular('2+3') 

Singular crashed -- automatically restarting. 

5 

 

""" 

if allow_use_file and wait_for_prompt and self._eval_using_file_cutoff and len(line) > self._eval_using_file_cutoff: 

return self._eval_line_using_file(line) 

try: 

if self._expect is None: 

self._start() 

E = self._expect 

try: 

if len(line) >= 4096: 

raise RuntimeError("Sending more than 4096 characters with %s on a line may cause a hang and you're sending %s characters"%(self, len(line))) 

E.sendline(line) 

if not wait_for_prompt: 

return '' 

 

except OSError as msg: 

if restart_if_needed: 

# The subprocess most likely crashed. 

# If it's really still alive, we fall through 

# and raise RuntimeError. 

if sys.platform.startswith('sunos'): 

# On (Open)Solaris, we might need to wait a 

# while because the process might not die 

# immediately. See Trac #14371. 

for t in [0.5, 1.0, 2.0]: 

if E.isalive(): 

time.sleep(t) 

else: 

break 

if not E.isalive(): 

try: 

self._synchronize() 

except (TypeError, RuntimeError): 

pass 

return self._eval_line(line,allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt, restart_if_needed=False) 

raise_(RuntimeError, "%s\nError evaluating %s in %s"%(msg, line, self), sys.exc_info()[2]) 

 

if len(line)>0: 

try: 

if isinstance(wait_for_prompt, string_types): 

E.expect(wait_for_prompt) 

else: 

E.expect(self._prompt) 

except pexpect.EOF as msg: 

try: 

if self.is_local(): 

tmp_to_use = self._local_tmpfile() 

else: 

tmp_to_use = self._remote_tmpfile() 

if self._read_in_file_command(tmp_to_use) in line: 

raise pexpect.EOF(msg) 

except NotImplementedError: 

pass 

if self._quit_string() in line: 

# we expect to get an EOF if we're quitting. 

return '' 

elif restart_if_needed: # the subprocess might have crashed 

try: 

self._synchronize() 

return self._eval_line(line,allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt, restart_if_needed=False) 

except (TypeError, RuntimeError): 

pass 

raise RuntimeError("%s\n%s crashed executing %s"%(msg,self, line)) 

if self._terminal_echo: 

out = E.before 

else: 

out = E.before.rstrip('\n\r') 

else: 

if self._terminal_echo: 

out = '\n\r' 

else: 

out = '' 

except KeyboardInterrupt: 

self._keyboard_interrupt() 

raise KeyboardInterrupt("Ctrl-c pressed while running %s"%self) 

if self._terminal_echo: 

i = out.find("\n") 

j = out.rfind("\r") 

return out[i+1:j].replace('\r\n','\n') 

else: 

return out.replace('\r\n','\n') 

 

def _keyboard_interrupt(self): 

print("Interrupting %s..." % self) 

if self._restart_on_ctrlc: 

try: 

self._expect.close(force=1) 

except pexpect.ExceptionPexpect as msg: 

raise pexpect.ExceptionPexpect( "THIS IS A BUG -- PLEASE REPORT. This should never happen.\n" + msg) 

self._start() 

raise KeyboardInterrupt("Restarting %s (WARNING: all variables defined in previous session are now invalid)"%self) 

else: 

self._expect.sendline(chr(3)) # send ctrl-c 

self._expect.expect(self._prompt) 

self._expect.expect(self._prompt) 

raise KeyboardInterrupt("Ctrl-c pressed while running %s"%self) 

 

def interrupt(self, tries=5, timeout=2.0, quit_on_fail=True): 

E = self._expect 

if E is None: 

return True 

try: 

for i in range(tries): 

self._send_interrupt() 

try: 

E.expect(self._prompt, timeout=timeout) 

except (pexpect.TIMEOUT, pexpect.EOF): 

pass 

else: 

return True # Success 

except Exception: 

pass 

# Failed to interrupt... 

if quit_on_fail: 

self.quit() 

return False 

 

########################################################################### 

# BEGIN Synchronization code. 

########################################################################### 

 

def _before(self): 

r""" 

Return the previous string that was sent through the interface. 

 

EXAMPLES:: 

 

sage: singular('2+3') 

5 

sage: singular._before() 

'5\r\n' 

""" 

return self._expect.before 

 

def _interrupt(self): 

for i in range(15): 

try: 

self._sendstr('quit;\n'+chr(3)) 

self._expect_expr(timeout=2) 

except pexpect.TIMEOUT: 

pass 

except pexpect.EOF: 

self._crash_msg() 

self.quit() 

else: 

return 

 

def _expect_expr(self, expr=None, timeout=None): 

r""" 

Wait for a given expression expr (which could be a regular 

expression or list of regular expressions) to appear in the output 

for at most timeout seconds. 

 

Use ``r._expect.before`` to see what was put in the 

output stream before the expression. 

 

INPUT: 

 

 

- ``expr`` - None or a string or list of strings 

(default: None) 

 

- ``timeout`` - None or a number (default: None) 

 

 

EXAMPLES: 

 

We test all of this using the R interface. First we put 

10 + 15 in the input stream:: 

 

sage: r._sendstr('abc <- 10 +15;\n') 

 

Here an exception is raised because 25 hasn't appeared yet in the 

output stream. The key thing is that this doesn't lock, but instead 

quickly raises an exception. 

 

:: 

 

sage: t = walltime() 

sage: try: 

....: r._expect_expr('25', timeout=0.5) 

....: except Exception: 

....: print('Did not get expression') 

Did not get expression 

 

A quick consistency check on the time that the above took:: 

 

sage: w = walltime(t); w > 0.4 and w < 10 

True 

 

We tell R to print abc, which equals 25. 

 

:: 

 

sage: r._sendstr('abc;\n') 

 

Now 25 is in the output stream, so we can wait for it. 

 

:: 

 

sage: r._expect_expr('25') 

 

This gives us everything before the 25. 

 

:: 

 

sage: r._expect.before 

'...abc;\r\n[1] ' 

 

We test interrupting ``_expect_expr`` using the GP interface, 

see :trac:`6661`. Unfortunately, this test doesn't work reliably using 

Singular, see :trac:`9163` and the follow-up :trac:`10476`. 

The ``gp.eval('0')`` in this test makes sure that ``gp`` is 

running, so a timeout of 1 second should be sufficient. :: 

 

sage: print(sage0.eval("dummy=gp.eval('0'); alarm(1); gp._expect_expr('1')")) # long time 

Control-C pressed. Interrupting PARI/GP interpreter. Please wait a few seconds... 

... 

AlarmInterrupt: 

""" 

if expr is None: 

# the following works around gap._prompt_wait not being defined 

expr = getattr(self, '_prompt_wait', None) or self._prompt 

if self._expect is None: 

self._start() 

try: 

if timeout: 

i = self._expect.expect(expr, timeout=timeout) 

else: 

i = self._expect.expect(expr) 

if i > 0: 

v = self._expect.before 

self.quit() 

raise ValueError("%s\nComputation failed due to a bug in %s -- NOTE: Had to restart."%(v, self)) 

except KeyboardInterrupt: 

print("Control-C pressed. Interrupting %s. Please wait a few seconds..."%self) 

self.interrupt() 

raise 

 

def _sendstr(self, string): 

r""" 

Send a string to the pexpect interface, autorestarting the expect 

interface if anything goes wrong. 

 

INPUT: 

 

- ``string`` -- a string 

 

EXAMPLES: We illustrate this function using the R interface:: 

 

sage: r._synchronize() 

sage: r._sendstr('a <- 10;\n') 

sage: r.eval('a') 

'[1] 10' 

 

We illustrate using the singular interface:: 

 

sage: singular._synchronize() 

sage: singular._sendstr('int i = 5;') 

sage: singular('i') 

5 

""" 

if self._expect is None: 

self._start() 

try: 

os.write(self._expect.child_fd, string) 

except OSError: 

self._crash_msg() 

self.quit() 

self._sendstr(string) 

 

def _crash_msg(self): 

r""" 

Show a message if the interface crashed. 

 

EXAMPLES:: 

 

sage: singular._crash_msg() 

Singular crashed -- automatically restarting. 

 

:: 

 

sage: singular('2+3') 

5 

sage: singular._sendstr('quit;\n') # make it so that singular appears to die. 

sage: singular('2+3') 

Singular crashed -- automatically restarting. 

5 

""" 

print("%s crashed -- automatically restarting." % self) 

 

def _synchronize(self, cmd='1+%s;\n'): 

""" 

Synchronize pexpect interface. 

 

This put a random integer (plus one!) into the output stream, then 

waits for it, thus resynchronizing the stream. If the random 

integer doesn't appear within 1 second, the interface is sent 

interrupt signals. 

 

This way, even if you somehow left the interface in a busy state 

computing, calling _synchronize gets everything fixed. 

 

EXAMPLES: We observe nothing, just as it should be:: 

 

sage: r._synchronize() 

 

TESTS: 

 

This illustrates a synchronization bug being fixed (thanks 

to Simon King and David Joyner for tracking this down):: 

 

sage: R.<x> = QQ[]; f = x^3 + x + 1; g = x^3 - x - 1; r = f.resultant(g); gap(ZZ); singular(R) 

Integers 

polynomial ring, over a field, global ordering 

// coefficients: QQ 

// number of vars : 1 

// block 1 : ordering lp 

// : names x 

// block 2 : ordering C 

""" 

if self._expect is None: 

return 

rnd = randrange(2147483647) 

s = str(rnd+1) 

cmd = cmd%rnd 

self._sendstr(cmd) 

try: 

self._expect_expr(timeout=0.5) 

if not s in self._expect.before: 

self._expect_expr(s,timeout=0.5) 

self._expect_expr(timeout=0.5) 

except pexpect.TIMEOUT: 

self._interrupt() 

except pexpect.EOF: 

self._crash_msg() 

self.quit() 

 

########################################################################### 

# END Synchronization code. 

########################################################################### 

 

def eval(self, code, strip=True, synchronize=False, locals=None, allow_use_file=True, 

split_lines="nofile", **kwds): 

""" 

INPUT: 

 

 

- ``code`` -- text to evaluate 

 

- ``strip`` -- bool; whether to strip output prompts, 

etc. (ignored in the base class). 

 

- ``locals`` -- None (ignored); this is used for compatibility 

with the Sage notebook's generic system interface. 

 

- ``allow_use_file`` -- bool (default: True); if True and ``code`` exceeds an 

interface-specific threshold then ``code`` will be communicated 

via a temporary file rather that the character-based interface. 

If False then the code will be communicated via the character interface. 

 

- ``split_lines`` -- Tri-state (default: "nofile"); if "nofile" then ``code`` is sent line by line 

unless it gets communicated via a temporary file. 

If True then ``code`` is sent line by line, but some lines individually 

might be sent via temporary file. Depending on the interface, this may transform 

grammatical ``code`` into ungrammatical input. 

If False, then the whole block of code is evaluated all at once. 

 

- ``**kwds`` -- All other arguments are passed onto the _eval_line 

method. An often useful example is reformat=False. 

""" 

if synchronize: 

try: 

self._synchronize() 

except AttributeError: 

pass 

 

if strip: 

try: 

code = self._strip_prompt(code) 

except AttributeError: 

pass 

 

if not isinstance(code, string_types): 

raise TypeError('input code must be a string.') 

 

#Remove extra whitespace 

code = code.strip() 

 

try: 

with gc_disabled(): 

if (split_lines == "nofile" and allow_use_file and 

self._eval_using_file_cutoff and len(code) > self._eval_using_file_cutoff): 

return self._eval_line_using_file(code) 

elif split_lines: 

return '\n'.join([self._eval_line(L, allow_use_file=allow_use_file, **kwds) 

for L in code.split('\n') if L != '']) 

else: 

return self._eval_line(code, allow_use_file=allow_use_file, **kwds) 

# DO NOT CATCH KeyboardInterrupt, as it is being caught 

# by _eval_line 

# In particular, do NOT call self._keyboard_interrupt() 

except TypeError as s: 

raise TypeError('error evaluating "%s":\n%s'%(code,s)) 

 

############################################################ 

# Functions for working with variables. 

# The first three must be overloaded by derived classes, 

# and the definition depends a lot on the class. But 

# the functionality one gets from this is very nice. 

############################################################ 

 

def _object_class(self): 

""" 

EXAMPLES:: 

 

sage: from sage.interfaces.expect import Expect 

sage: Expect._object_class(maxima) 

<class 'sage.interfaces.expect.ExpectElement'> 

""" 

return ExpectElement 

 

def _function_class(self): 

""" 

EXAMPLES:: 

 

sage: from sage.interfaces.expect import Expect 

sage: Expect._function_class(maxima) 

<class 'sage.interfaces.expect.ExpectFunction'> 

""" 

return ExpectFunction 

 

def _function_element_class(self): 

""" 

EXAMPLES:: 

 

sage: from sage.interfaces.expect import Expect 

sage: Expect._function_element_class(maxima) 

<class 'sage.interfaces.expect.FunctionElement'> 

""" 

return FunctionElement 

 

 

@instancedoc 

class ExpectFunction(InterfaceFunction): 

""" 

Expect function. 

""" 

pass 

 

@instancedoc 

class FunctionElement(InterfaceFunctionElement): 

""" 

Expect function element. 

""" 

pass 

 

 

def is_ExpectElement(x): 

return isinstance(x, ExpectElement) 

 

 

@instancedoc 

class ExpectElement(InterfaceElement): 

""" 

Expect element. 

""" 

def __init__(self, parent, value, is_name=False, name=None): 

RingElement.__init__(self, parent) 

self._create = value 

if parent is None: return # means "invalid element" 

# idea: Joe Wetherell -- try to find out if the output 

# is too long and if so get it using file, otherwise 

# don't. 

if isinstance(value, string_types) and parent._eval_using_file_cutoff and \ 

parent._eval_using_file_cutoff < len(value): 

self._get_using_file = True 

 

if is_name: 

self._name = value 

else: 

try: 

self._name = parent._create(value, name=name) 

# Convert ValueError and RuntimeError to TypeError for 

# coercion to work properly. 

except (RuntimeError, ValueError) as x: 

self._session_number = -1 

raise_(TypeError, x, sys.exc_info()[2]) 

except BaseException: 

self._session_number = -1 

raise 

self._session_number = parent._session_number 

 

def __hash__(self): 

""" 

Returns the hash of self. This is a default implementation of hash 

which just takes the hash of the string of self. 

""" 

return hash('%s%s'%(self, self._session_number)) 

 

 

def _check_valid(self): 

""" 

Check that this object is valid, i.e., the session in which this 

object is defined is still running. This is relevant for 

interpreters that can't be interrupted via ctrl-C, hence get 

restarted. 

""" 

try: 

P = self.parent() 

if P is None or P._session_number == BAD_SESSION or self._session_number == -1 or \ 

P._session_number != self._session_number: 

raise ValueError("The %s session in which this object was defined is no longer running."%P.name()) 

except AttributeError: 

raise ValueError("The session in which this object was defined is no longer running.") 

return P 

 

def __del__(self): 

try: 

self._check_valid() 

except ValueError: 

return 

try: 

if hasattr(self,'_name'): 

P = self.parent() 

if P is not None: 

P.clear(self._name) 

 

except (RuntimeError, ExceptionPexpect): # needed to avoid infinite loops in some rare cases 

pass 

 

# def _sage_repr(self): 

#TO DO: this could use file transfers when self.is_remote() 

 

 

class StdOutContext: 

""" 

A context in which all communication between Sage and a subprocess 

interfaced via pexpect is printed to stdout. 

""" 

def __init__(self, interface, silent=False, stdout=None): 

""" 

Construct a new context in which all communication between Sage 

and a subprocess interfaced via pexpect is printed to stdout. 

 

INPUT: 

 

- ``interface`` - the interface whose communication shall be dumped. 

 

- ``silent`` - if ``True`` this context does nothing 

 

- ``stdout`` - optional parameter for alternative stdout device (default: ``None``) 

 

EXAMPLES:: 

 

sage: from sage.interfaces.expect import StdOutContext 

sage: with StdOutContext(Gp()) as g: 

....: g('1+1') 

sage=... 

""" 

self.interface = interface 

self.silent = silent 

self.stdout = stdout if stdout else sys.stdout 

 

def __enter__(self): 

""" 

EXAMPLES:: 

 

sage: from sage.interfaces.expect import StdOutContext 

sage: with StdOutContext(singular): 

....: singular.eval('1+1') 

1+1; 

... 

""" 

if self.silent: 

return self.interface 

if self.interface._expect is None: 

self.interface._start() 

self._logfile_backup = self.interface._expect.logfile 

if self.interface._expect.logfile: 

self.interface._expect.logfile = Multiplex(self.interface._expect.logfile, self.stdout) 

else: 

self.interface._expect.logfile = Multiplex(self.stdout) 

return self.interface 

 

def __exit__(self, typ, value, tb): 

r""" 

EXAMPLES:: 

 

sage: from sage.interfaces.expect import StdOutContext 

sage: with StdOutContext(gap): 

....: gap('1+1') 

\$sage... 

""" 

if self.silent: 

return 

self.interface._expect.logfile.flush() 

self.stdout.write("\n") 

self.interface._expect.logfile = self._logfile_backup 

 

 

def console(cmd): 

os.system(cmd)