././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1602381088.2437418 PyMsgBox-1.0.9/0000777000000000000000000000000000000000000010124 5ustar00././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1409690804.0 PyMsgBox-1.0.9/MANIFEST.in0000666000000000000000000000030500000000000011660 0ustar00include *.md recursive-include docs *.bat recursive-include docs *.py recursive-include docs *.rst recursive-include docs Makefile recursive-include pymsgbox *.py recursive-include tests *.py././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1602381088.239751 PyMsgBox-1.0.9/PKG-INFO0000666000000000000000000000444100000000000011224 0ustar00Metadata-Version: 2.1 Name: PyMsgBox Version: 1.0.9 Summary: A simple, cross-platform, pure Python module for JavaScript-like message boxes. Home-page: https://github.com/asweigart/pymsgbox Author: Al Sweigart Author-email: al@inventwithpython.com License: GPLv3+ Description: PyMsgBox ======== A simple, cross-platform, pure Python module for JavaScript-like message boxes. To import, run: >>> from pymsgbox import *` There are four functions in PyMsgBox, which follow JavaScript's message box naming conventions: >>> alert(text='', title='', button='OK')` Displays a simple message box with text and a single OK button. Returns the text of the button clicked on. >>> confirm(text='', title='', buttons=['OK', 'Cancel'])` Displays a message box with OK and Cancel buttons. Number and text of buttons can be customized. Returns the text of the button clicked on. >>> prompt(text='', title='' , defaultValue='')` Displays a message box with text input, and OK & Cancel buttons. Returns the text entered, or None if Cancel was clicked. >>> password(text='', title='', defaultValue='', mask='*')` Displays a message box with text input, and OK & Cancel buttons. Typed characters appear as *. Returns the text entered, or None if Cancel was clicked. On Linux Python 2, you need to first install Tkinter by running: sudo apt-get install python-tk Modified BSD License Derived from Stephen Raymond Ferg's EasyGui http://easygui.sourceforge.net/ Platform: UNKNOWN Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+) Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Description-Content-Type: text/markdown ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1410571305.0 PyMsgBox-1.0.9/README.md0000666000000000000000000000233700000000000011410 0ustar00PyMsgBox ======== A simple, cross-platform, pure Python module for JavaScript-like message boxes. To import, run: >>> from pymsgbox import *` There are four functions in PyMsgBox, which follow JavaScript's message box naming conventions: >>> alert(text='', title='', button='OK')` Displays a simple message box with text and a single OK button. Returns the text of the button clicked on. >>> confirm(text='', title='', buttons=['OK', 'Cancel'])` Displays a message box with OK and Cancel buttons. Number and text of buttons can be customized. Returns the text of the button clicked on. >>> prompt(text='', title='' , defaultValue='')` Displays a message box with text input, and OK & Cancel buttons. Returns the text entered, or None if Cancel was clicked. >>> password(text='', title='', defaultValue='', mask='*')` Displays a message box with text input, and OK & Cancel buttons. Typed characters appear as *. Returns the text entered, or None if Cancel was clicked. On Linux Python 2, you need to first install Tkinter by running: sudo apt-get install python-tk Modified BSD License Derived from Stephen Raymond Ferg's EasyGui http://easygui.sourceforge.net/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1560824660.0 PyMsgBox-1.0.9/code_of_conduct.md0000666000000000000000000000631600000000000013571 0ustar00# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1602381088.162957 PyMsgBox-1.0.9/docs/0000777000000000000000000000000000000000000011054 5ustar00././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1408594104.0 PyMsgBox-1.0.9/docs/Makefile0000666000000000000000000001516200000000000012521 0ustar00# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PyMsgBox.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PyMsgBox.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/PyMsgBox" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PyMsgBox" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1489902042.0 PyMsgBox-1.0.9/docs/basics.rst0000666000000000000000000000473500000000000013063 0ustar00.. default-role:: code =============== PyMsgBox Basics =============== Installation ============ PyMsgBox can be installed from PyPI with pip: `pip install PyMsgBox` OS X and Linux may require sudo to install the module: `sudo pip install PyMsgBox` PyMsgBox uses Python's built-in TKinter module for its GUI. It is cross-platform and runs on Python 2 and Python 3. PyMsgBox's code is derived from Stephen Raymond Ferg's EasyGui. http://easygui.sourceforge.net/ Usage ===== There are four functions in PyMsgBox, which follow JavaScript's message box naming conventions: - `alert(text='', title='', button='OK')` Displays a simple message box with text and a single OK button. Returns the text of the button clicked on. >>> pymsgbox.alert('This is an alert.', 'Alert!') 'OK' .. image:: alert_example.png - `confirm(text='', title='', buttons=['OK', 'Cancel'])` Displays a message box with OK and Cancel buttons. Number and text of buttons can be customized. Returns the text of the button clicked on. >>> pymsgbox.confirm('Nuke the site from orbit?', 'Confirm nuke', ["Yes, I'm sure.", 'Cancel']) "Yes, I'm sure." .. image:: confirm_example.png - `prompt(text='', title='', defaultValue='')` Displays a message box with text input, and OK & Cancel buttons. Returns the text entered, or None if Cancel was clicked. >>> pymsgbox.prompt('What does the fox say?', default='This reference dates this example.') 'This reference dates this example.' .. image:: prompt_example.png - `password(text='', title='', defaultValue='', mask='*')` Displays a message box with text input, and OK & Cancel buttons. Typed characters appear as \*. Returns the text entered, or None if Cancel was clicked. >>> pymsgbox.password('Enter your password.') '12345' .. image:: password_example.png Timeout ======= All four functions have a `timeout` parameter which takes a number of milliseconds. At the end of the timeout, the message box will close and have a return value of `'Timeout'`. >>> pymsgbox.confirm('Nuke the site from orbit?', 'Confirm nuke', ["Yes, I'm sure.", 'Cancel'], timeout=2000) # closes after 2000 milliseconds (2 seconds) "Timeout" Localization ============ You can change the default `'OK'`, `'Cancel`', and `'Timeout'` strings by changing `pymsgbox.OK_TEXT`, `pymsgbox.CANCEL_TEXT`, and `pymsgbox.TIMEOUT_TEXT` variables respectively.././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1408594103.0 PyMsgBox-1.0.9/docs/conf.py0000666000000000000000000002034700000000000012361 0ustar00#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # PyMsgBox documentation build configuration file, created by # sphinx-quickstart on Wed Aug 20 21:08:23 2014. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os # 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 # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'PyMsgBox' copyright = '2014, Al Sweigart' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '0.9.0' # The full version, including alpha/beta/rc tags. release = '0.9.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # 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 # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'PyMsgBoxdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'PyMsgBox.tex', 'PyMsgBox Documentation', 'Al Sweigart', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'pymsgbox', 'PyMsgBox Documentation', ['Al Sweigart'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'PyMsgBox', 'PyMsgBox Documentation', 'Al Sweigart', 'PyMsgBox', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1409865445.0 PyMsgBox-1.0.9/docs/index.rst0000666000000000000000000000076400000000000012724 0ustar00.. PyMsgBox documentation master file, created by sphinx-quickstart on Wed Aug 20 21:08:23 2014. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to PyMsgBox's documentation! ==================================== Contents: .. toctree:: :maxdepth: 2 quickstart.rst basics.rst native.rst Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1408594104.0 PyMsgBox-1.0.9/docs/make.bat0000777000000000000000000001506100000000000012467 0ustar00@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\PyMsgBox.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\PyMsgBox.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1409906310.0 PyMsgBox-1.0.9/docs/native.rst0000666000000000000000000000456500000000000013106 0ustar00.. default-role:: code ==================== Native Message Boxes ==================== In addition to displaying message boxes using Python's built-in TkInter GUI toolkit, PyMsgBox also has limited support for displaying message boxes by calling the operating system's native functions. These exist in the `native` module. To use them, call: >>> import pymsgbox >>> pymsgbox.native.alert('This is an alert.', 'The title.') Or, to avoid changing your function calls to use pymsgbox.native, run: >>> import pymsgbox.native as pymsgbox Support ======= These are the platforms and functions that have native message box support. Functions that do are not supported will default back to the normal TkInter-based message box. Support as of v1.0.1: +-------------+---------+---------+---------+--------------+ | | Windows | OS X | Linux | JVM / Jython | +-------------+---------+---------+---------+--------------+ | `alert()` | Yes | No | No | No | +-------------+---------+---------+---------+--------------+ | `confirm()` | Yes | No | No | No | +-------------+---------+---------+---------+--------------+ | `prompt()` | No | No | No | No | +-------------+---------+---------+---------+--------------+ |`password()` | No | No | No | No | +-------------+---------+---------+---------+--------------+ Special Notes ============= Windows - alert() ----------------- The message box will only show a button with text "OK", no matter what is passed for the `button` argument. The `button` argument will be the text that is returned by the function, just like the TkInter `alert()`. >>> pymsgbox.native.alert('This is an alert.', 'Alert!') 'OK' .. image:: win32native_alert_example.png Windows - confirm() ------------------- There will only be buttons "OK" and "Cancel", no matter what is passed for the `buttons` argument. If "OK" is clicked, the first item in the `buttons` list is returned (by default, this is `'OK'`). If "Cancel" is clicked, the second item in the `buttons` list is returned (by default, this is `'Cancel'`), just like the TkInter `confirm()`. >>> pymsgbox.native.confirm('Nuke the site from orbit?', 'Confirm nuke', ["Yes, I'm sure.", 'Cancel']) "Yes, I'm sure." .. image:: win32native_confirm_example.png ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1410571338.0 PyMsgBox-1.0.9/docs/quickstart.rst0000666000000000000000000000205300000000000014000 0ustar00 .. default-role:: code ========== Quickstart ========== On Linux Python 2, you need to first install Tkinter by running: `sudo apt-get install python-tk` All of the arguments to PyMsgBox functions are optional. >>> import pymsgbox >>> pymsgbox.alert('This is an alert.') >>> pymsgbox.confirm('Click OK to continue, click Cancel to cancel.') >>> pymsgbox.prompt('Enter your name.') >>> pymsgbox.password('Enter your password. (It will appear hidden in this text field.)') Here are the default arguments for each function. >>> pymsgbox.alert(text='', title='', button='OK') >>> pymsgbox.confirm(text='', title='', buttons=['OK', 'Cancel']) >>> pymsgbox.prompt(text='', title='' , defaultValue='') >>> pymsgbox.password(text='', title='', defaultValue='', mask='*') To use native operating system message boxes, run the following: >>> import pymsgbox.native as pymsgbox (Only a few of the message boxes have native support. Unsupported message boxes will default to the normal message boxes.)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1560824660.0 PyMsgBox-1.0.9/pyproject.toml0000666000000000000000000000000000000000000013026 0ustar00././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1602381088.2437418 PyMsgBox-1.0.9/setup.cfg0000666000000000000000000000005200000000000011742 0ustar00[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1602381033.0 PyMsgBox-1.0.9/setup.py0000666000000000000000000000266700000000000011651 0ustar00import re from setuptools import setup, find_packages # Load version from module (without loading the whole module) with open('src/pymsgbox/__init__.py', 'r') as fo: version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', fo.read(), re.MULTILINE).group(1) # Read in the README.md for the long description. with open('README.md') as fo: long_description = fo.read() setup( name='PyMsgBox', version=version, url='https://github.com/asweigart/pymsgbox', author='Al Sweigart', author_email='al@inventwithpython.com', description=('''A simple, cross-platform, pure Python module for JavaScript-like message boxes.'''), long_description=long_description, long_description_content_type="text/markdown", license='GPLv3+', packages=find_packages(where='src'), package_dir={'': 'src'}, test_suite='tests', install_requires=[], keywords='', classifiers=[ 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', ], ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1602381087.8481672 PyMsgBox-1.0.9/src/0000777000000000000000000000000000000000000010713 5ustar00././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1602381088.2218053 PyMsgBox-1.0.9/src/PyMsgBox.egg-info/0000777000000000000000000000000000000000000014115 5ustar00././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1602381087.0 PyMsgBox-1.0.9/src/PyMsgBox.egg-info/PKG-INFO0000666000000000000000000000444100000000000015215 0ustar00Metadata-Version: 2.1 Name: PyMsgBox Version: 1.0.9 Summary: A simple, cross-platform, pure Python module for JavaScript-like message boxes. Home-page: https://github.com/asweigart/pymsgbox Author: Al Sweigart Author-email: al@inventwithpython.com License: GPLv3+ Description: PyMsgBox ======== A simple, cross-platform, pure Python module for JavaScript-like message boxes. To import, run: >>> from pymsgbox import *` There are four functions in PyMsgBox, which follow JavaScript's message box naming conventions: >>> alert(text='', title='', button='OK')` Displays a simple message box with text and a single OK button. Returns the text of the button clicked on. >>> confirm(text='', title='', buttons=['OK', 'Cancel'])` Displays a message box with OK and Cancel buttons. Number and text of buttons can be customized. Returns the text of the button clicked on. >>> prompt(text='', title='' , defaultValue='')` Displays a message box with text input, and OK & Cancel buttons. Returns the text entered, or None if Cancel was clicked. >>> password(text='', title='', defaultValue='', mask='*')` Displays a message box with text input, and OK & Cancel buttons. Typed characters appear as *. Returns the text entered, or None if Cancel was clicked. On Linux Python 2, you need to first install Tkinter by running: sudo apt-get install python-tk Modified BSD License Derived from Stephen Raymond Ferg's EasyGui http://easygui.sourceforge.net/ Platform: UNKNOWN Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+) Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Description-Content-Type: text/markdown ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1602381087.0 PyMsgBox-1.0.9/src/PyMsgBox.egg-info/SOURCES.txt0000666000000000000000000000061000000000000015776 0ustar00MANIFEST.in README.md code_of_conduct.md pyproject.toml setup.py docs/Makefile docs/basics.rst docs/conf.py docs/index.rst docs/make.bat docs/native.rst docs/quickstart.rst src/PyMsgBox.egg-info/PKG-INFO src/PyMsgBox.egg-info/SOURCES.txt src/PyMsgBox.egg-info/dependency_links.txt src/PyMsgBox.egg-info/top_level.txt src/pymsgbox/__init__.py src/pymsgbox/_native_win.py tests/test_pymsgbox.py././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1602381087.0 PyMsgBox-1.0.9/src/PyMsgBox.egg-info/dependency_links.txt0000666000000000000000000000000100000000000020163 0ustar00 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1602381087.0 PyMsgBox-1.0.9/src/PyMsgBox.egg-info/top_level.txt0000666000000000000000000000001100000000000016637 0ustar00pymsgbox ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1602381088.2277844 PyMsgBox-1.0.9/src/pymsgbox/0000777000000000000000000000000000000000000012563 5ustar00././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1602381042.0 PyMsgBox-1.0.9/src/pymsgbox/__init__.py0000666000000000000000000003436000000000000014702 0ustar00# PyMsgBox - A simple, cross-platform, pure Python module for JavaScript-like message boxes. # By Al Sweigart al@inventwithpython.com __version__ = "1.0.9" # Modified BSD License # Derived from Stephen Raymond Ferg's EasyGui http://easygui.sourceforge.net/ """ The four functions in PyMsgBox: - alert(text='', title='', button='OK') Displays a simple message box with text and a single OK button. Returns the text of the button clicked on. - confirm(text='', title='', buttons=['OK', 'Cancel']) Displays a message box with OK and Cancel buttons. Number and text of buttons can be customized. Returns the text of the button clicked on. - prompt(text='', title='' , default='') Displays a message box with text input, and OK & Cancel buttons. Returns the text entered, or None if Cancel was clicked. - password(text='', title='', default='', mask='*') Displays a message box with text input, and OK & Cancel buttons. Typed characters appear as *. Returns the text entered, or None if Cancel was clicked. """ """ TODO Roadmap: - Be able to specify a custom icon in the message box. - Be able to place the message box at an arbitrary position (including on multi screen layouts) - Add mouse clicks to unit testing. - progress() function to display a progress bar - Maybe other types of dialog: open, save, file/folder picker, etc. """ import sys RUNNING_PYTHON_2 = sys.version_info[0] == 2 # Because PyAutoGUI requires PyMsgBox but might be installed on systems # without tkinter, we don't want a lack of tkinter to cause installation # to fail. So exceptions won't be raised until the PyMsgBox functions # are actually called. TKINTER_IMPORT_SUCCEEDED = True try: if RUNNING_PYTHON_2: import Tkinter as tk else: import tkinter as tk rootWindowPosition = "+300+200" if tk.TkVersion < 8.0: raise RuntimeError( "You are running Tk version: " + str(tk.TkVersion) + "You must be using Tk version 8.0 or greater to use PyMsgBox." ) except ImportError: TKINTER_IMPORT_SUCCEEDED = False PROPORTIONAL_FONT_FAMILY = ("MS", "Sans", "Serif") MONOSPACE_FONT_FAMILY = "Courier" PROPORTIONAL_FONT_SIZE = 10 MONOSPACE_FONT_SIZE = ( 9 ) # a little smaller, because it it more legible at a smaller size TEXT_ENTRY_FONT_SIZE = 12 # a little larger makes it easier to see STANDARD_SELECTION_EVENTS = ["Return", "Button-1", "space"] # constants for strings: (TODO: for internationalization, change these) OK_TEXT = "OK" CANCEL_TEXT = "Cancel" YES_TEXT = "Yes" NO_TEXT = "No" RETRY_TEXT = "Retry" ABORT_TEXT = "Abort" IGNORE_TEXT = "Ignore" TRY_AGAIN_TEXT = "Try Again" CONTINUE_TEXT = "Continue" TIMEOUT_RETURN_VALUE = "Timeout" # Initialize some global variables that will be reset later __choiceboxMultipleSelect = None __widgetTexts = None __replyButtonText = None __choiceboxResults = None __firstWidget = None __enterboxText = None __enterboxDefaultText = "" __multenterboxText = "" choiceboxChoices = None choiceboxWidget = None entryWidget = None boxRoot = None buttonsFrame = None def _alertTkinter(text="", title="", button=OK_TEXT, root=None, timeout=None): """Displays a simple message box with text and a single OK button. Returns the text of the button clicked on.""" assert TKINTER_IMPORT_SUCCEEDED, "Tkinter is required for pymsgbox" text = str(text) retVal = _buttonbox( msg=text, title=title, choices=[str(button)], root=root, timeout=timeout ) if retVal is None: return button else: return retVal alert = _alertTkinter def _confirmTkinter( text="", title="", buttons=(OK_TEXT, CANCEL_TEXT), root=None, timeout=None ): """Displays a message box with OK and Cancel buttons. Number and text of buttons can be customized. Returns the text of the button clicked on.""" assert TKINTER_IMPORT_SUCCEEDED, "Tkinter is required for pymsgbox" text = str(text) return _buttonbox( msg=text, title=title, choices=[str(b) for b in buttons], root=root, timeout=timeout, ) confirm = _confirmTkinter def _promptTkinter(text="", title="", default="", root=None, timeout=None): """Displays a message box with text input, and OK & Cancel buttons. Returns the text entered, or None if Cancel was clicked.""" assert TKINTER_IMPORT_SUCCEEDED, "Tkinter is required for pymsgbox" text = str(text) return __fillablebox( text, title, default=default, mask=None, root=root, timeout=timeout ) prompt = _promptTkinter def _passwordTkinter(text="", title="", default="", mask="*", root=None, timeout=None): """Displays a message box with text input, and OK & Cancel buttons. Typed characters appear as *. Returns the text entered, or None if Cancel was clicked.""" assert TKINTER_IMPORT_SUCCEEDED, "Tkinter is required for pymsgbox" text = str(text) return __fillablebox(text, title, default, mask=mask, root=root, timeout=timeout) password = _passwordTkinter # Load the native versions of the alert/confirm/prompt/password functions, if available: if sys.platform == "win32": from . import _native_win NO_ICON = 0 STOP = 0x10 QUESTION = 0x20 WARNING = 0x30 INFO = 0x40 alert = _native_win.alert confirm = _native_win.confirm def timeoutBoxRoot(): global boxRoot, __replyButtonText, __enterboxText boxRoot.destroy() __replyButtonText = TIMEOUT_RETURN_VALUE __enterboxText = TIMEOUT_RETURN_VALUE def _buttonbox(msg, title, choices, root=None, timeout=None): """ Display a msg, a title, and a set of buttons. The buttons are defined by the members of the choices list. Return the text of the button that the user selected. @arg msg: the msg to be displayed. @arg title: the window title @arg choices: a list or tuple of the choices to be displayed """ global boxRoot, __replyButtonText, __widgetTexts, buttonsFrame # Initialize __replyButtonText to the first choice. # This is what will be used if the window is closed by the close button. __replyButtonText = choices[0] if root: root.withdraw() boxRoot = tk.Toplevel(master=root) boxRoot.withdraw() else: boxRoot = tk.Tk() boxRoot.withdraw() boxRoot.title(title) boxRoot.iconname("Dialog") boxRoot.geometry(rootWindowPosition) boxRoot.minsize(400, 100) # ------------- define the messageFrame --------------------------------- messageFrame = tk.Frame(master=boxRoot) messageFrame.pack(side=tk.TOP, fill=tk.BOTH) # ------------- define the buttonsFrame --------------------------------- buttonsFrame = tk.Frame(master=boxRoot) buttonsFrame.pack(side=tk.TOP, fill=tk.BOTH) # -------------------- place the widgets in the frames ----------------------- messageWidget = tk.Message(messageFrame, text=msg, width=400) messageWidget.configure(font=(PROPORTIONAL_FONT_FAMILY, PROPORTIONAL_FONT_SIZE)) messageWidget.pack(side=tk.TOP, expand=tk.YES, fill=tk.X, padx="3m", pady="3m") __put_buttons_in_buttonframe(choices) # -------------- the action begins ----------- # put the focus on the first button __firstWidget.focus_force() boxRoot.deiconify() if timeout is not None: boxRoot.after(timeout, timeoutBoxRoot) boxRoot.mainloop() try: boxRoot.destroy() except tk.TclError: if __replyButtonText != TIMEOUT_RETURN_VALUE: __replyButtonText = None if root: root.deiconify() return __replyButtonText def __put_buttons_in_buttonframe(choices): """Put the buttons in the buttons frame""" global __widgetTexts, __firstWidget, buttonsFrame __firstWidget = None __widgetTexts = {} i = 0 for buttonText in choices: tempButton = tk.Button(buttonsFrame, takefocus=1, text=buttonText) _bindArrows(tempButton) tempButton.pack( expand=tk.YES, side=tk.LEFT, padx="1m", pady="1m", ipadx="2m", ipady="1m" ) # remember the text associated with this widget __widgetTexts[tempButton] = buttonText # remember the first widget, so we can put the focus there if i == 0: __firstWidget = tempButton i = 1 # for the commandButton, bind activation events to the activation event handler commandButton = tempButton handler = __buttonEvent for selectionEvent in STANDARD_SELECTION_EVENTS: commandButton.bind("<%s>" % selectionEvent, handler) if CANCEL_TEXT in choices: commandButton.bind("", __cancelButtonEvent) def _bindArrows(widget, skipArrowKeys=False): widget.bind("", _tabRight) widget.bind("", _tabLeft) if not skipArrowKeys: widget.bind("", _tabRight) widget.bind("", _tabLeft) def _tabRight(event): boxRoot.event_generate("") def _tabLeft(event): boxRoot.event_generate("") def __buttonEvent(event): """ Handle an event that is generated by a person clicking a button. """ global boxRoot, __widgetTexts, __replyButtonText __replyButtonText = __widgetTexts[event.widget] boxRoot.quit() # quit the main loop def __cancelButtonEvent(event): """Handle pressing Esc by clicking the Cancel button.""" global boxRoot, __widgetTexts, __replyButtonText __replyButtonText = CANCEL_TEXT boxRoot.quit() def __fillablebox(msg, title="", default="", mask=None, root=None, timeout=None): """ Show a box in which a user can enter some text. You may optionally specify some default text, which will appear in the enterbox when it is displayed. Returns the text that the user entered, or None if he cancels the operation. """ global boxRoot, __enterboxText, __enterboxDefaultText global cancelButton, entryWidget, okButton if title == None: title == "" if default == None: default = "" __enterboxDefaultText = default __enterboxText = __enterboxDefaultText if root: root.withdraw() boxRoot = tk.Toplevel(master=root) boxRoot.withdraw() else: boxRoot = tk.Tk() boxRoot.withdraw() boxRoot.title(title) boxRoot.iconname("Dialog") boxRoot.geometry(rootWindowPosition) boxRoot.bind("", __enterboxCancel) # ------------- define the messageFrame --------------------------------- messageFrame = tk.Frame(master=boxRoot) messageFrame.pack(side=tk.TOP, fill=tk.BOTH) # ------------- define the buttonsFrame --------------------------------- buttonsFrame = tk.Frame(master=boxRoot) buttonsFrame.pack(side=tk.TOP, fill=tk.BOTH) # ------------- define the entryFrame --------------------------------- entryFrame = tk.Frame(master=boxRoot) entryFrame.pack(side=tk.TOP, fill=tk.BOTH) # ------------- define the buttonsFrame --------------------------------- buttonsFrame = tk.Frame(master=boxRoot) buttonsFrame.pack(side=tk.TOP, fill=tk.BOTH) # -------------------- the msg widget ---------------------------- messageWidget = tk.Message(messageFrame, width="4.5i", text=msg) messageWidget.configure(font=(PROPORTIONAL_FONT_FAMILY, PROPORTIONAL_FONT_SIZE)) messageWidget.pack(side=tk.RIGHT, expand=1, fill=tk.BOTH, padx="3m", pady="3m") # --------- entryWidget ---------------------------------------------- entryWidget = tk.Entry(entryFrame, width=40) _bindArrows(entryWidget, skipArrowKeys=True) entryWidget.configure(font=(PROPORTIONAL_FONT_FAMILY, TEXT_ENTRY_FONT_SIZE)) if mask: entryWidget.configure(show=mask) entryWidget.pack(side=tk.LEFT, padx="3m") entryWidget.bind("", __enterboxGetText) entryWidget.bind("", __enterboxCancel) # put text into the entryWidget and have it pre-highlighted if __enterboxDefaultText != "": entryWidget.insert(0, __enterboxDefaultText) entryWidget.select_range(0, tk.END) # ------------------ ok button ------------------------------- okButton = tk.Button(buttonsFrame, takefocus=1, text=OK_TEXT) _bindArrows(okButton) okButton.pack(expand=1, side=tk.LEFT, padx="3m", pady="3m", ipadx="2m", ipady="1m") # for the commandButton, bind activation events to the activation event handler commandButton = okButton handler = __enterboxGetText for selectionEvent in STANDARD_SELECTION_EVENTS: commandButton.bind("<%s>" % selectionEvent, handler) # ------------------ cancel button ------------------------------- cancelButton = tk.Button(buttonsFrame, takefocus=1, text=CANCEL_TEXT) _bindArrows(cancelButton) cancelButton.pack( expand=1, side=tk.RIGHT, padx="3m", pady="3m", ipadx="2m", ipady="1m" ) # for the commandButton, bind activation events to the activation event handler commandButton = cancelButton handler = __enterboxCancel for selectionEvent in STANDARD_SELECTION_EVENTS: commandButton.bind("<%s>" % selectionEvent, handler) # ------------------- time for action! ----------------- entryWidget.focus_force() # put the focus on the entryWidget boxRoot.deiconify() if timeout is not None: boxRoot.after(timeout, timeoutBoxRoot) boxRoot.mainloop() # run it! # -------- after the run has completed ---------------------------------- if root: root.deiconify() try: boxRoot.destroy() # button_click didn't destroy boxRoot, so we do it now except tk.TclError: if __enterboxText != TIMEOUT_RETURN_VALUE: return None return __enterboxText def __enterboxGetText(event): global __enterboxText __enterboxText = entryWidget.get() boxRoot.quit() def __enterboxRestore(event): global entryWidget entryWidget.delete(0, len(entryWidget.get())) entryWidget.insert(0, __enterboxDefaultText) def __enterboxCancel(event): global __enterboxText __enterboxText = None boxRoot.quit() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1589241693.0 PyMsgBox-1.0.9/src/pymsgbox/_native_win.py0000666000000000000000000001172700000000000015447 0ustar00# This module contains all the Windows-specific code to create native # message boxes using the winapi. # If you'd like to learn more about calling the winapi functions from # Python, you can check out my other module "nicewin" to see nicely-documented # examples. It is at https://github.com/asweigart/nicewin # The documentation for the MessageBox winapi is at: # https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-messagebox import sys, ctypes import pymsgbox MB_OK = 0x0 MB_OKCANCEL = 0x1 MB_ABORTRETRYIGNORE = 0x2 MB_YESNOCANCEL = 0x3 MB_YESNO = 0x4 MB_RETRYCANCEL = 0x5 MB_CANCELTRYCONTINUE = 0x6 NO_ICON = 0 STOP = MB_ICONHAND = MB_ICONSTOP = MB_ICONERRPR = 0x10 QUESTION = MB_ICONQUESTION = 0x20 WARNING = MB_ICONEXCLAIMATION = 0x30 INFO = MB_ICONASTERISK = MB_ICONINFOMRAITON = 0x40 MB_DEFAULTBUTTON1 = 0x0 MB_DEFAULTBUTTON2 = 0x100 MB_DEFAULTBUTTON3 = 0x200 MB_DEFAULTBUTTON4 = 0x300 MB_SETFOREGROUND = 0x10000 MB_TOPMOST = 0x40000 IDABORT = 0x3 IDCANCEL = 0x2 IDCONTINUE = 0x11 IDIGNORE = 0x5 IDNO = 0x7 IDOK = 0x1 IDRETRY = 0x4 IDTRYAGAIN = 0x10 IDYES = 0x6 runningOnPython2 = sys.version_info[0] == 2 if runningOnPython2: messageBoxFunc = ctypes.windll.user32.MessageBoxA else: # Python 3 functions. messageBoxFunc = ctypes.windll.user32.MessageBoxW def alert( text="", title="", button=pymsgbox.OK_TEXT, root=None, timeout=None, icon=NO_ICON, _tkinter=False, ): """Displays a simple message box with text and a single OK button. Returns the text of the button clicked on.""" text = str(text) if (_tkinter) or (timeout is not None) or (button != pymsgbox.OK_TEXT): # Timeouts are not supported by Windows message boxes. # Call the original tkinter alert function, not this native one: return pymsgbox._alertTkinter(text, title, button, root, timeout) messageBoxFunc(0, text, title, MB_OK | MB_SETFOREGROUND | MB_TOPMOST | icon) return button def confirm( text="", title="", buttons=(pymsgbox.OK_TEXT, pymsgbox.CANCEL_TEXT), root=None, timeout=None, icon=QUESTION, _tkinter=False, ): """Displays a message box with OK and Cancel buttons. Number and text of buttons can be customized. Returns the text of the button clicked on.""" text = str(text) buttonFlag = None if len(buttons) == 1: if buttons[0] == pymsgbox.OK_TEXT: buttonFlag = MB_OK elif len(buttons) == 2: if buttons[0] == pymsgbox.OK_TEXT and buttons[1] == pymsgbox.CANCEL_TEXT: buttonFlag = MB_OKCANCEL elif buttons[0] == pymsgbox.YES_TEXT and buttons[1] == pymsgbox.NO_TEXT: buttonFlag = MB_YESNO elif buttons[0] == pymsgbox.RETRY_TEXT and buttons[1] == pymsgbox.CANCEL_TEXT: buttonFlag = MB_RETRYCANCEL elif len(buttons) == 3: if ( buttons[0] == pymsgbox.ABORT_TEXT and buttons[1] == pymsgbox.RETRY_TEXT and buttons[2] == pymsgbox.IGNORE_TEXT ): buttonFlag = MB_ABORTRETRYIGNORE elif ( buttons[0] == pymsgbox.CANCEL_TEXT and buttons[1] == pymsgbox.TRY_AGAIN_TEXT and buttons[2] == pymsgbox.CONTINUE_TEXT ): buttonFlag = MB_CANCELTRYCONTINUE elif ( buttons[0] == pymsgbox.YES_TEXT and buttons[1] == pymsgbox.NO_TEXT and buttons[2] == pymsgbox.CANCEL_TEXT ): buttonFlag = MB_YESNOCANCEL if (_tkinter) or (timeout is not None) or (buttonFlag is None): # Call the original tkinter confirm() function, not this native one: return pymsgbox._confirmTkinter(text, title, buttons, root, timeout) retVal = messageBoxFunc( 0, text, title, buttonFlag | MB_SETFOREGROUND | MB_TOPMOST | icon ) if retVal == IDOK or len(buttons) == 1: return pymsgbox.OK_TEXT elif retVal == IDCANCEL: return pymsgbox.CANCEL_TEXT elif retVal == IDYES: return pymsgbox.YES_TEXT elif retVal == IDNO: return pymsgbox.NO_TEXT elif retVal == IDTRYAGAIN: return pymsgbox.TRY_TEXT elif retVal == IDRETRY: return pymsgbox.RETRY_TEXT elif retVal == IDIGNORE: return pymsgbox.IGNORE_TEXT elif retVal == IDCONTINUE: return pymsgbox.CONTINUE_TEXT elif retVal == IDABORT: return pymsgbox.ABORT_TEXT else: assert False, "Unexpected return value from MessageBox: %s" % (retVal) ''' def prompt(text='', title='' , default=''): """Displays a message box with text input, and OK & Cancel buttons. Returns the text entered, or None if Cancel was clicked.""" pass def password(text='', title='', default='', mask='*'): """Displays a message box with text input, and OK & Cancel buttons. Typed characters appear as *. Returns the text entered, or None if Cancel was clicked.""" pass ''' ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1602381088.2367697 PyMsgBox-1.0.9/tests/0000777000000000000000000000000000000000000011266 5ustar00././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1602380967.0 PyMsgBox-1.0.9/tests/test_pymsgbox.py0000666000000000000000000003227500000000000014560 0ustar00import unittest import sys import os import time import threading import inspect import pymsgbox # Note: Yes, PyAutoGUI does have PyMsgBox itself as a dependency, but we won't be using that part of PyAutoGUI for this testing. import pyautogui # PyAutoGUI simulates key presses on the message boxes. pyautogui.PAUSE = 0.1 GUI_WAIT = 0.4 # if tests start failing, maybe try bumping this up a bit (though that'll slow the tests down) """ NOTE: You will often see this code in this test: print('Line', inspect.currentframe().f_lineno); This is because due to the GUI nature of these tests, if something messes up and PyAutoGUI is unable to click on the message box, this program will get held up. By printing out the line number, you will at least be able to see which line displayed the message box that is held up. This is a bit unorthodox, and I'm welcome to other suggestions about how to deal with this possible scenario. """ class KeyPresses(threading.Thread): def __init__(self, keyPresses): super(KeyPresses, self).__init__() self.keyPresses = keyPresses def run(self): time.sleep(GUI_WAIT) pyautogui.typewrite(self.keyPresses, interval=0.05) class AlertTests(unittest.TestCase): def test_alert(self): for func in (pymsgbox._alertTkinter, pymsgbox.alert): if func is pymsgbox._alertTkinter: print('Testing tkinter alert()') elif func is pymsgbox.alert: print('Testing native alert()') # no text t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func(), 'OK') # text t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello'), 'OK') # text and title t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title'), 'OK') # text, title, and custom button t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title', 'Button'), 'Button') # using keyword arguments t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func(text='Hello', title='Title', button='Button'), 'Button') class ConfirmTests(unittest.TestCase): def test_confirm(self): for func in (pymsgbox._confirmTkinter, pymsgbox.confirm): if func is pymsgbox._confirmTkinter: print('Testing tkinter confirm()') elif func is pymsgbox.confirm: print('Testing native confirm()') # press enter on OK t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func(), 'OK') # press right, enter on Cancel t = KeyPresses(['right', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func(), 'Cancel') # press right, left, right, enter on Cancel t = KeyPresses(['right', 'left', 'right', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func(), 'Cancel') # press tab, enter on Cancel t = KeyPresses(['tab', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func(), 'Cancel') # press tab, tab, enter on OK t = KeyPresses(['tab', 'tab', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func(), 'OK') # with text t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello'), 'OK') # with text, title t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title'), 'OK') # with text, title, and one custom button t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title', ['A']), 'A') # with text, title, and one custom blank button t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title', ['']), '') # with text, title, and two custom buttons t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title', ['A', 'B']), 'A') t = KeyPresses(['right', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title', ['A', 'B']), 'B') t = KeyPresses(['right', 'left', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title', ['A', 'B']), 'A') t = KeyPresses(['tab', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title', ['A', 'B']), 'B') t = KeyPresses(['tab', 'tab', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title', ['A', 'B']), 'A') # with text, title, and three custom buttons t = KeyPresses(['tab', 'tab', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title', ['A', 'B', 'C']), 'C') # with text, title, and four custom buttons t = KeyPresses(['tab', 'tab', 'tab', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title', ['A', 'B', 'C', 'D']), 'D') # with text, title, and five custom buttons t = KeyPresses(['tab', 'tab', 'tab', 'tab', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func('Hello', 'Title', ['A', 'B', 'C', 'D', 'E']), 'E') # with text, title, and three custom buttons specified with keyword arguments t = KeyPresses(['tab', 'tab', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func(text='Hello', title='Title', buttons=['A', 'B', 'C']), 'C') # test that pressing Esc is the same as clicking Cancel (but only when there is a cancel button) t = KeyPresses(['escape']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func(text='Escape button press test'), 'Cancel') # Make sure that Esc keypress does nothing if there is no Cancel button. t = KeyPresses(['escape', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(func(text='Escape button press test', buttons=['OK', 'Not OK']), 'OK') class PromptPasswordTests(unittest.TestCase): def test_prompt(self): self._prompt_and_password_tests(pymsgbox._promptTkinter, 'prompt()') def test_password(self): # NOTE: Currently there is no way to test the appearance of the * or custom mask characters. self._prompt_and_password_tests(pymsgbox._passwordTkinter, 'password()') def _prompt_and_password_tests(self, msgBoxFunc, msgBoxFuncName): # entering nothing t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual((msgBoxFuncName, msgBoxFunc()), (msgBoxFuncName, '')) # entering text t = KeyPresses(['a', 'b', 'c', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual((msgBoxFuncName, msgBoxFunc()), (msgBoxFuncName, 'abc')) # entering text, tabbing to the Ok key t = KeyPresses(['a', 'b', 'c', 'tab', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual((msgBoxFuncName, msgBoxFunc()), (msgBoxFuncName, 'abc')) # entering text but hitting cancel t = KeyPresses(['a', 'b', 'c', 'tab', 'tab', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual((msgBoxFuncName, msgBoxFunc()), (msgBoxFuncName, None)) # with text t = KeyPresses(['a', 'b', 'c', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual((msgBoxFuncName, msgBoxFunc('Hello')), (msgBoxFuncName, 'abc')) # with text and title t = KeyPresses(['a', 'b', 'c', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual((msgBoxFuncName, msgBoxFunc('Hello', 'Title')), (msgBoxFuncName, 'abc')) # with text, title and default value t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual((msgBoxFuncName, msgBoxFunc('Hello', 'Title', 'default')), (msgBoxFuncName, 'default')) # with text, title and default value specified by keyword arguments t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual((msgBoxFuncName, msgBoxFunc(text='Hello', title='Title', default='default')), (msgBoxFuncName, 'default')) class TimeoutTests(unittest.TestCase): def test_timeout(self): # Note: If these test's fail, the unit tests will hang. self.assertEqual(pymsgbox._alertTkinter('timeout test', timeout=300), pymsgbox.TIMEOUT_RETURN_VALUE) self.assertEqual(pymsgbox._confirmTkinter('timeout test', timeout=300), pymsgbox.TIMEOUT_RETURN_VALUE) self.assertEqual(pymsgbox.prompt('timeout test', timeout=300), pymsgbox.TIMEOUT_RETURN_VALUE) self.assertEqual(pymsgbox.password('timeout test', timeout=300), pymsgbox.TIMEOUT_RETURN_VALUE) """" # NOTE: This is weird. This test fails (the additional typed in text gets added # to the end of the default string, instead of replacing it), but when I run # this same code using PyAutoGUI from the interactive shell (on Win7 Py3.3) it # works. It also works when I type it in myself. # Commenting this out for now. class DefaultValueOverwriteTests(unittest.TestCase): def test_prompt(self): self._prompt_and_password_tests(pymsgbox.prompt, 'prompt()') def test_password(self): # NOTE: Currently there is no way to test the appearance of the * or custom mask characters. self._prompt_and_password_tests(pymsgbox.password, 'password()') def _prompt_and_password_tests(self, msgBoxFunc, msgBoxFuncName): # with text, title and default value that is typed over t = KeyPresses(['a', 'b', 'c', 'enter']) t.start() print('Line', inspect.currentframe().f_lineno); self.assertEqual((msgBoxFuncName, msgBoxFunc('Hello', 'Title', 'default')), (msgBoxFuncName, 'abc')) """ class WindowsNativeAlertTests(unittest.TestCase): def test_alert(self): if sys.platform != 'win32': return # TODO - We need some way of determining if the tkinter or native message box appeared. # test passing True for _tkinter t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(pymsgbox.alert(_tkinter=True), pymsgbox.OK_TEXT) # test passing timeout t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(pymsgbox.alert(timeout=300), pymsgbox.OK_TEXT) # test non-ok button to check that it falls back to tkinter t = KeyPresses(['enter']) t.start() print('Line', inspect.currentframe().f_lineno) self.assertEqual(pymsgbox.alert(button='Test'), 'Test') class WindowsNativeConfirmTests(unittest.TestCase): def test_confirm(self): if sys.platform != 'win32': return # TODO - We need some way of determining if the tkinter or native message box appeared. # press enter on OK #t = KeyPresses(['enter']) #t.start() #print('Line', inspect.currentframe().f_lineno) #self.assertEqual(pymsgbox.confirm(), pymsgbox.OK_TEXT) if __name__ == '__main__': unittest.main()