1 /**
2  * Copyright (c) 2016-2019 JEP AUTHORS.
3  *
4  * This file is licensed under the the zlib/libpng License.
5  *
6  * This software is provided 'as-is', without any express or implied
7  * warranty. In no event will the authors be held liable for any
8  * damages arising from the use of this software.
9  *
10  * Permission is granted to anyone to use this software for any
11  * purpose, including commercial applications, and to alter it and
12  * redistribute it freely, subject to the following restrictions:
13  *
14  *     1. The origin of this software must not be misrepresented; you
15  *     must not claim that you wrote the original software. If you use
16  *     this software in a product, an acknowledgment in the product
17  *     documentation would be appreciated but is not required.
18  *
19  *     2. Altered source versions must be plainly marked as such, and
20  *     must not be misrepresented as being the original software.
21  *
22  *     3. This notice may not be removed or altered from any source
23  *     distribution.
24  */
25 package jep;
26 
27 import java.io.File;
28 import java.util.HashSet;
29 import java.util.Set;
30 
31 /**
32  * <p>
33  * A configuration object for constructing a Jep instance, corresponding to the
34  * configuration of the particular Python sub-interpreter. This class is
35  * intended to make constructing Jep instances easier while maintaining
36  * compatible APIs between releases.
37  * </p>
38  *
39  * @author Nate Jensen
40  *
41  * @since 3.5
42  */
43 public class JepConfig {
44 
45     protected boolean interactive = false;
46 
47     protected StringBuilder includePath = null;
48 
49     protected ClassLoader classLoader = null;
50 
51     protected ClassEnquirer classEnquirer = null;
52 
53     protected boolean redirectOutputStreams = false;
54 
55     protected Set<String> sharedModules = null;
56 
57     /**
58      * Sets whether <code>Jep.eval(String)</code> should support the slower
59      * behavior of potentially waiting for multiple statements
60      *
61      * @deprecated Interactive mode will be removed in a future release. See
62      *             console.py for an example of how to interactively execute
63      *             Python using the builtin compile() and exec() functions.
64      *
65      * @param interactive
66      *            whether the Jep instance should be interactive
67      * @return a reference to this JepConfig
68      */
69     @Deprecated
setInteractive(boolean interactive)70     public JepConfig setInteractive(boolean interactive) {
71         this.interactive = interactive;
72         return this;
73     }
74 
75     /**
76      * Sets a path of directories separated by File.pathSeparator that will be
77      * appended to the sub-intepreter's <code>sys.path</code>
78      *
79      * @param includePath
80      *            directory or directories to include on sys.path
81      * @return a reference to this JepConfig
82      */
setIncludePath(String includePath)83     public JepConfig setIncludePath(String includePath) {
84         this.includePath = null;
85         if (includePath != null) {
86             this.includePath = new StringBuilder(includePath);
87         }
88         return this;
89     }
90 
91     /**
92      * Adds a path of directories separated by File.pathSeparator that will be
93      * appended to the sub-intepreter's <code>sys.path</code>
94      *
95      * @param includePaths
96      *            directories to include on sys.path
97      * @return a reference to this JepConfig
98      */
addIncludePaths(String... includePaths)99     public JepConfig addIncludePaths(String... includePaths) {
100         if (this.includePath == null) {
101             this.includePath = new StringBuilder();
102         }
103         for (String path : includePaths) {
104             if (this.includePath.length() > 0) {
105                 this.includePath.append(File.pathSeparator);
106             }
107             this.includePath.append(path);
108         }
109         return this;
110     }
111 
112     /**
113      * Sets the ClassLoader to use when importing Java classes from Python
114      *
115      * @param classLoader
116      *            the initial ClassLoader for the Jep instance
117      * @return a reference to this JepConfig
118      */
setClassLoader(ClassLoader classLoader)119     public JepConfig setClassLoader(ClassLoader classLoader) {
120         this.classLoader = classLoader;
121         return this;
122     }
123 
124     /**
125      * Sets a ClassEnquirer to determine which imports are Python vs Java, or
126      * null for the default {@link ClassList}
127      *
128      * @param classEnquirer
129      *            the ClassEnquirer for the Jep instance
130      * @return a reference to this JepConfig
131      */
setClassEnquirer(ClassEnquirer classEnquirer)132     public JepConfig setClassEnquirer(ClassEnquirer classEnquirer) {
133         this.classEnquirer = classEnquirer;
134         return this;
135     }
136 
137     /**
138      * Sets whether to redirect the Python sys.stdout and sys.stderr streams to
139      * the Java System.out and System.err streams
140      *
141      * @param redirectOutputStreams
142      *            whether to redirect Python streams to Java
143      * @return a reference to this JepConfig
144      */
setRedirectOutputStreams(boolean redirectOutputStreams)145     public JepConfig setRedirectOutputStreams(boolean redirectOutputStreams) {
146         this.redirectOutputStreams = redirectOutputStreams;
147         return this;
148     }
149 
150     /**
151      * Sets the names of modules which should be shared with other Jep
152      * sub-interpreters. This can make it possible to use modules which are not
153      * designed for use from Python sub-interpreters. This should not be
154      * necessary for any module written in Python but is intended for extensions
155      * that use the c-api. For a complete discussion of the types of problems
156      * that can require shared modules see the documentation on
157      * shared_modules_hook.py.
158      *
159      * @param sharedModules
160      *            a set of module names that should be shared
161      * @return a reference to this JepConfig
162      *
163      * @since 3.6
164      */
setSharedModules(Set<String> sharedModules)165     public JepConfig setSharedModules(Set<String> sharedModules) {
166         this.sharedModules = sharedModules;
167         return this;
168     }
169 
170     /**
171      * Adds module names to the set of shared modules
172      *
173      * @param sharedModule
174      *            a set of module names that should be shared
175      * @return a reference to this JepConfig
176      * @see #setSharedModules(Set)
177      *
178      * @since 3.6
179      */
addSharedModules(String... sharedModule)180     public JepConfig addSharedModules(String... sharedModule) {
181         if (sharedModules == null) {
182             sharedModules = new HashSet<>();
183         }
184         for (String sm : sharedModule) {
185             sharedModules.add(sm);
186         }
187         return this;
188     }
189 
190     /**
191      * Creates a new SubInterpreter instance and its associated sub-interpreter
192      * with this JepConfig.
193      *
194      * @deprecated Use {@link #createSubInterpreter()} instead.
195      *
196      * @return a new Jep instance
197      * @throws JepException
198      *             if an error occurs
199      * @since 3.8
200      */
201     @Deprecated
createJep()202     public Jep createJep() throws JepException {
203         return createSubInterpreter();
204     }
205 
206     /**
207      * Creates a new Jep instance and its associated sub-interpreter with this
208      * JepConfig.
209      *
210      * @return a new SubInterpreter instance
211      * @throws JepException
212      *             if an error occurs
213      * @since 3.9
214      */
createSubInterpreter()215     public SubInterpreter createSubInterpreter() throws JepException {
216         return new SubInterpreter(this);
217     }
218 
219 }
220