Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Tuesday, February 16, 2010

HTML in clipboard

It turns out copying/pasting hyperlinks to the windows clipboard isn't as easy as just copying the unformatted HTML. Turns out you need some crazy format inside of the clipboard for an application that handles HTML copy/paste to actually recognize it. Originally I looked for a solution using the Microsoft Office clipboard since that is where the html from the clipboard was going to be pasted to anyways, but it turns out there is no longer an object model for the office clipboard in versions past 2000. I ended up finding the solution to copy/pasting HTML in windows HTML Clipboard format.

This is what the clipboard actually looks like when you have HTML as your format in the clipboard:


Version:0.9
StartHTML:71
EndHTML:170
StartFragment:140
EndFragment:160
StartSelection:140
EndSelection:160
<!DOCTYPE>
<HTML>
<HEAD>
<TITLE> The HTML Clipboard</TITLE>
<BASE HREF="http://sample/specs">
</HEAD>
<BODY>
<UL>
<!--StartFragment -->
<LI> The Fragment </LI>
<!--EndFragment -->
</UL>
</BODY>
</HTML>



Some more information on the HTML clipboard format can be found Here
Standard clipboard formats can be found Here

To implement the HTML clipboard in python, I found a class Phillip Piper had written that does exactly what I need, that code can be found Here.

Also in my search I ran across this python script called PathCatcher - From the Doc String : PathCatcher is a Windows utility that allows one to right-click on
a folder or a file in Explorer and save its path to the clipboard. PathCatcher can be located Here

Thursday, February 11, 2010

Import errors - I always forget about this

Sometimes, boost can be a pain in the ass. I moved directories of the .pyd file as I was renaming everything and expanding the .pyd into different exposed modules. I thought I had messed something up, because when I tried importing the module in python, I got
ImportError: DLL load failed: The specified module could not be found.
I kept changing things on the C++ side trying to figure it out, and then I remembered, the boost.python dll needs to be in the same directory.

Moving it into the directory fixed the import issue. I'm full of fail this morning.

BOOST_PYTHON_STATIC_LIB vs BOOST_PYTHON_DYNAMIC_LIB

I have a pretty bad habit of changing things in one configuration and then not replicating the results in the others, so this morning while trying to compile in release I ran into a bunch of issues. Most were pretty easily solved, but then I ran into a linker error that I had solved yesterday, it took me a couple of minutes of comparing settings from configuration to configuration to figure it out but then I remembered. In my precompiled header I was getting these linker errors earlier yesterday:

1>precompiled.obj : error LNK2001: unresolved external symbol "private: static bool volatile boost::python::docstring_options::show_py_signatures_" (?show_py_signatures_@docstring_options@python@boost@@0_NC)
1>precompiled.obj : error LNK2001: unresolved external symbol "private: static bool volatile boost::python::docstring_options::show_user_defined_" (?show_user_defined_@docstring_options@python@boost@@0_NC)
1>precompiled.obj : error LNK2001: unresolved external symbol "private: static bool volatile boost::python::docstring_options::show_cpp_signatures_" (?show_cpp_signatures_@docstring_options@python@boost@@0_NC)


Web searches haven't been much help to explain why this is, and maybe I just don't know enough about boost to understand it, but the solution to this error is to change your preprocesser defines.

Previously I was using
BOOST_PYTHON_DYNAMIC_LIB
in my preprocessor defines, it works fine for everything else I've done, but something in my new project doesn't like it. The solution to this is to tell boost to static link instead by using
BOOST_PYTHON_STATIC_LIB
instead of
BOOST_PYTHON_DYNAMIC_LIB
.

When I have some more time I'm going to look into this a little bit more, I'd personally just like an explanation as to why I need to do this.

Wednesday, February 10, 2010

Boost Python and Custom Classes

Yesterday I started messing around with exposing our XML parsing code written in C++ to python using Boost.Python. I've gone down this road before, but never exposed a complex class structure to python. About 15 minutes into starting this task I realized that I would need to do that, I had no idea it was going to cause so many issues.

Simply exposing a class and the needed functions wasn't exactly straight forward. For about a day and a half I kept running into compiler issues with boost. Mainly involving compile errors along the lines of "specify_a_return_value_policy_to_wrap_functions_returning" in boost.

Scouring the interwebs for hours really didn't seem to yield many results, but I finally stumbled across the solution. It all has to do with defining the functions inside of the module. For example this is what my module looked like before I found my solution:


class_<parse_xml, boost::noncopyable>("parse_xml", boost::python::no_init)
.def("find_element", &parse_xml::find_element)
.def("find_next_element", &parse_xml::find_next_element)
.def("get_element_data", &parse_xml::get_element_data)
;

class_<xml_element>("xml_element");

def("get_filepath_from_vac", get_vdir_path_cf);
def("parse_chunkx", parse_chunkx);



Now this obviously wasn't working like I stated above, it turns out the key is to add another parameter to the .def function, boost::python::return_internal_reference<>().
What this does is tells boost that this function is returning a non-standard type. In my case it is returning a custom class. So, the moral of the story is, if you are using boost.python to expose a class or a function that returns a custom datatype, make sure you include boost::python::return_internal_reference<>() in the def arguments.

This is what my code looked like afterwards:


class_<parse_xml, boost::noncopyable>("parse_xml", boost::python::no_init)
.def("find_element", &parse_xml::find_element, boost::python::return_internal_reference<>())
.def("find_next_element", &parse_xml::find_next_element,boost::python::return_internal_reference<>())
.def("get_element_data", &parse_xml::get_element_data,boost::python::return_internal_reference<>())
;

class_<xml_element>("xml_element");

def("get_filepath_from_vac", get_vdir_path_cf);
def("parse_chunkx", parse_chunkx, boost::python::return_internal_reference<>());



Another thing that I've run into on this is trying to access parameters on an exposed struct wasn't working as expected. It comes down to the fact that if you have a char * that you want to access in python, you simply can't without having a wrapper for it. When trying to access a char *, you lose the sizing information, which makes it basically useless to python.

So, to access a char * member, you need to write a wrapper function that returns a const char *. For example:



const char *parse_xml::get_value_from_element(xml_element *root) {
return root->text;
}



Now I can easily access the member variable I was going after.