If I made a python file named hello.py that has a script made like this.
msg = input("insert your message here: ")
script = '''
def say_something():
print("{msg}")
'''
exec(script)
say_something()
And then I tried to use Cython
from distutils.core import setup
from Cython.Build import cythonize
setup(
ext_modules=cythonize("Hello.py")
)
It will show an error like this: undeclared name not builtin: say_something
I do understand why this happens but I'm not really an expert with python and C just yet. This is just an example, but it's similar to what I'm trying to do with one of my projects. Is there any way I could resolve this? I want to find a way to convert the script string into C as well.
I was trying to build an editable python script.
Cython compiles the Python functions to a native binary that does what the CPython interpreter should do. exec is a function that execute arbitrary code at runtime (which is generally a very bad idea for speed, maintainability/readability and security). Cython does not support exec because it would mean that the could would be compiled at runtime. Thus, the code executed by exec cannot be a Cython code. However, the exec function can still be used to execute a pure-Python code. The error can be removed by turning off the Cython.Compiler.Options.error_on_unknown_names in the setup script (just before calling setup) as pointed out by #DavidW. With this Cython will not complain when it does not find a function defined by exec (or similar methods). Please keep in mind that CPython can only be used in this case instead of Cython (which partially defeat the purpose of using Cython in the first place).
Related
I am attempting to use the LMDB C API with Cython.
I want to import the following definitions from the header file:
typedef struct MDB_env MDB_env;
int mdb_env_create(MDB_env **env);
So I created a .pxd file:
cdef extern from 'lmdb.h':
struct MDB_env:
pass
int mdb_env_create(MDB_env **env)
And I am using it in a Cython script:
cdef MDB_env *e
x = mdb_env_create(&e)
This code compiles fine, but If I run it, I get:
ImportError: /home/me/.cache/ipython/cython/_cython_magic_15705c11c6f56670efe6282cbabe4abc.cpython-36m-x86_64-linux-gnu.so: undefined symbol: mdb_env_create
This happens both in a Cython .pyx + .pxd setup and in a prototype typed in IPython.
If I import another symbol, say a constant, I can access it. So I seem to be looking at the right header file.
I don't see any discrepancy between my syntax and the documentation, but I am clearly doing something wrong. Can somebody give me a hint?
Thanks.
To compile it with IPythons-magic (would be nice if you would mention this explicitly in your question) you have to provide library-path (via -L-option) and library name (via -l-option) of the built c-library you want to wrap, see also the documentation:
%%cython -L=<path to your library> -l=<your_library>
The library you are trying to wrap is not a header-only library. That means that some symbols (e.g. mdb_env_create) are only declared but not defined in the header. When you build the library, the definitions of those symbols can be found in the resulting artifact, which should be provided to the linker when your extension is built. These definitions is what is needed when the program runs.
If you don't do it, the following happens on Linux: When the extension (the *.so-file) is built,the linker allows undefined symbols per default - so this step is "successful" - but the failure is only postponed. When the extension is loaded via import, Python loads the corresponding *.so with help of ldopen and in this step loader checks that the definitions of all symbols are known. But we didn't provide a definition of mdb_env_create so, the loader fails with
undefined symbol: mdb_env_create
It is differently for symbols which are defined in the header-file, for example enums MDB_FIRST&Co - the compiled library isn't necessary and thus the extension can be loaded, as there are no undefined symbols.
The following code defines a simple Cython function (using Ipython magic, for convenience).
%load_ext cython
%%cython
def f(float x, float y=2):
return x+y
Then, calling help(f) gives this message:
Help on built-in function f in module _cython_magic_e37eeabbc63d5167217465ba978239fc:
f(...)
Note that the arguments of f are not shown. Also, the tab-completion does not work either for the argument names in ipython (e.g. typing f(x then tab).
If I define this function without using Cython:
def g(x, y=2):
return x+y
Calling help(g) gives this and the tab-completion works as expected:
Help on function g in module __main__:
g(x, y=2)
Is there a way to get this behavior with the Cython function? I tried with def, cdef, cpdef, with and without ipython magic, with no success.
Disagree with the agreed answer.
While enabling binding does have the side-effect of documentation strings showing up in code, it also binds all other Python class attributes to Cython extension classes which makes for lower performance, more memory used for each extension object and so on.
The correct flag to enable docstrings only without side effects is embedsignature=True.
It can either be used as decorator - #cython.embedsignature(True) on top of all functions, or part of cython directives in setup.py Extension to apply to all Cython functions - {'embedsignature': True}
From docs:
embedsignature (True / False)
If set to True, Cython will embed a textual copy of the call signature in the docstring of all Python visible functions and
classes. Tools like IPython and epydoc can thus display the signature,
which cannot otherwise be retrieved after compilation. Default is
False.
import cython
#cython.binding(True)
def f(float x, float y=2):
# ...
now help(f) gives
Help on cython_function_or_method in module cy_exc:
f(x, y=2.0)
The documentation says
When enabled, functions will bind to an instance when looked up as a class attribute (hence the name) and will emulate the attributes of Python functions, including introspections like argument names and annotations. Default is False.
You can enable the compilation option in other ways (for example, if you want it enabled everywhere).
You might also want to look at this related question
Is there a ready or idiomatic way of declaring an entry point in a Julia program (i.e. the equivalent of main in C or the if __name__ == "__main__" construct in Python)?
This seems to be an important functionality in order to write larger pieces of structured code that won't be used in interactive mode but I couldn't find any hints as to how this is accomplished in Julia, if at all (a possible escape route could be writing an arbitrary function to serve as main and then calling it once on the top level at the end of the main module but that's not elegant and maybe not even efficient). TIA.
You could write a main function and not call it from the top level of the file. To run the program from the command line you would use julia -L file.jl -e 'main(some,args)'. The -L switch tells Julia to load your file, and then -e tells it to evaluate the following expression. There is also an -E switch that evaluates and prints (I think of it as "evaluating out loud", since capital letters seem "loud").
This has a couple of advantages over C's main or Python's if __name__ == "__main__":
You don't have to have a single entry point! You can evaluate any expression at all after loading your file, so you don't have to cram all your command line functionality into one function.
The calls you write use full Julia syntax, so often you can avoid parsing the arguments. Soemthing like -e main(53) calls main with the integer 53, no need for atoi inside main.
When modules are loaded, if they have a function called __init__ it will be called. Does that help?
If you want to do what the if __name__ == "__main__": idiom in python does, I found that
if !isdefined(Base, :active_repl)
main()
end
does the trick.
I often find myself wanting to be able to load my main file into a REPL and selectively poke at some of the functions without invoking main or staple a CLI onto a module that is mostly intended as a library module, so I really like this trick from python.
Environment Details
Mac OS X 10.9
Oracle JDK 1.7.0_55 64-bit
jython-standalone-2.5.3.jar
junit-4.11
What I have done so far
I have added the junit jar to /Library/Java/Extensions.
I invoked Jython as follows java -jar jython-standalone-2.5.3.jar
In the Jython interpreter, I imported the following import org.junit.Assert, and this import was successful.
Problem
When I tried to use assertTrue, I got a NameError in the interpreter. Why is this so?
I understand that assertTrue is a static method. Not sure what implication this has when I try to use it in Jython.
Additional Context
I am using XMLUnit in Jython. Was able to successfully import the Diff class from org.custommonkey.xmlunit in Jython. Also able to use the methods in this class, and call them on a Diff object. The result of this method call is what I am trying to pass to assertTrue, when it throws the error.
from org.custommonkey.xmlunit import Diff
import org.junit.Assert
xml1 = ...some XML string...
xml2 = ...some XML string...
myDiff = Diff(xml1, xml2)
assertTrue(myDiff.similar())
Hope this additional information is useful in identifying a solution to this problem.
Latest Status
I narrowed it down to setting this property python.security.respectJavaAccessibility = false, since the Assert() constructor is protected.
Still trying to get it to work. Any help is greatly appreciated.
Figured it out.
In addition to junit.jar file, the hamcrest-core.jar file also needed to be copied to /Library/Java/Extensions.
Then I got rid of the jython.jar file, and instead installed it using the jython installer.
After the installation was completed, I updated the registry file in the installation folder, specifically setting this property python.security.respectJavaAccessibility = false.
Now I am able to see the assertTrue method, and no longer getting a NameError.
I have problems while generating .java files with jruby 1.7.3. Here is an example:
class Duck
def quack()
puts "quack!";
end
end
def quack_it(duck)
duck.quack
end
a = Duck.new
quack_it(a)
when I execute
jrubyc --java Test.rb I get the following compilation error:
Failure during compilation of file DuckExample_simple.rb:
undefined method `new_method' for nil:NilClass.
Therefore, I have 2 questions:
What is wrong here?
I want to generate .java files in order to see how the JRuby code is translated into the bytecode and instead of reading the bytecode itself I thought to read the java code. Does the generated java code correspond 1 to 1 to the bytecode generated by AOT jruby compiler, or it's better to read the bytecode itself? I actually want to see how jruby handles dynamic method dispatch at the bytecode level. Any hints would be appreciated.
i don't use jruby so i am not really the best guy to talk to, but here are my 2 cents anyways.
if you just put a simple class into the file, it will work. so try
class Duck
def quack()
puts "quack!"
end
end
it will create a Duck.java file as you would expect, which answeres the second question you had. there is also a nice writeup about the generated file here: http://rhnh.net/2012/10/20/guice-in-your-jruby
i guess that the command is somewhat broken. it would be best to open an issue at the jruby issue tracker: http://jira.codehaus.org/browse/JRUBY