[Python-modules-commits] [python-public] 01/03: import python-public_0.4.orig.tar.gz
Barry Warsaw
barry at moszumanska.debian.org
Tue Dec 13 00:42:05 UTC 2016
This is an automated email from the git hooks/post-receive script.
barry pushed a commit to branch master
in repository python-public.
commit c27f42eeb5c8ab1db0acd0bdab113afe080f52e0
Author: Barry Warsaw <barry at python.org>
Date: Mon Dec 12 18:06:04 2016 -0500
import python-public_0.4.orig.tar.gz
---
LICENSE.txt | 13 ++
MANIFEST.in | 8 ++
NEWS.rst | 22 +++
PKG-INFO | 24 ++++
README.rst | 250 +++++++++++++++++++++++++++++++++
atpublic.egg-info/PKG-INFO | 24 ++++
atpublic.egg-info/SOURCES.txt | 17 +++
atpublic.egg-info/dependency_links.txt | 1 +
atpublic.egg-info/top_level.txt | 1 +
conf.py | 239 +++++++++++++++++++++++++++++++
coverage.ini | 13 ++
public/__init__.py | 30 ++++
public/public.py | 25 ++++
public/tests/__init__.py | 0
public/tests/test_public.py | 228 ++++++++++++++++++++++++++++++
setup.cfg | 5 +
setup.py | 55 ++++++++
setup_helpers.py | 153 ++++++++++++++++++++
tox.ini | 56 ++++++++
19 files changed, 1164 insertions(+)
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..0b2c13c
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,13 @@
+Copyright 2016 Barry Warsaw
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..f3b2742
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,8 @@
+include *.py MANIFEST.in
+global-include *.txt *.rst *.ini
+prune build
+prune dist
+prune .tox
+prune .git
+exclude .gitignore
+exclude *.so
diff --git a/NEWS.rst b/NEWS.rst
new file mode 100644
index 0000000..f5f66c7
--- /dev/null
+++ b/NEWS.rst
@@ -0,0 +1,22 @@
+==============
+ @public NEWS
+==============
+
+0.4 (2016-11-28)
+================
+* Add Python 3.6 support.
+* Make building the C extension optional, for environments without a C
+ compiler.
+
+0.3 (2016-05-25)
+================
+* Raise ``ValueError`` when ``__all__`` isn't a list (or subclass) instance.
+
+0.2 (2016-05-22)
+================
+* Documentation updates based on initial feedback.
+* Some minor test suite clean up.
+
+0.1 (2016-05-09)
+================
+* Initial release.
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..44e6efc
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,24 @@
+Metadata-Version: 1.1
+Name: atpublic
+Version: 0.4
+Summary: public -- @public for populating __all__
+Home-page: http://public.readthedocs.io/
+Author: Barry Warsaw
+Author-email: barry at python.org
+License: Apache 2.0
+Description: This is a very simple decorator and function which populates a module's
+ __all__ and optionally the module globals.
+
+ This provides both a pure-Python implementation and a C implementation. It is
+ proposed that the C implementation be added to builtins_ for Python 3.6.
+
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: POSIX
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Utilities
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..9c41aa5
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,250 @@
+=========
+ @public
+=========
+
+This is a very simple decorator and function which populates a module's
+``__all__`` and optionally the module globals. This provides both a
+pure-Python implementation and an optional C implementation.
+
+
+Background
+==========
+
+``__all__`` is great. It has both a functional and a documentation purpose.
+
+The functional purpose is that it `directly controls`_ which module names are
+imported by the ``from <module> import *`` statement. In the absence of an
+``__all__``, when this statement is executed, every name in ``<module>`` that
+does not start with an underscore will be imported. This often leads to
+importing too many names into the module. That's a good enough reason not to
+use ``from <module> import *`` with modules that don't have an ``__all__``.
+
+In the presence of an ``__all__``, only the names specified in this list are
+imported by the ``from <module> import *`` statement. This in essence gives
+the ``<module>`` author a way to explicitly state which names are for public
+consumption.
+
+And that's the second purpose of ``__all__``; it serves as module
+documentation, explicitly naming the public objects it wants to export. You
+can print a module's ``__all__`` and get an explicit declaration of its public
+API.
+
+
+The problem
+===========
+
+``__all__`` has two problems.
+
+First, it separates the declaration of a name's public export semantics from
+the implementation of that name. Usually the ``__all__`` is put at the top of
+the module, although this isn't required, and in some cases it's `actively
+prohibited`_. So when you're looking at the definition of a function or class
+in a module, you have to search for the ``__all__`` definition to know whether
+the function or class is intended for public consumption.
+
+This leads to the second problem, which is that it's too easy for the
+``__all__`` to get `out of sync`_ with the module's contents. Often a
+function or class is renamed, removed, or added without the ``__all__`` being
+updated. Then it's difficult to know what the module author's intent was, and
+it can lead to an exception when a string appearing in ``__all__`` doesn't
+match an existing name in the module.
+
+
+The solution
+============
+
+The solution is to provide a way to declare a name's *publicness* right at the
+point of its declaration, and to infer the name to export from that
+definition. In this way, a module's author never explicitly sets the
+``__all__`` so there's no way for it to get out of sync.
+
+This package, and Python `issue 26632`_, propose just such a solution, in the
+form of a ``public`` builtin that can be used as either a decorator, or a
+callable.
+
+You'll usually use this as a decorator, for example::
+
+ @public
+ def foo():
+ pass
+
+or::
+
+ @public
+ class Bar:
+ pass
+
+If you were to print the ``__all__`` after both of those code snippets, you'd
+see::
+
+ >>> print(__all__)
+ ['foo', 'Bar']
+
+Note that you do not need to initialize ``__all__`` in the module, since
+``public`` will do it for you. Of course, if your module *already* has an
+``__all__``, it will just append new names to the existing list.
+
+The requirements to use the ``@public`` decorator are simple: the decorated
+thing must have a ``__name__`` attribute. Since you'll overwhelmingly use it
+to decorate functions and classes, this will always be the case.
+
+There's one other common use case that isn't covered by the ``@public``
+decorator. Sometimes you want to declare simple constants or instances as
+publicly available. You can't use the ``@public`` decorator for two reasons:
+constants don't have a ``__name__`` and Python's syntax doesn't allow you to
+decorate such constructs.
+
+To solve this use case, ``public`` is also a callable function accepting
+keyword arguments. An example makes this obvious::
+
+ public(SEVEN=7)
+ public(a_bar=Bar())
+
+Now if you print the module's ``__all__`` you'll see::
+
+ >>> print(__all__)
+ ['foo', 'Bar', 'SEVEN', 'a_bar']
+
+and as should be obvious, the module contains name bindings for these
+constants::
+
+ >>> print(SEVEN)
+ 7
+ >>> print(a_bar)
+ <__main__.Bar object at ...>
+
+**Note:** While you can use ``public()`` with multiple keyword arguments in a
+single call, the order of the resulting ``__all__`` entries is undefined in
+Python versions earlier than 3.6, due to indeterminate dictionary sort order.
+If order matters to you, call ``public()`` multiple times each with a single
+keyword argument.
+
+
+Usage
+=====
+
+To use this, just import it::
+
+ >>> from public import public
+
+This package actually provides both a pure Python implementation and an
+optional C extension module. By default, the import above provides you with
+the more efficient C implementation, if available. See the installation
+instructions below for details.
+
+If for some reason you want the pure-Python implementation just do::
+
+ >>> from public import py_public as public
+
+Having to do this import in every module you want to use it can get pretty
+tedious, so what if you could put ``public`` into Python's builtins? Then it
+would be available in all your code for free::
+
+ >>> from public import install
+ >>> install()
+
+and now you can just use ``@public`` without having to import anything in your
+other modules.
+
+By default, this installs the C implementation but if you wanted to install
+the pure-Python version, just do::
+
+ >>> from public import py_install
+ >>> py_install()
+
+
+Installation
+============
+
+Use the normal ``setup.py install`` or ``pip install`` commands to install
+this library. By default, the C extension is **not** built, in order to make
+it more portable to environments without a C compiler. If you want a version
+that's a little more efficient than the pure-Python implementation, set the
+environment variable ``ATPUBLIC_BUILD_EXTENSION=1`` when you build/install the
+module.
+
+
+Caveats
+=======
+
+There are some important usage restrictions you should be aware of:
+
+* Only use ``@public`` on top-level object. Specifically, don't try to use
+ ``@public`` on a class method name. While the declaration won't fail, when
+ You will get an exception when you attempt to ``from <module> import *``
+ because the name pulled from ``__all__`` won't be in the module's globals.
+* If you explicitly set ``__all__`` in your module, be sure to set it to a
+ list. Some style guides require ``__all__`` to be a tuple, but since that's
+ immutable, as soon as ``@public`` tries to append to it, you will get an
+ exception. Best practice is to not set ``__all__`` explicitly; let
+ ``@public`` do it!
+* If you still want ``__all__`` to be immutable, put the following at the
+ bottom of your module::
+
+ __all__ = tuple(__all__)
+
+
+Alternatives
+============
+
+This isn't a unique approach to ``@public``. Other_ implementations_ do
+exist. There are some subtle differences between this package and those
+others. This package:
+
+* uses keyword arguments to map names which don't have an ``__name__``
+ attribute;
+* can be used to bind names and values into a module's globals;
+* provides both C and Python implementations;
+* can optionally put ``public`` in builtins.
+
+
+Author
+======
+
+``public`` is Copyright (C) 2016 Barry Warsaw
+
+Contact Barry:
+
+* barry at python.org
+* @pumpichank on Twitter
+* @warsaw on GitHub and GitLab
+
+Licensed under the terms of the Apache License 2.0. See LICENSE.txt for
+details.
+
+
+Project details
+===============
+
+* Project home: https://gitlab.com/warsaw/public
+* Report bugs at: https://gitlab.com/warsaw/public/issues
+* Fork the code: https://gitlab.com/warsaw/public.git
+* Documentation: http://public.readthedocs.io/en/latest/
+* PyPI: https://pypi.python.org/pypi/atpublic
+
+
+NEWS
+====
+
+.. toctree::
+ :maxdepth: 2
+
+ NEWS
+
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+
+.. _`issue 26632`: http://bugs.python.org/issue26632
+.. _builtins: https://docs.python.org/3/library/builtins.html
+.. _`directly controls`: https://docs.python.org/3/tutorial/modules.html#importing-from-a-package
+.. _`actively prohibited`: http://pep8.readthedocs.io/en/latest/intro.html?highlight=e402#error-codes
+.. _`out of sync`: http://bugs.python.org/issue23883
+.. _Other: https://pypi.python.org/pypi/public
+.. _implementations: http://bugs.python.org/issue22247#msg225637
diff --git a/atpublic.egg-info/PKG-INFO b/atpublic.egg-info/PKG-INFO
new file mode 100644
index 0000000..44e6efc
--- /dev/null
+++ b/atpublic.egg-info/PKG-INFO
@@ -0,0 +1,24 @@
+Metadata-Version: 1.1
+Name: atpublic
+Version: 0.4
+Summary: public -- @public for populating __all__
+Home-page: http://public.readthedocs.io/
+Author: Barry Warsaw
+Author-email: barry at python.org
+License: Apache 2.0
+Description: This is a very simple decorator and function which populates a module's
+ __all__ and optionally the module globals.
+
+ This provides both a pure-Python implementation and a C implementation. It is
+ proposed that the C implementation be added to builtins_ for Python 3.6.
+
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: POSIX
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Utilities
diff --git a/atpublic.egg-info/SOURCES.txt b/atpublic.egg-info/SOURCES.txt
new file mode 100644
index 0000000..e3ffc12
--- /dev/null
+++ b/atpublic.egg-info/SOURCES.txt
@@ -0,0 +1,17 @@
+LICENSE.txt
+MANIFEST.in
+NEWS.rst
+README.rst
+conf.py
+coverage.ini
+setup.py
+setup_helpers.py
+tox.ini
+atpublic.egg-info/PKG-INFO
+atpublic.egg-info/SOURCES.txt
+atpublic.egg-info/dependency_links.txt
+atpublic.egg-info/top_level.txt
+public/__init__.py
+public/public.py
+public/tests/__init__.py
+public/tests/test_public.py
\ No newline at end of file
diff --git a/atpublic.egg-info/dependency_links.txt b/atpublic.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/atpublic.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/atpublic.egg-info/top_level.txt b/atpublic.egg-info/top_level.txt
new file mode 100644
index 0000000..a48cf0d
--- /dev/null
+++ b/atpublic.egg-info/top_level.txt
@@ -0,0 +1 @@
+public
diff --git a/conf.py b/conf.py
new file mode 100644
index 0000000..4cf68da
--- /dev/null
+++ b/conf.py
@@ -0,0 +1,239 @@
+# -*- coding: utf-8 -*-
+#
+# 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, 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 = ['sphinx.ext.autodoc',
+ 'sphinx.ext.viewcode',
+ 'sphinx.ext.graphviz']
+
+# 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 = 'README'
+
+# General information about the project.
+project = u'public'
+copyright = u'2016 by Barry Warsaw'
+
+# 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.
+from public import __version__ as version
+# The full version, including alpha/beta/rc tags.
+release = version
+
+# 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', 'eggs', '.tox']
+
+# 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 = []
+
+
+# -- 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
+# "<project> v<release> 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']
+
+# 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 <link> 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 = 'public'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'public.tex', u'public Documentation',
+ u'Barry Warsaw', '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
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# 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', 'public', u'public Documentation',
+ [u'Barry Warsaw'], 1)
+]
+
+
+def index_html():
+ import errno
+ cwd = os.getcwd()
+ try:
+ try:
+ os.makedirs('build/sphinx/html')
+ except OSError as error:
+ if error.errno != errno.EEXIST:
+ raise
+ os.chdir('build/sphinx/html')
+ try:
+ os.symlink('README.html', 'index.html')
+ print('index.html -> README.html')
+ except OSError as error:
+ if error.errno != errno.EEXIST:
+ raise
+ finally:
+ os.chdir(cwd)
+
+import atexit
+atexit.register(index_html)
diff --git a/coverage.ini b/coverage.ini
new file mode 100644
index 0000000..46049cd
--- /dev/null
+++ b/coverage.ini
@@ -0,0 +1,13 @@
+[run]
+branch = true
+parallel = true
+omit =
+ setup*
+ .tox/*/lib/python*/site-packages/*
+ public/tests/*
+ /tmp/*
+
+[paths]
+source =
+ public
+ .tox/*/lib/python*/site-packages/public
diff --git a/public/__init__.py b/public/__init__.py
new file mode 100644
index 0000000..e9c3128
--- /dev/null
+++ b/public/__init__.py
@@ -0,0 +1,30 @@
+# Copyright (C) 2016 Barry Warsaw
+#
+# This project is licensed under the terms of the Apache 2.0 License. See
+# LICENSE.txt for details.
+
+"""@public -- populate __all__"""
+
+from public.public import public as py_public
+try:
+ from _public import public as c_public
+except ImportError: # pragma: nocover
+ # This library was built without the extension module.
+ c_public = None
+
+
+__version__ = '0.4'
+
+
+if c_public is None: # pragma: nocover
+ py_public(public=py_public)
+ py_public(py_public=py_public)
+else: # pragma: nocover
+ c_public(public=c_public)
+ c_public(py_public=py_public)
+
+
+def install():
+ """Install @public into builtins."""
+ import builtins
+ builtins.public = c_public or py_public
diff --git a/public/public.py b/public/public.py
new file mode 100644
index 0000000..27ea415
--- /dev/null
+++ b/public/public.py
@@ -0,0 +1,25 @@
+# Copyright (C) 2016 Barry Warsaw
+#
+# This project is licensed under the terms of the Apache 2.0 License. See
+# LICENSE.txt for details.
+
+"""Pure-Python implementation."""
+
+import sys
+
+
+# http://bugs.python.org/issue26632
+def public(thing=None, **kws):
+ mdict = (sys._getframe(1).f_globals
+ if thing is None
+ else sys.modules[thing.__module__].__dict__)
+ dunder_all = mdict.setdefault('__all__', [])
+ if not isinstance(dunder_all, list):
+ raise ValueError(
+ '__all__ must be a list not: {}'.format(type(dunder_all)))
+ if thing is not None:
+ dunder_all.append(thing.__name__)
+ for key, value in kws.items():
+ dunder_all.append(key)
+ mdict[key] = value
+ return thing
diff --git a/public/tests/__init__.py b/public/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/public/tests/test_public.py b/public/tests/test_public.py
new file mode 100644
index 0000000..d69ba86
--- /dev/null
+++ b/public/tests/test_public.py
@@ -0,0 +1,228 @@
+# Copyright (C) 2016 Barry Warsaw
+#
+# This project is licensed under the terms of the Apache 2.0 License. See
+# LICENSE.txt for details.
+
+import os
+import sys
+import builtins
+import unittest
+
+try:
+ from _public import public as c_public
+except ImportError:
+ # This library was built without the extension module.
+ c_public = None
+from contextlib import ExitStack, contextmanager
+from importlib import import_module
+from public import install
+from public.public import public as py_public
+from tempfile import TemporaryDirectory
+
+
+ at contextmanager
+def syspath(directory):
+ try:
+ sys.path.insert(0, directory)
+ yield
+ finally:
+ assert sys.path[0] == directory
+ del sys.path[0]
+
+
+ at contextmanager
+def sysmodules():
+ modules = sys.modules.copy()
+ try:
+ yield
+ finally:
+ sys.modules = modules
+
+
+class TestPublic(unittest.TestCase):
+ import_line = 'from public import public'
+
+ def setUp(self):
+ self.resources = ExitStack()
+ self.addCleanup(self.resources.close)
+ self.tmpdir = self.resources.enter_context(TemporaryDirectory())
+ self.resources.enter_context(syspath(self.tmpdir))
+ self.resources.enter_context(sysmodules())
+ self.modpath = os.path.join(self.tmpdir, 'example.py')
+
+ def test_atpublic_function(self):
+ with open(self.modpath, 'w', encoding='utf-8') as fp:
+ print("""\
+{}
+
+ at public
+def a_function():
+ pass
+""".format(self.import_line), file=fp)
+ module = import_module('example')
+ self.assertEqual(module.__all__, ['a_function'])
+
+ def test_atpublic_function_runnable(self):
+ with open(self.modpath, 'w', encoding='utf-8') as fp:
+ print("""\
+{}
+
+ at public
+def a_function():
+ return 1
+""".format(self.import_line), file=fp)
+ module = import_module('example')
+ self.assertEqual(module.a_function(), 1)
+
+ def test_atpublic_class(self):
+ with open(self.modpath, 'w', encoding='utf-8') as fp:
+ print("""\
+{}
+
+ at public
+class AClass:
+ pass
+""".format(self.import_line), file=fp)
+ module = import_module('example')
+ self.assertEqual(module.__all__, ['AClass'])
+
+ def test_atpublic_class_runnable(self):
+ with open(self.modpath, 'w', encoding='utf-8') as fp:
+ print("""\
+{}
+
+ at public
+class AClass:
+ pass
+""".format(self.import_line), file=fp)
+ module = import_module('example')
+ self.assertIsInstance(module.AClass(), module.AClass)
+
+ def test_atpublic_two_things(self):
+ with open(self.modpath, 'w', encoding='utf-8') as fp:
+ print("""\
+{}
+
+ at public
+def foo():
+ pass
+
+ at public
+class AClass:
+ pass
+""".format(self.import_line), file=fp)
+ module = import_module('example')
+ self.assertEqual(module.__all__, ['foo', 'AClass'])
+
+ def test_atpublic_append_to_all(self):
+ with open(self.modpath, 'w', encoding='utf-8') as fp:
+ print("""\
+__all__ = ['a', 'b']
+
+a = 1
+b = 2
+
+{}
+
+ at public
+def foo():
+ pass
+
+ at public
+class AClass:
+ pass
+""".format(self.import_line), file=fp)
+ module = import_module('example')
+ self.assertEqual(module.__all__, ['a', 'b', 'foo', 'AClass'])
+
+ def test_atpublic_keywords(self):
+ with open(self.modpath, 'w', encoding='utf-8') as fp:
+ print("""\
+{}
+
+public(a=1, b=2)
+""".format(self.import_line), file=fp)
+ module = import_module('example')
+ self.assertEqual(sorted(module.__all__), ['a', 'b'])
+
+ def test_atpublic_keywords_multicall(self):
+ with open(self.modpath, 'w', encoding='utf-8') as fp:
+ print("""\
+{}
+
+public(b=1)
+public(a=2)
+""".format(self.import_line), file=fp)
+ module = import_module('example')
+ self.assertEqual(module.__all__, ['b', 'a'])
+
+ def test_atpublic_keywords_global_bindings(self):
+ with open(self.modpath, 'w', encoding='utf-8') as fp:
+ print("""\
+{}
+
+public(a=1, b=2)
+""".format(self.import_line), file=fp)
+ module = import_module('example')
+ self.assertEqual(module.a, 1)
+ self.assertEqual(module.b, 2)
+
+ def test_atpublic_mixnmatch(self):
+ with open(self.modpath, 'w', encoding='utf-8') as fp:
+ print("""\
+__all__ = ['a', 'b']
+
+a = 1
+b = 2
+
+{}
+
+ at public
+def foo():
+ pass
+
+ at public
+class AClass:
+ pass
+
+public(c=3)
+""".format(self.import_line), file=fp)
+ module = import_module('example')
+ self.assertEqual(module.__all__, ['a', 'b', 'foo', 'AClass', 'c'])
+
+ def test_all_is_a_tuple(self):
+ with open(self.modpath, 'w', encoding='utf-8') as fp:
+ print("""\
+__all__ = ('foo',)
+
+{}
+
+def foo():
+ pass
+
+ at public
+def bar():
+ pass
+""".format(self.import_line), file=fp)
+ self.assertRaises(ValueError, import_module, 'example')
+
+
+class TestPyPublic(TestPublic):
+ import_line = 'from public import py_public as public'
+
+
+class TestInstall(unittest.TestCase):
+ @unittest.skipIf(c_public is None, 'Built without the extension module')
+ def test_install_c_public(self):
+ self.assertFalse(hasattr(builtins, 'public'))
+ self.addCleanup(delattr, builtins, 'public')
... 303 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-public.git
More information about the Python-modules-commits
mailing list