========================================
wxPython Project Phoenix Migration Guide
========================================

wxPython's Project Phoenix is a new incarnation of the wxPython
toolkit in which everything that existed before will be cast into the
flames in the hopes that that which emerges from the ashes will be
better, brighter, stronger and faster than before.  For more details
about why and how, please see the ProjectPhoenix_ pages in the
wiki.

.. _ProjectPhoenix: http://wiki.wxpython.org/ProjectPhoenix

This document will describe some of the incompatibilities that
programmers will run into when migrating code from Classic wxPython to
the Phoenix.  For some types of changes there won't be any attempt to
document the nitty gritty details of the differences, but rather the
general patterns of the changes will be documented.  Most programmers
should then be able to work out the details for themselves.


Version Numbers
---------------

Classic wxPython used version numbers with 4 components, in order to be able
to specify the exact version of wxWidgets used (3 version number components)
and an additional component to allow for multiple wxPython releases for each
wxWidgets release. While this version numbering works okay and solves a
specific need that wxPython had, it does not follow the common version
numbering pattern that probably 99% of other software packages use and so it
is non-intuitive for most users.

So Phoenix will be moving to a 3 component version number, where the first 2
components match the MAJOR.MINOR version of wxWidgets being used, and the 3rd
component of the version number is used to indicate the release of wxPython
Phoenix using that version of wxWidgets.  It is felt that matching the 3rd
component of the wxWidgets is no longer as important as it was in the past,
because the wxWidgets source is being included with the Phoenix source, so
matching exact versions of the two packages by hand is no longer needed.

Additional flags will be appended to the version number in a manner that is
compliant with Python's PEP-440_. This includes syntax for alpha, beta,
release candidate releases, post-release builds, development snapshots, etc.
See `buildtools/version.py` in the Phoenix build tree for more details.

.. _PEP-440: https://www.python.org/dev/peps/pep-0440/


Overloaded Functions
--------------------

In order to support more than one of the versions of an overloaded C++
function or class method in Classic wxPython, we had to rename all but
one of them.  For example, for the wxWindow::SetSize method we have
SetSize, SetDimensions, SetRect and SetSizeWH.  One of the features of
the new tools used for Project Phoenix is that we no longer need to do
that and instead we can have just one function or method in the Python
API and the proper version of the C++ function or method is chosen at
runtime based on the number and types of parameters passed to the
function. So in most cases the renamed versions of the overloaded
functions have been removed and you can call the function with the same
name as the C++ API.

This also includes the default constructor for all widget classes,
used for the 2-phase create. Previously they were renamed to be the
class name with "Pre" prepended to it.  For example, wx.PreWindow(),
wx.PreFrame(), etc.  Now in the Phoenix build of wxPython that is no
longer necessary and you can just call the class with no parameters
like normal.

For those renamed items that are more commonly used in the old Classic
wxPython I'll add some aliases that will issue a DeprecationWarning for
the first release or two after we switch over to the Phoenix version
of the code, and then remove them in a later release.

For a (relatively comprehensive) list of classes, functions and methods
which need modification while porting your code from Classic to Phoenix,
please see the :ref:`Classic vs. Phoenix <classic vs phoenix>` document.


Static Methods 
-------------- 

In the distant past when SWIG was generating wrapper code for C++ static
methods it would create a standalone function named ClassName_MethodName for
it. When Python added support for static methods then SWIG was able to use
that to make a real static method named ClassName.MethodName, but it still
generated the standalone function named with the underscore, for
compatibility. That underscore version of the static methods is now gone, and
you will get an AttributeError in existing code that is using them. To fix
the problem simply change the underscore to a dot, for example you should
change this::

    c = wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENUTEXT)
    
to this::

    c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_MENUTEXT)

You can also make this change in your existing code that is using pre-Phoenix
versions of wxPython, in order to help you prepare for the transition.




Unicode and Auto-Converting Strings
-----------------------------------

Starting with the wxPython 2.9 release series, there are no longer
separate ansi/Unicode builds of wxPython.  All wxPython builds are now
essentially the same as the old Unicode builds. This means that all
string objects passed to wx API functions or methods are converted to
Unicode before calling the C++ function or method.  By default Classic
wxPython would use the encoding specified by the locale that was
current at the time of the import of the wx module.

However using the default locale could sometimes cause issues because
it meant that slightly different encodings could be used on different
platforms, even in the same locale, or the program could end up using
an encoding in a different locale that the developer has not tested
their code with.

Project Phoenix takes this Unicode simplification one step further by
stipulating that only the utf-8 encoding will be used for
auto-converting string objects to the Unicode objects that will be
passed on to the wx APIs.  If you need to deal with text using a
different encoding then you will need to convert it to Unicode
yourself before passing the text to the wx API.  For the most part this
should not be much of a problem for well written programs that support
Unicode because they will typically only convert to/from Unicode when
reading/writing text to a file or database, and will use Unicode objects
throughout the rest of the code.  The common exception to this is that
string-literals are often used in the code for specifying labels,
etc. for UI elements.  If your text for the string literals in your
code are all ascii or utf-8 then you should not need to make any
changes at all.  If you have literals with some other encoding then
you'll need to deal with them one way or another, either change the
encoding of your source file to utf-8, or convert the literals from
your encoding to Unicode before passing the text to the wx API.

In Python 3.x, where strings are already Unicode objects, most of the above
confusion goes away, however if you have bytes objects then the same rules of
auto-converting only from utf-8 will still apply.


Font, Pen, and Brush Styles
---------------------------

The following aliases are currently added for backwards compatibility,
but will be removed in a future release.  You should migrate any code
that is using the old names to use the new ones instead::

            wx.DEFAULT    = wx.FONTFAMILY_DEFAULT
            wx.DECORATIVE = wx.FONTFAMILY_DECORATIVE
            wx.ROMAN      = wx.FONTFAMILY_ROMAN
            wx.SCRIPT     = wx.FONTFAMILY_SCRIPT
            wx.SWISS      = wx.FONTFAMILY_SWISS
            wx.MODERN     = wx.FONTFAMILY_MODERN
            wx.TELETYPE   = wx.FONTFAMILY_TELETYPE

            wx.NORMAL = wx.FONTWEIGHT_NORMAL
            wx.LIGHT  = wx.FONTWEIGHT_LIGHT
            wx.BOLD   = wx.FONTWEIGHT_BOLD
            
            wx.NORMAL = wx.FONTSTYLE_NORMAL
            wx.ITALIC = wx.FONTSTYLE_ITALIC
            wx.SLANT  = wx.FONTSTYLE_SLANT
            
            wx.SOLID       = wx.PENSTYLE_SOLID
            wx.DOT         = wx.PENSTYLE_DOT 
            wx.LONG_DASH   = wx.PENSTYLE_LONG_DASH 
            wx.SHORT_DASH  = wx.PENSTYLE_SHORT_DASH 
            wx.DOT_DASH    = wx.PENSTYLE_DOT_DASH 
            wx.USER_DASH   = wx.PENSTYLE_USER_DASH 
            wx.TRANSPARENT = wx.PENSTYLE_TRANSPARENT 

            wx.STIPPLE_MASK_OPAQUE = wx.BRUSHSTYLE_STIPPLE_MASK_OPAQUE 
            wx.STIPPLE_MASK        = wx.BRUSHSTYLE_STIPPLE_MASK 
            wx.STIPPLE             = wx.BRUSHSTYLE_STIPPLE 
            wx.BDIAGONAL_HATCH     = wx.BRUSHSTYLE_BDIAGONAL_HATCH 
            wx.CROSSDIAG_HATCH     = wx.BRUSHSTYLE_CROSSDIAG_HATCH 
            wx.FDIAGONAL_HATCH     = wx.BRUSHSTYLE_FDIAGONAL_HATCH 
            wx.CROSS_HATCH         = wx.BRUSHSTYLE_CROSS_HATCH 
            wx.HORIZONTAL_HATCH    = wx.BRUSHSTYLE_HORIZONTAL_HATCH 
            wx.VERTICAL_HATCH      = wx.BRUSHSTYLE_VERTICAL_HATCH 



wx.PyDeadObjectError --> RuntimeError
-------------------------------------

Classic wxPython tracks when the C++ part of some types of objects (pretty
much just window types) is destroyed and then replaces the proxy object's
class with one that raises a wx.PyDeadObjectError exception. SIP takes care of
that for us now in a much better way, so that custom hack is no longer
present in Phoenix, however a RuntimeError is the exception that is raised
now. The wx.Window class has a __nonzero__ method that tests if the C++
object has been deleted, so you can still test the window with an if or other
conditional statement to see if it is safe to use, like this::

    if someWindow:
        someWindow.doSomething()
        
        
        
wx.PyAssertionError --> wx.wxAssertionError
-------------------------------------------

This is the exception raised when one of the wxASSERT (or similar) statements
in the wx C++ code fails. Since it is a wxWidgets assertion and not a
wxPython assertion the name was changed to make that a little more clear. A
compatibility alias exists so using wx.PyAssertionError will still work, but
you should migrate those uses to wx.wxAssertionError if possible.




The 'wx' namespace and submodules reorganized
---------------------------------------------

Some reorganization of what classes and functions goes in which internal wx
extension module has been done. In Classic the organization of the extension
modules was somewhat haphazard and chaotic. For example there were 5 separate
modules whose contents were loaded into the main "wx" package namespace and
several others that needed to be imported separately. However since there was
not much organization of the core the C++ wxadv and wxhtml DLLs would need to
be distributed with any applications built with a bundling tool even if the
application did not use any of those classes.

For Phoenix the location of the wrapper code for the classes and functions
will attempt to follow the same organization that wxWidgets uses for putting
those same classes and functions into DLLs or shared libraries. This means
that some things that were formerly in the core wx package namespace are no
longer there. They will have to be used by importing a wx submodule. Most of
them will be in the wx.adv module. One nice advantage of doing this is that
if your application is not using any of these lesser used classes then you
will not have to bundle the new modules (nor the associated wx DLLs) with
your application when you use py2exe or other executable builder. See
the :ref:`Classic vs. Phoenix <classic vs phoenix>` document for details.



wx.ListCtrl
-----------

In wx.ListItem and wx.ListEvent the ``"m_"`` properties are no longer
public. Instead use the associated getter/setter methods or the
auto-generated properties that are using them.



wx.TreeCtrl
-----------

The GetItemData and SetItemData now behave just like GetItemPyData
and SetItemPyData did in Classic wxPython.  In other words, instead
of needing to create and use instances of wx.TreeItemData to
associate Python data objects with tree items, you just use the
Python objects directly.  It will also work when passing the data
objects directly to the AppendItem, InsertItem, etc. methods.  (If
anybody was actually using the wx.TreeItemData objects directly
before and are unable to adapt then please let Robin know.)  The
[G|S]etItemPyData members still exist, but are now deprecated
aliases for [G|S]etItemData.



wx.DragImage
------------

Phoenix is providing both wx.DragImage and wx.GenericDragImage classes.
Classic wxPython only provided wx.DragImage, but it was actually using
wx.GenericDragImage internally for all platforms. wx.DragImage will now be a
native implementation on Windows, and will still be the generic version
elsewhere. If you would rather use the generic implementation on Windows too
then switch to using the wx.GenericDragImage class name.


2-Phase Create
--------------

In Classic wxPython we had to do some fancy footwork to make use of
wxWidget's 2-Phase Create scheme for creating instances of a C++ widget
class, but delaying the creation of the UI object until later. (This is
needed for things like setting extended style flags that can not be set after
creation, or with class factories like XRC.) The old trickery should no
longer be needed, and instead you can write code that is much more sane. For
example, instead of Classic code like this::

    class MyDialog(wx.Dialog):
        def __init__(self, parent, ID, title):
            pre = wx.PreDialog()
            pre.SetExtraStyle(wx.FRAME_EX_CONTEXTHELP)
            pre.Create(parent, ID, title)
            self.PostCreate(pre)                           # 4

In Phoenix that should now be done like this::

    class MyDialog(wx.Dialog):
        def __init__(self, parent, ID, title):
            wx.Dialog.__init__(self)                       # 1
            self.SetExtraStyle(wx.FRAME_EX_CONTEXTHELP)    # 2
            self.Create(parent, ID, title)                 # 3


Notice that we are (#1) calling the base class __init__ like usual,
but passing no parameters so the default C++ constructor will be
invoked. Next (#2, #3) we use self instead of pre because self is now
a legitimate instance of wx.Dialog, and (#4) there is no longer any
need to call PostCreate to do its black magic for us because there is
no longer a rogue instance that needs to be transplanted into self.



wx.Image and Python Buffer Objects
----------------------------------

wx.Image is now using the new buffer APIs for the constructors and
methods which accept any object supporting the buffer protocol.  These
are methods which allow you to set the raw RGB or Alpha data in the
image in one step.  As a consequence of using the new APIs the objects
passed must also implement the new buffer interface in order to be
compatible.  

GetData and GetAlpha now return a copy of the image data as a
bytearray object instead of a string object.  This means that since
bytearrays are mutable you can do things like make changes to the data
and then use it in the SetData of another image.  

GetDataBuffer and GetAlphaBuffer now return memoryview objects, which
allow direct access to the RGB and Alpha buffers inside the image.
Just as in Classic you should not use those memoryview buffers after
the wx.Image has been destroyed.  Using the returned memoryview object
you can manipulate the RGB or Alpha data inside the wx.Image without
needing to make a copy of the data.

Just as in Classic the SetDataBuffer and SetAlphaBuffer methods allow
you to tell the wx.Image to use memory buffers in other objects (such
as a numpy array) as its RGB or Alpha data, as long as the other
object supports the new buffer protocol.



wx.DropSource
-------------

We don't (yet) have an easy way to support different APIs per platform
in the wx class constructors, so wx.DropSource (which optionally takes
parameters that should be a wx.Icon on wxGTK or a wx.Cursor on the
other platforms) has been changed to not accept the cursor/icon in the
constructors.  Instead you'll have to call either SetCursor or SetIcon
depending on the platform.



wx.DataObject and derived classes
---------------------------------

The wx.DataObject and wx.DataObjectSimple classes can now be
subclassed in Python.  wx.DataObject will let you provide complex
multi-format data objects that do not need to copy the data until one
of the formats is requested from the clipboard or a DnD operation.
wx.DataObjectSimple is a simplification that only deals with one data
format, (although multiple objects can still be provided with
wx.DataObjectComposite.)

Python buffer objects are used for transferring data to/from the
clipboard or DnD partner.  Anything that supports the buffer protocol
can be used for setting or providing data, and a memoryview object is
created for the APIs where the data object should fetch from or copy
to a specific memory location.  Here is a simple example::

        class MyDataObject(wx.DataObjectSimple):
            def __init__(self, value=''):
                wx.DataObjectSimple.__init__(self)
                self.SetFormat(wx.DataFormat("my data format"))
                self.myData = bytes(value)
                
            def GetDataSize(self):
                return len(self.myData)
            
            def GetDataHere(self, buf):
                # copy our local data value to buf
                assert isinstance(buf, memoryview)
                buf[:] = self.myData
                return True
                            
            def SetData(self, buf):
                # copy from buf to our local data value
                assert isinstance(buf, memoryview)
                self.myData = buf.tobytes()
                return True



Multiple Inheritance
--------------------

The SIP tool currently does not support having more than one wrapped
C++ class as the base classes of a Python class.  In most cases this
is not a problem because in wxPython you're more likely to use
multiple inheritance with simple mix-in classes or similar constructs
than needing to inherit from more than one wx class.

However there is at least one use case where that can be a problem,
and that is with the ComboCtrl's wx.ComboPopup class.  In wxWidgets
and also in Classic wxPython you're encouraged to use wx.ComboPopup as
a mix-in class combined with the widget class that is going to be
your popup window for the wx.ComboCtrl.  This can not currently be
done with Phoenix in the same way, but you can also use a widget class
with a wx.ComboPopup in a has-a relationship rather than an is-a
relationship.  See samples/combo/combo1.py for an example.



XRC
---

The "LoadOnFoo" methods of the XmlResource class were renamed overloads of
the corresponding "LoadFoo" methods. Since we no longer need to rename
overloaded methods the "LoadOn" version has been removed and you should just
use the "LoadFoo" version instead. These methods are used to load some XRC
content onto an existing window, such as a Frame, instead of creating a new
Frame for the content.



wx.PyEvent and wx.PyCommandEvent
--------------------------------

Unlike most other ``wx.Py`` classes these two still exist in Phoenix, and are
still the base classes that you should use when creating your own custom
event classes. For the most part they work just like they did in Classic, and
they take care of ensuring that any Python attributes that you assign to
instances of the class will still be there when the event is delivered to an
event handler. There is one main difference from Classic however, and that is
that those attributes are now stored in a dictionary object owned by the C++
instance, instead of being stored directly in the Python instance's
dictionary. In most cases this won't matter to you at all, but if your
derived class has a __getattr__ method (or __setattr__ or __delattr__) then
you will need to get the attributes from that other dictionary instead. You
can get a reference to that dictionary using _getAttrDict(). For example::

    def __getattr__(self, name):
        d = self._getAttrDict()
        if name in d:
            return d[name]
        return getattr(self._someOtherThing, name)



MakeModal
---------

Since it is usually not a good idea to make arbitrary top-level windows be
modal, (you should just use a wx.Dialog instead,) the MakeModal method has
been removed. The recommended alternative is to use the wx.WindowDisabler
class instead, but if you prefer the semantics of having a method to call to
turn on or off the modalness of a window then you can add a method like this
to your classes to give you a way to do it::

    def MakeModal(self, modal=True):
        if modal and not hasattr(self, '_disabler'):
            self._disabler = wx.WindowDisabler(self)
        if not modal and hasattr(self, '_disabler'):
            del self._disabler



The wxversion module
--------------------

The ``wxversion`` module is gone, and will not be coming back.  The old way of
handling muti-version installs and choosing between them was a giant hack in
my opinion, and I regretted doing it not long after it was implemented.  However
since there wasn't any other way that made sense at the time, and since some
people were using it already, it got left in the distribution.  But one of the
purposes of the Phoenix project is to remove as many of the hacks and cruft
from Classic as possible, so wxversion is gone.

These days there are **much** better ways to handle the things that the old
multi-versioning and version selection features provided.  Since wxPython
Phoenix is built by default to be self-contained and relocatable on all of the
platforms, then unlike Classic there is no problem with installing it in
Python virtual environments.  So if you need to have multiple versions of
wxPython on your system, then create a virtual environment for each project
and install the version that each needs in their environments.  If you have
code that requires a specific version or range of versions of wxPython then
define the dependency in your ``setup.py`` file or a ``requirements.txt`` file
and let ``pip`` take care of the details.  I'm confident that you'll be much
happier with this approach.



.. toctree::
   :maxdepth: 2
   :hidden:

   classic_vs_phoenix

