-
Notifications
You must be signed in to change notification settings - Fork 226
Expand file tree
/
Copy pathPy.java
More file actions
2967 lines (2620 loc) · 107 KB
/
Py.java
File metadata and controls
2967 lines (2620 loc) · 107 KB
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
// Copyright (c) Corporation for National Research Initiatives
package org.python.core;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectStreamException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StreamCorruptedException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.logging.Level;
import org.python.antlr.base.mod;
import org.python.core.adapter.ClassicPyObjectAdapter;
import org.python.core.adapter.ExtensiblePyObjectAdapter;
import org.python.modules.posix.PosixModule;
import jline.console.UserInterruptException;
import jnr.constants.Constant;
import jnr.constants.platform.Errno;
import jnr.posix.util.Platform;
public final class Py extends PrePy {
static class SingletonResolver implements Serializable {
private String which;
SingletonResolver(String which) {
this.which = which;
}
private Object readResolve() throws ObjectStreamException {
if (which.equals("None")) {
return Py.None;
} else if (which.equals("Ellipsis")) {
return Py.Ellipsis;
} else if (which.equals("NotImplemented")) {
return Py.NotImplemented;
}
throw new StreamCorruptedException("unknown singleton: " + which);
}
}
/* Holds the singleton None and Ellipsis objects */
/** The singleton None Python object **/
public final static PyObject None = PyNone.getInstance();
/** The singleton Ellipsis Python object - written as ... when indexing */
public final static PyObject Ellipsis = new PyEllipsis();
/** The singleton NotImplemented Python object. Used in rich comparison */
public final static PyObject NotImplemented = new PyNotImplemented();
/** A zero-length array of Strings to pass to functions that
don't have any keyword arguments **/
public final static String[] NoKeywords = new String[0];
/** A zero-length array of PyObject's to pass to functions when we have no arguments **/
public final static PyObject[] EmptyObjects = new PyObject[0];
/** A frozenset with zero elements **/
public final static PyFrozenSet EmptyFrozenSet = new PyFrozenSet();
/** A tuple with zero elements **/
public final static PyTuple EmptyTuple = new PyTuple(Py.EmptyObjects);
/** The Python integer 0 **/
public final static PyInteger Zero = new PyInteger(0);
/** The Python integer 1 **/
public final static PyInteger One = new PyInteger(1);
/** The Python boolean False **/
public final static PyBoolean False = new PyBoolean(false);
/** The Python boolean True **/
public final static PyBoolean True = new PyBoolean(true);
/** A zero-length Python byte string **/
public final static PyString EmptyString = PyString.fromInterned("");
/** A zero-length Python Unicode string **/
public final static PyUnicode EmptyUnicode = new PyUnicode("");
/** A Python string containing '\n' **/
public final static PyString Newline = PyString.fromInterned("\n");
/** A Python unicode string containing '\n' **/
public final static PyUnicode UnicodeNewline = new PyUnicode("\n");
/** A Python string containing ' ' **/
public final static PyString Space = PyString.fromInterned(" ");
/** A Python unicode string containing ' ' **/
public final static PyUnicode UnicodeSpace = new PyUnicode(" ");
/** Set if the type object is dynamically allocated */
public final static long TPFLAGS_HEAPTYPE = 1L << 9;
/** Set if the type allows subclassing */
public final static long TPFLAGS_BASETYPE = 1L << 10;
/** Type is abstract and cannot be instantiated */
public final static long TPFLAGS_IS_ABSTRACT = 1L << 20;
/** A unique object to indicate no conversion is possible
in __tojava__ methods **/
public final static Object NoConversion = new PySingleton("Error");
public static PyObject OSError;
public static PyException OSError(String message) {
return new PyException(Py.OSError, message);
}
public static PyException OSError(IOException ioe) {
return fromIOException(ioe, Py.OSError);
}
public static PyException OSError(Constant errno) {
int value = errno.intValue();
PyObject args = new PyTuple(Py.newInteger(value), PosixModule.strerror(value));
return new PyException(Py.OSError, args);
}
public static PyException OSError(Constant errno, PyObject filename) {
int value = errno.intValue();
// see https://github.com/jruby/jruby/commit/947c661e46683ea82f8016dde9d3fa597cd10e56
// for rationale to do this mapping, but in a nutshell jnr-constants is automatically
// generated from header files, so that's not the right place to do this mapping,
// but for Posix compatibility reasons both CPython andCRuby do this mapping;
// except CPython chooses EEXIST instead of CRuby's ENOENT
if (Platform.IS_WINDOWS && (value == 20047 || value == Errno.ESRCH.intValue())) {
value = Errno.EEXIST.intValue();
}
// Pass to strerror because jnr-constants currently lacks Errno descriptions on
// Windows, and strerror falls back to Linux's
PyObject args = new PyTuple(Py.newInteger(value), PosixModule.strerror(value), filename);
return new PyException(Py.OSError, args);
}
public static PyObject NotImplementedError;
public static PyException NotImplementedError(String message) {
return new PyException(Py.NotImplementedError, message);
}
public static PyObject EnvironmentError;
public static PyException EnvironmentError(String message) {
return new PyException(Py.EnvironmentError, message);
}
/* The standard Python exceptions */
public static PyObject OverflowError;
public static PyException OverflowError(String message) {
return new PyException(Py.OverflowError, message);
}
public static PyObject RuntimeError;
public static PyException RuntimeError(String message) {
return new PyException(Py.RuntimeError, message);
}
public static PyObject KeyboardInterrupt;
public static PyException KeyboardInterrupt(String message) {
return new PyException(Py.KeyboardInterrupt, message);
}
public static PyObject FloatingPointError;
public static PyException FloatingPointError(String message) {
return new PyException(Py.FloatingPointError, message);
}
public static PyObject SyntaxError;
public static PyException SyntaxError(String message) {
return new PyException(Py.SyntaxError, message);
}
public static PyObject IndentationError;
public static PyObject TabError;
public static PyObject AttributeError;
public static PyException AttributeError(String message) {
return new PyException(Py.AttributeError, message);
}
public static PyObject IOError;
public static PyException IOError(IOException ioe) {
return fromIOException(ioe, Py.IOError);
}
public static PyException IOError(String message) {
return new PyException(Py.IOError, message);
}
public static PyException IOError(Constant errno) {
int value = errno.intValue();
PyObject args = new PyTuple(Py.newInteger(value), PosixModule.strerror(value));
return new PyException(Py.IOError, args);
}
public static PyException IOError(Constant errno, String filename) {
return IOError(errno, Py.fileSystemEncode(filename));
}
public static PyException IOError(Constant errno, PyObject filename) {
int value = errno.intValue();
PyObject args = new PyTuple(Py.newInteger(value), PosixModule.strerror(value), filename);
return new PyException(Py.IOError, args);
}
private static PyException fromIOException(IOException ioe, PyObject err) {
String message = ioe.getMessage();
if (message == null) {
message = ioe.getClass().getName();
}
if (ioe instanceof FileNotFoundException) {
PyTuple args = new PyTuple(Py.newInteger(Errno.ENOENT.intValue()),
Py.newStringOrUnicode("File not found - " + message));
return new PyException(err, args);
}
return new PyException(err, message);
}
public static PyObject KeyError;
public static PyException KeyError(String message) {
return new PyException(Py.KeyError, message);
}
public static PyException KeyError(PyObject key) {
return new PyException(Py.KeyError, key);
}
public static PyObject AssertionError;
public static PyException AssertionError(String message) {
return new PyException(Py.AssertionError, message);
}
public static PyObject TypeError;
public static PyException TypeError(String message) {
return new PyException(Py.TypeError, message);
}
public static PyObject ReferenceError;
public static PyException ReferenceError(String message) {
return new PyException(Py.ReferenceError, message);
}
public static PyObject SystemError;
public static PyException SystemError(String message) {
return new PyException(Py.SystemError, message);
}
public static PyObject IndexError;
public static PyException IndexError(String message) {
return new PyException(Py.IndexError, message);
}
public static PyObject ZeroDivisionError;
public static PyException ZeroDivisionError(String message) {
return new PyException(Py.ZeroDivisionError, message);
}
public static PyObject NameError;
public static PyException NameError(String message) {
return new PyException(Py.NameError, message);
}
public static PyObject UnboundLocalError;
public static PyException UnboundLocalError(String message) {
return new PyException(Py.UnboundLocalError, message);
}
public static PyObject SystemExit;
static void maybeSystemExit(PyException exc) {
if (exc.match(Py.SystemExit)) {
// No actual exit here if Options.interactive (-i flag) is in force.
handleSystemExit(exc);
}
}
/**
* Exit the process, if {@value Options#inspect}{@code ==false}, cleaning up the system state.
* This exception (normally SystemExit) determines the message, if any, and the
* {@code System.exit} status.
*
* @param exc supplies the message or exit status
*/
static void handleSystemExit(PyException exc) {
if (!Options.inspect) {
PyObject value = exc.value;
if (PyException.isExceptionInstance(exc.value)) {
value = value.__findattr__("code");
}
// Decide exit status and produce message while Jython still works
int exitStatus;
if (value instanceof PyInteger) {
exitStatus = ((PyInteger) value).getValue();
} else {
if (value != Py.None) {
try {
Py.println(value);
exitStatus = 1;
} catch (Throwable t) {
exitStatus = 0;
}
} else {
exitStatus = 0;
}
}
// Shut down Jython
PySystemState sys = Py.getSystemState();
sys.callExitFunc();
sys.close();
System.exit(exitStatus);
}
}
public static PyObject StopIteration;
public static PyException StopIteration(String message) {
return new PyException(Py.StopIteration, message);
}
public static PyObject GeneratorExit;
public static PyException GeneratorExit(String message) {
return new PyException(Py.GeneratorExit, message);
}
public static PyObject ImportError;
public static PyException ImportError(String message) {
return new PyException(Py.ImportError, message);
}
public static PyObject ValueError;
public static PyException ValueError(String message) {
return new PyException(Py.ValueError, message);
}
public static PyObject UnicodeError;
public static PyException UnicodeError(String message) {
return new PyException(Py.UnicodeError, message);
}
public static PyObject UnicodeTranslateError;
public static PyException UnicodeTranslateError(String object,
int start,
int end, String reason) {
return new PyException(Py.UnicodeTranslateError, new PyTuple(new PyString(object),
new PyInteger(start),
new PyInteger(end),
new PyString(reason)));
}
public static PyObject UnicodeDecodeError;
public static PyException UnicodeDecodeError(String encoding,
String object,
int start,
int end,
String reason) {
return new PyException(Py.UnicodeDecodeError, new PyTuple(new PyString(encoding),
new PyString(object),
new PyInteger(start),
new PyInteger(end),
new PyString(reason)));
}
public static PyObject UnicodeEncodeError;
public static PyException UnicodeEncodeError(String encoding,
String object,
int start,
int end,
String reason) {
return new PyException(Py.UnicodeEncodeError, new PyTuple(new PyString(encoding),
new PyUnicode(object),
new PyInteger(start),
new PyInteger(end),
new PyString(reason)));
}
public static PyObject EOFError;
public static PyException EOFError(String message) {
return new PyException(Py.EOFError, message);
}
public static PyObject MemoryError;
public static void memory_error(OutOfMemoryError t) {
if (Options.showJavaExceptions) {
t.printStackTrace();
}
}
public static PyException MemoryError(String message) {
return new PyException(Py.MemoryError, message);
}
public static PyObject BufferError;
public static PyException BufferError(String message) {
return new PyException(Py.BufferError, message);
}
public static PyObject ArithmeticError;
public static PyObject LookupError;
public static PyObject StandardError;
public static PyObject Exception;
public static PyObject BaseException;
public static PyObject Warning;
public static void Warning(String message) {
warning(Warning, message);
}
public static PyObject UserWarning;
public static void UserWarning(String message) {
warning(UserWarning, message);
}
public static PyObject DeprecationWarning;
public static void DeprecationWarning(String message) {
warning(DeprecationWarning, message);
}
public static PyObject PendingDeprecationWarning;
public static void PendingDeprecationWarning(String message) {
warning(PendingDeprecationWarning, message);
}
public static PyObject SyntaxWarning;
public static void SyntaxWarning(String message) {
warning(SyntaxWarning, message);
}
public static PyObject RuntimeWarning;
public static void RuntimeWarning(String message) {
warning(RuntimeWarning, message);
}
public static PyObject FutureWarning;
public static void FutureWarning(String message) {
warning(FutureWarning, message);
}
public static PyObject ImportWarning;
public static void ImportWarning(String message) {
warning(ImportWarning, message);
}
public static PyObject UnicodeWarning;
public static void UnicodeWarning(String message) {
warning(UnicodeWarning, message);
}
public static PyObject BytesWarning;
public static void BytesWarning(String message) {
warning(BytesWarning, message);
}
public static void warnPy3k(String message) {
warnPy3k(message, 1);
}
public static void warnPy3k(String message, int stacklevel) {
if (Options.py3k_warning) {
warning(DeprecationWarning, message, stacklevel);
}
}
private static PyObject warnings_mod;
private static PyObject importWarnings() {
if (warnings_mod != null) {
return warnings_mod;
}
PyObject mod;
try {
mod = __builtin__.__import__("warnings");
} catch (PyException e) {
if (e.match(ImportError)) {
return null;
}
throw e;
}
warnings_mod = mod;
return mod;
}
private static String warn_hcategory(PyObject category) {
PyObject name = category.__findattr__("__name__");
if (name != null) {
return "[" + name + "]";
}
return "[warning]";
}
public static void warning(PyObject category, String message) {
warning(category, message, 1);
}
public static void warning(PyObject category, String message, int stacklevel) {
PyObject func = null;
PyObject mod = importWarnings();
if (mod != null) {
func = mod.__getattr__("warn");
}
if (func == null) {
System.err.println(warn_hcategory(category) + ": " + message);
return;
} else {
func.__call__(Py.newString(message), category, Py.newInteger(stacklevel));
}
}
public static void warning(PyObject category, String message,
String filename, int lineno, String module,
PyObject registry) {
PyObject func = null;
PyObject mod = importWarnings();
if (mod != null) {
func = mod.__getattr__("warn_explicit");
}
if (func == null) {
System.err.println(filename + ":" + lineno + ":" +
warn_hcategory(category) + ": " + message);
return;
} else {
func.__call__(new PyObject[]{
Py.newString(message), category,
Py.newString(filename), Py.newInteger(lineno),
(module == null) ? Py.None : Py.newString(module),
registry
}, Py.NoKeywords);
}
}
public static PyObject JavaError;
public static PyException JavaError(Throwable t) {
if (t instanceof PyException) {
return (PyException) t;
} else if (t instanceof InvocationTargetException) {
return JavaError(((InvocationTargetException) t).getTargetException());
} else if (t instanceof StackOverflowError) {
return Py.RuntimeError("maximum recursion depth exceeded (Java StackOverflowError)");
} else if (t instanceof OutOfMemoryError) {
memory_error((OutOfMemoryError) t);
} else if (t instanceof UserInterruptException) {
return Py.KeyboardInterrupt("");
}
PyObject exc = PyJavaType.wrapJavaObject(t);
PyException pyex = new PyException(exc.getType(), exc);
// Set the cause to the original throwable to preserve
// the exception chain.
pyex.initCause(t);
return pyex;
}
private Py() {
}
/**
Convert a given <code>PyObject</code> to an instance of a Java class.
Identical to <code>o.__tojava__(c)</code> except that it will
raise a <code>TypeError</code> if the conversion fails.
@param o the <code>PyObject</code> to convert.
@param c the class to convert it to.
**/
@SuppressWarnings("unchecked")
public static <T> T tojava(PyObject o, Class<T> c) {
Object obj = o.__tojava__(c);
if (obj == Py.NoConversion) {
throw Py.TypeError("can't convert " + o.__repr__() + " to " +
c.getName());
}
return (T)obj;
}
// ??pending: was @deprecated but is actually used by proxie code.
// Can get rid of it?
public static Object tojava(PyObject o, String s) {
Class<?> c = findClass(s);
if (c == null) {
throw Py.TypeError("can't convert to: " + s);
}
return tojava(o, c); // prev:Class.forName
}
/* Helper functions for PyProxy's */
/* Convenience methods to create new constants without using "new" */
private final static PyInteger[] integerCache = new PyInteger[1000];
static {
for (int j = -100; j < 900; j++) {
integerCache[j + 100] = new PyInteger(j);
}
}
public static final PyInteger newInteger(int i) {
if (i >= -100 && i < 900) {
return integerCache[i + 100];
} else {
return new PyInteger(i);
}
}
public static PyObject newInteger(long i) {
if (i < Integer.MIN_VALUE || i > Integer.MAX_VALUE) {
return new PyLong(i);
} else {
return newInteger((int) i);
}
}
public static PyLong newLong(String s) {
return new PyLong(s);
}
public static PyLong newLong(java.math.BigInteger i) {
return new PyLong(i);
}
public static PyLong newLong(int i) {
return new PyLong(i);
}
public static PyLong newLong(long l) {
return new PyLong(l);
}
public static PyComplex newImaginary(double v) {
return new PyComplex(0, v);
}
public static PyFloat newFloat(float v) {
return new PyFloat((double) v);
}
public static PyFloat newFloat(double v) {
return new PyFloat(v);
}
/**
* Return a not-necessarily new {@link PyString} from a Java {@code char}. The character code
* must < 256. (This is checked.)
*
* @param c character codes < 256.
* @return a new or re-used {@code PyString}
*/
public static PyString newString(char c) {
return makeCharacter(c);
}
/**
* Return a not-necessarily new {@link PyString} from a Java {@code String}. The character codes
* must all be all < 256.
*
* @param s character codes are all < 256.
* @param promise is true if the caller promises the codes are all < 256.
* @return a new or re-used {@code PyString}
*/
static PyString newString(String s, boolean promise) {
int n = s.length();
if (n > 1) {
return new PyString(s, promise);
} else if (n == 1) {
return makeCharacter(s.charAt(0));
} else {
return Py.EmptyString;
}
}
/**
* Return a not-necessarily new {@link PyString} from a Java {@code String}. The character codes
* must all be all < 256. (This is checked.)
*
* @param s character codes should all be < 256 or an error occurs.
* @return a new or re-used {@code PyString}
*/
public static PyString newString(String s) {
return newString(s, false);
}
/**
* Return a not-necessarily new {@link PyString} from a Java {@code String} where the caller guarantees that the
* character codes are all < 256. (This is <b>not</b> checked.)
*
* @param s character codes are all < 256.
* @return a new {@code PyString}
*/
static PyString newBytes(String s) {
return newString(s, true);
}
/**
* Return a {@link PyString} for the given Java <code>String</code>, if it can be represented as
* US-ASCII, and a {@link PyUnicode} otherwise.
*
* @param s string content
* @return <code>PyString</code> or <code>PyUnicode</code> according to content of
* <code>s</code>.
*/
public static PyString newStringOrUnicode(String s) {
return newStringOrUnicode(Py.EmptyString, s);
}
/**
* Return a {@link PyString} for the given Java <code>String</code>, if it can be represented as
* US-ASCII and if a preceding object is not a <code>PyUnicode</code>, and a {@link PyUnicode}
* otherwise. In some contexts, we want the result to be a <code>PyUnicode</code> if some
* preceding result is a <code>PyUnicode</code>.
*
* @param precedent string of which the type sets a precedent
* @param s string content
* @return <code>PyString</code> or <code>PyUnicode</code> according to content of
* <code>s</code>.
*/
public static PyString newStringOrUnicode(PyObject precedent, String s) {
if (!(precedent instanceof PyUnicode) && PyString.charsFitWidth(s, 7)) {
return Py.newBytes(s);
} else {
return Py.newUnicode(s);
}
}
public static PyString newStringUTF8(String s) {
if (PyString.charsFitWidth(s, 7)) {
// ascii of course is a subset of UTF-8
return Py.newBytes(s);
} else {
return Py.newBytes(codecs.PyUnicode_EncodeUTF8(s, null));
}
}
/**
* Return a file name or path as Unicode (Java UTF-16 <code>String</code>), decoded if necessary
* from a Python <code>bytes</code> object, using the file system encoding. In Jython, this
* encoding is UTF-8, irrespective of the OS platform. This method is comparable with Python 3
* <code>os.fsdecode</code>, but for Java use, in places such as the <code>os</code> module. If
* the argument is not a <code>PyUnicode</code>, it will be decoded using the nominal Jython
* file system encoding. If the argument <i>is</i> a <code>PyUnicode</code>, its
* <code>String</code> is returned.
*
* @param filename as <code>bytes</code> to decode, or already as <code>unicode</code>
* @return unicode version of path
*/
public static String fileSystemDecode(PyString filename) {
String s = filename.getString();
if (filename instanceof PyUnicode || PyString.charsFitWidth(s, 7)) {
// Already decoded or bytes usable as ASCII
return s;
} else {
// It's bytes, so must decode properly
assert "utf-8".equals(PySystemState.FILE_SYSTEM_ENCODING.toString());
return codecs.PyUnicode_DecodeUTF8(s, null);
}
}
/**
* As {@link #fileSystemDecode(PyString)} but raising <code>ValueError</code> if not a
* <code>str</code> or <code>unicode</code>.
*
* @param filename as <code>bytes</code> to decode, or already as <code>unicode</code>
* @return unicode version of the file name
*/
public static String fileSystemDecode(PyObject filename) {
if (filename instanceof PyString) {
return fileSystemDecode((PyString)filename);
} else {
throw Py.TypeError(String.format("coercing to Unicode: need string, %s type found",
filename.getType().fastGetName()));
}
}
/**
* Return a PyString object we can use as a file name or file path in places where Python
* expects a <code>bytes</code> (that is a <code>str</code>) object in the file system encoding.
* In Jython, this encoding is UTF-8, irrespective of the OS platform.
* <p>
* This is subtly different from CPython's use of "file system encoding", which tracks the
* platform's choice so that OS services may be called that have a bytes interface. Jython's
* interaction with the OS occurs via Java using String arguments representing Unicode values,
* so we have no need to match the encoding actually chosen by the platform (e.g. 'mbcs' on
* Windows). Rather we need a nominal Jython file system encoding, for use where the standard
* library forces byte paths on us (in Python 2). There is no reason for this choice to vary
* with OS platform. Methods receiving paths as <code>bytes</code> will
* {@link #fileSystemDecode(PyString)} them again for Java.
*
* @param filename as <code>unicode</code> to encode, or already as <code>bytes</code>
* @return encoded bytes version of path
*/
public static PyString fileSystemEncode(String filename) {
if (PyString.charsFitWidth(filename, 7)) {
// Just wrap it as US-ASCII is a subset of the file system encoding
return Py.newBytes(filename);
} else {
// It's non just US-ASCII, so must encode properly
assert "utf-8".equals(PySystemState.FILE_SYSTEM_ENCODING.toString());
return Py.newBytes(codecs.PyUnicode_EncodeUTF8(filename, null));
}
}
/**
* Return a PyString object we can use as a file name or file path in places where Python
* expects a <code>bytes</code> (that is, <code>str</code>) object in the file system encoding.
* In Jython, this encoding is UTF-8, irrespective of the OS platform. This method is comparable
* with Python 3 <code>os.fsencode</code>. If the argument is a PyString, it is returned
* unchanged. If the argument is a PyUnicode, it is converted to a <code>bytes</code> using the
* nominal Jython file system encoding.
*
* @param filename as <code>unicode</code> to encode, or already as <code>bytes</code>
* @return encoded bytes version of path
*/
public static PyString fileSystemEncode(PyString filename) {
return (filename instanceof PyUnicode) ? fileSystemEncode(filename.getString()) : filename;
}
/**
* Convert a <code>PyList</code> path to a list of Java <code>String</code> objects decoded from
* the path elements to strings guaranteed usable in the Java API.
*
* @param path a Python search path
* @return equivalent Java list
*/
private static List<String> fileSystemDecode(PyList path) {
List<String> list = new ArrayList<>(path.__len__());
for (PyObject filename : path.getList()) {
list.add(fileSystemDecode(filename));
}
return list;
}
/**
* Get the environment variables from {@code os.environ}. Keys and values should be
* {@code PyString}s in the file system encoding, and it may be a {@code dict} but nothing can
* be guaranteed. (Note that in the case of multiple interpreters, the target is in the current
* interpreter's copy of {@code os}.)
*
* @return {@code os.environ}
*/
private static PyObject getEnvironment() {
PyObject os = imp.importName("os", true);
PyObject environ = os.__getattr__("environ");
return environ;
}
/** The same as {@code getenv(name, null)}. See {@link #getenv(PyString, PyString)}. */
public static PyString getenv(PyString name) {
return getenv(name, null);
}
/**
* Get the value of the environment variable named from {@code os.environ} or return the given
* default value. Empty string values are treated as undefined for this purpose.
*
* @param name of the environment variable.
* @param defaultValue to return if {@code key} is not defined (may be {@code null}.
* @return the corresponding value or <code>defaultValue</code>.
*/
public static PyString getenv(PyString name, PyString defaultValue) {
try {
PyObject value = getEnvironment().__finditem__(name);
if (value == null) {
return defaultValue;
} else {
return value.__str__();
}
} catch (PyException e) {
// Something is fishy about os.environ, so the name is not defined.
return defaultValue;
}
}
/** The same as {@code getenv(name, null)}. See {@link #getenv(String, String)}. */
public static String getenv(String name) {
return getenv(name, null);
}
/**
* Get the value of the environment variable named from {@code os.environ} or return the given
* default value. This is a convenience wrapper on {@link #getenv(PyString, PyString)} which
* takes care of the fact that environment variables are FS-encoded.
*
* @param name to access in the environment.
* @param defaultValue to return if {@code key} is not defined.
* @return the corresponding value or <code>defaultValue</code>.
*/
public static String getenv(String name, String defaultValue) {
PyString value = getenv(newUnicode(name), null);
if (value == null) {
return defaultValue;
} else {
// Environment variables are FS-encoded byte strings
return fileSystemDecode(value);
}
}
public static PyStringMap newStringMap() {
return new PyStringMap();
}
/**
* Return a not-necessarily new {@link PyUnicode} from a Java {@code char}. Some low index chars
* (ASCII) return a re-used {@code PyUnicode}. This method does not assume the character is
* basic-plane.
*
* @param c to convert to a {@code PyUnicode}.
* @return a new or re-used {@code PyUnicode}
*/
public static PyUnicode newUnicode(char c) {
return PyUnicode.from(c);
}
/**
* Return a not-necessarily new {@link PyUnicode} from a Java {@code String}. Empty and some
* single-character strings return a re-used {@code PyUnicode}. This method does not assume the
* character codes are basic-plane, but scans the string to find out. (See
* {@link #newUnicode(String, boolean)} for one that allows the caller to assert that it is.
*
* @param s to wrap as a {@code PyUnicode}.
* @return a new or re-used {@code PyUnicode}
*/
public static PyUnicode newUnicode(String s) {
return PyUnicode.fromString(s, false);
}
public static PyUnicode newUnicode(String s, boolean isBasic) {
return PyUnicode.fromString(s, isBasic);
}
public static PyBoolean newBoolean(boolean t) {
return t ? Py.True : Py.False;
}
public static PyObject newDate(Date date) {
if (date == null) {
return Py.None;
}
PyObject datetimeModule = __builtin__.__import__("datetime");
PyObject dateClass = datetimeModule.__getattr__("date");
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return dateClass.__call__(newInteger(cal.get(Calendar.YEAR)),
newInteger(cal.get(Calendar.MONTH) + 1),
newInteger(cal.get(Calendar.DAY_OF_MONTH)));
}
public static PyObject newTime(Time time) {
if (time == null) {
return Py.None;
}
PyObject datetimeModule = __builtin__.__import__("datetime");
PyObject timeClass = datetimeModule.__getattr__("time");
Calendar cal = Calendar.getInstance();
cal.setTime(time);
return timeClass.__call__(newInteger(cal.get(Calendar.HOUR_OF_DAY)),
newInteger(cal.get(Calendar.MINUTE)),
newInteger(cal.get(Calendar.SECOND)),
newInteger(cal.get(Calendar.MILLISECOND) *
1000));
}
public static PyObject newDatetime(Timestamp timestamp) {
if (timestamp == null) {
return Py.None;
}
PyObject datetimeModule = __builtin__.__import__("datetime");
PyObject datetimeClass = datetimeModule.__getattr__("datetime");
Calendar cal = Calendar.getInstance();
cal.setTime(timestamp);
return datetimeClass.__call__(new PyObject[] {
newInteger(cal.get(Calendar.YEAR)),
newInteger(cal.get(Calendar.MONTH) + 1),
newInteger(cal.get(Calendar.DAY_OF_MONTH)),
newInteger(cal.get(Calendar.HOUR_OF_DAY)),
newInteger(cal.get(Calendar.MINUTE)),
newInteger(cal.get(Calendar.SECOND)),
newInteger(timestamp.getNanos() / 1000)});
}
public static PyObject newDecimal(String decimal) {
if (decimal == null) {
return Py.None;
}
PyObject decimalModule = __builtin__.__import__("decimal");
PyObject decimalClass = decimalModule.__getattr__("Decimal");
return decimalClass.__call__(newString(decimal));
}
public static PyCode newCode(int argcount, String varnames[],
String filename, String name,
boolean args, boolean keywords,
PyFunctionTable funcs, int func_id,
String[] cellvars, String[] freevars,
int npurecell, int moreflags) {
return new PyTableCode(argcount, varnames,
filename, name, 0, args, keywords, funcs,
func_id, cellvars, freevars, npurecell,
moreflags);
}
public static PyCode newCode(int argcount, String varnames[],
String filename, String name,
int firstlineno,
boolean args, boolean keywords,