All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.python.core.PyShadowString Maven / Gradle / Ivy

Go to download

Jython is an implementation of the high-level, dynamic, object-oriented language Python written in 100% Pure Java, and seamlessly integrated with the Java platform. It thus allows you to run Python on any Java platform.

There is a newer version: 2.7.4
Show newest version
package org.python.core;

import java.util.regex.Pattern;

import org.python.expose.ExposedMethod;
import org.python.expose.ExposedNew;
import org.python.expose.ExposedType;
import org.python.expose.MethodType;

/**
 * This class provides a string that sometimes seems to change value, as far as equality tests and
 * startswith are concerned. This solves a problem that Jython users sometimes
 * experience with libraries that are sensitive to platform.
 * 

* A library may test for a particular platform in order to adjust to local file name conventions or * to decide which operating system commands are available. In Jython, os.name and * sys.platform indicate that Java is the platform, which is necessary information in * some parts of the standard library, but other libraries assuming CPython then draw incorrect * conclusions. *

* With hindsight, a better choice could be made, where sys.platform etc. indicated * Windows or Posix, and something else indicates the implementation. A change in Jython 2 would * cause more problems than it solved, but we expect Jython 3 to work that way. In the Python * Standard Library, the Jython project can make all necessary changes. It can't do anything about * third-party libraries. But it would be a big help if users could cause sys.platform * or os.name to appear to have the OS-dependent value as far as those troublesome * libraries were concerned. *

* This is what this class achieves. os.name and sys.platform regular * strings for most purposes, but each has a "shadow" value that is used in contexts the user may * specify. */ @Untraversable @ExposedType(name = "shadowstr", base = PyString.class, isBaseType = true) public class PyShadowString extends PyString { public static final PyType TYPE = PyType.fromClass(PyShadowString.class); /** * Contexts (expressed as a {@link PyTuple} of class name and method name) where {@link #shadow} * is allowed to match as well as the primary value. */ protected PyList targets; /** * The shadow string is additionally used for some comparisons, especially for __eq__. __eq__ * will evaluate positive if the other string equals the primary value *or* the shadow. The * shadow persists slicing (is sliced accordingly) and is taken into account by startswith. */ protected PyString shadow; /** Empty string (not very useful but needed for technical reasons). */ public PyShadowString() { this(Py.EmptyString, Py.EmptyString); } /** Construct an instance specifying primary and shadow values. */ public PyShadowString(String primary, String shadow) { this(TYPE, Py.newString(primary), Py.newString(shadow), new PyList()); } /** Construct an instance specifying primary and shadow values (bytes objects expected). */ private PyShadowString(PyObject primary, PyObject shadow) { this(TYPE, primary, shadow, new PyList()); } private PyShadowString(PyObject primary, PyObject shadow, PyList targets) { this(TYPE, primary, shadow, targets); } public PyShadowString(PyType subtype, PyObject primary, PyObject shadow) { this(subtype, primary, shadow, new PyList()); } private PyShadowString(PyType subtype, PyObject primary, PyObject shadow, PyList targets) { super(subtype, primary.__str__().getString()); this.shadow = shadow.__str__(); this.targets = targets; } @ExposedNew static PyObject shadowstr_new(PyNewWrapper new_, boolean init, PyType subtype, PyObject[] args, String[] keywords) { ArgParser ap = new ArgParser("shadowstr", args, keywords, new String[] {"primary", "shadow"}, 0); PyObject valueObj = ap.getPyObject(0, Py.EmptyString); PyObject shadowObj = ap.getPyObject(1, Py.EmptyString); if (valueObj instanceof PyString && shadowObj instanceof PyString) { return new PyShadowString(valueObj, shadowObj); } else { String message = String.format("arguments must be strings not (%.200s, %.200s)", valueObj.getType(), shadowObj.getType()); throw Py.TypeError(message); } } /** Convert a PyObject (specifying a regex) to a compiled pattern or null. */ private static Pattern getPattern(PyObject o) { if (o instanceof PyString) { return Pattern.compile(o.toString()); } else { return null; } } /** * Test whether the current code is executing in of one of the target contexts, by searching up * the stack for a class and method pait that match. * * @return true iff in one of the named contexts */ private boolean isTarget() { // Get a stack trace by constructing an exception here Exception exc = new Exception(); for (PyObject obj : targets.getList()) { // Only process proper tuple entries if (obj instanceof PyTuple && ((PyTuple) obj).__len__() >= 2) { // Compile the target specification PyTuple target = (PyTuple) obj; Pattern clazz = getPattern(target.__finditem__(0)); Pattern method = getPattern(target.__finditem__(1)); // Now scan the stack using this pair of patterns for (StackTraceElement ste : exc.getStackTrace()) { if (clazz == null || clazz.matcher(ste.getClassName()).matches()) { // Either we don't care about the class it matches, and ... if ((method == null || method.matcher(ste.getMethodName()).matches())) { // Either we don't care about the method name or it matches return true; } } } } } // Nothing matched return false; } /** Get the shadow value. */ public PyString getshadow() { return shadowstr_getshadow(); } @ExposedMethod public final PyString shadowstr_getshadow() { return shadow; } /** * Specify a context (class, method) in which the shadow string is allowed to match. * * @param className class name to match or null to match anything. * @param methodName method name to match or null to match anything. */ public void addTarget(String className, String methodName) { shadowstr_addtarget( // className == null ? Py.None : Py.newUnicode(className), methodName == null ? Py.None : Py.newUnicode(methodName)); } @ExposedMethod(defaults = {"null"}) public final void shadowstr_addtarget(PyObject classname, PyObject methodname) { // In principle these could be unicode strings PyTuple entry = new PyTuple(asUnicode(classname), asUnicode(methodname)); targets.add(entry); } /** Prepare argument for addtarget, allowing string-like values or None. */ private static PyObject asUnicode(PyObject o) { if (o == null || o == Py.None) { return Py.None; } else if (o instanceof PyString) { return o.__unicode__(); } throw Py.TypeError(String.format("string or None required, not %.200s", o.getType())); } /** * Return a list of the tuples specifying the contexts in which the shadow value will be * consulted during matching. */ public PyList getTargets() { return (PyList) shadowstr_gettargets(); } @ExposedMethod public final PyObject shadowstr_gettargets() { return targets; } /** * Compare this PyShadowString with another PyObject for equality. A * PyShadowString is equal to the other object if its primary value is equal to it, * or if its shadow value is equal to the other object and the test is made in one of its target * contexts. (Two PyShadowString are equal if the primary values are equal, the * primary of one matches the shadow of the other in the shadow's context, or their shadows * match and both are in context. * * @param other to compare * @return PyBoolean result (or null if not implemented) */ @Override public PyObject __eq__(PyObject other) { return shadowstr___eq__(other); } @ExposedMethod(type = MethodType.BINARY) final PyObject shadowstr___eq__(PyObject other) { // Re-wrap the primary value as a PyString to invoke the right kind of equality test. PyObject result = testEqual(new PyString(getString()), other); if (result != Py.False) { // True, or null if str does not know how to compare with other (so we don't either). return result; } else if (targets.isEmpty()) { // We aren't going to be using our shadow string return Py.False; } else { // Since we have targets, compare the shadow string with the other object. result = testEqual(shadow, other); if (result == Py.True) { // It matches, so the result is true iff we are in a target context return Py.newBoolean(isTarget()); } else { return result; } } } /** * Test for equality, used as a helper to shadowstr___eq__, dealing with the * possibility that other is another PyShadowString. */ private static final PyObject testEqual(PyString string, PyObject other) { if (other instanceof PyShadowString) { return ((PyShadowString) other).shadowstr___eq__(string); } else { return string.__eq__(other); } } @Override public PyObject __getslice__(PyObject start, PyObject stop, PyObject step) { PyObject primary = super.__getslice__(start, stop, step); PyObject shadow = this.shadow.__getslice__(start, stop, step); return new PyShadowString(primary, shadow, targets); } @Override public boolean startswith(PyObject prefix) { return shadowstr_startswith(prefix, null, null); } @Override public boolean startswith(PyObject prefix, PyObject start) { return shadowstr_startswith(prefix, start, null); } @Override public boolean startswith(PyObject prefix, PyObject start, PyObject end) { return shadowstr_startswith(prefix, start, end); } @ExposedMethod(defaults = {"null", "null"}) final boolean shadowstr_startswith(PyObject prefix, PyObject startObj, PyObject endObj) { return super.startswith(prefix, startObj, endObj) // || (!targets.isEmpty() && shadow.startswith(prefix, startObj, endObj) && isTarget()); } @Override public PyString __repr__() { return shadowstr___repr__(); } @ExposedMethod final PyString shadowstr___repr__() { // What you'd type to get this instance (without targets). String fmt = "PyShadowString(%.200s, %.200s)"; return Py.newString(String.format(fmt, super.__repr__(), shadow.__repr__())); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy