Permalink
Browse files

Initial import

  • Loading branch information...
0 parents commit 4c072591cd66d439e118f1da08752e892540419c @hynek committed Oct 3, 2012
Showing with 221 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +6 −0 HISTORY.rst
  3. +19 −0 LICENSE
  4. +1 −0 MANIFEST.in
  5. +5 −0 Makefile
  6. +85 −0 README.rst
  7. +66 −0 first.py
  8. +35 −0 setup.py
4 .gitignore
@@ -0,0 +1,4 @@
+__pycache__
+build
+dist
+first.egg-info
6 HISTORY.rst
@@ -0,0 +1,6 @@
+History
+=======
+
+1.0.0 (2012-10-XX)
+------------------
+ - Initial release.
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2012 Hynek Schlawack
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
1 MANIFEST.in
@@ -0,0 +1 @@
+include README.rst LICENSE HISTORY.rst first.py
5 Makefile
@@ -0,0 +1,5 @@
+test:
+ python -m doctest first.py
+ python -m doctest README.rst
+
+.PHONY: test
85 README.rst
@@ -0,0 +1,85 @@
+first: The function you always missed in itertools
+==================================================
+
+*first* is a MIT licensed Python package with a simple function that returns
+the first true value from an iterable, or ``None`` if there is none. If you need
+more power, you can also supply a predicate whose result will be returned iff
+true.
+
+ I’m using the term “true” consistently with Python docs for ``any()`` and
+ ``all()`` — it means that the value evaluates to true like: ``True``, ``1``,
+ ``"foo"`` or ``[None]``. But **not**: ``None``, ``False`` or ``0``. In
+ JavaScript, they call this “truthy”.
+
+
+Examples
+========
+
+A simple example first: ::
+
+ >> from first import first
+ >> first([0, None, False, [], (), 42])
+ 42
+
+However, it’s especially useful for dealing with regular expressions in
+``if/elif/else`` branches: ::
+
+ import re
+
+ from first import first
+
+
+ re1 = re.compile('b(.*)')
+ re2 = re.compile('a(.*)')
+
+ m = first(regexp.match('abc') for regexp in [re1, re2])
+ if m.re is re1:
+ print('re1', m.group(1))
+ elif m.re is re2:
+ print('re2', m.group(1))
+ else:
+ print('no match!')
+
+The optional predicate gives you even *more* power. If you want to return the
+square of the first even number from a list, just do the following: ::
+
+ >>> from first import first
+ >>> first([1, 1, 3, 4, 5], lambda x: (x ** 2) if (x % 2) == 0 else False)
+ 16
+
+
+Usage
+=====
+
+The package consists of one module consisting of one function::
+
+ from first import first
+
+ first(iterable, pred=None)
+
+This function returns the first element of ``iterable`` that is true if
+``pred`` is ``None``. If there is no true element, ``None`` is returned.
+
+If a callable is supplied in ``pred``, the result of ``pred(element)`` is
+returned, if the result it true.
+
+*first* has no dependencies and should work with any Python available. Of
+course, it works with the awesome `Python 3`_ everybody should be using.
+
+
+Background
+==========
+
+The idea for *first* goes back to a discussion I had with `Łukasz Langa`_ about
+how the ``re`` example above is painful in Python. We figured such a function
+is missing from `itertools`_, however it’s rather unlikely we’d get it in and
+even if, it wouldn’t get in before 3.4 anyway, which is years away as of yours
+truly is writing this.
+
+So I decided to release it as a package for now. If it proves popular enough,
+it may even make it into Python’s stdlib in the end.
+
+
+.. _`Python 3`: http://getpython3.com/
+.. _`Łukasz Langa`: https://github.com/ambv
+.. _`itertools`: http://docs.python.org/dev/library/itertools.html
66 first.py
@@ -0,0 +1,66 @@
+## -*- coding: utf-8 -*-
+
+"""
+first
+=====
+
+first is the function you always missed in itertools.
+
+In the simples case, it returns the first true element from an iterable:
+
+>>> from first import first
+>>> first([0, False, None, [], (), 42])
+42
+
+It also supports the passing of a predicate whose result will be returned iff
+the result is true:
+
+>>> from first import first
+>>> first([1, 1, 3, 4, 5], lambda x: (x ** 2) if (x % 2) == 0 else False)
+16
+
+:copyright: (c) 2012 by Hynek Schlawack.
+:license: MIT, see LICENSE for more details.
+
+"""
+
+__title__ = 'first'
+__version__ = '1.0.0'
+__author__ = 'Hynek Schlawack'
+__license__ = 'MIT'
+__copyright__ = 'Copyright 2012 Hynek Schlawack'
+
+
+def first(iterable, pred=None):
+ """
+ Return first element of `iterable` that evaluates truish, else return None.
+
+ >>> first([0, False, None, [], (), 42])
+ 42
+
+ >>> import re
+ >>> m = first(re.match(regex, 'abc') for regex in ['b.*', 'a(.*)'])
+ >>> m.group(1)
+ 'bc'
+
+ >>> first([]) is None
+ True
+ >>> first([0, False, None, [], ()]) is None
+ True
+
+ If `pred` is specified, the result of `pred` is returned if the result is
+ truish.
+
+ >>> first([1, 1, 3, 4, 5], lambda x: (x ** 2) if (x % 2) == 0 else False)
+ 16
+
+ """
+ for el in iterable:
+ if pred:
+ rv = pred(el)
+ if rv:
+ return rv
+ elif el:
+ return el
+ else:
+ return None
35 setup.py
@@ -0,0 +1,35 @@
+from setuptools import setup
+
+import first
+
+
+setup(
+ name='first',
+ version=first.__version__,
+ description=first.__doc__.strip(),
+ long_description=open('README.rst').read() + open('HISTORY.rst').read(),
+ url='http://github.com/hynek/first/',
+ license=first.__license__,
+ author=first.__author__,
+ author_email='hs@ox.cx',
+ classifiers=[
+ 'Development Status :: 5 - Production/Stable',
+ 'Intended Audience :: Developers',
+ 'Natural Language :: English',
+ 'License :: OSI Approved :: MIT License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.3',
+ 'Programming Language :: Python :: 2.4',
+ 'Programming Language :: Python :: 2.5',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.0',
+ 'Programming Language :: Python :: 3.1',
+ 'Programming Language :: Python :: 3.2',
+ 'Programming Language :: Python :: 3.3',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ ],
+)

0 comments on commit 4c07259

Please sign in to comment.