Merge branch 'jamielennox-readme'
Conflicts: README.rst
This commit is contained in:
		
							
								
								
									
										30
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								README.rst
									
									
									
									
									
								
							@@ -2,22 +2,21 @@
 | 
			
		||||
positional
 | 
			
		||||
==========
 | 
			
		||||
 | 
			
		||||
A decorator which enforces only some args may be passed positionally.
 | 
			
		||||
 | 
			
		||||
|PyPi|
 | 
			
		||||
 | 
			
		||||
|Build Status|
 | 
			
		||||
 | 
			
		||||
|Documentation Status|
 | 
			
		||||
 | 
			
		||||
Intro
 | 
			
		||||
=====
 | 
			
		||||
The Basics
 | 
			
		||||
==========
 | 
			
		||||
 | 
			
		||||
`positional` provides a decorator which enforces only some args may be passed
 | 
			
		||||
positionally. The idea and some of the code was taken from the oauth2 client
 | 
			
		||||
of the google-api client.
 | 
			
		||||
 | 
			
		||||
The Basics
 | 
			
		||||
==========
 | 
			
		||||
 | 
			
		||||
The decorator makes it easy to support Python 3 style key-word only
 | 
			
		||||
parameters. For example, in Python 3 it is possible to write:
 | 
			
		||||
 | 
			
		||||
@@ -121,18 +120,25 @@ This behaviour will work with the `positional.method` and
 | 
			
		||||
    ...    @positional.classmethod()
 | 
			
		||||
    ...    def my_method(cls, pos1, kwonly1=None):
 | 
			
		||||
    ...        ...
 | 
			
		||||
 | 
			
		||||
    MyClass.my_method(10)  # Ok.
 | 
			
		||||
    MyClass.my_method(10, 20)  # Raises exception.
 | 
			
		||||
    MyClass.my_method(10, kwonly1=20)  # Ok.
 | 
			
		||||
    ...
 | 
			
		||||
    >>> MyClass.my_method(10)  # Ok.
 | 
			
		||||
    >>> MyClass.my_method(10, 20)  # Raises exception.
 | 
			
		||||
    >>> MyClass.my_method(10, kwonly1=20)  # Ok.
 | 
			
		||||
 | 
			
		||||
For compatibility reasons you may wish to not always raise an exception so
 | 
			
		||||
a WARN mode is available. Rather than raise an exception a warning message
 | 
			
		||||
will be logged:
 | 
			
		||||
 | 
			
		||||
    @positional(1, enforcement=positional.WARN):
 | 
			
		||||
    def fn(pos1, kwonly=1):
 | 
			
		||||
       ...
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
    >>> @positional(1, enforcement=positional.WARN):
 | 
			
		||||
    ... def fn(pos1, kwonly=1):
 | 
			
		||||
    ...     ...
 | 
			
		||||
 | 
			
		||||
Available modes are:
 | 
			
		||||
 | 
			
		||||
- positional.EXCEPT - the default, raise an exception.
 | 
			
		||||
- positional.WARN - log a warning on mistake.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.. |Build Status| image:: https://travis-ci.org/morganfainberg/positional.svg?branch=master
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,13 @@ Contents:
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :maxdepth: 1
 | 
			
		||||
 | 
			
		||||
   api/positional
 | 
			
		||||
   api/modules
 | 
			
		||||
 | 
			
		||||
Usage
 | 
			
		||||
=====
 | 
			
		||||
 | 
			
		||||
.. include:: ../../README.rst
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Release Notes
 | 
			
		||||
=============
 | 
			
		||||
 
 | 
			
		||||
@@ -21,109 +21,31 @@ _logger = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class positional(object):
 | 
			
		||||
    """A decorator which enforces only some args may be passed positionally.
 | 
			
		||||
    """A decorator to enforce passing arguments as keywords.
 | 
			
		||||
 | 
			
		||||
    This idea and some of the code was taken from the oauth2 client of the
 | 
			
		||||
    google-api client.
 | 
			
		||||
    When you have a function that takes a lot of arguments you expect people to
 | 
			
		||||
    pass those arguments as keyword arguments. Python however does not enforce
 | 
			
		||||
    this. In future then if you decide that you want to insert a new argument
 | 
			
		||||
    or rearrange the arguments or transition to using **kwargs you break
 | 
			
		||||
    compatibility with users of your code who (wrongly) gave you 20 positional
 | 
			
		||||
    arguments.
 | 
			
		||||
 | 
			
		||||
    This decorator makes it easy to support Python 3 style key-word only
 | 
			
		||||
    parameters. For example, in Python 3 it is possible to write::
 | 
			
		||||
    In python 3 there is syntax to prevent this however we are not all in the
 | 
			
		||||
    position where we can write python 3 exclusive code. Positional solves the
 | 
			
		||||
    problem in the mean time across both pythons by enforcing that certain
 | 
			
		||||
    arguments must be past as keyword arguments.
 | 
			
		||||
 | 
			
		||||
      def fn(pos1, *, kwonly1, kwonly2=None):
 | 
			
		||||
          ...
 | 
			
		||||
    :param max_positional_args: the maixmum number of arguments that can be
 | 
			
		||||
        passed to this function without keyword parameters. Defaults to
 | 
			
		||||
        enforcing that every parameter with a default value must be passed as a
 | 
			
		||||
        keyword argument.
 | 
			
		||||
    :type max_positional_args int
 | 
			
		||||
 | 
			
		||||
    All named parameters after * must be a keyword::
 | 
			
		||||
 | 
			
		||||
      fn(10, 'kw1', 'kw2')  # Raises exception.
 | 
			
		||||
      fn(10, kwonly1='kw1', kwonly2='kw2')  # Ok.
 | 
			
		||||
 | 
			
		||||
    To replicate this behaviour with the positional decorator you simply
 | 
			
		||||
    specify how many arguments may be passed positionally. To replicate the
 | 
			
		||||
    example above::
 | 
			
		||||
 | 
			
		||||
        @positional(1)
 | 
			
		||||
        def fn(pos1, kwonly1=None, kwonly2=None):
 | 
			
		||||
            ...
 | 
			
		||||
 | 
			
		||||
    If no default value is provided to a keyword argument, it becomes a
 | 
			
		||||
    required keyword argument::
 | 
			
		||||
 | 
			
		||||
        @positional(0)
 | 
			
		||||
        def fn(required_kw):
 | 
			
		||||
            ...
 | 
			
		||||
 | 
			
		||||
    This must be called with the keyword parameter::
 | 
			
		||||
 | 
			
		||||
        fn()  # Raises exception.
 | 
			
		||||
        fn(10)  # Raises exception.
 | 
			
		||||
        fn(required_kw=10)  # Ok.
 | 
			
		||||
 | 
			
		||||
    When defining instance or class methods always remember that in python the
 | 
			
		||||
    first positional argument passed is always the instance so you will need to
 | 
			
		||||
    account for `self` and `cls`::
 | 
			
		||||
 | 
			
		||||
        class MyClass(object):
 | 
			
		||||
 | 
			
		||||
            @positional(2)
 | 
			
		||||
            def my_method(self, pos1, kwonly1=None):
 | 
			
		||||
                ...
 | 
			
		||||
 | 
			
		||||
            @classmethod
 | 
			
		||||
            @positional(2)
 | 
			
		||||
            def my_method(cls, pos1, kwonly1=None):
 | 
			
		||||
                ...
 | 
			
		||||
 | 
			
		||||
    If you would prefer not to account for `self` and `cls` you can use the
 | 
			
		||||
    `method` and `classmethod` helpers which do not consider the initial
 | 
			
		||||
    positional argument. So the following class is exactly the same as the one
 | 
			
		||||
    above::
 | 
			
		||||
 | 
			
		||||
        class MyClass(object):
 | 
			
		||||
 | 
			
		||||
            @positional.method(1)
 | 
			
		||||
            def my_method(self, pos1, kwonly1=None):
 | 
			
		||||
                ...
 | 
			
		||||
 | 
			
		||||
            @positional.classmethod(1)
 | 
			
		||||
            def my_method(cls, pos1, kwonly1=None):
 | 
			
		||||
                ...
 | 
			
		||||
 | 
			
		||||
    If a value isn't provided to the decorator then it will enforce that
 | 
			
		||||
    every variable without a default value will be required to be a kwarg::
 | 
			
		||||
 | 
			
		||||
        @positional()
 | 
			
		||||
        def fn(pos1, kwonly1=None):
 | 
			
		||||
            ...
 | 
			
		||||
 | 
			
		||||
        fn(10)  # Ok.
 | 
			
		||||
        fn(10, 20)  # Raises exception.
 | 
			
		||||
        fn(10, kwonly1=20)  # Ok.
 | 
			
		||||
 | 
			
		||||
    This behaviour will work with the `positional.method` and
 | 
			
		||||
    `positional.classmethod` helper functions as well::
 | 
			
		||||
 | 
			
		||||
        class MyClass(object):
 | 
			
		||||
 | 
			
		||||
            @positional.classmethod()
 | 
			
		||||
            def my_method(cls, pos1, kwonly1=None):
 | 
			
		||||
                ...
 | 
			
		||||
 | 
			
		||||
        MyClass.my_method(10)  # Ok.
 | 
			
		||||
        MyClass.my_method(10, 20)  # Raises exception.
 | 
			
		||||
        MyClass.my_method(10, kwonly1=20)  # Ok.
 | 
			
		||||
 | 
			
		||||
    For compatibility reasons you may wish to not always raise an exception so
 | 
			
		||||
    a WARN mode is available. Rather than raise an exception a warning message
 | 
			
		||||
    will be logged::
 | 
			
		||||
 | 
			
		||||
        @positional(1, enforcement=positional.WARN):
 | 
			
		||||
        def fn(pos1, kwonly=1):
 | 
			
		||||
           ...
 | 
			
		||||
 | 
			
		||||
    Available modes are:
 | 
			
		||||
 | 
			
		||||
    - positional.EXCEPT - the default, raise an exception.
 | 
			
		||||
    - positional.WARN - log a warning on mistake.
 | 
			
		||||
    :param enforcement: defines the way incorrect usage is reported. Currenlty
 | 
			
		||||
        accepts :py:attr:`positional.EXCEPT` to raise a TypeError or
 | 
			
		||||
        :py:attr:`positional.WARN` to print a warning. A warning can be useful
 | 
			
		||||
        for applying to functions that are already public as a deprecation
 | 
			
		||||
        notice. Defaults to :py:attr:`positional.EXCEPT`.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    EXCEPT = 'except'
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user