diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml
index 88913f03..4b968844 100644
--- a/.github/workflows/ci-build.yml
+++ b/.github/workflows/ci-build.yml
@@ -254,16 +254,16 @@ jobs:
submodules: 'recursive'
fetch-depth: 0
- - name: Set up Python 3.9
+ - name: Set up Python 3.13
uses: actions/setup-python@v5
with:
- python-version: '3.9'
+ python-version: '3.13'
cache: 'pip'
- name: Install Python dependencies
run: |
python -m pip install --upgrade -r requirements.txt
- python -m pip install pillow
+ python -m pip install --upgrade pillow numpy comtypes pywin32 cairocffi PyMuPDF
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
diff --git a/.gitignore b/.gitignore
index 14e46c46..e2acb59c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,8 +5,10 @@
.waf-*
.waf3-*
.lock-waf*
+.DS_Store
wingdbstub.py*
mydbstub.py*
+venv*/
.idea
.cache
@@ -27,6 +29,7 @@ mydbstub.py*
/bin/waf-*
/bin/waf3-*
/bin/doxygen-*
+/bin/libclang*
/demo/version.py
diff --git a/build.py b/build.py
index da09d1b8..de85259f 100755
--- a/build.py
+++ b/build.py
@@ -21,6 +21,11 @@ import os
import re
import shutil
import subprocess
+import requests
+from requests.exceptions import HTTPError
+import traceback
+from io import BytesIO
+import bz2
import tarfile
import tempfile
import datetime
@@ -83,11 +88,11 @@ wxICON = 'packaging/docset/mondrian.png'
wafCurrentVersion = '2.1.5'
wafMD5 = '2e7b2166c030dbac3e21891048df10aa'
-doxygenCurrentVersion = '1.8.8'
+doxygenCurrentVersion = '1.9.1'
doxygenMD5 = {
- 'darwin' : '71c590e6cab47100f23919a2696cc7fd',
- 'win32' : 'a3dcff227458e423c132f16f57e26510',
- 'linux' : '083b3d8f614b538696041c7364e0f334',
+ 'darwin' : '6912d41cef5971fb07573190849a8a84',
+ 'win32' : '90439896025dc8ddcd5d767ab2c2c489',
+ 'linux' : 'ed2c35099165fce0d07d9a1809935928',
}
# And the location where they can be downloaded from
@@ -525,7 +530,6 @@ def deleteIfExists(deldir, verbose=True):
shutil.rmtree(deldir)
except Exception:
if verbose:
- import traceback
msg("Error: %s" % traceback.format_exc(1))
else:
if verbose:
@@ -538,6 +542,49 @@ def delFiles(fileList, verbose=True):
print("Removing file: %s" % afile)
os.remove(afile)
+def errorMsg(txt, cmdname, envvar):
+ msg('ERROR: ' + txt)
+ msg(' Set %s in the environment to use a local build of %s instead' % (envvar, cmdname))
+
+def downloadTool(cmd, cmdname, envvar):
+ msg('Not found. Attempting to download...')
+ url = f"{toolsURL}/{os.path.basename(cmd)}.bz2"
+
+ try:
+ resp = requests.get(url)
+ resp.raise_for_status()
+ except HTTPError:
+ # The files could be packed as a tarball
+ url = url.replace(".bz2", ".tar.bz2")
+ try:
+ resp = requests.get(url)
+ resp.raise_for_status()
+ except HTTPError:
+ errorMsg('Unable to download ' + url, cmdname, envvar)
+ traceback.print_exc()
+ sys.exit(1)
+
+ msg('Connection successful...')
+ data = resp.content
+ msg('Data downloaded...')
+
+ if ".tar." in url:
+ with tarfile.open('r:bz2', fileobj=BytesIO(data)) as tar:
+ # Extraction filters are only available since Python 3.12
+ tar.extraction_filter = getattr(tarfile, 'data_filter',
+ (lambda member, path: member))
+ filelist = []
+ for file in tar.getmembers():
+ if file.name.startswith("doxygen") or \
+ file.name.startswith("libclang"):
+ filelist.append(file)
+
+ tar.extractall(members=filelist, path=os.path.dirname(cmd))
+ else:
+ data = bz2.decompress(data)
+ Path(cmd).write_bytes(data)
+
+ os.chmod(cmd, 0o755)
def getTool(cmdName, version, MD5, envVar, platformBinary, linuxBits=False):
# Check in the bin dir for the specified version of the tool command. If
@@ -546,88 +593,67 @@ def getTool(cmdName, version, MD5, envVar, platformBinary, linuxBits=False):
if os.environ.get(envVar):
# Setting a value in the environment overrides other options
return os.environ.get(envVar)
+
+ # setup
+ if platformBinary:
+ platform = getToolsPlatformName(linuxBits)
+ ext = ''
+ if platform == 'win32':
+ ext = '.exe'
+ cmd = opj(phoenixDir(), 'bin', '%s-%s-%s%s' % (cmdName, version, platform, ext))
+ md5 = MD5[platform]
else:
- # setup
- if platformBinary:
- platform = getToolsPlatformName(linuxBits)
- ext = ''
- if platform == 'win32':
- ext = '.exe'
- cmd = opj(phoenixDir(), 'bin', '%s-%s-%s%s' % (cmdName, version, platform, ext))
- md5 = MD5[platform]
- else:
- cmd = opj(phoenixDir(), 'bin', '%s-%s' % (cmdName, version))
- md5 = MD5
+ cmd = opj(phoenixDir(), 'bin', '%s-%s' % (cmdName, version))
+ md5 = MD5
+ msg('Checking for %s...' % cmd)
+ if os.path.exists(cmd):
+ # if the file exists run some verification checks on it
- def _error_msg(txt):
- msg('ERROR: ' + txt)
- msg(' Set %s in the environment to use a local build of %s instead' % (envVar, cmdName))
-
-
- msg('Checking for %s...' % cmd)
- if os.path.exists(cmd):
- # if the file exists run some verification checks on it
-
- # first make sure it is a normal file
- if not os.path.isfile(cmd):
- _error_msg('%s exists but is not a regular file.' % cmd)
- sys.exit(1)
-
- # now check the MD5 if not in dev mode and it's set to None
- if not (devMode and md5 is None):
- m = hashlib.md5()
- m.update(Path(cmd).read_bytes())
- if m.hexdigest() != md5:
- _error_msg('MD5 mismatch, got "%s"\n '
- 'expected "%s"' % (m.hexdigest(), md5))
- sys.exit(1)
-
- # If the cmd is a script run by some interpreter, or similar,
- # then we don't need to check anything else
- if not platformBinary:
- return cmd
-
- # Ensure that commands that are platform binaries are executable
- if not os.access(cmd, os.R_OK | os.X_OK):
- _error_msg('Cannot execute %s due to permissions error' % cmd)
- sys.exit(1)
-
- try:
- p = subprocess.Popen([cmd, '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=os.environ)
- p.communicate()
- except OSError as e:
- _error_msg('Could not execute %s, got "%s"' % (cmd, e))
- sys.exit(1)
-
- # if we get this far then all is well, the cmd is good to go
- return cmd
-
-
- msg('Not found. Attempting to download...')
- url = '%s/%s.bz2' % (toolsURL, os.path.basename(cmd))
- try:
- import requests
- resp = requests.get(url)
- resp.raise_for_status()
- msg('Connection successful...')
- data = resp.content
- msg('Data downloaded...')
- except Exception:
- _error_msg('Unable to download ' + url)
- import traceback
- traceback.print_exc()
+ # first make sure it is a normal file
+ if not os.path.isfile(cmd):
+ errorMsg('%s exists but is not a regular file.' % cmd,
+ cmdName, envVar)
sys.exit(1)
- import bz2
- data = bz2.decompress(data)
- Path(cmd).write_bytes(data)
- os.chmod(cmd, 0o755)
+ # now check the MD5 if not in dev mode and it's set to None
+ if not (devMode and md5 is None):
+ m = hashlib.md5()
+ m.update(Path(cmd).read_bytes())
+ if m.hexdigest() != md5:
+ errorMsg('MD5 mismatch, got "%s"\n '
+ 'expected "%s"' % (m.hexdigest(), md5),
+ cmdName, envVar)
+ sys.exit(1)
- # Recursive call so the MD5 value will be double-checked on what was
- # just downloaded
- return getTool(cmdName, version, MD5, envVar, platformBinary, linuxBits)
+ # If the cmd is a script run by some interpreter, or similar,
+ # then we don't need to check anything else
+ if not platformBinary:
+ return cmd
+ # Ensure that commands that are platform binaries are executable
+ if not os.access(cmd, os.R_OK | os.X_OK):
+ errorMsg('Cannot execute %s due to permissions error' % cmd,
+ cmdName, envVar)
+ sys.exit(1)
+
+ try:
+ p = subprocess.Popen([cmd, '--help'], stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, env=os.environ)
+ p.communicate()
+ except OSError as e:
+ errorMsg('Could not execute %s, got "%s"' % (cmd, e),
+ cmdName, envVar)
+ sys.exit(1)
+
+ # if we get this far then all is well, the cmd is good to go
+ return cmd
+
+ downloadTool(cmd, cmdName, envVar)
+
+ # Recursive call so the MD5 value will be double-checked on what was
+ # just downloaded
+ return getTool(cmdName, version, MD5, envVar, platformBinary, linuxBits)
# The download and MD5 check only needs to happen once per run, cache the sip
@@ -658,14 +684,12 @@ def getMSWebView2():
msg('Downloading microsoft.web.webview2 {}...'.format(MS_edge_version))
try:
- import requests
resp = requests.get(MS_edge_url)
resp.raise_for_status()
msg('Connection successful...')
data = resp.content
msg('Data downloaded...')
except Exception:
- import traceback
traceback.print_exc()
sys.exit(1)
@@ -1018,8 +1042,8 @@ def cmd_docset_py(options, args):
sys.exit(1)
# clear out any old docset build
- name = 'wxPython-{}'.format(cfg.VERSION)
- docset = posixjoin('dist', '{}.docset'.format(name))
+ name = 'wxPython-{}.docset'.format(cfg.VERSION)
+ docset = posixjoin('dist', name)
if os.path.isdir(docset):
shutil.rmtree(docset)
@@ -1036,7 +1060,7 @@ def cmd_docset_py(options, args):
# Remove the sidebar from the pages in the docset
msg('Removing sidebar from docset pages...')
- _removeSidebar(opj('dist', name+'.docset', 'Contents', 'Resources', 'Documents'))
+ _removeSidebar(opj('dist', name, 'Contents', 'Resources', 'Documents'))
# build the tarball
msg('Archiving Phoenix docset...')
@@ -1045,7 +1069,7 @@ def cmd_docset_py(options, args):
if os.path.exists(tarfilename):
os.remove(tarfilename)
with tarfile.open(name=tarfilename, mode="w:gz") as tarball:
- tarball.add(opj('dist', name+'.docset'), name+'.docset', filter=_setTarItemPerms)
+ tarball.add(opj('dist', name), name, filter=_setTarItemPerms)
if options.upload:
uploadPackage(tarfilename, options, keep=5,
@@ -1121,6 +1145,7 @@ def cmd_etg(options, args):
def cmd_sphinx(options, args):
from sphinxtools.postprocess import genIndexes, makeHeadings, postProcess, genGallery
+ from sphinxtools.stc_doc_postprocess import stc_categorise_methods
cmdTimer = CommandTimer('sphinx')
pwd = pushDir(phoenixDir())
@@ -1134,6 +1159,9 @@ def cmd_sphinx(options, args):
if not textFiles:
raise Exception('No documentation files found. Please run "build.py touch etg" first')
+ # Sort all wx.stc.StyledTextCtrl methods into categories
+ stc_categorise_methods()
+
# Copy the rst files into txt files
restDir = os.path.join(sphinxDir, 'rest_substitutions', 'overviews')
rstFiles = sorted(glob.glob(restDir + '/*.rst'))
@@ -1156,7 +1184,10 @@ def cmd_sphinx(options, args):
pwd2 = pushDir(sphinxDir)
buildDir = os.path.join(sphinxDir, 'build')
htmlDir = os.path.join(phoenixDir(), 'docs', 'html')
- runcmd('{} -m sphinx -b html -d {}/doctrees . {}'.format(PYTHON, buildDir, htmlDir))
+ sphinx_log = os.path.join(htmlDir, 'warnings', 'sphinx_warnings.log')
+
+ runcmd('"{}" -m sphinx --builder html --color --warning-file {} \
+ --doctree-dir {}/doctrees . {}'.format(PYTHON, sphinx_log, buildDir, htmlDir))
del pwd2
msg('Postprocessing sphinx output...')
@@ -1566,7 +1597,6 @@ def cmd_build_wx(options, args):
except Exception:
print("ERROR: failed building wxWidgets")
- import traceback
traceback.print_exc()
sys.exit(1)
diff --git a/docs/sphinx/_static/css/phoenix.css b/docs/sphinx/_static/css/phoenix.css
index 152b4014..da43c268 100644
--- a/docs/sphinx/_static/css/phoenix.css
+++ b/docs/sphinx/_static/css/phoenix.css
@@ -107,13 +107,18 @@ div.headerimage-noshow {
}
div.document {
- background-color: rgb(230,230,230);
- position: relative;
- margin-left: 240px;
+ background-color: rgb(230,230,230);
+ position: relative;
+ margin-left: 240px;
+ z-index: 500;
}
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
+ min-height: 98%;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
}
div.document-no-sidebar {
@@ -136,17 +141,17 @@ div.sphinxsidebar {
left: 0;
top: 30px;
bottom: 0;
+ z-index: 600;
}
-div#searchbox {
- margin-top: 30px;
+#searchbox {
+ margin-top: 1.8em;
+ flex-grow: 1;
}
-div#sourcelink {
- position: absolute;
- bottom: 0;
- font-style: italic;
- font-size: small;
+#sourcelink {
+ margin-top: 1.8em;
+ flex-grow: 0;
}
div.related {
@@ -156,9 +161,9 @@ div.related {
font-size: 90%;
line-height: normal;
height: auto;
- left: 0;
- right: 0;
+ position: sticky;
top: 0;
+ z-index: 999;
}
div.related ul {
@@ -255,6 +260,36 @@ div.footer {
color: rgb(0,102,204);
}
+.control-appearance-figures {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ align-items: end;
+ column-gap: 1.0em;
+ justify-content: space-around;
+}
+
+.appearance-figure {
+ margin: 0;
+ padding: 0;
+ max-width: 500px;
+ flex-shrink: 1;
+}
+
+.appearance-figure img {
+ max-height: 320px;
+}
+
+figcaption {
+ text-align: center;
+ text-align-last: center;
+}
+
+figcaption a.headerlink {
+ margin: 0;
+ padding: 0;
+}
+
.floatleft {
position: relative;
float:left;
@@ -551,9 +586,10 @@ cite, code, tt {
letter-spacing: 0.01em;
}
-code.descname, code.descclassname {
+code.descname, code.descclassname, span.sig-name, span.sig-prename {
font-weight: bold;
}
+
a.headerlink {
color: #c60f0f;
font-size: 0.8em;
@@ -755,6 +791,14 @@ table.contentstable p.mybiglink {
line-height: 150%;
}
+hr {
+ color: #ccc;
+ background-color: #ccc;
+ height: 1px;
+ border: none;
+ margin-bottom: 0.7rem;
+}
+
hr.overloadsep {
color: #0000FF;
background-color: #0000FF;
@@ -762,4 +806,4 @@ hr.overloadsep {
border: none;
width: 50%;
float: left;
-}
\ No newline at end of file
+}
diff --git a/docs/sphinx/_templates/searchbox.html b/docs/sphinx/_templates/searchbox.html
index e9c86019..30459536 100644
--- a/docs/sphinx/_templates/searchbox.html
+++ b/docs/sphinx/_templates/searchbox.html
@@ -8,14 +8,14 @@
:license: BSD, see LICENSE for details.
#}
{%- if pagename != "search" and builder != "singlehtml" %}
-
-
{{ _('Search') }}
+
+ {{ _('Search') }}
+
-
-
+
+
+
{%- endif %}
diff --git a/docs/sphinx/_templates/sourcelink.html b/docs/sphinx/_templates/sourcelink.html
index 2692973e..25ce54a9 100644
--- a/docs/sphinx/_templates/sourcelink.html
+++ b/docs/sphinx/_templates/sourcelink.html
@@ -8,8 +8,10 @@
:license: BSD, see LICENSE for details.
#}
{%- if show_source and has_source and sourcename %}
-
+
+
+
{%- endif %}
diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py
index 8184a084..2158acc8 100644
--- a/docs/sphinx/conf.py
+++ b/docs/sphinx/conf.py
@@ -14,6 +14,7 @@
import sys, os
from datetime import datetime
+from buildtools.config import Config
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@@ -25,7 +26,8 @@ sys.path.append(os.path.abspath('..'))
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.todo',
+extensions = ["sphinxcontrib.jquery",
+ 'sphinx.ext.todo',
'sphinx.ext.autodoc',
'sphinx.ext.autosummary',
'sphinx.ext.coverage',
@@ -36,7 +38,7 @@ extensions = ['sphinx.ext.todo',
templates_path = ['_templates']
# The suffix(es) of source filenames.
-source_suffix = ['.txt']
+source_suffix = {'.txt': 'restructuredtext'}
todo_include_todos = True
todo_all_todos = True
@@ -49,6 +51,7 @@ availability_all_availabilities = True
# The master toctree document.
master_doc = 'index'
+toc_object_entries = False
# General information about the project.
project = u'wxPython Phoenix'
@@ -58,7 +61,6 @@ copyright = u'2012-{}, The wxPython Team'.format(datetime.now().year)
# |version| and |release|, also used in various other places throughout the
# built documents.
-from buildtools.config import Config
cfg = Config(noWxConfig=True)
# The short X.Y version.
@@ -66,7 +68,6 @@ version = '%s.%s' % (cfg.VER_MAJOR, cfg.VER_MINOR)
# The full version, including alpha/beta/rc tags.
release = cfg.VERSION
-
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
@@ -101,11 +102,10 @@ show_authors = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
-# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
-
# If true, keep warnings as "system message" paragraphs in the built documents.
-#keep_warnings = False
+keep_warnings = False
+show_warning_types = True
+supress_warnings = []
# -- Options for HTML output ---------------------------------------------------
@@ -165,10 +165,12 @@ html_sidebars = {
# Additional templates that should be rendered to pages, maps page names to
# template names.
-html_additional_pages = {'gallery': 'gallery.html', 'main': 'main.html'}
+html_additional_pages = {'gallery': 'gallery.html',
+ 'main': 'main.html'}
-# If false, no module index is generated.
-html_use_modindex = True
+html_domain_indices = {'py-modindex'}
+# A list of ignored prefixes for module index sorting.
+modindex_common_prefix = ['wx.', 'wx.lib.', 'wx.py.']
# If false, no index is generated.
html_use_index = True
@@ -280,3 +282,4 @@ pdf_verbosity = 2
# Enable experimental feature to split table cells. Use it
# if you get "DelayedTable too big" errors
pdf_splittables = True
+
diff --git a/docs/sphinx/phoenix_theme/theme.conf b/docs/sphinx/phoenix_theme/theme.conf
deleted file mode 100644
index 6ae2b098..00000000
--- a/docs/sphinx/phoenix_theme/theme.conf
+++ /dev/null
@@ -1,38 +0,0 @@
-[theme]
-
-inherit = basic
-stylesheet = phoenix.css
-pygments_style = sphinx
-
-[options]
-
-disqus_comments = false
-google_analytics = false
-
-rightsidebar = false
-collapsiblesidebar = true
-headerheight = 30px
-
-externalrefs = false
-
-footerbgcolor = #11303d
-footertextcolor = #ffffff
-sidebarbgcolor = #1c4e63
-sidebarbtncolor = #3c6e83
-sidebartextcolor = #ffffff
-sidebarlinkcolor = #98dbcc
-relbarbgcolor = #133f52
-relbartextcolor = #ffffff
-relbarlinkcolor = #ffffff
-bgcolor = #ffffff
-textcolor = #000000
-headbgcolor = #f2f2f2
-headtextcolor = #20435c
-headlinkcolor = #c60f0f
-linkcolor = #355f7c
-visitedlinkcolor = #355f7c
-codebgcolor = #eeffcc
-codetextcolor = #333333
-
-bodyfont = sans-serif
-headfont = 'Trebuchet MS', Verdana, Arial, Helvetica, sans-serif
\ No newline at end of file
diff --git a/docs/sphinx/phoenix_theme/theme.toml b/docs/sphinx/phoenix_theme/theme.toml
new file mode 100644
index 00000000..71ee4a4a
--- /dev/null
+++ b/docs/sphinx/phoenix_theme/theme.toml
@@ -0,0 +1,35 @@
+[theme]
+inherit = "basic"
+stylesheets = [
+ "phoenix.css",
+]
+pygments_style = { default = "sphinx" }
+
+[options]
+disqus_comments = "false"
+google_analytics = "false"
+rightsidebar = "false"
+collapsiblesidebar = "true"
+headerheight = "30px"
+externalrefs = "false"
+footerbgcolor = "#11303d"
+footertextcolor = "#ffffff"
+sidebarbgcolor = "#1c4e63"
+sidebarbtncolor = "#3c6e83"
+sidebartextcolor = "#ffffff"
+sidebarlinkcolor = "#98dbcc"
+relbarbgcolor = "#133f52"
+relbartextcolor = "#ffffff"
+relbarlinkcolor = "#ffffff"
+bgcolor = "#ffffff"
+textcolor = "#000000"
+headbgcolor = "#f2f2f2"
+headtextcolor = "#20435c"
+headlinkcolor = "#c60f0f"
+linkcolor = "#355f7c"
+visitedlinkcolor = "#355f7c"
+codebgcolor = "#eeffcc"
+codetextcolor = "#333333"
+bodyfont = "sans-serif"
+headfont = "'Trebuchet MS', Verdana, Arial, Helvetica, sans-serif"
+
diff --git a/docs/sphinx/rest_substitutions/overviews/high_dpi_overview.rst b/docs/sphinx/rest_substitutions/overviews/high_dpi_overview.rst
index 210a0bb7..4dc0f451 100644
--- a/docs/sphinx/rest_substitutions/overviews/high_dpi_overview.rst
+++ b/docs/sphinx/rest_substitutions/overviews/high_dpi_overview.rst
@@ -1,7 +1,7 @@
.. include:: headings.inc
-.. _html overview:
+.. _high dpi overview:
======================================
|phoenix_title| **High DPI Overview**
diff --git a/docs/sphinx/rest_substitutions/overviews/index.rst b/docs/sphinx/rest_substitutions/overviews/index.rst
index 190e616f..5439305b 100644
--- a/docs/sphinx/rest_substitutions/overviews/index.rst
+++ b/docs/sphinx/rest_substitutions/overviews/index.rst
@@ -23,7 +23,7 @@ and launch the wxPython demo for you.
.. note:: If you wish to help in the documentation effort, the main
docstrings guidelines are outlined in the
- `Docstring Guidelines `_
+ `Docstring Guidelines `_
document.
diff --git a/etgtools/sphinx_generator.py b/etgtools/sphinx_generator.py
index 27019da6..b41768b3 100644
--- a/etgtools/sphinx_generator.py
+++ b/etgtools/sphinx_generator.py
@@ -1163,7 +1163,9 @@ class Image(Node):
rel_path = os.path.normpath(static_path[rel_path_index:])
docstrings = '\n\n'
- docstrings += '.. figure:: %s\n' % rel_path
+ # Sphinx (on windows) can't parse windows style paths when reading
+ # .rst files. Therefore paths are written unix style.
+ docstrings += '.. figure:: %s\n' % rel_path.replace('\\', '/')
docstrings += ' :align: center\n\n\n'
docstrings += '|\n\n'
@@ -1592,7 +1594,7 @@ class XRef(Node):
text = ''
elif not isNumeric(text):
- text = '``%s``'%text
+ text = '``%s``' % text.strip()
elif 'funcmacro' in values:
if '(' in stripped:
@@ -2893,7 +2895,7 @@ class XMLDocString(object):
pickleItem(desc, self.current_module, self.class_name, 'class')
if self.overloads:
- docstrings += '\n\n%s|overload| Overloaded Implementations:\n\n'%spacer
+ docstrings += '\n\n%s|overload| **Overloaded Implementations:**\n\n'%spacer
docstrings += '%s:html:`
`\n\n'%spacer
for index, over in enumerate(self.overloads):
diff --git a/requirements/devel.txt b/requirements/devel.txt
index 8164e828..d341a4b3 100644
--- a/requirements/devel.txt
+++ b/requirements/devel.txt
@@ -12,17 +12,8 @@ pytest-xdist
pytest-forked
pytest-timeout
-sphinx==2.2.0 ; python_version >= '3.0'
-sphinx==1.8.5 ; python_version < '3.0'
-alabaster<0.7.14
-sphinxcontrib-applehelp<1.0.8
-sphinxcontrib-devhelp<1.0.6
-sphinxcontrib-htmlhelp<2.0.5
-sphinxcontrib-jsmath<1.0.2
-sphinxcontrib-qthelp<1.0.7
-sphinxcontrib-serializinghtml<1.1.10
-Jinja2==2.10
-markupsafe==1.1.1
-doc2dash==2.3.0
+sphinx
+sphinxcontrib-jquery
+doc2dash
beautifulsoup4
typing-extensions; python_version < '3.11'
diff --git a/sphinxtools/constants.py b/sphinxtools/constants.py
index 7ee45bfe..67bb8fc8 100644
--- a/sphinxtools/constants.py
+++ b/sphinxtools/constants.py
@@ -169,15 +169,17 @@ RE_KEEP_SPACES = re.compile(r'(\s+)')
# A list of things used in the post-processing of the HTML files generated by Sphinx
# This list is used only to insert a HTML horizontal line (
) after each method/function
# description
-HTML_REPLACE = ['module', 'function', 'method', 'class', 'classmethod', 'staticmethod', 'attribute']
+HTML_REPLACE = ['module', 'function', 'py function', 'class', 'py class',
+ 'method', 'py method', 'classmethod', 'staticmethod',
+ 'attribute', 'py attribute']
# Today's date representation for the Sphinx HTML docs
TODAY = datetime.date.today().strftime('%d %B %Y')
# Inheritance diagram external hyperlinks
-PYTHON_DOCS = 'http://docs.python.org/library/'
-NUMPY_DOCS = 'http://docs.scipy.org/doc/numpy/reference/generated/'
+PYTHON_DOCS = 'https://docs.python.org/3/library/'
+NUMPY_DOCS = 'https://numpy.org/doc/stable/reference/generated/'
EXTERN_INHERITANCE = {'UserDict.' : PYTHON_DOCS,
'ctypes.' : PYTHON_DOCS,
diff --git a/sphinxtools/inheritance.py b/sphinxtools/inheritance.py
index 18704ed3..f2fb37b1 100644
--- a/sphinxtools/inheritance.py
+++ b/sphinxtools/inheritance.py
@@ -10,22 +10,19 @@
#---------------------------------------------------------------------------
# Standard library imports
-
import os
import sys
import errno
from subprocess import Popen, PIPE
# Phoenix-specific imports
-
-from .utilities import wx2Sphinx, formatExternalLink
+from .utilities import formatExternalLink
from .constants import INHERITANCEROOT
ENOENT = getattr(errno, 'ENOENT', 0)
EPIPE = getattr(errno, 'EPIPE', 0)
-
class InheritanceDiagram:
"""
Given a list of classes, determines the set of classes that they inherit
@@ -108,8 +105,7 @@ class InheritanceDiagram:
'shape': 'box',
'fontsize': 10,
'height': 0.3,
- 'fontname': '"Vera Sans, DejaVu Sans, Liberation Sans, '
- 'Arial, Helvetica, sans"',
+ 'fontname': '"Liberation Sans, Arial, sans-serif"',
'style': '"setlinewidth(0.5)"',
}
default_edge_attrs = {
@@ -123,7 +119,8 @@ class InheritanceDiagram:
def _format_graph_attrs(self, attrs):
return ''.join(['%s=%s;\n' % x for x in list(attrs.items())])
- def generate_dot(self, class_summary, name="dummy", graph_attrs={}, node_attrs={}, edge_attrs={}):
+ def generate_dot(self, class_summary, name="dummy",
+ graph_attrs={}, node_attrs={}, edge_attrs={}):
"""Generate a graphviz dot graph from the classes that were passed in
to __init__.
@@ -133,18 +130,22 @@ class InheritanceDiagram:
key/value pairs to pass on as graphviz properties.
"""
- inheritance_graph_attrs = dict(fontsize=9, ratio='auto', size='""', rankdir="TB")
- inheritance_node_attrs = {"align": "center", 'shape': 'box',
- 'fontsize': 10, 'height': 0.3,
- 'fontname': '"Vera Sans, DejaVu Sans, Liberation Sans, '
- 'Arial, Helvetica, sans"', 'style': '"setlinewidth(0.5)"',
- 'labelloc': 'c', 'fontcolor': 'grey45'}
+ inheritance_graph_attrs = {"fontsize": 9, "ratio": 'auto',
+ "size": '""', "rankdir": "TB"}
- inheritance_edge_attrs = {'arrowsize': 0.5,
- 'style': '"setlinewidth(0.5)"',
- 'color': '"#23238E"',
+ inheritance_node_attrs = {"align": "center", 'shape': 'box',
+ 'fontsize': 12, 'height': 0.3,
+ 'margin': '"0.15, 0.05"',
+ 'fontname': '"Liberation Sans, Arial, sans-serif"',
+ 'style': '"setlinewidth(0.8), rounded"',
+ 'labelloc': 'c', 'fontcolor': 'grey45',
+ "color": "dodgerblue4"}
+
+ inheritance_edge_attrs = {'arrowsize': 0.6,
+ 'style': '"setlinewidth(0.8)"',
+ 'color': 'dodgerblue4',
'dir': 'back',
- 'arrowtail': 'open',
+ 'arrowtail': 'normal',
}
g_attrs = self.default_graph_attrs.copy()
@@ -163,9 +164,9 @@ class InheritanceDiagram:
this_node_attrs = n_attrs.copy()
if fullname in self.specials:
- this_node_attrs['fontcolor'] = 'black'
- this_node_attrs['color'] = 'blue'
- this_node_attrs['style'] = 'bold'
+ this_node_attrs['fontcolor'] = 'dodgerblue4'
+ this_node_attrs['color'] = 'dodgerblue2'
+ this_node_attrs['style'] = '"bold, rounded"'
if class_summary is None:
# Phoenix base classes, assume there is always a link
@@ -185,7 +186,7 @@ class InheritanceDiagram:
for base_name in bases:
this_edge_attrs = e_attrs.copy()
if fullname in self.specials:
- this_edge_attrs['color'] = 'red'
+ this_edge_attrs['color'] = 'darkorange1'
res.append(' "%s" -> "%s" [%s];\n' %
(base_name, fullname,
@@ -198,7 +199,7 @@ class InheritanceDiagram:
def makeInheritanceDiagram(self, class_summary=None):
"""
- Actually generates the inheritance diagram as a PNG file plus the corresponding
+ Actually generates the inheritance diagram as a SVG file plus the corresponding
MAP file for mouse navigation over the inheritance boxes.
These two files are saved into the ``INHERITANCEROOT`` folder (see `sphinxtools/constants.py`
@@ -209,7 +210,7 @@ class InheritanceDiagram:
:rtype: `tuple`
- :returns: a tuple containing the PNG file name and a string representing the content
+ :returns: a tuple containing the SVG file name and a string representing the content
of the MAP file (with newlines stripped away).
.. note:: The MAP file is deleted as soon as its content has been read.
@@ -224,13 +225,13 @@ class InheritanceDiagram:
else:
filename = self.specials[0]
- outfn = os.path.join(static_root, filename + '_inheritance.png')
+ outfn = os.path.join(static_root, filename + '_inheritance.svg')
mapfile = outfn + '.map'
if os.path.isfile(outfn) and os.path.isfile(mapfile):
- with open(mapfile, 'rt') as fid:
- map = fid.read()
- return os.path.split(outfn)[1], map.replace('\n', ' ')
+ with open(mapfile, 'rt', encoding="utf-8") as fid:
+ mp = fid.read()
+ return os.path.split(outfn)[1], mp.replace('\n', ' ')
code = self.generate_dot(class_summary)
@@ -245,7 +246,7 @@ class InheritanceDiagram:
if os.path.isfile(mapfile):
os.remove(mapfile)
- dot_args.extend(['-Tpng', '-o' + outfn])
+ dot_args.extend(['-Tsvg', '-o' + outfn])
dot_args.extend(['-Tcmapx', '-o' + mapfile])
popen_args = {
@@ -283,7 +284,7 @@ class InheritanceDiagram:
if p.returncode != 0:
print(('\nERROR: Graphviz `dot` command exited with error:\n[stderr]\n%s\n[stdout]\n%s\n\n' % (stderr, stdout)))
- with open(mapfile, 'rt') as fid:
- map = fid.read()
+ with open(mapfile, 'rt', encoding="utf-8") as fid:
+ mp = fid.read()
- return os.path.split(outfn)[1], map.replace('\n', ' ')
+ return os.path.split(outfn)[1], mp.replace('\n', ' ')
diff --git a/sphinxtools/modulehunter.py b/sphinxtools/modulehunter.py
index 7626614a..4a6acfaa 100644
--- a/sphinxtools/modulehunter.py
+++ b/sphinxtools/modulehunter.py
@@ -13,7 +13,7 @@ import pkgutil
from buildtools.config import phoenixDir
-from inspect import getargspec, ismodule, getdoc, getmodule, getcomments, isfunction
+from inspect import getfullargspec, ismodule, getdoc, getmodule, getcomments, isfunction
from inspect import ismethoddescriptor, getsource, ismemberdescriptor, isgetsetdescriptor
from inspect import isbuiltin, isclass, getfile, ismethod
@@ -117,23 +117,21 @@ def analyze_params(obj, signature):
return signature, param_tuple
try:
- arginfo = getargspec(obj)
- # TODO: Switch to getfullargspec
+ arginfo = getfullargspec(obj)
except (TypeError, ValueError):
arginfo = None
pevals = {}
if arginfo:
- args = arginfo[0]
- argsvar = arginfo[1]
+ args = arginfo.args
- if arginfo[3]:
+ if arginfo.defaults:
- dl = len(arginfo[3])
+ dl = len(arginfo.defaults)
al = len(args)
defargs = args[al-dl:al]
- info = arginfo[3]
+ info = arginfo.defaults
for d, i in zip(defargs, info):
pevals[d] = i
diff --git a/sphinxtools/postprocess.py b/sphinxtools/postprocess.py
index 0c66051d..e61ac73f 100644
--- a/sphinxtools/postprocess.py
+++ b/sphinxtools/postprocess.py
@@ -339,7 +339,7 @@ def removeUnreferenced(input, class_summary, enum_base, unreferenced_classes, te
def addSpacesToLinks(text):
- regex = re.findall('\w:ref:`(.*?)`', text)
+ regex = re.findall(r'\w:ref:`(.*?)`', text)
for reg in regex:
text = text.replace(':ref:`%s`'%reg, ' :ref:`%s`'%reg)
@@ -657,22 +657,24 @@ def postProcess(folder, options):
for indx, enum in enumerate(enum_base):
html_file = os.path.split(enum_files[indx])[1]
base = enum.split('.')[-1]
- new = '(%s)'%(html_file, base, base)
- enum_dict['(%s)'%enum] = new
+ new = '(%s)' % (html_file, base, base)
+ enum_dict['(%s)' % enum] = new
for filename in fileNames:
if "genindex" in filename or "modindex" in filename:
continue
- methods_done = properties_done = False
+ methods_done = attr_done = fn_done = False
with textfile_open(filename, "rt") as fid:
orig_text = text = fid.read()
- text = text.replace('Overloaded Implementations:', 'Overloaded Implementations:')
for item in HTML_REPLACE:
- if item != 'class':
- text = text.replace(''%item, '\n
\n'%item)
+ if item in ('class', 'py class'):
+ continue
+
+ text = text.replace('' % item,
+ '
' % item)
newtext = ''
splitted_text = text.splitlines()
@@ -684,19 +686,32 @@ def postProcess(folder, options):
line = line.replace('– ', '– ')
line = line.replace('
', '')
- if line.strip() == '
' or line.strip() == '
':
- next_line = splitted_text[index+1]
- stripline = next_line.strip()
+ if not fn_done and \
+ line.strip() in ('
',
+ '
'):
- # replace the
with a new headline for the first method or first property
- if (stripline == '' or stripline == '' \
- or stripline == '') and not methods_done:
- line = '\n
Methods
\n'
- methods_done = True
+ line = line[8:]
+ fn_done = True
- elif stripline == '' and not properties_done:
- line = '\n
Properties
\n'
- properties_done = True
+ if not methods_done and \
+ line.strip() in ('
',
+ '
',
+ '
',
+ '
'):
+
+ line = '\n
\nMethods
\n' + line[8:]
+ methods_done = True
+
+ if not attr_done and \
+ line.strip() in ('
',
+ '
'):
+
+ line = '\n
\nProperties
\n' + line[8:]
+ attr_done = True
newtext += line + '\n'
diff --git a/sphinxtools/stc_doc_postprocess.py b/sphinxtools/stc_doc_postprocess.py
new file mode 100644
index 00000000..7abfd342
--- /dev/null
+++ b/sphinxtools/stc_doc_postprocess.py
@@ -0,0 +1,256 @@
+# -*- coding: utf-8 -*-
+#---------------------------------------------------------------------------
+# Name: sphinxtools/stc_doc_postprocess.py
+# Author: Matthias (neofelis2X)
+#
+# Created: 27-Jan-2025
+# Copyright: (c) 2010-2025
+# License: wxWindows License
+#---------------------------------------------------------------------------
+"""
+This script postprocesses the ReST documentation file of the
+wx.stc.StyledTextCtrl class. This class has more than 760 methods,
+so the 'Method Summary' is sorted into categories.
+"""
+
+import xml.etree.ElementTree as ET
+from pathlib import Path
+
+from buildtools.config import msg
+from sphinxtools.constants import XMLSRC, SPHINXROOT
+
+STC_CLASS_XML = Path(XMLSRC, "classwx_styled_text_ctrl.xml")
+STC_RST = Path(SPHINXROOT, "wx.stc.StyledTextCtrl.txt")
+TBL_SEP = "======================================================" + \
+ "========================== ===========================" + \
+ "=====================================================\n"
+
+def _parse_method_categories(xml_file):
+ """
+ Parses values from an xml file containing categories, method
+ names and occasional additional category descriptions.
+ """
+
+ tree = ET.parse(xml_file)
+ root = tree.getroot()
+
+ method_mapping = {}
+ current_category = "empty"
+ current_pretty = "Empty"
+ description = ''
+ new_header = False
+
+ for elem in root.iter():
+ if elem.tag == 'listofallmembers':
+ break
+
+ if elem.tag == "header" and isinstance(elem.text, str):
+ if "Raw variants" in elem.text:
+ current_category = "Raw Variants"
+ current_pretty = "Raw Variants"
+ else:
+ current_category = elem.text
+ current_pretty = _clean_category_title(current_category)
+
+ description = ''
+ new_header = True
+
+ elif elem.tag == "description" and new_header:
+ para = elem.findall("para")
+ description = _parse_description(para)
+
+ new_header = False
+
+ elif elem.tag == "name":
+ method_mapping[elem.text] = (current_pretty, description)
+
+ return method_mapping
+
+def _parse_description(para):
+ """
+ Goes through some extra steps to parse method descriptions from references.
+ """
+ description = ''
+
+ if len(para) > 1:
+ txt = para[1].itertext()
+ sect = para[1].findall("simplesect")
+
+ if len(sect):
+ description = "".join(txt).split('(', maxsplit=1)[0].strip()
+ description = f".. seealso:: :meth:`~wx.stc.StyledTextCtrl.{description}`"
+ else:
+ description = "".join(txt).strip()
+
+ return description
+
+def _parse_stcdoc_segments(file):
+ """
+ Read the reStructuredText file and split relevant parts into textblocks.
+ """
+
+ m_count = 0 # Count the collected methods
+ pretext = '' # All text before the 'Method Summary'
+ parse_pretext = True
+ links = [] #
+ index_links_done = False
+ methods = {}
+ current_method = ''
+ parse_methods = False
+ posttext = '' # All text after the 'Method Summary'
+ parse_posttext = False
+
+ with open(file, 'r', encoding="utf-8") as f:
+ for line in f:
+
+ if parse_posttext:
+ posttext += line
+
+ elif not index_links_done and line.startswith("- `"):
+ # Rewrite index links
+ new_link = line.split('<')[0].strip("-_ `")
+ new_link = _clean_category_title(new_link)
+ pretext += f"- `{new_link}`_\n"
+ links.append(new_link)
+
+ if "Constructors" in line:
+ awm = "Additional wxPython Methods"
+ pretext += f"- `{awm}`_\n"
+ links.append(awm)
+
+ elif "Text area methods" in line:
+ index_links_done = True
+
+ elif line.startswith(":meth:`~wx.stc.StyledTextCtrl."):
+ # Collect all methods from 'Method Summary'
+ m_count += 1
+ parse_pretext = False
+ parse_methods = True
+
+ current_method = line[30:].split('`')[0].strip()
+
+ if not current_method:
+ print("stc_doc_postprocess:: WARNING: Invalid method name")
+ else:
+ methods[current_method] = line
+
+ elif parse_methods and line.strip() == '|':
+ parse_methods = False
+ parse_posttext = True
+ posttext = '\n' + line
+
+ elif parse_pretext:
+ if not TBL_SEP.strip() in line:
+ pretext += line
+
+ # print(f"Debug: Read {m_count} methods from file.")
+ return (pretext, methods, posttext, links)
+
+def _methods_to_categories(methods, mapping):
+ """
+ Find the right category for each method. Around 20 methods are
+ unique in wxPython and will be put into their own group.
+ """
+ grouped_methods = {}
+
+ for name, text in methods.items():
+
+ if name in ("__init__", "Create"):
+ category = "Constructors and Related Methods"
+ description = ''
+ text = text.replace("Ctor.", '')
+
+ elif name in mapping:
+ category = mapping[name][0]
+ description = mapping[name][1]
+
+ else:
+ category = "Additional wxPython Methods"
+ description = "In addition to the standard Scintilla " + \
+ "functions, wxPython includes the following " + \
+ "methods to better integrate better with other features."
+
+ if category in grouped_methods:
+ grouped_methods[category][0].append(text)
+ grouped_methods[category][1] = description
+ else:
+ grouped_methods[category] = [[text, ], '']
+
+ if description:
+ grouped_methods[category][1] = description
+
+ return grouped_methods
+
+def _clean_category_title(raw_title):
+ """
+ Applies proper title case to category titles.
+ """
+ category_title = raw_title.strip().title().replace("And", "and")
+ category_title = category_title.replace("Wxstyledtextctrl", "wxStyledTextCtrl")
+ category_title = category_title.replace("Wxpython", "wxPython")
+
+ return category_title
+
+def _assemble_method_category(category, cat_methods, cc):
+ """
+ Assembles all method ReST directives that go into one category.
+ """
+ group = ''
+
+ dashline = '-' * len(category)
+ group = f"\n{category}\n{dashline}\n\n"
+
+ if cat_methods[1]:
+ group += '\n' + cat_methods[1] + '\n\n'
+
+ group += TBL_SEP
+
+ for method in cat_methods[0]:
+ cc += 1
+ group += method
+
+ group += TBL_SEP + '\n'
+
+ return group, cc
+
+def _output_reordered_doc(pretext, posttext, grouped_methods):
+ """
+ Writes the formatted ReST to a file. Overwrites the original file.
+ """
+ m_count = 0 # count the written methods
+ doc = pretext
+
+ for category, methods in grouped_methods.items():
+ cat, m_count = _assemble_method_category(category, methods, m_count)
+ doc += cat
+
+ doc += posttext
+
+ STC_RST.write_text(doc, encoding="utf-8")
+
+ # print(f"Debug: Wrote {m_count} methods to new file.")
+
+def stc_categorise_methods():
+ """
+ Loads the ReST file, categorises the method summary and saves a new file.
+ Thr original file is overwritten.
+ """
+ if not STC_CLASS_XML.is_file():
+ return msg(f"Warning: StyledTextCtrl post-processing failed: {STC_CLASS_XML.name} not available.")
+
+ mapping = _parse_method_categories(STC_CLASS_XML)
+
+ if not STC_RST.is_file():
+ return msg(f"Warning: StyledTextCtrl post-processing failed: {STC_RST.name} not available.")
+
+ pre, methods, post, links = _parse_stcdoc_segments(STC_RST)
+ grouped_methods = _methods_to_categories(methods, mapping)
+ sorted_methods = {key: grouped_methods[key] for key in links}
+ _output_reordered_doc(pre, post, sorted_methods)
+
+ return msg("StyledTextCtrl post-processing completed successfully.")
+
+
+if __name__ == "__main__":
+ stc_categorise_methods()
+
diff --git a/sphinxtools/templates.py b/sphinxtools/templates.py
index 03fbeee8..97832dd6 100644
--- a/sphinxtools/templates.py
+++ b/sphinxtools/templates.py
@@ -60,26 +60,27 @@ TEMPLATE_APPEARANCE = '''
|
-.. figure:: _static/images/widgets/fullsize/wxmsw/%s
- :alt: wxMSW
- :figclass: floatleft
+.. container:: control-appearance-figures
- **wxMSW**
+ .. figure:: _static/images/widgets/fullsize/wxmsw/%s
+ :alt: wxMSW
+ :figclass: appearance-figure
+
+ **wxMSW**
-.. figure:: _static/images/widgets/fullsize/wxmac/%s
- :alt: wxMAC
- :figclass: floatright
+ .. figure:: _static/images/widgets/fullsize/wxmac/%s
+ :alt: wxMAC
+ :figclass: appearance-figure
- **wxMAC**
+ **wxMAC**
-.. figure:: _static/images/widgets/fullsize/wxgtk/%s
- :alt: wxGTK
- :figclass: floatcenter
-
- **wxGTK**
+ .. figure:: _static/images/widgets/fullsize/wxgtk/%s
+ :alt: wxGTK
+ :figclass: appearance-figure
+ **wxGTK**
|
diff --git a/wx/lib/agw/scrolledthumbnail.py b/wx/lib/agw/scrolledthumbnail.py
index 22155816..ce8f187e 100644
--- a/wx/lib/agw/scrolledthumbnail.py
+++ b/wx/lib/agw/scrolledthumbnail.py
@@ -71,7 +71,7 @@ wxWidgets implementation of the :class:`ThumbnailCtrl` control. Andrea Gavana
notes that :class:`ThumbnailCtrl` wouldn't have been so fast and complete
without the suggestions and hints from Peter Damoc.
-Usage:
+Usage
=====
Usage example::
diff --git a/wx/lib/masked/maskededit.py b/wx/lib/masked/maskededit.py
index 87335d42..b99d0543 100644
--- a/wx/lib/masked/maskededit.py
+++ b/wx/lib/masked/maskededit.py
@@ -117,7 +117,7 @@ mask
X Allow string.letters, string.punctuation, string.digits
& Allow string.punctuation only (doesn't include all unicode symbols)
\* Allow any visible character
- | explicit field boundary (takes no space in the control; allows mix
+ \| Explicit field boundary (takes no space in the control; allows mix
of adjacent mask characters to be treated as separate fields,
eg: '&|###' means "field 0 = '&', field 1 = '###'", but there's
no fixed characters in between.
@@ -189,59 +189,67 @@ defaultEncoding
formatcodes
These other properties can be passed to the class when instantiating it:
Formatcodes are specified as a string of single character formatting
- codes that modify behavior of the control::
+ codes that modify behavior of the control:
- _ Allow spaces
- ! Force upper
- ^ Force lower
- R Right-align field(s)
- r Right-insert in field(s) (implies R)
- < Stay in field until explicit navigation out of it
+ ======= ==========================================================
+ _ Allow spaces
+ ! Force upper
+ ^ Force lower
+ R Right-align field(s)
+ r Right-insert in field(s) (implies R)
+ < Stay in field until explicit navigation out of it
- > Allow insert/delete within partially filled fields (as
- opposed to the default "overwrite" mode for fixed-width
- masked edit controls.) This allows single-field controls
- or each field within a multi-field control to optionally
- behave more like standard text controls.
- (See EMAIL or phone number autoformat examples.)
+ > Allow insert/delete within partially filled fields (as
+ opposed to the default "overwrite" mode for fixed-width
+ masked edit controls.) This allows single-field controls
+ or each field within a multi-field control to optionally
+ behave more like standard text controls.
+ (See EMAIL or phone number autoformat examples.)
- *Note: This also governs whether backspace/delete operations
- shift contents of field to right of cursor, or just blank the
- erased section.
+ .. note::
- Also, when combined with 'r', this indicates that the field
- or control allows right insert anywhere within the current
- non-empty value in the field. (Otherwise right-insert behavior
- is only performed to when the entire right-insertable field is
- selected or the cursor is at the right edge of the field.*
+ This also governs whether backspace/delete operations
+ shift contents of field to right of cursor, or just blank
+ the erased section.
+
+ Also, when combined with 'r', this indicates that the field
+ or control allows right insert anywhere within the current
+ non-empty value in the field. (Otherwise right-insert behavior
+ is only performed to when the entire right-insertable field is
+ selected or the cursor is at the right edge of the field.
- , Allow grouping character in integer fields of numeric controls
- and auto-group/regroup digits (if the result fits) when leaving
- such a field. (If specified, .SetValue() will attempt to
- auto-group as well.)
- ',' is also the default grouping character. To change the
- grouping character and/or decimal character, use the groupChar
- and decimalChar parameters, respectively.
- Note: typing the "decimal point" character in such fields will
- clip the value to that left of the cursor for integer
- fields of controls with "integer" or "floating point" masks.
- If the ',' format code is specified, this will also cause the
- resulting digits to be regrouped properly, using the current
- grouping character.
- - Prepend and reserve leading space for sign to mask and allow
- signed values (negative #s shown in red by default.) Can be
- used with argument useParensForNegatives (see below.)
- 0 integer fields get leading zeros
- D Date[/time] field
- T Time field
- F Auto-Fit: the control calculates its size from
- the length of the template mask
- V validate entered chars against validRegex before allowing them
- to be entered vs. being allowed by basic mask and then having
- the resulting value just colored as invalid.
- (See USSTATE autoformat demo for how this can be used.)
- S select entire field when navigating to new field
+ , Allow grouping character in integer fields of numeric controls
+ and auto-group/regroup digits (if the result fits) when leaving
+ such a field. (If specified, .SetValue() will attempt to
+ auto-group as well.)
+ ',' is also the default grouping character. To change the
+ grouping character and/or decimal character, use the groupChar
+ and decimalChar parameters, respectively.
+
+ .. note::
+
+ Typing the "decimal point" character in such fields will
+ clip the value to that left of the cursor for integer
+ fields of controls with "integer" or "floating point" masks.
+
+ If the ',' format code is specified, this will also cause the
+ resulting digits to be regrouped properly, using the current
+ grouping character.
+ \- Prepend and reserve leading space for sign to mask and allow
+ signed values (negative #s shown in red by default.) Can be
+ used with argument useParensForNegatives (see below.)
+ 0 Integer fields get leading zeros
+ D Date[/time] field
+ T Time field
+ F Auto-Fit: the control calculates its size from
+ the length of the template mask
+ V Validate entered chars against validRegex before allowing them
+ to be entered vs. being allowed by basic mask and then having
+ the resulting value just colored as invalid.
+ (See USSTATE autoformat demo for how this can be used.)
+ S Select entire field when navigating to new field
+ ======= ==========================================================
fillChar
diff --git a/wx/lib/masked/numctrl.py b/wx/lib/masked/numctrl.py
index d0177d19..284f7a5a 100644
--- a/wx/lib/masked/numctrl.py
+++ b/wx/lib/masked/numctrl.py
@@ -89,7 +89,7 @@ masked.NumCtrl:
emptyBackgroundColour = "White",
validBackgroundColour = "White",
invalidBackgroundColour = "Yellow",
- autoSize = True
+ autoSize = True,
)
diff --git a/wx/lib/plot/examples/demo.py b/wx/lib/plot/examples/demo.py
index ce1767b1..4bb63437 100644
--- a/wx/lib/plot/examples/demo.py
+++ b/wx/lib/plot/examples/demo.py
@@ -7,10 +7,14 @@
demo.py
=======
-This is a demo showing some of the capabilities of the :mod:`wx.lib.plot`
-package. It is intended to be run as a standalone script via::
+.. highlight:: shell
- user@host:.../site-packages/wx/lib/plot$ python examples/demo.py
+This is a demo showing some of the capabilities of the :mod:`wx.lib.plot`
+package.
+
+It is intended to be run as a standalone script via::
+
+ user@host:.../site-packages/wx/lib/plot$ python examples/demo.py
"""
__docformat__ = "restructuredtext en"
diff --git a/wx/lib/plot/examples/simple_example.py b/wx/lib/plot/examples/simple_example.py
index e8f539c8..b120bfe0 100644
--- a/wx/lib/plot/examples/simple_example.py
+++ b/wx/lib/plot/examples/simple_example.py
@@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-
"""
+.. highlight:: shell
+
A simple example showing how to use lib.plot from wxPython.
It is intended to be run as a standalone script via::
- user@host:.../site-packages/wx/lib/plot$ python examples/simple_example.py
+ user@host:.../site-packages/wx/lib/plot$ python examples/simple_example.py
"""
__docformat__ = "restructuredtext en"
diff --git a/wx/lib/plot/polyobjects.py b/wx/lib/plot/polyobjects.py
index be9ab831..81f5d27b 100644
--- a/wx/lib/plot/polyobjects.py
+++ b/wx/lib/plot/polyobjects.py
@@ -120,7 +120,7 @@ class PolyPoints(object):
:type: tuple of bool, length 2
:raises ValueError: when setting an invalid value
- .. notes::
+ .. note::
This is a simplified example of how SymLog works::
@@ -163,7 +163,7 @@ class PolyPoints(object):
:type: tuple of float, length 2
:raises ValueError: when setting an invalid value
- .. notes::
+ .. note::
This is a simplified example of how SymLog works::
@@ -221,7 +221,7 @@ class PolyPoints(object):
:setter: Sets the value of points.
:type: list of `(x, y)` pairs
- .. Note::
+ .. note::
Only set unscaled points - do not perform the log, abs, or symlog
adjustments yourself.
@@ -1010,17 +1010,10 @@ class PolyBoxPlot(PolyPoints):
outliers are outside of 1.5 * IQR
- Parameters
- ----------
- data : array-like
- The data to plot
-
- Returns
- -------
- bpdata : collections.namedtuple
- Descriptive statistics for data:
+ :param array-like data: The data to plot
+ :return bpdata: Descriptive statistics for data:
(min_data, low_whisker, q25, median, q75, high_whisker, max_data)
-
+ :rtype: collections.namedtuple
"""
data = self._clean_data(data)
@@ -1066,20 +1059,20 @@ class PolyBoxPlot(PolyPoints):
"""
Draws a box plot on the DC.
- Notes
- -----
- The following draw order is required:
+ .. note::
- 1. First the whisker line
- 2. Then the IQR box
- 3. Lasly the median line.
+ The following draw order is required:
- This is because
+ 1. First the whisker line
+ 2. Then the IQR box
+ 3. Lasly the median line.
- + The whiskers are drawn as single line rather than two lines
- + The median line must be visible over the box if the box has a fill.
+ This is because
- Other than that, the draw order can be changed.
+ + The whiskers are drawn as single line rather than two lines
+ + The median line must be visible over the box if the box has a fill.
+
+ Other than that, the draw order can be changed.
"""
self._draw_whisker(dc, printerScale)
self._draw_iqr_box(dc, printerScale)