Merge pull request #12 from morganfainberg/jamielennox-readme-merged
Jamielennox readme merged
This commit is contained in:
commit
6cf6726813
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'
|
||||
|
Loading…
x
Reference in New Issue
Block a user