From 1608051d7531555be3bb6f1e38db6e28ca4e0a7f Mon Sep 17 00:00:00 2001 From: Christopher Armstrong Date: Sat, 9 May 2015 10:12:52 -0500 Subject: [PATCH 1/5] remove the examples and the twisted integration code. --- effect/test_twisted.py | 224 -------------------------------- effect/twisted.py | 105 --------------- examples/README.md | 41 ------ examples/__init__.py | 0 examples/github/__init__.py | 0 examples/github/core.py | 69 ---------- examples/github/sync_main.py | 62 --------- examples/github/test_core.py | 78 ----------- examples/github/twisted_main.py | 59 --------- examples/http/__init__.py | 0 examples/http/http_intent.py | 14 -- examples/http/sync_http.py | 22 ---- examples/http/twisted_http.py | 20 --- examples/readline_intent.py | 16 --- 14 files changed, 710 deletions(-) delete mode 100644 effect/test_twisted.py delete mode 100644 effect/twisted.py delete mode 100644 examples/README.md delete mode 100644 examples/__init__.py delete mode 100644 examples/github/__init__.py delete mode 100644 examples/github/core.py delete mode 100644 examples/github/sync_main.py delete mode 100644 examples/github/test_core.py delete mode 100644 examples/github/twisted_main.py delete mode 100644 examples/http/__init__.py delete mode 100644 examples/http/http_intent.py delete mode 100644 examples/http/sync_http.py delete mode 100644 examples/http/twisted_http.py delete mode 100644 examples/readline_intent.py diff --git a/effect/test_twisted.py b/effect/test_twisted.py deleted file mode 100644 index 677a3c2..0000000 --- a/effect/test_twisted.py +++ /dev/null @@ -1,224 +0,0 @@ -from __future__ import absolute_import - -from functools import partial -import sys - -from testtools import TestCase -from testtools.matchers import MatchesListwise, Equals, MatchesException - -from twisted.trial.unittest import SynchronousTestCase -from twisted.internet.defer import Deferred -from twisted.internet.task import Clock -from twisted.python.failure import Failure - -from ._base import Effect -from ._intents import ( - Constant, - Delay, - base_dispatcher, - parallel) -from ._dispatcher import ComposedDispatcher -from .twisted import ( - deferred_performer, - exc_info_to_failure, - make_twisted_dispatcher, - perform) - -from .test_base import func_dispatcher - - -def _dispatcher(reactor): - return ComposedDispatcher([ - make_twisted_dispatcher(reactor), - base_dispatcher - ]) - - -class TestCase(TestCase, SynchronousTestCase): - - skip = None # horrible hack to make trial cooperate with testtools - - -class ParallelTests(TestCase): - """Tests for :func:`parallel`.""" - def test_parallel(self): - """ - 'parallel' results in a list of results of the given effects, in the - same order that they were passed to parallel. - """ - d = perform( - _dispatcher(None), - parallel([Effect(Constant('a')), - Effect(Constant('b'))])) - self.assertEqual(self.successResultOf(d), ['a', 'b']) - - -class DelayTests(TestCase): - """Tests for :class:`Delay`.""" - - def test_delay(self): - """ - Delay intents will cause time to pass with reactor.callLater, and - result in None. - """ - clock = Clock() - called = [] - eff = Effect(Delay(1)).on(called.append) - perform(make_twisted_dispatcher(clock), eff) - self.assertEqual(called, []) - clock.advance(1) - self.assertEqual(called, [None]) - - -class TwistedPerformTests(TestCase): - - def test_perform(self): - """ - effect.twisted.perform returns a Deferred which fires with the ultimate - result of the Effect. - """ - boxes = [] - e = Effect(boxes.append) - d = perform(func_dispatcher, e) - self.assertNoResult(d) - boxes[0].succeed("foo") - self.assertEqual(self.successResultOf(d), 'foo') - - def test_perform_failure(self): - """ - effect.twisted.perform fails the Deferred it returns if the ultimate - result of the Effect is an exception. - """ - boxes = [] - e = Effect(boxes.append) - d = perform(func_dispatcher, e) - self.assertNoResult(d) - boxes[0].fail((ValueError, ValueError("oh dear"), None)) - f = self.failureResultOf(d) - self.assertEqual(f.type, ValueError) - self.assertEqual(str(f.value), 'oh dear') - - -class DeferredPerformerTests(TestCase): - """Tests for :func:`deferred_performer`.""" - - def test_deferred_success(self): - """ - @deferred_performer wraps a function taking the dispatcher and intent - and hooks up its Deferred result to the box. - """ - deferred = Deferred() - eff = Effect('meaningless').on(success=lambda x: ('success', x)) - dispatcher = lambda i: deferred_performer( - lambda dispatcher, intent: deferred) - result = perform(dispatcher, eff) - self.assertNoResult(result) - deferred.callback("foo") - self.assertEqual(self.successResultOf(result), ('success', 'foo')) - - def test_deferred_failure(self): - """ - A failing Deferred causes error handlers to be called with an exception - tuple based on the failure. - """ - deferred = Deferred() - eff = Effect('meaningless').on(error=lambda e: ('error', e)) - dispatcher = lambda i: deferred_performer( - lambda dispatcher, intent: deferred) - result = perform(dispatcher, eff) - self.assertNoResult(result) - deferred.errback(Failure(ValueError('foo'))) - self.assertThat(self.successResultOf(result), - MatchesListwise([ - Equals('error'), - MatchesException(ValueError('foo'))])) - - def test_synchronous_success(self): - """ - If ``deferred_performer`` wraps a function that returns a non-deferred, - that result is the result of the effect. - """ - dispatcher = lambda i: deferred_performer( - lambda dispatcher, intent: "foo") - result = perform(dispatcher, Effect("meaningless")) - self.assertEqual( - self.successResultOf(result), - "foo") - - def test_synchronous_exception(self): - """ - If ``deferred_performer`` wraps a function that raises an exception, - the effect results in that exception. - """ - def raise_(): - raise ValueError("foo") - - dispatcher = lambda i: deferred_performer( - lambda dispatcher, intent: raise_()) - eff = Effect('meaningless').on(error=lambda e: ('error', e)) - result = perform(dispatcher, eff) - self.assertThat(self.successResultOf(result), - MatchesListwise([ - Equals('error'), - MatchesException(ValueError('foo'))])) - - def test_instance_method_performer(self): - """The @deferred_performer decorator works on instance methods.""" - eff = Effect('meaningless') - - class PerformerContainer(object): - @deferred_performer - def performer(self, dispatcher, intent): - return (self, dispatcher, intent) - - container = PerformerContainer() - - dispatcher = lambda i: container.performer - result = self.successResultOf(perform(dispatcher, eff)) - self.assertEqual(result, (container, dispatcher, 'meaningless')) - - def test_promote_metadata(self): - """ - The decorator copies metadata from the wrapped function onto the - wrapper. - """ - def original(dispatcher, intent): - """Original!""" - pass - original.attr = 1 - wrapped = deferred_performer(original) - self.assertEqual(wrapped.__name__, 'original') - self.assertEqual(wrapped.attr, 1) - self.assertEqual(wrapped.__doc__, 'Original!') - - def test_ignore_lack_of_metadata(self): - """ - When the original callable is not a function, a new function is still - returned. - """ - def original(something, dispatcher, intent): - """Original!""" - pass - new_func = partial(original, 'something') - original.attr = 1 - wrapped = deferred_performer(new_func) - self.assertEqual(wrapped.__name__, 'deferred_wrapper') - - -class ExcInfoToFailureTests(TestCase): - """Tests for :func:`exc_info_to_failure`.""" - - def test_exc_info_to_failure(self): - """ - :func:`exc_info_to_failure` converts an exc_info tuple to a - :obj:`Failure`. - """ - try: - raise RuntimeError("foo") - except: - exc_info = sys.exc_info() - - failure = exc_info_to_failure(exc_info) - self.assertIs(failure.type, RuntimeError) - self.assertEqual(str(failure.value), "foo") - self.assertIs(failure.tb, exc_info[2]) diff --git a/effect/twisted.py b/effect/twisted.py deleted file mode 100644 index 87e44de..0000000 --- a/effect/twisted.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- test-case-name: effect.test_twisted -*- - -""" -Twisted integration for the Effect library. - -This is largely concerned with bridging the gap between Effects and Deferreds, -and also implementing Twisted-specific performers for standard Intents. - -The most important functions here are :func:`perform`, -:func:`make_twisted_dispatcher`, and :func:`deferred_performer`. - -Note that the core effect library does *not* depend on Twisted, but this module -does. -""" - -from __future__ import absolute_import - -from functools import partial -import sys - -from twisted.internet.defer import Deferred -from twisted.python.failure import Failure -from twisted.internet.task import deferLater - -from ._intents import Delay, ParallelEffects -from ._base import perform as base_perform -from ._dispatcher import TypeDispatcher -from ._utils import wraps -from .async import perform_parallel_async - - -def deferred_to_box(d, box): - """ - Make a Deferred pass its success or fail events on to the given box. - """ - d.addCallbacks(box.succeed, lambda f: box.fail((f.type, f.value, f.tb))) - - -def make_twisted_dispatcher(reactor): - """ - Create a dispatcher that knows how to perform certain built-in Intents - with Twisted-specific implementations. - """ - return TypeDispatcher({ - ParallelEffects: perform_parallel_async, - Delay: deferred_performer(partial(perform_delay, reactor)), - }) - - -def deferred_performer(f): - """ - A decorator for performers that return Deferreds. - - The function being decorated is expected to take a dispatcher and an intent - (and not a box), and may return a Deferred. The wrapper function - that this decorator returns will accept a dispatcher, an intent, and a box - (conforming to the performer interface). The wrapper deals with - putting the Deferred's result into the box. - - Example:: - - @deferred_performer - def perform_foo(dispatcher, foo): - return do_side_effecting_deferred_operation(foo) - """ - @wraps(f) - def deferred_wrapper(*args): - box = args[-1] - pass_args = args[:-1] - try: - result = f(*pass_args) - except: - box.fail(sys.exc_info()) - else: - if isinstance(result, Deferred): - deferred_to_box(result, box) - else: - box.succeed(result) - return deferred_wrapper - - -def perform_delay(reactor, dispatcher, delay): - """ - Perform a :obj:`effect.Delay` with Twisted's - :func:`twisted.internet.task.deferLater`. - """ - return deferLater(reactor, delay.delay, lambda: None) - - -def perform(dispatcher, effect): - """ - Perform an effect, returning a Deferred that will fire with the effect's - ultimate result. - """ - d = Deferred() - eff = effect.on( - success=d.callback, - error=lambda e: d.errback(exc_info_to_failure(e))) - base_perform(dispatcher, eff) - return d - - -def exc_info_to_failure(exc_info): - """Convert an exc_info tuple to a :class:`Failure`.""" - return Failure(exc_info[1], exc_info[0], exc_info[2]) diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 38aaa80..0000000 --- a/examples/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Effect Examples - -## http - -The `http` directory contains a very simple `HTTPRequest` intent and performers -using common HTTP client libraries: -[requests](http://warehouse.python.org/project/requests/) and -[treq](https://warehouse.python.org/project/treq/). - - -## readline_intent - -The `readline_intent.py` file has a simple `ReadLine` intent that uses -`raw_input` (or `input` in Py3) to prompt the user for input. - -## github - -The `github` directory contains a simple application that lets the user input a -GitHub username and prints out a list of all repositories that that user has -access to. It depends on the `http` and `readline_intent` modules. - -There are two entrypoints into the example: -[`examples.github.sync_main`](github/sync_main.py) and -[`examples.github.twisted_main`](github/twisted_main.py). `sync_main` does -typical blocking IO, and `twisted_main` uses asynchronous IO. Note that the -vast majority of the code doesn't need to care about this difference; the only -part that cares about it is the `*_main.py` files. All of the logic in -[`core.py`](github/core.py) is generic. Tests are in -[`test_core.py`](github/test_core.py). - -To run them: - - python -m examples.github.sync_main - -or - - python -m examples.github.twisted_main - - -Note that the twisted example does not run on Python 3, but all other examples -do. diff --git a/examples/__init__.py b/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/examples/github/__init__.py b/examples/github/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/examples/github/core.py b/examples/github/core.py deleted file mode 100644 index f3edb84..0000000 --- a/examples/github/core.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -Core application / API interaction logic of the GitHub example. - -None of this code needs to change based on your I/O strategy -- you can -use blocking API (e.g. the ``requests`` library) or Twisted, asyncio, -or Tornado implementations of an HTTP client with this code, by providing -different performers for the :obj:`HTTPRequest` intent. -""" - -from __future__ import print_function - -from functools import reduce -import json -import operator - -from effect import Effect, parallel - -from ..readline_intent import ReadLine -from ..http.http_intent import HTTPRequest - - -def get_orgs(name): - """ - Fetch the organizations a user belongs to. - - :return: An Effect resulting in a list of strings naming the user's - organizations. - """ - req = Effect( - HTTPRequest("get", - "https://api.github.com/users/{0}/orgs".format(name))) - return req.on(success=lambda x: [org['login'] for org in json.loads(x)]) - - -def get_org_repos(name): - """ - Fetch the repos that belong to an organization. - - :return: An Effect resulting in a list of strings naming the repositories. - """ - req = Effect( - HTTPRequest("get", - "https://api.github.com/orgs/{0}/repos".format(name))) - return req.on(success=lambda x: [repo['name'] for repo in json.loads(x)]) - - -def get_orgs_repos(name): - """ - Fetch ALL of the repos that a user has access to, in any organization. - - :return: An Effect resulting in a list of repositories. - """ - req = get_orgs(name) - req = req.on(lambda org_names: parallel(map(get_org_repos, org_names))) - req = req.on(lambda repo_lists: reduce(operator.add, repo_lists)) - return req - - -def main_effect(): - """ - Request a username from the keyboard, and look up all repos in all of - that user's organizations. - - :return: an Effect resulting in a list of repositories. - """ - intent = ReadLine("Enter Github Username> ") - read_eff = Effect(intent) - org_repos_eff = read_eff.on(success=get_orgs_repos) - return org_repos_eff diff --git a/examples/github/sync_main.py b/examples/github/sync_main.py deleted file mode 100644 index c45908a..0000000 --- a/examples/github/sync_main.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Run this example with: - python -m examples.github.sync_main - -This is an example of using Effect in a normal program that uses -synchronous/blocking functions to do I/O. - -This code has these responsibilities: - -- set up a dispatcher that knows how to find performers for all intents - used in this application. The application uses ReadLine, HTTPRequest, and - ParallelEffects. -- use :func:`effect.sync_perform` to perform an effect, which returns the - result of the effect (or raises an exception it it failed). -""" - -from __future__ import print_function - -from functools import partial -from multiprocessing.pool import ThreadPool - -from effect import ( - ComposedDispatcher, - ParallelEffects, - TypeDispatcher, - sync_perform) -from effect.threads import perform_parallel_with_pool - - -from ..http.http_intent import HTTPRequest -from ..http.sync_http import perform_request_requests -from ..readline_intent import ReadLine, perform_readline_stdin - -from .core import main_effect - - -def get_dispatcher(): - """ - Create a dispatcher that can find performers for :obj:`ReadLine`, - :obj:`HTTPRequest`, and :obj:`ParallelEffects`. There's a built-in - performer for ParallelEffects that uses a multiprocessing ThreadPool, - :func:`effect.perform_parallel_with_pool`. - """ - my_pool = ThreadPool() - pool_performer = partial(perform_parallel_with_pool, my_pool) - return ComposedDispatcher([ - TypeDispatcher({ - ReadLine: perform_readline_stdin, - HTTPRequest: perform_request_requests, - ParallelEffects: pool_performer, - }) - ]) - - -def main(): - dispatcher = get_dispatcher() - eff = main_effect() - print(sync_perform(dispatcher, eff)) - - -if __name__ == '__main__': - main() diff --git a/examples/github/test_core.py b/examples/github/test_core.py deleted file mode 100644 index 504710b..0000000 --- a/examples/github/test_core.py +++ /dev/null @@ -1,78 +0,0 @@ -# Run these tests with "trial examples.github.test_core" -# or "python -m testtools.run examples.github.test_core" - -import json - -from testtools import TestCase - -from effect import ParallelEffects -from effect.testing import resolve_effect - -from .core import get_orgs, get_org_repos, get_orgs_repos - - -class GithubTests(TestCase): - def test_get_orgs_request(self): - """ - get_orgs returns an effect that makes an HTTP request to - the GitHub API to look up organizations for a user. - """ - eff = get_orgs('radix') - http = eff.intent - self.assertEqual(http.method, 'get') - self.assertEqual(http.url, 'https://api.github.com/users/radix/orgs') - - def test_get_orgs_success(self): - """get_orgs extracts the result into a simple list of orgs.""" - eff = get_orgs('radix') - self.assertEqual( - resolve_effect(eff, json.dumps([{'login': 'twisted'}, - {'login': 'rackerlabs'}])), - ['twisted', 'rackerlabs']) - - def test_get_org_repos_request(self): - """ - get_org_repos returns an effect that makes an HTTP request to - the GitHub API to look up repos in an org. - """ - eff = get_org_repos('twisted') - http = eff.intent - self.assertEqual(http.method, 'get') - self.assertEqual(http.url, 'https://api.github.com/orgs/twisted/repos') - - def test_get_org_repos_success(self): - """get_org_repos extracts the result into a simple list of repos.""" - eff = get_org_repos('radix') - self.assertEqual( - resolve_effect(eff, json.dumps([{'name': 'twisted'}, - {'name': 'txstuff'}])), - ['twisted', 'txstuff']) - - def test_get_orgs_repos(self): - """ - get_orgs_repos returns an Effect which looks up the organizations for - a user, and then looks up all of the repositories of those orgs in - parallel, and returns a single flat list of all repos. - """ - effect = get_orgs_repos('radix') - self.assertEqual(effect.intent.method, 'get') - self.assertEqual(effect.intent.url, - 'https://api.github.com/users/radix/orgs') - next_effect = resolve_effect( - effect, - json.dumps([{'login': 'twisted'}, {'login': 'rackerlabs'}])) - self.assertIsInstance(next_effect.intent, ParallelEffects) - # Get each parallel effect - effects = next_effect.intent.effects - self.assertEqual(effects[0].intent.method, 'get') - self.assertEqual(effects[0].intent.url, - 'https://api.github.com/orgs/twisted/repos') - self.assertEqual(effects[1].intent.method, 'get') - self.assertEqual(effects[1].intent.url, - 'https://api.github.com/orgs/rackerlabs/repos') - self.assertEqual(resolve_effect(next_effect, [['twisted', 'txstuff'], - ['otter', 'nova']]), - ['twisted', 'txstuff', 'otter', 'nova']) - - # These tests don't have 100% coverage, but they should teach you - # everything you need to know to extend to testing any type of effect. diff --git a/examples/github/twisted_main.py b/examples/github/twisted_main.py deleted file mode 100644 index ee0d791..0000000 --- a/examples/github/twisted_main.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Run this example with: - python -m examples.github.twisted_main - -This is an example of using Effect with Twisted. - -It's important to note that none of the application code relies on Twisted -- -this is the only file that has any dependencies on Twisted. There's also an -example of running the same application code in ``sync_main.py`` in the same -directory. - -This code has these responsibilities: - -- set up a dispatcher that knows how to find performers for all intents - used in this application. The application uses ReadLine, HTTPRequest, and - ParallelEffects. -- use :func:`effect.twisted.perform` to perform an effect, which returns a - Deferred that we can return from our react function. -""" - -from __future__ import print_function - -from twisted.internet.task import react - -from effect.twisted import make_twisted_dispatcher, perform -from effect import ( - ComposedDispatcher, - TypeDispatcher) - -from ..http.http_intent import HTTPRequest -from ..http.twisted_http import perform_request_with_treq -from ..readline_intent import ReadLine, perform_readline_stdin - -from .core import main_effect - - -def get_dispatcher(reactor): - """ - Create a dispatcher that can find performers for :obj:`ReadLine`, - :obj:`HTTPRequest`, and :obj:`ParallelEffects`. - :func:`make_twisted_dispatcher` is able to provide the ``ParallelEffects`` - performer, so we compose it with our own custom :obj:`TypeDispatcher`. - """ - return ComposedDispatcher([ - TypeDispatcher({ - ReadLine: perform_readline_stdin, - HTTPRequest: perform_request_with_treq, - }), - make_twisted_dispatcher(reactor), - ]) - - -def main(reactor): - dispatcher = get_dispatcher(reactor) - eff = main_effect() - return perform(dispatcher, eff).addCallback(print) - -if __name__ == '__main__': - react(main, []) diff --git a/examples/http/__init__.py b/examples/http/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/examples/http/http_intent.py b/examples/http/http_intent.py deleted file mode 100644 index 406f87b..0000000 --- a/examples/http/http_intent.py +++ /dev/null @@ -1,14 +0,0 @@ -class HTTPRequest(object): - """ - An HTTP request intent. - """ - - def __init__(self, method, url, headers=None, data=None): - self.method = method - self.url = url - self.headers = headers - self.data = data - - def __repr__(self): - return "HTTPRequest(%r, %r, headers=%r, data=%r)" % ( - self.method, self.url, self.headers, self.data) diff --git a/examples/http/sync_http.py b/examples/http/sync_http.py deleted file mode 100644 index a07d411..0000000 --- a/examples/http/sync_http.py +++ /dev/null @@ -1,22 +0,0 @@ -from effect import sync_performer - -import requests - - -@sync_performer -def perform_request_requests(dispatcher, http_request): - """ - A performer for :obj:`HTTPRequest` that uses the ``requests`` library. - """ - headers = ( - http_request.headers.copy() - if http_request.headers is not None - else {}) - if 'user-agent' not in headers: - headers['user-agent'] = 'Effect example' - response = requests.request( - http_request.method.lower(), - http_request.url, - headers=headers, - data=http_request.data) - return response.content.decode('utf-8') diff --git a/examples/http/twisted_http.py b/examples/http/twisted_http.py deleted file mode 100644 index dda2947..0000000 --- a/examples/http/twisted_http.py +++ /dev/null @@ -1,20 +0,0 @@ -from effect.twisted import deferred_performer - -import treq - - -@deferred_performer -def perform_request_with_treq(dispatcher, http_request): - """A performer for :obj:`HTTPRequest` that uses the ``treq`` library.""" - headers = ( - http_request.headers.copy() - if http_request.headers is not None - else {}) - if 'user-agent' not in headers: - headers['user-agent'] = ['Effect example'] - d = treq.request( - http_request.method.lower(), - http_request.url, - headers=headers, - data=http_request.data).addCallback(treq.content) - return d diff --git a/examples/readline_intent.py b/examples/readline_intent.py deleted file mode 100644 index c871bb5..0000000 --- a/examples/readline_intent.py +++ /dev/null @@ -1,16 +0,0 @@ -from six.moves import input - -from effect import sync_performer - - -class ReadLine(object): - """An effect intent for getting input from the user.""" - - def __init__(self, prompt): - self.prompt = prompt - - -@sync_performer -def perform_readline_stdin(dispatcher, readline): - """Perform a :obj:`ReadLine` intent by reading from stdin.""" - return input(readline.prompt) From 1f766ec2a97d8bb8f54784bee1376ac12fb2d82f Mon Sep 17 00:00:00 2001 From: Christopher Armstrong Date: Sat, 9 May 2015 10:13:26 -0500 Subject: [PATCH 2/5] twisted is no longer necessary to build docs or run tests --- dev-requirements.txt | 1 - rtd-requirements.txt | 1 - 2 files changed, 2 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index b92b476..70023d4 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,4 +1,3 @@ testtools -twisted flake8 pytest diff --git a/rtd-requirements.txt b/rtd-requirements.txt index 0109959..29262fd 100644 --- a/rtd-requirements.txt +++ b/rtd-requirements.txt @@ -1,3 +1,2 @@ # requirements for Read The Docs alabaster -twisted From f65f503ec0db277a75a5dca40824541f8ddabcef Mon Sep 17 00:00:00 2001 From: Christopher Armstrong Date: Sat, 9 May 2015 10:14:49 -0500 Subject: [PATCH 3/5] link to the new effect-examples repo --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index fd63b06..39109a5 100644 --- a/README.rst +++ b/README.rst @@ -89,10 +89,10 @@ possible to override the way an intent is performed to do whatever you want. For more information on how to implement the actual effect-performing code, and other details, see the `documentation`_. There is also a full example of interacting with the user and using an HTTP client to talk to the GitHub -API in the `examples`_ directory. +API in the `effect-examples`_ repository. .. _`documentation`: https://effect.readthedocs.org/ -.. _`examples`: https://github.com/python-effect/effect/tree/master/examples +.. _`effect-examples`: https://github.com/python-effect/effect-examples From 6cc385a5d3243ad3fb313d3f44b40119a69730f4 Mon Sep 17 00:00:00 2001 From: Christopher Armstrong Date: Sat, 9 May 2015 10:17:18 -0500 Subject: [PATCH 4/5] link to txEffect --- README.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.rst b/README.rst index 39109a5..1d09575 100644 --- a/README.rst +++ b/README.rst @@ -133,6 +133,12 @@ There is a ``#python-effect`` IRC channel on irc.freenode.net. See Also ======== +For integrating Effect with Twisted's Deferreds, see the ``txEffect`` package +(`pypi`_, `github`_). + +.. _`pypi`: https://warehouse.python.org/project/txeffect +.. _`github`: https://github.com/python-effect/txeffect + Over the past few years, the ecosystem of libraries to help with functional programming in Python has exploded. Here are some libraries I recommend: From e6a60750b2a07bc71a0d2382923ee27e17748c73 Mon Sep 17 00:00:00 2001 From: Christopher Armstrong Date: Sat, 9 May 2015 10:19:21 -0500 Subject: [PATCH 5/5] don't try to lint the `examples` directory any more since it was removed --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 94d6de9..ea2e273 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ lint: - flake8 --ignore=E131,E731,W503 effect/ examples/ + flake8 --ignore=E131,E731,W503 effect/ build-dist: rm -rf dist