GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-96471: Add asyncio queue shutdown by EpicWink · Pull Request #104228 · python/cpython

Conversation

@EpicWink

@EpicWink EpicWink commented May 6, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

asyncio-only changes from #102499 (which supercedes #96474), updated to match the API introduced by #104750

  • Issue: Queue shutdown #96471

📚 Documentation preview 📚: https://cpython-previews--104228.org.readthedocs.build/

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

heckad and aalekhpatel07 reacted with thumbs up emoji
All reactions
  • 👍 2 reactions
EpicWink and others added 2 commits May 6, 2023 14:50
@EpicWink
Add asyncio queue shutdown
440a702
* Include docs
@YvesDup @EpicWink
Fix queue shutdown
fb458db
* Queue state enum members are capitalised
* Termination state in str/repr
* Include raised exception in docstrings
* Factor out queue-state checks and updates to methods
* Logic fixes in get_nowait and shutdown
* Handle queue shutdown in task_done and join
* Updated tests
* Document feature added in 3.13
@EpicWink
EpicWink requested a review from rhettinger as a code owner May 6, 2023 04:54
@bedevere-bot bedevere-bot mentioned this pull request May 6, 2023
Queue shutdown #96471
Open
@bedevere-bot bedevere-bot added the awaiting review label May 6, 2023
@EpicWink

EpicWink commented May 6, 2023

Copy link
Copy Markdown
Contributor Author

@willingc ready for review

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@blurb-it
📜🤖 Added by blurb_it.
e5951ac
This was referenced May 6, 2023
gh-96471: Add queue shutdown #96474
Closed
gh-96471: Add queue shutdown, next step. #102499
Closed
@gvanrossum gvanrossum added the topic-asyncio label May 6, 2023
@rhettinger
rhettinger removed their request for review May 6, 2023 19:16
@gvanrossum

gvanrossum commented May 9, 2023

Copy link
Copy Markdown
Member

asyncio-only changes from #102499 (on top of #96474)

I assume the "on top of ..." part is obsolete, since that PR was closed without merging. I'll add @willingc as a reviewer per your request.

EpicWink reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum
gvanrossum requested a review from willingc May 9, 2023 17:56
@gvanrossum

gvanrossum commented Feb 10, 2024

Copy link
Copy Markdown
Member

@EpicWink Could you merge main?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

EpicWink added 2 commits February 20, 2024 20:58
@EpicWink
Merge remote-tracking branch 'upstream/main' into asyncio-queue-shutdown
a72aedd
@EpicWink
Add references in docs and news entry
d5e925d
@EpicWink

EpicWink commented Feb 20, 2024

Copy link
Copy Markdown
Contributor Author

Could you merge main?

Done, but like #104750, we may want to modify the implementation of immediate=True to simply consume the queue rather than having a separate state.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum

gvanrossum commented Feb 20, 2024

Copy link
Copy Markdown
Member

Eh, @EpicWink, did you see the hubbub about the hanging test in your previous PR? The test was disabled because it kept hanging in CI on various platforms. Could you look into what's wrong with it? (At least the feature wasn't reverted.)

YvesDup reacted with eyes emoji
All reactions
  • 👀 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@EpicWink

EpicWink commented Feb 20, 2024

Copy link
Copy Markdown
Contributor Author

Eh, @EpicWink, did you see the hubbub about the hanging test in your previous PR? The test was disabled because it kept hanging in CI on various platforms. Could you look into what's wrong with it?

I did see the follow-on issue and pull-requests. Yves and I are working on fixing it (you can follow the changes here: main...EpicWink:cpython:fix-thread-queue-shutdown-test)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum

gvanrossum commented Feb 21, 2024

Copy link
Copy Markdown
Member

Awesome! (An acknowledgement that you were working on it would have lessened my stress. :-)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum

gvanrossum commented Feb 22, 2024

Copy link
Copy Markdown
Member

Looking at this with an eye towards review, I realized that the threaded-queue implementation doesn't appear to match its documentation: It appears that q.join() does not raise ShutDown when the queue is shutdown immediately. The tests don't seem to be testing for this either. (Come to think of it, the test never seems to take the except self.queue.ShutDown path -- if I put a breakpoint there it never gets hit during any of the tests. The test logic is pretty convoluted, which is my only excuse for not having caught this in the review of gh-104750.)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum gvanrossum mentioned this pull request Feb 22, 2024
gh-96471: Add threading queue shutdown #104750
Merged
@EpicWink

EpicWink commented Feb 22, 2024 via email

Copy link
Copy Markdown
Contributor Author
Now that the immediate-consume implementation of the threading queue shutdown has been accepted, I'm going to do the same here and for multiprocessing. I'll personally rewrite the tests to be more readable and obvious. Laurie
…
________________________________ From: Guido van Rossum ***@***.***> Sent: Thursday, February 22, 2024 11:00:09 AM To: python/cpython ***@***.***> Cc: Laurie O ***@***.***>; Mention ***@***.***> Subject: Re: [python/cpython] gh-96471: Add asyncio queue shutdown (PR #104228) Looking at this with an eye towards review, I realized that the threaded-queue implementation doesn't appear to match its documentation: It appears that q.join() does not raise ShutDown when the queue is shutdown immediately. The tests don't seem to be testing for this either. (Come to think of it, the test never seems to take the except self.queue.ShutDown path -- if I put a breakpoint there it never gets hit during any of the tests. The test logic is pretty convoluted, which is my only excuse for not having caught this in the review of gh-104750<#104750>.) — Reply to this email directly, view it on GitHub<#104228 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AF72GRNKMPJRCRIJHOB4NUDYU2KBTAVCNFSM6AAAAAAXX3PWIGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNJYGQ3TENZYGQ>. You are receiving this because you were mentioned.Message ID: ***@***.***>
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum

gvanrossum commented Feb 22, 2024

Copy link
Copy Markdown
Member

Now that the immediate-consume implementation of the threading queue shutdown has been accepted, I'm going to do the same here and for multiprocessing. I'll personally rewrite the tests to be more readable and obvious.

And what about queue.Queue.join()? Should it raise after shutdown(immediate=True)? Either way some changes are needed -- either in the implementation or in the docs. And the tests there too (what you wrote above appears to apply to the asyncio and multiprocessing versions only.)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

gvanrossum
gvanrossum reviewed Feb 22, 2024
View reviewed changes

@gvanrossum gvanrossum left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll wait reviewing until you've rewritten shutdown, but here's one doc markup nit.

Also, please mark PRs that aren't ready for review as Draft.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Doc/library/asyncio-queue.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

@EpicWink
EpicWink marked this pull request as draft February 22, 2024 01:14
@bedevere-app bedevere-app Bot removed the awaiting review label Feb 22, 2024
@EpicWink

EpicWink commented Feb 22, 2024

Copy link
Copy Markdown
Contributor Author

And what about queue.Queue.join()? Should it raise after shutdown(immediate=True)? Either way some changes are needed -- either in the implementation or in the docs. And the tests there too (what you wrote above appears to apply to the asyncio and multiprocessing versions only.)

The behaviour should (and I intend to implement it to) be the same between the threading, multiprocessing and asyncio queues

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@YvesDup

YvesDup commented Feb 22, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

By the way, should task_done() raise an exception after shutdown or not ?
update; see https://docs.python.org/3.13/library/queue.html#queue.Queue.task_done

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@EpicWink

EpicWink commented Feb 25, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

By the way, should task_done() raise an exception after shutdown or not ?

@YvesDup No (except the usual ValueError); see #115838

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

EpicWink added 6 commits April 4, 2024 11:20
@EpicWink
Format shutdown docstring
d49c6dd
@EpicWink
Check for 0 unfinised tasks in shutdown
5a435a6
@EpicWink
Use asyncio.sleep to run other tasks
c8db40e
@EpicWink
Use public method to shut down queue in format test
ca01ee1
@EpicWink
Only start queue join after shutdown in test
b02c4dd
@EpicWink
Test join before failing task-done
8deca77
@EpicWink

EpicWink commented Apr 4, 2024

Copy link
Copy Markdown
Contributor Author

I want to trust that you two have done the right thing there

@gvanrossum please don't trust, have you seen xz-utils's backdoor?

but not push until the big test run completes? (Buildbot tests can take many hours, sorry.)

Oops, sorry. I forgot to hold off my most recent push

ALso, why is the DO-NOT-MERGE label set? Is it because of #104228?

No, I think it was because I hadn't updated the implementation to match the new agreed-upon behaviour (this PR was in draft at that time anyway, so I don't think the label was needed).

wondering why you always wake up all getters -- and came to the conclusion that it is needed

I should probably add a comment

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@EpicWink EpicWink mentioned this pull request Apr 4, 2024
Queue non-immediate shutdown doesn't unblock getters #117531
Closed
@EpicWink

EpicWink commented Apr 4, 2024

Copy link
Copy Markdown
Contributor Author

there is the same bug on threading queue shutdown. I will open an issue.

@YvesDup I've created issue #117531, and fix in PR #117532

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

YvesDup
YvesDup reviewed Apr 4, 2024
View reviewed changes
Comment thread Lib/test/test_asyncio/test_queues.py
# Setup queue with 2 items (1 retrieved), and a join() task
q = self.q_class()
loop = asyncio.get_running_loop()
q.put_nowait("data")

@YvesDup YvesDup Apr 4, 2024

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest:

q.put_nowait("data1")
q.put_nowait("data2")

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
YvesDup
YvesDup reviewed Apr 4, 2024
View reviewed changes
Comment thread Lib/test/test_asyncio/test_queues.py
q.put_nowait("data")
q.put_nowait("data")
join_task = loop.create_task(q.join())
self.assertEqual(await q.get(), "data")

@YvesDup YvesDup Apr 4, 2024

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and testing on "data1".

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@EpicWink EpicWink Apr 4, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except when q is an instance of LifoQueue, when the value should be "data2". Is it necessary to test queue ordering in the shutdown tests?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@YvesDup YvesDup Apr 4, 2024

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot the LifoQueue class. Is this worth commenting on?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@EpicWink EpicWink Apr 4, 2024

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have implemented your suggestion, but I have not committed. I am considering it. I don't think it's necessary.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@YvesDup YvesDup Apr 4, 2024

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test case (thus including LifoQueue) is implicit. A comment would be enough.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@YvesDup

YvesDup commented Apr 4, 2024

Copy link
Copy Markdown
Contributor

there is the same bug on threading queue shutdown. I will open an issue.

@YvesDup I've created issue #117531, and fix in PR #117532

I have seen and commented

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

YvesDup
YvesDup reviewed Apr 4, 2024
View reviewed changes
Comment thread Lib/asyncio/queues.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum gvanrossum removed the DO-NOT-MERGE label Apr 6, 2024
gvanrossum
gvanrossum approved these changes Apr 6, 2024
View reviewed changes

@gvanrossum gvanrossum left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup! This version looks great. Let me know if you agree -- I've removed the DO-NOT-MERGE label, but I'll wait until you and @YvesDup are happy too.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Mohsin1910 reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting review labels Apr 6, 2024
@EpicWink

EpicWink commented Apr 6, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

I think it's good to go

wondering why you always wake up all getters -- and came to the conclusion that it is needed

I should probably add a comment

I could do this, but I don't think it's worth revoking the PR's approval

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum
gvanrossum merged commit df4d84c into python:main Apr 6, 2024
@bedevere-app bedevere-app Bot removed the awaiting merge label Apr 6, 2024
YvesDup
YvesDup reviewed Apr 6, 2024
View reviewed changes
Comment thread Doc/library/asyncio-queue.rst
All blocked callers of :meth:`~Queue.put` will be unblocked. If
*immediate* is true, also unblock callers of :meth:`~Queue.get`
and :meth:`~Queue.join`.

@YvesDup YvesDup Apr 6, 2024

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry but I have a doubt, shouldn't this documentation block be rather:

    All blocked callers of :meth:`~Queue.put` and :meth:`~Queue.get` 
    will be unblocked. If *immediate* is true, also unblock callers of 
    :meth:`~Queue.join`.

In event of change, the docstring of the shutdown method must be updated.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@EpicWink EpicWink Apr 6, 2024

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

join callers aren't necessarily even unblocked anyway, if consumers are processing any items. I should probably say that a task is marked as done for each item in the queue if immediate shutdown.

Also, I think the threading queue docs are the same.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@YvesDup YvesDup Apr 7, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a task is marked as done for each item in the queue if immediate shutdown.

It's very precise, better.

Also, I think the threading queue docs are the same.

Yes, I commented here so as not to forget (see #117532 (comment)).

English is your native language, I think it'is best if you update documentations and docstrings.

Update: but I can create the follow-up PR.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@EpicWink EpicWink Apr 8, 2024

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made a PR: #117621

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

YvesDup reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
YvesDup
YvesDup reviewed Apr 6, 2024
View reviewed changes
Comment thread Lib/asyncio/queues.py

All blocked callers of put() will be unblocked, and also get()
and join() if 'immediate'.
"""

@YvesDup YvesDup Apr 6, 2024

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstring to modify depending of agree/disagree on my first remark about `blocked callers'.
Changes could be:

All blocked callers of put() and get() will be unblocked, and
also join() if 'immediate

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
YvesDup
YvesDup reviewed Apr 6, 2024
View reviewed changes
Comment thread Doc/whatsnew/3.13.rst
* Add :meth:`asyncio.Queue.shutdown` (along with
:exc:`asyncio.QueueShutDown`) for queue termination.
(Contributed by Laurie Opperman in :gh:`104228`.)

@YvesDup YvesDup Apr 6, 2024

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've worked well together, I'd be nice if you'd mention me.
:-)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@gvanrossum

gvanrossum commented Apr 6, 2024

Copy link
Copy Markdown
Member

Sorry for merging prematurely. @EpicWink Can you prepare a follow-up PR? I will merge it as soon as @YvesDup approves it. (Or, alternatively, @YvesDup can make a PR and I will merge when @EpicWink approves.)

Mohsin1910 reacted with thumbs up emoji EpicWink reacted with eyes emoji
All reactions
  • 👍 1 reaction
  • 👀 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@EpicWink
EpicWink deleted the asyncio-queue-shutdown branch April 8, 2024 00:49
@EpicWink EpicWink mentioned this pull request Apr 8, 2024
gh-96471: Correct documentation for asyncio queue shutdown #117621
Merged
@EpicWink

EpicWink commented Apr 8, 2024

Copy link
Copy Markdown
Contributor Author

@gvanrossum see #117621

YvesDup reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

diegorusso pushed a commit to diegorusso/cpython that referenced this pull request Apr 17, 2024
@EpicWink @YvesDup @diegorusso
pythongh-96471: Add asyncio queue shutdown (python#104228)
21be21c
Co-authored-by: Duprat <[email protected]>
@john-parton

john-parton commented Aug 27, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

I'd like to add that the shutdown() method and task groups makes certain patterns really easy to express. I was struggling with how to properly make a generic async map function with a fixed number of workers (mostly as an exercise), but when I saw the new shutdown method, it came together really easily:

async def async_map[T, R](
    func: Callable[[T], Awaitable[R]],
    iterable: AsyncIterable[T],
    *,
    limit: int,
    maxsize: int = -1,
) -> AsyncIterator[R]:
    if maxsize < 0:
        maxsize = limit

    arguments_queue = Queue[T](maxsize=maxsize)
    results_queue = Queue[R](maxsize=maxsize)

    async def drain():
        async for argument in iterable:
            await arguments_queue.put(argument)
        arguments_queue.shutdown(immediate=False)

    async def worker():
        while True:
            try:
                argument = await arguments_queue.get()
            except QueueShutDown:
                break
            await results_queue.put(await func(argument))

    async def background():
        async with asyncio.TaskGroup() as background_task_group:
            background_task_group.create_task(drain())
            for _ in range(limit):
                background_task_group.create_task(worker())
        results_queue.shutdown(immediate=False)
 
    async with asyncio.TaskGroup() as task_group:
        task_group.create_task(background())

        while True:
            try:
                yield await results_queue.get()
            except QueueShutDown:
                break

I believe this has a common issue that a lot of async generators do, in that if you don't consume the entire generator, it will still continue processing and end up with a lot of futures never awaited.

I know there's some backports. Is there a backports package for asyncio stuff already?

aalekhpatel07 reacted with heart emoji
All reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@YvesDup YvesDup mentioned this pull request Sep 12, 2025
gh-96471: Add multiprocessing.Queue.shutdown() #138828
Open
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@gvanrossum gvanrossum gvanrossum approved these changes
@willingc willingc Awaiting requested review from willingc willingc is a code owner
+1 more reviewer
@YvesDup YvesDup YvesDup left review comments
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

topic-asyncio

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

6 participants

@EpicWink @gvanrossum @YvesDup @bedevere-bot @john-parton @willingc
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.