From c93c87abc9878cb75f33effec77ea812d1eef1a1 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 15 Aug 2022 22:26:12 +0000 Subject: Remove funcsigs, which is no longer used. Do not necromance this without going through the go/android-3p process again. Test: treehugger Change-Id: I57bde9cf18542d3740be93de61ce1dd3040f2052 --- Android.bp | 55 --- Android_tests.py | 33 -- CHANGELOG | 19 - LICENSE | 13 - MANIFEST.in | 7 - METADATA | 21 - MODULE_LICENSE_APACHE2 | 0 Makefile | 39 -- OWNERS | 5 +- README.rst | 83 ---- docs/Makefile | 153 ------ docs/_templates/page.html | 9 - docs/conf.py | 251 ---------- docs/index.rst | 315 ------------- funcsigs/Android.bp | 31 -- funcsigs/__init__.py | 818 -------------------------------- funcsigs/odict.py | 261 ---------- funcsigs/version.py | 1 - requirements/development.txt | 6 - requirements/production.txt | 0 setup.cfg | 2 - setup.py | 55 --- tests/__init__.py | 0 tests/test_formatannotation.py | 27 -- tests/test_funcsigs.py | 93 ---- tests/test_inspect.py | 1019 ---------------------------------------- 26 files changed, 1 insertion(+), 3315 deletions(-) delete mode 100644 Android.bp delete mode 100644 Android_tests.py delete mode 100644 CHANGELOG delete mode 100644 LICENSE delete mode 100644 MANIFEST.in delete mode 100644 METADATA delete mode 100644 MODULE_LICENSE_APACHE2 delete mode 100644 Makefile delete mode 100644 README.rst delete mode 100644 docs/Makefile delete mode 100644 docs/_templates/page.html delete mode 100644 docs/conf.py delete mode 100644 docs/index.rst delete mode 100644 funcsigs/Android.bp delete mode 100644 funcsigs/__init__.py delete mode 100644 funcsigs/odict.py delete mode 100644 funcsigs/version.py delete mode 100644 requirements/development.txt delete mode 100644 requirements/production.txt delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 tests/__init__.py delete mode 100644 tests/test_formatannotation.py delete mode 100644 tests/test_funcsigs.py delete mode 100644 tests/test_inspect.py diff --git a/Android.bp b/Android.bp deleted file mode 100644 index 2f4dfa8..0000000 --- a/Android.bp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2018 Google Inc. All rights reserved. -// -// 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. - -package { - default_applicable_licenses: ["external_python_funcsigs_license"], -} - -// Added automatically by a large-scale-change that took the approach of -// 'apply every license found to every target'. While this makes sure we respect -// every license restriction, it may not be entirely correct. -// -// e.g. GPL in an MIT project might only apply to the contrib/ directory. -// -// Please consider splitting the single license below into multiple licenses, -// taking care not to lose any license_kind information, and overriding the -// default license using the 'licenses: [...]' property on targets as needed. -// -// For unused files, consider creating a 'fileGroup' with "//visibility:private" -// to attach the license to, and including a comment whether the files may be -// used in the current project. -// See: http://go/android-license-faq -license { - name: "external_python_funcsigs_license", - visibility: [":__subpackages__"], - license_kinds: [ - "SPDX-license-identifier-Apache-2.0", - "SPDX-license-identifier-PSF-2.0", - ], - license_text: [ - "LICENSE", - ], -} - -python_test { - name: "py3-funcsigs-tests", - main: "Android_tests.py", - srcs: [ - "tests/*.py", - "Android_tests.py", - ], - host_supported: true, - libs: ["py-funcsigs"], - data: ["README.rst"], -} diff --git a/Android_tests.py b/Android_tests.py deleted file mode 100644 index ac84729..0000000 --- a/Android_tests.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2018 Google Inc. All rights reserved. -# -# 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. - -import os -import sys -import unittest - -# this runs any test*.py files located anywhere in this subtree -if __name__ == '__main__': - test_loader = unittest.defaultTestLoader - # output is normal text formatting (as if running from a CLI), prints to stderr - test_runner = unittest.TextTestRunner(stream=sys.stderr) - - # look at tests relative to the dir of this file. - this_dir = os.path.dirname(os.path.abspath(__file__)) - - # automagically find all tests recursively whose file name matches test*.py - test_suite = test_loader.discover(this_dir, pattern='test*.py') - - # execute all the found tests - test_runner.run(test_suite) - diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index 602eec5..0000000 --- a/CHANGELOG +++ /dev/null @@ -1,19 +0,0 @@ -Changelog ---------- - -0.4 (2013-12-20) -```````````````` -* Fix unbound methods getting their first parameter curried -* Publish Python wheel packages - -0.3 (2013-05-29) -```````````````` -* Fix annotation formatting of builtin types on Python 2.x - -0.2 (2012-01-07) -```````````````` -* PyPy compatability - -0.1 (2012-01-06) -```````````````` -* Initial release diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 3e563d6..0000000 --- a/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2013 Aaron Iles - -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 deleted file mode 100644 index f0abb42..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,7 +0,0 @@ -recursive-include docs * -recursive-include tests *.py -include *.py -include CHANGELOG -include LICENSE -include MANIFEST.in -include README.rst diff --git a/METADATA b/METADATA deleted file mode 100644 index 1539e3a..0000000 --- a/METADATA +++ /dev/null @@ -1,21 +0,0 @@ -name: "funcsigs" -description: - "funcsigs is a backport of the PEP 362 function signature features from " - "Python 3.3's inspect module. The backport is compatible with Python 2.6, " - "2.7 as well as 3.2 and up. " - " " - "(The primary purpose for importing this is as a pytest dependency)" - -third_party { - url { - type: HOMEPAGE - value: "https://pypi.org/project/funcsigs/" - } - url { - type: GIT - value: "https://github.com/aliles/funcsigs.git" - } - version: "0.4" - last_upgrade_date { year: 2018 month: 8 day: 2 } - license_type: NOTICE -} diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29..0000000 diff --git a/Makefile b/Makefile deleted file mode 100644 index e232923..0000000 --- a/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -SHELL := /bin/bash - -deps: - pip install --upgrade \ - -r requirements/development.txt \ - -r requirements/production.txt - -sdist: - python setup.py sdist - python setup.py bdist_wheel - -register: - python setup.py register - python setup.py sdist upload - python setup.py bdist_wheel upload - -site: - cd docs; make html - -test: - coverage run setup.py test - -unittest: - coverage run -m unittest discover - -lint: - flake8 --exit-zero funcsigs tests - -coverage: - coverage report --show-missing - -clean: - python setup.py clean --all - find . -type f -name "*.pyc" -exec rm '{}' + - find . -type d -name "__pycache__" -exec rmdir '{}' + - rm -rf *.egg-info .coverage - cd docs; make clean - -docs: site diff --git a/OWNERS b/OWNERS index 136a553..7529cb9 100644 --- a/OWNERS +++ b/OWNERS @@ -1,4 +1 @@ -# Default owners are top 3 or more active developers of the past 1 or 2 years -# or people with more than 10 commits last year. -# Please update this list if you find better owner candidates. -iam@google.com +include platform/system/core:/janitors/OWNERS diff --git a/README.rst b/README.rst deleted file mode 100644 index f04b7b4..0000000 --- a/README.rst +++ /dev/null @@ -1,83 +0,0 @@ -funcsigs -======== - -``funcsigs`` is a backport of the `PEP 362`_ function signature features from -Python 3.3's `inspect`_ module. The backport is compatible with Python 2.6, 2.7 -as well as 3.2 and up. - -|pypi_version| - -Documentation -------------- - -The reference documentation is standard library documentation for the -`inspect`_ module in Python3. This documentation has been included in the -``funcsigs`` package documentation hosted on `Read The Docs`_. - -Example -------- - -To obtain a signature object, pass the target function to the -``funcsigs.signature`` function. :: - - >>> from funcsigs import signature - >>> def foo(a, b=None, *args, **kwargs): - ... pass - - >>> sig = signature(foo) - -For the details of the signature object, refer to the either the package of -standard library documentation. - -Compatability -------------- - -The ``funcsigs`` backport has been tested against: - -* CPython 2.6 -* CPython 2.7 -* CPython 3.2 -* PyPy 1.9 - -Continuous integration testing is provided by `Travis CI`_. - -Under Python 2.x there is a compatability issue when a function is assigned to -the ``__wrapped__`` property of a class after it has been constructed. -Similiarily there under PyPy directly passing the ``__call__`` method of a -builtin is also a compatability issues. Otherwise the functionality is -believed to be uniform between both Python2 and Python3. - -Issues ------- - -Source code for ``funcsigs`` is hosted on `GitHub`_. Any bug reports or feature -requests can be made using GitHub's `issues system`_. |build_status| |coverage| - -Copyright ---------- - -This is a derived work of CPython under the terms of the `PSF License -Agreement`_. The original CPython inspect module, its unit tests and -documentation are the copyright of the Python Software Foundation. The derived -work is distributed under the `Apache License Version 2.0`_. - -.. _Apache License Version 2.0: http://opensource.org/licenses/Apache-2.0 -.. _GitHub: https://github.com/aliles/funcsigs -.. _PSF License Agreement: http://docs.python.org/3/license.html#terms-and-conditions-for-accessing-or-otherwise-using-python -.. _Travis CI: http://travis-ci.org/ -.. _Read The Docs: http://funcsigs.readthedocs.org/ -.. _PEP 362: http://www.python.org/dev/peps/pep-0362/ -.. _inspect: http://docs.python.org/3/library/inspect.html#introspecting-callables-with-the-signature-object -.. _issues system: https://github.com/alies/funcsigs/issues - -.. |build_status| image:: https://secure.travis-ci.org/aliles/funcsigs.png?branch=master - :target: http://travis-ci.org/#!/aliles/funcsigs - :alt: Current build status - -.. |coverage| image:: https://coveralls.io/repos/aliles/funcsigs/badge.png?branch=master - :target: https://coveralls.io/r/aliles/funcsigs?branch=master - :alt: Coverage status - -.. |pypi_version| image:: https://pypip.in/v/funcsigs/badge.png - :target: https://crate.io/packages/funcsigs/ - :alt: Latest PyPI version diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index f7ab3d1..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,153 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# 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 " 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 " 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/funcsigs.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/funcsigs.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/funcsigs" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/funcsigs" - @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." - -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." diff --git a/docs/_templates/page.html b/docs/_templates/page.html deleted file mode 100644 index 5e1e00b..0000000 --- a/docs/_templates/page.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends "!page.html" %} -{% block extrahead %} - - Fork me on GitHub - - {{ super() }} -{% endblock %} diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index c6e4194..0000000 --- a/docs/conf.py +++ /dev/null @@ -1,251 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# funcsigs documentation build configuration file, created by -# sphinx-quickstart on Fri Apr 20 20:27:52 2012. -# -# 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.intersphinx', 'sphinx.ext.viewcode'] - -# 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 = 'funcsigs' -copyright = '2013, Aaron Iles' - -# 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 funcsigs import __version__ -version = '.'.join(__version__.split('.')[:2]) -# 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'] - -# 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 = 'agogo' - -# 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 = [] - -# 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 = 'funcsigsdoc' - - -# -- 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]). -latex_documents = [ - ('index', 'funcsigs.tex', 'funcsigs Documentation', - 'Aaron Iles', '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', 'funcsigs', 'funcsigs Documentation', - ['Aaron Iles'], 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', 'funcsigs', 'funcsigs Documentation', - 'Aaron Iles', 'funcsigs', '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' - - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = { - 'python3': ('http://docs.python.org/py3k', None), - 'python': ('http://docs.python.org/', None) -} diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 5d0f42f..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,315 +0,0 @@ -.. funcsigs documentation master file, created by - sphinx-quickstart on Fri Apr 20 20:27:52 2012. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Introducing funcsigs -==================== - -The Funcsigs Package --------------------- - -*funcsigs* is a backport of the `PEP 362`_ function signature features from -Python 3.3's `inspect`_ module. The backport is compatible with Python 2.6, 2.7 -as well as 3.2 and up. - -.. _PEP 362: http://www.python.org/dev/peps/pep-0362/ -.. _inspect: http://docs.python.org/3/library/inspect.html#introspecting-callables-with-the-signature-object - -Compatability -````````````` - -The *funcsigs* backport has been tested against: - -* CPython 2.6 -* CPython 2.7 -* CPython 3.2 -* PyPy 1.9 - -Continuous integration testing is provided by `Travis CI`_. - -Under Python 2.x there is a compatability issue when a function is assigned to -the ``__wrapped__`` property of a class after it has been constructed. -Similiarily there under PyPy directly passing the ``__call__`` method of a -builtin is also a compatability issues. Otherwise the functionality is -believed to be uniform between both Python2 and Python3. - -.. _Travis CI: http://travis-ci.org/ - -Issues -`````` - -Source code for *funcsigs* is hosted on `GitHub`_. Any bug reports or feature -requests can be made using GitHub's `issues system`_. - -.. _GitHub: https://github.com/aliles/funcsigs -.. _issues system: https://github.com/alies/funcsigs/issues - -Introspecting callables with the Signature object -------------------------------------------------- - -.. note:: - - This section of documentation is a direct repoduction of the Python - standard library documentation for the inspect module. - -The Signature object represents the call signature of a callable object and its -return annotation. To retrieve a Signature object, use the :func:`signature` -function. - -.. function:: signature(callable) - - Return a :class:`Signature` object for the given ``callable``:: - - >>> from inspect import signature - >>> def foo(a, *, b:int, **kwargs): - ... pass - - >>> sig = signature(foo) - - >>> str(sig) - '(a, *, b:int, **kwargs)' - - >>> str(sig.parameters['b']) - 'b:int' - - >>> sig.parameters['b'].annotation - - - Accepts a wide range of python callables, from plain functions and classes to - :func:`functools.partial` objects. - - .. note:: - - Some callables may not be introspectable in certain implementations of - Python. For example, in CPython, built-in functions defined in C provide - no metadata about their arguments. - - -.. class:: Signature - - A Signature object represents the call signature of a function and its return - annotation. For each parameter accepted by the function it stores a - :class:`Parameter` object in its :attr:`parameters` collection. - - Signature objects are *immutable*. Use :meth:`Signature.replace` to make a - modified copy. - - .. attribute:: Signature.empty - - A special class-level marker to specify absence of a return annotation. - - .. attribute:: Signature.parameters - - An ordered mapping of parameters' names to the corresponding - :class:`Parameter` objects. - - .. attribute:: Signature.return_annotation - - The "return" annotation for the callable. If the callable has no "return" - annotation, this attribute is set to :attr:`Signature.empty`. - - .. method:: Signature.bind(*args, **kwargs) - - Create a mapping from positional and keyword arguments to parameters. - Returns :class:`BoundArguments` if ``*args`` and ``**kwargs`` match the - signature, or raises a :exc:`TypeError`. - - .. method:: Signature.bind_partial(*args, **kwargs) - - Works the same way as :meth:`Signature.bind`, but allows the omission of - some required arguments (mimics :func:`functools.partial` behavior.) - Returns :class:`BoundArguments`, or raises a :exc:`TypeError` if the - passed arguments do not match the signature. - - .. method:: Signature.replace(*[, parameters][, return_annotation]) - - Create a new Signature instance based on the instance replace was invoked - on. It is possible to pass different ``parameters`` and/or - ``return_annotation`` to override the corresponding properties of the base - signature. To remove return_annotation from the copied Signature, pass in - :attr:`Signature.empty`. - - :: - - >>> def test(a, b): - ... pass - >>> sig = signature(test) - >>> new_sig = sig.replace(return_annotation="new return anno") - >>> str(new_sig) - "(a, b) -> 'new return anno'" - - -.. class:: Parameter - - Parameter objects are *immutable*. Instead of modifying a Parameter object, - you can use :meth:`Parameter.replace` to create a modified copy. - - .. attribute:: Parameter.empty - - A special class-level marker to specify absence of default values and - annotations. - - .. attribute:: Parameter.name - - The name of the parameter as a string. Must be a valid python identifier - name (with the exception of ``POSITIONAL_ONLY`` parameters, which can have - it set to ``None``). - - .. attribute:: Parameter.default - - The default value for the parameter. If the parameter has no default - value, this attribute is set to :attr:`Parameter.empty`. - - .. attribute:: Parameter.annotation - - The annotation for the parameter. If the parameter has no annotation, - this attribute is set to :attr:`Parameter.empty`. - - .. attribute:: Parameter.kind - - Describes how argument values are bound to the parameter. Possible values - (accessible via :class:`Parameter`, like ``Parameter.KEYWORD_ONLY``): - - +------------------------+----------------------------------------------+ - | Name | Meaning | - +========================+==============================================+ - | *POSITIONAL_ONLY* | Value must be supplied as a positional | - | | argument. | - | | | - | | Python has no explicit syntax for defining | - | | positional-only parameters, but many built-in| - | | and extension module functions (especially | - | | those that accept only one or two parameters)| - | | accept them. | - +------------------------+----------------------------------------------+ - | *POSITIONAL_OR_KEYWORD*| Value may be supplied as either a keyword or | - | | positional argument (this is the standard | - | | binding behaviour for functions implemented | - | | in Python.) | - +------------------------+----------------------------------------------+ - | *VAR_POSITIONAL* | A tuple of positional arguments that aren't | - | | bound to any other parameter. This | - | | corresponds to a ``*args`` parameter in a | - | | Python function definition. | - +------------------------+----------------------------------------------+ - | *KEYWORD_ONLY* | Value must be supplied as a keyword argument.| - | | Keyword only parameters are those which | - | | appear after a ``*`` or ``*args`` entry in a | - | | Python function definition. | - +------------------------+----------------------------------------------+ - | *VAR_KEYWORD* | A dict of keyword arguments that aren't bound| - | | to any other parameter. This corresponds to a| - | | ``**kwargs`` parameter in a Python function | - | | definition. | - +------------------------+----------------------------------------------+ - - Example: print all keyword-only arguments without default values:: - - >>> def foo(a, b, *, c, d=10): - ... pass - - >>> sig = signature(foo) - >>> for param in sig.parameters.values(): - ... if (param.kind == param.KEYWORD_ONLY and - ... param.default is param.empty): - ... print('Parameter:', param) - Parameter: c - - .. method:: Parameter.replace(*[, name][, kind][, default][, annotation]) - - Create a new Parameter instance based on the instance replaced was invoked - on. To override a :class:`Parameter` attribute, pass the corresponding - argument. To remove a default value or/and an annotation from a - Parameter, pass :attr:`Parameter.empty`. - - :: - - >>> from inspect import Parameter - >>> param = Parameter('foo', Parameter.KEYWORD_ONLY, default=42) - >>> str(param) - 'foo=42' - - >>> str(param.replace()) # Will create a shallow copy of 'param' - 'foo=42' - - >>> str(param.replace(default=Parameter.empty, annotation='spam')) - "foo:'spam'" - - -.. class:: BoundArguments - - Result of a :meth:`Signature.bind` or :meth:`Signature.bind_partial` call. - Holds the mapping of arguments to the function's parameters. - - .. attribute:: BoundArguments.arguments - - An ordered, mutable mapping (:class:`collections.OrderedDict`) of - parameters' names to arguments' values. Contains only explicitly bound - arguments. Changes in :attr:`arguments` will reflect in :attr:`args` and - :attr:`kwargs`. - - Should be used in conjunction with :attr:`Signature.parameters` for any - argument processing purposes. - - .. note:: - - Arguments for which :meth:`Signature.bind` or - :meth:`Signature.bind_partial` relied on a default value are skipped. - However, if needed, it is easy to include them. - - :: - - >>> def foo(a, b=10): - ... pass - - >>> sig = signature(foo) - >>> ba = sig.bind(5) - - >>> ba.args, ba.kwargs - ((5,), {}) - - >>> for param in sig.parameters.values(): - ... if param.name not in ba.arguments: - ... ba.arguments[param.name] = param.default - - >>> ba.args, ba.kwargs - ((5, 10), {}) - - - .. attribute:: BoundArguments.args - - A tuple of positional arguments values. Dynamically computed from the - :attr:`arguments` attribute. - - .. attribute:: BoundArguments.kwargs - - A dict of keyword arguments values. Dynamically computed from the - :attr:`arguments` attribute. - - The :attr:`args` and :attr:`kwargs` properties can be used to invoke - functions:: - - def test(a, *, b): - ... - - sig = signature(test) - ba = sig.bind(10, b=20) - test(*ba.args, **ba.kwargs) - - -.. seealso:: - - :pep:`362` - Function Signature Object. - The detailed specification, implementation details and examples. - -Copyright ---------- - -*funcsigs* is a derived work of CPython under the terms of the `PSF License -Agreement`_. The original CPython inspect module, its unit tests and -documentation are the copyright of the Python Software Foundation. The derived -work is distributed under the `Apache License Version 2.0`_. - -.. _PSF License Agreement: http://docs.python.org/3/license.html#terms-and-conditions-for-accessing-or-otherwise-using-python -.. _Apache License Version 2.0: http://opensource.org/licenses/Apache-2.0 diff --git a/funcsigs/Android.bp b/funcsigs/Android.bp deleted file mode 100644 index 74882e7..0000000 --- a/funcsigs/Android.bp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2018 Google Inc. All rights reserved. -// -// 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. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "external_python_funcsigs_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["external_python_funcsigs_license"], -} - -python_library { - name: "py-funcsigs", - host_supported: true, - srcs: [ - "*.py", - ], - pkg_path: "funcsigs", -} diff --git a/funcsigs/__init__.py b/funcsigs/__init__.py deleted file mode 100644 index fd2f47b..0000000 --- a/funcsigs/__init__.py +++ /dev/null @@ -1,818 +0,0 @@ -# Copyright 2001-2013 Python Software Foundation; All Rights Reserved -"""Function signature objects for callables - -Back port of Python 3.3's function signature tools from the inspect module, -modified to be compatible with Python 2.6, 2.7 and 3.2+. -""" -from __future__ import absolute_import, division, print_function -import itertools -import functools -import re -import types - -try: - from collections import OrderedDict -except ImportError: - from funcsigs.odict import OrderedDict - -from funcsigs.version import __version__ - -__all__ = ['BoundArguments', 'Parameter', 'Signature', 'signature'] - - -_WrapperDescriptor = type(type.__call__) -_MethodWrapper = type(all.__call__) - -_NonUserDefinedCallables = (_WrapperDescriptor, - _MethodWrapper, - types.BuiltinFunctionType) - - -def formatannotation(annotation, base_module=None): - if isinstance(annotation, type): - if annotation.__module__ in ('builtins', '__builtin__', base_module): - return annotation.__name__ - return annotation.__module__+'.'+annotation.__name__ - return repr(annotation) - - -def _get_user_defined_method(cls, method_name, *nested): - try: - if cls is type: - return - meth = getattr(cls, method_name) - for name in nested: - meth = getattr(meth, name, meth) - except AttributeError: - return - else: - if not isinstance(meth, _NonUserDefinedCallables): - # Once '__signature__' will be added to 'C'-level - # callables, this check won't be necessary - return meth - - -def signature(obj): - '''Get a signature object for the passed callable.''' - - if not callable(obj): - raise TypeError('{0!r} is not a callable object'.format(obj)) - - if isinstance(obj, types.MethodType): - sig = signature(obj.__func__) - if obj.__self__ is None: - # Unbound method: the first parameter becomes positional-only - if sig.parameters: - first = sig.parameters.values()[0].replace( - kind=_POSITIONAL_ONLY) - return sig.replace( - parameters=(first,) + tuple(sig.parameters.values())[1:]) - else: - return sig - else: - # In this case we skip the first parameter of the underlying - # function (usually `self` or `cls`). - return sig.replace(parameters=tuple(sig.parameters.values())[1:]) - - try: - sig = obj.__signature__ - except AttributeError: - pass - else: - if sig is not None: - return sig - - try: - # Was this function wrapped by a decorator? - wrapped = obj.__wrapped__ - except AttributeError: - pass - else: - return signature(wrapped) - - if isinstance(obj, types.FunctionType): - return Signature.from_function(obj) - - if isinstance(obj, functools.partial): - sig = signature(obj.func) - - new_params = OrderedDict(sig.parameters.items()) - - partial_args = obj.args or () - partial_keywords = obj.keywords or {} - try: - ba = sig.bind_partial(*partial_args, **partial_keywords) - except TypeError as ex: - msg = 'partial object {0!r} has incorrect arguments'.format(obj) - raise ValueError(msg) - - for arg_name, arg_value in ba.arguments.items(): - param = new_params[arg_name] - if arg_name in partial_keywords: - # We set a new default value, because the following code - # is correct: - # - # >>> def foo(a): print(a) - # >>> print(partial(partial(foo, a=10), a=20)()) - # 20 - # >>> print(partial(partial(foo, a=10), a=20)(a=30)) - # 30 - # - # So, with 'partial' objects, passing a keyword argument is - # like setting a new default value for the corresponding - # parameter - # - # We also mark this parameter with '_partial_kwarg' - # flag. Later, in '_bind', the 'default' value of this - # parameter will be added to 'kwargs', to simulate - # the 'functools.partial' real call. - new_params[arg_name] = param.replace(default=arg_value, - _partial_kwarg=True) - - elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) and - not param._partial_kwarg): - new_params.pop(arg_name) - - return sig.replace(parameters=new_params.values()) - - sig = None - if isinstance(obj, type): - # obj is a class or a metaclass - - # First, let's see if it has an overloaded __call__ defined - # in its metaclass - call = _get_user_defined_method(type(obj), '__call__') - if call is not None: - sig = signature(call) - else: - # Now we check if the 'obj' class has a '__new__' method - new = _get_user_defined_method(obj, '__new__') - if new is not None: - sig = signature(new) - else: - # Finally, we should have at least __init__ implemented - init = _get_user_defined_method(obj, '__init__') - if init is not None: - sig = signature(init) - elif not isinstance(obj, _NonUserDefinedCallables): - # An object with __call__ - # We also check that the 'obj' is not an instance of - # _WrapperDescriptor or _MethodWrapper to avoid - # infinite recursion (and even potential segfault) - call = _get_user_defined_method(type(obj), '__call__', 'im_func') - if call is not None: - sig = signature(call) - - if sig is not None: - # For classes and objects we skip the first parameter of their - # __call__, __new__, or __init__ methods - return sig.replace(parameters=tuple(sig.parameters.values())[1:]) - - if isinstance(obj, types.BuiltinFunctionType): - # Raise a nicer error message for builtins - msg = 'no signature found for builtin function {0!r}'.format(obj) - raise ValueError(msg) - - raise ValueError('callable {0!r} is not supported by signature'.format(obj)) - - -class _void(object): - '''A private marker - used in Parameter & Signature''' - - -class _empty(object): - pass - - -class _ParameterKind(int): - def __new__(self, *args, **kwargs): - obj = int.__new__(self, *args) - obj._name = kwargs['name'] - return obj - - def __str__(self): - return self._name - - def __repr__(self): - return '<_ParameterKind: {0!r}>'.format(self._name) - - -_POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY') -_POSITIONAL_OR_KEYWORD = _ParameterKind(1, name='POSITIONAL_OR_KEYWORD') -_VAR_POSITIONAL = _ParameterKind(2, name='VAR_POSITIONAL') -_KEYWORD_ONLY = _ParameterKind(3, name='KEYWORD_ONLY') -_VAR_KEYWORD = _ParameterKind(4, name='VAR_KEYWORD') - - -class Parameter(object): - '''Represents a parameter in a function signature. - - Has the following public attributes: - - * name : str - The name of the parameter as a string. - * default : object - The default value for the parameter if specified. If the - parameter has no default value, this attribute is not set. - * annotation - The annotation for the parameter if specified. If the - parameter has no annotation, this attribute is not set. - * kind : str - Describes how argument values are bound to the parameter. - Possible values: `Parameter.POSITIONAL_ONLY`, - `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`, - `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`. - ''' - - __slots__ = ('_name', '_kind', '_default', '_annotation', '_partial_kwarg') - - POSITIONAL_ONLY = _POSITIONAL_ONLY - POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD - VAR_POSITIONAL = _VAR_POSITIONAL - KEYWORD_ONLY = _KEYWORD_ONLY - VAR_KEYWORD = _VAR_KEYWORD - - empty = _empty - - def __init__(self, name, kind, default=_empty, annotation=_empty, - _partial_kwarg=False): - - if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD, - _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD): - raise ValueError("invalid value for 'Parameter.kind' attribute") - self._kind = kind - - if default is not _empty: - if kind in (_VAR_POSITIONAL, _VAR_KEYWORD): - msg = '{0} parameters cannot have default values'.format(kind) - raise ValueError(msg) - self._default = default - self._annotation = annotation - - if name is None: - if kind != _POSITIONAL_ONLY: - raise ValueError("None is not a valid name for a " - "non-positional-only parameter") - self._name = name - else: - name = str(name) - if kind != _POSITIONAL_ONLY and not re.match(r'[a-z_]\w*$', name, re.I): - msg = '{0!r} is not a valid parameter name'.format(name) - raise ValueError(msg) - self._name = name - - self._partial_kwarg = _partial_kwarg - - @property - def name(self): - return self._name - - @property - def default(self): - return self._default - - @property - def annotation(self): - return self._annotation - - @property - def kind(self): - return self._kind - - def replace(self, name=_void, kind=_void, annotation=_void, - default=_void, _partial_kwarg=_void): - '''Creates a customized copy of the Parameter.''' - - if name is _void: - name = self._name - - if kind is _void: - kind = self._kind - - if annotation is _void: - annotation = self._annotation - - if default is _void: - default = self._default - - if _partial_kwarg is _void: - _partial_kwarg = self._partial_kwarg - - return type(self)(name, kind, default=default, annotation=annotation, - _partial_kwarg=_partial_kwarg) - - def __str__(self): - kind = self.kind - - formatted = self._name - if kind == _POSITIONAL_ONLY: - if formatted is None: - formatted = '' - formatted = '<{0}>'.format(formatted) - - # Add annotation and default value - if self._annotation is not _empty: - formatted = '{0}:{1}'.format(formatted, - formatannotation(self._annotation)) - - if self._default is not _empty: - formatted = '{0}={1}'.format(formatted, repr(self._default)) - - if kind == _VAR_POSITIONAL: - formatted = '*' + formatted - elif kind == _VAR_KEYWORD: - formatted = '**' + formatted - - return formatted - - def __repr__(self): - return '<{0} at {1:#x} {2!r}>'.format(self.__class__.__name__, - id(self), self.name) - - def __hash__(self): - msg = "unhashable type: '{0}'".format(self.__class__.__name__) - raise TypeError(msg) - - def __eq__(self, other): - return (issubclass(other.__class__, Parameter) and - self._name == other._name and - self._kind == other._kind and - self._default == other._default and - self._annotation == other._annotation) - - def __ne__(self, other): - return not self.__eq__(other) - - -class BoundArguments(object): - '''Result of `Signature.bind` call. Holds the mapping of arguments - to the function's parameters. - - Has the following public attributes: - - * arguments : OrderedDict - An ordered mutable mapping of parameters' names to arguments' values. - Does not contain arguments' default values. - * signature : Signature - The Signature object that created this instance. - * args : tuple - Tuple of positional arguments values. - * kwargs : dict - Dict of keyword arguments values. - ''' - - def __init__(self, signature, arguments): - self.arguments = arguments - self._signature = signature - - @property - def signature(self): - return self._signature - - @property - def args(self): - args = [] - for param_name, param in self._signature.parameters.items(): - if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or - param._partial_kwarg): - # Keyword arguments mapped by 'functools.partial' - # (Parameter._partial_kwarg is True) are mapped - # in 'BoundArguments.kwargs', along with VAR_KEYWORD & - # KEYWORD_ONLY - break - - try: - arg = self.arguments[param_name] - except KeyError: - # We're done here. Other arguments - # will be mapped in 'BoundArguments.kwargs' - break - else: - if param.kind == _VAR_POSITIONAL: - # *args - args.extend(arg) - else: - # plain argument - args.append(arg) - - return tuple(args) - - @property - def kwargs(self): - kwargs = {} - kwargs_started = False - for param_name, param in self._signature.parameters.items(): - if not kwargs_started: - if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or - param._partial_kwarg): - kwargs_started = True - else: - if param_name not in self.arguments: - kwargs_started = True - continue - - if not kwargs_started: - continue - - try: - arg = self.arguments[param_name] - except KeyError: - pass - else: - if param.kind == _VAR_KEYWORD: - # **kwargs - kwargs.update(arg) - else: - # plain keyword argument - kwargs[param_name] = arg - - return kwargs - - def __hash__(self): - msg = "unhashable type: '{0}'".format(self.__class__.__name__) - raise TypeError(msg) - - def __eq__(self, other): - return (issubclass(other.__class__, BoundArguments) and - self.signature == other.signature and - self.arguments == other.arguments) - - def __ne__(self, other): - return not self.__eq__(other) - - -class Signature(object): - '''A Signature object represents the overall signature of a function. - It stores a Parameter object for each parameter accepted by the - function, as well as information specific to the function itself. - - A Signature object has the following public attributes and methods: - - * parameters : OrderedDict - An ordered mapping of parameters' names to the corresponding - Parameter objects (keyword-only arguments are in the same order - as listed in `code.co_varnames`). - * return_annotation : object - The annotation for the return type of the function if specified. - If the function has no annotation for its return type, this - attribute is not set. - * bind(*args, **kwargs) -> BoundArguments - Creates a mapping from positional and keyword arguments to - parameters. - * bind_partial(*args, **kwargs) -> BoundArguments - Creates a partial mapping from positional and keyword arguments - to parameters (simulating 'functools.partial' behavior.) - ''' - - __slots__ = ('_return_annotation', '_parameters') - - _parameter_cls = Parameter - _bound_arguments_cls = BoundArguments - - empty = _empty - - def __init__(self, parameters=None, return_annotation=_empty, - __validate_parameters__=True): - '''Constructs Signature from the given list of Parameter - objects and 'return_annotation'. All arguments are optional. - ''' - - if parameters is None: - params = OrderedDict() - else: - if __validate_parameters__: - params = OrderedDict() - top_kind = _POSITIONAL_ONLY - - for idx, param in enumerate(parameters): - kind = param.kind - if kind < top_kind: - msg = 'wrong parameter order: {0} before {1}' - msg = msg.format(top_kind, param.kind) - raise ValueError(msg) - else: - top_kind = kind - - name = param.name - if name is None: - name = str(idx) - param = param.replace(name=name) - - if name in params: - msg = 'duplicate parameter name: {0!r}'.format(name) - raise ValueError(msg) - params[name] = param - else: - params = OrderedDict(((param.name, param) - for param in parameters)) - - self._parameters = params - self._return_annotation = return_annotation - - @classmethod - def from_function(cls, func): - '''Constructs Signature for the given python function''' - - if not isinstance(func, types.FunctionType): - raise TypeError('{0!r} is not a Python function'.format(func)) - - Parameter = cls._parameter_cls - - # Parameter information. - func_code = func.__code__ - pos_count = func_code.co_argcount - arg_names = func_code.co_varnames - positional = tuple(arg_names[:pos_count]) - keyword_only_count = getattr(func_code, 'co_kwonlyargcount', 0) - keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)] - annotations = getattr(func, '__annotations__', {}) - defaults = func.__defaults__ - kwdefaults = getattr(func, '__kwdefaults__', None) - - if defaults: - pos_default_count = len(defaults) - else: - pos_default_count = 0 - - parameters = [] - - # Non-keyword-only parameters w/o defaults. - non_default_count = pos_count - pos_default_count - for name in positional[:non_default_count]: - annotation = annotations.get(name, _empty) - parameters.append(Parameter(name, annotation=annotation, - kind=_POSITIONAL_OR_KEYWORD)) - - # ... w/ defaults. - for offset, name in enumerate(positional[non_default_count:]): - annotation = annotations.get(name, _empty) - parameters.append(Parameter(name, annotation=annotation, - kind=_POSITIONAL_OR_KEYWORD, - default=defaults[offset])) - - # *args - if func_code.co_flags & 0x04: - name = arg_names[pos_count + keyword_only_count] - annotation = annotations.get(name, _empty) - parameters.append(Parameter(name, annotation=annotation, - kind=_VAR_POSITIONAL)) - - # Keyword-only parameters. - for name in keyword_only: - default = _empty - if kwdefaults is not None: - default = kwdefaults.get(name, _empty) - - annotation = annotations.get(name, _empty) - parameters.append(Parameter(name, annotation=annotation, - kind=_KEYWORD_ONLY, - default=default)) - # **kwargs - if func_code.co_flags & 0x08: - index = pos_count + keyword_only_count - if func_code.co_flags & 0x04: - index += 1 - - name = arg_names[index] - annotation = annotations.get(name, _empty) - parameters.append(Parameter(name, annotation=annotation, - kind=_VAR_KEYWORD)) - - return cls(parameters, - return_annotation=annotations.get('return', _empty), - __validate_parameters__=False) - - @property - def parameters(self): - try: - return types.MappingProxyType(self._parameters) - except AttributeError: - return OrderedDict(self._parameters.items()) - - @property - def return_annotation(self): - return self._return_annotation - - def replace(self, parameters=_void, return_annotation=_void): - '''Creates a customized copy of the Signature. - Pass 'parameters' and/or 'return_annotation' arguments - to override them in the new copy. - ''' - - if parameters is _void: - parameters = self.parameters.values() - - if return_annotation is _void: - return_annotation = self._return_annotation - - return type(self)(parameters, - return_annotation=return_annotation) - - def __hash__(self): - msg = "unhashable type: '{0}'".format(self.__class__.__name__) - raise TypeError(msg) - - def __eq__(self, other): - if (not issubclass(type(other), Signature) or - self.return_annotation != other.return_annotation or - len(self.parameters) != len(other.parameters)): - return False - - other_positions = dict((param, idx) - for idx, param in enumerate(other.parameters.keys())) - - for idx, (param_name, param) in enumerate(self.parameters.items()): - if param.kind == _KEYWORD_ONLY: - try: - other_param = other.parameters[param_name] - except KeyError: - return False - else: - if param != other_param: - return False - else: - try: - other_idx = other_positions[param_name] - except KeyError: - return False - else: - if (idx != other_idx or - param != other.parameters[param_name]): - return False - - return True - - def __ne__(self, other): - return not self.__eq__(other) - - def _bind(self, args, kwargs, partial=False): - '''Private method. Don't use directly.''' - - arguments = OrderedDict() - - parameters = iter(self.parameters.values()) - parameters_ex = () - arg_vals = iter(args) - - if partial: - # Support for binding arguments to 'functools.partial' objects. - # See 'functools.partial' case in 'signature()' implementation - # for details. - for param_name, param in self.parameters.items(): - if (param._partial_kwarg and param_name not in kwargs): - # Simulating 'functools.partial' behavior - kwargs[param_name] = param.default - - while True: - # Let's iterate through the positional arguments and corresponding - # parameters - try: - arg_val = next(arg_vals) - except StopIteration: - # No more positional arguments - try: - param = next(parameters) - except StopIteration: - # No more parameters. That's it. Just need to check that - # we have no `kwargs` after this while loop - break - else: - if param.kind == _VAR_POSITIONAL: - # That's OK, just empty *args. Let's start parsing - # kwargs - break - elif param.name in kwargs: - if param.kind == _POSITIONAL_ONLY: - msg = '{arg!r} parameter is positional only, ' \ - 'but was passed as a keyword' - msg = msg.format(arg=param.name) - raise TypeError(msg) - parameters_ex = (param,) - break - elif (param.kind == _VAR_KEYWORD or - param.default is not _empty): - # That's fine too - we have a default value for this - # parameter. So, lets start parsing `kwargs`, starting - # with the current parameter - parameters_ex = (param,) - break - else: - if partial: - parameters_ex = (param,) - break - else: - msg = '{arg!r} parameter lacking default value' - msg = msg.format(arg=param.name) - raise TypeError(msg) - else: - # We have a positional argument to process - try: - param = next(parameters) - except StopIteration: - raise TypeError('too many positional arguments') - else: - if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY): - # Looks like we have no parameter for this positional - # argument - raise TypeError('too many positional arguments') - - if param.kind == _VAR_POSITIONAL: - # We have an '*args'-like argument, let's fill it with - # all positional arguments we have left and move on to - # the next phase - values = [arg_val] - values.extend(arg_vals) - arguments[param.name] = tuple(values) - break - - if param.name in kwargs: - raise TypeError('multiple values for argument ' - '{arg!r}'.format(arg=param.name)) - - arguments[param.name] = arg_val - - # Now, we iterate through the remaining parameters to process - # keyword arguments - kwargs_param = None - for param in itertools.chain(parameters_ex, parameters): - if param.kind == _POSITIONAL_ONLY: - # This should never happen in case of a properly built - # Signature object (but let's have this check here - # to ensure correct behaviour just in case) - raise TypeError('{arg!r} parameter is positional only, ' - 'but was passed as a keyword'. \ - format(arg=param.name)) - - if param.kind == _VAR_KEYWORD: - # Memorize that we have a '**kwargs'-like parameter - kwargs_param = param - continue - - param_name = param.name - try: - arg_val = kwargs.pop(param_name) - except KeyError: - # We have no value for this parameter. It's fine though, - # if it has a default value, or it is an '*args'-like - # parameter, left alone by the processing of positional - # arguments. - if (not partial and param.kind != _VAR_POSITIONAL and - param.default is _empty): - raise TypeError('{arg!r} parameter lacking default value'. \ - format(arg=param_name)) - - else: - arguments[param_name] = arg_val - - if kwargs: - if kwargs_param is not None: - # Process our '**kwargs'-like parameter - arguments[kwargs_param.name] = kwargs - else: - raise TypeError('too many keyword arguments') - - return self._bound_arguments_cls(self, arguments) - - def bind(self, *args, **kwargs): - '''Get a BoundArguments object, that maps the passed `args` - and `kwargs` to the function's signature. Raises `TypeError` - if the passed arguments can not be bound. - ''' - return self._bind(args, kwargs) - - def bind_partial(self, *args, **kwargs): - '''Get a BoundArguments object, that partially maps the - passed `args` and `kwargs` to the function's signature. - Raises `TypeError` if the passed arguments can not be bound. - ''' - return self._bind(args, kwargs, partial=True) - - def __str__(self): - result = [] - render_kw_only_separator = True - for idx, param in enumerate(self.parameters.values()): - formatted = str(param) - - kind = param.kind - if kind == _VAR_POSITIONAL: - # OK, we have an '*args'-like parameter, so we won't need - # a '*' to separate keyword-only arguments - render_kw_only_separator = False - elif kind == _KEYWORD_ONLY and render_kw_only_separator: - # We have a keyword-only parameter to render and we haven't - # rendered an '*args'-like parameter before, so add a '*' - # separator to the parameters list ("foo(arg1, *, arg2)" case) - result.append('*') - # This condition should be only triggered once, so - # reset the flag - render_kw_only_separator = False - - result.append(formatted) - - rendered = '({0})'.format(', '.join(result)) - - if self.return_annotation is not _empty: - anno = formatannotation(self.return_annotation) - rendered += ' -> {0}'.format(anno) - - return rendered diff --git a/funcsigs/odict.py b/funcsigs/odict.py deleted file mode 100644 index 6221e97..0000000 --- a/funcsigs/odict.py +++ /dev/null @@ -1,261 +0,0 @@ -# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. -# Passes Python2.7's test suite and incorporates all the latest updates. -# Copyright 2009 Raymond Hettinger -# http://code.activestate.com/recipes/576693/ -"Ordered dictionary" - -try: - from thread import get_ident as _get_ident -except ImportError: - from dummy_thread import get_ident as _get_ident - -try: - from _abcoll import KeysView, ValuesView, ItemsView -except ImportError: - pass - - -class OrderedDict(dict): - 'Dictionary that remembers insertion order' - # An inherited dict maps keys to values. - # The inherited dict provides __getitem__, __len__, __contains__, and get. - # The remaining methods are order-aware. - # Big-O running times for all methods are the same as for regular dictionaries. - - # The internal self.__map dictionary maps keys to links in a doubly linked list. - # The circular doubly linked list starts and ends with a sentinel element. - # The sentinel element never gets deleted (this simplifies the algorithm). - # Each link is stored as a list of length three: [PREV, NEXT, KEY]. - - def __init__(self, *args, **kwds): - '''Initialize an ordered dictionary. Signature is the same as for - regular dictionaries, but keyword arguments are not recommended - because their insertion order is arbitrary. - - ''' - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - try: - self.__root - except AttributeError: - self.__root = root = [] # sentinel node - root[:] = [root, root, None] - self.__map = {} - self.__update(*args, **kwds) - - def __setitem__(self, key, value, dict_setitem=dict.__setitem__): - 'od.__setitem__(i, y) <==> od[i]=y' - # Setting a new item creates a new link which goes at the end of the linked - # list, and the inherited dictionary is updated with the new key/value pair. - if key not in self: - root = self.__root - last = root[0] - last[1] = root[0] = self.__map[key] = [last, root, key] - dict_setitem(self, key, value) - - def __delitem__(self, key, dict_delitem=dict.__delitem__): - 'od.__delitem__(y) <==> del od[y]' - # Deleting an existing item uses self.__map to find the link which is - # then removed by updating the links in the predecessor and successor nodes. - dict_delitem(self, key) - link_prev, link_next, key = self.__map.pop(key) - link_prev[1] = link_next - link_next[0] = link_prev - - def __iter__(self): - 'od.__iter__() <==> iter(od)' - root = self.__root - curr = root[1] - while curr is not root: - yield curr[2] - curr = curr[1] - - def __reversed__(self): - 'od.__reversed__() <==> reversed(od)' - root = self.__root - curr = root[0] - while curr is not root: - yield curr[2] - curr = curr[0] - - def clear(self): - 'od.clear() -> None. Remove all items from od.' - try: - for node in self.__map.itervalues(): - del node[:] - root = self.__root - root[:] = [root, root, None] - self.__map.clear() - except AttributeError: - pass - dict.clear(self) - - def popitem(self, last=True): - '''od.popitem() -> (k, v), return and remove a (key, value) pair. - Pairs are returned in LIFO order if last is true or FIFO order if false. - - ''' - if not self: - raise KeyError('dictionary is empty') - root = self.__root - if last: - link = root[0] - link_prev = link[0] - link_prev[1] = root - root[0] = link_prev - else: - link = root[1] - link_next = link[1] - root[1] = link_next - link_next[0] = root - key = link[2] - del self.__map[key] - value = dict.pop(self, key) - return key, value - - # -- the following methods do not depend on the internal structure -- - - def keys(self): - 'od.keys() -> list of keys in od' - return list(self) - - def values(self): - 'od.values() -> list of values in od' - return [self[key] for key in self] - - def items(self): - 'od.items() -> list of (key, value) pairs in od' - return [(key, self[key]) for key in self] - - def iterkeys(self): - 'od.iterkeys() -> an iterator over the keys in od' - return iter(self) - - def itervalues(self): - 'od.itervalues -> an iterator over the values in od' - for k in self: - yield self[k] - - def iteritems(self): - 'od.iteritems -> an iterator over the (key, value) items in od' - for k in self: - yield (k, self[k]) - - def update(*args, **kwds): - '''od.update(E, **F) -> None. Update od from dict/iterable E and F. - - If E is a dict instance, does: for k in E: od[k] = E[k] - If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] - Or if E is an iterable of items, does: for k, v in E: od[k] = v - In either case, this is followed by: for k, v in F.items(): od[k] = v - - ''' - if len(args) > 2: - raise TypeError('update() takes at most 2 positional ' - 'arguments (%d given)' % (len(args),)) - elif not args: - raise TypeError('update() takes at least 1 argument (0 given)') - self = args[0] - # Make progressively weaker assumptions about "other" - other = () - if len(args) == 2: - other = args[1] - if isinstance(other, dict): - for key in other: - self[key] = other[key] - elif hasattr(other, 'keys'): - for key in other.keys(): - self[key] = other[key] - else: - for key, value in other: - self[key] = value - for key, value in kwds.items(): - self[key] = value - - __update = update # let subclasses override update without breaking __init__ - - __marker = object() - - def pop(self, key, default=__marker): - '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. - If key is not found, d is returned if given, otherwise KeyError is raised. - - ''' - if key in self: - result = self[key] - del self[key] - return result - if default is self.__marker: - raise KeyError(key) - return default - - def setdefault(self, key, default=None): - 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' - if key in self: - return self[key] - self[key] = default - return default - - def __repr__(self, _repr_running={}): - 'od.__repr__() <==> repr(od)' - call_key = id(self), _get_ident() - if call_key in _repr_running: - return '...' - _repr_running[call_key] = 1 - try: - if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, self.items()) - finally: - del _repr_running[call_key] - - def __reduce__(self): - 'Return state information for pickling' - items = [[k, self[k]] for k in self] - inst_dict = vars(self).copy() - for k in vars(OrderedDict()): - inst_dict.pop(k, None) - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - - def copy(self): - 'od.copy() -> a shallow copy of od' - return self.__class__(self) - - @classmethod - def fromkeys(cls, iterable, value=None): - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S - and values equal to v (which defaults to None). - - ''' - d = cls() - for key in iterable: - d[key] = value - return d - - def __eq__(self, other): - '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive - while comparison to a regular mapping is order-insensitive. - - ''' - if isinstance(other, OrderedDict): - return len(self)==len(other) and self.items() == other.items() - return dict.__eq__(self, other) - - def __ne__(self, other): - return not self == other - - # -- the following methods are only used in Python 2.7 -- - - def viewkeys(self): - "od.viewkeys() -> a set-like object providing a view on od's keys" - return KeysView(self) - - def viewvalues(self): - "od.viewvalues() -> an object providing a view on od's values" - return ValuesView(self) - - def viewitems(self): - "od.viewitems() -> a set-like object providing a view on od's items" - return ItemsView(self) diff --git a/funcsigs/version.py b/funcsigs/version.py deleted file mode 100644 index 896a370..0000000 --- a/funcsigs/version.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "0.4" diff --git a/requirements/development.txt b/requirements/development.txt deleted file mode 100644 index ecafb0a..0000000 --- a/requirements/development.txt +++ /dev/null @@ -1,6 +0,0 @@ -coverage -coveralls -pip -flake8 -sphinx -wheel diff --git a/requirements/production.txt b/requirements/production.txt deleted file mode 100644 index e69de29..0000000 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 5e40900..0000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 98b0912..0000000 --- a/setup.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python -from setuptools import setup -import re -import sys - -def load_version(filename='funcsigs/version.py'): - "Parse a __version__ number from a source file" - with open(filename) as source: - text = source.read() - match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", text) - if not match: - msg = "Unable to find version number in {}".format(filename) - raise RuntimeError(msg) - version = match.group(1) - return version - -def load_rst(filename='docs/source/guide_content.rst'): - "Purge refs directives from restructured text" - with open(filename) as source: - text = source.read() - doc = re.sub(r':\w+:`~?([a-zA-Z._()]+)`', r'*\1*', text) - return doc - -setup( - name="funcsigs", - version=load_version(), - packages=['funcsigs'], - zip_safe=False, - author="Aaron Iles", - author_email="aaron.iles@gmail.com", - url="http://funcsigs.readthedocs.org", - description="Python function signatures from PEP362 for Python 2.6, 2.7 and 3.2+", - long_description=open('README.rst').read(), - # long_description=load_rst(), - license="ASL", - install_requires = [], - classifiers = [ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Topic :: Software Development :: Libraries :: Python Modules' - ], - tests_require = [] if sys.version_info[0] > 2 else ['unittest2'], - test_suite = "tests" if sys.version_info[0] > 2 else 'unittest2.collector' -) diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/test_formatannotation.py b/tests/test_formatannotation.py deleted file mode 100644 index fd7a887..0000000 --- a/tests/test_formatannotation.py +++ /dev/null @@ -1,27 +0,0 @@ -try: - # python 2.x - import unittest2 as unittest -except ImportError: - # python 3.x - import unittest - -import funcsigs - - -class TestFormatAnnotation(unittest.TestCase): - def test_string (self): - self.assertEqual(funcsigs.formatannotation("annotation"), - "'annotation'") - - def test_builtin_type (self): - self.assertEqual(funcsigs.formatannotation(int), - "int") - - def test_user_type (self): - class dummy (object): pass - self.assertEqual(funcsigs.formatannotation(dummy), - "tests.test_formatannotation.dummy") - - -if __name__ == "__main__": - unittest.begin() diff --git a/tests/test_funcsigs.py b/tests/test_funcsigs.py deleted file mode 100644 index eecc0a8..0000000 --- a/tests/test_funcsigs.py +++ /dev/null @@ -1,93 +0,0 @@ -try: - # python 2.x - import unittest2 as unittest -except ImportError: - # python 3.x - import unittest - -import doctest -import sys - -import funcsigs as inspect - - -class TestFunctionSignatures(unittest.TestCase): - - @staticmethod - def signature(func): - sig = inspect.signature(func) - return (tuple((param.name, - (Ellipsis if param.default is param.empty else param.default), - (Ellipsis if param.annotation is param.empty - else param.annotation), - str(param.kind).lower()) - for param in sig.parameters.values()), - (Ellipsis if sig.return_annotation is sig.empty - else sig.return_annotation)) - - def test_zero_arguments(self): - def test(): - pass - self.assertEqual(self.signature(test), - ((), Ellipsis)) - - def test_single_positional_argument(self): - def test(a): - pass - self.assertEqual(self.signature(test), - (((('a', Ellipsis, Ellipsis, "positional_or_keyword")),), Ellipsis)) - - def test_single_keyword_argument(self): - def test(a=None): - pass - self.assertEqual(self.signature(test), - (((('a', None, Ellipsis, "positional_or_keyword")),), Ellipsis)) - - def test_var_args(self): - def test(*args): - pass - self.assertEqual(self.signature(test), - (((('args', Ellipsis, Ellipsis, "var_positional")),), Ellipsis)) - - def test_keywords_args(self): - def test(**kwargs): - pass - self.assertEqual(self.signature(test), - (((('kwargs', Ellipsis, Ellipsis, "var_keyword")),), Ellipsis)) - - def test_multiple_arguments(self): - def test(a, b=None, *args, **kwargs): - pass - self.assertEqual(self.signature(test), (( - ('a', Ellipsis, Ellipsis, "positional_or_keyword"), - ('b', None, Ellipsis, "positional_or_keyword"), - ('args', Ellipsis, Ellipsis, "var_positional"), - ('kwargs', Ellipsis, Ellipsis, "var_keyword"), - ), Ellipsis)) - - def test_has_version(self): - self.assertTrue(inspect.__version__) - - def test_readme(self): - doctest.testfile('../README.rst') - - def test_unbound_method(self): - if sys.version_info < (3,): - self_kind = "positional_only" - else: - self_kind = "positional_or_keyword" - class Test(object): - def method(self): - pass - def method_with_args(self, a): - pass - self.assertEqual(self.signature(Test.method), - (((('self', Ellipsis, Ellipsis, self_kind)),), Ellipsis)) - self.assertEqual(self.signature(Test.method_with_args), (( - ('self', Ellipsis, Ellipsis, self_kind), - ('a', Ellipsis, Ellipsis, "positional_or_keyword"), - ), Ellipsis)) - - -if __name__ == "__main__": - unittest.begin() diff --git a/tests/test_inspect.py b/tests/test_inspect.py deleted file mode 100644 index 323c323..0000000 --- a/tests/test_inspect.py +++ /dev/null @@ -1,1019 +0,0 @@ -# Copyright 2001-2013 Python Software Foundation; All Rights Reserved -from __future__ import absolute_import, division, print_function -import collections -import sys - -try: - import unittest2 as unittest -except ImportError: - import unittest - -import funcsigs as inspect - - -class TestSignatureObject(unittest.TestCase): - @staticmethod - def signature(func): - sig = inspect.signature(func) - return (tuple((param.name, - (Ellipsis if param.default is param.empty else param.default), - (Ellipsis if param.annotation is param.empty - else param.annotation), - str(param.kind).lower()) - for param in sig.parameters.values()), - (Ellipsis if sig.return_annotation is sig.empty - else sig.return_annotation)) - - def __init__(self, *args, **kwargs): - unittest.TestCase.__init__(self, *args, **kwargs) - if not hasattr(self, 'assertRaisesRegex'): - self.assertRaisesRegex = self.assertRaisesRegexp - - if sys.version_info[0] > 2: - exec(""" -def test_signature_object(self): - S = inspect.Signature - P = inspect.Parameter - - self.assertEqual(str(S()), '()') - - def test(po, pk, *args, ko, **kwargs): - pass - sig = inspect.signature(test) - po = sig.parameters['po'].replace(kind=P.POSITIONAL_ONLY) - pk = sig.parameters['pk'] - args = sig.parameters['args'] - ko = sig.parameters['ko'] - kwargs = sig.parameters['kwargs'] - - S((po, pk, args, ko, kwargs)) - - with self.assertRaisesRegex(ValueError, 'wrong parameter order'): - S((pk, po, args, ko, kwargs)) - - with self.assertRaisesRegex(ValueError, 'wrong parameter order'): - S((po, args, pk, ko, kwargs)) - - with self.assertRaisesRegex(ValueError, 'wrong parameter order'): - S((args, po, pk, ko, kwargs)) - - with self.assertRaisesRegex(ValueError, 'wrong parameter order'): - S((po, pk, args, kwargs, ko)) - - kwargs2 = kwargs.replace(name='args') - with self.assertRaisesRegex(ValueError, 'duplicate parameter name'): - S((po, pk, args, kwargs2, ko)) -""") - - def test_signature_immutability(self): - def test(a): - pass - sig = inspect.signature(test) - - with self.assertRaises(AttributeError): - sig.foo = 'bar' - - # Python2 does not have MappingProxyType class - if sys.version_info[:2] < (3, 3): - return - - with self.assertRaises(TypeError): - sig.parameters['a'] = None - - def test_signature_on_noarg(self): - def test(): - pass - self.assertEqual(self.signature(test), ((), Ellipsis)) - - if sys.version_info[0] > 2: - exec(""" -def test_signature_on_wargs(self): - def test(a, b:'foo') -> 123: - pass - self.assertEqual(self.signature(test), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), - ('b', Ellipsis, 'foo', "positional_or_keyword")), - 123)) -""") - - if sys.version_info[0] > 2: - exec(""" -def test_signature_on_wkwonly(self): - def test(*, a:float, b:str) -> int: - pass - self.assertEqual(self.signature(test), - ((('a', Ellipsis, float, "keyword_only"), - ('b', Ellipsis, str, "keyword_only")), - int)) -""") - - if sys.version_info[0] > 2: - exec(""" -def test_signature_on_complex_args(self): - def test(a, b:'foo'=10, *args:'bar', spam:'baz', ham=123, **kwargs:int): - pass - self.assertEqual(self.signature(test), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), - ('b', 10, 'foo', "positional_or_keyword"), - ('args', Ellipsis, 'bar', "var_positional"), - ('spam', Ellipsis, 'baz', "keyword_only"), - ('ham', 123, Ellipsis, "keyword_only"), - ('kwargs', Ellipsis, int, "var_keyword")), - Ellipsis)) -""") - - def test_signature_on_builtin_function(self): - with self.assertRaisesRegex(ValueError, 'not supported by signature'): - inspect.signature(type) - with self.assertRaisesRegex(ValueError, 'not supported by signature'): - # support for 'wrapper_descriptor' - inspect.signature(type.__call__) - if hasattr(sys, 'pypy_version_info'): - raise ValueError('not supported by signature') - with self.assertRaisesRegex(ValueError, 'not supported by signature'): - # support for 'method-wrapper' - inspect.signature(min.__call__) - if hasattr(sys, 'pypy_version_info'): - raise ValueError('not supported by signature') - with self.assertRaisesRegex(ValueError, - 'no signature found for builtin function'): - # support for 'method-wrapper' - inspect.signature(min) - - def test_signature_on_non_function(self): - with self.assertRaisesRegex(TypeError, 'is not a callable object'): - inspect.signature(42) - - with self.assertRaisesRegex(TypeError, 'is not a Python function'): - inspect.Signature.from_function(42) - - if sys.version_info[0] > 2: - exec(""" -def test_signature_on_method(self): - class Test: - def foo(self, arg1, arg2=1) -> int: - pass - - meth = Test().foo - - self.assertEqual(self.signature(meth), - ((('arg1', Ellipsis, Ellipsis, "positional_or_keyword"), - ('arg2', 1, Ellipsis, "positional_or_keyword")), - int)) -""") - - if sys.version_info[0] > 2: - exec(""" -def test_signature_on_classmethod(self): - class Test: - @classmethod - def foo(cls, arg1, *, arg2=1): - pass - - meth = Test().foo - self.assertEqual(self.signature(meth), - ((('arg1', Ellipsis, Ellipsis, "positional_or_keyword"), - ('arg2', 1, Ellipsis, "keyword_only")), - Ellipsis)) - - meth = Test.foo - self.assertEqual(self.signature(meth), - ((('arg1', Ellipsis, Ellipsis, "positional_or_keyword"), - ('arg2', 1, Ellipsis, "keyword_only")), - Ellipsis)) -""") - - if sys.version_info[0] > 2: - exec(""" -def test_signature_on_staticmethod(self): - class Test: - @staticmethod - def foo(cls, *, arg): - pass - - meth = Test().foo - self.assertEqual(self.signature(meth), - ((('cls', Ellipsis, Ellipsis, "positional_or_keyword"), - ('arg', Ellipsis, Ellipsis, "keyword_only")), - Ellipsis)) - - meth = Test.foo - self.assertEqual(self.signature(meth), - ((('cls', Ellipsis, Ellipsis, "positional_or_keyword"), - ('arg', Ellipsis, Ellipsis, "keyword_only")), - Ellipsis)) -""") - - if sys.version_info[0] > 2: - exec(""" -def test_signature_on_partial(self): - from functools import partial - - def test(): - pass - - self.assertEqual(self.signature(partial(test)), ((), Ellipsis)) - - with self.assertRaisesRegex(ValueError, "has incorrect arguments"): - inspect.signature(partial(test, 1)) - - with self.assertRaisesRegex(ValueError, "has incorrect arguments"): - inspect.signature(partial(test, a=1)) - - def test(a, b, *, c, d): - pass - - self.assertEqual(self.signature(partial(test)), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), - ('b', Ellipsis, Ellipsis, "positional_or_keyword"), - ('c', Ellipsis, Ellipsis, "keyword_only"), - ('d', Ellipsis, Ellipsis, "keyword_only")), - Ellipsis)) - - self.assertEqual(self.signature(partial(test, 1)), - ((('b', Ellipsis, Ellipsis, "positional_or_keyword"), - ('c', Ellipsis, Ellipsis, "keyword_only"), - ('d', Ellipsis, Ellipsis, "keyword_only")), - Ellipsis)) - - self.assertEqual(self.signature(partial(test, 1, c=2)), - ((('b', Ellipsis, Ellipsis, "positional_or_keyword"), - ('c', 2, Ellipsis, "keyword_only"), - ('d', Ellipsis, Ellipsis, "keyword_only")), - Ellipsis)) - - self.assertEqual(self.signature(partial(test, b=1, c=2)), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), - ('b', 1, Ellipsis, "positional_or_keyword"), - ('c', 2, Ellipsis, "keyword_only"), - ('d', Ellipsis, Ellipsis, "keyword_only")), - Ellipsis)) - - self.assertEqual(self.signature(partial(test, 0, b=1, c=2)), - ((('b', 1, Ellipsis, "positional_or_keyword"), - ('c', 2, Ellipsis, "keyword_only"), - ('d', Ellipsis, Ellipsis, "keyword_only"),), - Ellipsis)) - - def test(a, *args, b, **kwargs): - pass - - self.assertEqual(self.signature(partial(test, 1)), - ((('args', Ellipsis, Ellipsis, "var_positional"), - ('b', Ellipsis, Ellipsis, "keyword_only"), - ('kwargs', Ellipsis, Ellipsis, "var_keyword")), - Ellipsis)) - - self.assertEqual(self.signature(partial(test, 1, 2, 3)), - ((('args', Ellipsis, Ellipsis, "var_positional"), - ('b', Ellipsis, Ellipsis, "keyword_only"), - ('kwargs', Ellipsis, Ellipsis, "var_keyword")), - Ellipsis)) - - - self.assertEqual(self.signature(partial(test, 1, 2, 3, test=True)), - ((('args', Ellipsis, Ellipsis, "var_positional"), - ('b', Ellipsis, Ellipsis, "keyword_only"), - ('kwargs', Ellipsis, Ellipsis, "var_keyword")), - Ellipsis)) - - self.assertEqual(self.signature(partial(test, 1, 2, 3, test=1, b=0)), - ((('args', Ellipsis, Ellipsis, "var_positional"), - ('b', 0, Ellipsis, "keyword_only"), - ('kwargs', Ellipsis, Ellipsis, "var_keyword")), - Ellipsis)) - - self.assertEqual(self.signature(partial(test, b=0)), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), - ('args', Ellipsis, Ellipsis, "var_positional"), - ('b', 0, Ellipsis, "keyword_only"), - ('kwargs', Ellipsis, Ellipsis, "var_keyword")), - Ellipsis)) - - self.assertEqual(self.signature(partial(test, b=0, test=1)), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), - ('args', Ellipsis, Ellipsis, "var_positional"), - ('b', 0, Ellipsis, "keyword_only"), - ('kwargs', Ellipsis, Ellipsis, "var_keyword")), - Ellipsis)) - - def test(a, b, c:int) -> 42: - pass - - sig = test.__signature__ = inspect.signature(test) - - self.assertEqual(self.signature(partial(partial(test, 1))), - ((('b', Ellipsis, Ellipsis, "positional_or_keyword"), - ('c', Ellipsis, int, "positional_or_keyword")), - 42)) - - self.assertEqual(self.signature(partial(partial(test, 1), 2)), - ((('c', Ellipsis, int, "positional_or_keyword"),), - 42)) - - psig = inspect.signature(partial(partial(test, 1), 2)) - - def foo(a): - return a - _foo = partial(partial(foo, a=10), a=20) - self.assertEqual(self.signature(_foo), - ((('a', 20, Ellipsis, "positional_or_keyword"),), - Ellipsis)) - # check that we don't have any side-effects in signature(), - # and the partial object is still functioning - self.assertEqual(_foo(), 20) - - def foo(a, b, c): - return a, b, c - _foo = partial(partial(foo, 1, b=20), b=30) - self.assertEqual(self.signature(_foo), - ((('b', 30, Ellipsis, "positional_or_keyword"), - ('c', Ellipsis, Ellipsis, "positional_or_keyword")), - Ellipsis)) - self.assertEqual(_foo(c=10), (1, 30, 10)) - _foo = partial(_foo, 2) # now 'b' has two values - - # positional and keyword - with self.assertRaisesRegex(ValueError, "has incorrect arguments"): - inspect.signature(_foo) - - def foo(a, b, c, *, d): - return a, b, c, d - _foo = partial(partial(foo, d=20, c=20), b=10, d=30) - self.assertEqual(self.signature(_foo), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), - ('b', 10, Ellipsis, "positional_or_keyword"), - ('c', 20, Ellipsis, "positional_or_keyword"), - ('d', 30, Ellipsis, "keyword_only")), - Ellipsis)) - ba = inspect.signature(_foo).bind(a=200, b=11) - self.assertEqual(_foo(*ba.args, **ba.kwargs), (200, 11, 20, 30)) - - def foo(a=1, b=2, c=3): - return a, b, c - _foo = partial(foo, a=10, c=13) - ba = inspect.signature(_foo).bind(11) - self.assertEqual(_foo(*ba.args, **ba.kwargs), (11, 2, 13)) - ba = inspect.signature(_foo).bind(11, 12) - self.assertEqual(_foo(*ba.args, **ba.kwargs), (11, 12, 13)) - ba = inspect.signature(_foo).bind(11, b=12) - self.assertEqual(_foo(*ba.args, **ba.kwargs), (11, 12, 13)) - ba = inspect.signature(_foo).bind(b=12) - self.assertEqual(_foo(*ba.args, **ba.kwargs), (10, 12, 13)) - _foo = partial(_foo, b=10) - ba = inspect.signature(_foo).bind(12, 14) - self.assertEqual(_foo(*ba.args, **ba.kwargs), (12, 14, 13)) -""") - - if sys.version_info[0] > 2: - exec(""" -def test_signature_on_decorated(self): - import functools - - def decorator(func): - @functools.wraps(func) - def wrapper(*args, **kwargs) -> int: - return func(*args, **kwargs) - return wrapper - - class Foo: - @decorator - def bar(self, a, b): - pass - - self.assertEqual(self.signature(Foo.bar), - ((('self', Ellipsis, Ellipsis, "positional_or_keyword"), - ('a', Ellipsis, Ellipsis, "positional_or_keyword"), - ('b', Ellipsis, Ellipsis, "positional_or_keyword")), - Ellipsis)) - - self.assertEqual(self.signature(Foo().bar), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), - ('b', Ellipsis, Ellipsis, "positional_or_keyword")), - Ellipsis)) - - # Test that we handle method wrappers correctly - def decorator(func): - @functools.wraps(func) - def wrapper(*args, **kwargs) -> int: - return func(42, *args, **kwargs) - sig = inspect.signature(func) - new_params = tuple(sig.parameters.values())[1:] - wrapper.__signature__ = sig.replace(parameters=new_params) - return wrapper - - class Foo: - @decorator - def __call__(self, a, b): - pass - - self.assertEqual(self.signature(Foo.__call__), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), - ('b', Ellipsis, Ellipsis, "positional_or_keyword")), - Ellipsis)) - - self.assertEqual(self.signature(Foo().__call__), - ((('b', Ellipsis, Ellipsis, "positional_or_keyword"),), - Ellipsis)) -""") - - if sys.version_info[0] > 2: - exec(""" -def test_signature_on_class(self): - class C: - def __init__(self, a): - pass - - self.assertEqual(self.signature(C), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), - Ellipsis)) - - class CM(type): - def __call__(cls, a): - pass - class C(metaclass=CM): - def __init__(self, b): - pass - - self.assertEqual(self.signature(C), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), - Ellipsis)) - - class CM(type): - def __new__(mcls, name, bases, dct, *, foo=1): - return super().__new__(mcls, name, bases, dct) - class C(metaclass=CM): - def __init__(self, b): - pass - - self.assertEqual(self.signature(C), - ((('b', Ellipsis, Ellipsis, "positional_or_keyword"),), - Ellipsis)) - - self.assertEqual(self.signature(CM), - ((('name', Ellipsis, Ellipsis, "positional_or_keyword"), - ('bases', Ellipsis, Ellipsis, "positional_or_keyword"), - ('dct', Ellipsis, Ellipsis, "positional_or_keyword"), - ('foo', 1, Ellipsis, "keyword_only")), - Ellipsis)) - - class CMM(type): - def __new__(mcls, name, bases, dct, *, foo=1): - return super().__new__(mcls, name, bases, dct) - def __call__(cls, nm, bs, dt): - return type(nm, bs, dt) - class CM(type, metaclass=CMM): - def __new__(mcls, name, bases, dct, *, bar=2): - return super().__new__(mcls, name, bases, dct) - class C(metaclass=CM): - def __init__(self, b): - pass - - self.assertEqual(self.signature(CMM), - ((('name', Ellipsis, Ellipsis, "positional_or_keyword"), - ('bases', Ellipsis, Ellipsis, "positional_or_keyword"), - ('dct', Ellipsis, Ellipsis, "positional_or_keyword"), - ('foo', 1, Ellipsis, "keyword_only")), - Ellipsis)) - - self.assertEqual(self.signature(CM), - ((('nm', Ellipsis, Ellipsis, "positional_or_keyword"), - ('bs', Ellipsis, Ellipsis, "positional_or_keyword"), - ('dt', Ellipsis, Ellipsis, "positional_or_keyword")), - Ellipsis)) - - self.assertEqual(self.signature(C), - ((('b', Ellipsis, Ellipsis, "positional_or_keyword"),), - Ellipsis)) - - class CM(type): - def __init__(cls, name, bases, dct, *, bar=2): - return super().__init__(name, bases, dct) - class C(metaclass=CM): - def __init__(self, b): - pass - - self.assertEqual(self.signature(CM), - ((('name', Ellipsis, Ellipsis, "positional_or_keyword"), - ('bases', Ellipsis, Ellipsis, "positional_or_keyword"), - ('dct', Ellipsis, Ellipsis, "positional_or_keyword"), - ('bar', 2, Ellipsis, "keyword_only")), - Ellipsis)) -""") - - def test_signature_on_callable_objects(self): - class Foo(object): - def __call__(self, a): - pass - - self.assertEqual(self.signature(Foo()), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), - Ellipsis)) - - class Spam(object): - pass - with self.assertRaisesRegex(TypeError, "is not a callable object"): - inspect.signature(Spam()) - - class Bar(Spam, Foo): - pass - - self.assertEqual(self.signature(Bar()), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), - Ellipsis)) - - class ToFail(object): - __call__ = type - with self.assertRaisesRegex(ValueError, "not supported by signature"): - inspect.signature(ToFail()) - - if sys.version_info[0] < 3: - return - - class Wrapped(object): - pass - Wrapped.__wrapped__ = lambda a: None - self.assertEqual(self.signature(Wrapped), - ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), - Ellipsis)) - - def test_signature_on_lambdas(self): - self.assertEqual(self.signature((lambda a=10: a)), - ((('a', 10, Ellipsis, "positional_or_keyword"),), - Ellipsis)) - - if sys.version_info[0] > 2: - exec(""" -def test_signature_equality(self): - def foo(a, *, b:int) -> float: pass - self.assertNotEqual(inspect.signature(foo), 42) - - def bar(a, *, b:int) -> float: pass - self.assertEqual(inspect.signature(foo), inspect.signature(bar)) - - def bar(a, *, b:int) -> int: pass - self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) - - def bar(a, *, b:int): pass - self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) - - def bar(a, *, b:int=42) -> float: pass - self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) - - def bar(a, *, c) -> float: pass - self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) - - def bar(a, b:int) -> float: pass - self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) - def spam(b:int, a) -> float: pass - self.assertNotEqual(inspect.signature(spam), inspect.signature(bar)) - - def foo(*, a, b, c): pass - def bar(*, c, b, a): pass - self.assertEqual(inspect.signature(foo), inspect.signature(bar)) - - def foo(*, a=1, b, c): pass - def bar(*, c, b, a=1): pass - self.assertEqual(inspect.signature(foo), inspect.signature(bar)) - - def foo(pos, *, a=1, b, c): pass - def bar(pos, *, c, b, a=1): pass - self.assertEqual(inspect.signature(foo), inspect.signature(bar)) - - def foo(pos, *, a, b, c): pass - def bar(pos, *, c, b, a=1): pass - self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) - - def foo(pos, *args, a=42, b, c, **kwargs:int): pass - def bar(pos, *args, c, b, a=42, **kwargs:int): pass - self.assertEqual(inspect.signature(foo), inspect.signature(bar)) -""") - - def test_signature_unhashable(self): - def foo(a): pass - sig = inspect.signature(foo) - with self.assertRaisesRegex(TypeError, 'unhashable type'): - hash(sig) - - - if sys.version_info[0] > 2: - exec(""" -def test_signature_str(self): - def foo(a:int=1, *, b, c=None, **kwargs) -> 42: - pass - self.assertEqual(str(inspect.signature(foo)), - '(a:int=1, *, b, c=None, **kwargs) -> 42') - - def foo(a:int=1, *args, b, c=None, **kwargs) -> 42: - pass - self.assertEqual(str(inspect.signature(foo)), - '(a:int=1, *args, b, c=None, **kwargs) -> 42') - - def foo(): - pass - self.assertEqual(str(inspect.signature(foo)), '()') -""") - - if sys.version_info[0] > 2: - exec(""" -def test_signature_str_positional_only(self): - P = inspect.Parameter - - def test(a_po, *, b, **kwargs): - return a_po, kwargs - - sig = inspect.signature(test) - new_params = list(sig.parameters.values()) - new_params[0] = new_params[0].replace(kind=P.POSITIONAL_ONLY) - test.__signature__ = sig.replace(parameters=new_params) - - self.assertEqual(str(inspect.signature(test)), - '(, *, b, **kwargs)') - - sig = inspect.signature(test) - new_params = list(sig.parameters.values()) - new_params[0] = new_params[0].replace(name=None) - test.__signature__ = sig.replace(parameters=new_params) - self.assertEqual(str(inspect.signature(test)), - '(<0>, *, b, **kwargs)') -""") - - if sys.version_info[0] > 2: - exec(""" -def test_signature_replace_anno(self): - def test() -> 42: - pass - - sig = inspect.signature(test) - sig = sig.replace(return_annotation=None) - self.assertIs(sig.return_annotation, None) - sig = sig.replace(return_annotation=sig.empty) - self.assertIs(sig.return_annotation, sig.empty) - sig = sig.replace(return_annotation=42) - self.assertEqual(sig.return_annotation, 42) - self.assertEqual(sig, inspect.signature(test)) -""") - - -class TestParameterObject(unittest.TestCase): - - def __init__(self, *args, **kwargs): - unittest.TestCase.__init__(self, *args, **kwargs) - if not hasattr(self, 'assertRaisesRegex'): - self.assertRaisesRegex = self.assertRaisesRegexp - - def test_signature_parameter_kinds(self): - P = inspect.Parameter - self.assertTrue(P.POSITIONAL_ONLY < P.POSITIONAL_OR_KEYWORD < \ - P.VAR_POSITIONAL < P.KEYWORD_ONLY < P.VAR_KEYWORD) - - self.assertEqual(str(P.POSITIONAL_ONLY), 'POSITIONAL_ONLY') - self.assertTrue('POSITIONAL_ONLY' in repr(P.POSITIONAL_ONLY)) - - def test_signature_parameter_object(self): - p = inspect.Parameter('foo', default=10, - kind=inspect.Parameter.POSITIONAL_ONLY) - self.assertEqual(p.name, 'foo') - self.assertEqual(p.default, 10) - self.assertIs(p.annotation, p.empty) - self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) - - with self.assertRaisesRegex(ValueError, 'invalid value'): - inspect.Parameter('foo', default=10, kind='123') - - with self.assertRaisesRegex(ValueError, 'not a valid parameter name'): - inspect.Parameter('1', kind=inspect.Parameter.VAR_KEYWORD) - - with self.assertRaisesRegex(ValueError, - 'non-positional-only parameter'): - inspect.Parameter(None, kind=inspect.Parameter.VAR_KEYWORD) - - with self.assertRaisesRegex(ValueError, 'cannot have default values'): - inspect.Parameter('a', default=42, - kind=inspect.Parameter.VAR_KEYWORD) - - with self.assertRaisesRegex(ValueError, 'cannot have default values'): - inspect.Parameter('a', default=42, - kind=inspect.Parameter.VAR_POSITIONAL) - - p = inspect.Parameter('a', default=42, - kind=inspect.Parameter.POSITIONAL_OR_KEYWORD) - with self.assertRaisesRegex(ValueError, 'cannot have default values'): - p.replace(kind=inspect.Parameter.VAR_POSITIONAL) - - self.assertTrue(repr(p).startswith('') - - p = p.replace(name='1') - self.assertEqual(str(p), '<1>') - - def test_signature_parameter_immutability(self): - p = inspect.Parameter(None, kind=inspect.Parameter.POSITIONAL_ONLY) - - with self.assertRaises(AttributeError): - p.foo = 'bar' - - with self.assertRaises(AttributeError): - p.kind = 123 - - -class TestSignatureBind(unittest.TestCase): - @staticmethod - def call(func, *args, **kwargs): - sig = inspect.signature(func) - ba = sig.bind(*args, **kwargs) - return func(*ba.args, **ba.kwargs) - - def __init__(self, *args, **kwargs): - unittest.TestCase.__init__(self, *args, **kwargs) - if not hasattr(self, 'assertRaisesRegex'): - self.assertRaisesRegex = self.assertRaisesRegexp - - def test_signature_bind_empty(self): - def test(): - return 42 - - self.assertEqual(self.call(test), 42) - with self.assertRaisesRegex(TypeError, 'too many positional arguments'): - self.call(test, 1) - with self.assertRaisesRegex(TypeError, 'too many positional arguments'): - self.call(test, 1, spam=10) - with self.assertRaisesRegex(TypeError, 'too many keyword arguments'): - self.call(test, spam=1) - - def test_signature_bind_var(self): - def test(*args, **kwargs): - return args, kwargs - - self.assertEqual(self.call(test), ((), {})) - self.assertEqual(self.call(test, 1), ((1,), {})) - self.assertEqual(self.call(test, 1, 2), ((1, 2), {})) - self.assertEqual(self.call(test, foo='bar'), ((), {'foo': 'bar'})) - self.assertEqual(self.call(test, 1, foo='bar'), ((1,), {'foo': 'bar'})) - self.assertEqual(self.call(test, args=10), ((), {'args': 10})) - self.assertEqual(self.call(test, 1, 2, foo='bar'), - ((1, 2), {'foo': 'bar'})) - - def test_signature_bind_just_args(self): - def test(a, b, c): - return a, b, c - - self.assertEqual(self.call(test, 1, 2, 3), (1, 2, 3)) - - with self.assertRaisesRegex(TypeError, 'too many positional arguments'): - self.call(test, 1, 2, 3, 4) - - with self.assertRaisesRegex(TypeError, "'b' parameter lacking default"): - self.call(test, 1) - - with self.assertRaisesRegex(TypeError, "'a' parameter lacking default"): - self.call(test) - - def test(a, b, c=10): - return a, b, c - self.assertEqual(self.call(test, 1, 2, 3), (1, 2, 3)) - self.assertEqual(self.call(test, 1, 2), (1, 2, 10)) - - def test(a=1, b=2, c=3): - return a, b, c - self.assertEqual(self.call(test, a=10, c=13), (10, 2, 13)) - self.assertEqual(self.call(test, a=10), (10, 2, 3)) - self.assertEqual(self.call(test, b=10), (1, 10, 3)) - - def test_signature_bind_varargs_order(self): - def test(*args): - return args - - self.assertEqual(self.call(test), ()) - self.assertEqual(self.call(test, 1, 2, 3), (1, 2, 3)) - - def test_signature_bind_args_and_varargs(self): - def test(a, b, c=3, *args): - return a, b, c, args - - self.assertEqual(self.call(test, 1, 2, 3, 4, 5), (1, 2, 3, (4, 5))) - self.assertEqual(self.call(test, 1, 2), (1, 2, 3, ())) - self.assertEqual(self.call(test, b=1, a=2), (2, 1, 3, ())) - self.assertEqual(self.call(test, 1, b=2), (1, 2, 3, ())) - - with self.assertRaisesRegex(TypeError, - "multiple values for argument 'c'"): - self.call(test, 1, 2, 3, c=4) - - def test_signature_bind_just_kwargs(self): - def test(**kwargs): - return kwargs - - self.assertEqual(self.call(test), {}) - self.assertEqual(self.call(test, foo='bar', spam='ham'), - {'foo': 'bar', 'spam': 'ham'}) - - def test_signature_bind_args_and_kwargs(self): - def test(a, b, c=3, **kwargs): - return a, b, c, kwargs - - self.assertEqual(self.call(test, 1, 2), (1, 2, 3, {})) - self.assertEqual(self.call(test, 1, 2, foo='bar', spam='ham'), - (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) - self.assertEqual(self.call(test, b=2, a=1, foo='bar', spam='ham'), - (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) - self.assertEqual(self.call(test, a=1, b=2, foo='bar', spam='ham'), - (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) - self.assertEqual(self.call(test, 1, b=2, foo='bar', spam='ham'), - (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) - self.assertEqual(self.call(test, 1, b=2, c=4, foo='bar', spam='ham'), - (1, 2, 4, {'foo': 'bar', 'spam': 'ham'})) - self.assertEqual(self.call(test, 1, 2, 4, foo='bar'), - (1, 2, 4, {'foo': 'bar'})) - self.assertEqual(self.call(test, c=5, a=4, b=3), - (4, 3, 5, {})) - - if sys.version_info[0] > 2: - exec(""" -def test_signature_bind_kwonly(self): - def test(*, foo): - return foo - with self.assertRaisesRegex(TypeError, - 'too many positional arguments'): - self.call(test, 1) - self.assertEqual(self.call(test, foo=1), 1) - - def test(a, *, foo=1, bar): - return foo - with self.assertRaisesRegex(TypeError, - "'bar' parameter lacking default value"): - self.call(test, 1) - - def test(foo, *, bar): - return foo, bar - self.assertEqual(self.call(test, 1, bar=2), (1, 2)) - self.assertEqual(self.call(test, bar=2, foo=1), (1, 2)) - - with self.assertRaisesRegex(TypeError, - 'too many keyword arguments'): - self.call(test, bar=2, foo=1, spam=10) - - with self.assertRaisesRegex(TypeError, - 'too many positional arguments'): - self.call(test, 1, 2) - - with self.assertRaisesRegex(TypeError, - 'too many positional arguments'): - self.call(test, 1, 2, bar=2) - - with self.assertRaisesRegex(TypeError, - 'too many keyword arguments'): - self.call(test, 1, bar=2, spam='ham') - - with self.assertRaisesRegex(TypeError, - "'bar' parameter lacking default value"): - self.call(test, 1) - - def test(foo, *, bar, **bin): - return foo, bar, bin - self.assertEqual(self.call(test, 1, bar=2), (1, 2, {})) - self.assertEqual(self.call(test, foo=1, bar=2), (1, 2, {})) - self.assertEqual(self.call(test, 1, bar=2, spam='ham'), - (1, 2, {'spam': 'ham'})) - self.assertEqual(self.call(test, spam='ham', foo=1, bar=2), - (1, 2, {'spam': 'ham'})) - with self.assertRaisesRegex(TypeError, - "'foo' parameter lacking default value"): - self.call(test, spam='ham', bar=2) - self.assertEqual(self.call(test, 1, bar=2, bin=1, spam=10), - (1, 2, {'bin': 1, 'spam': 10})) -""") -# - if sys.version_info[0] > 2: - exec(""" -def test_signature_bind_arguments(self): - def test(a, *args, b, z=100, **kwargs): - pass - sig = inspect.signature(test) - ba = sig.bind(10, 20, b=30, c=40, args=50, kwargs=60) - # we won't have 'z' argument in the bound arguments object, as we didn't - # pass it to the 'bind' - self.assertEqual(tuple(ba.arguments.items()), - (('a', 10), ('args', (20,)), ('b', 30), - ('kwargs', {'c': 40, 'args': 50, 'kwargs': 60}))) - self.assertEqual(ba.kwargs, - {'b': 30, 'c': 40, 'args': 50, 'kwargs': 60}) - self.assertEqual(ba.args, (10, 20)) -""") -# - if sys.version_info[0] > 2: - exec(""" -def test_signature_bind_positional_only(self): - P = inspect.Parameter - - def test(a_po, b_po, c_po=3, foo=42, *, bar=50, **kwargs): - return a_po, b_po, c_po, foo, bar, kwargs - - sig = inspect.signature(test) - new_params = collections.OrderedDict(tuple(sig.parameters.items())) - for name in ('a_po', 'b_po', 'c_po'): - new_params[name] = new_params[name].replace(kind=P.POSITIONAL_ONLY) - new_sig = sig.replace(parameters=new_params.values()) - test.__signature__ = new_sig - - self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6), - (1, 2, 4, 5, 6, {})) - - with self.assertRaisesRegex(TypeError, "parameter is positional only"): - self.call(test, 1, 2, c_po=4) - - with self.assertRaisesRegex(TypeError, "parameter is positional only"): - self.call(test, a_po=1, b_po=2) -""") - - -class TestBoundArguments(unittest.TestCase): - - def __init__(self, *args, **kwargs): - unittest.TestCase.__init__(self, *args, **kwargs) - if not hasattr(self, 'assertRaisesRegex'): - self.assertRaisesRegex = self.assertRaisesRegexp - - def test_signature_bound_arguments_unhashable(self): - def foo(a): pass - ba = inspect.signature(foo).bind(1) - - with self.assertRaisesRegex(TypeError, 'unhashable type'): - hash(ba) - - def test_signature_bound_arguments_equality(self): - def foo(a): pass - ba = inspect.signature(foo).bind(1) - self.assertEqual(ba, ba) - - ba2 = inspect.signature(foo).bind(1) - self.assertEqual(ba, ba2) - - ba3 = inspect.signature(foo).bind(2) - self.assertNotEqual(ba, ba3) - ba3.arguments['a'] = 1 - self.assertEqual(ba, ba3) - - def bar(b): pass - ba4 = inspect.signature(bar).bind(1) - self.assertNotEqual(ba, ba4) - - -if __name__ == "__main__": - unittest.begin() -- cgit v1.2.3