+# This token stream ignores the value of {@link Token#getChannel}. If your
+# parser requires the token stream filter tokens to only those on a particular
+# channel, such as {@link Token#DEFAULT_CHANNEL} or
+# {@link Token#HIDDEN_CHANNEL}, use a filtering token stream such a
+# {@link CommonTokenStream}.
+from io import StringIO
+from antlr4.Token import Token
+from antlr4.error.Errors import IllegalStateException
+
+# need forward declaration
+Lexer = None
+
+# this is just to keep meaningful parameter types to Parser
+class TokenStream(object):
+
+ pass
+
+
+class BufferedTokenStream(TokenStream):
+ __slots__ = ('tokenSource', 'tokens', 'index', 'fetchedEOF')
+
+ def __init__(self, tokenSource:Lexer):
+ # The {@link TokenSource} from which tokens for this stream are fetched.
+ self.tokenSource = tokenSource
+
+ # A collection of all tokens fetched from the token source. The list is
+ # considered a complete view of the input once {@link #fetchedEOF} is set
+ # to {@code true}.
+ self.tokens = []
+
+ # The index into {@link #tokens} of the current token (next token to
+ # {@link #consume}). {@link #tokens}{@code [}{@link #p}{@code ]} should be
+ # {@link #LT LT(1)}.
+ #
+ #
This field is set to -1 when the stream is first constructed or when
+ # {@link #setTokenSource} is called, indicating that the first token has
+ # not yet been fetched from the token source. For additional information,
+ # see the documentation of {@link IntStream} for a description of
+ # Initializing Methods.
+ self.index = -1
+
+ # Indicates whether the {@link Token#EOF} token has been fetched from
+ # {@link #tokenSource} and added to {@link #tokens}. This field improves
+ # performance for the following cases:
+ #
+ #
+ #
{@link #consume}: The lookahead check in {@link #consume} to prevent
+ # consuming the EOF symbol is optimized by checking the values of
+ # {@link #fetchedEOF} and {@link #p} instead of calling {@link #LA}.
+ #
{@link #fetch}: The check to prevent adding multiple EOF symbols into
+ # {@link #tokens} is trivial with this field.
+ #
+ self.fetchedEOF = False
+
+ def mark(self):
+ return 0
+
+ def release(self, marker:int):
+ # no resources to release
+ pass
+
+ def reset(self):
+ self.seek(0)
+
+ def seek(self, index:int):
+ self.lazyInit()
+ self.index = self.adjustSeekIndex(index)
+
+ def get(self, index:int):
+ self.lazyInit()
+ return self.tokens[index]
+
+ def consume(self):
+ skipEofCheck = False
+ if self.index >= 0:
+ if self.fetchedEOF:
+ # the last token in tokens is EOF. skip check if p indexes any
+ # fetched token except the last.
+ skipEofCheck = self.index < len(self.tokens) - 1
+ else:
+ # no EOF token in tokens. skip check if p indexes a fetched token.
+ skipEofCheck = self.index < len(self.tokens)
+ else:
+ # not yet initialized
+ skipEofCheck = False
+
+ if not skipEofCheck and self.LA(1) == Token.EOF:
+ raise IllegalStateException("cannot consume EOF")
+
+ if self.sync(self.index + 1):
+ self.index = self.adjustSeekIndex(self.index + 1)
+
+ # Make sure index {@code i} in tokens has a token.
+ #
+ # @return {@code true} if a token is located at index {@code i}, otherwise
+ # {@code false}.
+ # @see #get(int i)
+ #/
+ def sync(self, i:int):
+ n = i - len(self.tokens) + 1 # how many more elements we need?
+ if n > 0 :
+ fetched = self.fetch(n)
+ return fetched >= n
+ return True
+
+ # Add {@code n} elements to buffer.
+ #
+ # @return The actual number of elements added to the buffer.
+ #/
+ def fetch(self, n:int):
+ if self.fetchedEOF:
+ return 0
+ for i in range(0, n):
+ t = self.tokenSource.nextToken()
+ t.tokenIndex = len(self.tokens)
+ self.tokens.append(t)
+ if t.type==Token.EOF:
+ self.fetchedEOF = True
+ return i + 1
+ return n
+
+
+ # Get all tokens from start..stop inclusively#/
+ def getTokens(self, start:int, stop:int, types:set=None):
+ if start<0 or stop<0:
+ return None
+ self.lazyInit()
+ subset = []
+ if stop >= len(self.tokens):
+ stop = len(self.tokens)-1
+ for i in range(start, stop):
+ t = self.tokens[i]
+ if t.type==Token.EOF:
+ break
+ if types is None or t.type in types:
+ subset.append(t)
+ return subset
+
+ def LA(self, i:int):
+ return self.LT(i).type
+
+ def LB(self, k:int):
+ if (self.index-k) < 0:
+ return None
+ return self.tokens[self.index-k]
+
+ def LT(self, k:int):
+ self.lazyInit()
+ if k==0:
+ return None
+ if k < 0:
+ return self.LB(-k)
+ i = self.index + k - 1
+ self.sync(i)
+ if i >= len(self.tokens): # return EOF token
+ # EOF must be last token
+ return self.tokens[len(self.tokens)-1]
+ return self.tokens[i]
+
+ # Allowed derived classes to modify the behavior of operations which change
+ # the current stream position by adjusting the target token index of a seek
+ # operation. The default implementation simply returns {@code i}. If an
+ # exception is thrown in this method, the current stream index should not be
+ # changed.
+ #
+ #
For example, {@link CommonTokenStream} overrides this method to ensure that
+ # the seek target is always an on-channel token.
+ #
+ # @param i The target token index.
+ # @return The adjusted target token index.
+
+ def adjustSeekIndex(self, i:int):
+ return i
+
+ def lazyInit(self):
+ if self.index == -1:
+ self.setup()
+
+ def setup(self):
+ self.sync(0)
+ self.index = self.adjustSeekIndex(0)
+
+ # Reset this token stream by setting its token source.#/
+ def setTokenSource(self, tokenSource:Lexer):
+ self.tokenSource = tokenSource
+ self.tokens = []
+ self.index = -1
+ self.fetchedEOF = False
+
+
+ # Given a starting index, return the index of the next token on channel.
+ # Return i if tokens[i] is on channel. Return the index of the EOF token
+ # if there are no tokens on channel between i and EOF.
+ #/
+ def nextTokenOnChannel(self, i:int, channel:int):
+ self.sync(i)
+ if i>=len(self.tokens):
+ return len(self.tokens) - 1
+ token = self.tokens[i]
+ while token.channel!=channel:
+ if token.type==Token.EOF:
+ return i
+ i += 1
+ self.sync(i)
+ token = self.tokens[i]
+ return i
+
+ # Given a starting index, return the index of the previous token on channel.
+ # Return i if tokens[i] is on channel. Return -1 if there are no tokens
+ # on channel between i and 0.
+ def previousTokenOnChannel(self, i:int, channel:int):
+ while i>=0 and self.tokens[i].channel!=channel:
+ i -= 1
+ return i
+
+ # Collect all tokens on specified channel to the right of
+ # the current token up until we see a token on DEFAULT_TOKEN_CHANNEL or
+ # EOF. If channel is -1, find any non default channel token.
+ def getHiddenTokensToRight(self, tokenIndex:int, channel:int=-1):
+ self.lazyInit()
+ if tokenIndex<0 or tokenIndex>=len(self.tokens):
+ raise Exception(str(tokenIndex) + " not in 0.." + str(len(self.tokens)-1))
+ from antlr4.Lexer import Lexer
+ nextOnChannel = self.nextTokenOnChannel(tokenIndex + 1, Lexer.DEFAULT_TOKEN_CHANNEL)
+ from_ = tokenIndex+1
+ # if none onchannel to right, nextOnChannel=-1 so set to = last token
+ to = (len(self.tokens)-1) if nextOnChannel==-1 else nextOnChannel
+ return self.filterForChannel(from_, to, channel)
+
+
+ # Collect all tokens on specified channel to the left of
+ # the current token up until we see a token on DEFAULT_TOKEN_CHANNEL.
+ # If channel is -1, find any non default channel token.
+ def getHiddenTokensToLeft(self, tokenIndex:int, channel:int=-1):
+ self.lazyInit()
+ if tokenIndex<0 or tokenIndex>=len(self.tokens):
+ raise Exception(str(tokenIndex) + " not in 0.." + str(len(self.tokens)-1))
+ from antlr4.Lexer import Lexer
+ prevOnChannel = self.previousTokenOnChannel(tokenIndex - 1, Lexer.DEFAULT_TOKEN_CHANNEL)
+ if prevOnChannel == tokenIndex - 1:
+ return None
+ # if none on channel to left, prevOnChannel=-1 then from=0
+ from_ = prevOnChannel+1
+ to = tokenIndex-1
+ return self.filterForChannel(from_, to, channel)
+
+
+ def filterForChannel(self, left:int, right:int, channel:int):
+ hidden = []
+ for i in range(left, right+1):
+ t = self.tokens[i]
+ if channel==-1:
+ from antlr4.Lexer import Lexer
+ if t.channel!= Lexer.DEFAULT_TOKEN_CHANNEL:
+ hidden.append(t)
+ elif t.channel==channel:
+ hidden.append(t)
+ if len(hidden)==0:
+ return None
+ return hidden
+
+ def getSourceName(self):
+ return self.tokenSource.getSourceName()
+
+ # Get the text of all tokens in this buffer.#/
+ def getText(self, start:int=None, stop:int=None):
+ self.lazyInit()
+ self.fill()
+ if isinstance(start, Token):
+ start = start.tokenIndex
+ elif start is None:
+ start = 0
+ if isinstance(stop, Token):
+ stop = stop.tokenIndex
+ elif stop is None or stop >= len(self.tokens):
+ stop = len(self.tokens) - 1
+ if start < 0 or stop < 0 or stop < start:
+ return ""
+ with StringIO() as buf:
+ for i in range(start, stop+1):
+ t = self.tokens[i]
+ if t.type==Token.EOF:
+ break
+ buf.write(t.text)
+ return buf.getvalue()
+
+
+ # Get all tokens from lexer until EOF#/
+ def fill(self):
+ self.lazyInit()
+ while self.fetch(1000)==1000:
+ pass
diff --git a/venv/Lib/site-packages/antlr4/CommonTokenFactory.py b/venv/Lib/site-packages/antlr4/CommonTokenFactory.py
new file mode 100644
index 0000000000000000000000000000000000000000..0d09ad78598de14f7a32d813c667e877ef1c0f6c
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/CommonTokenFactory.py
@@ -0,0 +1,61 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+#
+# This default implementation of {@link TokenFactory} creates
+# {@link CommonToken} objects.
+#
+from antlr4.Token import CommonToken
+
+class TokenFactory(object):
+
+ pass
+
+class CommonTokenFactory(TokenFactory):
+ __slots__ = 'copyText'
+
+ #
+ # The default {@link CommonTokenFactory} instance.
+ #
+ #
+ # This token factory does not explicitly copy token text when constructing
+ # tokens.
+ #
+ DEFAULT = None
+
+ def __init__(self, copyText:bool=False):
+ # Indicates whether {@link CommonToken#setText} should be called after
+ # constructing tokens to explicitly set the text. This is useful for cases
+ # where the input stream might not be able to provide arbitrary substrings
+ # of text from the input after the lexer creates a token (e.g. the
+ # implementation of {@link CharStream#getText} in
+ # {@link UnbufferedCharStream} throws an
+ # {@link UnsupportedOperationException}). Explicitly setting the token text
+ # allows {@link Token#getText} to be called at any time regardless of the
+ # input stream implementation.
+ #
+ #
+ # The default value is {@code false} to avoid the performance and memory
+ # overhead of copying text for every token unless explicitly requested.
+ #
+ self.copyText = copyText
+
+ def create(self, source, type:int, text:str, channel:int, start:int, stop:int, line:int, column:int):
+ t = CommonToken(source, type, channel, start, stop)
+ t.line = line
+ t.column = column
+ if text is not None:
+ t.text = text
+ elif self.copyText and source[1] is not None:
+ t.text = source[1].getText(start,stop)
+ return t
+
+ def createThin(self, type:int, text:str):
+ t = CommonToken(type=type)
+ t.text = text
+ return t
+
+CommonTokenFactory.DEFAULT = CommonTokenFactory()
diff --git a/venv/Lib/site-packages/antlr4/CommonTokenStream.py b/venv/Lib/site-packages/antlr4/CommonTokenStream.py
new file mode 100644
index 0000000000000000000000000000000000000000..dd0a984e33fe42b3499844705b698953e7f04af9
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/CommonTokenStream.py
@@ -0,0 +1,87 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+
+#
+# This class extends {@link BufferedTokenStream} with functionality to filter
+# token streams to tokens on a particular channel (tokens where
+# {@link Token#getChannel} returns a particular value).
+#
+#
+# This token stream provides access to all tokens by index or when calling
+# methods like {@link #getText}. The channel filtering is only used for code
+# accessing tokens via the lookahead methods {@link #LA}, {@link #LT}, and
+# {@link #LB}.
+#
+#
+# By default, tokens are placed on the default channel
+# ({@link Token#DEFAULT_CHANNEL}), but may be reassigned by using the
+# {@code ->channel(HIDDEN)} lexer command, or by using an embedded action to
+# call {@link Lexer#setChannel}.
+#
+#
+#
+# Note: lexer rules which use the {@code ->skip} lexer command or call
+# {@link Lexer#skip} do not produce tokens at all, so input text matched by
+# such a rule will not be available as part of the token stream, regardless of
+# channel.
+#/
+
+from antlr4.BufferedTokenStream import BufferedTokenStream
+from antlr4.Lexer import Lexer
+from antlr4.Token import Token
+
+
+class CommonTokenStream(BufferedTokenStream):
+ __slots__ = 'channel'
+
+ def __init__(self, lexer:Lexer, channel:int=Token.DEFAULT_CHANNEL):
+ super().__init__(lexer)
+ self.channel = channel
+
+ def adjustSeekIndex(self, i:int):
+ return self.nextTokenOnChannel(i, self.channel)
+
+ def LB(self, k:int):
+ if k==0 or (self.index-k)<0:
+ return None
+ i = self.index
+ n = 1
+ # find k good tokens looking backwards
+ while n <= k:
+ # skip off-channel tokens
+ i = self.previousTokenOnChannel(i - 1, self.channel)
+ n += 1
+ if i < 0:
+ return None
+ return self.tokens[i]
+
+ def LT(self, k:int):
+ self.lazyInit()
+ if k == 0:
+ return None
+ if k < 0:
+ return self.LB(-k)
+ i = self.index
+ n = 1 # we know tokens[pos] is a good one
+ # find k good tokens
+ while n < k:
+ # skip off-channel tokens, but make sure to not look past EOF
+ if self.sync(i + 1):
+ i = self.nextTokenOnChannel(i + 1, self.channel)
+ n += 1
+ return self.tokens[i]
+
+ # Count EOF just once.#/
+ def getNumberOfOnChannelTokens(self):
+ n = 0
+ self.fill()
+ for i in range(0, len(self.tokens)):
+ t = self.tokens[i]
+ if t.channel==self.channel:
+ n += 1
+ if t.type==Token.EOF:
+ break
+ return n
diff --git a/venv/Lib/site-packages/antlr4/FileStream.py b/venv/Lib/site-packages/antlr4/FileStream.py
new file mode 100644
index 0000000000000000000000000000000000000000..1c6ce9fbc02a6f42965f44d5df0a55787626d7eb
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/FileStream.py
@@ -0,0 +1,27 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+#
+# This is an InputStream that is loaded from a file all at once
+# when you construct the object.
+#
+
+import codecs
+from antlr4.InputStream import InputStream
+
+
+class FileStream(InputStream):
+ __slots__ = 'fileName'
+
+ def __init__(self, fileName:str, encoding:str='ascii', errors:str='strict'):
+ super().__init__(self.readDataFrom(fileName, encoding, errors))
+ self.fileName = fileName
+
+ def readDataFrom(self, fileName:str, encoding:str, errors:str='strict'):
+ # read binary to avoid line ending conversion
+ with open(fileName, 'rb') as file:
+ bytes = file.read()
+ return codecs.decode(bytes, encoding, errors)
diff --git a/venv/Lib/site-packages/antlr4/InputStream.py b/venv/Lib/site-packages/antlr4/InputStream.py
new file mode 100644
index 0000000000000000000000000000000000000000..5d077d13576d2fd5f91153608f91e907092b87d5
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/InputStream.py
@@ -0,0 +1,87 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+
+#
+# Vacuum all input from a string and then treat it like a buffer.
+#
+from antlr4.Token import Token
+
+
+class InputStream (object):
+ __slots__ = ('name', 'strdata', '_index', 'data', '_size')
+
+ def __init__(self, data: str):
+ self.name = ""
+ self.strdata = data
+ self._loadString()
+
+ def _loadString(self):
+ self._index = 0
+ self.data = [ord(c) for c in self.strdata]
+ self._size = len(self.data)
+
+ @property
+ def index(self):
+ return self._index
+
+ @property
+ def size(self):
+ return self._size
+
+ # Reset the stream so that it's in the same state it was
+ # when the object was created *except* the data array is not
+ # touched.
+ #
+ def reset(self):
+ self._index = 0
+
+ def consume(self):
+ if self._index >= self._size:
+ assert self.LA(1) == Token.EOF
+ raise Exception("cannot consume EOF")
+ self._index += 1
+
+ def LA(self, offset: int):
+ if offset==0:
+ return 0 # undefined
+ if offset<0:
+ offset += 1 # e.g., translate LA(-1) to use offset=0
+ pos = self._index + offset - 1
+ if pos < 0 or pos >= self._size: # invalid
+ return Token.EOF
+ return self.data[pos]
+
+ def LT(self, offset: int):
+ return self.LA(offset)
+
+ # mark/release do nothing; we have entire buffer
+ def mark(self):
+ return -1
+
+ def release(self, marker: int):
+ pass
+
+ # consume() ahead until p==_index; can't just set p=_index as we must
+ # update line and column. If we seek backwards, just set p
+ #
+ def seek(self, _index: int):
+ if _index<=self._index:
+ self._index = _index # just jump; don't update stream state (line, ...)
+ return
+ # seek forward
+ self._index = min(_index, self._size)
+
+ def getText(self, start :int, stop: int):
+ if stop >= self._size:
+ stop = self._size-1
+ if start >= self._size:
+ return ""
+ else:
+ return self.strdata[start:stop+1]
+
+ def __str__(self):
+ return self.strdata
diff --git a/venv/Lib/site-packages/antlr4/IntervalSet.py b/venv/Lib/site-packages/antlr4/IntervalSet.py
new file mode 100644
index 0000000000000000000000000000000000000000..fda8e6da3f69ba12147fdcb61268f7000d55d635
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/IntervalSet.py
@@ -0,0 +1,180 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+from io import StringIO
+from antlr4.Token import Token
+
+# need forward declarations
+IntervalSet = None
+
+class IntervalSet(object):
+ __slots__ = ('intervals', 'readonly')
+
+ def __init__(self):
+ self.intervals = None
+ self.readonly = False
+
+ def __iter__(self):
+ if self.intervals is not None:
+ for i in self.intervals:
+ for c in i:
+ yield c
+
+ def __getitem__(self, item):
+ i = 0
+ for k in self:
+ if i==item:
+ return k
+ else:
+ i += 1
+ return Token.INVALID_TYPE
+
+ def addOne(self, v:int):
+ self.addRange(range(v, v+1))
+
+ def addRange(self, v:range):
+ if self.intervals is None:
+ self.intervals = list()
+ self.intervals.append(v)
+ else:
+ # find insert pos
+ k = 0
+ for i in self.intervals:
+ # distinct range -> insert
+ if v.stop adjust
+ elif v.stop==i.start:
+ self.intervals[k] = range(v.start, i.stop)
+ return
+ # overlapping range -> adjust and reduce
+ elif v.start<=i.stop:
+ self.intervals[k] = range(min(i.start,v.start), max(i.stop,v.stop))
+ self.reduce(k)
+ return
+ k += 1
+ # greater than any existing
+ self.intervals.append(v)
+
+ def addSet(self, other:IntervalSet):
+ if other.intervals is not None:
+ for i in other.intervals:
+ self.addRange(i)
+ return self
+
+ def reduce(self, k:int):
+ # only need to reduce if k is not the last
+ if k= r.stop:
+ self.intervals.pop(k+1)
+ self.reduce(k)
+ elif l.stop >= r.start:
+ self.intervals[k] = range(l.start, r.stop)
+ self.intervals.pop(k+1)
+
+ def complement(self, start, stop):
+ result = IntervalSet()
+ result.addRange(range(start,stop+1))
+ for i in self.intervals:
+ result.removeRange(i)
+ return result
+
+ def __contains__(self, item):
+ if self.intervals is None:
+ return False
+ else:
+ return any(item in i for i in self.intervals)
+
+ def __len__(self):
+ return sum(len(i) for i in self.intervals)
+
+ def removeRange(self, v):
+ if v.start==v.stop-1:
+ self.removeOne(v.start)
+ elif self.intervals is not None:
+ k = 0
+ for i in self.intervals:
+ # intervals are ordered
+ if v.stop<=i.start:
+ return
+ # check for including range, split it
+ elif v.start>i.start and v.stop=i.stop:
+ self.intervals.pop(k)
+ k -= 1 # need another pass
+ # check for lower boundary
+ elif v.start1:
+ buf.write("{")
+ first = True
+ for i in self.intervals:
+ for j in i:
+ if not first:
+ buf.write(", ")
+ buf.write(self.elementName(literalNames, symbolicNames, j))
+ first = False
+ if len(self)>1:
+ buf.write("}")
+ return buf.getvalue()
+
+ def elementName(self, literalNames:list, symbolicNames:list, a:int):
+ if a==Token.EOF:
+ return ""
+ elif a==Token.EPSILON:
+ return ""
+ else:
+ if a":
+ return literalNames[a]
+ if a"
diff --git a/venv/Lib/site-packages/antlr4/LL1Analyzer.py b/venv/Lib/site-packages/antlr4/LL1Analyzer.py
new file mode 100644
index 0000000000000000000000000000000000000000..ac149fa2f1d23903ef60593521291c4d9f1945a4
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/LL1Analyzer.py
@@ -0,0 +1,173 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+from antlr4.IntervalSet import IntervalSet
+from antlr4.Token import Token
+from antlr4.PredictionContext import PredictionContext, SingletonPredictionContext, PredictionContextFromRuleContext
+from antlr4.RuleContext import RuleContext
+from antlr4.atn.ATN import ATN
+from antlr4.atn.ATNConfig import ATNConfig
+from antlr4.atn.ATNState import ATNState, RuleStopState
+from antlr4.atn.Transition import WildcardTransition, NotSetTransition, AbstractPredicateTransition, RuleTransition
+
+
+class LL1Analyzer (object):
+ __slots__ = 'atn'
+
+ #* Special value added to the lookahead sets to indicate that we hit
+ # a predicate during analysis if {@code seeThruPreds==false}.
+ #/
+ HIT_PRED = Token.INVALID_TYPE
+
+ def __init__(self, atn:ATN):
+ self.atn = atn
+
+ #*
+ # Calculates the SLL(1) expected lookahead set for each outgoing transition
+ # of an {@link ATNState}. The returned array has one element for each
+ # outgoing transition in {@code s}. If the closure from transition
+ # i leads to a semantic predicate before matching a symbol, the
+ # element at index i of the result will be {@code null}.
+ #
+ # @param s the ATN state
+ # @return the expected symbols for each outgoing transition of {@code s}.
+ #/
+ def getDecisionLookahead(self, s:ATNState):
+ if s is None:
+ return None
+
+ count = len(s.transitions)
+ look = [] * count
+ for alt in range(0, count):
+ look[alt] = set()
+ lookBusy = set()
+ seeThruPreds = False # fail to get lookahead upon pred
+ self._LOOK(s.transition(alt).target, None, PredictionContext.EMPTY,
+ look[alt], lookBusy, set(), seeThruPreds, False)
+ # Wipe out lookahead for this alternative if we found nothing
+ # or we had a predicate when we !seeThruPreds
+ if len(look[alt])==0 or self.HIT_PRED in look[alt]:
+ look[alt] = None
+ return look
+
+ #*
+ # Compute set of tokens that can follow {@code s} in the ATN in the
+ # specified {@code ctx}.
+ #
+ #
If {@code ctx} is {@code null} and the end of the rule containing
+ # {@code s} is reached, {@link Token#EPSILON} is added to the result set.
+ # If {@code ctx} is not {@code null} and the end of the outermost rule is
+ # reached, {@link Token#EOF} is added to the result set.
+ #
+ # @param s the ATN state
+ # @param stopState the ATN state to stop at. This can be a
+ # {@link BlockEndState} to detect epsilon paths through a closure.
+ # @param ctx the complete parser context, or {@code null} if the context
+ # should be ignored
+ #
+ # @return The set of tokens that can follow {@code s} in the ATN in the
+ # specified {@code ctx}.
+ #/
+ def LOOK(self, s:ATNState, stopState:ATNState=None, ctx:RuleContext=None):
+ r = IntervalSet()
+ seeThruPreds = True # ignore preds; get all lookahead
+ lookContext = PredictionContextFromRuleContext(s.atn, ctx) if ctx is not None else None
+ self._LOOK(s, stopState, lookContext, r, set(), set(), seeThruPreds, True)
+ return r
+
+ #*
+ # Compute set of tokens that can follow {@code s} in the ATN in the
+ # specified {@code ctx}.
+ #
+ #
If {@code ctx} is {@code null} and {@code stopState} or the end of the
+ # rule containing {@code s} is reached, {@link Token#EPSILON} is added to
+ # the result set. If {@code ctx} is not {@code null} and {@code addEOF} is
+ # {@code true} and {@code stopState} or the end of the outermost rule is
+ # reached, {@link Token#EOF} is added to the result set.
+ #
+ # @param s the ATN state.
+ # @param stopState the ATN state to stop at. This can be a
+ # {@link BlockEndState} to detect epsilon paths through a closure.
+ # @param ctx The outer context, or {@code null} if the outer context should
+ # not be used.
+ # @param look The result lookahead set.
+ # @param lookBusy A set used for preventing epsilon closures in the ATN
+ # from causing a stack overflow. Outside code should pass
+ # {@code new HashSet} for this argument.
+ # @param calledRuleStack A set used for preventing left recursion in the
+ # ATN from causing a stack overflow. Outside code should pass
+ # {@code new BitSet()} for this argument.
+ # @param seeThruPreds {@code true} to true semantic predicates as
+ # implicitly {@code true} and "see through them", otherwise {@code false}
+ # to treat semantic predicates as opaque and add {@link #HIT_PRED} to the
+ # result if one is encountered.
+ # @param addEOF Add {@link Token#EOF} to the result if the end of the
+ # outermost context is reached. This parameter has no effect if {@code ctx}
+ # is {@code null}.
+ #/
+ def _LOOK(self, s:ATNState, stopState:ATNState , ctx:PredictionContext, look:IntervalSet, lookBusy:set,
+ calledRuleStack:set, seeThruPreds:bool, addEOF:bool):
+ c = ATNConfig(s, 0, ctx)
+
+ if c in lookBusy:
+ return
+ lookBusy.add(c)
+
+ if s == stopState:
+ if ctx is None:
+ look.addOne(Token.EPSILON)
+ return
+ elif ctx.isEmpty() and addEOF:
+ look.addOne(Token.EOF)
+ return
+
+ if isinstance(s, RuleStopState ):
+ if ctx is None:
+ look.addOne(Token.EPSILON)
+ return
+ elif ctx.isEmpty() and addEOF:
+ look.addOne(Token.EOF)
+ return
+
+ if ctx != PredictionContext.EMPTY:
+ removed = s.ruleIndex in calledRuleStack
+ try:
+ calledRuleStack.discard(s.ruleIndex)
+ # run thru all possible stack tops in ctx
+ for i in range(0, len(ctx)):
+ returnState = self.atn.states[ctx.getReturnState(i)]
+ self._LOOK(returnState, stopState, ctx.getParent(i), look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
+ finally:
+ if removed:
+ calledRuleStack.add(s.ruleIndex)
+ return
+
+ for t in s.transitions:
+ if type(t) == RuleTransition:
+ if t.target.ruleIndex in calledRuleStack:
+ continue
+
+ newContext = SingletonPredictionContext.create(ctx, t.followState.stateNumber)
+
+ try:
+ calledRuleStack.add(t.target.ruleIndex)
+ self._LOOK(t.target, stopState, newContext, look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
+ finally:
+ calledRuleStack.remove(t.target.ruleIndex)
+ elif isinstance(t, AbstractPredicateTransition ):
+ if seeThruPreds:
+ self._LOOK(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
+ else:
+ look.addOne(self.HIT_PRED)
+ elif t.isEpsilon:
+ self._LOOK(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
+ elif type(t) == WildcardTransition:
+ look.addRange( range(Token.MIN_USER_TOKEN_TYPE, self.atn.maxTokenType + 1) )
+ else:
+ set_ = t.label
+ if set_ is not None:
+ if isinstance(t, NotSetTransition):
+ set_ = set_.complement(Token.MIN_USER_TOKEN_TYPE, self.atn.maxTokenType)
+ look.addSet(set_)
diff --git a/venv/Lib/site-packages/antlr4/Lexer.py b/venv/Lib/site-packages/antlr4/Lexer.py
new file mode 100644
index 0000000000000000000000000000000000000000..82accadcbca680b48f4c0206731259d32adc299e
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/Lexer.py
@@ -0,0 +1,329 @@
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+
+# A lexer is recognizer that draws input symbols from a character stream.
+# lexer grammars result in a subclass of self object. A Lexer object
+# uses simplified match() and error recovery mechanisms in the interest
+# of speed.
+#/
+from io import StringIO
+
+import sys
+if sys.version_info[1] > 5:
+ from typing import TextIO
+else:
+ from typing.io import TextIO
+from antlr4.CommonTokenFactory import CommonTokenFactory
+from antlr4.atn.LexerATNSimulator import LexerATNSimulator
+from antlr4.InputStream import InputStream
+from antlr4.Recognizer import Recognizer
+from antlr4.Token import Token
+from antlr4.error.Errors import IllegalStateException, LexerNoViableAltException, RecognitionException
+
+class TokenSource(object):
+
+ pass
+
+
+class Lexer(Recognizer, TokenSource):
+ __slots__ = (
+ '_input', '_output', '_factory', '_tokenFactorySourcePair', '_token',
+ '_tokenStartCharIndex', '_tokenStartLine', '_tokenStartColumn',
+ '_hitEOF', '_channel', '_type', '_modeStack', '_mode', '_text'
+ )
+
+ DEFAULT_MODE = 0
+ MORE = -2
+ SKIP = -3
+
+ DEFAULT_TOKEN_CHANNEL = Token.DEFAULT_CHANNEL
+ HIDDEN = Token.HIDDEN_CHANNEL
+ MIN_CHAR_VALUE = 0x0000
+ MAX_CHAR_VALUE = 0x10FFFF
+
+ def __init__(self, input:InputStream, output:TextIO = sys.stdout):
+ super().__init__()
+ self._input = input
+ self._output = output
+ self._factory = CommonTokenFactory.DEFAULT
+ self._tokenFactorySourcePair = (self, input)
+
+ self._interp = None # child classes must populate this
+
+ # The goal of all lexer rules/methods is to create a token object.
+ # self is an instance variable as multiple rules may collaborate to
+ # create a single token. nextToken will return self object after
+ # matching lexer rule(s). If you subclass to allow multiple token
+ # emissions, then set self to the last token to be matched or
+ # something nonnull so that the auto token emit mechanism will not
+ # emit another token.
+ self._token = None
+
+ # What character index in the stream did the current token start at?
+ # Needed, for example, to get the text for current token. Set at
+ # the start of nextToken.
+ self._tokenStartCharIndex = -1
+
+ # The line on which the first character of the token resides#/
+ self._tokenStartLine = -1
+
+ # The character position of first character within the line#/
+ self._tokenStartColumn = -1
+
+ # Once we see EOF on char stream, next token will be EOF.
+ # If you have DONE : EOF ; then you see DONE EOF.
+ self._hitEOF = False
+
+ # The channel number for the current token#/
+ self._channel = Token.DEFAULT_CHANNEL
+
+ # The token type for the current token#/
+ self._type = Token.INVALID_TYPE
+
+ self._modeStack = []
+ self._mode = self.DEFAULT_MODE
+
+ # You can set the text for the current token to override what is in
+ # the input char buffer. Use setText() or can set self instance var.
+ #/
+ self._text = None
+
+
+ def reset(self):
+ # wack Lexer state variables
+ if self._input is not None:
+ self._input.seek(0) # rewind the input
+ self._token = None
+ self._type = Token.INVALID_TYPE
+ self._channel = Token.DEFAULT_CHANNEL
+ self._tokenStartCharIndex = -1
+ self._tokenStartColumn = -1
+ self._tokenStartLine = -1
+ self._text = None
+
+ self._hitEOF = False
+ self._mode = Lexer.DEFAULT_MODE
+ self._modeStack = []
+
+ self._interp.reset()
+
+ # Return a token from self source; i.e., match a token on the char
+ # stream.
+ def nextToken(self):
+ if self._input is None:
+ raise IllegalStateException("nextToken requires a non-null input stream.")
+
+ # Mark start location in char stream so unbuffered streams are
+ # guaranteed at least have text of current token
+ tokenStartMarker = self._input.mark()
+ try:
+ while True:
+ if self._hitEOF:
+ self.emitEOF()
+ return self._token
+ self._token = None
+ self._channel = Token.DEFAULT_CHANNEL
+ self._tokenStartCharIndex = self._input.index
+ self._tokenStartColumn = self._interp.column
+ self._tokenStartLine = self._interp.line
+ self._text = None
+ continueOuter = False
+ while True:
+ self._type = Token.INVALID_TYPE
+ ttype = self.SKIP
+ try:
+ ttype = self._interp.match(self._input, self._mode)
+ except LexerNoViableAltException as e:
+ self.notifyListeners(e) # report error
+ self.recover(e)
+ if self._input.LA(1)==Token.EOF:
+ self._hitEOF = True
+ if self._type == Token.INVALID_TYPE:
+ self._type = ttype
+ if self._type == self.SKIP:
+ continueOuter = True
+ break
+ if self._type!=self.MORE:
+ break
+ if continueOuter:
+ continue
+ if self._token is None:
+ self.emit()
+ return self._token
+ finally:
+ # make sure we release marker after match or
+ # unbuffered char stream will keep buffering
+ self._input.release(tokenStartMarker)
+
+ # Instruct the lexer to skip creating a token for current lexer rule
+ # and look for another token. nextToken() knows to keep looking when
+ # a lexer rule finishes with token set to SKIP_TOKEN. Recall that
+ # if token==null at end of any token rule, it creates one for you
+ # and emits it.
+ #/
+ def skip(self):
+ self._type = self.SKIP
+
+ def more(self):
+ self._type = self.MORE
+
+ def mode(self, m:int):
+ self._mode = m
+
+ def pushMode(self, m:int):
+ if self._interp.debug:
+ print("pushMode " + str(m), file=self._output)
+ self._modeStack.append(self._mode)
+ self.mode(m)
+
+ def popMode(self):
+ if len(self._modeStack)==0:
+ raise Exception("Empty Stack")
+ if self._interp.debug:
+ print("popMode back to "+ self._modeStack[:-1], file=self._output)
+ self.mode( self._modeStack.pop() )
+ return self._mode
+
+ # Set the char stream and reset the lexer#/
+ @property
+ def inputStream(self):
+ return self._input
+
+ @inputStream.setter
+ def inputStream(self, input:InputStream):
+ self._input = None
+ self._tokenFactorySourcePair = (self, self._input)
+ self.reset()
+ self._input = input
+ self._tokenFactorySourcePair = (self, self._input)
+
+ @property
+ def sourceName(self):
+ return self._input.sourceName
+
+ # By default does not support multiple emits per nextToken invocation
+ # for efficiency reasons. Subclass and override self method, nextToken,
+ # and getToken (to push tokens into a list and pull from that list
+ # rather than a single variable as self implementation does).
+ #/
+ def emitToken(self, token:Token):
+ self._token = token
+
+ # The standard method called to automatically emit a token at the
+ # outermost lexical rule. The token object should point into the
+ # char buffer start..stop. If there is a text override in 'text',
+ # use that to set the token's text. Override self method to emit
+ # custom Token objects or provide a new factory.
+ #/
+ def emit(self):
+ t = self._factory.create(self._tokenFactorySourcePair, self._type, self._text, self._channel, self._tokenStartCharIndex,
+ self.getCharIndex()-1, self._tokenStartLine, self._tokenStartColumn)
+ self.emitToken(t)
+ return t
+
+ def emitEOF(self):
+ cpos = self.column
+ lpos = self.line
+ eof = self._factory.create(self._tokenFactorySourcePair, Token.EOF, None, Token.DEFAULT_CHANNEL, self._input.index,
+ self._input.index-1, lpos, cpos)
+ self.emitToken(eof)
+ return eof
+
+ @property
+ def type(self):
+ return self._type
+
+ @type.setter
+ def type(self, type:int):
+ self._type = type
+
+ @property
+ def line(self):
+ return self._interp.line
+
+ @line.setter
+ def line(self, line:int):
+ self._interp.line = line
+
+ @property
+ def column(self):
+ return self._interp.column
+
+ @column.setter
+ def column(self, column:int):
+ self._interp.column = column
+
+ # What is the index of the current character of lookahead?#/
+ def getCharIndex(self):
+ return self._input.index
+
+ # Return the text matched so far for the current token or any
+ # text override.
+ @property
+ def text(self):
+ if self._text is not None:
+ return self._text
+ else:
+ return self._interp.getText(self._input)
+
+ # Set the complete text of self token; it wipes any previous
+ # changes to the text.
+ @text.setter
+ def text(self, txt:str):
+ self._text = txt
+
+ # Return a list of all Token objects in input char stream.
+ # Forces load of all tokens. Does not include EOF token.
+ #/
+ def getAllTokens(self):
+ tokens = []
+ t = self.nextToken()
+ while t.type!=Token.EOF:
+ tokens.append(t)
+ t = self.nextToken()
+ return tokens
+
+ def notifyListeners(self, e:LexerNoViableAltException):
+ start = self._tokenStartCharIndex
+ stop = self._input.index
+ text = self._input.getText(start, stop)
+ msg = "token recognition error at: '" + self.getErrorDisplay(text) + "'"
+ listener = self.getErrorListenerDispatch()
+ listener.syntaxError(self, None, self._tokenStartLine, self._tokenStartColumn, msg, e)
+
+ def getErrorDisplay(self, s:str):
+ with StringIO() as buf:
+ for c in s:
+ buf.write(self.getErrorDisplayForChar(c))
+ return buf.getvalue()
+
+ def getErrorDisplayForChar(self, c:str):
+ if ord(c[0])==Token.EOF:
+ return ""
+ elif c=='\n':
+ return "\\n"
+ elif c=='\t':
+ return "\\t"
+ elif c=='\r':
+ return "\\r"
+ else:
+ return c
+
+ def getCharErrorDisplay(self, c:str):
+ return "'" + self.getErrorDisplayForChar(c) + "'"
+
+ # Lexers can normally match any char in it's vocabulary after matching
+ # a token, so do the easy thing and just kill a character and hope
+ # it all works out. You can instead use the rule invocation stack
+ # to do sophisticated error recovery if you are in a fragment rule.
+ #/
+ def recover(self, re:RecognitionException):
+ if self._input.LA(1) != Token.EOF:
+ if isinstance(re, LexerNoViableAltException):
+ # skip a char and try again
+ self._interp.consume(self._input)
+ else:
+ # TODO: Do we lose character or line position information?
+ self._input.consume()
diff --git a/venv/Lib/site-packages/antlr4/ListTokenSource.py b/venv/Lib/site-packages/antlr4/ListTokenSource.py
new file mode 100644
index 0000000000000000000000000000000000000000..40bcaf94a243e7bd7d2c9b9bfa7f522706a46788
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/ListTokenSource.py
@@ -0,0 +1,144 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+#
+# Provides an implementation of {@link TokenSource} as a wrapper around a list
+# of {@link Token} objects.
+#
+#
If the final token in the list is an {@link Token#EOF} token, it will be used
+# as the EOF token for every call to {@link #nextToken} after the end of the
+# list is reached. Otherwise, an EOF token will be created.
+#
+from antlr4.CommonTokenFactory import CommonTokenFactory
+from antlr4.Lexer import TokenSource
+from antlr4.Token import Token
+
+
+class ListTokenSource(TokenSource):
+ __slots__ = ('tokens', 'sourceName', 'pos', 'eofToken', '_factory')
+
+ # Constructs a new {@link ListTokenSource} instance from the specified
+ # collection of {@link Token} objects and source name.
+ #
+ # @param tokens The collection of {@link Token} objects to provide as a
+ # {@link TokenSource}.
+ # @param sourceName The name of the {@link TokenSource}. If this value is
+ # {@code null}, {@link #getSourceName} will attempt to infer the name from
+ # the next {@link Token} (or the previous token if the end of the input has
+ # been reached).
+ #
+ # @exception NullPointerException if {@code tokens} is {@code null}
+ #
+ def __init__(self, tokens:list, sourceName:str=None):
+ if tokens is None:
+ raise ReferenceError("tokens cannot be null")
+ self.tokens = tokens
+ self.sourceName = sourceName
+ # The index into {@link #tokens} of token to return by the next call to
+ # {@link #nextToken}. The end of the input is indicated by this value
+ # being greater than or equal to the number of items in {@link #tokens}.
+ self.pos = 0
+ # This field caches the EOF token for the token source.
+ self.eofToken = None
+ # This is the backing field for {@link #getTokenFactory} and
+ self._factory = CommonTokenFactory.DEFAULT
+
+
+ #
+ # {@inheritDoc}
+ #
+ @property
+ def column(self):
+ if self.pos < len(self.tokens):
+ return self.tokens[self.pos].column
+ elif self.eofToken is not None:
+ return self.eofToken.column
+ elif len(self.tokens) > 0:
+ # have to calculate the result from the line/column of the previous
+ # token, along with the text of the token.
+ lastToken = self.tokens[len(self.tokens) - 1]
+ tokenText = lastToken.text
+ if tokenText is not None:
+ lastNewLine = tokenText.rfind('\n')
+ if lastNewLine >= 0:
+ return len(tokenText) - lastNewLine - 1
+ return lastToken.column + lastToken.stop - lastToken.start + 1
+
+ # only reach this if tokens is empty, meaning EOF occurs at the first
+ # position in the input
+ return 0
+
+ #
+ # {@inheritDoc}
+ #
+ def nextToken(self):
+ if self.pos >= len(self.tokens):
+ if self.eofToken is None:
+ start = -1
+ if len(self.tokens) > 0:
+ previousStop = self.tokens[len(self.tokens) - 1].stop
+ if previousStop != -1:
+ start = previousStop + 1
+ stop = max(-1, start - 1)
+ self.eofToken = self._factory.create((self, self.getInputStream()),
+ Token.EOF, "EOF", Token.DEFAULT_CHANNEL, start, stop, self.line, self.column)
+ return self.eofToken
+ t = self.tokens[self.pos]
+ if self.pos == len(self.tokens) - 1 and t.type == Token.EOF:
+ self.eofToken = t
+ self.pos += 1
+ return t
+
+ #
+ # {@inheritDoc}
+ #
+ @property
+ def line(self):
+ if self.pos < len(self.tokens):
+ return self.tokens[self.pos].line
+ elif self.eofToken is not None:
+ return self.eofToken.line
+ elif len(self.tokens) > 0:
+ # have to calculate the result from the line/column of the previous
+ # token, along with the text of the token.
+ lastToken = self.tokens[len(self.tokens) - 1]
+ line = lastToken.line
+ tokenText = lastToken.text
+ if tokenText is not None:
+ line += tokenText.count('\n')
+
+ # if no text is available, assume the token did not contain any newline characters.
+ return line
+
+ # only reach this if tokens is empty, meaning EOF occurs at the first
+ # position in the input
+ return 1
+
+ #
+ # {@inheritDoc}
+ #
+ def getInputStream(self):
+ if self.pos < len(self.tokens):
+ return self.tokens[self.pos].getInputStream()
+ elif self.eofToken is not None:
+ return self.eofToken.getInputStream()
+ elif len(self.tokens) > 0:
+ return self.tokens[len(self.tokens) - 1].getInputStream()
+ else:
+ # no input stream information is available
+ return None
+
+ #
+ # {@inheritDoc}
+ #
+ def getSourceName(self):
+ if self.sourceName is not None:
+ return self.sourceName
+ inputStream = self.getInputStream()
+ if inputStream is not None:
+ return inputStream.getSourceName()
+ else:
+ return "List"
diff --git a/venv/Lib/site-packages/antlr4/Parser.py b/venv/Lib/site-packages/antlr4/Parser.py
new file mode 100644
index 0000000000000000000000000000000000000000..ae7f48cce07bebc77f03a577278b95a45832fda0
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/Parser.py
@@ -0,0 +1,580 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+import sys
+if sys.version_info[1] > 5:
+ from typing import TextIO
+else:
+ from typing.io import TextIO
+from antlr4.BufferedTokenStream import TokenStream
+from antlr4.CommonTokenFactory import TokenFactory
+from antlr4.error.ErrorStrategy import DefaultErrorStrategy
+from antlr4.InputStream import InputStream
+from antlr4.Recognizer import Recognizer
+from antlr4.RuleContext import RuleContext
+from antlr4.ParserRuleContext import ParserRuleContext
+from antlr4.Token import Token
+from antlr4.Lexer import Lexer
+from antlr4.atn.ATNDeserializer import ATNDeserializer
+from antlr4.atn.ATNDeserializationOptions import ATNDeserializationOptions
+from antlr4.error.Errors import UnsupportedOperationException, RecognitionException
+from antlr4.tree.ParseTreePatternMatcher import ParseTreePatternMatcher
+from antlr4.tree.Tree import ParseTreeListener, TerminalNode, ErrorNode
+
+class TraceListener(ParseTreeListener):
+ __slots__ = '_parser'
+
+ def __init__(self, parser):
+ self._parser = parser
+
+ def enterEveryRule(self, ctx):
+ print("enter " + self._parser.ruleNames[ctx.getRuleIndex()] + ", LT(1)=" + self._parser._input.LT(1).text, file=self._parser._output)
+
+ def visitTerminal(self, node):
+
+ print("consume " + str(node.symbol) + " rule " + self._parser.ruleNames[self._parser._ctx.getRuleIndex()], file=self._parser._output)
+
+ def visitErrorNode(self, node):
+ pass
+
+
+ def exitEveryRule(self, ctx):
+ print("exit " + self._parser.ruleNames[ctx.getRuleIndex()] + ", LT(1)=" + self._parser._input.LT(1).text, file=self._parser._output)
+
+
+# self is all the parsing support code essentially; most of it is error recovery stuff.#
+class Parser (Recognizer):
+ __slots__ = (
+ '_input', '_output', '_errHandler', '_precedenceStack', '_ctx',
+ 'buildParseTrees', '_tracer', '_parseListeners', '_syntaxErrors'
+
+ )
+ # self field maps from the serialized ATN string to the deserialized {@link ATN} with
+ # bypass alternatives.
+ #
+ # @see ATNDeserializationOptions#isGenerateRuleBypassTransitions()
+ #
+ bypassAltsAtnCache = dict()
+
+ def __init__(self, input:TokenStream, output:TextIO = sys.stdout):
+ super().__init__()
+ # The input stream.
+ self._input = None
+ self._output = output
+ # The error handling strategy for the parser. The default value is a new
+ # instance of {@link DefaultErrorStrategy}.
+ self._errHandler = DefaultErrorStrategy()
+ self._precedenceStack = list()
+ self._precedenceStack.append(0)
+ # The {@link ParserRuleContext} object for the currently executing rule.
+ # self is always non-null during the parsing process.
+ self._ctx = None
+ # Specifies whether or not the parser should construct a parse tree during
+ # the parsing process. The default value is {@code true}.
+ self.buildParseTrees = True
+ # When {@link #setTrace}{@code (true)} is called, a reference to the
+ # {@link TraceListener} is stored here so it can be easily removed in a
+ # later call to {@link #setTrace}{@code (false)}. The listener itself is
+ # implemented as a parser listener so self field is not directly used by
+ # other parser methods.
+ self._tracer = None
+ # The list of {@link ParseTreeListener} listeners registered to receive
+ # events during the parse.
+ self._parseListeners = None
+ # The number of syntax errors reported during parsing. self value is
+ # incremented each time {@link #notifyErrorListeners} is called.
+ self._syntaxErrors = 0
+ self.setInputStream(input)
+
+ # reset the parser's state#
+ def reset(self):
+ if self._input is not None:
+ self._input.seek(0)
+ self._errHandler.reset(self)
+ self._ctx = None
+ self._syntaxErrors = 0
+ self.setTrace(False)
+ self._precedenceStack = list()
+ self._precedenceStack.append(0)
+ if self._interp is not None:
+ self._interp.reset()
+
+ # Match current input symbol against {@code ttype}. If the symbol type
+ # matches, {@link ANTLRErrorStrategy#reportMatch} and {@link #consume} are
+ # called to complete the match process.
+ #
+ #
If the symbol type does not match,
+ # {@link ANTLRErrorStrategy#recoverInline} is called on the current error
+ # strategy to attempt recovery. If {@link #getBuildParseTree} is
+ # {@code true} and the token index of the symbol returned by
+ # {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
+ # the parse tree by calling {@link ParserRuleContext#addErrorNode}.
+ #
+ # @param ttype the token type to match
+ # @return the matched symbol
+ # @throws RecognitionException if the current input symbol did not match
+ # {@code ttype} and the error strategy could not recover from the
+ # mismatched symbol
+
+ def match(self, ttype:int):
+ t = self.getCurrentToken()
+ if t.type==ttype:
+ self._errHandler.reportMatch(self)
+ self.consume()
+ else:
+ t = self._errHandler.recoverInline(self)
+ if self.buildParseTrees and t.tokenIndex==-1:
+ # we must have conjured up a new token during single token insertion
+ # if it's not the current symbol
+ self._ctx.addErrorNode(t)
+ return t
+
+ # Match current input symbol as a wildcard. If the symbol type matches
+ # (i.e. has a value greater than 0), {@link ANTLRErrorStrategy#reportMatch}
+ # and {@link #consume} are called to complete the match process.
+ #
+ #
If the symbol type does not match,
+ # {@link ANTLRErrorStrategy#recoverInline} is called on the current error
+ # strategy to attempt recovery. If {@link #getBuildParseTree} is
+ # {@code true} and the token index of the symbol returned by
+ # {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
+ # the parse tree by calling {@link ParserRuleContext#addErrorNode}.
+ #
+ # @return the matched symbol
+ # @throws RecognitionException if the current input symbol did not match
+ # a wildcard and the error strategy could not recover from the mismatched
+ # symbol
+
+ def matchWildcard(self):
+ t = self.getCurrentToken()
+ if t.type > 0:
+ self._errHandler.reportMatch(self)
+ self.consume()
+ else:
+ t = self._errHandler.recoverInline(self)
+ if self.buildParseTrees and t.tokenIndex == -1:
+ # we must have conjured up a new token during single token insertion
+ # if it's not the current symbol
+ self._ctx.addErrorNode(t)
+
+ return t
+
+ def getParseListeners(self):
+ return list() if self._parseListeners is None else self._parseListeners
+
+ # Registers {@code listener} to receive events during the parsing process.
+ #
+ #
To support output-preserving grammar transformations (including but not
+ # limited to left-recursion removal, automated left-factoring, and
+ # optimized code generation), calls to listener methods during the parse
+ # may differ substantially from calls made by
+ # {@link ParseTreeWalker#DEFAULT} used after the parse is complete. In
+ # particular, rule entry and exit events may occur in a different order
+ # during the parse than after the parser. In addition, calls to certain
+ # rule entry methods may be omitted.
+ #
+ #
With the following specific exceptions, calls to listener events are
+ # deterministic, i.e. for identical input the calls to listener
+ # methods will be the same.
+ #
+ #
+ #
Alterations to the grammar used to generate code may change the
+ # behavior of the listener calls.
+ #
Alterations to the command line options passed to ANTLR 4 when
+ # generating the parser may change the behavior of the listener calls.
+ #
Changing the version of the ANTLR Tool used to generate the parser
+ # may change the behavior of the listener calls.
+ #
+ #
+ # @param listener the listener to add
+ #
+ # @throws NullPointerException if {@code} listener is {@code null}
+ #
+ def addParseListener(self, listener:ParseTreeListener):
+ if listener is None:
+ raise ReferenceError("listener")
+ if self._parseListeners is None:
+ self._parseListeners = []
+ self._parseListeners.append(listener)
+
+ #
+ # Remove {@code listener} from the list of parse listeners.
+ #
+ #
If {@code listener} is {@code null} or has not been added as a parse
+ # listener, self method does nothing.
+ # @param listener the listener to remove
+ #
+ def removeParseListener(self, listener:ParseTreeListener):
+ if self._parseListeners is not None:
+ self._parseListeners.remove(listener)
+ if len(self._parseListeners)==0:
+ self._parseListeners = None
+
+ # Remove all parse listeners.
+ def removeParseListeners(self):
+ self._parseListeners = None
+
+ # Notify any parse listeners of an enter rule event.
+ def triggerEnterRuleEvent(self):
+ if self._parseListeners is not None:
+ for listener in self._parseListeners:
+ listener.enterEveryRule(self._ctx)
+ self._ctx.enterRule(listener)
+
+ #
+ # Notify any parse listeners of an exit rule event.
+ #
+ # @see #addParseListener
+ #
+ def triggerExitRuleEvent(self):
+ if self._parseListeners is not None:
+ # reverse order walk of listeners
+ for listener in reversed(self._parseListeners):
+ self._ctx.exitRule(listener)
+ listener.exitEveryRule(self._ctx)
+
+
+ # Gets the number of syntax errors reported during parsing. This value is
+ # incremented each time {@link #notifyErrorListeners} is called.
+ #
+ # @see #notifyErrorListeners
+ #
+ def getNumberOfSyntaxErrors(self):
+ return self._syntaxErrors
+
+ def getTokenFactory(self):
+ return self._input.tokenSource._factory
+
+ # Tell our token source and error strategy about a new way to create tokens.#
+ def setTokenFactory(self, factory:TokenFactory):
+ self._input.tokenSource._factory = factory
+
+ # The ATN with bypass alternatives is expensive to create so we create it
+ # lazily.
+ #
+ # @throws UnsupportedOperationException if the current parser does not
+ # implement the {@link #getSerializedATN()} method.
+ #
+ def getATNWithBypassAlts(self):
+ serializedAtn = self.getSerializedATN()
+ if serializedAtn is None:
+ raise UnsupportedOperationException("The current parser does not support an ATN with bypass alternatives.")
+ result = self.bypassAltsAtnCache.get(serializedAtn, None)
+ if result is None:
+ deserializationOptions = ATNDeserializationOptions()
+ deserializationOptions.generateRuleBypassTransitions = True
+ result = ATNDeserializer(deserializationOptions).deserialize(serializedAtn)
+ self.bypassAltsAtnCache[serializedAtn] = result
+ return result
+
+ # The preferred method of getting a tree pattern. For example, here's a
+ # sample use:
+ #
+ #
+ # ParseTree t = parser.expr();
+ # ParseTreePattern p = parser.compileParseTreePattern("<ID>+0", MyParser.RULE_expr);
+ # ParseTreeMatch m = p.match(t);
+ # String id = m.get("ID");
+ #
+ #
+ def compileParseTreePattern(self, pattern:str, patternRuleIndex:int, lexer:Lexer = None):
+ if lexer is None:
+ if self.getTokenStream() is not None:
+ tokenSource = self.getTokenStream().tokenSource
+ if isinstance( tokenSource, Lexer ):
+ lexer = tokenSource
+ if lexer is None:
+ raise UnsupportedOperationException("Parser can't discover a lexer to use")
+
+ m = ParseTreePatternMatcher(lexer, self)
+ return m.compile(pattern, patternRuleIndex)
+
+
+ def getInputStream(self):
+ return self.getTokenStream()
+
+ def setInputStream(self, input:InputStream):
+ self.setTokenStream(input)
+
+ def getTokenStream(self):
+ return self._input
+
+ # Set the token stream and reset the parser.#
+ def setTokenStream(self, input:TokenStream):
+ self._input = None
+ self.reset()
+ self._input = input
+
+ # Match needs to return the current input symbol, which gets put
+ # into the label for the associated token ref; e.g., x=ID.
+ #
+ def getCurrentToken(self):
+ return self._input.LT(1)
+
+ def notifyErrorListeners(self, msg:str, offendingToken:Token = None, e:RecognitionException = None):
+ if offendingToken is None:
+ offendingToken = self.getCurrentToken()
+ self._syntaxErrors += 1
+ line = offendingToken.line
+ column = offendingToken.column
+ listener = self.getErrorListenerDispatch()
+ listener.syntaxError(self, offendingToken, line, column, msg, e)
+
+ #
+ # Consume and return the {@linkplain #getCurrentToken current symbol}.
+ #
+ #
E.g., given the following input with {@code A} being the current
+ # lookahead symbol, self function moves the cursor to {@code B} and returns
+ # {@code A}.
+ #
+ #
+ # A B
+ # ^
+ #
+ #
+ # If the parser is not in error recovery mode, the consumed symbol is added
+ # to the parse tree using {@link ParserRuleContext#addChild(Token)}, and
+ # {@link ParseTreeListener#visitTerminal} is called on any parse listeners.
+ # If the parser is in error recovery mode, the consumed symbol is
+ # added to the parse tree using
+ # {@link ParserRuleContext#addErrorNode(Token)}, and
+ # {@link ParseTreeListener#visitErrorNode} is called on any parse
+ # listeners.
+ #
+ def consume(self):
+ o = self.getCurrentToken()
+ if o.type != Token.EOF:
+ self.getInputStream().consume()
+ hasListener = self._parseListeners is not None and len(self._parseListeners)>0
+ if self.buildParseTrees or hasListener:
+ if self._errHandler.inErrorRecoveryMode(self):
+ node = self._ctx.addErrorNode(o)
+ else:
+ node = self._ctx.addTokenNode(o)
+ if hasListener:
+ for listener in self._parseListeners:
+ if isinstance(node, ErrorNode):
+ listener.visitErrorNode(node)
+ elif isinstance(node, TerminalNode):
+ listener.visitTerminal(node)
+ return o
+
+ def addContextToParseTree(self):
+ # add current context to parent if we have a parent
+ if self._ctx.parentCtx is not None:
+ self._ctx.parentCtx.addChild(self._ctx)
+
+ # Always called by generated parsers upon entry to a rule. Access field
+ # {@link #_ctx} get the current context.
+ #
+ def enterRule(self, localctx:ParserRuleContext , state:int , ruleIndex:int):
+ self.state = state
+ self._ctx = localctx
+ self._ctx.start = self._input.LT(1)
+ if self.buildParseTrees:
+ self.addContextToParseTree()
+ if self._parseListeners is not None:
+ self.triggerEnterRuleEvent()
+
+ def exitRule(self):
+ self._ctx.stop = self._input.LT(-1)
+ # trigger event on _ctx, before it reverts to parent
+ if self._parseListeners is not None:
+ self.triggerExitRuleEvent()
+ self.state = self._ctx.invokingState
+ self._ctx = self._ctx.parentCtx
+
+ def enterOuterAlt(self, localctx:ParserRuleContext, altNum:int):
+ localctx.setAltNumber(altNum)
+ # if we have new localctx, make sure we replace existing ctx
+ # that is previous child of parse tree
+ if self.buildParseTrees and self._ctx != localctx:
+ if self._ctx.parentCtx is not None:
+ self._ctx.parentCtx.removeLastChild()
+ self._ctx.parentCtx.addChild(localctx)
+ self._ctx = localctx
+
+ # Get the precedence level for the top-most precedence rule.
+ #
+ # @return The precedence level for the top-most precedence rule, or -1 if
+ # the parser context is not nested within a precedence rule.
+ #
+ def getPrecedence(self):
+ if len(self._precedenceStack)==0:
+ return -1
+ else:
+ return self._precedenceStack[-1]
+
+ def enterRecursionRule(self, localctx:ParserRuleContext, state:int, ruleIndex:int, precedence:int):
+ self.state = state
+ self._precedenceStack.append(precedence)
+ self._ctx = localctx
+ self._ctx.start = self._input.LT(1)
+ if self._parseListeners is not None:
+ self.triggerEnterRuleEvent() # simulates rule entry for left-recursive rules
+
+ #
+ # Like {@link #enterRule} but for recursive rules.
+ #
+ def pushNewRecursionContext(self, localctx:ParserRuleContext, state:int, ruleIndex:int):
+ previous = self._ctx
+ previous.parentCtx = localctx
+ previous.invokingState = state
+ previous.stop = self._input.LT(-1)
+
+ self._ctx = localctx
+ self._ctx.start = previous.start
+ if self.buildParseTrees:
+ self._ctx.addChild(previous)
+
+ if self._parseListeners is not None:
+ self.triggerEnterRuleEvent() # simulates rule entry for left-recursive rules
+
+ def unrollRecursionContexts(self, parentCtx:ParserRuleContext):
+ self._precedenceStack.pop()
+ self._ctx.stop = self._input.LT(-1)
+ retCtx = self._ctx # save current ctx (return value)
+ # unroll so _ctx is as it was before call to recursive method
+ if self._parseListeners is not None:
+ while self._ctx is not parentCtx:
+ self.triggerExitRuleEvent()
+ self._ctx = self._ctx.parentCtx
+ else:
+ self._ctx = parentCtx
+
+ # hook into tree
+ retCtx.parentCtx = parentCtx
+
+ if self.buildParseTrees and parentCtx is not None:
+ # add return ctx into invoking rule's tree
+ parentCtx.addChild(retCtx)
+
+ def getInvokingContext(self, ruleIndex:int):
+ ctx = self._ctx
+ while ctx is not None:
+ if ctx.getRuleIndex() == ruleIndex:
+ return ctx
+ ctx = ctx.parentCtx
+ return None
+
+
+ def precpred(self, localctx:RuleContext , precedence:int):
+ return precedence >= self._precedenceStack[-1]
+
+ def inContext(self, context:str):
+ # TODO: useful in parser?
+ return False
+
+ #
+ # Checks whether or not {@code symbol} can follow the current state in the
+ # ATN. The behavior of self method is equivalent to the following, but is
+ # implemented such that the complete context-sensitive follow set does not
+ # need to be explicitly constructed.
+ #
+ #
+ #
+ # @param symbol the symbol type to check
+ # @return {@code true} if {@code symbol} can follow the current state in
+ # the ATN, otherwise {@code false}.
+ #
+ def isExpectedToken(self, symbol:int):
+ atn = self._interp.atn
+ ctx = self._ctx
+ s = atn.states[self.state]
+ following = atn.nextTokens(s)
+ if symbol in following:
+ return True
+ if not Token.EPSILON in following:
+ return False
+
+ while ctx is not None and ctx.invokingState>=0 and Token.EPSILON in following:
+ invokingState = atn.states[ctx.invokingState]
+ rt = invokingState.transitions[0]
+ following = atn.nextTokens(rt.followState)
+ if symbol in following:
+ return True
+ ctx = ctx.parentCtx
+
+ if Token.EPSILON in following and symbol == Token.EOF:
+ return True
+ else:
+ return False
+
+ # Computes the set of input symbols which could follow the current parser
+ # state and context, as given by {@link #getState} and {@link #getContext},
+ # respectively.
+ #
+ # @see ATN#getExpectedTokens(int, RuleContext)
+ #
+ def getExpectedTokens(self):
+ return self._interp.atn.getExpectedTokens(self.state, self._ctx)
+
+ def getExpectedTokensWithinCurrentRule(self):
+ atn = self._interp.atn
+ s = atn.states[self.state]
+ return atn.nextTokens(s)
+
+ # Get a rule's index (i.e., {@code RULE_ruleName} field) or -1 if not found.#
+ def getRuleIndex(self, ruleName:str):
+ ruleIndex = self.getRuleIndexMap().get(ruleName, None)
+ if ruleIndex is not None:
+ return ruleIndex
+ else:
+ return -1
+
+ # Return List<String> of the rule names in your parser instance
+ # leading up to a call to the current rule. You could override if
+ # you want more details such as the file/line info of where
+ # in the ATN a rule is invoked.
+ #
+ # this is very useful for error messages.
+ #
+ def getRuleInvocationStack(self, p:RuleContext=None):
+ if p is None:
+ p = self._ctx
+ stack = list()
+ while p is not None:
+ # compute what follows who invoked us
+ ruleIndex = p.getRuleIndex()
+ if ruleIndex<0:
+ stack.append("n/a")
+ else:
+ stack.append(self.ruleNames[ruleIndex])
+ p = p.parentCtx
+ return stack
+
+ # For debugging and other purposes.#
+ def getDFAStrings(self):
+ return [ str(dfa) for dfa in self._interp.decisionToDFA]
+
+ # For debugging and other purposes.#
+ def dumpDFA(self):
+ seenOne = False
+ for i in range(0, len(self._interp.decisionToDFA)):
+ dfa = self._interp.decisionToDFA[i]
+ if len(dfa.states)>0:
+ if seenOne:
+ print(file=self._output)
+ print("Decision " + str(dfa.decision) + ":", file=self._output)
+ print(dfa.toString(self.literalNames, self.symbolicNames), end='', file=self._output)
+ seenOne = True
+
+
+ def getSourceName(self):
+ return self._input.sourceName
+
+ # During a parse is sometimes useful to listen in on the rule entry and exit
+ # events as well as token matches. self is for quick and dirty debugging.
+ #
+ def setTrace(self, trace:bool):
+ if not trace:
+ self.removeParseListener(self._tracer)
+ self._tracer = None
+ else:
+ if self._tracer is not None:
+ self.removeParseListener(self._tracer)
+ self._tracer = TraceListener(self)
+ self.addParseListener(self._tracer)
diff --git a/venv/Lib/site-packages/antlr4/ParserInterpreter.py b/venv/Lib/site-packages/antlr4/ParserInterpreter.py
new file mode 100644
index 0000000000000000000000000000000000000000..4de43623cf7d308e841c9484470a93fec510d616
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/ParserInterpreter.py
@@ -0,0 +1,170 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+# A parser simulator that mimics what ANTLR's generated
+# parser code does. A ParserATNSimulator is used to make
+# predictions via adaptivePredict but this class moves a pointer through the
+# ATN to simulate parsing. ParserATNSimulator just
+# makes us efficient rather than having to backtrack, for example.
+#
+# This properly creates parse trees even for left recursive rules.
+#
+# We rely on the left recursive rule invocation and special predicate
+# transitions to make left recursive rules work.
+#
+# See TestParserInterpreter for examples.
+#
+from antlr4.dfa.DFA import DFA
+from antlr4.BufferedTokenStream import TokenStream
+from antlr4.Lexer import Lexer
+from antlr4.Parser import Parser
+from antlr4.ParserRuleContext import InterpreterRuleContext, ParserRuleContext
+from antlr4.Token import Token
+from antlr4.atn.ATN import ATN
+from antlr4.atn.ATNState import StarLoopEntryState, ATNState, LoopEndState
+from antlr4.atn.ParserATNSimulator import ParserATNSimulator
+from antlr4.PredictionContext import PredictionContextCache
+from antlr4.atn.Transition import Transition
+from antlr4.error.Errors import RecognitionException, UnsupportedOperationException, FailedPredicateException
+
+
+class ParserInterpreter(Parser):
+ __slots__ = (
+ 'grammarFileName', 'atn', 'tokenNames', 'ruleNames', 'decisionToDFA',
+ 'sharedContextCache', '_parentContextStack',
+ 'pushRecursionContextStates'
+ )
+
+ def __init__(self, grammarFileName:str, tokenNames:list, ruleNames:list, atn:ATN, input:TokenStream):
+ super().__init__(input)
+ self.grammarFileName = grammarFileName
+ self.atn = atn
+ self.tokenNames = tokenNames
+ self.ruleNames = ruleNames
+ self.decisionToDFA = [ DFA(state) for state in atn.decisionToState ]
+ self.sharedContextCache = PredictionContextCache()
+ self._parentContextStack = list()
+ # identify the ATN states where pushNewRecursionContext must be called
+ self.pushRecursionContextStates = set()
+ for state in atn.states:
+ if not isinstance(state, StarLoopEntryState):
+ continue
+ if state.isPrecedenceDecision:
+ self.pushRecursionContextStates.add(state.stateNumber)
+ # get atn simulator that knows how to do predictions
+ self._interp = ParserATNSimulator(self, atn, self.decisionToDFA, self.sharedContextCache)
+
+ # Begin parsing at startRuleIndex#
+ def parse(self, startRuleIndex:int):
+ startRuleStartState = self.atn.ruleToStartState[startRuleIndex]
+ rootContext = InterpreterRuleContext(None, ATNState.INVALID_STATE_NUMBER, startRuleIndex)
+ if startRuleStartState.isPrecedenceRule:
+ self.enterRecursionRule(rootContext, startRuleStartState.stateNumber, startRuleIndex, 0)
+ else:
+ self.enterRule(rootContext, startRuleStartState.stateNumber, startRuleIndex)
+ while True:
+ p = self.getATNState()
+ if p.stateType==ATNState.RULE_STOP :
+ # pop; return from rule
+ if len(self._ctx)==0:
+ if startRuleStartState.isPrecedenceRule:
+ result = self._ctx
+ parentContext = self._parentContextStack.pop()
+ self.unrollRecursionContexts(parentContext.a)
+ return result
+ else:
+ self.exitRule()
+ return rootContext
+ self.visitRuleStopState(p)
+
+ else:
+ try:
+ self.visitState(p)
+ except RecognitionException as e:
+ self.state = self.atn.ruleToStopState[p.ruleIndex].stateNumber
+ self._ctx.exception = e
+ self._errHandler.reportError(self, e)
+ self._errHandler.recover(self, e)
+
+ def enterRecursionRule(self, localctx:ParserRuleContext, state:int, ruleIndex:int, precedence:int):
+ self._parentContextStack.append((self._ctx, localctx.invokingState))
+ super().enterRecursionRule(localctx, state, ruleIndex, precedence)
+
+ def getATNState(self):
+ return self.atn.states[self.state]
+
+ def visitState(self, p:ATNState):
+ edge = 0
+ if len(p.transitions) > 1:
+ self._errHandler.sync(self)
+ edge = self._interp.adaptivePredict(self._input, p.decision, self._ctx)
+ else:
+ edge = 1
+
+ transition = p.transitions[edge - 1]
+ tt = transition.serializationType
+ if tt==Transition.EPSILON:
+
+ if self.pushRecursionContextStates[p.stateNumber] and not isinstance(transition.target, LoopEndState):
+ t = self._parentContextStack[-1]
+ ctx = InterpreterRuleContext(t[0], t[1], self._ctx.ruleIndex)
+ self.pushNewRecursionContext(ctx, self.atn.ruleToStartState[p.ruleIndex].stateNumber, self._ctx.ruleIndex)
+
+ elif tt==Transition.ATOM:
+
+ self.match(transition.label)
+
+ elif tt in [ Transition.RANGE, Transition.SET, Transition.NOT_SET]:
+
+ if not transition.matches(self._input.LA(1), Token.MIN_USER_TOKEN_TYPE, Lexer.MAX_CHAR_VALUE):
+ self._errHandler.recoverInline(self)
+ self.matchWildcard()
+
+ elif tt==Transition.WILDCARD:
+
+ self.matchWildcard()
+
+ elif tt==Transition.RULE:
+
+ ruleStartState = transition.target
+ ruleIndex = ruleStartState.ruleIndex
+ ctx = InterpreterRuleContext(self._ctx, p.stateNumber, ruleIndex)
+ if ruleStartState.isPrecedenceRule:
+ self.enterRecursionRule(ctx, ruleStartState.stateNumber, ruleIndex, transition.precedence)
+ else:
+ self.enterRule(ctx, transition.target.stateNumber, ruleIndex)
+
+ elif tt==Transition.PREDICATE:
+
+ if not self.sempred(self._ctx, transition.ruleIndex, transition.predIndex):
+ raise FailedPredicateException(self)
+
+ elif tt==Transition.ACTION:
+
+ self.action(self._ctx, transition.ruleIndex, transition.actionIndex)
+
+ elif tt==Transition.PRECEDENCE:
+
+ if not self.precpred(self._ctx, transition.precedence):
+ msg = "precpred(_ctx, " + str(transition.precedence) + ")"
+ raise FailedPredicateException(self, msg)
+
+ else:
+ raise UnsupportedOperationException("Unrecognized ATN transition type.")
+
+ self.state = transition.target.stateNumber
+
+ def visitRuleStopState(self, p:ATNState):
+ ruleStartState = self.atn.ruleToStartState[p.ruleIndex]
+ if ruleStartState.isPrecedenceRule:
+ parentContext = self._parentContextStack.pop()
+ self.unrollRecursionContexts(parentContext.a)
+ self.state = parentContext[1]
+ else:
+ self.exitRule()
+
+ ruleTransition = self.atn.states[self.state].transitions[0]
+ self.state = ruleTransition.followState.stateNumber
diff --git a/venv/Lib/site-packages/antlr4/ParserRuleContext.py b/venv/Lib/site-packages/antlr4/ParserRuleContext.py
new file mode 100644
index 0000000000000000000000000000000000000000..f945c5ba94ac394ff7714e4d4e43a86aa31924df
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/ParserRuleContext.py
@@ -0,0 +1,186 @@
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+
+#* A rule invocation record for parsing.
+#
+# Contains all of the information about the current rule not stored in the
+# RuleContext. It handles parse tree children list, Any ATN state
+# tracing, and the default values available for rule indications:
+# start, stop, rule index, current alt number, current
+# ATN state.
+#
+# Subclasses made for each rule and grammar track the parameters,
+# return values, locals, and labels specific to that rule. These
+# are the objects that are returned from rules.
+#
+# Note text is not an actual field of a rule return value; it is computed
+# from start and stop using the input stream's toString() method. I
+# could add a ctor to this so that we can pass in and store the input
+# stream, but I'm not sure we want to do that. It would seem to be undefined
+# to get the .text property anyway if the rule matches tokens from multiple
+# input streams.
+#
+# I do not use getters for fields of objects that are used simply to
+# group values such as this aggregate. The getters/setters are there to
+# satisfy the superclass interface.
+
+from antlr4.RuleContext import RuleContext
+from antlr4.Token import Token
+from antlr4.tree.Tree import ParseTreeListener, ParseTree, TerminalNodeImpl, ErrorNodeImpl, TerminalNode, \
+ INVALID_INTERVAL
+
+# need forward declaration
+ParserRuleContext = None
+
+class ParserRuleContext(RuleContext):
+ __slots__ = ('children', 'start', 'stop', 'exception')
+ def __init__(self, parent:ParserRuleContext = None, invokingStateNumber:int = None ):
+ super().__init__(parent, invokingStateNumber)
+ #* If we are debugging or building a parse tree for a visitor,
+ # we need to track all of the tokens and rule invocations associated
+ # with this rule's context. This is empty for parsing w/o tree constr.
+ # operation because we don't the need to track the details about
+ # how we parse this rule.
+ #/
+ self.children = None
+ self.start = None
+ self.stop = None
+ # The exception that forced this rule to return. If the rule successfully
+ # completed, this is {@code null}.
+ self.exception = None
+
+ #* COPY a ctx (I'm deliberately not using copy constructor)#/
+ #
+ # This is used in the generated parser code to flip a generic XContext
+ # node for rule X to a YContext for alt label Y. In that sense, it is
+ # not really a generic copy function.
+ #
+ # If we do an error sync() at start of a rule, we might add error nodes
+ # to the generic XContext so this function must copy those nodes to
+ # the YContext as well else they are lost!
+ #/
+ def copyFrom(self, ctx:ParserRuleContext):
+ # from RuleContext
+ self.parentCtx = ctx.parentCtx
+ self.invokingState = ctx.invokingState
+ self.children = None
+ self.start = ctx.start
+ self.stop = ctx.stop
+
+ # copy any error nodes to alt label node
+ if ctx.children is not None:
+ self.children = []
+ # reset parent pointer for any error nodes
+ for child in ctx.children:
+ if isinstance(child, ErrorNodeImpl):
+ self.children.append(child)
+ child.parentCtx = self
+
+ # Double dispatch methods for listeners
+ def enterRule(self, listener:ParseTreeListener):
+ pass
+
+ def exitRule(self, listener:ParseTreeListener):
+ pass
+
+ #* Does not set parent link; other add methods do that#/
+ def addChild(self, child:ParseTree):
+ if self.children is None:
+ self.children = []
+ self.children.append(child)
+ return child
+
+ #* Used by enterOuterAlt to toss out a RuleContext previously added as
+ # we entered a rule. If we have # label, we will need to remove
+ # generic ruleContext object.
+ #/
+ def removeLastChild(self):
+ if self.children is not None:
+ del self.children[len(self.children)-1]
+
+ def addTokenNode(self, token:Token):
+ node = TerminalNodeImpl(token)
+ self.addChild(node)
+ node.parentCtx = self
+ return node
+
+ def addErrorNode(self, badToken:Token):
+ node = ErrorNodeImpl(badToken)
+ self.addChild(node)
+ node.parentCtx = self
+ return node
+
+ def getChild(self, i:int, ttype:type = None):
+ if ttype is None:
+ return self.children[i] if len(self.children)>i else None
+ else:
+ for child in self.getChildren():
+ if not isinstance(child, ttype):
+ continue
+ if i==0:
+ return child
+ i -= 1
+ return None
+
+ def getChildren(self, predicate = None):
+ if self.children is not None:
+ for child in self.children:
+ if predicate is not None and not predicate(child):
+ continue
+ yield child
+
+ def getToken(self, ttype:int, i:int):
+ for child in self.getChildren():
+ if not isinstance(child, TerminalNode):
+ continue
+ if child.symbol.type != ttype:
+ continue
+ if i==0:
+ return child
+ i -= 1
+ return None
+
+ def getTokens(self, ttype:int ):
+ if self.getChildren() is None:
+ return []
+ tokens = []
+ for child in self.getChildren():
+ if not isinstance(child, TerminalNode):
+ continue
+ if child.symbol.type != ttype:
+ continue
+ tokens.append(child)
+ return tokens
+
+ def getTypedRuleContext(self, ctxType:type, i:int):
+ return self.getChild(i, ctxType)
+
+ def getTypedRuleContexts(self, ctxType:type):
+ children = self.getChildren()
+ if children is None:
+ return []
+ contexts = []
+ for child in children:
+ if not isinstance(child, ctxType):
+ continue
+ contexts.append(child)
+ return contexts
+
+ def getChildCount(self):
+ return len(self.children) if self.children else 0
+
+ def getSourceInterval(self):
+ if self.start is None or self.stop is None:
+ return INVALID_INTERVAL
+ else:
+ return (self.start.tokenIndex, self.stop.tokenIndex)
+
+
+RuleContext.EMPTY = ParserRuleContext()
+
+class InterpreterRuleContext(ParserRuleContext):
+
+ def __init__(self, parent:ParserRuleContext, invokingStateNumber:int, ruleIndex:int):
+ super().__init__(parent, invokingStateNumber)
+ self.ruleIndex = ruleIndex
diff --git a/venv/Lib/site-packages/antlr4/PredictionContext.py b/venv/Lib/site-packages/antlr4/PredictionContext.py
new file mode 100644
index 0000000000000000000000000000000000000000..1ae1d377cc688b16df4c6a4270d65f513e074bd9
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/PredictionContext.py
@@ -0,0 +1,629 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+from antlr4.RuleContext import RuleContext
+from antlr4.atn.ATN import ATN
+from antlr4.error.Errors import IllegalStateException
+from io import StringIO
+
+# dup ParserATNSimulator class var here to avoid circular import; no idea why this can't be in PredictionContext
+_trace_atn_sim = False
+
+class PredictionContext(object):
+
+ # Represents {@code $} in local context prediction, which means wildcard.
+ # {@code#+x =#}.
+ #/
+ EMPTY = None
+
+ # Represents {@code $} in an array in full context mode, when {@code $}
+ # doesn't mean wildcard: {@code $ + x = [$,x]}. Here,
+ # {@code $} = {@link #EMPTY_RETURN_STATE}.
+ #/
+ EMPTY_RETURN_STATE = 0x7FFFFFFF
+
+ globalNodeCount = 1
+ id = globalNodeCount
+
+ # Stores the computed hash code of this {@link PredictionContext}. The hash
+ # code is computed in parts to match the following reference algorithm.
+ #
+ #
+ #/
+
+ def __init__(self, cachedHashCode:int):
+ self.cachedHashCode = cachedHashCode
+
+ def __len__(self):
+ return 0
+
+ # This means only the {@link #EMPTY} context is in set.
+ def isEmpty(self):
+ return self is self.EMPTY
+
+ def hasEmptyPath(self):
+ return self.getReturnState(len(self) - 1) == self.EMPTY_RETURN_STATE
+
+ def getReturnState(self, index:int):
+ raise IllegalStateException("illegal!")
+
+ def __hash__(self):
+ return self.cachedHashCode
+
+def calculateHashCode(parent:PredictionContext, returnState:int):
+ return hash("") if parent is None else hash((hash(parent), returnState))
+
+def calculateListsHashCode(parents:[], returnStates:[] ):
+ h = 0
+ for parent, returnState in zip(parents, returnStates):
+ h = hash((h, calculateHashCode(parent, returnState)))
+ return h
+
+# Used to cache {@link PredictionContext} objects. Its used for the shared
+# context cash associated with contexts in DFA states. This cache
+# can be used for both lexers and parsers.
+
+class PredictionContextCache(object):
+
+ def __init__(self):
+ self.cache = dict()
+
+ # Add a context to the cache and return it. If the context already exists,
+ # return that one instead and do not add a new context to the cache.
+ # Protect shared cache from unsafe thread access.
+ #
+ def add(self, ctx:PredictionContext):
+ if ctx==PredictionContext.EMPTY:
+ return PredictionContext.EMPTY
+ existing = self.cache.get(ctx, None)
+ if existing is not None:
+ return existing
+ self.cache[ctx] = ctx
+ return ctx
+
+ def get(self, ctx:PredictionContext):
+ return self.cache.get(ctx, None)
+
+ def __len__(self):
+ return len(self.cache)
+
+
+class SingletonPredictionContext(PredictionContext):
+
+ @staticmethod
+ def create(parent:PredictionContext , returnState:int ):
+ if returnState == PredictionContext.EMPTY_RETURN_STATE and parent is None:
+ # someone can pass in the bits of an array ctx that mean $
+ return SingletonPredictionContext.EMPTY
+ else:
+ return SingletonPredictionContext(parent, returnState)
+
+ def __init__(self, parent:PredictionContext, returnState:int):
+ hashCode = calculateHashCode(parent, returnState)
+ super().__init__(hashCode)
+ self.parentCtx = parent
+ self.returnState = returnState
+
+ def __len__(self):
+ return 1
+
+ def getParent(self, index:int):
+ return self.parentCtx
+
+ def getReturnState(self, index:int):
+ return self.returnState
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif other is None:
+ return False
+ elif not isinstance(other, SingletonPredictionContext):
+ return False
+ else:
+ return self.returnState == other.returnState and self.parentCtx == other.parentCtx
+
+ def __hash__(self):
+ return self.cachedHashCode
+
+ def __str__(self):
+ up = "" if self.parentCtx is None else str(self.parentCtx)
+ if len(up)==0:
+ if self.returnState == self.EMPTY_RETURN_STATE:
+ return "$"
+ else:
+ return str(self.returnState)
+ else:
+ return str(self.returnState) + " " + up
+
+
+class EmptyPredictionContext(SingletonPredictionContext):
+
+ def __init__(self):
+ super().__init__(None, PredictionContext.EMPTY_RETURN_STATE)
+
+ def isEmpty(self):
+ return True
+
+ def __eq__(self, other):
+ return self is other
+
+ def __hash__(self):
+ return self.cachedHashCode
+
+ def __str__(self):
+ return "$"
+
+
+PredictionContext.EMPTY = EmptyPredictionContext()
+
+class ArrayPredictionContext(PredictionContext):
+ # Parent can be null only if full ctx mode and we make an array
+ # from {@link #EMPTY} and non-empty. We merge {@link #EMPTY} by using null parent and
+ # returnState == {@link #EMPTY_RETURN_STATE}.
+
+ def __init__(self, parents:list, returnStates:list):
+ super().__init__(calculateListsHashCode(parents, returnStates))
+ self.parents = parents
+ self.returnStates = returnStates
+
+ def isEmpty(self):
+ # since EMPTY_RETURN_STATE can only appear in the last position, we
+ # don't need to verify that size==1
+ return self.returnStates[0]==PredictionContext.EMPTY_RETURN_STATE
+
+ def __len__(self):
+ return len(self.returnStates)
+
+ def getParent(self, index:int):
+ return self.parents[index]
+
+ def getReturnState(self, index:int):
+ return self.returnStates[index]
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, ArrayPredictionContext):
+ return False
+ elif hash(self) != hash(other):
+ return False # can't be same if hash is different
+ else:
+ return self.returnStates==other.returnStates and self.parents==other.parents
+
+ def __str__(self):
+ if self.isEmpty():
+ return "[]"
+ with StringIO() as buf:
+ buf.write("[")
+ for i in range(0,len(self.returnStates)):
+ if i>0:
+ buf.write(", ")
+ if self.returnStates[i]==PredictionContext.EMPTY_RETURN_STATE:
+ buf.write("$")
+ continue
+ buf.write(str(self.returnStates[i]))
+ if self.parents[i] is not None:
+ buf.write(' ')
+ buf.write(str(self.parents[i]))
+ else:
+ buf.write("null")
+ buf.write("]")
+ return buf.getvalue()
+
+ def __hash__(self):
+ return self.cachedHashCode
+
+
+
+# Convert a {@link RuleContext} tree to a {@link PredictionContext} graph.
+# Return {@link #EMPTY} if {@code outerContext} is empty or null.
+#/
+def PredictionContextFromRuleContext(atn:ATN, outerContext:RuleContext=None):
+ if outerContext is None:
+ outerContext = RuleContext.EMPTY
+
+ # if we are in RuleContext of start rule, s, then PredictionContext
+ # is EMPTY. Nobody called us. (if we are empty, return empty)
+ if outerContext.parentCtx is None or outerContext is RuleContext.EMPTY:
+ return PredictionContext.EMPTY
+
+ # If we have a parent, convert it to a PredictionContext graph
+ parent = PredictionContextFromRuleContext(atn, outerContext.parentCtx)
+ state = atn.states[outerContext.invokingState]
+ transition = state.transitions[0]
+ return SingletonPredictionContext.create(parent, transition.followState.stateNumber)
+
+
+def merge(a:PredictionContext, b:PredictionContext, rootIsWildcard:bool, mergeCache:dict):
+
+ # share same graph if both same
+ if a==b:
+ return a
+
+ if isinstance(a, SingletonPredictionContext) and isinstance(b, SingletonPredictionContext):
+ return mergeSingletons(a, b, rootIsWildcard, mergeCache)
+
+ # At least one of a or b is array
+ # If one is $ and rootIsWildcard, return $ as# wildcard
+ if rootIsWildcard:
+ if isinstance( a, EmptyPredictionContext ):
+ return a
+ if isinstance( b, EmptyPredictionContext ):
+ return b
+
+ # convert singleton so both are arrays to normalize
+ if isinstance( a, SingletonPredictionContext ):
+ a = ArrayPredictionContext([a.parentCtx], [a.returnState])
+ if isinstance( b, SingletonPredictionContext):
+ b = ArrayPredictionContext([b.parentCtx], [b.returnState])
+ return mergeArrays(a, b, rootIsWildcard, mergeCache)
+
+
+#
+# Merge two {@link SingletonPredictionContext} instances.
+#
+#
Stack tops equal, parents merge is same; return left graph.
+#
+#
+#
Same stack top, parents differ; merge parents giving array node, then
+# remainders of those graphs. A new root node is created to point to the
+# merged parents.
+#
+#
+#
Different stack tops pointing to same parent. Make array node for the
+# root where both element in the root point to the same (original)
+# parent.
+#
+#
+#
Different stack tops pointing to different parents. Make array node for
+# the root where each element points to the corresponding original
+# parent.
+#
+#
+# @param a the first {@link SingletonPredictionContext}
+# @param b the second {@link SingletonPredictionContext}
+# @param rootIsWildcard {@code true} if this is a local-context merge,
+# otherwise false to indicate a full-context merge
+# @param mergeCache
+#/
+def mergeSingletons(a:SingletonPredictionContext, b:SingletonPredictionContext, rootIsWildcard:bool, mergeCache:dict):
+ if mergeCache is not None:
+ previous = mergeCache.get((a,b), None)
+ if previous is not None:
+ return previous
+ previous = mergeCache.get((b,a), None)
+ if previous is not None:
+ return previous
+
+ merged = mergeRoot(a, b, rootIsWildcard)
+ if merged is not None:
+ if mergeCache is not None:
+ mergeCache[(a, b)] = merged
+ return merged
+
+ if a.returnState==b.returnState:
+ parent = merge(a.parentCtx, b.parentCtx, rootIsWildcard, mergeCache)
+ # if parent is same as existing a or b parent or reduced to a parent, return it
+ if parent == a.parentCtx:
+ return a # ax + bx = ax, if a=b
+ if parent == b.parentCtx:
+ return b # ax + bx = bx, if a=b
+ # else: ax + ay = a'[x,y]
+ # merge parents x and y, giving array node with x,y then remainders
+ # of those graphs. dup a, a' points at merged array
+ # new joined parent so create new singleton pointing to it, a'
+ merged = SingletonPredictionContext.create(parent, a.returnState)
+ if mergeCache is not None:
+ mergeCache[(a, b)] = merged
+ return merged
+ else: # a != b payloads differ
+ # see if we can collapse parents due to $+x parents if local ctx
+ singleParent = None
+ if a is b or (a.parentCtx is not None and a.parentCtx==b.parentCtx): # ax + bx = [a,b]x
+ singleParent = a.parentCtx
+ if singleParent is not None: # parents are same
+ # sort payloads and use same parent
+ payloads = [ a.returnState, b.returnState ]
+ if a.returnState > b.returnState:
+ payloads = [ b.returnState, a.returnState ]
+ parents = [singleParent, singleParent]
+ merged = ArrayPredictionContext(parents, payloads)
+ if mergeCache is not None:
+ mergeCache[(a, b)] = merged
+ return merged
+ # parents differ and can't merge them. Just pack together
+ # into array; can't merge.
+ # ax + by = [ax,by]
+ payloads = [ a.returnState, b.returnState ]
+ parents = [ a.parentCtx, b.parentCtx ]
+ if a.returnState > b.returnState: # sort by payload
+ payloads = [ b.returnState, a.returnState ]
+ parents = [ b.parentCtx, a.parentCtx ]
+ merged = ArrayPredictionContext(parents, payloads)
+ if mergeCache is not None:
+ mergeCache[(a, b)] = merged
+ return merged
+
+
+#
+# Handle case where at least one of {@code a} or {@code b} is
+# {@link #EMPTY}. In the following diagrams, the symbol {@code $} is used
+# to represent {@link #EMPTY}.
+#
+#
Local-Context Merges
+#
+#
These local-context merge operations are used when {@code rootIsWildcard}
+# is true.
+#
+#
{@link #EMPTY} is superset of any graph; return {@link #EMPTY}.
+#
+#
+#
{@link #EMPTY} and anything is {@code #EMPTY}, so merged parent is
+# {@code #EMPTY}; return left graph.
+#
+#
+#
Special case of last merge if local context.
+#
+#
+#
Full-Context Merges
+#
+#
These full-context merge operations are used when {@code rootIsWildcard}
+# is false.
+#
+#
+#
+#
Must keep all contexts; {@link #EMPTY} in array is a special value (and
+# null parent).
+#
+#
+#
+#
+# @param a the first {@link SingletonPredictionContext}
+# @param b the second {@link SingletonPredictionContext}
+# @param rootIsWildcard {@code true} if this is a local-context merge,
+# otherwise false to indicate a full-context merge
+#/
+def mergeRoot(a:SingletonPredictionContext, b:SingletonPredictionContext, rootIsWildcard:bool):
+ if rootIsWildcard:
+ if a == PredictionContext.EMPTY:
+ return PredictionContext.EMPTY ## + b =#
+ if b == PredictionContext.EMPTY:
+ return PredictionContext.EMPTY # a +# =#
+ else:
+ if a == PredictionContext.EMPTY and b == PredictionContext.EMPTY:
+ return PredictionContext.EMPTY # $ + $ = $
+ elif a == PredictionContext.EMPTY: # $ + x = [$,x]
+ payloads = [ b.returnState, PredictionContext.EMPTY_RETURN_STATE ]
+ parents = [ b.parentCtx, None ]
+ return ArrayPredictionContext(parents, payloads)
+ elif b == PredictionContext.EMPTY: # x + $ = [$,x] ($ is always first if present)
+ payloads = [ a.returnState, PredictionContext.EMPTY_RETURN_STATE ]
+ parents = [ a.parentCtx, None ]
+ return ArrayPredictionContext(parents, payloads)
+ return None
+
+
+#
+# Merge two {@link ArrayPredictionContext} instances.
+#
+#
Different tops, different parents.
+#
+#
+#
Shared top, same parents.
+#
+#
+#
Shared top, different parents.
+#
+#
+#
Shared top, all shared parents.
+#
+#
+#
Equal tops, merge parents and reduce top to
+# {@link SingletonPredictionContext}.
+#
+#/
+def mergeArrays(a:ArrayPredictionContext, b:ArrayPredictionContext, rootIsWildcard:bool, mergeCache:dict):
+ if mergeCache is not None:
+ previous = mergeCache.get((a,b), None)
+ if previous is not None:
+ if _trace_atn_sim: print("mergeArrays a="+str(a)+",b="+str(b)+" -> previous")
+ return previous
+ previous = mergeCache.get((b,a), None)
+ if previous is not None:
+ if _trace_atn_sim: print("mergeArrays a="+str(a)+",b="+str(b)+" -> previous")
+ return previous
+
+ # merge sorted payloads a + b => M
+ i = 0 # walks a
+ j = 0 # walks b
+ k = 0 # walks target M array
+
+ mergedReturnStates = [None] * (len(a.returnStates) + len( b.returnStates))
+ mergedParents = [None] * len(mergedReturnStates)
+ # walk and merge to yield mergedParents, mergedReturnStates
+ while i ax
+ if bothDollars or ax_ax:
+ mergedParents[k] = a_parent # choose left
+ mergedReturnStates[k] = payload
+ else: # ax+ay -> a'[x,y]
+ mergedParent = merge(a_parent, b_parent, rootIsWildcard, mergeCache)
+ mergedParents[k] = mergedParent
+ mergedReturnStates[k] = payload
+ i += 1 # hop over left one as usual
+ j += 1 # but also skip one in right side since we merge
+ elif a.returnStates[i] a, copy b[j] to M
+ mergedParents[k] = b_parent
+ mergedReturnStates[k] = b.returnStates[j]
+ j += 1
+ k += 1
+
+ # copy over any payloads remaining in either array
+ if i < len(a.returnStates):
+ for p in range(i, len(a.returnStates)):
+ mergedParents[k] = a.parents[p]
+ mergedReturnStates[k] = a.returnStates[p]
+ k += 1
+ else:
+ for p in range(j, len(b.returnStates)):
+ mergedParents[k] = b.parents[p]
+ mergedReturnStates[k] = b.returnStates[p]
+ k += 1
+
+ # trim merged if we combined a few that had same stack tops
+ if k < len(mergedParents): # write index < last position; trim
+ if k == 1: # for just one merged element, return singleton top
+ merged = SingletonPredictionContext.create(mergedParents[0], mergedReturnStates[0])
+ if mergeCache is not None:
+ mergeCache[(a,b)] = merged
+ return merged
+ mergedParents = mergedParents[0:k]
+ mergedReturnStates = mergedReturnStates[0:k]
+
+ merged = ArrayPredictionContext(mergedParents, mergedReturnStates)
+
+ # if we created same array as a or b, return that instead
+ # TODO: track whether this is possible above during merge sort for speed
+ if merged==a:
+ if mergeCache is not None:
+ mergeCache[(a,b)] = a
+ if _trace_atn_sim: print("mergeArrays a="+str(a)+",b="+str(b)+" -> a")
+ return a
+ if merged==b:
+ if mergeCache is not None:
+ mergeCache[(a,b)] = b
+ if _trace_atn_sim: print("mergeArrays a="+str(a)+",b="+str(b)+" -> b")
+ return b
+ combineCommonParents(mergedParents)
+
+ if mergeCache is not None:
+ mergeCache[(a,b)] = merged
+
+ if _trace_atn_sim: print("mergeArrays a="+str(a)+",b="+str(b)+" -> "+str(M))
+
+ return merged
+
+
+#
+# Make pass over all M {@code parents}; merge any {@code equals()}
+# ones.
+#/
+def combineCommonParents(parents:list):
+ uniqueParents = dict()
+
+ for p in range(0, len(parents)):
+ parent = parents[p]
+ if uniqueParents.get(parent, None) is None:
+ uniqueParents[parent] = parent
+
+ for p in range(0, len(parents)):
+ parents[p] = uniqueParents[parents[p]]
+
+def getCachedPredictionContext(context:PredictionContext, contextCache:PredictionContextCache, visited:dict):
+ if context.isEmpty():
+ return context
+ existing = visited.get(context)
+ if existing is not None:
+ return existing
+ existing = contextCache.get(context)
+ if existing is not None:
+ visited[context] = existing
+ return existing
+ changed = False
+ parents = [None] * len(context)
+ for i in range(0, len(parents)):
+ parent = getCachedPredictionContext(context.getParent(i), contextCache, visited)
+ if changed or parent is not context.getParent(i):
+ if not changed:
+ parents = [context.getParent(j) for j in range(len(context))]
+ changed = True
+ parents[i] = parent
+ if not changed:
+ contextCache.add(context)
+ visited[context] = context
+ return context
+
+ updated = None
+ if len(parents) == 0:
+ updated = PredictionContext.EMPTY
+ elif len(parents) == 1:
+ updated = SingletonPredictionContext.create(parents[0], context.getReturnState(0))
+ else:
+ updated = ArrayPredictionContext(parents, context.returnStates)
+
+ contextCache.add(updated)
+ visited[updated] = updated
+ visited[context] = updated
+
+ return updated
+
+
+# # extra structures, but cut/paste/morphed works, so leave it.
+# # seems to do a breadth-first walk
+# public static List getAllNodes(PredictionContext context) {
+# Map visited =
+# new IdentityHashMap();
+# Deque workList = new ArrayDeque();
+# workList.add(context);
+# visited.put(context, context);
+# List nodes = new ArrayList();
+# while (!workList.isEmpty()) {
+# PredictionContext current = workList.pop();
+# nodes.add(current);
+# for (int i = 0; i < current.size(); i++) {
+# PredictionContext parent = current.getParent(i);
+# if ( parent!=null && visited.put(parent, parent) == null) {
+# workList.push(parent);
+# }
+# }
+# }
+# return nodes;
+# }
+
+# ter's recursive version of Sam's getAllNodes()
+def getAllContextNodes(context:PredictionContext, nodes:list=None, visited:dict=None):
+ if nodes is None:
+ nodes = list()
+ return getAllContextNodes(context, nodes, visited)
+ elif visited is None:
+ visited = dict()
+ return getAllContextNodes(context, nodes, visited)
+ else:
+ if context is None or visited.get(context, None) is not None:
+ return nodes
+ visited.put(context, context)
+ nodes.add(context)
+ for i in range(0, len(context)):
+ getAllContextNodes(context.getParent(i), nodes, visited)
+ return nodes
+
diff --git a/venv/Lib/site-packages/antlr4/Recognizer.py b/venv/Lib/site-packages/antlr4/Recognizer.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f9d6e660e4cda89540b200732ffd772cf049c39
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/Recognizer.py
@@ -0,0 +1,147 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+from antlr4.RuleContext import RuleContext
+from antlr4.Token import Token
+from antlr4.error.ErrorListener import ProxyErrorListener, ConsoleErrorListener
+
+# need forward delcaration
+RecognitionException = None
+
+class Recognizer(object):
+ __slots__ = ('_listeners', '_interp', '_stateNumber')
+
+ tokenTypeMapCache = dict()
+ ruleIndexMapCache = dict()
+
+ def __init__(self):
+ self._listeners = [ ConsoleErrorListener.INSTANCE ]
+ self._interp = None
+ self._stateNumber = -1
+
+ def extractVersion(self, version):
+ pos = version.find(".")
+ major = version[0:pos]
+ version = version[pos+1:]
+ pos = version.find(".")
+ if pos==-1:
+ pos = version.find("-")
+ if pos==-1:
+ pos = len(version)
+ minor = version[0:pos]
+ return major, minor
+
+ def checkVersion(self, toolVersion):
+ runtimeVersion = "4.13.2"
+ rvmajor, rvminor = self.extractVersion(runtimeVersion)
+ tvmajor, tvminor = self.extractVersion(toolVersion)
+ if rvmajor!=tvmajor or rvminor!=tvminor:
+ print("ANTLR runtime and generated code versions disagree: "+runtimeVersion+"!="+toolVersion)
+
+ def addErrorListener(self, listener):
+ self._listeners.append(listener)
+
+ def removeErrorListener(self, listener):
+ self._listeners.remove(listener)
+
+ def removeErrorListeners(self):
+ self._listeners = []
+
+ def getTokenTypeMap(self):
+ tokenNames = self.getTokenNames()
+ if tokenNames is None:
+ from antlr4.error.Errors import UnsupportedOperationException
+ raise UnsupportedOperationException("The current recognizer does not provide a list of token names.")
+ result = self.tokenTypeMapCache.get(tokenNames, None)
+ if result is None:
+ result = zip( tokenNames, range(0, len(tokenNames)))
+ result["EOF"] = Token.EOF
+ self.tokenTypeMapCache[tokenNames] = result
+ return result
+
+ # Get a map from rule names to rule indexes.
+ #
+ #
Used for XPath and tree pattern compilation.
+ #
+ def getRuleIndexMap(self):
+ ruleNames = self.getRuleNames()
+ if ruleNames is None:
+ from antlr4.error.Errors import UnsupportedOperationException
+ raise UnsupportedOperationException("The current recognizer does not provide a list of rule names.")
+ result = self.ruleIndexMapCache.get(ruleNames, None)
+ if result is None:
+ result = zip( ruleNames, range(0, len(ruleNames)))
+ self.ruleIndexMapCache[ruleNames] = result
+ return result
+
+ def getTokenType(self, tokenName:str):
+ ttype = self.getTokenTypeMap().get(tokenName, None)
+ if ttype is not None:
+ return ttype
+ else:
+ return Token.INVALID_TYPE
+
+
+ # What is the error header, normally line/character position information?#
+ def getErrorHeader(self, e:RecognitionException):
+ line = e.getOffendingToken().line
+ column = e.getOffendingToken().column
+ return "line "+line+":"+column
+
+
+ # How should a token be displayed in an error message? The default
+ # is to display just the text, but during development you might
+ # want to have a lot of information spit out. Override in that case
+ # to use t.toString() (which, for CommonToken, dumps everything about
+ # the token). This is better than forcing you to override a method in
+ # your token objects because you don't have to go modify your lexer
+ # so that it creates a new Java type.
+ #
+ # @deprecated This method is not called by the ANTLR 4 Runtime. Specific
+ # implementations of {@link ANTLRErrorStrategy} may provide a similar
+ # feature when necessary. For example, see
+ # {@link DefaultErrorStrategy#getTokenErrorDisplay}.
+ #
+ def getTokenErrorDisplay(self, t:Token):
+ if t is None:
+ return ""
+ s = t.text
+ if s is None:
+ if t.type==Token.EOF:
+ s = ""
+ else:
+ s = "<" + str(t.type) + ">"
+ s = s.replace("\n","\\n")
+ s = s.replace("\r","\\r")
+ s = s.replace("\t","\\t")
+ return "'" + s + "'"
+
+ def getErrorListenerDispatch(self):
+ return ProxyErrorListener(self._listeners)
+
+ # subclass needs to override these if there are sempreds or actions
+ # that the ATN interp needs to execute
+ def sempred(self, localctx:RuleContext, ruleIndex:int, actionIndex:int):
+ return True
+
+ def precpred(self, localctx:RuleContext , precedence:int):
+ return True
+
+ @property
+ def state(self):
+ return self._stateNumber
+
+ # Indicate that the recognizer has changed internal state that is
+ # consistent with the ATN state passed in. This way we always know
+ # where we are in the ATN as the parser goes along. The rule
+ # context objects form a stack that lets us see the stack of
+ # invoking rules. Combine this and we have complete ATN
+ # configuration information.
+
+ @state.setter
+ def state(self, atnState:int):
+ self._stateNumber = atnState
+
+del RecognitionException
diff --git a/venv/Lib/site-packages/antlr4/RuleContext.py b/venv/Lib/site-packages/antlr4/RuleContext.py
new file mode 100644
index 0000000000000000000000000000000000000000..7812ba3b1c87cc53dd5a7e64cdd0c556f6a43822
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/RuleContext.py
@@ -0,0 +1,227 @@
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+
+
+# A rule context is a record of a single rule invocation. It knows
+# which context invoked it, if any. If there is no parent context, then
+# naturally the invoking state is not valid. The parent link
+# provides a chain upwards from the current rule invocation to the root
+# of the invocation tree, forming a stack. We actually carry no
+# information about the rule associated with this context (except
+# when parsing). We keep only the state number of the invoking state from
+# the ATN submachine that invoked this. Contrast this with the s
+# pointer inside ParserRuleContext that tracks the current state
+# being "executed" for the current rule.
+#
+# The parent contexts are useful for computing lookahead sets and
+# getting error information.
+#
+# These objects are used during parsing and prediction.
+# For the special case of parsers, we use the subclass
+# ParserRuleContext.
+#
+# @see ParserRuleContext
+#/
+from io import StringIO
+from antlr4.tree.Tree import RuleNode, INVALID_INTERVAL, ParseTreeVisitor
+from antlr4.tree.Trees import Trees
+
+# need forward declarations
+RuleContext = None
+Parser = None
+
+class RuleContext(RuleNode):
+ __slots__ = ('parentCtx', 'invokingState')
+ EMPTY = None
+
+ def __init__(self, parent:RuleContext=None, invokingState:int=-1):
+ super().__init__()
+ # What context invoked this rule?
+ self.parentCtx = parent
+ # What state invoked the rule associated with this context?
+ # The "return address" is the followState of invokingState
+ # If parent is null, this should be -1.
+ self.invokingState = invokingState
+
+
+ def depth(self):
+ n = 0
+ p = self
+ while p is not None:
+ p = p.parentCtx
+ n += 1
+ return n
+
+ # A context is empty if there is no invoking state; meaning nobody call
+ # current context.
+ def isEmpty(self):
+ return self.invokingState == -1
+
+ # satisfy the ParseTree / SyntaxTree interface
+
+ def getSourceInterval(self):
+ return INVALID_INTERVAL
+
+ def getRuleContext(self):
+ return self
+
+ def getPayload(self):
+ return self
+
+ # Return the combined text of all child nodes. This method only considers
+ # tokens which have been added to the parse tree.
+ #
+ # Since tokens on hidden channels (e.g. whitespace or comments) are not
+ # added to the parse trees, they will not appear in the output of this
+ # method.
+ #/
+ def getText(self):
+ if self.getChildCount() == 0:
+ return ""
+ with StringIO() as builder:
+ for child in self.getChildren():
+ builder.write(child.getText())
+ return builder.getvalue()
+
+ def getRuleIndex(self):
+ return -1
+
+ # For rule associated with this parse tree internal node, return
+ # the outer alternative number used to match the input. Default
+ # implementation does not compute nor store this alt num. Create
+ # a subclass of ParserRuleContext with backing field and set
+ # option contextSuperClass.
+ # to set it.
+ def getAltNumber(self):
+ return 0 # should use ATN.INVALID_ALT_NUMBER but won't compile
+
+ # Set the outer alternative number for this context node. Default
+ # implementation does nothing to avoid backing field overhead for
+ # trees that don't need it. Create
+ # a subclass of ParserRuleContext with backing field and set
+ # option contextSuperClass.
+ def setAltNumber(self, altNumber:int):
+ pass
+
+ def getChild(self, i:int):
+ return None
+
+ def getChildCount(self):
+ return 0
+
+ def getChildren(self):
+ for c in []:
+ yield c
+
+ def accept(self, visitor:ParseTreeVisitor):
+ return visitor.visitChildren(self)
+
+ # # Call this method to view a parse tree in a dialog box visually.#/
+ # public Future inspect(@Nullable Parser parser) {
+ # List ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null;
+ # return inspect(ruleNames);
+ # }
+ #
+ # public Future inspect(@Nullable List ruleNames) {
+ # TreeViewer viewer = new TreeViewer(ruleNames, this);
+ # return viewer.open();
+ # }
+ #
+ # # Save this tree in a postscript file#/
+ # public void save(@Nullable Parser parser, String fileName)
+ # throws IOException, PrintException
+ # {
+ # List ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null;
+ # save(ruleNames, fileName);
+ # }
+ #
+ # # Save this tree in a postscript file using a particular font name and size#/
+ # public void save(@Nullable Parser parser, String fileName,
+ # String fontName, int fontSize)
+ # throws IOException
+ # {
+ # List ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null;
+ # save(ruleNames, fileName, fontName, fontSize);
+ # }
+ #
+ # # Save this tree in a postscript file#/
+ # public void save(@Nullable List ruleNames, String fileName)
+ # throws IOException, PrintException
+ # {
+ # Trees.writePS(this, ruleNames, fileName);
+ # }
+ #
+ # # Save this tree in a postscript file using a particular font name and size#/
+ # public void save(@Nullable List ruleNames, String fileName,
+ # String fontName, int fontSize)
+ # throws IOException
+ # {
+ # Trees.writePS(this, ruleNames, fileName, fontName, fontSize);
+ # }
+ #
+ # # Print out a whole tree, not just a node, in LISP format
+ # # (root child1 .. childN). Print just a node if this is a leaf.
+ # # We have to know the recognizer so we can get rule names.
+ # #/
+ # @Override
+ # public String toStringTree(@Nullable Parser recog) {
+ # return Trees.toStringTree(this, recog);
+ # }
+ #
+ # Print out a whole tree, not just a node, in LISP format
+ # (root child1 .. childN). Print just a node if this is a leaf.
+ #
+ def toStringTree(self, ruleNames:list=None, recog:Parser=None):
+ return Trees.toStringTree(self, ruleNames=ruleNames, recog=recog)
+ # }
+ #
+ # @Override
+ # public String toStringTree() {
+ # return toStringTree((List)null);
+ # }
+ #
+ def __str__(self):
+ return self.toString(None, None)
+
+ # @Override
+ # public String toString() {
+ # return toString((List)null, (RuleContext)null);
+ # }
+ #
+ # public final String toString(@Nullable Recognizer,?> recog) {
+ # return toString(recog, ParserRuleContext.EMPTY);
+ # }
+ #
+ # public final String toString(@Nullable List ruleNames) {
+ # return toString(ruleNames, null);
+ # }
+ #
+ # // recog null unless ParserRuleContext, in which case we use subclass toString(...)
+ # public String toString(@Nullable Recognizer,?> recog, @Nullable RuleContext stop) {
+ # String[] ruleNames = recog != null ? recog.getRuleNames() : null;
+ # List ruleNamesList = ruleNames != null ? Arrays.asList(ruleNames) : null;
+ # return toString(ruleNamesList, stop);
+ # }
+
+ def toString(self, ruleNames:list, stop:RuleContext)->str:
+ with StringIO() as buf:
+ p = self
+ buf.write("[")
+ while p is not None and p is not stop:
+ if ruleNames is None:
+ if not p.isEmpty():
+ buf.write(str(p.invokingState))
+ else:
+ ri = p.getRuleIndex()
+ ruleName = ruleNames[ri] if ri >= 0 and ri < len(ruleNames) else str(ri)
+ buf.write(ruleName)
+
+ if p.parentCtx is not None and (ruleNames is not None or not p.parentCtx.isEmpty()):
+ buf.write(" ")
+
+ p = p.parentCtx
+
+ buf.write("]")
+ return buf.getvalue()
diff --git a/venv/Lib/site-packages/antlr4/StdinStream.py b/venv/Lib/site-packages/antlr4/StdinStream.py
new file mode 100644
index 0000000000000000000000000000000000000000..f044fc4d770b4bc86cce2a5578f2c2fa00fc7602
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/StdinStream.py
@@ -0,0 +1,11 @@
+import codecs
+import sys
+
+from antlr4.InputStream import InputStream
+
+
+class StdinStream(InputStream):
+ def __init__(self, encoding:str='ascii', errors:str='strict') -> None:
+ bytes = sys.stdin.buffer.read()
+ data = codecs.decode(bytes, encoding, errors)
+ super().__init__(data)
diff --git a/venv/Lib/site-packages/antlr4/Token.py b/venv/Lib/site-packages/antlr4/Token.py
new file mode 100644
index 0000000000000000000000000000000000000000..10a68a8c2260e47838a1c9403def21725aecc244
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/Token.py
@@ -0,0 +1,155 @@
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+# A token has properties: text, type, line, character position in the line
+# (so we can ignore tabs), token channel, index, and source from which
+# we obtained this token.
+from io import StringIO
+
+
+class Token (object):
+ __slots__ = ('source', 'type', 'channel', 'start', 'stop', 'tokenIndex', 'line', 'column', '_text')
+
+ INVALID_TYPE = 0
+
+ # During lookahead operations, this "token" signifies we hit rule end ATN state
+ # and did not follow it despite needing to.
+ EPSILON = -2
+
+ MIN_USER_TOKEN_TYPE = 1
+
+ EOF = -1
+
+ # All tokens go to the parser (unless skip() is called in that rule)
+ # on a particular "channel". The parser tunes to a particular channel
+ # so that whitespace etc... can go to the parser on a "hidden" channel.
+
+ DEFAULT_CHANNEL = 0
+
+ # Anything on different channel than DEFAULT_CHANNEL is not parsed
+ # by parser.
+
+ HIDDEN_CHANNEL = 1
+
+ def __init__(self):
+ self.source = None
+ self.type = None # token type of the token
+ self.channel = None # The parser ignores everything not on DEFAULT_CHANNEL
+ self.start = None # optional; return -1 if not implemented.
+ self.stop = None # optional; return -1 if not implemented.
+ self.tokenIndex = None # from 0..n-1 of the token object in the input stream
+ self.line = None # line=1..n of the 1st character
+ self.column = None # beginning of the line at which it occurs, 0..n-1
+ self._text = None # text of the token.
+
+ @property
+ def text(self):
+ return self._text
+
+ # Explicitly set the text for this token. If {code text} is not
+ # {@code null}, then {@link #getText} will return this value rather than
+ # extracting the text from the input.
+ #
+ # @param text The explicit text of the token, or {@code null} if the text
+ # should be obtained from the input along with the start and stop indexes
+ # of the token.
+
+ @text.setter
+ def text(self, text:str):
+ self._text = text
+
+
+ def getTokenSource(self):
+ return self.source[0]
+
+ def getInputStream(self):
+ return self.source[1]
+
+class CommonToken(Token):
+
+ # An empty {@link Pair} which is used as the default value of
+ # {@link #source} for tokens that do not have a source.
+ EMPTY_SOURCE = (None, None)
+
+ def __init__(self, source:tuple = EMPTY_SOURCE, type:int = None, channel:int=Token.DEFAULT_CHANNEL, start:int=-1, stop:int=-1):
+ super().__init__()
+ self.source = source
+ self.type = type
+ self.channel = channel
+ self.start = start
+ self.stop = stop
+ self.tokenIndex = -1
+ if source[0] is not None:
+ self.line = source[0].line
+ self.column = source[0].column
+ else:
+ self.column = -1
+
+ # Constructs a new {@link CommonToken} as a copy of another {@link Token}.
+ #
+ #
+ # If {@code oldToken} is also a {@link CommonToken} instance, the newly
+ # constructed token will share a reference to the {@link #text} field and
+ # the {@link Pair} stored in {@link #source}. Otherwise, {@link #text} will
+ # be assigned the result of calling {@link #getText}, and {@link #source}
+ # will be constructed from the result of {@link Token#getTokenSource} and
+ # {@link Token#getInputStream}.
+ #
+ # @param oldToken The token to copy.
+ #
+ def clone(self):
+ t = CommonToken(self.source, self.type, self.channel, self.start, self.stop)
+ t.tokenIndex = self.tokenIndex
+ t.line = self.line
+ t.column = self.column
+ t.text = self.text
+ return t
+
+ @property
+ def text(self):
+ if self._text is not None:
+ return self._text
+ input = self.getInputStream()
+ if input is None:
+ return None
+ n = input.size
+ if self.start < n and self.stop < n:
+ return input.getText(self.start, self.stop)
+ else:
+ return ""
+
+ @text.setter
+ def text(self, text:str):
+ self._text = text
+
+ def __str__(self):
+ with StringIO() as buf:
+ buf.write("[@")
+ buf.write(str(self.tokenIndex))
+ buf.write(",")
+ buf.write(str(self.start))
+ buf.write(":")
+ buf.write(str(self.stop))
+ buf.write("='")
+ txt = self.text
+ if txt is not None:
+ txt = txt.replace("\n","\\n")
+ txt = txt.replace("\r","\\r")
+ txt = txt.replace("\t","\\t")
+ else:
+ txt = ""
+ buf.write(txt)
+ buf.write("',<")
+ buf.write(str(self.type))
+ buf.write(">")
+ if self.channel > 0:
+ buf.write(",channel=")
+ buf.write(str(self.channel))
+ buf.write(",")
+ buf.write(str(self.line))
+ buf.write(":")
+ buf.write(str(self.column))
+ buf.write("]")
+ return buf.getvalue()
diff --git a/venv/Lib/site-packages/antlr4/TokenStreamRewriter.py b/venv/Lib/site-packages/antlr4/TokenStreamRewriter.py
new file mode 100644
index 0000000000000000000000000000000000000000..59baf8f47a1ba447a143842c8df825ef58035918
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/TokenStreamRewriter.py
@@ -0,0 +1,255 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+from io import StringIO
+from antlr4.Token import Token
+
+from antlr4.CommonTokenStream import CommonTokenStream
+
+
+class TokenStreamRewriter(object):
+ __slots__ = ('tokens', 'programs', 'lastRewriteTokenIndexes')
+
+ DEFAULT_PROGRAM_NAME = "default"
+ PROGRAM_INIT_SIZE = 100
+ MIN_TOKEN_INDEX = 0
+
+ def __init__(self, tokens):
+ """
+ :type tokens: antlr4.BufferedTokenStream.BufferedTokenStream
+ :param tokens:
+ :return:
+ """
+ super(TokenStreamRewriter, self).__init__()
+ self.tokens = tokens
+ self.programs = {self.DEFAULT_PROGRAM_NAME: []}
+ self.lastRewriteTokenIndexes = {}
+
+ def getTokenStream(self):
+ return self.tokens
+
+ def rollback(self, instruction_index, program_name):
+ ins = self.programs.get(program_name, None)
+ if ins:
+ self.programs[program_name] = ins[self.MIN_TOKEN_INDEX: instruction_index]
+
+ def deleteProgram(self, program_name=DEFAULT_PROGRAM_NAME):
+ self.rollback(self.MIN_TOKEN_INDEX, program_name)
+
+ def insertAfterToken(self, token, text, program_name=DEFAULT_PROGRAM_NAME):
+ self.insertAfter(token.tokenIndex, text, program_name)
+
+ def insertAfter(self, index, text, program_name=DEFAULT_PROGRAM_NAME):
+ op = self.InsertAfterOp(self.tokens, index + 1, text)
+ rewrites = self.getProgram(program_name)
+ op.instructionIndex = len(rewrites)
+ rewrites.append(op)
+
+ def insertBeforeIndex(self, index, text):
+ self.insertBefore(self.DEFAULT_PROGRAM_NAME, index, text)
+
+ def insertBeforeToken(self, token, text, program_name=DEFAULT_PROGRAM_NAME):
+ self.insertBefore(program_name, token.tokenIndex, text)
+
+ def insertBefore(self, program_name, index, text):
+ op = self.InsertBeforeOp(self.tokens, index, text)
+ rewrites = self.getProgram(program_name)
+ op.instructionIndex = len(rewrites)
+ rewrites.append(op)
+
+ def replaceIndex(self, index, text):
+ self.replace(self.DEFAULT_PROGRAM_NAME, index, index, text)
+
+ def replaceRange(self, from_idx, to_idx, text):
+ self.replace(self.DEFAULT_PROGRAM_NAME, from_idx, to_idx, text)
+
+ def replaceSingleToken(self, token, text):
+ self.replace(self.DEFAULT_PROGRAM_NAME, token.tokenIndex, token.tokenIndex, text)
+
+ def replaceRangeTokens(self, from_token, to_token, text, program_name=DEFAULT_PROGRAM_NAME):
+ self.replace(program_name, from_token.tokenIndex, to_token.tokenIndex, text)
+
+ def replace(self, program_name, from_idx, to_idx, text):
+ if any((from_idx > to_idx, from_idx < 0, to_idx < 0, to_idx >= len(self.tokens.tokens))):
+ raise ValueError(
+ 'replace: range invalid: {}..{}(size={})'.format(from_idx, to_idx, len(self.tokens.tokens)))
+ op = self.ReplaceOp(from_idx, to_idx, self.tokens, text)
+ rewrites = self.getProgram(program_name)
+ op.instructionIndex = len(rewrites)
+ rewrites.append(op)
+
+ def deleteToken(self, token):
+ self.delete(self.DEFAULT_PROGRAM_NAME, token, token)
+
+ def deleteIndex(self, index):
+ self.delete(self.DEFAULT_PROGRAM_NAME, index, index)
+
+ def delete(self, program_name, from_idx, to_idx):
+ if isinstance(from_idx, Token):
+ self.replace(program_name, from_idx.tokenIndex, to_idx.tokenIndex, "")
+ else:
+ self.replace(program_name, from_idx, to_idx, "")
+
+ def lastRewriteTokenIndex(self, program_name=DEFAULT_PROGRAM_NAME):
+ return self.lastRewriteTokenIndexes.get(program_name, -1)
+
+ def setLastRewriteTokenIndex(self, program_name, i):
+ self.lastRewriteTokenIndexes[program_name] = i
+
+ def getProgram(self, program_name):
+ return self.programs.setdefault(program_name, [])
+
+ def getDefaultText(self):
+ return self.getText(self.DEFAULT_PROGRAM_NAME, 0, len(self.tokens.tokens) - 1)
+
+ def getText(self, program_name, start:int, stop:int):
+ """
+ :return: the text in tokens[start, stop](closed interval)
+ """
+ rewrites = self.programs.get(program_name)
+
+ # ensure start/end are in range
+ if stop > len(self.tokens.tokens) - 1:
+ stop = len(self.tokens.tokens) - 1
+ if start < 0:
+ start = 0
+
+ # if no instructions to execute
+ if not rewrites: return self.tokens.getText(start, stop)
+ buf = StringIO()
+ indexToOp = self._reduceToSingleOperationPerIndex(rewrites)
+ i = start
+ while all((i <= stop, i < len(self.tokens.tokens))):
+ op = indexToOp.pop(i, None)
+ token = self.tokens.get(i)
+ if op is None:
+ if token.type != Token.EOF: buf.write(token.text)
+ i += 1
+ else:
+ i = op.execute(buf)
+
+ if stop == len(self.tokens.tokens)-1:
+ for op in indexToOp.values():
+ if op.index >= len(self.tokens.tokens)-1: buf.write(op.text)
+
+ return buf.getvalue()
+
+ def _reduceToSingleOperationPerIndex(self, rewrites):
+ # Walk replaces
+ for i, rop in enumerate(rewrites):
+ if any((rop is None, not isinstance(rop, TokenStreamRewriter.ReplaceOp))):
+ continue
+ # Wipe prior inserts within range
+ inserts = [op for op in rewrites[:i] if isinstance(op, TokenStreamRewriter.InsertBeforeOp)]
+ for iop in inserts:
+ if iop.index == rop.index:
+ rewrites[iop.instructionIndex] = None
+ rop.text = '{}{}'.format(iop.text, rop.text)
+ elif all((iop.index > rop.index, iop.index <= rop.last_index)):
+ rewrites[iop.instructionIndex] = None
+
+ # Drop any prior replaces contained within
+ prevReplaces = [op for op in rewrites[:i] if isinstance(op, TokenStreamRewriter.ReplaceOp)]
+ for prevRop in prevReplaces:
+ if all((prevRop.index >= rop.index, prevRop.last_index <= rop.last_index)):
+ rewrites[prevRop.instructionIndex] = None
+ continue
+ isDisjoint = any((prevRop.last_indexrop.last_index))
+ if all((prevRop.text is None, rop.text is None, not isDisjoint)):
+ rewrites[prevRop.instructionIndex] = None
+ rop.index = min(prevRop.index, rop.index)
+ rop.last_index = min(prevRop.last_index, rop.last_index)
+ print('New rop {}'.format(rop))
+ elif (not(isDisjoint)):
+ raise ValueError("replace op boundaries of {} overlap with previous {}".format(rop, prevRop))
+
+ # Walk inserts
+ for i, iop in enumerate(rewrites):
+ if any((iop is None, not isinstance(iop, TokenStreamRewriter.InsertBeforeOp))):
+ continue
+ prevInserts = [op for op in rewrites[:i] if isinstance(op, TokenStreamRewriter.InsertBeforeOp)]
+ for prev_index, prevIop in enumerate(prevInserts):
+ if prevIop.index == iop.index and type(prevIop) is TokenStreamRewriter.InsertBeforeOp:
+ iop.text += prevIop.text
+ rewrites[prev_index] = None
+ elif prevIop.index == iop.index and type(prevIop) is TokenStreamRewriter.InsertAfterOp:
+ iop.text = prevIop.text + iop.text
+ rewrites[prev_index] = None
+ # look for replaces where iop.index is in range; error
+ prevReplaces = [op for op in rewrites[:i] if isinstance(op, TokenStreamRewriter.ReplaceOp)]
+ for rop in prevReplaces:
+ if iop.index == rop.index:
+ rop.text = iop.text + rop.text
+ rewrites[i] = None
+ continue
+ if all((iop.index >= rop.index, iop.index <= rop.last_index)):
+ raise ValueError("insert op {} within boundaries of previous {}".format(iop, rop))
+
+ reduced = {}
+ for i, op in enumerate(rewrites):
+ if op is None: continue
+ if reduced.get(op.index): raise ValueError('should be only one op per index')
+ reduced[op.index] = op
+
+ return reduced
+
+ class RewriteOperation(object):
+ __slots__ = ('tokens', 'index', 'text', 'instructionIndex')
+
+ def __init__(self, tokens, index, text=""):
+ """
+ :type tokens: CommonTokenStream
+ :param tokens:
+ :param index:
+ :param text:
+ :return:
+ """
+ self.tokens = tokens
+ self.index = index
+ self.text = text
+ self.instructionIndex = 0
+
+ def execute(self, buf):
+ """
+ :type buf: StringIO.StringIO
+ :param buf:
+ :return:
+ """
+ return self.index
+
+ def __str__(self):
+ return '<{}@{}:"{}">'.format(self.__class__.__name__, self.tokens.get(self.index), self.text)
+
+ class InsertBeforeOp(RewriteOperation):
+
+ def __init__(self, tokens, index, text=""):
+ super(TokenStreamRewriter.InsertBeforeOp, self).__init__(tokens, index, text)
+
+ def execute(self, buf):
+ buf.write(self.text)
+ if self.tokens.get(self.index).type != Token.EOF:
+ buf.write(self.tokens.get(self.index).text)
+ return self.index + 1
+
+ class InsertAfterOp(InsertBeforeOp):
+ pass
+
+ class ReplaceOp(RewriteOperation):
+ __slots__ = 'last_index'
+
+ def __init__(self, from_idx, to_idx, tokens, text):
+ super(TokenStreamRewriter.ReplaceOp, self).__init__(tokens, from_idx, text)
+ self.last_index = to_idx
+
+ def execute(self, buf):
+ if self.text:
+ buf.write(self.text)
+ return self.last_index + 1
+
+ def __str__(self):
+ if self.text:
+ return ''.format(self.tokens.get(self.index), self.tokens.get(self.last_index),
+ self.text)
diff --git a/venv/Lib/site-packages/antlr4/Utils.py b/venv/Lib/site-packages/antlr4/Utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..88c870dae63ef4bda74e25aea47befb75be34a5d
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/Utils.py
@@ -0,0 +1,33 @@
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+from io import StringIO
+
+def str_list(val):
+ with StringIO() as buf:
+ buf.write('[')
+ first = True
+ for item in val:
+ if not first:
+ buf.write(', ')
+ buf.write(str(item))
+ first = False
+ buf.write(']')
+ return buf.getvalue()
+
+def escapeWhitespace(s:str, escapeSpaces:bool):
+ with StringIO() as buf:
+ for c in s:
+ if c==' ' and escapeSpaces:
+ buf.write('\u00B7')
+ elif c=='\t':
+ buf.write("\\t")
+ elif c=='\n':
+ buf.write("\\n")
+ elif c=='\r':
+ buf.write("\\r")
+ else:
+ buf.write(c)
+ return buf.getvalue()
diff --git a/venv/Lib/site-packages/antlr4/__init__.py b/venv/Lib/site-packages/antlr4/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..42027289e7af293a297b538f07f43ca4a566ef62
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/__init__.py
@@ -0,0 +1,21 @@
+from antlr4.Token import Token
+from antlr4.InputStream import InputStream
+from antlr4.FileStream import FileStream
+from antlr4.StdinStream import StdinStream
+from antlr4.BufferedTokenStream import TokenStream
+from antlr4.CommonTokenStream import CommonTokenStream
+from antlr4.Lexer import Lexer
+from antlr4.Parser import Parser
+from antlr4.dfa.DFA import DFA
+from antlr4.atn.ATN import ATN
+from antlr4.atn.ATNDeserializer import ATNDeserializer
+from antlr4.atn.LexerATNSimulator import LexerATNSimulator
+from antlr4.atn.ParserATNSimulator import ParserATNSimulator
+from antlr4.atn.PredictionMode import PredictionMode
+from antlr4.PredictionContext import PredictionContextCache
+from antlr4.ParserRuleContext import RuleContext, ParserRuleContext
+from antlr4.tree.Tree import ParseTreeListener, ParseTreeVisitor, ParseTreeWalker, TerminalNode, ErrorNode, RuleNode
+from antlr4.error.Errors import RecognitionException, IllegalStateException, NoViableAltException
+from antlr4.error.ErrorStrategy import BailErrorStrategy
+from antlr4.error.DiagnosticErrorListener import DiagnosticErrorListener
+from antlr4.Utils import str_list
diff --git a/venv/Lib/site-packages/antlr4/_pygrun.py b/venv/Lib/site-packages/antlr4/_pygrun.py
new file mode 100644
index 0000000000000000000000000000000000000000..c392ca16aab25dcaf6fc72bcbf237e4564b10c20
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/_pygrun.py
@@ -0,0 +1,171 @@
+#!python
+__author__ = 'jszheng'
+import optparse
+import sys
+import os
+import importlib
+from antlr4 import *
+
+
+# this is a python version of TestRig
+def beautify_lisp_string(in_string):
+ indent_size = 3
+ add_indent = ' '*indent_size
+ out_string = in_string[0] # no indent for 1st (
+ indent = ''
+ for i in range(1, len(in_string)):
+ if in_string[i] == '(' and in_string[i+1] != ' ':
+ indent += add_indent
+ out_string += "\n" + indent + '('
+ elif in_string[i] == ')':
+ out_string += ')'
+ if len(indent) > 0:
+ indent = indent.replace(add_indent, '', 1)
+ else:
+ out_string += in_string[i]
+ return out_string
+
+
+def main():
+
+ #############################################################
+ # parse options
+ # not support -gui -encoding -ps
+ #############################################################
+ usage = "Usage: %prog [options] Grammar_Name Start_Rule"
+ parser = optparse.OptionParser(usage=usage)
+ # parser.add_option('-t', '--tree',
+ # dest="out_file",
+ # default="default.out",
+ # help='set output file name',
+ # )
+ parser.add_option('-t', '--tree',
+ default=False,
+ action='store_true',
+ help='Print AST tree'
+ )
+ parser.add_option('-k', '--tokens',
+ dest="token",
+ default=False,
+ action='store_true',
+ help='Show Tokens'
+ )
+ parser.add_option('-s', '--sll',
+ dest="sll",
+ default=False,
+ action='store_true',
+ help='Show SLL'
+ )
+ parser.add_option('-d', '--diagnostics',
+ dest="diagnostics",
+ default=False,
+ action='store_true',
+ help='Enable diagnostics error listener'
+ )
+ parser.add_option('-a', '--trace',
+ dest="trace",
+ default=False,
+ action='store_true',
+ help='Enable Trace'
+ )
+
+ options, remainder = parser.parse_args()
+ if len(remainder) < 2:
+ print('ERROR: You have to provide at least 2 arguments!')
+ parser.print_help()
+ exit(1)
+ else:
+ grammar = remainder.pop(0)
+ start_rule = remainder.pop(0)
+ file_list = remainder
+
+ #############################################################
+ # check and load antlr generated files
+ #############################################################
+ # dynamic load the module and class
+ lexerName = grammar + 'Lexer'
+ parserName = grammar + 'Parser'
+ # check if the generate file exist
+ lexer_file = lexerName + '.py'
+ parser_file = parserName + '.py'
+ if not os.path.exists(lexer_file):
+ print("[ERROR] Can't find lexer file {}!".format(lexer_file))
+ print(os.path.realpath('.'))
+ exit(1)
+ if not os.path.exists(parser_file):
+ print("[ERROR] Can't find parser file {}!".format(lexer_file))
+ print(os.path.realpath('.'))
+ exit(1)
+
+ # current directory is where the generated file loaded
+ # the script might be in different place.
+ sys.path.append('.')
+ # print(sys.path)
+
+ # add current directory to python global namespace in case of relative imports
+ globals().update({'__package__': os.path.basename(os.getcwd())})
+
+ # print("Load Lexer {}".format(lexerName))
+ module_lexer = __import__(lexerName, globals(), locals(), lexerName)
+ class_lexer = getattr(module_lexer, lexerName)
+ # print(class_lexer)
+
+ # print("Load Parser {}".format(parserName))
+ module_parser = __import__(parserName, globals(), locals(), parserName)
+ class_parser = getattr(module_parser, parserName)
+ # print(class_parser)
+
+ #############################################################
+ # main process steps.
+ #############################################################
+ def process(input_stream, class_lexer, class_parser):
+ lexer = class_lexer(input_stream)
+ token_stream = CommonTokenStream(lexer)
+ token_stream.fill()
+ if options.token: # need to show token
+ for tok in token_stream.tokens:
+ print(tok)
+ if start_rule == 'tokens':
+ return
+
+ parser = class_parser(token_stream)
+
+ if options.diagnostics:
+ parser.addErrorListener(DiagnosticErrorListener())
+ parser._interp.predictionMode = PredictionMode.LL_EXACT_AMBIG_DETECTION
+ if options.tree:
+ parser.buildParseTrees = True
+ if options.sll:
+ parser._interp.predictionMode = PredictionMode.SLL
+ #parser.setTokenStream(token_stream)
+ parser.setTrace(options.trace)
+ if hasattr(parser, start_rule):
+ func_start_rule = getattr(parser, start_rule)
+ parser_ret = func_start_rule()
+ if options.tree:
+ lisp_tree_str = parser_ret.toStringTree(recog=parser)
+ print(beautify_lisp_string(lisp_tree_str))
+ else:
+ print("[ERROR] Can't find start rule '{}' in parser '{}'".format(start_rule, parserName))
+
+ #############################################################
+ # use stdin if not provide file as input stream
+ #############################################################
+ if len(file_list) == 0:
+ input_stream = InputStream(sys.stdin.read())
+ process(input_stream, class_lexer, class_parser)
+ exit(0)
+
+ #############################################################
+ # iterate all input file
+ #############################################################
+ for file_name in file_list:
+ if os.path.exists(file_name) and os.path.isfile(file_name):
+ input_stream = FileStream(file_name)
+ process(input_stream, class_lexer, class_parser)
+ else:
+ print("[ERROR] file {} not exist".format(os.path.normpath(file_name)))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/venv/Lib/site-packages/antlr4/atn/ATN.py b/venv/Lib/site-packages/antlr4/atn/ATN.py
new file mode 100644
index 0000000000000000000000000000000000000000..3f1abe0a4a7faacde5140d5631dfe48a79325cd4
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/ATN.py
@@ -0,0 +1,132 @@
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+from antlr4.IntervalSet import IntervalSet
+
+from antlr4.RuleContext import RuleContext
+
+from antlr4.Token import Token
+from antlr4.atn.ATNType import ATNType
+from antlr4.atn.ATNState import ATNState, DecisionState
+
+
+class ATN(object):
+ __slots__ = (
+ 'grammarType', 'maxTokenType', 'states', 'decisionToState',
+ 'ruleToStartState', 'ruleToStopState', 'modeNameToStartState',
+ 'ruleToTokenType', 'lexerActions', 'modeToStartState'
+ )
+
+ INVALID_ALT_NUMBER = 0
+
+ # Used for runtime deserialization of ATNs from strings#/
+ def __init__(self, grammarType:ATNType , maxTokenType:int ):
+ # The type of the ATN.
+ self.grammarType = grammarType
+ # The maximum value for any symbol recognized by a transition in the ATN.
+ self.maxTokenType = maxTokenType
+ self.states = []
+ # Each subrule/rule is a decision point and we must track them so we
+ # can go back later and build DFA predictors for them. This includes
+ # all the rules, subrules, optional blocks, ()+, ()* etc...
+ self.decisionToState = []
+ # Maps from rule index to starting state number.
+ self.ruleToStartState = []
+ # Maps from rule index to stop state number.
+ self.ruleToStopState = None
+ self.modeNameToStartState = dict()
+ # For lexer ATNs, this maps the rule index to the resulting token type.
+ # For parser ATNs, this maps the rule index to the generated bypass token
+ # type if the
+ # {@link ATNDeserializationOptions#isGenerateRuleBypassTransitions}
+ # deserialization option was specified; otherwise, this is {@code null}.
+ self.ruleToTokenType = None
+ # For lexer ATNs, this is an array of {@link LexerAction} objects which may
+ # be referenced by action transitions in the ATN.
+ self.lexerActions = None
+ self.modeToStartState = []
+
+ # Compute the set of valid tokens that can occur starting in state {@code s}.
+ # If {@code ctx} is null, the set of tokens will not include what can follow
+ # the rule surrounding {@code s}. In other words, the set will be
+ # restricted to tokens reachable staying within {@code s}'s rule.
+ def nextTokensInContext(self, s:ATNState, ctx:RuleContext):
+ from antlr4.LL1Analyzer import LL1Analyzer
+ anal = LL1Analyzer(self)
+ return anal.LOOK(s, ctx=ctx)
+
+ # Compute the set of valid tokens that can occur starting in {@code s} and
+ # staying in same rule. {@link Token#EPSILON} is in set if we reach end of
+ # rule.
+ def nextTokensNoContext(self, s:ATNState):
+ if s.nextTokenWithinRule is not None:
+ return s.nextTokenWithinRule
+ s.nextTokenWithinRule = self.nextTokensInContext(s, None)
+ s.nextTokenWithinRule.readonly = True
+ return s.nextTokenWithinRule
+
+ def nextTokens(self, s:ATNState, ctx:RuleContext = None):
+ if ctx==None:
+ return self.nextTokensNoContext(s)
+ else:
+ return self.nextTokensInContext(s, ctx)
+
+ def addState(self, state:ATNState):
+ if state is not None:
+ state.atn = self
+ state.stateNumber = len(self.states)
+ self.states.append(state)
+
+ def removeState(self, state:ATNState):
+ self.states[state.stateNumber] = None # just free mem, don't shift states in list
+
+ def defineDecisionState(self, s:DecisionState):
+ self.decisionToState.append(s)
+ s.decision = len(self.decisionToState)-1
+ return s.decision
+
+ def getDecisionState(self, decision:int):
+ if len(self.decisionToState)==0:
+ return None
+ else:
+ return self.decisionToState[decision]
+
+ # Computes the set of input symbols which could follow ATN state number
+ # {@code stateNumber} in the specified full {@code context}. This method
+ # considers the complete parser context, but does not evaluate semantic
+ # predicates (i.e. all predicates encountered during the calculation are
+ # assumed true). If a path in the ATN exists from the starting state to the
+ # {@link RuleStopState} of the outermost context without matching any
+ # symbols, {@link Token#EOF} is added to the returned set.
+ #
+ #
If {@code context} is {@code null}, it is treated as
+ # {@link ParserRuleContext#EMPTY}.
+ #
+ # @param stateNumber the ATN state number
+ # @param context the full parse context
+ # @return The set of potentially valid input symbols which could follow the
+ # specified state in the specified context.
+ # @throws IllegalArgumentException if the ATN does not contain a state with
+ # number {@code stateNumber}
+ #/
+ def getExpectedTokens(self, stateNumber:int, ctx:RuleContext ):
+ if stateNumber < 0 or stateNumber >= len(self.states):
+ raise Exception("Invalid state number.")
+ s = self.states[stateNumber]
+ following = self.nextTokens(s)
+ if Token.EPSILON not in following:
+ return following
+ expected = IntervalSet()
+ expected.addSet(following)
+ expected.removeOne(Token.EPSILON)
+ while (ctx != None and ctx.invokingState >= 0 and Token.EPSILON in following):
+ invokingState = self.states[ctx.invokingState]
+ rt = invokingState.transitions[0]
+ following = self.nextTokens(rt.followState)
+ expected.addSet(following)
+ expected.removeOne(Token.EPSILON)
+ ctx = ctx.parentCtx
+ if Token.EPSILON in following:
+ expected.addOne(Token.EOF)
+ return expected
diff --git a/venv/Lib/site-packages/antlr4/atn/ATNConfig.py b/venv/Lib/site-packages/antlr4/atn/ATNConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..e008fb2efac45a24b6d9566170bbd227cee252b6
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/ATNConfig.py
@@ -0,0 +1,159 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+
+# A tuple: (ATN state, predicted alt, syntactic, semantic context).
+# The syntactic context is a graph-structured stack node whose
+# path(s) to the root is the rule invocation(s)
+# chain used to arrive at the state. The semantic context is
+# the tree of semantic predicates encountered before reaching
+# an ATN state.
+#/
+from io import StringIO
+from antlr4.PredictionContext import PredictionContext
+from antlr4.atn.ATNState import ATNState, DecisionState
+from antlr4.atn.LexerActionExecutor import LexerActionExecutor
+from antlr4.atn.SemanticContext import SemanticContext
+
+# need a forward declaration
+ATNConfig = None
+
+class ATNConfig(object):
+ __slots__ = (
+ 'state', 'alt', 'context', 'semanticContext', 'reachesIntoOuterContext',
+ 'precedenceFilterSuppressed'
+ )
+
+ def __init__(self, state:ATNState=None, alt:int=None, context:PredictionContext=None, semantic:SemanticContext=None, config:ATNConfig=None):
+ if config is not None:
+ if state is None:
+ state = config.state
+ if alt is None:
+ alt = config.alt
+ if context is None:
+ context = config.context
+ if semantic is None:
+ semantic = config.semanticContext
+ if semantic is None:
+ semantic = SemanticContext.NONE
+ # The ATN state associated with this configuration#/
+ self.state = state
+ # What alt (or lexer rule) is predicted by this configuration#/
+ self.alt = alt
+ # The stack of invoking states leading to the rule/states associated
+ # with this config. We track only those contexts pushed during
+ # execution of the ATN simulator.
+ self.context = context
+ self.semanticContext = semantic
+ # We cannot execute predicates dependent upon local context unless
+ # we know for sure we are in the correct context. Because there is
+ # no way to do this efficiently, we simply cannot evaluate
+ # dependent predicates unless we are in the rule that initially
+ # invokes the ATN simulator.
+ #
+ # closure() tracks the depth of how far we dip into the
+ # outer context: depth > 0. Note that it may not be totally
+ # accurate depth since I don't ever decrement. TODO: make it a boolean then
+ self.reachesIntoOuterContext = 0 if config is None else config.reachesIntoOuterContext
+ self.precedenceFilterSuppressed = False if config is None else config.precedenceFilterSuppressed
+
+ # An ATN configuration is equal to another if both have
+ # the same state, they predict the same alternative, and
+ # syntactic/semantic contexts are the same.
+ #/
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, ATNConfig):
+ return False
+ else:
+ return self.state.stateNumber==other.state.stateNumber \
+ and self.alt==other.alt \
+ and ((self.context is other.context) or (self.context==other.context)) \
+ and self.semanticContext==other.semanticContext \
+ and self.precedenceFilterSuppressed==other.precedenceFilterSuppressed
+
+ def __hash__(self):
+ return hash((self.state.stateNumber, self.alt, self.context, self.semanticContext))
+
+ def hashCodeForConfigSet(self):
+ return hash((self.state.stateNumber, self.alt, hash(self.semanticContext)))
+
+ def equalsForConfigSet(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, ATNConfig):
+ return False
+ else:
+ return self.state.stateNumber==other.state.stateNumber \
+ and self.alt==other.alt \
+ and self.semanticContext==other.semanticContext
+
+ def __str__(self):
+ with StringIO() as buf:
+ buf.write('(')
+ buf.write(str(self.state))
+ buf.write(",")
+ buf.write(str(self.alt))
+ if self.context is not None:
+ buf.write(",[")
+ buf.write(str(self.context))
+ buf.write("]")
+ if self.semanticContext is not None and self.semanticContext is not SemanticContext.NONE:
+ buf.write(",")
+ buf.write(str(self.semanticContext))
+ if self.reachesIntoOuterContext>0:
+ buf.write(",up=")
+ buf.write(str(self.reachesIntoOuterContext))
+ buf.write(')')
+ return buf.getvalue()
+
+# need a forward declaration
+LexerATNConfig = None
+
+class LexerATNConfig(ATNConfig):
+ __slots__ = ('lexerActionExecutor', 'passedThroughNonGreedyDecision')
+
+ def __init__(self, state:ATNState, alt:int=None, context:PredictionContext=None, semantic:SemanticContext=SemanticContext.NONE,
+ lexerActionExecutor:LexerActionExecutor=None, config:LexerATNConfig=None):
+ super().__init__(state=state, alt=alt, context=context, semantic=semantic, config=config)
+ if config is not None:
+ if lexerActionExecutor is None:
+ lexerActionExecutor = config.lexerActionExecutor
+ # This is the backing field for {@link #getLexerActionExecutor}.
+ self.lexerActionExecutor = lexerActionExecutor
+ self.passedThroughNonGreedyDecision = False if config is None else self.checkNonGreedyDecision(config, state)
+
+ def __hash__(self):
+ return hash((self.state.stateNumber, self.alt, self.context,
+ self.semanticContext, self.passedThroughNonGreedyDecision,
+ self.lexerActionExecutor))
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, LexerATNConfig):
+ return False
+ if self.passedThroughNonGreedyDecision != other.passedThroughNonGreedyDecision:
+ return False
+ if not(self.lexerActionExecutor == other.lexerActionExecutor):
+ return False
+ return super().__eq__(other)
+
+
+
+ def hashCodeForConfigSet(self):
+ return hash(self)
+
+
+
+ def equalsForConfigSet(self, other):
+ return self==other
+
+
+
+ def checkNonGreedyDecision(self, source:LexerATNConfig, target:ATNState):
+ return source.passedThroughNonGreedyDecision \
+ or isinstance(target, DecisionState) and target.nonGreedy
diff --git a/venv/Lib/site-packages/antlr4/atn/ATNConfigSet.py b/venv/Lib/site-packages/antlr4/atn/ATNConfigSet.py
new file mode 100644
index 0000000000000000000000000000000000000000..d1886a4a5d3643fbdbf8a7ea191f31e433cad0ef
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/ATNConfigSet.py
@@ -0,0 +1,212 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+
+from antlr4.PredictionContext import merge
+from antlr4.Utils import str_list
+from antlr4.atn.ATN import ATN
+from antlr4.atn.ATNConfig import ATNConfig
+from antlr4.atn.SemanticContext import SemanticContext
+from antlr4.error.Errors import UnsupportedOperationException, IllegalStateException
+from functools import reduce
+#
+# Specialized {@link Set}{@code <}{@link ATNConfig}{@code >} that can track
+# info about the set, with support for combining similar configurations using a
+# graph-structured stack.
+# /
+from io import StringIO
+
+ATNSimulator = None
+
+class ATNConfigSet(object):
+ __slots__ = (
+ 'configLookup', 'fullCtx', 'readonly', 'configs', 'uniqueAlt',
+ 'conflictingAlts', 'hasSemanticContext', 'dipsIntoOuterContext',
+ 'cachedHashCode'
+ )
+
+ #
+ # The reason that we need this is because we don't want the hash map to use
+ # the standard hash code and equals. We need all configurations with the same
+ # {@code (s,i,_,semctx)} to be equal. Unfortunately, this key effectively doubles
+ # the number of objects associated with ATNConfigs. The other solution is to
+ # use a hash table that lets us specify the equals/hashcode operation.
+
+ def __init__(self, fullCtx:bool=True):
+ # All configs but hashed by (s, i, _, pi) not including context. Wiped out
+ # when we go readonly as this set becomes a DFA state.
+ self.configLookup = dict()
+ # Indicates that this configuration set is part of a full context
+ # LL prediction. It will be used to determine how to merge $. With SLL
+ # it's a wildcard whereas it is not for LL context merge.
+ self.fullCtx = fullCtx
+ # Indicates that the set of configurations is read-only. Do not
+ # allow any code to manipulate the set; DFA states will point at
+ # the sets and they must not change. This does not protect the other
+ # fields; in particular, conflictingAlts is set after
+ # we've made this readonly.
+ self.readonly = False
+ # Track the elements as they are added to the set; supports get(i)#/
+ self.configs = []
+
+ # TODO: these fields make me pretty uncomfortable but nice to pack up info together, saves recomputation
+ # TODO: can we track conflicts as they are added to save scanning configs later?
+ self.uniqueAlt = 0
+ self.conflictingAlts = None
+
+ # Used in parser and lexer. In lexer, it indicates we hit a pred
+ # while computing a closure operation. Don't make a DFA state from this.
+ self.hasSemanticContext = False
+ self.dipsIntoOuterContext = False
+
+ self.cachedHashCode = -1
+
+ def __iter__(self):
+ return self.configs.__iter__()
+
+ # Adding a new config means merging contexts with existing configs for
+ # {@code (s, i, pi, _)}, where {@code s} is the
+ # {@link ATNConfig#state}, {@code i} is the {@link ATNConfig#alt}, and
+ # {@code pi} is the {@link ATNConfig#semanticContext}. We use
+ # {@code (s,i,pi)} as key.
+ #
+ #
This method updates {@link #dipsIntoOuterContext} and
+ # {@link #hasSemanticContext} when necessary.
+ #/
+ def add(self, config:ATNConfig, mergeCache=None):
+ if self.readonly:
+ raise Exception("This set is readonly")
+ if config.semanticContext is not SemanticContext.NONE:
+ self.hasSemanticContext = True
+ if config.reachesIntoOuterContext > 0:
+ self.dipsIntoOuterContext = True
+ existing = self.getOrAdd(config)
+ if existing is config:
+ self.cachedHashCode = -1
+ self.configs.append(config) # track order here
+ return True
+ # a previous (s,i,pi,_), merge with it and save result
+ rootIsWildcard = not self.fullCtx
+ merged = merge(existing.context, config.context, rootIsWildcard, mergeCache)
+ # no need to check for existing.context, config.context in cache
+ # since only way to create new graphs is "call rule" and here.
+ # We cache at both places.
+ existing.reachesIntoOuterContext = max(existing.reachesIntoOuterContext, config.reachesIntoOuterContext)
+ # make sure to preserve the precedence filter suppression during the merge
+ if config.precedenceFilterSuppressed:
+ existing.precedenceFilterSuppressed = True
+ existing.context = merged # replace context; no need to alt mapping
+ return True
+
+ def getOrAdd(self, config:ATNConfig):
+ h = config.hashCodeForConfigSet()
+ l = self.configLookup.get(h, None)
+ if l is not None:
+ r = next((cfg for cfg in l if config.equalsForConfigSet(cfg)), None)
+ if r is not None:
+ return r
+ if l is None:
+ l = [config]
+ self.configLookup[h] = l
+ else:
+ l.append(config)
+ return config
+
+ def getStates(self):
+ return set(c.state for c in self.configs)
+
+ def getPredicates(self):
+ return list(cfg.semanticContext for cfg in self.configs if cfg.semanticContext!=SemanticContext.NONE)
+
+ def get(self, i:int):
+ return self.configs[i]
+
+ def optimizeConfigs(self, interpreter:ATNSimulator):
+ if self.readonly:
+ raise IllegalStateException("This set is readonly")
+ if len(self.configs)==0:
+ return
+ for config in self.configs:
+ config.context = interpreter.getCachedContext(config.context)
+
+ def addAll(self, coll:list):
+ for c in coll:
+ self.add(c)
+ return False
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, ATNConfigSet):
+ return False
+
+ same = self.configs is not None and \
+ self.configs==other.configs and \
+ self.fullCtx == other.fullCtx and \
+ self.uniqueAlt == other.uniqueAlt and \
+ self.conflictingAlts == other.conflictingAlts and \
+ self.hasSemanticContext == other.hasSemanticContext and \
+ self.dipsIntoOuterContext == other.dipsIntoOuterContext
+
+ return same
+
+ def __hash__(self):
+ if self.readonly:
+ if self.cachedHashCode == -1:
+ self.cachedHashCode = self.hashConfigs()
+ return self.cachedHashCode
+ return self.hashConfigs()
+
+ def hashConfigs(self):
+ return reduce(lambda h, cfg: hash((h, cfg)), self.configs, 0)
+
+ def __len__(self):
+ return len(self.configs)
+
+ def isEmpty(self):
+ return len(self.configs)==0
+
+ def __contains__(self, config):
+ if self.configLookup is None:
+ raise UnsupportedOperationException("This method is not implemented for readonly sets.")
+ h = config.hashCodeForConfigSet()
+ l = self.configLookup.get(h, None)
+ if l is not None:
+ for c in l:
+ if config.equalsForConfigSet(c):
+ return True
+ return False
+
+ def clear(self):
+ if self.readonly:
+ raise IllegalStateException("This set is readonly")
+ self.configs.clear()
+ self.cachedHashCode = -1
+ self.configLookup.clear()
+
+ def setReadonly(self, readonly:bool):
+ self.readonly = readonly
+ self.configLookup = None # can't mod, no need for lookup cache
+
+ def __str__(self):
+ with StringIO() as buf:
+ buf.write(str_list(self.configs))
+ if self.hasSemanticContext:
+ buf.write(",hasSemanticContext=")
+ buf.write(str(self.hasSemanticContext).lower()) # lower() to conform to java output
+ if self.uniqueAlt!=ATN.INVALID_ALT_NUMBER:
+ buf.write(",uniqueAlt=")
+ buf.write(str(self.uniqueAlt))
+ if self.conflictingAlts is not None:
+ buf.write(",conflictingAlts=")
+ buf.write(str(self.conflictingAlts))
+ if self.dipsIntoOuterContext:
+ buf.write(",dipsIntoOuterContext")
+ return buf.getvalue()
+
+
+class OrderedATNConfigSet(ATNConfigSet):
+
+ def __init__(self):
+ super().__init__()
diff --git a/venv/Lib/site-packages/antlr4/atn/ATNDeserializationOptions.py b/venv/Lib/site-packages/antlr4/atn/ATNDeserializationOptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..69d5437f35437874a60bcc76118f018edbf65fed
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/ATNDeserializationOptions.py
@@ -0,0 +1,24 @@
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+
+# need a forward declaration
+ATNDeserializationOptions = None
+
+class ATNDeserializationOptions(object):
+ __slots__ = ('readonly', 'verifyATN', 'generateRuleBypassTransitions')
+
+ defaultOptions = None
+
+ def __init__(self, copyFrom:ATNDeserializationOptions = None):
+ self.readonly = False
+ self.verifyATN = True if copyFrom is None else copyFrom.verifyATN
+ self.generateRuleBypassTransitions = False if copyFrom is None else copyFrom.generateRuleBypassTransitions
+
+ def __setattr__(self, key, value):
+ if key!="readonly" and self.readonly:
+ raise Exception("The object is read only.")
+ super(type(self), self).__setattr__(key,value)
+
+ATNDeserializationOptions.defaultOptions = ATNDeserializationOptions()
+ATNDeserializationOptions.defaultOptions.readonly = True
diff --git a/venv/Lib/site-packages/antlr4/atn/ATNDeserializer.py b/venv/Lib/site-packages/antlr4/atn/ATNDeserializer.py
new file mode 100644
index 0000000000000000000000000000000000000000..c491ac4c6532257fa613da8c4b56ece902c65168
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/ATNDeserializer.py
@@ -0,0 +1,446 @@
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+from io import StringIO
+from typing import Callable
+from antlr4.Token import Token
+from antlr4.atn.ATN import ATN
+from antlr4.atn.ATNType import ATNType
+from antlr4.atn.ATNState import *
+from antlr4.atn.Transition import *
+from antlr4.atn.LexerAction import *
+from antlr4.atn.ATNDeserializationOptions import ATNDeserializationOptions
+
+SERIALIZED_VERSION = 4
+
+class ATNDeserializer (object):
+ __slots__ = ('deserializationOptions', 'data', 'pos')
+
+ def __init__(self, options : ATNDeserializationOptions = None):
+ if options is None:
+ options = ATNDeserializationOptions.defaultOptions
+ self.deserializationOptions = options
+
+ def deserialize(self, data : [int]):
+ self.data = data
+ self.pos = 0
+ self.checkVersion()
+ atn = self.readATN()
+ self.readStates(atn)
+ self.readRules(atn)
+ self.readModes(atn)
+ sets = []
+ self.readSets(atn, sets)
+ self.readEdges(atn, sets)
+ self.readDecisions(atn)
+ self.readLexerActions(atn)
+ self.markPrecedenceDecisions(atn)
+ self.verifyATN(atn)
+ if self.deserializationOptions.generateRuleBypassTransitions \
+ and atn.grammarType == ATNType.PARSER:
+ self.generateRuleBypassTransitions(atn)
+ # re-verify after modification
+ self.verifyATN(atn)
+ return atn
+
+ def checkVersion(self):
+ version = self.readInt()
+ if version != SERIALIZED_VERSION:
+ raise Exception("Could not deserialize ATN with version {} (expected {}).".format(ord(version), SERIALIZED_VERSION))
+
+ def readATN(self):
+ idx = self.readInt()
+ grammarType = ATNType.fromOrdinal(idx)
+ maxTokenType = self.readInt()
+ return ATN(grammarType, maxTokenType)
+
+ def readStates(self, atn:ATN):
+ loopBackStateNumbers = []
+ endStateNumbers = []
+ nstates = self.readInt()
+ for i in range(0, nstates):
+ stype = self.readInt()
+ # ignore bad type of states
+ if stype==ATNState.INVALID_TYPE:
+ atn.addState(None)
+ continue
+ ruleIndex = self.readInt()
+ s = self.stateFactory(stype, ruleIndex)
+ if stype == ATNState.LOOP_END: # special case
+ loopBackStateNumber = self.readInt()
+ loopBackStateNumbers.append((s, loopBackStateNumber))
+ elif isinstance(s, BlockStartState):
+ endStateNumber = self.readInt()
+ endStateNumbers.append((s, endStateNumber))
+
+ atn.addState(s)
+
+ # delay the assignment of loop back and end states until we know all the state instances have been initialized
+ for pair in loopBackStateNumbers:
+ pair[0].loopBackState = atn.states[pair[1]]
+
+ for pair in endStateNumbers:
+ pair[0].endState = atn.states[pair[1]]
+
+ numNonGreedyStates = self.readInt()
+ for i in range(0, numNonGreedyStates):
+ stateNumber = self.readInt()
+ atn.states[stateNumber].nonGreedy = True
+
+ numPrecedenceStates = self.readInt()
+ for i in range(0, numPrecedenceStates):
+ stateNumber = self.readInt()
+ atn.states[stateNumber].isPrecedenceRule = True
+
+ def readRules(self, atn:ATN):
+ nrules = self.readInt()
+ if atn.grammarType == ATNType.LEXER:
+ atn.ruleToTokenType = [0] * nrules
+
+ atn.ruleToStartState = [0] * nrules
+ for i in range(0, nrules):
+ s = self.readInt()
+ startState = atn.states[s]
+ atn.ruleToStartState[i] = startState
+ if atn.grammarType == ATNType.LEXER:
+ tokenType = self.readInt()
+ atn.ruleToTokenType[i] = tokenType
+
+ atn.ruleToStopState = [0] * nrules
+ for state in atn.states:
+ if not isinstance(state, RuleStopState):
+ continue
+ atn.ruleToStopState[state.ruleIndex] = state
+ atn.ruleToStartState[state.ruleIndex].stopState = state
+
+ def readModes(self, atn:ATN):
+ nmodes = self.readInt()
+ for i in range(0, nmodes):
+ s = self.readInt()
+ atn.modeToStartState.append(atn.states[s])
+
+ def readSets(self, atn:ATN, sets:list):
+ m = self.readInt()
+ for i in range(0, m):
+ iset = IntervalSet()
+ sets.append(iset)
+ n = self.readInt()
+ containsEof = self.readInt()
+ if containsEof!=0:
+ iset.addOne(-1)
+ for j in range(0, n):
+ i1 = self.readInt()
+ i2 = self.readInt()
+ iset.addRange(range(i1, i2 + 1)) # range upper limit is exclusive
+
+ def readEdges(self, atn:ATN, sets:list):
+ nedges = self.readInt()
+ for i in range(0, nedges):
+ src = self.readInt()
+ trg = self.readInt()
+ ttype = self.readInt()
+ arg1 = self.readInt()
+ arg2 = self.readInt()
+ arg3 = self.readInt()
+ trans = self.edgeFactory(atn, ttype, src, trg, arg1, arg2, arg3, sets)
+ srcState = atn.states[src]
+ srcState.addTransition(trans)
+
+ # edges for rule stop states can be derived, so they aren't serialized
+ for state in atn.states:
+ for i in range(0, len(state.transitions)):
+ t = state.transitions[i]
+ if not isinstance(t, RuleTransition):
+ continue
+ outermostPrecedenceReturn = -1
+ if atn.ruleToStartState[t.target.ruleIndex].isPrecedenceRule:
+ if t.precedence == 0:
+ outermostPrecedenceReturn = t.target.ruleIndex
+ trans = EpsilonTransition(t.followState, outermostPrecedenceReturn)
+ atn.ruleToStopState[t.target.ruleIndex].addTransition(trans)
+
+ for state in atn.states:
+ if isinstance(state, BlockStartState):
+ # we need to know the end state to set its start state
+ if state.endState is None:
+ raise Exception("IllegalState")
+ # block end states can only be associated to a single block start state
+ if state.endState.startState is not None:
+ raise Exception("IllegalState")
+ state.endState.startState = state
+
+ if isinstance(state, PlusLoopbackState):
+ for i in range(0, len(state.transitions)):
+ target = state.transitions[i].target
+ if isinstance(target, PlusBlockStartState):
+ target.loopBackState = state
+ elif isinstance(state, StarLoopbackState):
+ for i in range(0, len(state.transitions)):
+ target = state.transitions[i].target
+ if isinstance(target, StarLoopEntryState):
+ target.loopBackState = state
+
+ def readDecisions(self, atn:ATN):
+ ndecisions = self.readInt()
+ for i in range(0, ndecisions):
+ s = self.readInt()
+ decState = atn.states[s]
+ atn.decisionToState.append(decState)
+ decState.decision = i
+
+ def readLexerActions(self, atn:ATN):
+ if atn.grammarType == ATNType.LEXER:
+ count = self.readInt()
+ atn.lexerActions = [ None ] * count
+ for i in range(0, count):
+ actionType = self.readInt()
+ data1 = self.readInt()
+ data2 = self.readInt()
+ lexerAction = self.lexerActionFactory(actionType, data1, data2)
+ atn.lexerActions[i] = lexerAction
+
+ def generateRuleBypassTransitions(self, atn:ATN):
+
+ count = len(atn.ruleToStartState)
+ atn.ruleToTokenType = [ 0 ] * count
+ for i in range(0, count):
+ atn.ruleToTokenType[i] = atn.maxTokenType + i + 1
+
+ for i in range(0, count):
+ self.generateRuleBypassTransition(atn, i)
+
+ def generateRuleBypassTransition(self, atn:ATN, idx:int):
+
+ bypassStart = BasicBlockStartState()
+ bypassStart.ruleIndex = idx
+ atn.addState(bypassStart)
+
+ bypassStop = BlockEndState()
+ bypassStop.ruleIndex = idx
+ atn.addState(bypassStop)
+
+ bypassStart.endState = bypassStop
+ atn.defineDecisionState(bypassStart)
+
+ bypassStop.startState = bypassStart
+
+ excludeTransition = None
+
+ if atn.ruleToStartState[idx].isPrecedenceRule:
+ # wrap from the beginning of the rule to the StarLoopEntryState
+ endState = None
+ for state in atn.states:
+ if self.stateIsEndStateFor(state, idx):
+ endState = state
+ excludeTransition = state.loopBackState.transitions[0]
+ break
+
+ if excludeTransition is None:
+ raise Exception("Couldn't identify final state of the precedence rule prefix section.")
+
+ else:
+
+ endState = atn.ruleToStopState[idx]
+
+ # all non-excluded transitions that currently target end state need to target blockEnd instead
+ for state in atn.states:
+ for transition in state.transitions:
+ if transition == excludeTransition:
+ continue
+ if transition.target == endState:
+ transition.target = bypassStop
+
+ # all transitions leaving the rule start state need to leave blockStart instead
+ ruleToStartState = atn.ruleToStartState[idx]
+ count = len(ruleToStartState.transitions)
+ while count > 0:
+ bypassStart.addTransition(ruleToStartState.transitions[count-1])
+ del ruleToStartState.transitions[-1]
+
+ # link the new states
+ atn.ruleToStartState[idx].addTransition(EpsilonTransition(bypassStart))
+ bypassStop.addTransition(EpsilonTransition(endState))
+
+ matchState = BasicState()
+ atn.addState(matchState)
+ matchState.addTransition(AtomTransition(bypassStop, atn.ruleToTokenType[idx]))
+ bypassStart.addTransition(EpsilonTransition(matchState))
+
+
+ def stateIsEndStateFor(self, state:ATNState, idx:int):
+ if state.ruleIndex != idx:
+ return None
+ if not isinstance(state, StarLoopEntryState):
+ return None
+
+ maybeLoopEndState = state.transitions[len(state.transitions) - 1].target
+ if not isinstance(maybeLoopEndState, LoopEndState):
+ return None
+
+ if maybeLoopEndState.epsilonOnlyTransitions and \
+ isinstance(maybeLoopEndState.transitions[0].target, RuleStopState):
+ return state
+ else:
+ return None
+
+
+ #
+ # Analyze the {@link StarLoopEntryState} states in the specified ATN to set
+ # the {@link StarLoopEntryState#isPrecedenceDecision} field to the
+ # correct value.
+ #
+ # @param atn The ATN.
+ #
+ def markPrecedenceDecisions(self, atn:ATN):
+ for state in atn.states:
+ if not isinstance(state, StarLoopEntryState):
+ continue
+
+ # We analyze the ATN to determine if this ATN decision state is the
+ # decision for the closure block that determines whether a
+ # precedence rule should continue or complete.
+ #
+ if atn.ruleToStartState[state.ruleIndex].isPrecedenceRule:
+ maybeLoopEndState = state.transitions[len(state.transitions) - 1].target
+ if isinstance(maybeLoopEndState, LoopEndState):
+ if maybeLoopEndState.epsilonOnlyTransitions and \
+ isinstance(maybeLoopEndState.transitions[0].target, RuleStopState):
+ state.isPrecedenceDecision = True
+
+ def verifyATN(self, atn:ATN):
+ if not self.deserializationOptions.verifyATN:
+ return
+ # verify assumptions
+ for state in atn.states:
+ if state is None:
+ continue
+
+ self.checkCondition(state.epsilonOnlyTransitions or len(state.transitions) <= 1)
+
+ if isinstance(state, PlusBlockStartState):
+ self.checkCondition(state.loopBackState is not None)
+
+ if isinstance(state, StarLoopEntryState):
+ self.checkCondition(state.loopBackState is not None)
+ self.checkCondition(len(state.transitions) == 2)
+
+ if isinstance(state.transitions[0].target, StarBlockStartState):
+ self.checkCondition(isinstance(state.transitions[1].target, LoopEndState))
+ self.checkCondition(not state.nonGreedy)
+ elif isinstance(state.transitions[0].target, LoopEndState):
+ self.checkCondition(isinstance(state.transitions[1].target, StarBlockStartState))
+ self.checkCondition(state.nonGreedy)
+ else:
+ raise Exception("IllegalState")
+
+ if isinstance(state, StarLoopbackState):
+ self.checkCondition(len(state.transitions) == 1)
+ self.checkCondition(isinstance(state.transitions[0].target, StarLoopEntryState))
+
+ if isinstance(state, LoopEndState):
+ self.checkCondition(state.loopBackState is not None)
+
+ if isinstance(state, RuleStartState):
+ self.checkCondition(state.stopState is not None)
+
+ if isinstance(state, BlockStartState):
+ self.checkCondition(state.endState is not None)
+
+ if isinstance(state, BlockEndState):
+ self.checkCondition(state.startState is not None)
+
+ if isinstance(state, DecisionState):
+ self.checkCondition(len(state.transitions) <= 1 or state.decision >= 0)
+ else:
+ self.checkCondition(len(state.transitions) <= 1 or isinstance(state, RuleStopState))
+
+ def checkCondition(self, condition:bool, message=None):
+ if not condition:
+ if message is None:
+ message = "IllegalState"
+ raise Exception(message)
+
+ def readInt(self):
+ i = self.data[self.pos]
+ self.pos += 1
+ return i
+
+ edgeFactories = [ lambda args : None,
+ lambda atn, src, trg, arg1, arg2, arg3, sets, target : EpsilonTransition(target),
+ lambda atn, src, trg, arg1, arg2, arg3, sets, target : \
+ RangeTransition(target, Token.EOF, arg2) if arg3 != 0 else RangeTransition(target, arg1, arg2),
+ lambda atn, src, trg, arg1, arg2, arg3, sets, target : \
+ RuleTransition(atn.states[arg1], arg2, arg3, target),
+ lambda atn, src, trg, arg1, arg2, arg3, sets, target : \
+ PredicateTransition(target, arg1, arg2, arg3 != 0),
+ lambda atn, src, trg, arg1, arg2, arg3, sets, target : \
+ AtomTransition(target, Token.EOF) if arg3 != 0 else AtomTransition(target, arg1),
+ lambda atn, src, trg, arg1, arg2, arg3, sets, target : \
+ ActionTransition(target, arg1, arg2, arg3 != 0),
+ lambda atn, src, trg, arg1, arg2, arg3, sets, target : \
+ SetTransition(target, sets[arg1]),
+ lambda atn, src, trg, arg1, arg2, arg3, sets, target : \
+ NotSetTransition(target, sets[arg1]),
+ lambda atn, src, trg, arg1, arg2, arg3, sets, target : \
+ WildcardTransition(target),
+ lambda atn, src, trg, arg1, arg2, arg3, sets, target : \
+ PrecedencePredicateTransition(target, arg1)
+ ]
+
+ def edgeFactory(self, atn:ATN, type:int, src:int, trg:int, arg1:int, arg2:int, arg3:int, sets:list):
+ target = atn.states[trg]
+ if type > len(self.edgeFactories) or self.edgeFactories[type] is None:
+ raise Exception("The specified transition type: " + str(type) + " is not valid.")
+ else:
+ return self.edgeFactories[type](atn, src, trg, arg1, arg2, arg3, sets, target)
+
+ stateFactories = [ lambda : None,
+ lambda : BasicState(),
+ lambda : RuleStartState(),
+ lambda : BasicBlockStartState(),
+ lambda : PlusBlockStartState(),
+ lambda : StarBlockStartState(),
+ lambda : TokensStartState(),
+ lambda : RuleStopState(),
+ lambda : BlockEndState(),
+ lambda : StarLoopbackState(),
+ lambda : StarLoopEntryState(),
+ lambda : PlusLoopbackState(),
+ lambda : LoopEndState()
+ ]
+
+ def stateFactory(self, type:int, ruleIndex:int):
+ if type> len(self.stateFactories) or self.stateFactories[type] is None:
+ raise Exception("The specified state type " + str(type) + " is not valid.")
+ else:
+ s = self.stateFactories[type]()
+ if s is not None:
+ s.ruleIndex = ruleIndex
+ return s
+
+ CHANNEL = 0 #The type of a {@link LexerChannelAction} action.
+ CUSTOM = 1 #The type of a {@link LexerCustomAction} action.
+ MODE = 2 #The type of a {@link LexerModeAction} action.
+ MORE = 3 #The type of a {@link LexerMoreAction} action.
+ POP_MODE = 4 #The type of a {@link LexerPopModeAction} action.
+ PUSH_MODE = 5 #The type of a {@link LexerPushModeAction} action.
+ SKIP = 6 #The type of a {@link LexerSkipAction} action.
+ TYPE = 7 #The type of a {@link LexerTypeAction} action.
+
+ actionFactories = [ lambda data1, data2: LexerChannelAction(data1),
+ lambda data1, data2: LexerCustomAction(data1, data2),
+ lambda data1, data2: LexerModeAction(data1),
+ lambda data1, data2: LexerMoreAction.INSTANCE,
+ lambda data1, data2: LexerPopModeAction.INSTANCE,
+ lambda data1, data2: LexerPushModeAction(data1),
+ lambda data1, data2: LexerSkipAction.INSTANCE,
+ lambda data1, data2: LexerTypeAction(data1)
+ ]
+
+ def lexerActionFactory(self, type:int, data1:int, data2:int):
+
+ if type > len(self.actionFactories) or self.actionFactories[type] is None:
+ raise Exception("The specified lexer action type " + str(type) + " is not valid.")
+ else:
+ return self.actionFactories[type](data1, data2)
diff --git a/venv/Lib/site-packages/antlr4/atn/ATNSimulator.py b/venv/Lib/site-packages/antlr4/atn/ATNSimulator.py
new file mode 100644
index 0000000000000000000000000000000000000000..4f6f53f488fa2b731fb39ceecf350b0cb43d1c39
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/ATNSimulator.py
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+from antlr4.PredictionContext import PredictionContextCache, PredictionContext, getCachedPredictionContext
+from antlr4.atn.ATN import ATN
+from antlr4.atn.ATNConfigSet import ATNConfigSet
+from antlr4.dfa.DFAState import DFAState
+
+
+class ATNSimulator(object):
+ __slots__ = ('atn', 'sharedContextCache', '__dict__')
+
+ # Must distinguish between missing edge and edge we know leads nowhere#/
+ ERROR = DFAState(configs=ATNConfigSet())
+ ERROR.stateNumber = 0x7FFFFFFF
+
+ # The context cache maps all PredictionContext objects that are ==
+ # to a single cached copy. This cache is shared across all contexts
+ # in all ATNConfigs in all DFA states. We rebuild each ATNConfigSet
+ # to use only cached nodes/graphs in addDFAState(). We don't want to
+ # fill this during closure() since there are lots of contexts that
+ # pop up but are not used ever again. It also greatly slows down closure().
+ #
+ #
This cache makes a huge difference in memory and a little bit in speed.
+ # For the Java grammar on java.*, it dropped the memory requirements
+ # at the end from 25M to 16M. We don't store any of the full context
+ # graphs in the DFA because they are limited to local context only,
+ # but apparently there's a lot of repetition there as well. We optimize
+ # the config contexts before storing the config set in the DFA states
+ # by literally rebuilding them with cached subgraphs only.
+ #
+ #
I tried a cache for use during closure operations, that was
+ # whacked after each adaptivePredict(). It cost a little bit
+ # more time I think and doesn't save on the overall footprint
+ # so it's not worth the complexity.
+ #/
+ def __init__(self, atn:ATN, sharedContextCache:PredictionContextCache):
+ self.atn = atn
+ self.sharedContextCache = sharedContextCache
+
+ def getCachedContext(self, context:PredictionContext):
+ if self.sharedContextCache is None:
+ return context
+ visited = dict()
+ return getCachedPredictionContext(context, self.sharedContextCache, visited)
diff --git a/venv/Lib/site-packages/antlr4/atn/ATNState.py b/venv/Lib/site-packages/antlr4/atn/ATNState.py
new file mode 100644
index 0000000000000000000000000000000000000000..fbf6a7b9442905c992bb1a88ce343a8a9d63f5b7
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/ATNState.py
@@ -0,0 +1,264 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+# The following images show the relation of states and
+# {@link ATNState#transitions} for various grammar constructs.
+#
+#
+#
+#
Solid edges marked with an ε indicate a required
+# {@link EpsilonTransition}.
+#
+#
Dashed edges indicate locations where any transition derived from
+# {@link Transition} might appear.
+#
+#
Dashed nodes are place holders for either a sequence of linked
+# {@link BasicState} states or the inclusion of a block representing a nested
+# construct in one of the forms below.
+#
+#
Nodes showing multiple outgoing alternatives with a {@code ...} support
+# any number of alternatives (one or more). Nodes without the {@code ...} only
+# support the exact number of alternatives shown in the diagram.
+#
+#
+#
+#
Basic Blocks
+#
+#
Rule
+#
+#
+#
+#
Block of 1 or more alternatives
+#
+#
+#
+#
Greedy Loops
+#
+#
Greedy Closure: {@code (...)*}
+#
+#
+#
+#
Greedy Positive Closure: {@code (...)+}
+#
+#
+#
+#
Greedy Optional: {@code (...)?}
+#
+#
+#
+#
Non-Greedy Loops
+#
+#
Non-Greedy Closure: {@code (...)*?}
+#
+#
+#
+#
Non-Greedy Positive Closure: {@code (...)+?}
+#
+#
+#
+#
Non-Greedy Optional: {@code (...)??}
+#
+#
+#
+
+from antlr4.atn.Transition import Transition
+
+INITIAL_NUM_TRANSITIONS = 4
+
+class ATNState(object):
+ __slots__ = (
+ 'atn', 'stateNumber', 'stateType', 'ruleIndex', 'epsilonOnlyTransitions',
+ 'transitions', 'nextTokenWithinRule',
+ )
+
+ # constants for serialization
+ INVALID_TYPE = 0
+ BASIC = 1
+ RULE_START = 2
+ BLOCK_START = 3
+ PLUS_BLOCK_START = 4
+ STAR_BLOCK_START = 5
+ TOKEN_START = 6
+ RULE_STOP = 7
+ BLOCK_END = 8
+ STAR_LOOP_BACK = 9
+ STAR_LOOP_ENTRY = 10
+ PLUS_LOOP_BACK = 11
+ LOOP_END = 12
+
+ serializationNames = [
+ "INVALID",
+ "BASIC",
+ "RULE_START",
+ "BLOCK_START",
+ "PLUS_BLOCK_START",
+ "STAR_BLOCK_START",
+ "TOKEN_START",
+ "RULE_STOP",
+ "BLOCK_END",
+ "STAR_LOOP_BACK",
+ "STAR_LOOP_ENTRY",
+ "PLUS_LOOP_BACK",
+ "LOOP_END" ]
+
+ INVALID_STATE_NUMBER = -1
+
+ def __init__(self):
+ # Which ATN are we in?
+ self.atn = None
+ self.stateNumber = ATNState.INVALID_STATE_NUMBER
+ self.stateType = None
+ self.ruleIndex = 0 # at runtime, we don't have Rule objects
+ self.epsilonOnlyTransitions = False
+ # Track the transitions emanating from this ATN state.
+ self.transitions = []
+ # Used to cache lookahead during parsing, not used during construction
+ self.nextTokenWithinRule = None
+
+ def __hash__(self):
+ return self.stateNumber
+
+ def __eq__(self, other):
+ return isinstance(other, ATNState) and self.stateNumber==other.stateNumber
+
+ def onlyHasEpsilonTransitions(self):
+ return self.epsilonOnlyTransitions
+
+ def isNonGreedyExitState(self):
+ return False
+
+ def __str__(self):
+ return str(self.stateNumber)
+
+ def addTransition(self, trans:Transition, index:int=-1):
+ if len(self.transitions)==0:
+ self.epsilonOnlyTransitions = trans.isEpsilon
+ elif self.epsilonOnlyTransitions != trans.isEpsilon:
+ self.epsilonOnlyTransitions = False
+ # TODO System.err.format(Locale.getDefault(), "ATN state %d has both epsilon and non-epsilon transitions.\n", stateNumber);
+ if index==-1:
+ self.transitions.append(trans)
+ else:
+ self.transitions.insert(index, trans)
+
+class BasicState(ATNState):
+
+ def __init__(self):
+ super().__init__()
+ self.stateType = self.BASIC
+
+
+class DecisionState(ATNState):
+ __slots__ = ('decision', 'nonGreedy')
+ def __init__(self):
+ super().__init__()
+ self.decision = -1
+ self.nonGreedy = False
+
+# The start of a regular {@code (...)} block.
+class BlockStartState(DecisionState):
+ __slots__ = 'endState'
+
+ def __init__(self):
+ super().__init__()
+ self.endState = None
+
+class BasicBlockStartState(BlockStartState):
+
+ def __init__(self):
+ super().__init__()
+ self.stateType = self.BLOCK_START
+
+# Terminal node of a simple {@code (a|b|c)} block.
+class BlockEndState(ATNState):
+ __slots__ = 'startState'
+
+ def __init__(self):
+ super().__init__()
+ self.stateType = self.BLOCK_END
+ self.startState = None
+
+# The last node in the ATN for a rule, unless that rule is the start symbol.
+# In that case, there is one transition to EOF. Later, we might encode
+# references to all calls to this rule to compute FOLLOW sets for
+# error handling.
+#
+class RuleStopState(ATNState):
+
+ def __init__(self):
+ super().__init__()
+ self.stateType = self.RULE_STOP
+
+class RuleStartState(ATNState):
+ __slots__ = ('stopState', 'isPrecedenceRule')
+
+ def __init__(self):
+ super().__init__()
+ self.stateType = self.RULE_START
+ self.stopState = None
+ self.isPrecedenceRule = False
+
+# Decision state for {@code A+} and {@code (A|B)+}. It has two transitions:
+# one to the loop back to start of the block and one to exit.
+#
+class PlusLoopbackState(DecisionState):
+
+ def __init__(self):
+ super().__init__()
+ self.stateType = self.PLUS_LOOP_BACK
+
+# Start of {@code (A|B|...)+} loop. Technically a decision state, but
+# we don't use for code generation; somebody might need it, so I'm defining
+# it for completeness. In reality, the {@link PlusLoopbackState} node is the
+# real decision-making note for {@code A+}.
+#
+class PlusBlockStartState(BlockStartState):
+ __slots__ = 'loopBackState'
+
+ def __init__(self):
+ super().__init__()
+ self.stateType = self.PLUS_BLOCK_START
+ self.loopBackState = None
+
+# The block that begins a closure loop.
+class StarBlockStartState(BlockStartState):
+
+ def __init__(self):
+ super().__init__()
+ self.stateType = self.STAR_BLOCK_START
+
+class StarLoopbackState(ATNState):
+
+ def __init__(self):
+ super().__init__()
+ self.stateType = self.STAR_LOOP_BACK
+
+
+class StarLoopEntryState(DecisionState):
+ __slots__ = ('loopBackState', 'isPrecedenceDecision')
+
+ def __init__(self):
+ super().__init__()
+ self.stateType = self.STAR_LOOP_ENTRY
+ self.loopBackState = None
+ # Indicates whether this state can benefit from a precedence DFA during SLL decision making.
+ self.isPrecedenceDecision = None
+
+# Mark the end of a * or + loop.
+class LoopEndState(ATNState):
+ __slots__ = 'loopBackState'
+
+ def __init__(self):
+ super().__init__()
+ self.stateType = self.LOOP_END
+ self.loopBackState = None
+
+# The Tokens rule start state linking to each lexer rule start state */
+class TokensStartState(DecisionState):
+
+ def __init__(self):
+ super().__init__()
+ self.stateType = self.TOKEN_START
diff --git a/venv/Lib/site-packages/antlr4/atn/ATNType.py b/venv/Lib/site-packages/antlr4/atn/ATNType.py
new file mode 100644
index 0000000000000000000000000000000000000000..cc0d4d925c6babee1caeee08f5e32fe4a1d6d0d4
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/ATNType.py
@@ -0,0 +1,17 @@
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+
+from enum import IntEnum
+
+# Represents the type of recognizer an ATN applies to.
+
+class ATNType(IntEnum):
+
+ LEXER = 0
+ PARSER = 1
+
+ @classmethod
+ def fromOrdinal(cls, i:int):
+ return cls._value2member_map_[i]
diff --git a/venv/Lib/site-packages/antlr4/atn/LexerATNSimulator.py b/venv/Lib/site-packages/antlr4/atn/LexerATNSimulator.py
new file mode 100644
index 0000000000000000000000000000000000000000..71201ff5f989820d340aac8672ab31db8579b55c
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/LexerATNSimulator.py
@@ -0,0 +1,570 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+
+# When we hit an accept state in either the DFA or the ATN, we
+# have to notify the character stream to start buffering characters
+# via {@link IntStream#mark} and record the current state. The current sim state
+# includes the current index into the input, the current line,
+# and current character position in that line. Note that the Lexer is
+# tracking the starting line and characterization of the token. These
+# variables track the "state" of the simulator when it hits an accept state.
+#
+#
We track these variables separately for the DFA and ATN simulation
+# because the DFA simulation often has to fail over to the ATN
+# simulation. If the ATN simulation fails, we need the DFA to fall
+# back to its previously accepted state, if any. If the ATN succeeds,
+# then the ATN does the accept and the DFA simulator that invoked it
+# can simply return the predicted token type.
+#/
+
+from antlr4.PredictionContext import PredictionContextCache, SingletonPredictionContext, PredictionContext
+from antlr4.InputStream import InputStream
+from antlr4.Token import Token
+from antlr4.atn.ATN import ATN
+from antlr4.atn.ATNConfig import LexerATNConfig
+from antlr4.atn.ATNSimulator import ATNSimulator
+from antlr4.atn.ATNConfigSet import ATNConfigSet, OrderedATNConfigSet
+from antlr4.atn.ATNState import RuleStopState, ATNState
+from antlr4.atn.LexerActionExecutor import LexerActionExecutor
+from antlr4.atn.Transition import Transition
+from antlr4.dfa.DFAState import DFAState
+from antlr4.error.Errors import LexerNoViableAltException, UnsupportedOperationException
+
+class SimState(object):
+ __slots__ = ('index', 'line', 'column', 'dfaState')
+
+ def __init__(self):
+ self.reset()
+
+ def reset(self):
+ self.index = -1
+ self.line = 0
+ self.column = -1
+ self.dfaState = None
+
+# need forward declaration
+Lexer = None
+LexerATNSimulator = None
+
+class LexerATNSimulator(ATNSimulator):
+ __slots__ = (
+ 'decisionToDFA', 'recog', 'startIndex', 'line', 'column', 'mode',
+ 'DEFAULT_MODE', 'MAX_CHAR_VALUE', 'prevAccept'
+ )
+
+ debug = False
+ dfa_debug = False
+
+ MIN_DFA_EDGE = 0
+ MAX_DFA_EDGE = 127 # forces unicode to stay in ATN
+
+ ERROR = None
+
+ def __init__(self, recog:Lexer, atn:ATN, decisionToDFA:list, sharedContextCache:PredictionContextCache):
+ super().__init__(atn, sharedContextCache)
+ self.decisionToDFA = decisionToDFA
+ self.recog = recog
+ # The current token's starting index into the character stream.
+ # Shared across DFA to ATN simulation in case the ATN fails and the
+ # DFA did not have a previous accept state. In this case, we use the
+ # ATN-generated exception object.
+ self.startIndex = -1
+ # line number 1..n within the input#/
+ self.line = 1
+ # The index of the character relative to the beginning of the line 0..n-1#/
+ self.column = 0
+ from antlr4.Lexer import Lexer
+ self.mode = Lexer.DEFAULT_MODE
+ # Cache Lexer properties to avoid further imports
+ self.DEFAULT_MODE = Lexer.DEFAULT_MODE
+ self.MAX_CHAR_VALUE = Lexer.MAX_CHAR_VALUE
+ # Used during DFA/ATN exec to record the most recent accept configuration info
+ self.prevAccept = SimState()
+
+
+ def copyState(self, simulator:LexerATNSimulator ):
+ self.column = simulator.column
+ self.line = simulator.line
+ self.mode = simulator.mode
+ self.startIndex = simulator.startIndex
+
+ def match(self, input:InputStream , mode:int):
+ self.mode = mode
+ mark = input.mark()
+ try:
+ self.startIndex = input.index
+ self.prevAccept.reset()
+ dfa = self.decisionToDFA[mode]
+ if dfa.s0 is None:
+ return self.matchATN(input)
+ else:
+ return self.execATN(input, dfa.s0)
+ finally:
+ input.release(mark)
+
+ def reset(self):
+ self.prevAccept.reset()
+ self.startIndex = -1
+ self.line = 1
+ self.column = 0
+ self.mode = self.DEFAULT_MODE
+
+ def matchATN(self, input:InputStream):
+ startState = self.atn.modeToStartState[self.mode]
+
+ if LexerATNSimulator.debug:
+ print("matchATN mode " + str(self.mode) + " start: " + str(startState))
+
+ old_mode = self.mode
+ s0_closure = self.computeStartState(input, startState)
+ suppressEdge = s0_closure.hasSemanticContext
+ s0_closure.hasSemanticContext = False
+
+ next = self.addDFAState(s0_closure)
+ if not suppressEdge:
+ self.decisionToDFA[self.mode].s0 = next
+
+ predict = self.execATN(input, next)
+
+ if LexerATNSimulator.debug:
+ print("DFA after matchATN: " + str(self.decisionToDFA[old_mode].toLexerString()))
+
+ return predict
+
+ def execATN(self, input:InputStream, ds0:DFAState):
+ if LexerATNSimulator.debug:
+ print("start state closure=" + str(ds0.configs))
+
+ if ds0.isAcceptState:
+ # allow zero-length tokens
+ self.captureSimState(self.prevAccept, input, ds0)
+
+ t = input.LA(1)
+ s = ds0 # s is current/from DFA state
+
+ while True: # while more work
+ if LexerATNSimulator.debug:
+ print("execATN loop starting closure:", str(s.configs))
+
+ # As we move src->trg, src->trg, we keep track of the previous trg to
+ # avoid looking up the DFA state again, which is expensive.
+ # If the previous target was already part of the DFA, we might
+ # be able to avoid doing a reach operation upon t. If s!=null,
+ # it means that semantic predicates didn't prevent us from
+ # creating a DFA state. Once we know s!=null, we check to see if
+ # the DFA state has an edge already for t. If so, we can just reuse
+ # it's configuration set; there's no point in re-computing it.
+ # This is kind of like doing DFA simulation within the ATN
+ # simulation because DFA simulation is really just a way to avoid
+ # computing reach/closure sets. Technically, once we know that
+ # we have a previously added DFA state, we could jump over to
+ # the DFA simulator. But, that would mean popping back and forth
+ # a lot and making things more complicated algorithmically.
+ # This optimization makes a lot of sense for loops within DFA.
+ # A character will take us back to an existing DFA state
+ # that already has lots of edges out of it. e.g., .* in comments.
+ # print("Target for:" + str(s) + " and:" + str(t))
+ target = self.getExistingTargetState(s, t)
+ # print("Existing:" + str(target))
+ if target is None:
+ target = self.computeTargetState(input, s, t)
+ # print("Computed:" + str(target))
+
+ if target == self.ERROR:
+ break
+
+ # If this is a consumable input element, make sure to consume before
+ # capturing the accept state so the input index, line, and char
+ # position accurately reflect the state of the interpreter at the
+ # end of the token.
+ if t != Token.EOF:
+ self.consume(input)
+
+ if target.isAcceptState:
+ self.captureSimState(self.prevAccept, input, target)
+ if t == Token.EOF:
+ break
+
+ t = input.LA(1)
+
+ s = target # flip; current DFA target becomes new src/from state
+
+ return self.failOrAccept(self.prevAccept, input, s.configs, t)
+
+ # Get an existing target state for an edge in the DFA. If the target state
+ # for the edge has not yet been computed or is otherwise not available,
+ # this method returns {@code null}.
+ #
+ # @param s The current DFA state
+ # @param t The next input symbol
+ # @return The existing target DFA state for the given input symbol
+ # {@code t}, or {@code null} if the target state for this edge is not
+ # already cached
+ def getExistingTargetState(self, s:DFAState, t:int):
+ if s.edges is None or t < self.MIN_DFA_EDGE or t > self.MAX_DFA_EDGE:
+ return None
+
+ target = s.edges[t - self.MIN_DFA_EDGE]
+ if LexerATNSimulator.debug and target is not None:
+ print("reuse state", str(s.stateNumber), "edge to", str(target.stateNumber))
+
+ return target
+
+ # Compute a target state for an edge in the DFA, and attempt to add the
+ # computed state and corresponding edge to the DFA.
+ #
+ # @param input The input stream
+ # @param s The current DFA state
+ # @param t The next input symbol
+ #
+ # @return The computed target DFA state for the given input symbol
+ # {@code t}. If {@code t} does not lead to a valid DFA state, this method
+ # returns {@link #ERROR}.
+ def computeTargetState(self, input:InputStream, s:DFAState, t:int):
+ reach = OrderedATNConfigSet()
+
+ # if we don't find an existing DFA state
+ # Fill reach starting from closure, following t transitions
+ self.getReachableConfigSet(input, s.configs, reach, t)
+
+ if len(reach)==0: # we got nowhere on t from s
+ if not reach.hasSemanticContext:
+ # we got nowhere on t, don't throw out this knowledge; it'd
+ # cause a failover from DFA later.
+ self. addDFAEdge(s, t, self.ERROR)
+
+ # stop when we can't match any more char
+ return self.ERROR
+
+ # Add an edge from s to target DFA found/created for reach
+ return self.addDFAEdge(s, t, cfgs=reach)
+
+ def failOrAccept(self, prevAccept:SimState , input:InputStream, reach:ATNConfigSet, t:int):
+ if self.prevAccept.dfaState is not None:
+ lexerActionExecutor = prevAccept.dfaState.lexerActionExecutor
+ self.accept(input, lexerActionExecutor, self.startIndex, prevAccept.index, prevAccept.line, prevAccept.column)
+ return prevAccept.dfaState.prediction
+ else:
+ # if no accept and EOF is first char, return EOF
+ if t==Token.EOF and input.index==self.startIndex:
+ return Token.EOF
+ raise LexerNoViableAltException(self.recog, input, self.startIndex, reach)
+
+ # Given a starting configuration set, figure out all ATN configurations
+ # we can reach upon input {@code t}. Parameter {@code reach} is a return
+ # parameter.
+ def getReachableConfigSet(self, input:InputStream, closure:ATNConfigSet, reach:ATNConfigSet, t:int):
+ # this is used to skip processing for configs which have a lower priority
+ # than a config that already reached an accept state for the same rule
+ skipAlt = ATN.INVALID_ALT_NUMBER
+ for cfg in closure:
+ currentAltReachedAcceptState = ( cfg.alt == skipAlt )
+ if currentAltReachedAcceptState and cfg.passedThroughNonGreedyDecision:
+ continue
+
+ if LexerATNSimulator.debug:
+ print("testing", self.getTokenName(t), "at", str(cfg))
+
+ for trans in cfg.state.transitions: # for each transition
+ target = self.getReachableTarget(trans, t)
+ if target is not None:
+ lexerActionExecutor = cfg.lexerActionExecutor
+ if lexerActionExecutor is not None:
+ lexerActionExecutor = lexerActionExecutor.fixOffsetBeforeMatch(input.index - self.startIndex)
+
+ treatEofAsEpsilon = (t == Token.EOF)
+ config = LexerATNConfig(state=target, lexerActionExecutor=lexerActionExecutor, config=cfg)
+ if self.closure(input, config, reach, currentAltReachedAcceptState, True, treatEofAsEpsilon):
+ # any remaining configs for this alt have a lower priority than
+ # the one that just reached an accept state.
+ skipAlt = cfg.alt
+
+ def accept(self, input:InputStream, lexerActionExecutor:LexerActionExecutor, startIndex:int, index:int, line:int, charPos:int):
+ if LexerATNSimulator.debug:
+ print("ACTION", lexerActionExecutor)
+
+ # seek to after last char in token
+ input.seek(index)
+ self.line = line
+ self.column = charPos
+
+ if lexerActionExecutor is not None and self.recog is not None:
+ lexerActionExecutor.execute(self.recog, input, startIndex)
+
+ def getReachableTarget(self, trans:Transition, t:int):
+ if trans.matches(t, 0, self.MAX_CHAR_VALUE):
+ return trans.target
+ else:
+ return None
+
+ def computeStartState(self, input:InputStream, p:ATNState):
+ initialContext = PredictionContext.EMPTY
+ configs = OrderedATNConfigSet()
+ for i in range(0,len(p.transitions)):
+ target = p.transitions[i].target
+ c = LexerATNConfig(state=target, alt=i+1, context=initialContext)
+ self.closure(input, c, configs, False, False, False)
+ return configs
+
+ # Since the alternatives within any lexer decision are ordered by
+ # preference, this method stops pursuing the closure as soon as an accept
+ # state is reached. After the first accept state is reached by depth-first
+ # search from {@code config}, all other (potentially reachable) states for
+ # this rule would have a lower priority.
+ #
+ # @return {@code true} if an accept state is reached, otherwise
+ # {@code false}.
+ def closure(self, input:InputStream, config:LexerATNConfig, configs:ATNConfigSet, currentAltReachedAcceptState:bool,
+ speculative:bool, treatEofAsEpsilon:bool):
+ if LexerATNSimulator.debug:
+ print("closure(" + str(config) + ")")
+
+ if isinstance( config.state, RuleStopState ):
+ if LexerATNSimulator.debug:
+ if self.recog is not None:
+ print("closure at", self.recog.symbolicNames[config.state.ruleIndex], "rule stop", str(config))
+ else:
+ print("closure at rule stop", str(config))
+
+ if config.context is None or config.context.hasEmptyPath():
+ if config.context is None or config.context.isEmpty():
+ configs.add(config)
+ return True
+ else:
+ configs.add(LexerATNConfig(state=config.state, config=config, context=PredictionContext.EMPTY))
+ currentAltReachedAcceptState = True
+
+ if config.context is not None and not config.context.isEmpty():
+ for i in range(0,len(config.context)):
+ if config.context.getReturnState(i) != PredictionContext.EMPTY_RETURN_STATE:
+ newContext = config.context.getParent(i) # "pop" return state
+ returnState = self.atn.states[config.context.getReturnState(i)]
+ c = LexerATNConfig(state=returnState, config=config, context=newContext)
+ currentAltReachedAcceptState = self.closure(input, c, configs,
+ currentAltReachedAcceptState, speculative, treatEofAsEpsilon)
+
+ return currentAltReachedAcceptState
+
+ # optimization
+ if not config.state.epsilonOnlyTransitions:
+ if not currentAltReachedAcceptState or not config.passedThroughNonGreedyDecision:
+ configs.add(config)
+
+ for t in config.state.transitions:
+ c = self.getEpsilonTarget(input, config, t, configs, speculative, treatEofAsEpsilon)
+ if c is not None:
+ currentAltReachedAcceptState = self.closure(input, c, configs, currentAltReachedAcceptState, speculative, treatEofAsEpsilon)
+
+ return currentAltReachedAcceptState
+
+ # side-effect: can alter configs.hasSemanticContext
+ def getEpsilonTarget(self, input:InputStream, config:LexerATNConfig, t:Transition, configs:ATNConfigSet,
+ speculative:bool, treatEofAsEpsilon:bool):
+ c = None
+ if t.serializationType==Transition.RULE:
+ newContext = SingletonPredictionContext.create(config.context, t.followState.stateNumber)
+ c = LexerATNConfig(state=t.target, config=config, context=newContext)
+
+ elif t.serializationType==Transition.PRECEDENCE:
+ raise UnsupportedOperationException("Precedence predicates are not supported in lexers.")
+
+ elif t.serializationType==Transition.PREDICATE:
+ # Track traversing semantic predicates. If we traverse,
+ # we cannot add a DFA state for this "reach" computation
+ # because the DFA would not test the predicate again in the
+ # future. Rather than creating collections of semantic predicates
+ # like v3 and testing them on prediction, v4 will test them on the
+ # fly all the time using the ATN not the DFA. This is slower but
+ # semantically it's not used that often. One of the key elements to
+ # this predicate mechanism is not adding DFA states that see
+ # predicates immediately afterwards in the ATN. For example,
+
+ # a : ID {p1}? | ID {p2}? ;
+
+ # should create the start state for rule 'a' (to save start state
+ # competition), but should not create target of ID state. The
+ # collection of ATN states the following ID references includes
+ # states reached by traversing predicates. Since this is when we
+ # test them, we cannot cash the DFA state target of ID.
+
+ if LexerATNSimulator.debug:
+ print("EVAL rule "+ str(t.ruleIndex) + ":" + str(t.predIndex))
+ configs.hasSemanticContext = True
+ if self.evaluatePredicate(input, t.ruleIndex, t.predIndex, speculative):
+ c = LexerATNConfig(state=t.target, config=config)
+
+ elif t.serializationType==Transition.ACTION:
+ if config.context is None or config.context.hasEmptyPath():
+ # execute actions anywhere in the start rule for a token.
+ #
+ # TODO: if the entry rule is invoked recursively, some
+ # actions may be executed during the recursive call. The
+ # problem can appear when hasEmptyPath() is true but
+ # isEmpty() is false. In this case, the config needs to be
+ # split into two contexts - one with just the empty path
+ # and another with everything but the empty path.
+ # Unfortunately, the current algorithm does not allow
+ # getEpsilonTarget to return two configurations, so
+ # additional modifications are needed before we can support
+ # the split operation.
+ lexerActionExecutor = LexerActionExecutor.append(config.lexerActionExecutor,
+ self.atn.lexerActions[t.actionIndex])
+ c = LexerATNConfig(state=t.target, config=config, lexerActionExecutor=lexerActionExecutor)
+
+ else:
+ # ignore actions in referenced rules
+ c = LexerATNConfig(state=t.target, config=config)
+
+ elif t.serializationType==Transition.EPSILON:
+ c = LexerATNConfig(state=t.target, config=config)
+
+ elif t.serializationType in [ Transition.ATOM, Transition.RANGE, Transition.SET ]:
+ if treatEofAsEpsilon:
+ if t.matches(Token.EOF, 0, self.MAX_CHAR_VALUE):
+ c = LexerATNConfig(state=t.target, config=config)
+
+ return c
+
+ # Evaluate a predicate specified in the lexer.
+ #
+ #
If {@code speculative} is {@code true}, this method was called before
+ # {@link #consume} for the matched character. This method should call
+ # {@link #consume} before evaluating the predicate to ensure position
+ # sensitive values, including {@link Lexer#getText}, {@link Lexer#getLine},
+ # and {@link Lexer#getcolumn}, properly reflect the current
+ # lexer state. This method should restore {@code input} and the simulator
+ # to the original state before returning (i.e. undo the actions made by the
+ # call to {@link #consume}.
+ #
+ # @param input The input stream.
+ # @param ruleIndex The rule containing the predicate.
+ # @param predIndex The index of the predicate within the rule.
+ # @param speculative {@code true} if the current index in {@code input} is
+ # one character before the predicate's location.
+ #
+ # @return {@code true} if the specified predicate evaluates to
+ # {@code true}.
+ #/
+ def evaluatePredicate(self, input:InputStream, ruleIndex:int, predIndex:int, speculative:bool):
+ # assume true if no recognizer was provided
+ if self.recog is None:
+ return True
+
+ if not speculative:
+ return self.recog.sempred(None, ruleIndex, predIndex)
+
+ savedcolumn = self.column
+ savedLine = self.line
+ index = input.index
+ marker = input.mark()
+ try:
+ self.consume(input)
+ return self.recog.sempred(None, ruleIndex, predIndex)
+ finally:
+ self.column = savedcolumn
+ self.line = savedLine
+ input.seek(index)
+ input.release(marker)
+
+ def captureSimState(self, settings:SimState, input:InputStream, dfaState:DFAState):
+ settings.index = input.index
+ settings.line = self.line
+ settings.column = self.column
+ settings.dfaState = dfaState
+
+ def addDFAEdge(self, from_:DFAState, tk:int, to:DFAState=None, cfgs:ATNConfigSet=None) -> DFAState:
+
+ if to is None and cfgs is not None:
+ # leading to this call, ATNConfigSet.hasSemanticContext is used as a
+ # marker indicating dynamic predicate evaluation makes this edge
+ # dependent on the specific input sequence, so the static edge in the
+ # DFA should be omitted. The target DFAState is still created since
+ # execATN has the ability to resynchronize with the DFA state cache
+ # following the predicate evaluation step.
+ #
+ # TJP notes: next time through the DFA, we see a pred again and eval.
+ # If that gets us to a previously created (but dangling) DFA
+ # state, we can continue in pure DFA mode from there.
+ #/
+ suppressEdge = cfgs.hasSemanticContext
+ cfgs.hasSemanticContext = False
+
+ to = self.addDFAState(cfgs)
+
+ if suppressEdge:
+ return to
+
+ # add the edge
+ if tk < self.MIN_DFA_EDGE or tk > self.MAX_DFA_EDGE:
+ # Only track edges within the DFA bounds
+ return to
+
+ if LexerATNSimulator.debug:
+ print("EDGE " + str(from_) + " -> " + str(to) + " upon "+ chr(tk))
+
+ if from_.edges is None:
+ # make room for tokens 1..n and -1 masquerading as index 0
+ from_.edges = [ None ] * (self.MAX_DFA_EDGE - self.MIN_DFA_EDGE + 1)
+
+ from_.edges[tk - self.MIN_DFA_EDGE] = to # connect
+
+ return to
+
+
+ # Add a new DFA state if there isn't one with this set of
+ # configurations already. This method also detects the first
+ # configuration containing an ATN rule stop state. Later, when
+ # traversing the DFA, we will know which rule to accept.
+ def addDFAState(self, configs:ATNConfigSet) -> DFAState:
+
+ proposed = DFAState(configs=configs)
+ firstConfigWithRuleStopState = next((cfg for cfg in configs if isinstance(cfg.state, RuleStopState)), None)
+
+ if firstConfigWithRuleStopState is not None:
+ proposed.isAcceptState = True
+ proposed.lexerActionExecutor = firstConfigWithRuleStopState.lexerActionExecutor
+ proposed.prediction = self.atn.ruleToTokenType[firstConfigWithRuleStopState.state.ruleIndex]
+
+ dfa = self.decisionToDFA[self.mode]
+ existing = dfa.states.get(proposed, None)
+ if existing is not None:
+ return existing
+
+ newState = proposed
+
+ newState.stateNumber = len(dfa.states)
+ configs.setReadonly(True)
+ newState.configs = configs
+ dfa.states[newState] = newState
+ return newState
+
+ def getDFA(self, mode:int):
+ return self.decisionToDFA[mode]
+
+ # Get the text matched so far for the current token.
+ def getText(self, input:InputStream):
+ # index is first lookahead char, don't include.
+ return input.getText(self.startIndex, input.index-1)
+
+ def consume(self, input:InputStream):
+ curChar = input.LA(1)
+ if curChar==ord('\n'):
+ self.line += 1
+ self.column = 0
+ else:
+ self.column += 1
+ input.consume()
+
+ def getTokenName(self, t:int):
+ if t==-1:
+ return "EOF"
+ else:
+ return "'" + chr(t) + "'"
+
+
+LexerATNSimulator.ERROR = DFAState(0x7FFFFFFF, ATNConfigSet())
+
+del Lexer
diff --git a/venv/Lib/site-packages/antlr4/atn/LexerAction.py b/venv/Lib/site-packages/antlr4/atn/LexerAction.py
new file mode 100644
index 0000000000000000000000000000000000000000..0fa7a895f31cea4415b71def30ca1ec90167f1b3
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/LexerAction.py
@@ -0,0 +1,298 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+ #
+
+from enum import IntEnum
+
+# need forward declaration
+Lexer = None
+
+
+class LexerActionType(IntEnum):
+
+ CHANNEL = 0 #The type of a {@link LexerChannelAction} action.
+ CUSTOM = 1 #The type of a {@link LexerCustomAction} action.
+ MODE = 2 #The type of a {@link LexerModeAction} action.
+ MORE = 3 #The type of a {@link LexerMoreAction} action.
+ POP_MODE = 4 #The type of a {@link LexerPopModeAction} action.
+ PUSH_MODE = 5 #The type of a {@link LexerPushModeAction} action.
+ SKIP = 6 #The type of a {@link LexerSkipAction} action.
+ TYPE = 7 #The type of a {@link LexerTypeAction} action.
+
+class LexerAction(object):
+ __slots__ = ('actionType', 'isPositionDependent')
+
+ def __init__(self, action:LexerActionType):
+ self.actionType = action
+ self.isPositionDependent = False
+
+ def __hash__(self):
+ return hash(self.actionType)
+
+ def __eq__(self, other):
+ return self is other
+
+
+#
+# Implements the {@code skip} lexer action by calling {@link Lexer#skip}.
+#
+#
The {@code skip} command does not have any parameters, so this action is
+# implemented as a singleton instance exposed by {@link #INSTANCE}.
This action is implemented by calling {@link Lexer#mode} with the
+ # value provided by {@link #getMode}.
+ def execute(self, lexer:Lexer):
+ lexer.mode(self.mode)
+
+ def __hash__(self):
+ return hash((self.actionType, self.mode))
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, LexerModeAction):
+ return False
+ else:
+ return self.mode == other.mode
+
+ def __str__(self):
+ return "mode(" + str(self.mode) + ")"
+
+# Executes a custom lexer action by calling {@link Recognizer#action} with the
+# rule and action indexes assigned to the custom action. The implementation of
+# a custom action is added to the generated code for the lexer in an override
+# of {@link Recognizer#action} when the grammar is compiled.
+#
+#
This class may represent embedded actions created with the {...}
+# syntax in ANTLR 4, as well as actions created for lexer commands where the
+# command argument could not be evaluated when the grammar was compiled.
+
+class LexerCustomAction(LexerAction):
+ __slots__ = ('ruleIndex', 'actionIndex')
+
+ # Constructs a custom lexer action with the specified rule and action
+ # indexes.
+ #
+ # @param ruleIndex The rule index to use for calls to
+ # {@link Recognizer#action}.
+ # @param actionIndex The action index to use for calls to
+ # {@link Recognizer#action}.
+ #/
+ def __init__(self, ruleIndex:int, actionIndex:int):
+ super().__init__(LexerActionType.CUSTOM)
+ self.ruleIndex = ruleIndex
+ self.actionIndex = actionIndex
+ self.isPositionDependent = True
+
+ #
Custom actions are implemented by calling {@link Lexer#action} with the
+ # appropriate rule and action indexes.
+ def execute(self, lexer:Lexer):
+ lexer.action(None, self.ruleIndex, self.actionIndex)
+
+ def __hash__(self):
+ return hash((self.actionType, self.ruleIndex, self.actionIndex))
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, LexerCustomAction):
+ return False
+ else:
+ return self.ruleIndex == other.ruleIndex and self.actionIndex == other.actionIndex
+
+# Implements the {@code channel} lexer action by calling
+# {@link Lexer#setChannel} with the assigned channel.
+class LexerChannelAction(LexerAction):
+ __slots__ = 'channel'
+
+ # Constructs a new {@code channel} action with the specified channel value.
+ # @param channel The channel value to pass to {@link Lexer#setChannel}.
+ def __init__(self, channel:int):
+ super().__init__(LexerActionType.CHANNEL)
+ self.channel = channel
+
+ #
This action is implemented by calling {@link Lexer#setChannel} with the
+ # value provided by {@link #getChannel}.
+ def execute(self, lexer:Lexer):
+ lexer._channel = self.channel
+
+ def __hash__(self):
+ return hash((self.actionType, self.channel))
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, LexerChannelAction):
+ return False
+ else:
+ return self.channel == other.channel
+
+ def __str__(self):
+ return "channel(" + str(self.channel) + ")"
+
+# This implementation of {@link LexerAction} is used for tracking input offsets
+# for position-dependent actions within a {@link LexerActionExecutor}.
+#
+#
This action is not serialized as part of the ATN, and is only required for
+# position-dependent lexer actions which appear at a location other than the
+# end of a rule. For more information about DFA optimizations employed for
+# lexer actions, see {@link LexerActionExecutor#append} and
+# {@link LexerActionExecutor#fixOffsetBeforeMatch}.
+class LexerIndexedCustomAction(LexerAction):
+ __slots__ = ('offset', 'action')
+
+ # Constructs a new indexed custom action by associating a character offset
+ # with a {@link LexerAction}.
+ #
+ #
Note: This class is only required for lexer actions for which
+ # {@link LexerAction#isPositionDependent} returns {@code true}.
+ #
+ # @param offset The offset into the input {@link CharStream}, relative to
+ # the token start index, at which the specified lexer action should be
+ # executed.
+ # @param action The lexer action to execute at a particular offset in the
+ # input {@link CharStream}.
+ def __init__(self, offset:int, action:LexerAction):
+ super().__init__(action.actionType)
+ self.offset = offset
+ self.action = action
+ self.isPositionDependent = True
+
+ #
This method calls {@link #execute} on the result of {@link #getAction}
+ # using the provided {@code lexer}.
+ def execute(self, lexer:Lexer):
+ # assume the input stream position was properly set by the calling code
+ self.action.execute(lexer)
+
+ def __hash__(self):
+ return hash((self.actionType, self.offset, self.action))
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, LexerIndexedCustomAction):
+ return False
+ else:
+ return self.offset == other.offset and self.action == other.action
diff --git a/venv/Lib/site-packages/antlr4/atn/LexerActionExecutor.py b/venv/Lib/site-packages/antlr4/atn/LexerActionExecutor.py
new file mode 100644
index 0000000000000000000000000000000000000000..5c6462c3a28f4ccbcb0a65dcde96f497dd392416
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/LexerActionExecutor.py
@@ -0,0 +1,143 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+
+# Represents an executor for a sequence of lexer actions which traversed during
+# the matching operation of a lexer rule (token).
+#
+#
The executor tracks position information for position-dependent lexer actions
+# efficiently, ensuring that actions appearing only at the end of the rule do
+# not cause bloating of the {@link DFA} created for the lexer.
+
+
+from antlr4.InputStream import InputStream
+from antlr4.atn.LexerAction import LexerAction, LexerIndexedCustomAction
+
+# need a forward declaration
+Lexer = None
+LexerActionExecutor = None
+
+class LexerActionExecutor(object):
+ __slots__ = ('lexerActions', 'hashCode')
+
+ def __init__(self, lexerActions:list=list()):
+ self.lexerActions = lexerActions
+ # Caches the result of {@link #hashCode} since the hash code is an element
+ # of the performance-critical {@link LexerATNConfig#hashCode} operation.
+ self.hashCode = hash("".join([str(la) for la in lexerActions]))
+
+
+ # Creates a {@link LexerActionExecutor} which executes the actions for
+ # the input {@code lexerActionExecutor} followed by a specified
+ # {@code lexerAction}.
+ #
+ # @param lexerActionExecutor The executor for actions already traversed by
+ # the lexer while matching a token within a particular
+ # {@link LexerATNConfig}. If this is {@code null}, the method behaves as
+ # though it were an empty executor.
+ # @param lexerAction The lexer action to execute after the actions
+ # specified in {@code lexerActionExecutor}.
+ #
+ # @return A {@link LexerActionExecutor} for executing the combine actions
+ # of {@code lexerActionExecutor} and {@code lexerAction}.
+ @staticmethod
+ def append(lexerActionExecutor:LexerActionExecutor , lexerAction:LexerAction ):
+ if lexerActionExecutor is None:
+ return LexerActionExecutor([ lexerAction ])
+
+ lexerActions = lexerActionExecutor.lexerActions + [ lexerAction ]
+ return LexerActionExecutor(lexerActions)
+
+ # Creates a {@link LexerActionExecutor} which encodes the current offset
+ # for position-dependent lexer actions.
+ #
+ #
Normally, when the executor encounters lexer actions where
+ # {@link LexerAction#isPositionDependent} returns {@code true}, it calls
+ # {@link IntStream#seek} on the input {@link CharStream} to set the input
+ # position to the end of the current token. This behavior provides
+ # for efficient DFA representation of lexer actions which appear at the end
+ # of a lexer rule, even when the lexer rule matches a variable number of
+ # characters.
+ #
+ #
Prior to traversing a match transition in the ATN, the current offset
+ # from the token start index is assigned to all position-dependent lexer
+ # actions which have not already been assigned a fixed offset. By storing
+ # the offsets relative to the token start index, the DFA representation of
+ # lexer actions which appear in the middle of tokens remains efficient due
+ # to sharing among tokens of the same length, regardless of their absolute
+ # position in the input stream.
+ #
+ #
If the current executor already has offsets assigned to all
+ # position-dependent lexer actions, the method returns {@code this}.
+ #
+ # @param offset The current offset to assign to all position-dependent
+ # lexer actions which do not already have offsets assigned.
+ #
+ # @return A {@link LexerActionExecutor} which stores input stream offsets
+ # for all position-dependent lexer actions.
+ #/
+ def fixOffsetBeforeMatch(self, offset:int):
+ updatedLexerActions = None
+ for i in range(0, len(self.lexerActions)):
+ if self.lexerActions[i].isPositionDependent and not isinstance(self.lexerActions[i], LexerIndexedCustomAction):
+ if updatedLexerActions is None:
+ updatedLexerActions = [ la for la in self.lexerActions ]
+ updatedLexerActions[i] = LexerIndexedCustomAction(offset, self.lexerActions[i])
+
+ if updatedLexerActions is None:
+ return self
+ else:
+ return LexerActionExecutor(updatedLexerActions)
+
+
+ # Execute the actions encapsulated by this executor within the context of a
+ # particular {@link Lexer}.
+ #
+ #
This method calls {@link IntStream#seek} to set the position of the
+ # {@code input} {@link CharStream} prior to calling
+ # {@link LexerAction#execute} on a position-dependent action. Before the
+ # method returns, the input position will be restored to the same position
+ # it was in when the method was invoked.
+ #
+ # @param lexer The lexer instance.
+ # @param input The input stream which is the source for the current token.
+ # When this method is called, the current {@link IntStream#index} for
+ # {@code input} should be the start of the following token, i.e. 1
+ # character past the end of the current token.
+ # @param startIndex The token start index. This value may be passed to
+ # {@link IntStream#seek} to set the {@code input} position to the beginning
+ # of the token.
+ #/
+ def execute(self, lexer:Lexer, input:InputStream, startIndex:int):
+ requiresSeek = False
+ stopIndex = input.index
+ try:
+ for lexerAction in self.lexerActions:
+ if isinstance(lexerAction, LexerIndexedCustomAction):
+ offset = lexerAction.offset
+ input.seek(startIndex + offset)
+ lexerAction = lexerAction.action
+ requiresSeek = (startIndex + offset) != stopIndex
+ elif lexerAction.isPositionDependent:
+ input.seek(stopIndex)
+ requiresSeek = False
+ lexerAction.execute(lexer)
+ finally:
+ if requiresSeek:
+ input.seek(stopIndex)
+
+ def __hash__(self):
+ return self.hashCode
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, LexerActionExecutor):
+ return False
+ else:
+ return self.hashCode == other.hashCode \
+ and self.lexerActions == other.lexerActions
+
+del Lexer
diff --git a/venv/Lib/site-packages/antlr4/atn/ParserATNSimulator.py b/venv/Lib/site-packages/antlr4/atn/ParserATNSimulator.py
new file mode 100644
index 0000000000000000000000000000000000000000..470aaef0ed22d423b932585fbf415807ba3b2c84
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/ParserATNSimulator.py
@@ -0,0 +1,1661 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+#
+# The embodiment of the adaptive LL(*), ALL(*), parsing strategy.
+#
+#
+# The basic complexity of the adaptive strategy makes it harder to understand.
+# We begin with ATN simulation to build paths in a DFA. Subsequent prediction
+# requests go through the DFA first. If they reach a state without an edge for
+# the current symbol, the algorithm fails over to the ATN simulation to
+# complete the DFA path for the current input (until it finds a conflict state
+# or uniquely predicting state).
+#
+#
+# All of that is done without using the outer context because we want to create
+# a DFA that is not dependent upon the rule invocation stack when we do a
+# prediction. One DFA works in all contexts. We avoid using context not
+# necessarily because it's slower, although it can be, but because of the DFA
+# caching problem. The closure routine only considers the rule invocation stack
+# created during prediction beginning in the decision rule. For example, if
+# prediction occurs without invoking another rule's ATN, there are no context
+# stacks in the configurations. When lack of context leads to a conflict, we
+# don't know if it's an ambiguity or a weakness in the strong LL(*) parsing
+# strategy (versus full LL(*)).
+#
+#
+# When SLL yields a configuration set with conflict, we rewind the input and
+# retry the ATN simulation, this time using full outer context without adding
+# to the DFA. Configuration context stacks will be the full invocation stacks
+# from the start rule. If we get a conflict using full context, then we can
+# definitively say we have a true ambiguity for that input sequence. If we
+# don't get a conflict, it implies that the decision is sensitive to the outer
+# context. (It is not context-sensitive in the sense of context-sensitive
+# grammars.)
+#
+#
+# The next time we reach this DFA state with an SLL conflict, through DFA
+# simulation, we will again retry the ATN simulation using full context mode.
+# This is slow because we can't save the results and have to "interpret" the
+# ATN each time we get that input.
+#
+#
+# CACHING FULL CONTEXT PREDICTIONS
+#
+#
+# We could cache results from full context to predicted alternative easily and
+# that saves a lot of time but doesn't work in presence of predicates. The set
+# of visible predicates from the ATN start state changes depending on the
+# context, because closure can fall off the end of a rule. I tried to cache
+# tuples (stack context, semantic context, predicted alt) but it was slower
+# than interpreting and much more complicated. Also required a huge amount of
+# memory. The goal is not to create the world's fastest parser anyway. I'd like
+# to keep this algorithm simple. By launching multiple threads, we can improve
+# the speed of parsing across a large number of files.
+#
+#
+# There is no strict ordering between the amount of input used by SLL vs LL,
+# which makes it really hard to build a cache for full context. Let's say that
+# we have input A B C that leads to an SLL conflict with full context X. That
+# implies that using X we might only use A B but we could also use A B C D to
+# resolve conflict. Input A B C D could predict alternative 1 in one position
+# in the input and A B C E could predict alternative 2 in another position in
+# input. The conflicting SLL configurations could still be non-unique in the
+# full context prediction, which would lead us to requiring more input than the
+# original A B C. To make a prediction cache work, we have to track the exact
+# input used during the previous prediction. That amounts to a cache that maps
+# X to a specific DFA for that context.
+#
+#
+# Something should be done for left-recursive expression predictions. They are
+# likely LL(1) + pred eval. Easier to do the whole SLL unless error and retry
+# with full LL thing Sam does.
+#
+#
+# AVOIDING FULL CONTEXT PREDICTION
+#
+#
+# We avoid doing full context retry when the outer context is empty, we did not
+# dip into the outer context by falling off the end of the decision state rule,
+# or when we force SLL mode.
+#
+#
+# As an example of the not dip into outer context case, consider as super
+# constructor calls versus function calls. One grammar might look like
+# this:
+# In both cases I believe that no closure operations will dip into the outer
+# context. In the first case ctorBody in the worst case will stop at the '}'.
+# In the 2nd case it should stop at the ';'. Both cases should stay within the
+# entry rule and not dip into the outer context.
+#
+#
+# PREDICATES
+#
+#
+# Predicates are always evaluated if present in either SLL or LL both. SLL and
+# LL simulation deals with predicates differently. SLL collects predicates as
+# it performs closure operations like ANTLR v3 did. It delays predicate
+# evaluation until it reaches and accept state. This allows us to cache the SLL
+# ATN simulation whereas, if we had evaluated predicates on-the-fly during
+# closure, the DFA state configuration sets would be different and we couldn't
+# build up a suitable DFA.
+#
+#
+# When building a DFA accept state during ATN simulation, we evaluate any
+# predicates and return the sole semantically valid alternative. If there is
+# more than 1 alternative, we report an ambiguity. If there are 0 alternatives,
+# we throw an exception. Alternatives without predicates act like they have
+# true predicates. The simple way to think about it is to strip away all
+# alternatives with false predicates and choose the minimum alternative that
+# remains.
+#
+#
+# When we start in the DFA and reach an accept state that's predicated, we test
+# those and return the minimum semantically viable alternative. If no
+# alternatives are viable, we throw an exception.
+#
+#
+# During full LL ATN simulation, closure always evaluates predicates and
+# on-the-fly. This is crucial to reducing the configuration set size during
+# closure. It hits a landmine when parsing with the Java grammar, for example,
+# without this on-the-fly evaluation.
+#
+#
+# SHARING DFA
+#
+#
+# All instances of the same parser share the same decision DFAs through a
+# static field. Each instance gets its own ATN simulator but they share the
+# same {@link #decisionToDFA} field. They also share a
+# {@link PredictionContextCache} object that makes sure that all
+# {@link PredictionContext} objects are shared among the DFA states. This makes
+# a big size difference.
+#
+#
+# THREAD SAFETY
+#
+#
+# The {@link ParserATNSimulator} locks on the {@link #decisionToDFA} field when
+# it adds a new DFA object to that array. {@link #addDFAEdge}
+# locks on the DFA for the current decision when setting the
+# {@link DFAState#edges} field. {@link #addDFAState} locks on
+# the DFA for the current decision when looking up a DFA state to see if it
+# already exists. We must make sure that all requests to add DFA states that
+# are equivalent result in the same shared DFA object. This is because lots of
+# threads will be trying to update the DFA at once. The
+# {@link #addDFAState} method also locks inside the DFA lock
+# but this time on the shared context cache when it rebuilds the
+# configurations' {@link PredictionContext} objects using cached
+# subgraphs/nodes. No other locking occurs, even during DFA simulation. This is
+# safe as long as we can guarantee that all threads referencing
+# {@code s.edge[t]} get the same physical target {@link DFAState}, or
+# {@code null}. Once into the DFA, the DFA simulation does not reference the
+# {@link DFA#states} map. It follows the {@link DFAState#edges} field to new
+# targets. The DFA simulator will either find {@link DFAState#edges} to be
+# {@code null}, to be non-{@code null} and {@code dfa.edges[t]} null, or
+# {@code dfa.edges[t]} to be non-null. The
+# {@link #addDFAEdge} method could be racing to set the field
+# but in either case the DFA simulator works; if {@code null}, and requests ATN
+# simulation. It could also race trying to get {@code dfa.edges[t]}, but either
+# way it will work because it's not doing a test and set operation.
+#
+#
+# Starting with SLL then failing to combined SLL/LL (Two-Stage
+# Parsing)
+#
+#
+# Sam pointed out that if SLL does not give a syntax error, then there is no
+# point in doing full LL, which is slower. We only have to try LL if we get a
+# syntax error. For maximum speed, Sam starts the parser set to pure SLL
+# mode with the {@link BailErrorStrategy}:
+# If it does not get a syntax error, then we're done. If it does get a syntax
+# error, we need to retry with the combined SLL/LL strategy.
+#
+#
+# The reason this works is as follows. If there are no SLL conflicts, then the
+# grammar is SLL (at least for that input set). If there is an SLL conflict,
+# the full LL analysis must yield a set of viable alternatives which is a
+# subset of the alternatives reported by SLL. If the LL set is a singleton,
+# then the grammar is LL but not SLL. If the LL set is the same size as the SLL
+# set, the decision is SLL. If the LL set has size > 1, then that decision
+# is truly ambiguous on the current input. If the LL set is smaller, then the
+# SLL conflict resolution might choose an alternative that the full LL would
+# rule out as a possibility based upon better context information. If that's
+# the case, then the SLL parse will definitely get an error because the full LL
+# analysis says it's not viable. If SLL conflict resolution chooses an
+# alternative within the LL set, them both SLL and LL would choose the same
+# alternative because they both choose the minimum of multiple conflicting
+# alternatives.
+#
+#
+# Let's say we have a set of SLL conflicting alternatives {@code {1, 2, 3}} and
+# a smaller LL set called s. If s is {@code {2, 3}}, then SLL
+# parsing will get an error because SLL will pursue alternative 1. If
+# s is {@code {1, 2}} or {@code {1, 3}} then both SLL and LL will
+# choose the same alternative because alternative one is the minimum of either
+# set. If s is {@code {2}} or {@code {3}} then SLL will get a syntax
+# error. If s is {@code {1}} then SLL will succeed.
+#
+#
+# Of course, if the input is invalid, then we will get an error for sure in
+# both SLL and LL parsing. Erroneous input will therefore require 2 passes over
+# the input.
+#
+import sys
+from antlr4 import DFA
+from antlr4.BufferedTokenStream import TokenStream
+from antlr4.Parser import Parser
+from antlr4.ParserRuleContext import ParserRuleContext
+from antlr4.PredictionContext import PredictionContextCache, PredictionContext, SingletonPredictionContext, \
+ PredictionContextFromRuleContext
+from antlr4.RuleContext import RuleContext
+from antlr4.Token import Token
+from antlr4.Utils import str_list
+from antlr4.atn.ATN import ATN
+from antlr4.atn.ATNConfig import ATNConfig
+from antlr4.atn.ATNConfigSet import ATNConfigSet
+from antlr4.atn.ATNSimulator import ATNSimulator
+from antlr4.atn.ATNState import DecisionState, RuleStopState, ATNState
+from antlr4.atn.PredictionMode import PredictionMode
+from antlr4.atn.SemanticContext import SemanticContext, andContext, orContext
+from antlr4.atn.Transition import Transition, RuleTransition, ActionTransition, PrecedencePredicateTransition, \
+ PredicateTransition, AtomTransition, SetTransition, NotSetTransition
+from antlr4.dfa.DFAState import DFAState, PredPrediction
+from antlr4.error.Errors import NoViableAltException
+
+
+class ParserATNSimulator(ATNSimulator):
+ __slots__ = (
+ 'parser', 'decisionToDFA', 'predictionMode', '_input', '_startIndex',
+ '_outerContext', '_dfa', 'mergeCache'
+ )
+
+ debug = False
+ trace_atn_sim = False
+ dfa_debug = False
+ retry_debug = False
+
+
+ def __init__(self, parser:Parser, atn:ATN, decisionToDFA:list, sharedContextCache:PredictionContextCache):
+ super().__init__(atn, sharedContextCache)
+ self.parser = parser
+ self.decisionToDFA = decisionToDFA
+ # SLL, LL, or LL + exact ambig detection?#
+ self.predictionMode = PredictionMode.LL
+ # LAME globals to avoid parameters!!!!! I need these down deep in predTransition
+ self._input = None
+ self._startIndex = 0
+ self._outerContext = None
+ self._dfa = None
+ # Each prediction operation uses a cache for merge of prediction contexts.
+ # Don't keep around as it wastes huge amounts of memory. DoubleKeyMap
+ # isn't synchronized but we're ok since two threads shouldn't reuse same
+ # parser/atnsim object because it can only handle one input at a time.
+ # This maps graphs a and b to merged result c. (a,b)→c. We can avoid
+ # the merge if we ever see a and b again. Note that (b,a)→c should
+ # also be examined during cache lookup.
+ #
+ self.mergeCache = None
+
+
+ def reset(self):
+ pass
+
+ def adaptivePredict(self, input:TokenStream, decision:int, outerContext:ParserRuleContext):
+ if ParserATNSimulator.debug or ParserATNSimulator.trace_atn_sim:
+ print("adaptivePredict decision " + str(decision) +
+ " exec LA(1)==" + self.getLookaheadName(input) +
+ " line " + str(input.LT(1).line) + ":" +
+ str(input.LT(1).column))
+ self._input = input
+ self._startIndex = input.index
+ self._outerContext = outerContext
+
+ dfa = self.decisionToDFA[decision]
+ self._dfa = dfa
+ m = input.mark()
+ index = input.index
+
+ # Now we are certain to have a specific decision's DFA
+ # But, do we still need an initial state?
+ try:
+ if dfa.precedenceDfa:
+ # the start state for a precedence DFA depends on the current
+ # parser precedence, and is provided by a DFA method.
+ s0 = dfa.getPrecedenceStartState(self.parser.getPrecedence())
+ else:
+ # the start state for a "regular" DFA is just s0
+ s0 = dfa.s0
+
+ if s0 is None:
+ if outerContext is None:
+ outerContext = ParserRuleContext.EMPTY
+ if ParserATNSimulator.debug:
+ print("predictATN decision " + str(dfa.decision) +
+ " exec LA(1)==" + self.getLookaheadName(input) +
+ ", outerContext=" + str(outerContext));#outerContext.toString(self.parser.literalNames, None))
+
+ fullCtx = False
+ s0_closure = self.computeStartState(dfa.atnStartState, ParserRuleContext.EMPTY, fullCtx)
+
+ if dfa.precedenceDfa:
+ # If this is a precedence DFA, we use applyPrecedenceFilter
+ # to convert the computed start state to a precedence start
+ # state. We then use DFA.setPrecedenceStartState to set the
+ # appropriate start state for the precedence level rather
+ # than simply setting DFA.s0.
+ #
+ dfa.s0.configs = s0_closure # not used for prediction but useful to know start configs anyway
+ s0_closure = self.applyPrecedenceFilter(s0_closure)
+ s0 = self.addDFAState(dfa, DFAState(configs=s0_closure))
+ dfa.setPrecedenceStartState(self.parser.getPrecedence(), s0)
+ else:
+ s0 = self.addDFAState(dfa, DFAState(configs=s0_closure))
+ dfa.s0 = s0
+
+ alt = self.execATN(dfa, s0, input, index, outerContext)
+ if ParserATNSimulator.debug:
+ print("DFA after predictATN: " + dfa.toString(self.parser.literalNames))
+ return alt
+ finally:
+ self._dfa = None
+ self.mergeCache = None # wack cache after each prediction
+ input.seek(index)
+ input.release(m)
+
+ # Performs ATN simulation to compute a predicted alternative based
+ # upon the remaining input, but also updates the DFA cache to avoid
+ # having to traverse the ATN again for the same input sequence.
+
+ # There are some key conditions we're looking for after computing a new
+ # set of ATN configs (proposed DFA state):
+ # if the set is empty, there is no viable alternative for current symbol
+ # does the state uniquely predict an alternative?
+ # does the state have a conflict that would prevent us from
+ # putting it on the work list?
+
+ # We also have some key operations to do:
+ # add an edge from previous DFA state to potentially new DFA state, D,
+ # upon current symbol but only if adding to work list, which means in all
+ # cases except no viable alternative (and possibly non-greedy decisions?)
+ # collecting predicates and adding semantic context to DFA accept states
+ # adding rule context to context-sensitive DFA accept states
+ # consuming an input symbol
+ # reporting a conflict
+ # reporting an ambiguity
+ # reporting a context sensitivity
+ # reporting insufficient predicates
+
+ # cover these cases:
+ # dead end
+ # single alt
+ # single alt + preds
+ # conflict
+ # conflict + preds
+ #
+ def execATN(self, dfa:DFA, s0:DFAState, input:TokenStream, startIndex:int, outerContext:ParserRuleContext ):
+ if ParserATNSimulator.debug or ParserATNSimulator.trace_atn_sim:
+ print("execATN decision " + str(dfa.decision) +
+ ", DFA state " + str(s0) +
+ ", LA(1)==" + self.getLookaheadName(input) +
+ " line " + str(input.LT(1).line) + ":" + str(input.LT(1).column))
+
+ previousD = s0
+
+ t = input.LA(1)
+
+ while True: # while more work
+ D = self.getExistingTargetState(previousD, t)
+ if D is None:
+ D = self.computeTargetState(dfa, previousD, t)
+ if D is self.ERROR:
+ # if any configs in previous dipped into outer context, that
+ # means that input up to t actually finished entry rule
+ # at least for SLL decision. Full LL doesn't dip into outer
+ # so don't need special case.
+ # We will get an error no matter what so delay until after
+ # decision; better error message. Also, no reachable target
+ # ATN states in SLL implies LL will also get nowhere.
+ # If conflict in states that dip out, choose min since we
+ # will get error no matter what.
+ e = self.noViableAlt(input, outerContext, previousD.configs, startIndex)
+ input.seek(startIndex)
+ alt = self.getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule(previousD.configs, outerContext)
+ if alt!=ATN.INVALID_ALT_NUMBER:
+ return alt
+ raise e
+
+ if D.requiresFullContext and self.predictionMode != PredictionMode.SLL:
+ # IF PREDS, MIGHT RESOLVE TO SINGLE ALT => SLL (or syntax error)
+ conflictingAlts = D.configs.conflictingAlts
+ if D.predicates is not None:
+ if ParserATNSimulator.debug:
+ print("DFA state has preds in DFA sim LL failover")
+ conflictIndex = input.index
+ if conflictIndex != startIndex:
+ input.seek(startIndex)
+
+ conflictingAlts = self.evalSemanticContext(D.predicates, outerContext, True)
+ if len(conflictingAlts)==1:
+ if ParserATNSimulator.debug:
+ print("Full LL avoided")
+ return min(conflictingAlts)
+
+ if conflictIndex != startIndex:
+ # restore the index so reporting the fallback to full
+ # context occurs with the index at the correct spot
+ input.seek(conflictIndex)
+
+ if ParserATNSimulator.dfa_debug:
+ print("ctx sensitive state " + str(outerContext) +" in " + str(D))
+ fullCtx = True
+ s0_closure = self.computeStartState(dfa.atnStartState, outerContext, fullCtx)
+ self.reportAttemptingFullContext(dfa, conflictingAlts, D.configs, startIndex, input.index)
+ alt = self.execATNWithFullContext(dfa, D, s0_closure, input, startIndex, outerContext)
+ return alt
+
+ if D.isAcceptState:
+ if D.predicates is None:
+ return D.prediction
+
+ stopIndex = input.index
+ input.seek(startIndex)
+ alts = self.evalSemanticContext(D.predicates, outerContext, True)
+ if len(alts)==0:
+ raise self.noViableAlt(input, outerContext, D.configs, startIndex)
+ elif len(alts)==1:
+ return min(alts)
+ else:
+ # report ambiguity after predicate evaluation to make sure the correct
+ # set of ambig alts is reported.
+ self.reportAmbiguity(dfa, D, startIndex, stopIndex, False, alts, D.configs)
+ return min(alts)
+
+ previousD = D
+
+ if t != Token.EOF:
+ input.consume()
+ t = input.LA(1)
+
+ #
+ # Get an existing target state for an edge in the DFA. If the target state
+ # for the edge has not yet been computed or is otherwise not available,
+ # this method returns {@code null}.
+ #
+ # @param previousD The current DFA state
+ # @param t The next input symbol
+ # @return The existing target DFA state for the given input symbol
+ # {@code t}, or {@code null} if the target state for this edge is not
+ # already cached
+ #
+ def getExistingTargetState(self, previousD:DFAState, t:int):
+ edges = previousD.edges
+ if edges is None or t + 1 < 0 or t + 1 >= len(edges):
+ return None
+ else:
+ return edges[t + 1]
+
+ #
+ # Compute a target state for an edge in the DFA, and attempt to add the
+ # computed state and corresponding edge to the DFA.
+ #
+ # @param dfa The DFA
+ # @param previousD The current DFA state
+ # @param t The next input symbol
+ #
+ # @return The computed target DFA state for the given input symbol
+ # {@code t}. If {@code t} does not lead to a valid DFA state, this method
+ # returns {@link #ERROR}.
+ #
+ def computeTargetState(self, dfa:DFA, previousD:DFAState, t:int):
+ reach = self.computeReachSet(previousD.configs, t, False)
+ if reach is None:
+ self.addDFAEdge(dfa, previousD, t, self.ERROR)
+ return self.ERROR
+
+ # create new target state; we'll add to DFA after it's complete
+ D = DFAState(configs=reach)
+
+ predictedAlt = self.getUniqueAlt(reach)
+
+ if ParserATNSimulator.debug:
+ altSubSets = PredictionMode.getConflictingAltSubsets(reach)
+ print("SLL altSubSets=" + str(altSubSets) + ", configs=" + str(reach) +
+ ", predict=" + str(predictedAlt) + ", allSubsetsConflict=" +
+ str(PredictionMode.allSubsetsConflict(altSubSets)) + ", conflictingAlts=" +
+ str(self.getConflictingAlts(reach)))
+
+ if predictedAlt!=ATN.INVALID_ALT_NUMBER:
+ # NO CONFLICT, UNIQUELY PREDICTED ALT
+ D.isAcceptState = True
+ D.configs.uniqueAlt = predictedAlt
+ D.prediction = predictedAlt
+ elif PredictionMode.hasSLLConflictTerminatingPrediction(self.predictionMode, reach):
+ # MORE THAN ONE VIABLE ALTERNATIVE
+ D.configs.conflictingAlts = self.getConflictingAlts(reach)
+ D.requiresFullContext = True
+ # in SLL-only mode, we will stop at this state and return the minimum alt
+ D.isAcceptState = True
+ D.prediction = min(D.configs.conflictingAlts)
+
+ if D.isAcceptState and D.configs.hasSemanticContext:
+ self.predicateDFAState(D, self.atn.getDecisionState(dfa.decision))
+ if D.predicates is not None:
+ D.prediction = ATN.INVALID_ALT_NUMBER
+
+ # all adds to dfa are done after we've created full D state
+ D = self.addDFAEdge(dfa, previousD, t, D)
+ return D
+
+ def predicateDFAState(self, dfaState:DFAState, decisionState:DecisionState):
+ # We need to test all predicates, even in DFA states that
+ # uniquely predict alternative.
+ nalts = len(decisionState.transitions)
+ # Update DFA so reach becomes accept state with (predicate,alt)
+ # pairs if preds found for conflicting alts
+ altsToCollectPredsFrom = self.getConflictingAltsOrUniqueAlt(dfaState.configs)
+ altToPred = self.getPredsForAmbigAlts(altsToCollectPredsFrom, dfaState.configs, nalts)
+ if altToPred is not None:
+ dfaState.predicates = self.getPredicatePredictions(altsToCollectPredsFrom, altToPred)
+ dfaState.prediction = ATN.INVALID_ALT_NUMBER # make sure we use preds
+ else:
+ # There are preds in configs but they might go away
+ # when OR'd together like {p}? || NONE == NONE. If neither
+ # alt has preds, resolve to min alt
+ dfaState.prediction = min(altsToCollectPredsFrom)
+
+ # comes back with reach.uniqueAlt set to a valid alt
+ def execATNWithFullContext(self, dfa:DFA, D:DFAState, # how far we got before failing over
+ s0:ATNConfigSet,
+ input:TokenStream,
+ startIndex:int,
+ outerContext:ParserRuleContext):
+ if ParserATNSimulator.debug or ParserATNSimulator.trace_atn_sim:
+ print("execATNWithFullContext", str(s0))
+ fullCtx = True
+ foundExactAmbig = False
+ reach = None
+ previous = s0
+ input.seek(startIndex)
+ t = input.LA(1)
+ predictedAlt = -1
+ while (True): # while more work
+ reach = self.computeReachSet(previous, t, fullCtx)
+ if reach is None:
+ # if any configs in previous dipped into outer context, that
+ # means that input up to t actually finished entry rule
+ # at least for LL decision. Full LL doesn't dip into outer
+ # so don't need special case.
+ # We will get an error no matter what so delay until after
+ # decision; better error message. Also, no reachable target
+ # ATN states in SLL implies LL will also get nowhere.
+ # If conflict in states that dip out, choose min since we
+ # will get error no matter what.
+ e = self.noViableAlt(input, outerContext, previous, startIndex)
+ input.seek(startIndex)
+ alt = self.getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule(previous, outerContext)
+ if alt!=ATN.INVALID_ALT_NUMBER:
+ return alt
+ else:
+ raise e
+
+ altSubSets = PredictionMode.getConflictingAltSubsets(reach)
+ if ParserATNSimulator.debug:
+ print("LL altSubSets=" + str(altSubSets) + ", predict=" +
+ str(PredictionMode.getUniqueAlt(altSubSets)) + ", resolvesToJustOneViableAlt=" +
+ str(PredictionMode.resolvesToJustOneViableAlt(altSubSets)))
+
+ reach.uniqueAlt = self.getUniqueAlt(reach)
+ # unique prediction?
+ if reach.uniqueAlt!=ATN.INVALID_ALT_NUMBER:
+ predictedAlt = reach.uniqueAlt
+ break
+ elif self.predictionMode is not PredictionMode.LL_EXACT_AMBIG_DETECTION:
+ predictedAlt = PredictionMode.resolvesToJustOneViableAlt(altSubSets)
+ if predictedAlt != ATN.INVALID_ALT_NUMBER:
+ break
+ else:
+ # In exact ambiguity mode, we never try to terminate early.
+ # Just keeps scarfing until we know what the conflict is
+ if PredictionMode.allSubsetsConflict(altSubSets) and PredictionMode.allSubsetsEqual(altSubSets):
+ foundExactAmbig = True
+ predictedAlt = PredictionMode.getSingleViableAlt(altSubSets)
+ break
+ # else there are multiple non-conflicting subsets or
+ # we're not sure what the ambiguity is yet.
+ # So, keep going.
+
+ previous = reach
+ if t != Token.EOF:
+ input.consume()
+ t = input.LA(1)
+
+ # If the configuration set uniquely predicts an alternative,
+ # without conflict, then we know that it's a full LL decision
+ # not SLL.
+ if reach.uniqueAlt != ATN.INVALID_ALT_NUMBER :
+ self.reportContextSensitivity(dfa, predictedAlt, reach, startIndex, input.index)
+ return predictedAlt
+
+ # We do not check predicates here because we have checked them
+ # on-the-fly when doing full context prediction.
+
+ #
+ # In non-exact ambiguity detection mode, we might actually be able to
+ # detect an exact ambiguity, but I'm not going to spend the cycles
+ # needed to check. We only emit ambiguity warnings in exact ambiguity
+ # mode.
+ #
+ # For example, we might know that we have conflicting configurations.
+ # But, that does not mean that there is no way forward without a
+ # conflict. It's possible to have nonconflicting alt subsets as in:
+
+ # altSubSets=[{1, 2}, {1, 2}, {1}, {1, 2}]
+
+ # from
+ #
+ # [(17,1,[5 $]), (13,1,[5 10 $]), (21,1,[5 10 $]), (11,1,[$]),
+ # (13,2,[5 10 $]), (21,2,[5 10 $]), (11,2,[$])]
+ #
+ # In this case, (17,1,[5 $]) indicates there is some next sequence that
+ # would resolve this without conflict to alternative 1. Any other viable
+ # next sequence, however, is associated with a conflict. We stop
+ # looking for input because no amount of further lookahead will alter
+ # the fact that we should predict alternative 1. We just can't say for
+ # sure that there is an ambiguity without looking further.
+
+ self.reportAmbiguity(dfa, D, startIndex, input.index, foundExactAmbig, None, reach)
+
+ return predictedAlt
+
+ def computeReachSet(self, closure:ATNConfigSet, t:int, fullCtx:bool):
+ if ParserATNSimulator.debug:
+ print("in computeReachSet, starting closure: " + str(closure))
+
+ if self.mergeCache is None:
+ self.mergeCache = dict()
+
+ intermediate = ATNConfigSet(fullCtx)
+
+ # Configurations already in a rule stop state indicate reaching the end
+ # of the decision rule (local context) or end of the start rule (full
+ # context). Once reached, these configurations are never updated by a
+ # closure operation, so they are handled separately for the performance
+ # advantage of having a smaller intermediate set when calling closure.
+ #
+ # For full-context reach operations, separate handling is required to
+ # ensure that the alternative matching the longest overall sequence is
+ # chosen when multiple such configurations can match the input.
+
+ skippedStopStates = None
+
+ # First figure out where we can reach on input t
+ for c in closure:
+ if ParserATNSimulator.debug:
+ print("testing " + self.getTokenName(t) + " at " + str(c))
+
+ if isinstance(c.state, RuleStopState):
+ if fullCtx or t == Token.EOF:
+ if skippedStopStates is None:
+ skippedStopStates = list()
+ skippedStopStates.append(c)
+ continue
+
+ for trans in c.state.transitions:
+ target = self.getReachableTarget(trans, t)
+ if target is not None:
+ intermediate.add(ATNConfig(state=target, config=c), self.mergeCache)
+
+ # Now figure out where the reach operation can take us...
+
+ reach = None
+
+ # This block optimizes the reach operation for intermediate sets which
+ # trivially indicate a termination state for the overall
+ # adaptivePredict operation.
+ #
+ # The conditions assume that intermediate
+ # contains all configurations relevant to the reach set, but this
+ # condition is not true when one or more configurations have been
+ # withheld in skippedStopStates, or when the current symbol is EOF.
+ #
+ if skippedStopStates is None and t!=Token.EOF:
+ if len(intermediate)==1:
+ # Don't pursue the closure if there is just one state.
+ # It can only have one alternative; just add to result
+ # Also don't pursue the closure if there is unique alternative
+ # among the configurations.
+ reach = intermediate
+ elif self.getUniqueAlt(intermediate)!=ATN.INVALID_ALT_NUMBER:
+ # Also don't pursue the closure if there is unique alternative
+ # among the configurations.
+ reach = intermediate
+
+ # If the reach set could not be trivially determined, perform a closure
+ # operation on the intermediate set to compute its initial value.
+ #
+ if reach is None:
+ reach = ATNConfigSet(fullCtx)
+ closureBusy = set()
+ treatEofAsEpsilon = t == Token.EOF
+ for c in intermediate:
+ self.closure(c, reach, closureBusy, False, fullCtx, treatEofAsEpsilon)
+
+ if t == Token.EOF:
+ # After consuming EOF no additional input is possible, so we are
+ # only interested in configurations which reached the end of the
+ # decision rule (local context) or end of the start rule (full
+ # context). Update reach to contain only these configurations. This
+ # handles both explicit EOF transitions in the grammar and implicit
+ # EOF transitions following the end of the decision or start rule.
+ #
+ # When reach==intermediate, no closure operation was performed. In
+ # this case, removeAllConfigsNotInRuleStopState needs to check for
+ # reachable rule stop states as well as configurations already in
+ # a rule stop state.
+ #
+ # This is handled before the configurations in skippedStopStates,
+ # because any configurations potentially added from that list are
+ # already guaranteed to meet this condition whether or not it's
+ # required.
+ #
+ reach = self.removeAllConfigsNotInRuleStopState(reach, reach is intermediate)
+
+ # If skippedStopStates is not null, then it contains at least one
+ # configuration. For full-context reach operations, these
+ # configurations reached the end of the start rule, in which case we
+ # only add them back to reach if no configuration during the current
+ # closure operation reached such a state. This ensures adaptivePredict
+ # chooses an alternative matching the longest overall sequence when
+ # multiple alternatives are viable.
+ #
+ if skippedStopStates is not None and ( (not fullCtx) or (not PredictionMode.hasConfigInRuleStopState(reach))):
+ for c in skippedStopStates:
+ reach.add(c, self.mergeCache)
+
+ if ParserATNSimulator.trace_atn_sim:
+ print("computeReachSet", str(closure), "->", reach)
+
+ if len(reach)==0:
+ return None
+ else:
+ return reach
+
+ #
+ # Return a configuration set containing only the configurations from
+ # {@code configs} which are in a {@link RuleStopState}. If all
+ # configurations in {@code configs} are already in a rule stop state, this
+ # method simply returns {@code configs}.
+ #
+ #
When {@code lookToEndOfRule} is true, this method uses
+ # {@link ATN#nextTokens} for each configuration in {@code configs} which is
+ # not already in a rule stop state to see if a rule stop state is reachable
+ # from the configuration via epsilon-only transitions.
+ #
+ # @param configs the configuration set to update
+ # @param lookToEndOfRule when true, this method checks for rule stop states
+ # reachable by epsilon-only transitions from each configuration in
+ # {@code configs}.
+ #
+ # @return {@code configs} if all configurations in {@code configs} are in a
+ # rule stop state, otherwise return a new configuration set containing only
+ # the configurations from {@code configs} which are in a rule stop state
+ #
+ def removeAllConfigsNotInRuleStopState(self, configs:ATNConfigSet, lookToEndOfRule:bool):
+ if PredictionMode.allConfigsInRuleStopStates(configs):
+ return configs
+ result = ATNConfigSet(configs.fullCtx)
+ for config in configs:
+ if isinstance(config.state, RuleStopState):
+ result.add(config, self.mergeCache)
+ continue
+ if lookToEndOfRule and config.state.epsilonOnlyTransitions:
+ nextTokens = self.atn.nextTokens(config.state)
+ if Token.EPSILON in nextTokens:
+ endOfRuleState = self.atn.ruleToStopState[config.state.ruleIndex]
+ result.add(ATNConfig(state=endOfRuleState, config=config), self.mergeCache)
+ return result
+
+ def computeStartState(self, p:ATNState, ctx:RuleContext, fullCtx:bool):
+ # always at least the implicit call to start rule
+ initialContext = PredictionContextFromRuleContext(self.atn, ctx)
+ configs = ATNConfigSet(fullCtx)
+
+ if ParserATNSimulator.trace_atn_sim:
+ print("computeStartState from ATN state "+str(p)+
+ " initialContext="+str(initialContext))
+
+ for i in range(0, len(p.transitions)):
+ target = p.transitions[i].target
+ c = ATNConfig(target, i+1, initialContext)
+ closureBusy = set()
+ self.closure(c, configs, closureBusy, True, fullCtx, False)
+ return configs
+
+ #
+ # This method transforms the start state computed by
+ # {@link #computeStartState} to the special start state used by a
+ # precedence DFA for a particular precedence value. The transformation
+ # process applies the following changes to the start state's configuration
+ # set.
+ #
+ #
+ #
Evaluate the precedence predicates for each configuration using
+ # {@link SemanticContext#evalPrecedence}.
+ #
Remove all configurations which predict an alternative greater than
+ # 1, for which another configuration that predicts alternative 1 is in the
+ # same ATN state with the same prediction context. This transformation is
+ # valid for the following reasons:
+ #
+ #
The closure block cannot contain any epsilon transitions which bypass
+ # the body of the closure, so all states reachable via alternative 1 are
+ # part of the precedence alternatives of the transformed left-recursive
+ # rule.
+ #
The "primary" portion of a left recursive rule cannot contain an
+ # epsilon transition, so the only way an alternative other than 1 can exist
+ # in a state that is also reachable via alternative 1 is by nesting calls
+ # to the left-recursive rule, with the outer calls not being at the
+ # preferred precedence level.
+ #
+ #
+ #
+ #
+ #
+ # The prediction context must be considered by this filter to address
+ # situations like the following.
+ #
+ # If the above grammar, the ATN state immediately before the token
+ # reference {@code 'a'} in {@code letterA} is reachable from the left edge
+ # of both the primary and closure blocks of the left-recursive rule
+ # {@code statement}. The prediction context associated with each of these
+ # configurations distinguishes between them, and prevents the alternative
+ # which stepped out to {@code prog} (and then back in to {@code statement}
+ # from being eliminated by the filter.
+ #
+ #
+ # @param configs The configuration set computed by
+ # {@link #computeStartState} as the start state for the DFA.
+ # @return The transformed configuration set representing the start state
+ # for a precedence DFA at a particular precedence level (determined by
+ # calling {@link Parser#getPrecedence}).
+ #
+ def applyPrecedenceFilter(self, configs:ATNConfigSet):
+ statesFromAlt1 = dict()
+ configSet = ATNConfigSet(configs.fullCtx)
+ for config in configs:
+ # handle alt 1 first
+ if config.alt != 1:
+ continue
+ updatedContext = config.semanticContext.evalPrecedence(self.parser, self._outerContext)
+ if updatedContext is None:
+ # the configuration was eliminated
+ continue
+
+ statesFromAlt1[config.state.stateNumber] = config.context
+ if updatedContext is not config.semanticContext:
+ configSet.add(ATNConfig(config=config, semantic=updatedContext), self.mergeCache)
+ else:
+ configSet.add(config, self.mergeCache)
+
+ for config in configs:
+ if config.alt == 1:
+ # already handled
+ continue
+
+ # In the future, this elimination step could be updated to also
+ # filter the prediction context for alternatives predicting alt>1
+ # (basically a graph subtraction algorithm).
+ #
+ if not config.precedenceFilterSuppressed:
+ context = statesFromAlt1.get(config.state.stateNumber, None)
+ if context==config.context:
+ # eliminated
+ continue
+
+ configSet.add(config, self.mergeCache)
+
+ return configSet
+
+ def getReachableTarget(self, trans:Transition, ttype:int):
+ if trans.matches(ttype, 0, self.atn.maxTokenType):
+ return trans.target
+ else:
+ return None
+
+ def getPredsForAmbigAlts(self, ambigAlts:set, configs:ATNConfigSet, nalts:int):
+ # REACH=[1|1|[]|0:0, 1|2|[]|0:1]
+ # altToPred starts as an array of all null contexts. The entry at index i
+ # corresponds to alternative i. altToPred[i] may have one of three values:
+ # 1. null: no ATNConfig c is found such that c.alt==i
+ # 2. SemanticContext.NONE: At least one ATNConfig c exists such that
+ # c.alt==i and c.semanticContext==SemanticContext.NONE. In other words,
+ # alt i has at least one unpredicated config.
+ # 3. Non-NONE Semantic Context: There exists at least one, and for all
+ # ATNConfig c such that c.alt==i, c.semanticContext!=SemanticContext.NONE.
+ #
+ # From this, it is clear that NONE||anything==NONE.
+ #
+ altToPred = [None] * (nalts + 1)
+ for c in configs:
+ if c.alt in ambigAlts:
+ altToPred[c.alt] = orContext(altToPred[c.alt], c.semanticContext)
+
+ nPredAlts = 0
+ for i in range(1, nalts+1):
+ if altToPred[i] is None:
+ altToPred[i] = SemanticContext.NONE
+ elif altToPred[i] is not SemanticContext.NONE:
+ nPredAlts += 1
+
+ # nonambig alts are null in altToPred
+ if nPredAlts==0:
+ altToPred = None
+ if ParserATNSimulator.debug:
+ print("getPredsForAmbigAlts result " + str_list(altToPred))
+ return altToPred
+
+ def getPredicatePredictions(self, ambigAlts:set, altToPred:list):
+ pairs = []
+ containsPredicate = False
+ for i in range(1, len(altToPred)):
+ pred = altToPred[i]
+ # unpredicated is indicated by SemanticContext.NONE
+ if ambigAlts is not None and i in ambigAlts:
+ pairs.append(PredPrediction(pred, i))
+ if pred is not SemanticContext.NONE:
+ containsPredicate = True
+
+ if not containsPredicate:
+ return None
+
+ return pairs
+
+ #
+ # This method is used to improve the localization of error messages by
+ # choosing an alternative rather than throwing a
+ # {@link NoViableAltException} in particular prediction scenarios where the
+ # {@link #ERROR} state was reached during ATN simulation.
+ #
+ #
+ # The default implementation of this method uses the following
+ # algorithm to identify an ATN configuration which successfully parsed the
+ # decision entry rule. Choosing such an alternative ensures that the
+ # {@link ParserRuleContext} returned by the calling rule will be complete
+ # and valid, and the syntax error will be reported later at a more
+ # localized location.
+ #
+ #
+ #
If a syntactically valid path or paths reach the end of the decision rule and
+ # they are semantically valid if predicated, return the min associated alt.
+ #
Else, if a semantically invalid but syntactically valid path exist
+ # or paths exist, return the minimum associated alt.
+ #
+ #
Otherwise, return {@link ATN#INVALID_ALT_NUMBER}.
+ #
+ #
+ #
+ # In some scenarios, the algorithm described above could predict an
+ # alternative which will result in a {@link FailedPredicateException} in
+ # the parser. Specifically, this could occur if the only configuration
+ # capable of successfully parsing to the end of the decision rule is
+ # blocked by a semantic predicate. By choosing this alternative within
+ # {@link #adaptivePredict} instead of throwing a
+ # {@link NoViableAltException}, the resulting
+ # {@link FailedPredicateException} in the parser will identify the specific
+ # predicate which is preventing the parser from successfully parsing the
+ # decision rule, which helps developers identify and correct logic errors
+ # in semantic predicates.
+ #
+ #
+ # @param configs The ATN configurations which were valid immediately before
+ # the {@link #ERROR} state was reached
+ # @param outerContext The is the \gamma_0 initial parser context from the paper
+ # or the parser stack at the instant before prediction commences.
+ #
+ # @return The value to return from {@link #adaptivePredict}, or
+ # {@link ATN#INVALID_ALT_NUMBER} if a suitable alternative was not
+ # identified and {@link #adaptivePredict} should report an error instead.
+ #
+ def getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule(self, configs:ATNConfigSet, outerContext:ParserRuleContext):
+ semValidConfigs, semInvalidConfigs = self.splitAccordingToSemanticValidity(configs, outerContext)
+ alt = self.getAltThatFinishedDecisionEntryRule(semValidConfigs)
+ if alt!=ATN.INVALID_ALT_NUMBER: # semantically/syntactically viable path exists
+ return alt
+ # Is there a syntactically valid path with a failed pred?
+ if len(semInvalidConfigs)>0:
+ alt = self.getAltThatFinishedDecisionEntryRule(semInvalidConfigs)
+ if alt!=ATN.INVALID_ALT_NUMBER: # syntactically viable path exists
+ return alt
+ return ATN.INVALID_ALT_NUMBER
+
+ def getAltThatFinishedDecisionEntryRule(self, configs:ATNConfigSet):
+ alts = set()
+ for c in configs:
+ if c.reachesIntoOuterContext>0 or (isinstance(c.state, RuleStopState) and c.context.hasEmptyPath() ):
+ alts.add(c.alt)
+ if len(alts)==0:
+ return ATN.INVALID_ALT_NUMBER
+ else:
+ return min(alts)
+
+ # Walk the list of configurations and split them according to
+ # those that have preds evaluating to true/false. If no pred, assume
+ # true pred and include in succeeded set. Returns Pair of sets.
+ #
+ # Create a new set so as not to alter the incoming parameter.
+ #
+ # Assumption: the input stream has been restored to the starting point
+ # prediction, which is where predicates need to evaluate.
+ #
+ def splitAccordingToSemanticValidity(self, configs:ATNConfigSet, outerContext:ParserRuleContext):
+ succeeded = ATNConfigSet(configs.fullCtx)
+ failed = ATNConfigSet(configs.fullCtx)
+ for c in configs:
+ if c.semanticContext is not SemanticContext.NONE:
+ predicateEvaluationResult = c.semanticContext.eval(self.parser, outerContext)
+ if predicateEvaluationResult:
+ succeeded.add(c)
+ else:
+ failed.add(c)
+ else:
+ succeeded.add(c)
+ return (succeeded,failed)
+
+ # Look through a list of predicate/alt pairs, returning alts for the
+ # pairs that win. A {@code NONE} predicate indicates an alt containing an
+ # unpredicated config which behaves as "always true." If !complete
+ # then we stop at the first predicate that evaluates to true. This
+ # includes pairs with null predicates.
+ #
+ def evalSemanticContext(self, predPredictions:list, outerContext:ParserRuleContext, complete:bool):
+ predictions = set()
+ for pair in predPredictions:
+ if pair.pred is SemanticContext.NONE:
+ predictions.add(pair.alt)
+ if not complete:
+ break
+ continue
+ predicateEvaluationResult = pair.pred.eval(self.parser, outerContext)
+ if ParserATNSimulator.debug or ParserATNSimulator.dfa_debug:
+ print("eval pred " + str(pair) + "=" + str(predicateEvaluationResult))
+
+ if predicateEvaluationResult:
+ if ParserATNSimulator.debug or ParserATNSimulator.dfa_debug:
+ print("PREDICT " + str(pair.alt))
+ predictions.add(pair.alt)
+ if not complete:
+ break
+ return predictions
+
+
+ # TODO: If we are doing predicates, there is no point in pursuing
+ # closure operations if we reach a DFA state that uniquely predicts
+ # alternative. We will not be caching that DFA state and it is a
+ # waste to pursue the closure. Might have to advance when we do
+ # ambig detection thought :(
+ #
+
+ def closure(self, config:ATNConfig, configs:ATNConfigSet, closureBusy:set, collectPredicates:bool, fullCtx:bool, treatEofAsEpsilon:bool):
+ initialDepth = 0
+ self.closureCheckingStopState(config, configs, closureBusy, collectPredicates,
+ fullCtx, initialDepth, treatEofAsEpsilon)
+
+
+ def closureCheckingStopState(self, config:ATNConfig, configs:ATNConfigSet, closureBusy:set, collectPredicates:bool, fullCtx:bool, depth:int, treatEofAsEpsilon:bool):
+ if ParserATNSimulator.trace_atn_sim:
+ print("closure(" + str(config) + ")")
+
+ if isinstance(config.state, RuleStopState):
+ # We hit rule end. If we have context info, use it
+ # run thru all possible stack tops in ctx
+ if not config.context.isEmpty():
+ for i in range(0, len(config.context)):
+ state = config.context.getReturnState(i)
+ if state is PredictionContext.EMPTY_RETURN_STATE:
+ if fullCtx:
+ configs.add(ATNConfig(state=config.state, context=PredictionContext.EMPTY, config=config), self.mergeCache)
+ continue
+ else:
+ # we have no context info, just chase follow links (if greedy)
+ if ParserATNSimulator.debug:
+ print("FALLING off rule " + self.getRuleName(config.state.ruleIndex))
+ self.closure_(config, configs, closureBusy, collectPredicates,
+ fullCtx, depth, treatEofAsEpsilon)
+ continue
+ returnState = self.atn.states[state]
+ newContext = config.context.getParent(i) # "pop" return state
+ c = ATNConfig(state=returnState, alt=config.alt, context=newContext, semantic=config.semanticContext)
+ # While we have context to pop back from, we may have
+ # gotten that context AFTER having falling off a rule.
+ # Make sure we track that we are now out of context.
+ c.reachesIntoOuterContext = config.reachesIntoOuterContext
+ self.closureCheckingStopState(c, configs, closureBusy, collectPredicates, fullCtx, depth - 1, treatEofAsEpsilon)
+ return
+ elif fullCtx:
+ # reached end of start rule
+ configs.add(config, self.mergeCache)
+ return
+ else:
+ # else if we have no context info, just chase follow links (if greedy)
+ if ParserATNSimulator.debug:
+ print("FALLING off rule " + self.getRuleName(config.state.ruleIndex))
+
+ self.closure_(config, configs, closureBusy, collectPredicates, fullCtx, depth, treatEofAsEpsilon)
+
+ # Do the actual work of walking epsilon edges#
+ def closure_(self, config:ATNConfig, configs:ATNConfigSet, closureBusy:set, collectPredicates:bool, fullCtx:bool, depth:int, treatEofAsEpsilon:bool):
+ p = config.state
+ # optimization
+ if not p.epsilonOnlyTransitions:
+ configs.add(config, self.mergeCache)
+ # make sure to not return here, because EOF transitions can act as
+ # both epsilon transitions and non-epsilon transitions.
+
+ first = True
+ for t in p.transitions:
+ if first:
+ first = False
+ if self.canDropLoopEntryEdgeInLeftRecursiveRule(config):
+ continue
+
+ continueCollecting = collectPredicates and not isinstance(t, ActionTransition)
+ c = self.getEpsilonTarget(config, t, continueCollecting, depth == 0, fullCtx, treatEofAsEpsilon)
+ if c is not None:
+ newDepth = depth
+ if isinstance( config.state, RuleStopState):
+ # target fell off end of rule; mark resulting c as having dipped into outer context
+ # We can't get here if incoming config was rule stop and we had context
+ # track how far we dip into outer context. Might
+ # come in handy and we avoid evaluating context dependent
+ # preds if this is > 0.
+ if self._dfa is not None and self._dfa.precedenceDfa:
+ if t.outermostPrecedenceReturn == self._dfa.atnStartState.ruleIndex:
+ c.precedenceFilterSuppressed = True
+ c.reachesIntoOuterContext += 1
+ if c in closureBusy:
+ # avoid infinite recursion for right-recursive rules
+ continue
+ closureBusy.add(c)
+ configs.dipsIntoOuterContext = True # TODO: can remove? only care when we add to set per middle of this method
+ newDepth -= 1
+ if ParserATNSimulator.debug:
+ print("dips into outer ctx: " + str(c))
+ else:
+ if not t.isEpsilon:
+ if c in closureBusy:
+ # avoid infinite recursion for EOF* and EOF+
+ continue
+ closureBusy.add(c)
+ if isinstance(t, RuleTransition):
+ # latch when newDepth goes negative - once we step out of the entry context we can't return
+ if newDepth >= 0:
+ newDepth += 1
+
+ self.closureCheckingStopState(c, configs, closureBusy, continueCollecting, fullCtx, newDepth, treatEofAsEpsilon)
+
+
+
+ # Implements first-edge (loop entry) elimination as an optimization
+ # during closure operations. See antlr/antlr4#1398.
+ #
+ # The optimization is to avoid adding the loop entry config when
+ # the exit path can only lead back to the same
+ # StarLoopEntryState after popping context at the rule end state
+ # (traversing only epsilon edges, so we're still in closure, in
+ # this same rule).
+ #
+ # We need to detect any state that can reach loop entry on
+ # epsilon w/o exiting rule. We don't have to look at FOLLOW
+ # links, just ensure that all stack tops for config refer to key
+ # states in LR rule.
+ #
+ # To verify we are in the right situation we must first check
+ # closure is at a StarLoopEntryState generated during LR removal.
+ # Then we check that each stack top of context is a return state
+ # from one of these cases:
+ #
+ # 1. 'not' expr, '(' type ')' expr. The return state points at loop entry state
+ # 2. expr op expr. The return state is the block end of internal block of (...)*
+ # 3. 'between' expr 'and' expr. The return state of 2nd expr reference.
+ # That state points at block end of internal block of (...)*.
+ # 4. expr '?' expr ':' expr. The return state points at block end,
+ # which points at loop entry state.
+ #
+ # If any is true for each stack top, then closure does not add a
+ # config to the current config set for edge[0], the loop entry branch.
+ #
+ # Conditions fail if any context for the current config is:
+ #
+ # a. empty (we'd fall out of expr to do a global FOLLOW which could
+ # even be to some weird spot in expr) or,
+ # b. lies outside of expr or,
+ # c. lies within expr but at a state not the BlockEndState
+ # generated during LR removal
+ #
+ # Do we need to evaluate predicates ever in closure for this case?
+ #
+ # No. Predicates, including precedence predicates, are only
+ # evaluated when computing a DFA start state. I.e., only before
+ # the lookahead (but not parser) consumes a token.
+ #
+ # There are no epsilon edges allowed in LR rule alt blocks or in
+ # the "primary" part (ID here). If closure is in
+ # StarLoopEntryState any lookahead operation will have consumed a
+ # token as there are no epsilon-paths that lead to
+ # StarLoopEntryState. We do not have to evaluate predicates
+ # therefore if we are in the generated StarLoopEntryState of a LR
+ # rule. Note that when making a prediction starting at that
+ # decision point, decision d=2, compute-start-state performs
+ # closure starting at edges[0], edges[1] emanating from
+ # StarLoopEntryState. That means it is not performing closure on
+ # StarLoopEntryState during compute-start-state.
+ #
+ # How do we know this always gives same prediction answer?
+ #
+ # Without predicates, loop entry and exit paths are ambiguous
+ # upon remaining input +b (in, say, a+b). Either paths lead to
+ # valid parses. Closure can lead to consuming + immediately or by
+ # falling out of this call to expr back into expr and loop back
+ # again to StarLoopEntryState to match +b. In this special case,
+ # we choose the more efficient path, which is to take the bypass
+ # path.
+ #
+ # The lookahead language has not changed because closure chooses
+ # one path over the other. Both paths lead to consuming the same
+ # remaining input during a lookahead operation. If the next token
+ # is an operator, lookahead will enter the choice block with
+ # operators. If it is not, lookahead will exit expr. Same as if
+ # closure had chosen to enter the choice block immediately.
+ #
+ # Closure is examining one config (some loopentrystate, some alt,
+ # context) which means it is considering exactly one alt. Closure
+ # always copies the same alt to any derived configs.
+ #
+ # How do we know this optimization doesn't mess up precedence in
+ # our parse trees?
+ #
+ # Looking through expr from left edge of stat only has to confirm
+ # that an input, say, a+b+c; begins with any valid interpretation
+ # of an expression. The precedence actually doesn't matter when
+ # making a decision in stat seeing through expr. It is only when
+ # parsing rule expr that we must use the precedence to get the
+ # right interpretation and, hence, parse tree.
+ #
+ # @since 4.6
+ #
+ def canDropLoopEntryEdgeInLeftRecursiveRule(self, config):
+ # return False
+ p = config.state
+ # First check to see if we are in StarLoopEntryState generated during
+ # left-recursion elimination. For efficiency, also check if
+ # the context has an empty stack case. If so, it would mean
+ # global FOLLOW so we can't perform optimization
+ # Are we the special loop entry/exit state? or SLL wildcard
+ if p.stateType != ATNState.STAR_LOOP_ENTRY \
+ or not p.isPrecedenceDecision \
+ or config.context.isEmpty() \
+ or config.context.hasEmptyPath():
+ return False
+
+ # Require all return states to return back to the same rule
+ # that p is in.
+ numCtxs = len(config.context)
+ for i in range(0, numCtxs): # for each stack context
+ returnState = self.atn.states[config.context.getReturnState(i)]
+ if returnState.ruleIndex != p.ruleIndex:
+ return False
+
+ decisionStartState = p.transitions[0].target
+ blockEndStateNum = decisionStartState.endState.stateNumber
+ blockEndState = self.atn.states[blockEndStateNum]
+
+ # Verify that the top of each stack context leads to loop entry/exit
+ # state through epsilon edges and w/o leaving rule.
+ for i in range(0, numCtxs): # for each stack context
+ returnStateNumber = config.context.getReturnState(i)
+ returnState = self.atn.states[returnStateNumber]
+ # all states must have single outgoing epsilon edge
+ if len(returnState.transitions) != 1 or not returnState.transitions[0].isEpsilon:
+ return False
+
+ # Look for prefix op case like 'not expr', (' type ')' expr
+ returnStateTarget = returnState.transitions[0].target
+ if returnState.stateType == ATNState.BLOCK_END and returnStateTarget is p:
+ continue
+
+ # Look for 'expr op expr' or case where expr's return state is block end
+ # of (...)* internal block; the block end points to loop back
+ # which points to p but we don't need to check that
+ if returnState is blockEndState:
+ continue
+
+ # Look for ternary expr ? expr : expr. The return state points at block end,
+ # which points at loop entry state
+ if returnStateTarget is blockEndState:
+ continue
+
+ # Look for complex prefix 'between expr and expr' case where 2nd expr's
+ # return state points at block end state of (...)* internal block
+ if returnStateTarget.stateType == ATNState.BLOCK_END \
+ and len(returnStateTarget.transitions) == 1 \
+ and returnStateTarget.transitions[0].isEpsilon \
+ and returnStateTarget.transitions[0].target is p:
+ continue
+
+ # anything else ain't conforming
+ return False
+
+ return True
+
+
+ def getRuleName(self, index:int):
+ if self.parser is not None and index>=0:
+ return self.parser.ruleNames[index]
+ else:
+ return ""
+
+ epsilonTargetMethods = dict()
+ epsilonTargetMethods[Transition.RULE] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \
+ sim.ruleTransition(config, t)
+ epsilonTargetMethods[Transition.PRECEDENCE] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \
+ sim.precedenceTransition(config, t, collectPredicates, inContext, fullCtx)
+ epsilonTargetMethods[Transition.PREDICATE] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \
+ sim.predTransition(config, t, collectPredicates, inContext, fullCtx)
+ epsilonTargetMethods[Transition.ACTION] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \
+ sim.actionTransition(config, t)
+ epsilonTargetMethods[Transition.EPSILON] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \
+ ATNConfig(state=t.target, config=config)
+ epsilonTargetMethods[Transition.ATOM] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \
+ ATNConfig(state=t.target, config=config) if treatEofAsEpsilon and t.matches(Token.EOF, 0, 1) else None
+ epsilonTargetMethods[Transition.RANGE] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \
+ ATNConfig(state=t.target, config=config) if treatEofAsEpsilon and t.matches(Token.EOF, 0, 1) else None
+ epsilonTargetMethods[Transition.SET] = lambda sim, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon: \
+ ATNConfig(state=t.target, config=config) if treatEofAsEpsilon and t.matches(Token.EOF, 0, 1) else None
+
+ def getEpsilonTarget(self, config:ATNConfig, t:Transition, collectPredicates:bool, inContext:bool, fullCtx:bool, treatEofAsEpsilon:bool):
+ m = self.epsilonTargetMethods.get(t.serializationType, None)
+ if m is None:
+ return None
+ else:
+ return m(self, config, t, collectPredicates, inContext, fullCtx, treatEofAsEpsilon)
+
+ def actionTransition(self, config:ATNConfig, t:ActionTransition):
+ if ParserATNSimulator.debug:
+ print("ACTION edge " + str(t.ruleIndex) + ":" + str(t.actionIndex))
+ return ATNConfig(state=t.target, config=config)
+
+ def precedenceTransition(self, config:ATNConfig, pt:PrecedencePredicateTransition, collectPredicates:bool, inContext:bool, fullCtx:bool):
+ if ParserATNSimulator.debug:
+ print("PRED (collectPredicates=" + str(collectPredicates) + ") " +
+ str(pt.precedence) + ">=_p, ctx dependent=true")
+ if self.parser is not None:
+ print("context surrounding pred is " + str(self.parser.getRuleInvocationStack()))
+
+ c = None
+ if collectPredicates and inContext:
+ if fullCtx:
+ # In full context mode, we can evaluate predicates on-the-fly
+ # during closure, which dramatically reduces the size of
+ # the config sets. It also obviates the need to test predicates
+ # later during conflict resolution.
+ currentPosition = self._input.index
+ self._input.seek(self._startIndex)
+ predSucceeds = pt.getPredicate().eval(self.parser, self._outerContext)
+ self._input.seek(currentPosition)
+ if predSucceeds:
+ c = ATNConfig(state=pt.target, config=config) # no pred context
+ else:
+ newSemCtx = andContext(config.semanticContext, pt.getPredicate())
+ c = ATNConfig(state=pt.target, semantic=newSemCtx, config=config)
+ else:
+ c = ATNConfig(state=pt.target, config=config)
+
+ if ParserATNSimulator.debug:
+ print("config from pred transition=" + str(c))
+ return c
+
+ def predTransition(self, config:ATNConfig, pt:PredicateTransition, collectPredicates:bool, inContext:bool, fullCtx:bool):
+ if ParserATNSimulator.debug:
+ print("PRED (collectPredicates=" + str(collectPredicates) + ") " + str(pt.ruleIndex) +
+ ":" + str(pt.predIndex) + ", ctx dependent=" + str(pt.isCtxDependent))
+ if self.parser is not None:
+ print("context surrounding pred is " + str(self.parser.getRuleInvocationStack()))
+
+ c = None
+ if collectPredicates and (not pt.isCtxDependent or (pt.isCtxDependent and inContext)):
+ if fullCtx:
+ # In full context mode, we can evaluate predicates on-the-fly
+ # during closure, which dramatically reduces the size of
+ # the config sets. It also obviates the need to test predicates
+ # later during conflict resolution.
+ currentPosition = self._input.index
+ self._input.seek(self._startIndex)
+ predSucceeds = pt.getPredicate().eval(self.parser, self._outerContext)
+ self._input.seek(currentPosition)
+ if predSucceeds:
+ c = ATNConfig(state=pt.target, config=config) # no pred context
+ else:
+ newSemCtx = andContext(config.semanticContext, pt.getPredicate())
+ c = ATNConfig(state=pt.target, semantic=newSemCtx, config=config)
+ else:
+ c = ATNConfig(state=pt.target, config=config)
+
+ if ParserATNSimulator.debug:
+ print("config from pred transition=" + str(c))
+ return c
+
+ def ruleTransition(self, config:ATNConfig, t:RuleTransition):
+ if ParserATNSimulator.debug:
+ print("CALL rule " + self.getRuleName(t.target.ruleIndex) + ", ctx=" + str(config.context))
+ returnState = t.followState
+ newContext = SingletonPredictionContext.create(config.context, returnState.stateNumber)
+ return ATNConfig(state=t.target, context=newContext, config=config )
+
+ def getConflictingAlts(self, configs:ATNConfigSet):
+ altsets = PredictionMode.getConflictingAltSubsets(configs)
+ return PredictionMode.getAlts(altsets)
+
+ # Sam pointed out a problem with the previous definition, v3, of
+ # ambiguous states. If we have another state associated with conflicting
+ # alternatives, we should keep going. For example, the following grammar
+ #
+ # s : (ID | ID ID?) ';' ;
+ #
+ # When the ATN simulation reaches the state before ';', it has a DFA
+ # state that looks like: [12|1|[], 6|2|[], 12|2|[]]. Naturally
+ # 12|1|[] and 12|2|[] conflict, but we cannot stop processing this node
+ # because alternative to has another way to continue, via [6|2|[]].
+ # The key is that we have a single state that has config's only associated
+ # with a single alternative, 2, and crucially the state transitions
+ # among the configurations are all non-epsilon transitions. That means
+ # we don't consider any conflicts that include alternative 2. So, we
+ # ignore the conflict between alts 1 and 2. We ignore a set of
+ # conflicting alts when there is an intersection with an alternative
+ # associated with a single alt state in the state→config-list map.
+ #
+ # It's also the case that we might have two conflicting configurations but
+ # also a 3rd nonconflicting configuration for a different alternative:
+ # [1|1|[], 1|2|[], 8|3|[]]. This can come about from grammar:
+ #
+ # a : A | A | A B ;
+ #
+ # After matching input A, we reach the stop state for rule A, state 1.
+ # State 8 is the state right before B. Clearly alternatives 1 and 2
+ # conflict and no amount of further lookahead will separate the two.
+ # However, alternative 3 will be able to continue and so we do not
+ # stop working on this state. In the previous example, we're concerned
+ # with states associated with the conflicting alternatives. Here alt
+ # 3 is not associated with the conflicting configs, but since we can continue
+ # looking for input reasonably, I don't declare the state done. We
+ # ignore a set of conflicting alts when we have an alternative
+ # that we still need to pursue.
+ #
+
+ def getConflictingAltsOrUniqueAlt(self, configs:ATNConfigSet):
+ conflictingAlts = None
+ if configs.uniqueAlt!= ATN.INVALID_ALT_NUMBER:
+ conflictingAlts = set()
+ conflictingAlts.add(configs.uniqueAlt)
+ else:
+ conflictingAlts = configs.conflictingAlts
+ return conflictingAlts
+
+ def getTokenName(self, t:int):
+ if t==Token.EOF:
+ return "EOF"
+ if self.parser is not None and \
+ self.parser.literalNames is not None and \
+ t < len(self.parser.literalNames):
+ return self.parser.literalNames[t] + "<" + str(t) + ">"
+ if self.parser is not None and \
+ self.parser.symbolicNames is not None and \
+ t < len(self.parser.symbolicNames):
+ return self.parser.symbolicNames[t] + "<" + str(t) + ">"
+ else:
+ return str(t)
+
+ def getLookaheadName(self, input:TokenStream):
+ return self.getTokenName(input.LA(1))
+
+ # Used for debugging in adaptivePredict around execATN but I cut
+ # it out for clarity now that alg. works well. We can leave this
+ # "dead" code for a bit.
+ #
+ def dumpDeadEndConfigs(self, nvae:NoViableAltException):
+ print("dead end configs: ")
+ for c in nvae.getDeadEndConfigs():
+ trans = "no edges"
+ if len(c.state.transitions)>0:
+ t = c.state.transitions[0]
+ if isinstance(t, AtomTransition):
+ trans = "Atom "+ self.getTokenName(t.label)
+ elif isinstance(t, SetTransition):
+ neg = isinstance(t, NotSetTransition)
+ trans = ("~" if neg else "")+"Set "+ str(t.set)
+ print(c.toString(self.parser, True) + ":" + trans, file=sys.stderr)
+
+ def noViableAlt(self, input:TokenStream, outerContext:ParserRuleContext, configs:ATNConfigSet, startIndex:int):
+ return NoViableAltException(self.parser, input, input.get(startIndex), input.LT(1), configs, outerContext)
+
+ def getUniqueAlt(self, configs:ATNConfigSet):
+ alt = ATN.INVALID_ALT_NUMBER
+ for c in configs:
+ if alt == ATN.INVALID_ALT_NUMBER:
+ alt = c.alt # found first alt
+ elif c.alt!=alt:
+ return ATN.INVALID_ALT_NUMBER
+ return alt
+
+ #
+ # Add an edge to the DFA, if possible. This method calls
+ # {@link #addDFAState} to ensure the {@code to} state is present in the
+ # DFA. If {@code from} is {@code null}, or if {@code t} is outside the
+ # range of edges that can be represented in the DFA tables, this method
+ # returns without adding the edge to the DFA.
+ #
+ #
If {@code to} is {@code null}, this method returns {@code null}.
+ # Otherwise, this method returns the {@link DFAState} returned by calling
+ # {@link #addDFAState} for the {@code to} state.
+ #
+ # @param dfa The DFA
+ # @param from The source state for the edge
+ # @param t The input symbol
+ # @param to The target state for the edge
+ #
+ # @return If {@code to} is {@code null}, this method returns {@code null};
+ # otherwise this method returns the result of calling {@link #addDFAState}
+ # on {@code to}
+ #
+ def addDFAEdge(self, dfa:DFA, from_:DFAState, t:int, to:DFAState):
+ if ParserATNSimulator.debug:
+ print("EDGE " + str(from_) + " -> " + str(to) + " upon " + self.getTokenName(t))
+
+ if to is None:
+ return None
+
+ to = self.addDFAState(dfa, to) # used existing if possible not incoming
+ if from_ is None or t < -1 or t > self.atn.maxTokenType:
+ return to
+
+ if from_.edges is None:
+ from_.edges = [None] * (self.atn.maxTokenType + 2)
+ from_.edges[t+1] = to # connect
+
+ if ParserATNSimulator.debug:
+ names = None if self.parser is None else self.parser.literalNames
+ print("DFA=\n" + dfa.toString(names))
+
+ return to
+
+ #
+ # Add state {@code D} to the DFA if it is not already present, and return
+ # the actual instance stored in the DFA. If a state equivalent to {@code D}
+ # is already in the DFA, the existing state is returned. Otherwise this
+ # method returns {@code D} after adding it to the DFA.
+ #
+ #
If {@code D} is {@link #ERROR}, this method returns {@link #ERROR} and
+ # does not change the DFA.
+ #
+ # @param dfa The dfa
+ # @param D The DFA state to add
+ # @return The state stored in the DFA. This will be either the existing
+ # state if {@code D} is already in the DFA, or {@code D} itself if the
+ # state was not already present.
+ #
+ def addDFAState(self, dfa:DFA, D:DFAState):
+ if D is self.ERROR:
+ return D
+
+
+ existing = dfa.states.get(D, None)
+ if existing is not None:
+ if ParserATNSimulator.trace_atn_sim: print("addDFAState", str(D), "exists")
+ return existing
+
+ D.stateNumber = len(dfa.states)
+ if not D.configs.readonly:
+ D.configs.optimizeConfigs(self)
+ D.configs.setReadonly(True)
+
+ if ParserATNSimulator.trace_atn_sim: print("addDFAState new", str(D))
+
+ dfa.states[D] = D
+ return D
+
+ def reportAttemptingFullContext(self, dfa:DFA, conflictingAlts:set, configs:ATNConfigSet, startIndex:int, stopIndex:int):
+ if ParserATNSimulator.debug or ParserATNSimulator.retry_debug:
+ print("reportAttemptingFullContext decision=" + str(dfa.decision) + ":" + str(configs) +
+ ", input=" + self.parser.getTokenStream().getText(startIndex, stopIndex))
+ if self.parser is not None:
+ self.parser.getErrorListenerDispatch().reportAttemptingFullContext(self.parser, dfa, startIndex, stopIndex, conflictingAlts, configs)
+
+ def reportContextSensitivity(self, dfa:DFA, prediction:int, configs:ATNConfigSet, startIndex:int, stopIndex:int):
+ if ParserATNSimulator.debug or ParserATNSimulator.retry_debug:
+ print("reportContextSensitivity decision=" + str(dfa.decision) + ":" + str(configs) +
+ ", input=" + self.parser.getTokenStream().getText(startIndex, stopIndex))
+ if self.parser is not None:
+ self.parser.getErrorListenerDispatch().reportContextSensitivity(self.parser, dfa, startIndex, stopIndex, prediction, configs)
+
+ # If context sensitive parsing, we know it's ambiguity not conflict#
+ def reportAmbiguity(self, dfa:DFA, D:DFAState, startIndex:int, stopIndex:int,
+ exact:bool, ambigAlts:set, configs:ATNConfigSet ):
+ if ParserATNSimulator.debug or ParserATNSimulator.retry_debug:
+# ParserATNPathFinder finder = new ParserATNPathFinder(parser, atn);
+# int i = 1;
+# for (Transition t : dfa.atnStartState.transitions) {
+# print("ALT "+i+"=");
+# print(startIndex+".."+stopIndex+", len(input)="+parser.getInputStream().size());
+# TraceTree path = finder.trace(t.target, parser.getContext(), (TokenStream)parser.getInputStream(),
+# startIndex, stopIndex);
+# if ( path!=null ) {
+# print("path = "+path.toStringTree());
+# for (TraceTree leaf : path.leaves) {
+# List states = path.getPathToNode(leaf);
+# print("states="+states);
+# }
+# }
+# i++;
+# }
+ print("reportAmbiguity " + str(ambigAlts) + ":" + str(configs) +
+ ", input=" + self.parser.getTokenStream().getText(startIndex, stopIndex))
+ if self.parser is not None:
+ self.parser.getErrorListenerDispatch().reportAmbiguity(self.parser, dfa, startIndex, stopIndex, exact, ambigAlts, configs)
diff --git a/venv/Lib/site-packages/antlr4/atn/PredictionMode.py b/venv/Lib/site-packages/antlr4/atn/PredictionMode.py
new file mode 100644
index 0000000000000000000000000000000000000000..8e5c73bb47f329d519f4e574ba3a36fc6c4ac29f
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/PredictionMode.py
@@ -0,0 +1,499 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+#
+# This enumeration defines the prediction modes available in ANTLR 4 along with
+# utility methods for analyzing configuration sets for conflicts and/or
+# ambiguities.
+
+
+from enum import Enum
+from antlr4.atn.ATN import ATN
+from antlr4.atn.ATNConfig import ATNConfig
+from antlr4.atn.ATNConfigSet import ATNConfigSet
+from antlr4.atn.ATNState import RuleStopState
+from antlr4.atn.SemanticContext import SemanticContext
+
+PredictionMode = None
+
+class PredictionMode(Enum):
+ #
+ # The SLL(*) prediction mode. This prediction mode ignores the current
+ # parser context when making predictions. This is the fastest prediction
+ # mode, and provides correct results for many grammars. This prediction
+ # mode is more powerful than the prediction mode provided by ANTLR 3, but
+ # may result in syntax errors for grammar and input combinations which are
+ # not SLL.
+ #
+ #
+ # When using this prediction mode, the parser will either return a correct
+ # parse tree (i.e. the same parse tree that would be returned with the
+ # {@link #LL} prediction mode), or it will report a syntax error. If a
+ # syntax error is encountered when using the {@link #SLL} prediction mode,
+ # it may be due to either an actual syntax error in the input or indicate
+ # that the particular combination of grammar and input requires the more
+ # powerful {@link #LL} prediction abilities to complete successfully.
+ #
+ #
+ # This prediction mode does not provide any guarantees for prediction
+ # behavior for syntactically-incorrect inputs.
+ #
+ SLL = 0
+ #
+ # The LL(*) prediction mode. This prediction mode allows the current parser
+ # context to be used for resolving SLL conflicts that occur during
+ # prediction. This is the fastest prediction mode that guarantees correct
+ # parse results for all combinations of grammars with syntactically correct
+ # inputs.
+ #
+ #
+ # When using this prediction mode, the parser will make correct decisions
+ # for all syntactically-correct grammar and input combinations. However, in
+ # cases where the grammar is truly ambiguous this prediction mode might not
+ # report a precise answer for exactly which alternatives are
+ # ambiguous.
+ #
+ #
+ # This prediction mode does not provide any guarantees for prediction
+ # behavior for syntactically-incorrect inputs.
+ #
+ LL = 1
+ #
+ # The LL(*) prediction mode with exact ambiguity detection. In addition to
+ # the correctness guarantees provided by the {@link #LL} prediction mode,
+ # this prediction mode instructs the prediction algorithm to determine the
+ # complete and exact set of ambiguous alternatives for every ambiguous
+ # decision encountered while parsing.
+ #
+ #
+ # This prediction mode may be used for diagnosing ambiguities during
+ # grammar development. Due to the performance overhead of calculating sets
+ # of ambiguous alternatives, this prediction mode should be avoided when
+ # the exact results are not necessary.
+ #
+ #
+ # This prediction mode does not provide any guarantees for prediction
+ # behavior for syntactically-incorrect inputs.
+ # This method computes the SLL prediction termination condition for both of
+ # the following cases.
+ #
+ #
+ #
The usual SLL+LL fallback upon SLL conflict
+ #
Pure SLL without LL fallback
+ #
+ #
+ #
COMBINED SLL+LL PARSING
+ #
+ #
When LL-fallback is enabled upon SLL conflict, correct predictions are
+ # ensured regardless of how the termination condition is computed by this
+ # method. Due to the substantially higher cost of LL prediction, the
+ # prediction should only fall back to LL when the additional lookahead
+ # cannot lead to a unique SLL prediction.
+ #
+ #
Assuming combined SLL+LL parsing, an SLL configuration set with only
+ # conflicting subsets should fall back to full LL, even if the
+ # configuration sets don't resolve to the same alternative (e.g.
+ # {@code {1,2}} and {@code {3,4}}. If there is at least one non-conflicting
+ # configuration, SLL could continue with the hopes that more lookahead will
+ # resolve via one of those non-conflicting configurations.
+ #
+ #
Here's the prediction termination rule them: SLL (for SLL+LL parsing)
+ # stops when it sees only conflicting configuration subsets. In contrast,
+ # full LL keeps going when there is uncertainty.
+ #
+ #
HEURISTIC
+ #
+ #
As a heuristic, we stop prediction when we see any conflicting subset
+ # unless we see a state that only has one alternative associated with it.
+ # The single-alt-state thing lets prediction continue upon rules like
+ # (otherwise, it would admit defeat too soon):
+ #
+ #
{@code [12|1|[], 6|2|[], 12|2|[]]. s : (ID | ID ID?) ';' ;}
+ #
+ #
When the ATN simulation reaches the state before {@code ';'}, it has a
+ # DFA state that looks like: {@code [12|1|[], 6|2|[], 12|2|[]]}. Naturally
+ # {@code 12|1|[]} and {@code 12|2|[]} conflict, but we cannot stop
+ # processing this node because alternative to has another way to continue,
+ # via {@code [6|2|[]]}.
+ #
+ #
It also let's us continue for this rule:
+ #
+ #
{@code [1|1|[], 1|2|[], 8|3|[]] a : A | A | A B ;}
+ #
+ #
After matching input A, we reach the stop state for rule A, state 1.
+ # State 8 is the state right before B. Clearly alternatives 1 and 2
+ # conflict and no amount of further lookahead will separate the two.
+ # However, alternative 3 will be able to continue and so we do not stop
+ # working on this state. In the previous example, we're concerned with
+ # states associated with the conflicting alternatives. Here alt 3 is not
+ # associated with the conflicting configs, but since we can continue
+ # looking for input reasonably, don't declare the state done.
+ #
+ #
PURE SLL PARSING
+ #
+ #
To handle pure SLL parsing, all we have to do is make sure that we
+ # combine stack contexts for configurations that differ only by semantic
+ # predicate. From there, we can do the usual SLL termination heuristic.
+ #
+ #
PREDICATES IN SLL+LL PARSING
+ #
+ #
SLL decisions don't evaluate predicates until after they reach DFA stop
+ # states because they need to create the DFA cache that works in all
+ # semantic situations. In contrast, full LL evaluates predicates collected
+ # during start state computation so it can ignore predicates thereafter.
+ # This means that SLL termination detection can totally ignore semantic
+ # predicates.
+ #
+ #
Implementation-wise, {@link ATNConfigSet} combines stack contexts but not
+ # semantic predicate contexts so we might see two configurations like the
+ # following.
+ #
+ #
{@code (s, 1, x, {}), (s, 1, x', {p})}
+ #
+ #
Before testing these configurations against others, we have to merge
+ # {@code x} and {@code x'} (without modifying the existing configurations).
+ # For example, we test {@code (x+x')==x''} when looking for conflicts in
+ # the following configurations.
If the configuration set has predicates (as indicated by
+ # {@link ATNConfigSet#hasSemanticContext}), this algorithm makes a copy of
+ # the configurations to strip out all of the predicates so that a standard
+ # {@link ATNConfigSet} will merge everything ignoring predicates.
+ #
+ @classmethod
+ def hasSLLConflictTerminatingPrediction(cls, mode:PredictionMode, configs:ATNConfigSet):
+ # Configs in rule stop states indicate reaching the end of the decision
+ # rule (local context) or end of start rule (full context). If all
+ # configs meet this condition, then none of the configurations is able
+ # to match additional input so we terminate prediction.
+ #
+ if cls.allConfigsInRuleStopStates(configs):
+ return True
+
+ # pure SLL mode parsing
+ if mode == PredictionMode.SLL:
+ # Don't bother with combining configs from different semantic
+ # contexts if we can fail over to full LL; costs more time
+ # since we'll often fail over anyway.
+ if configs.hasSemanticContext:
+ # dup configs, tossing out semantic predicates
+ dup = ATNConfigSet()
+ for c in configs:
+ c = ATNConfig(config=c, semantic=SemanticContext.NONE)
+ dup.add(c)
+ configs = dup
+ # now we have combined contexts for configs with dissimilar preds
+
+ # pure SLL or combined SLL+LL mode parsing
+ altsets = cls.getConflictingAltSubsets(configs)
+ return cls.hasConflictingAltSet(altsets) and not cls.hasStateAssociatedWithOneAlt(configs)
+
+ # Checks if any configuration in {@code configs} is in a
+ # {@link RuleStopState}. Configurations meeting this condition have reached
+ # the end of the decision rule (local context) or end of start rule (full
+ # context).
+ #
+ # @param configs the configuration set to test
+ # @return {@code true} if any configuration in {@code configs} is in a
+ # {@link RuleStopState}, otherwise {@code false}
+ @classmethod
+ def hasConfigInRuleStopState(cls, configs:ATNConfigSet):
+ return any(isinstance(cfg.state, RuleStopState) for cfg in configs)
+
+ # Checks if all configurations in {@code configs} are in a
+ # {@link RuleStopState}. Configurations meeting this condition have reached
+ # the end of the decision rule (local context) or end of start rule (full
+ # context).
+ #
+ # @param configs the configuration set to test
+ # @return {@code true} if all configurations in {@code configs} are in a
+ # {@link RuleStopState}, otherwise {@code false}
+ @classmethod
+ def allConfigsInRuleStopStates(cls, configs:ATNConfigSet):
+ return all(isinstance(cfg.state, RuleStopState) for cfg in configs)
+
+ #
+ # Full LL prediction termination.
+ #
+ #
Can we stop looking ahead during ATN simulation or is there some
+ # uncertainty as to which alternative we will ultimately pick, after
+ # consuming more input? Even if there are partial conflicts, we might know
+ # that everything is going to resolve to the same minimum alternative. That
+ # means we can stop since no more lookahead will change that fact. On the
+ # other hand, there might be multiple conflicts that resolve to different
+ # minimums. That means we need more look ahead to decide which of those
+ # alternatives we should predict.
+ #
+ #
The basic idea is to split the set of configurations {@code C}, into
+ # conflicting subsets {@code (s, _, ctx, _)} and singleton subsets with
+ # non-conflicting configurations. Two configurations conflict if they have
+ # identical {@link ATNConfig#state} and {@link ATNConfig#context} values
+ # but different {@link ATNConfig#alt} value, e.g. {@code (s, i, ctx, _)}
+ # and {@code (s, j, ctx, _)} for {@code i!=j}.
+ #
+ #
Reduce these configuration subsets to the set of possible alternatives.
+ # You can compute the alternative subsets in one pass as follows:
+ #
+ #
{@code A_s,ctx = {i | (s, i, ctx, _)}} for each configuration in
+ # {@code C} holding {@code s} and {@code ctx} fixed.
+ #
+ #
Or in pseudo-code, for each configuration {@code c} in {@code C}:
+ #
+ #
+ # map[c] U= c.{@link ATNConfig#alt alt} # map hash/equals uses s and x, not
+ # alt and not pred
+ #
+ #
+ #
The values in {@code map} are the set of {@code A_s,ctx} sets.
+ #
+ #
If {@code |A_s,ctx|=1} then there is no conflict associated with
+ # {@code s} and {@code ctx}.
+ #
+ #
Reduce the subsets to singletons by choosing a minimum of each subset. If
+ # the union of these alternative subsets is a singleton, then no amount of
+ # more lookahead will help us. We will always pick that alternative. If,
+ # however, there is more than one alternative, then we are uncertain which
+ # alternative to predict and must continue looking for resolution. We may
+ # or may not discover an ambiguity in the future, even if there are no
+ # conflicting subsets this round.
+ #
+ #
The biggest sin is to terminate early because it means we've made a
+ # decision but were uncertain as to the eventual outcome. We haven't used
+ # enough lookahead. On the other hand, announcing a conflict too late is no
+ # big deal; you will still have the conflict. It's just inefficient. It
+ # might even look until the end of file.
+ #
+ #
No special consideration for semantic predicates is required because
+ # predicates are evaluated on-the-fly for full LL prediction, ensuring that
+ # no configuration contains a semantic context during the termination
+ # check.
+ #
+ #
CONFLICTING CONFIGS
+ #
+ #
Two configurations {@code (s, i, x)} and {@code (s, j, x')}, conflict
+ # when {@code i!=j} but {@code x=x'}. Because we merge all
+ # {@code (s, i, _)} configurations together, that means that there are at
+ # most {@code n} configurations associated with state {@code s} for
+ # {@code n} possible alternatives in the decision. The merged stacks
+ # complicate the comparison of configuration contexts {@code x} and
+ # {@code x'}. Sam checks to see if one is a subset of the other by calling
+ # merge and checking to see if the merged result is either {@code x} or
+ # {@code x'}. If the {@code x} associated with lowest alternative {@code i}
+ # is the superset, then {@code i} is the only possible prediction since the
+ # others resolve to {@code min(i)} as well. However, if {@code x} is
+ # associated with {@code j>i} then at least one stack configuration for
+ # {@code j} is not in conflict with alternative {@code i}. The algorithm
+ # should keep going, looking for more lookahead due to the uncertainty.
+ #
+ #
For simplicity, I'm doing a equality check between {@code x} and
+ # {@code x'} that lets the algorithm continue to consume lookahead longer
+ # than necessary. The reason I like the equality is of course the
+ # simplicity but also because that is the test you need to detect the
+ # alternatives that are actually in conflict.
+ #
+ #
CONTINUE/STOP RULE
+ #
+ #
Continue if union of resolved alternative sets from non-conflicting and
+ # conflicting alternative subsets has more than one alternative. We are
+ # uncertain about which alternative to predict.
+ #
+ #
The complete set of alternatives, {@code [i for (_,i,_)]}, tells us which
+ # alternatives are still in the running for the amount of input we've
+ # consumed at this point. The conflicting sets let us to strip away
+ # configurations that won't lead to more states because we resolve
+ # conflicts to the configuration with a minimum alternate for the
+ # conflicting set.
+ #
+ #
CASES
+ #
+ #
+ #
+ #
no conflicts and more than 1 alternative in set => continue
If all states report the same conflicting set of alternatives, then we
+ # know we have the exact ambiguity set.
+ #
+ #
|A_i|>1 and
+ # A_i = A_j for all i, j.
+ #
+ #
In other words, we continue examining lookahead until all {@code A_i}
+ # have more than one alternative and all {@code A_i} are the same. If
+ # {@code A={{1,2}, {1,3}}}, then regular LL prediction would terminate
+ # because the resolved set is {@code {1}}. To determine what the real
+ # ambiguity is, we have to know whether the ambiguity is between one and
+ # two or one and three so we keep going. We can only stop prediction when
+ # we need exact ambiguity detection when the sets look like
+ # {@code A={{1,2}}} or {@code {{1,2},{1,2}}}, etc...
+ #
+ @classmethod
+ def resolvesToJustOneViableAlt(cls, altsets:list):
+ return cls.getSingleViableAlt(altsets)
+
+ #
+ # Determines if every alternative subset in {@code altsets} contains more
+ # than one alternative.
+ #
+ # @param altsets a collection of alternative subsets
+ # @return {@code true} if every {@link BitSet} in {@code altsets} has
+ # {@link BitSet#cardinality cardinality} > 1, otherwise {@code false}
+ #
+ @classmethod
+ def allSubsetsConflict(cls, altsets:list):
+ return not cls.hasNonConflictingAltSet(altsets)
+
+ #
+ # Determines if any single alternative subset in {@code altsets} contains
+ # exactly one alternative.
+ #
+ # @param altsets a collection of alternative subsets
+ # @return {@code true} if {@code altsets} contains a {@link BitSet} with
+ # {@link BitSet#cardinality cardinality} 1, otherwise {@code false}
+ #
+ @classmethod
+ def hasNonConflictingAltSet(cls, altsets:list):
+ return any(len(alts) == 1 for alts in altsets)
+
+ #
+ # Determines if any single alternative subset in {@code altsets} contains
+ # more than one alternative.
+ #
+ # @param altsets a collection of alternative subsets
+ # @return {@code true} if {@code altsets} contains a {@link BitSet} with
+ # {@link BitSet#cardinality cardinality} > 1, otherwise {@code false}
+ #
+ @classmethod
+ def hasConflictingAltSet(cls, altsets:list):
+ return any(len(alts) > 1 for alts in altsets)
+
+ #
+ # Determines if every alternative subset in {@code altsets} is equivalent.
+ #
+ # @param altsets a collection of alternative subsets
+ # @return {@code true} if every member of {@code altsets} is equal to the
+ # others, otherwise {@code false}
+ #
+ @classmethod
+ def allSubsetsEqual(cls, altsets:list):
+ if not altsets:
+ return True
+ first = next(iter(altsets))
+ return all(alts == first for alts in iter(altsets))
+
+ #
+ # Returns the unique alternative predicted by all alternative subsets in
+ # {@code altsets}. If no such alternative exists, this method returns
+ # {@link ATN#INVALID_ALT_NUMBER}.
+ #
+ # @param altsets a collection of alternative subsets
+ #
+ @classmethod
+ def getUniqueAlt(cls, altsets:list):
+ all = cls.getAlts(altsets)
+ if len(all)==1:
+ return next(iter(all))
+ return ATN.INVALID_ALT_NUMBER
+
+ # Gets the complete set of represented alternatives for a collection of
+ # alternative subsets. This method returns the union of each {@link BitSet}
+ # in {@code altsets}.
+ #
+ # @param altsets a collection of alternative subsets
+ # @return the set of represented alternatives in {@code altsets}
+ #
+ @classmethod
+ def getAlts(cls, altsets:list):
+ return set.union(*altsets)
+
+ #
+ # This function gets the conflicting alt subsets from a configuration set.
+ # For each configuration {@code c} in {@code configs}:
+ #
+ #
+ # map[c] U= c.{@link ATNConfig#alt alt} # map hash/equals uses s and x, not
+ # alt and not pred
+ #
+ #
+ @classmethod
+ def getConflictingAltSubsets(cls, configs:ATNConfigSet):
+ configToAlts = dict()
+ for c in configs:
+ h = hash((c.state.stateNumber, c.context))
+ alts = configToAlts.get(h, None)
+ if alts is None:
+ alts = set()
+ configToAlts[h] = alts
+ alts.add(c.alt)
+ return configToAlts.values()
+
+ #
+ # Get a map from state to alt subset from a configuration set. For each
+ # configuration {@code c} in {@code configs}:
+ #
+ #
+ #
+ @classmethod
+ def getStateToAltMap(cls, configs:ATNConfigSet):
+ m = dict()
+ for c in configs:
+ alts = m.get(c.state, None)
+ if alts is None:
+ alts = set()
+ m[c.state] = alts
+ alts.add(c.alt)
+ return m
+
+ @classmethod
+ def hasStateAssociatedWithOneAlt(cls, configs:ATNConfigSet):
+ return any(len(alts) == 1 for alts in cls.getStateToAltMap(configs).values())
+
+ @classmethod
+ def getSingleViableAlt(cls, altsets:list):
+ viableAlts = set()
+ for alts in altsets:
+ minAlt = min(alts)
+ viableAlts.add(minAlt)
+ if len(viableAlts)>1 : # more than 1 viable alt
+ return ATN.INVALID_ALT_NUMBER
+ return min(viableAlts)
diff --git a/venv/Lib/site-packages/antlr4/atn/SemanticContext.py b/venv/Lib/site-packages/antlr4/atn/SemanticContext.py
new file mode 100644
index 0000000000000000000000000000000000000000..3f33a18010673f447e5fa25c949503c7629e3cab
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/SemanticContext.py
@@ -0,0 +1,330 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+# A tree structure used to record the semantic context in which
+# an ATN configuration is valid. It's either a single predicate,
+# a conjunction {@code p1&&p2}, or a sum of products {@code p1||p2}.
+#
+#
I have scoped the {@link AND}, {@link OR}, and {@link Predicate} subclasses of
+# {@link SemanticContext} within the scope of this outer class.
+#
+from antlr4.Recognizer import Recognizer
+from antlr4.RuleContext import RuleContext
+from io import StringIO
+
+
+class SemanticContext(object):
+ #
+ # The default {@link SemanticContext}, which is semantically equivalent to
+ # a predicate of the form {@code {true}?}.
+ #
+ NONE = None
+
+ #
+ # For context independent predicates, we evaluate them without a local
+ # context (i.e., null context). That way, we can evaluate them without
+ # having to create proper rule-specific context during prediction (as
+ # opposed to the parser, which creates them naturally). In a practical
+ # sense, this avoids a cast exception from RuleContext to myruleContext.
+ #
+ #
For context dependent predicates, we must pass in a local context so that
+ # references such as $arg evaluate properly as _localctx.arg. We only
+ # capture context dependent predicates in the context in which we begin
+ # prediction, so we passed in the outer context here in case of context
+ # dependent predicate evaluation.
+ #
+ def eval(self, parser:Recognizer , outerContext:RuleContext ):
+ pass
+
+ #
+ # Evaluate the precedence predicates for the context and reduce the result.
+ #
+ # @param parser The parser instance.
+ # @param outerContext The current parser context object.
+ # @return The simplified semantic context after precedence predicates are
+ # evaluated, which will be one of the following values.
+ #
+ #
{@link #NONE}: if the predicate simplifies to {@code true} after
+ # precedence predicates are evaluated.
+ #
{@code null}: if the predicate simplifies to {@code false} after
+ # precedence predicates are evaluated.
+ #
{@code this}: if the semantic context is not changed as a result of
+ # precedence predicate evaluation.
+ #
A non-{@code null} {@link SemanticContext}: the new simplified
+ # semantic context after precedence predicates are evaluated.
+ #
+ #
+ def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext):
+ return self
+
+# need forward declaration
+AND = None
+
+def andContext(a:SemanticContext, b:SemanticContext):
+ if a is None or a is SemanticContext.NONE:
+ return b
+ if b is None or b is SemanticContext.NONE:
+ return a
+ result = AND(a, b)
+ if len(result.opnds) == 1:
+ return result.opnds[0]
+ else:
+ return result
+
+# need forward declaration
+OR = None
+
+def orContext(a:SemanticContext, b:SemanticContext):
+ if a is None:
+ return b
+ if b is None:
+ return a
+ if a is SemanticContext.NONE or b is SemanticContext.NONE:
+ return SemanticContext.NONE
+ result = OR(a, b)
+ if len(result.opnds) == 1:
+ return result.opnds[0]
+ else:
+ return result
+
+def filterPrecedencePredicates(collection:set):
+ return [context for context in collection if isinstance(context, PrecedencePredicate)]
+
+
+class EmptySemanticContext(SemanticContext):
+ pass
+
+class Predicate(SemanticContext):
+ __slots__ = ('ruleIndex', 'predIndex', 'isCtxDependent')
+
+ def __init__(self, ruleIndex:int=-1, predIndex:int=-1, isCtxDependent:bool=False):
+ self.ruleIndex = ruleIndex
+ self.predIndex = predIndex
+ self.isCtxDependent = isCtxDependent # e.g., $i ref in pred
+
+ def eval(self, parser:Recognizer , outerContext:RuleContext ):
+ localctx = outerContext if self.isCtxDependent else None
+ return parser.sempred(localctx, self.ruleIndex, self.predIndex)
+
+ def __hash__(self):
+ return hash((self.ruleIndex, self.predIndex, self.isCtxDependent))
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, Predicate):
+ return False
+ return self.ruleIndex == other.ruleIndex and \
+ self.predIndex == other.predIndex and \
+ self.isCtxDependent == other.isCtxDependent
+
+ def __str__(self):
+ return "{" + str(self.ruleIndex) + ":" + str(self.predIndex) + "}?"
+
+
+class PrecedencePredicate(SemanticContext):
+
+ def __init__(self, precedence:int=0):
+ self.precedence = precedence
+
+ def eval(self, parser:Recognizer , outerContext:RuleContext ):
+ return parser.precpred(outerContext, self.precedence)
+
+ def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext):
+ if parser.precpred(outerContext, self.precedence):
+ return SemanticContext.NONE
+ else:
+ return None
+
+ def __lt__(self, other):
+ return self.precedence < other.precedence
+
+ def __hash__(self):
+ return 31
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, PrecedencePredicate):
+ return False
+ else:
+ return self.precedence == other.precedence
+
+ def __str__(self):
+ return "{" + str(self.precedence) + ">=prec}?"
+
+
+# A semantic context which is true whenever none of the contained contexts
+# is false.
+del AND
+class AND(SemanticContext):
+ __slots__ = 'opnds'
+
+ def __init__(self, a:SemanticContext, b:SemanticContext):
+ operands = set()
+ if isinstance( a, AND ):
+ operands.update(a.opnds)
+ else:
+ operands.add(a)
+ if isinstance( b, AND ):
+ operands.update(b.opnds)
+ else:
+ operands.add(b)
+
+ precedencePredicates = filterPrecedencePredicates(operands)
+ if len(precedencePredicates)>0:
+ # interested in the transition with the lowest precedence
+ reduced = min(precedencePredicates)
+ operands.add(reduced)
+
+ self.opnds = list(operands)
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, AND):
+ return False
+ else:
+ return self.opnds == other.opnds
+
+ def __hash__(self):
+ h = 0
+ for o in self.opnds:
+ h = hash((h, o))
+ return hash((h, "AND"))
+
+ #
+ # {@inheritDoc}
+ #
+ #
+ # The evaluation of predicates by this context is short-circuiting, but
+ # unordered.
+ #
+ def eval(self, parser:Recognizer, outerContext:RuleContext):
+ return all(opnd.eval(parser, outerContext) for opnd in self.opnds)
+
+ def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext):
+ differs = False
+ operands = []
+ for context in self.opnds:
+ evaluated = context.evalPrecedence(parser, outerContext)
+ differs |= evaluated is not context
+ if evaluated is None:
+ # The AND context is false if any element is false
+ return None
+ elif evaluated is not SemanticContext.NONE:
+ # Reduce the result by skipping true elements
+ operands.append(evaluated)
+
+ if not differs:
+ return self
+
+ if len(operands)==0:
+ # all elements were true, so the AND context is true
+ return SemanticContext.NONE
+
+ result = None
+ for o in operands:
+ result = o if result is None else andContext(result, o)
+
+ return result
+
+ def __str__(self):
+ with StringIO() as buf:
+ first = True
+ for o in self.opnds:
+ if not first:
+ buf.write("&&")
+ buf.write(str(o))
+ first = False
+ return buf.getvalue()
+
+#
+# A semantic context which is true whenever at least one of the contained
+# contexts is true.
+del OR
+class OR (SemanticContext):
+ __slots__ = 'opnds'
+
+ def __init__(self, a:SemanticContext, b:SemanticContext):
+ operands = set()
+ if isinstance( a, OR ):
+ operands.update(a.opnds)
+ else:
+ operands.add(a)
+ if isinstance( b, OR ):
+ operands.update(b.opnds)
+ else:
+ operands.add(b)
+
+ precedencePredicates = filterPrecedencePredicates(operands)
+ if len(precedencePredicates)>0:
+ # interested in the transition with the highest precedence
+ s = sorted(precedencePredicates)
+ reduced = s[-1]
+ operands.add(reduced)
+
+ self.opnds = list(operands)
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ elif not isinstance(other, OR):
+ return False
+ else:
+ return self.opnds == other.opnds
+
+ def __hash__(self):
+ h = 0
+ for o in self.opnds:
+ h = hash((h, o))
+ return hash((h, "OR"))
+
+ #
+ # The evaluation of predicates by this context is short-circuiting, but
+ # unordered.
+ #
+ def eval(self, parser:Recognizer, outerContext:RuleContext):
+ return any(opnd.eval(parser, outerContext) for opnd in self.opnds)
+
+ def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext):
+ differs = False
+ operands = []
+ for context in self.opnds:
+ evaluated = context.evalPrecedence(parser, outerContext)
+ differs |= evaluated is not context
+ if evaluated is SemanticContext.NONE:
+ # The OR context is true if any element is true
+ return SemanticContext.NONE
+ elif evaluated is not None:
+ # Reduce the result by skipping false elements
+ operands.append(evaluated)
+
+ if not differs:
+ return self
+
+ if len(operands)==0:
+ # all elements were false, so the OR context is false
+ return None
+
+ result = None
+ for o in operands:
+ result = o if result is None else orContext(result, o)
+
+ return result
+
+ def __str__(self):
+ with StringIO() as buf:
+ first = True
+ for o in self.opnds:
+ if not first:
+ buf.write("||")
+ buf.write(str(o))
+ first = False
+ return buf.getvalue()
+
+
+SemanticContext.NONE = EmptySemanticContext()
diff --git a/venv/Lib/site-packages/antlr4/atn/Transition.py b/venv/Lib/site-packages/antlr4/atn/Transition.py
new file mode 100644
index 0000000000000000000000000000000000000000..2e4c9971763c34dbb2690660434c5c99d44193e1
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/Transition.py
@@ -0,0 +1,268 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+# An ATN transition between any two ATN states. Subclasses define
+# atom, set, epsilon, action, predicate, rule transitions.
+#
+#
This is a one way link. It emanates from a state (usually via a list of
+# transitions) and has a target state.
+#
+#
Since we never have to change the ATN transitions once we construct it,
+# we can fix these transitions as specific classes. The DFA transitions
+# on the other hand need to update the labels as it adds transitions to
+# the states. We'll use the term Edge for the DFA to distinguish them from
+# ATN transitions.
+#
+from antlr4.IntervalSet import IntervalSet
+from antlr4.Token import Token
+
+# need forward declarations
+from antlr4.atn.SemanticContext import Predicate, PrecedencePredicate
+
+ATNState = None
+RuleStartState = None
+
+class Transition (object):
+ __slots__ = ('target','isEpsilon','label')
+
+ # constants for serialization
+ EPSILON = 1
+ RANGE = 2
+ RULE = 3
+ PREDICATE = 4 # e.g., {isType(input.LT(1))}?
+ ATOM = 5
+ ACTION = 6
+ SET = 7 # ~(A|B) or ~atom, wildcard, which convert to next 2
+ NOT_SET = 8
+ WILDCARD = 9
+ PRECEDENCE = 10
+
+ serializationNames = [
+ "INVALID",
+ "EPSILON",
+ "RANGE",
+ "RULE",
+ "PREDICATE",
+ "ATOM",
+ "ACTION",
+ "SET",
+ "NOT_SET",
+ "WILDCARD",
+ "PRECEDENCE"
+ ]
+
+ serializationTypes = dict()
+
+ def __init__(self, target:ATNState):
+ # The target of this transition.
+ if target is None:
+ raise Exception("target cannot be null.")
+ self.target = target
+ # Are we epsilon, action, sempred?
+ self.isEpsilon = False
+ self.label = None
+
+
+# TODO: make all transitions sets? no, should remove set edges
+class AtomTransition(Transition):
+ __slots__ = ('label_', 'serializationType')
+
+ def __init__(self, target:ATNState, label:int):
+ super().__init__(target)
+ self.label_ = label # The token type or character value; or, signifies special label.
+ self.label = self.makeLabel()
+ self.serializationType = self.ATOM
+
+ def makeLabel(self):
+ s = IntervalSet()
+ s.addOne(self.label_)
+ return s
+
+ def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int):
+ return self.label_ == symbol
+
+ def __str__(self):
+ return str(self.label_)
+
+class RuleTransition(Transition):
+ __slots__ = ('ruleIndex', 'precedence', 'followState', 'serializationType')
+
+ def __init__(self, ruleStart:RuleStartState, ruleIndex:int, precedence:int, followState:ATNState):
+ super().__init__(ruleStart)
+ self.ruleIndex = ruleIndex # ptr to the rule definition object for this rule ref
+ self.precedence = precedence
+ self.followState = followState # what node to begin computations following ref to rule
+ self.serializationType = self.RULE
+ self.isEpsilon = True
+
+ def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int):
+ return False
+
+
+class EpsilonTransition(Transition):
+ __slots__ = ('serializationType', 'outermostPrecedenceReturn')
+
+ def __init__(self, target, outermostPrecedenceReturn=-1):
+ super(EpsilonTransition, self).__init__(target)
+ self.serializationType = self.EPSILON
+ self.isEpsilon = True
+ self.outermostPrecedenceReturn = outermostPrecedenceReturn
+
+ def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int):
+ return False
+
+ def __str__(self):
+ return "epsilon"
+
+class RangeTransition(Transition):
+ __slots__ = ('serializationType', 'start', 'stop')
+
+ def __init__(self, target:ATNState, start:int, stop:int):
+ super().__init__(target)
+ self.serializationType = self.RANGE
+ self.start = start
+ self.stop = stop
+ self.label = self.makeLabel()
+
+ def makeLabel(self):
+ s = IntervalSet()
+ s.addRange(range(self.start, self.stop + 1))
+ return s
+
+ def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int):
+ return symbol >= self.start and symbol <= self.stop
+
+ def __str__(self):
+ return "'" + chr(self.start) + "'..'" + chr(self.stop) + "'"
+
+class AbstractPredicateTransition(Transition):
+
+ def __init__(self, target:ATNState):
+ super().__init__(target)
+
+
+class PredicateTransition(AbstractPredicateTransition):
+ __slots__ = ('serializationType', 'ruleIndex', 'predIndex', 'isCtxDependent')
+
+ def __init__(self, target:ATNState, ruleIndex:int, predIndex:int, isCtxDependent:bool):
+ super().__init__(target)
+ self.serializationType = self.PREDICATE
+ self.ruleIndex = ruleIndex
+ self.predIndex = predIndex
+ self.isCtxDependent = isCtxDependent # e.g., $i ref in pred
+ self.isEpsilon = True
+
+ def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int):
+ return False
+
+ def getPredicate(self):
+ return Predicate(self.ruleIndex, self.predIndex, self.isCtxDependent)
+
+ def __str__(self):
+ return "pred_" + str(self.ruleIndex) + ":" + str(self.predIndex)
+
+class ActionTransition(Transition):
+ __slots__ = ('serializationType', 'ruleIndex', 'actionIndex', 'isCtxDependent')
+
+ def __init__(self, target:ATNState, ruleIndex:int, actionIndex:int=-1, isCtxDependent:bool=False):
+ super().__init__(target)
+ self.serializationType = self.ACTION
+ self.ruleIndex = ruleIndex
+ self.actionIndex = actionIndex
+ self.isCtxDependent = isCtxDependent # e.g., $i ref in pred
+ self.isEpsilon = True
+
+ def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int):
+ return False
+
+ def __str__(self):
+ return "action_"+self.ruleIndex+":"+self.actionIndex
+
+# A transition containing a set of values.
+class SetTransition(Transition):
+ __slots__ = 'serializationType'
+
+ def __init__(self, target:ATNState, set:IntervalSet):
+ super().__init__(target)
+ self.serializationType = self.SET
+ if set is not None:
+ self.label = set
+ else:
+ self.label = IntervalSet()
+ self.label.addRange(range(Token.INVALID_TYPE, Token.INVALID_TYPE + 1))
+
+ def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int):
+ return symbol in self.label
+
+ def __str__(self):
+ return str(self.label)
+
+class NotSetTransition(SetTransition):
+
+ def __init__(self, target:ATNState, set:IntervalSet):
+ super().__init__(target, set)
+ self.serializationType = self.NOT_SET
+
+ def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int):
+ return symbol >= minVocabSymbol \
+ and symbol <= maxVocabSymbol \
+ and not super(type(self), self).matches(symbol, minVocabSymbol, maxVocabSymbol)
+
+ def __str__(self):
+ return '~' + super(type(self), self).__str__()
+
+
+class WildcardTransition(Transition):
+ __slots__ = 'serializationType'
+
+ def __init__(self, target:ATNState):
+ super().__init__(target)
+ self.serializationType = self.WILDCARD
+
+ def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int):
+ return symbol >= minVocabSymbol and symbol <= maxVocabSymbol
+
+ def __str__(self):
+ return "."
+
+
+class PrecedencePredicateTransition(AbstractPredicateTransition):
+ __slots__ = ('serializationType', 'precedence')
+
+ def __init__(self, target:ATNState, precedence:int):
+ super().__init__(target)
+ self.serializationType = self.PRECEDENCE
+ self.precedence = precedence
+ self.isEpsilon = True
+
+ def matches( self, symbol:int, minVocabSymbol:int, maxVocabSymbol:int):
+ return False
+
+
+ def getPredicate(self):
+ return PrecedencePredicate(self.precedence)
+
+ def __str__(self):
+ return self.precedence + " >= _p"
+
+
+Transition.serializationTypes = {
+ EpsilonTransition: Transition.EPSILON,
+ RangeTransition: Transition.RANGE,
+ RuleTransition: Transition.RULE,
+ PredicateTransition: Transition.PREDICATE,
+ AtomTransition: Transition.ATOM,
+ ActionTransition: Transition.ACTION,
+ SetTransition: Transition.SET,
+ NotSetTransition: Transition.NOT_SET,
+ WildcardTransition: Transition.WILDCARD,
+ PrecedencePredicateTransition: Transition.PRECEDENCE
+ }
+
+del ATNState
+del RuleStartState
+
+from antlr4.atn.ATNState import *
diff --git a/venv/Lib/site-packages/antlr4/atn/__init__.py b/venv/Lib/site-packages/antlr4/atn/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..216c000dc5ffc8e53cc9c596e420c1e67604d1aa
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/atn/__init__.py
@@ -0,0 +1 @@
+__author__ = 'ericvergnaud'
diff --git a/venv/Lib/site-packages/antlr4/dfa/DFA.py b/venv/Lib/site-packages/antlr4/dfa/DFA.py
new file mode 100644
index 0000000000000000000000000000000000000000..d80589a6834a48cc6bb718bf33f57156e32ec934
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/dfa/DFA.py
@@ -0,0 +1,133 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+from antlr4.atn.ATNState import StarLoopEntryState
+
+from antlr4.atn.ATNConfigSet import ATNConfigSet
+from antlr4.atn.ATNState import DecisionState
+from antlr4.dfa.DFAState import DFAState
+from antlr4.error.Errors import IllegalStateException
+
+
+class DFA(object):
+ __slots__ = ('atnStartState', 'decision', '_states', 's0', 'precedenceDfa')
+
+ def __init__(self, atnStartState:DecisionState, decision:int=0):
+ # From which ATN state did we create this DFA?
+ self.atnStartState = atnStartState
+ self.decision = decision
+ # A set of all DFA states. Use {@link Map} so we can get old state back
+ # ({@link Set} only allows you to see if it's there).
+ self._states = dict()
+ self.s0 = None
+ # {@code true} if this DFA is for a precedence decision; otherwise,
+ # {@code false}. This is the backing field for {@link #isPrecedenceDfa},
+ # {@link #setPrecedenceDfa}.
+ self.precedenceDfa = False
+
+ if isinstance(atnStartState, StarLoopEntryState):
+ if atnStartState.isPrecedenceDecision:
+ self.precedenceDfa = True
+ precedenceState = DFAState(configs=ATNConfigSet())
+ precedenceState.edges = []
+ precedenceState.isAcceptState = False
+ precedenceState.requiresFullContext = False
+ self.s0 = precedenceState
+
+
+ # Get the start state for a specific precedence value.
+ #
+ # @param precedence The current precedence.
+ # @return The start state corresponding to the specified precedence, or
+ # {@code null} if no start state exists for the specified precedence.
+ #
+ # @throws IllegalStateException if this is not a precedence DFA.
+ # @see #isPrecedenceDfa()
+
+ def getPrecedenceStartState(self, precedence:int):
+ if not self.precedenceDfa:
+ raise IllegalStateException("Only precedence DFAs may contain a precedence start state.")
+
+ # s0.edges is never null for a precedence DFA
+ if precedence < 0 or precedence >= len(self.s0.edges):
+ return None
+ return self.s0.edges[precedence]
+
+ # Set the start state for a specific precedence value.
+ #
+ # @param precedence The current precedence.
+ # @param startState The start state corresponding to the specified
+ # precedence.
+ #
+ # @throws IllegalStateException if this is not a precedence DFA.
+ # @see #isPrecedenceDfa()
+ #
+ def setPrecedenceStartState(self, precedence:int, startState:DFAState):
+ if not self.precedenceDfa:
+ raise IllegalStateException("Only precedence DFAs may contain a precedence start state.")
+
+ if precedence < 0:
+ return
+
+ # synchronization on s0 here is ok. when the DFA is turned into a
+ # precedence DFA, s0 will be initialized once and not updated again
+ # s0.edges is never null for a precedence DFA
+ if precedence >= len(self.s0.edges):
+ ext = [None] * (precedence + 1 - len(self.s0.edges))
+ self.s0.edges.extend(ext)
+ self.s0.edges[precedence] = startState
+ #
+ # Sets whether this is a precedence DFA. If the specified value differs
+ # from the current DFA configuration, the following actions are taken;
+ # otherwise no changes are made to the current DFA.
+ #
+ #
+ #
The {@link #states} map is cleared
+ #
If {@code precedenceDfa} is {@code false}, the initial state
+ # {@link #s0} is set to {@code null}; otherwise, it is initialized to a new
+ # {@link DFAState} with an empty outgoing {@link DFAState#edges} array to
+ # store the start states for individual precedence values.
+ #
The {@link #precedenceDfa} field is updated
+ #
+ #
+ # @param precedenceDfa {@code true} if this is a precedence DFA; otherwise,
+ # {@code false}
+
+ def setPrecedenceDfa(self, precedenceDfa:bool):
+ if self.precedenceDfa != precedenceDfa:
+ self._states = dict()
+ if precedenceDfa:
+ precedenceState = DFAState(configs=ATNConfigSet())
+ precedenceState.edges = []
+ precedenceState.isAcceptState = False
+ precedenceState.requiresFullContext = False
+ self.s0 = precedenceState
+ else:
+ self.s0 = None
+ self.precedenceDfa = precedenceDfa
+
+ @property
+ def states(self):
+ return self._states
+
+ # Return a list of all states in this DFA, ordered by state number.
+ def sortedStates(self):
+ return sorted(self._states.keys(), key=lambda state: state.stateNumber)
+
+ def __str__(self):
+ return self.toString(None)
+
+ def toString(self, literalNames:list=None, symbolicNames:list=None):
+ if self.s0 is None:
+ return ""
+ from antlr4.dfa.DFASerializer import DFASerializer
+ serializer = DFASerializer(self,literalNames,symbolicNames)
+ return str(serializer)
+
+ def toLexerString(self):
+ if self.s0 is None:
+ return ""
+ from antlr4.dfa.DFASerializer import LexerDFASerializer
+ serializer = LexerDFASerializer(self)
+ return str(serializer)
diff --git a/venv/Lib/site-packages/antlr4/dfa/DFASerializer.py b/venv/Lib/site-packages/antlr4/dfa/DFASerializer.py
new file mode 100644
index 0000000000000000000000000000000000000000..bca0727b76dc54909be0bf60b6d636ec8f539927
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/dfa/DFASerializer.py
@@ -0,0 +1,73 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+
+# A DFA walker that knows how to dump them to serialized strings.#/
+from io import StringIO
+from antlr4 import DFA
+from antlr4.Utils import str_list
+from antlr4.dfa.DFAState import DFAState
+
+
+class DFASerializer(object):
+ __slots__ = ('dfa', 'literalNames', 'symbolicNames')
+
+ def __init__(self, dfa:DFA, literalNames:list=None, symbolicNames:list=None):
+ self.dfa = dfa
+ self.literalNames = literalNames
+ self.symbolicNames = symbolicNames
+
+ def __str__(self):
+ if self.dfa.s0 is None:
+ return None
+ with StringIO() as buf:
+ for s in self.dfa.sortedStates():
+ n = 0
+ if s.edges is not None:
+ n = len(s.edges)
+ for i in range(0, n):
+ t = s.edges[i]
+ if t is not None and t.stateNumber != 0x7FFFFFFF:
+ buf.write(self.getStateString(s))
+ label = self.getEdgeLabel(i)
+ buf.write("-")
+ buf.write(label)
+ buf.write("->")
+ buf.write(self.getStateString(t))
+ buf.write('\n')
+ output = buf.getvalue()
+ if len(output)==0:
+ return None
+ else:
+ return output
+
+ def getEdgeLabel(self, i:int):
+ if i==0:
+ return "EOF"
+ if self.literalNames is not None and i<=len(self.literalNames):
+ return self.literalNames[i-1]
+ elif self.symbolicNames is not None and i<=len(self.symbolicNames):
+ return self.symbolicNames[i-1]
+ else:
+ return str(i-1)
+
+ def getStateString(self, s:DFAState):
+ n = s.stateNumber
+ baseStateStr = ( ":" if s.isAcceptState else "") + "s" + str(n) + ( "^" if s.requiresFullContext else "")
+ if s.isAcceptState:
+ if s.predicates is not None:
+ return baseStateStr + "=>" + str_list(s.predicates)
+ else:
+ return baseStateStr + "=>" + str(s.prediction)
+ else:
+ return baseStateStr
+
+class LexerDFASerializer(DFASerializer):
+
+ def __init__(self, dfa:DFA):
+ super().__init__(dfa, None)
+
+ def getEdgeLabel(self, i:int):
+ return "'" + chr(i) + "'"
diff --git a/venv/Lib/site-packages/antlr4/dfa/DFAState.py b/venv/Lib/site-packages/antlr4/dfa/DFAState.py
new file mode 100644
index 0000000000000000000000000000000000000000..51955a448886ea1fa34f0f4dff7fb0976edd1975
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/dfa/DFAState.py
@@ -0,0 +1,126 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+
+# Map a predicate to a predicted alternative.#/
+from io import StringIO
+from antlr4.atn.ATNConfigSet import ATNConfigSet
+from antlr4.atn.SemanticContext import SemanticContext
+
+
+class PredPrediction(object):
+ __slots__ = ('alt', 'pred')
+
+ def __init__(self, pred:SemanticContext, alt:int):
+ self.alt = alt
+ self.pred = pred
+
+ def __str__(self):
+ return "(" + str(self.pred) + ", " + str(self.alt) + ")"
+
+# A DFA state represents a set of possible ATN configurations.
+# As Aho, Sethi, Ullman p. 117 says "The DFA uses its state
+# to keep track of all possible states the ATN can be in after
+# reading each input symbol. That is to say, after reading
+# input a1a2..an, the DFA is in a state that represents the
+# subset T of the states of the ATN that are reachable from the
+# ATN's start state along some path labeled a1a2..an."
+# In conventional NFA→DFA conversion, therefore, the subset T
+# would be a bitset representing the set of states the
+# ATN could be in. We need to track the alt predicted by each
+# state as well, however. More importantly, we need to maintain
+# a stack of states, tracking the closure operations as they
+# jump from rule to rule, emulating rule invocations (method calls).
+# I have to add a stack to simulate the proper lookahead sequences for
+# the underlying LL grammar from which the ATN was derived.
+#
+#
I use a set of ATNConfig objects not simple states. An ATNConfig
+# is both a state (ala normal conversion) and a RuleContext describing
+# the chain of rules (if any) followed to arrive at that state.
+#
+#
A DFA state may have multiple references to a particular state,
+# but with different ATN contexts (with same or different alts)
+# meaning that state was reached via a different set of rule invocations.
+#/
+class DFAState(object):
+ __slots__ = (
+ 'stateNumber', 'configs', 'edges', 'isAcceptState', 'prediction',
+ 'lexerActionExecutor', 'requiresFullContext', 'predicates'
+ )
+
+ def __init__(self, stateNumber:int=-1, configs:ATNConfigSet=ATNConfigSet()):
+ self.stateNumber = stateNumber
+ self.configs = configs
+ # {@code edges[symbol]} points to target of symbol. Shift up by 1 so (-1)
+ # {@link Token#EOF} maps to {@code edges[0]}.
+ self.edges = None
+ self.isAcceptState = False
+ # if accept state, what ttype do we match or alt do we predict?
+ # This is set to {@link ATN#INVALID_ALT_NUMBER} when {@link #predicates}{@code !=null} or
+ # {@link #requiresFullContext}.
+ self.prediction = 0
+ self.lexerActionExecutor = None
+ # Indicates that this state was created during SLL prediction that
+ # discovered a conflict between the configurations in the state. Future
+ # {@link ParserATNSimulator#execATN} invocations immediately jumped doing
+ # full context prediction if this field is true.
+ self.requiresFullContext = False
+ # During SLL parsing, this is a list of predicates associated with the
+ # ATN configurations of the DFA state. When we have predicates,
+ # {@link #requiresFullContext} is {@code false} since full context prediction evaluates predicates
+ # on-the-fly. If this is not null, then {@link #prediction} is
+ # {@link ATN#INVALID_ALT_NUMBER}.
+ #
+ #
We only use these for non-{@link #requiresFullContext} but conflicting states. That
+ # means we know from the context (it's $ or we don't dip into outer
+ # context) that it's an ambiguity not a conflict.
+ #
+ #
This list is computed by {@link ParserATNSimulator#predicateDFAState}.
+ self.predicates = None
+
+
+
+ # Get the set of all alts mentioned by all ATN configurations in this
+ # DFA state.
+ def getAltSet(self):
+ if self.configs is not None:
+ return set(cfg.alt for cfg in self.configs) or None
+ return None
+
+ def __hash__(self):
+ return hash(self.configs)
+
+ # Two {@link DFAState} instances are equal if their ATN configuration sets
+ # are the same. This method is used to see if a state already exists.
+ #
+ #
Because the number of alternatives and number of ATN configurations are
+ # finite, there is a finite number of DFA states that can be processed.
+ # This is necessary to show that the algorithm terminates.
+ #
+ #
Cannot test the DFA state numbers here because in
+ # {@link ParserATNSimulator#addDFAState} we need to know if any other state
+ # exists that has this exact set of ATN configurations. The
+ # {@link #stateNumber} is irrelevant.
+ def __eq__(self, other):
+ # compare set of ATN configurations in this set with other
+ if self is other:
+ return True
+ elif not isinstance(other, DFAState):
+ return False
+ else:
+ return self.configs==other.configs
+
+ def __str__(self):
+ with StringIO() as buf:
+ buf.write(str(self.stateNumber))
+ buf.write(":")
+ buf.write(str(self.configs))
+ if self.isAcceptState:
+ buf.write("=>")
+ if self.predicates is not None:
+ buf.write(str(self.predicates))
+ else:
+ buf.write(str(self.prediction))
+ return buf.getvalue()
diff --git a/venv/Lib/site-packages/antlr4/dfa/__init__.py b/venv/Lib/site-packages/antlr4/dfa/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..216c000dc5ffc8e53cc9c596e420c1e67604d1aa
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/dfa/__init__.py
@@ -0,0 +1 @@
+__author__ = 'ericvergnaud'
diff --git a/venv/Lib/site-packages/antlr4/error/DiagnosticErrorListener.py b/venv/Lib/site-packages/antlr4/error/DiagnosticErrorListener.py
new file mode 100644
index 0000000000000000000000000000000000000000..32ac14b63579ce7c984c2e34f2b1c80bebe328ed
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/error/DiagnosticErrorListener.py
@@ -0,0 +1,107 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+
+#
+# This implementation of {@link ANTLRErrorListener} can be used to identify
+# certain potential correctness and performance problems in grammars. "Reports"
+# are made by calling {@link Parser#notifyErrorListeners} with the appropriate
+# message.
+#
+#
+#
Ambiguities: These are cases where more than one path through the
+# grammar can match the input.
+#
Weak context sensitivity: These are cases where full-context
+# prediction resolved an SLL conflict to a unique alternative which equaled the
+# minimum alternative of the SLL conflict.
+#
Strong (forced) context sensitivity: These are cases where the
+# full-context prediction resolved an SLL conflict to a unique alternative,
+# and the minimum alternative of the SLL conflict was found to not be
+# a truly viable alternative. Two-stage parsing cannot be used for inputs where
+# this situation occurs.
+#
+
+from io import StringIO
+from antlr4 import Parser, DFA
+from antlr4.atn.ATNConfigSet import ATNConfigSet
+from antlr4.error.ErrorListener import ErrorListener
+
+class DiagnosticErrorListener(ErrorListener):
+
+ def __init__(self, exactOnly:bool=True):
+ # whether all ambiguities or only exact ambiguities are reported.
+ self.exactOnly = exactOnly
+
+ def reportAmbiguity(self, recognizer:Parser, dfa:DFA, startIndex:int,
+ stopIndex:int, exact:bool, ambigAlts:set, configs:ATNConfigSet):
+ if self.exactOnly and not exact:
+ return
+
+ with StringIO() as buf:
+ buf.write("reportAmbiguity d=")
+ buf.write(self.getDecisionDescription(recognizer, dfa))
+ buf.write(": ambigAlts=")
+ buf.write(str(self.getConflictingAlts(ambigAlts, configs)))
+ buf.write(", input='")
+ buf.write(recognizer.getTokenStream().getText(startIndex, stopIndex))
+ buf.write("'")
+ recognizer.notifyErrorListeners(buf.getvalue())
+
+
+ def reportAttemptingFullContext(self, recognizer:Parser, dfa:DFA, startIndex:int,
+ stopIndex:int, conflictingAlts:set, configs:ATNConfigSet):
+ with StringIO() as buf:
+ buf.write("reportAttemptingFullContext d=")
+ buf.write(self.getDecisionDescription(recognizer, dfa))
+ buf.write(", input='")
+ buf.write(recognizer.getTokenStream().getText(startIndex, stopIndex))
+ buf.write("'")
+ recognizer.notifyErrorListeners(buf.getvalue())
+
+ def reportContextSensitivity(self, recognizer:Parser, dfa:DFA, startIndex:int,
+ stopIndex:int, prediction:int, configs:ATNConfigSet):
+ with StringIO() as buf:
+ buf.write("reportContextSensitivity d=")
+ buf.write(self.getDecisionDescription(recognizer, dfa))
+ buf.write(", input='")
+ buf.write(recognizer.getTokenStream().getText(startIndex, stopIndex))
+ buf.write("'")
+ recognizer.notifyErrorListeners(buf.getvalue())
+
+ def getDecisionDescription(self, recognizer:Parser, dfa:DFA):
+ decision = dfa.decision
+ ruleIndex = dfa.atnStartState.ruleIndex
+
+ ruleNames = recognizer.ruleNames
+ if ruleIndex < 0 or ruleIndex >= len(ruleNames):
+ return str(decision)
+
+ ruleName = ruleNames[ruleIndex]
+ if ruleName is None or len(ruleName)==0:
+ return str(decision)
+
+ return str(decision) + " (" + ruleName + ")"
+
+ #
+ # Computes the set of conflicting or ambiguous alternatives from a
+ # configuration set, if that information was not already provided by the
+ # parser.
+ #
+ # @param reportedAlts The set of conflicting or ambiguous alternatives, as
+ # reported by the parser.
+ # @param configs The conflicting or ambiguous configuration set.
+ # @return Returns {@code reportedAlts} if it is not {@code null}, otherwise
+ # returns the set of alternatives represented in {@code configs}.
+ #
+ def getConflictingAlts(self, reportedAlts:set, configs:ATNConfigSet):
+ if reportedAlts is not None:
+ return reportedAlts
+
+ result = set()
+ for config in configs:
+ result.add(config.alt)
+
+ return result
diff --git a/venv/Lib/site-packages/antlr4/error/ErrorListener.py b/venv/Lib/site-packages/antlr4/error/ErrorListener.py
new file mode 100644
index 0000000000000000000000000000000000000000..933264d431b9829f43a38d5f0f07c83bbad703a0
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/error/ErrorListener.py
@@ -0,0 +1,72 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+
+# Provides an empty default implementation of {@link ANTLRErrorListener}. The
+# default implementation of each method does nothing, but can be overridden as
+# necessary.
+
+
+import sys
+
+class ErrorListener(object):
+
+ def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
+ pass
+
+ def reportAmbiguity(self, recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs):
+ pass
+
+ def reportAttemptingFullContext(self, recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs):
+ pass
+
+ def reportContextSensitivity(self, recognizer, dfa, startIndex, stopIndex, prediction, configs):
+ pass
+
+class ConsoleErrorListener(ErrorListener):
+ #
+ # Provides a default instance of {@link ConsoleErrorListener}.
+ #
+ INSTANCE = None
+
+ #
+ # {@inheritDoc}
+ #
+ #
+ # This implementation prints messages to {@link System#err} containing the
+ # values of {@code line}, {@code charPositionInLine}, and {@code msg} using
+ # the following format.
+ #
+ #
+ # line line:charPositionInLinemsg
+ #
+ #
+ def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
+ print("line " + str(line) + ":" + str(column) + " " + msg, file=sys.stderr)
+
+ConsoleErrorListener.INSTANCE = ConsoleErrorListener()
+
+class ProxyErrorListener(ErrorListener):
+
+ def __init__(self, delegates):
+ super().__init__()
+ if delegates is None:
+ raise ReferenceError("delegates")
+ self.delegates = delegates
+
+ def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
+ for delegate in self.delegates:
+ delegate.syntaxError(recognizer, offendingSymbol, line, column, msg, e)
+
+ def reportAmbiguity(self, recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs):
+ for delegate in self.delegates:
+ delegate.reportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs)
+
+ def reportAttemptingFullContext(self, recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs):
+ for delegate in self.delegates:
+ delegate.reportAttemptingFullContext(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs)
+
+ def reportContextSensitivity(self, recognizer, dfa, startIndex, stopIndex, prediction, configs):
+ for delegate in self.delegates:
+ delegate.reportContextSensitivity(recognizer, dfa, startIndex, stopIndex, prediction, configs)
diff --git a/venv/Lib/site-packages/antlr4/error/ErrorStrategy.py b/venv/Lib/site-packages/antlr4/error/ErrorStrategy.py
new file mode 100644
index 0000000000000000000000000000000000000000..0f7caadb240445e6d997ad582a51836f95cab5c5
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/error/ErrorStrategy.py
@@ -0,0 +1,709 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+import sys
+from antlr4.IntervalSet import IntervalSet
+
+from antlr4.Token import Token
+from antlr4.atn.ATNState import ATNState
+from antlr4.error.Errors import RecognitionException, NoViableAltException, InputMismatchException, \
+ FailedPredicateException, ParseCancellationException
+
+# need forward declaration
+Parser = None
+
+class ErrorStrategy(object):
+
+ def reset(self, recognizer:Parser):
+ pass
+
+ def recoverInline(self, recognizer:Parser):
+ pass
+
+ def recover(self, recognizer:Parser, e:RecognitionException):
+ pass
+
+ def sync(self, recognizer:Parser):
+ pass
+
+ def inErrorRecoveryMode(self, recognizer:Parser):
+ pass
+
+ def reportError(self, recognizer:Parser, e:RecognitionException):
+ pass
+
+
+# This is the default implementation of {@link ANTLRErrorStrategy} used for
+# error reporting and recovery in ANTLR parsers.
+#
+class DefaultErrorStrategy(ErrorStrategy):
+
+ def __init__(self):
+ super().__init__()
+ # Indicates whether the error strategy is currently "recovering from an
+ # error". This is used to suppress reporting multiple error messages while
+ # attempting to recover from a detected syntax error.
+ #
+ # @see #inErrorRecoveryMode
+ #
+ self.errorRecoveryMode = False
+
+ # The index into the input stream where the last error occurred.
+ # This is used to prevent infinite loops where an error is found
+ # but no token is consumed during recovery...another error is found,
+ # ad nauseum. This is a failsafe mechanism to guarantee that at least
+ # one token/tree node is consumed for two errors.
+ #
+ self.lastErrorIndex = -1
+ self.lastErrorStates = None
+ self.nextTokensContext = None
+ self.nextTokenState = 0
+
+ #
The default implementation simply calls {@link #endErrorCondition} to
+ # ensure that the handler is not in error recovery mode.
+ def reset(self, recognizer:Parser):
+ self.endErrorCondition(recognizer)
+
+ #
+ # This method is called to enter error recovery mode when a recognition
+ # exception is reported.
+ #
+ # @param recognizer the parser instance
+ #
+ def beginErrorCondition(self, recognizer:Parser):
+ self.errorRecoveryMode = True
+
+ def inErrorRecoveryMode(self, recognizer:Parser):
+ return self.errorRecoveryMode
+
+ #
+ # This method is called to leave error recovery mode after recovering from
+ # a recognition exception.
+ #
+ # @param recognizer
+ #
+ def endErrorCondition(self, recognizer:Parser):
+ self.errorRecoveryMode = False
+ self.lastErrorStates = None
+ self.lastErrorIndex = -1
+
+ #
+ # {@inheritDoc}
+ #
+ #
The default implementation simply calls {@link #endErrorCondition}.
The default implementation returns immediately if the handler is already
+ # in error recovery mode. Otherwise, it calls {@link #beginErrorCondition}
+ # and dispatches the reporting task based on the runtime type of {@code e}
+ # according to the following table.
+ #
+ #
+ #
{@link NoViableAltException}: Dispatches the call to
+ # {@link #reportNoViableAlternative}
+ #
{@link InputMismatchException}: Dispatches the call to
+ # {@link #reportInputMismatch}
+ #
{@link FailedPredicateException}: Dispatches the call to
+ # {@link #reportFailedPredicate}
+ #
All other types: calls {@link Parser#notifyErrorListeners} to report
+ # the exception
+ #
+ #
+ def reportError(self, recognizer:Parser, e:RecognitionException):
+ # if we've already reported an error and have not matched a token
+ # yet successfully, don't report any errors.
+ if self.inErrorRecoveryMode(recognizer):
+ return # don't report spurious errors
+ self.beginErrorCondition(recognizer)
+ if isinstance( e, NoViableAltException ):
+ self.reportNoViableAlternative(recognizer, e)
+ elif isinstance( e, InputMismatchException ):
+ self.reportInputMismatch(recognizer, e)
+ elif isinstance( e, FailedPredicateException ):
+ self.reportFailedPredicate(recognizer, e)
+ else:
+ print("unknown recognition error type: " + type(e).__name__)
+ recognizer.notifyErrorListeners(e.message, e.offendingToken, e)
+
+ #
+ # {@inheritDoc}
+ #
+ #
The default implementation resynchronizes the parser by consuming tokens
+ # until we find one in the resynchronization set--loosely the set of tokens
+ # that can follow the current rule.
+ #
+ def recover(self, recognizer:Parser, e:RecognitionException):
+ if self.lastErrorIndex==recognizer.getInputStream().index \
+ and self.lastErrorStates is not None \
+ and recognizer.state in self.lastErrorStates:
+ # uh oh, another error at same token index and previously-visited
+ # state in ATN; must be a case where LT(1) is in the recovery
+ # token set so nothing got consumed. Consume a single token
+ # at least to prevent an infinite loop; this is a failsafe.
+ recognizer.consume()
+
+ self.lastErrorIndex = recognizer._input.index
+ if self.lastErrorStates is None:
+ self.lastErrorStates = []
+ self.lastErrorStates.append(recognizer.state)
+ followSet = self.getErrorRecoverySet(recognizer)
+ self.consumeUntil(recognizer, followSet)
+
+ # The default implementation of {@link ANTLRErrorStrategy#sync} makes sure
+ # that the current lookahead symbol is consistent with what were expecting
+ # at this point in the ATN. You can call this anytime but ANTLR only
+ # generates code to check before subrules/loops and each iteration.
+ #
+ #
Implements Jim Idle's magic sync mechanism in closures and optional
+ # subrules. E.g.,
+ #
+ #
+ # a : sync ( stuff sync )* ;
+ # sync : {consume to what can follow sync} ;
+ #
+ #
+ # At the start of a sub rule upon error, {@link #sync} performs single
+ # token deletion, if possible. If it can't do that, it bails on the current
+ # rule and uses the default error recovery, which consumes until the
+ # resynchronization set of the current rule.
+ #
+ #
If the sub rule is optional ({@code (...)?}, {@code (...)*}, or block
+ # with an empty alternative), then the expected set includes what follows
+ # the subrule.
+ #
+ #
During loop iteration, it consumes until it sees a token that can start a
+ # sub rule or what follows loop. Yes, that is pretty aggressive. We opt to
+ # stay in the loop as long as possible.
+ #
+ #
ORIGINS
+ #
+ #
Previous versions of ANTLR did a poor job of their recovery within loops.
+ # A single mismatch token or missing token would force the parser to bail
+ # out of the entire rules surrounding the loop. So, for rule
+ #
+ #
+ # classDef : 'class' ID '{' member* '}'
+ #
+ #
+ # input with an extra token between members would force the parser to
+ # consume until it found the next class definition rather than the next
+ # member definition of the current class.
+ #
+ #
This functionality cost a little bit of effort because the parser has to
+ # compare token set at the start of the loop and at each iteration. If for
+ # some reason speed is suffering for you, you can turn off this
+ # functionality by simply overriding this method as a blank { }.
+ #
+ def sync(self, recognizer:Parser):
+ # If already recovering, don't try to sync
+ if self.inErrorRecoveryMode(recognizer):
+ return
+
+ s = recognizer._interp.atn.states[recognizer.state]
+ la = recognizer.getTokenStream().LA(1)
+ # try cheaper subset first; might get lucky. seems to shave a wee bit off
+ nextTokens = recognizer.atn.nextTokens(s)
+ if la in nextTokens:
+ self.nextTokensContext = None
+ self.nextTokenState = ATNState.INVALID_STATE_NUMBER
+ return
+ elif Token.EPSILON in nextTokens:
+ if self.nextTokensContext is None:
+ # It's possible the next token won't match information tracked
+ # by sync is restricted for performance.
+ self.nextTokensContext = recognizer._ctx
+ self.nextTokensState = recognizer._stateNumber
+ return
+
+ if s.stateType in [ATNState.BLOCK_START, ATNState.STAR_BLOCK_START,
+ ATNState.PLUS_BLOCK_START, ATNState.STAR_LOOP_ENTRY]:
+ # report error and recover if possible
+ if self.singleTokenDeletion(recognizer)is not None:
+ return
+ else:
+ raise InputMismatchException(recognizer)
+
+ elif s.stateType in [ATNState.PLUS_LOOP_BACK, ATNState.STAR_LOOP_BACK]:
+ self.reportUnwantedToken(recognizer)
+ expecting = recognizer.getExpectedTokens()
+ whatFollowsLoopIterationOrRule = expecting.addSet(self.getErrorRecoverySet(recognizer))
+ self.consumeUntil(recognizer, whatFollowsLoopIterationOrRule)
+
+ else:
+ # do nothing if we can't identify the exact kind of ATN state
+ pass
+
+ # This is called by {@link #reportError} when the exception is a
+ # {@link NoViableAltException}.
+ #
+ # @see #reportError
+ #
+ # @param recognizer the parser instance
+ # @param e the recognition exception
+ #
+ def reportNoViableAlternative(self, recognizer:Parser, e:NoViableAltException):
+ tokens = recognizer.getTokenStream()
+ if tokens is not None:
+ if e.startToken.type==Token.EOF:
+ input = ""
+ else:
+ input = tokens.getText(e.startToken, e.offendingToken)
+ else:
+ input = ""
+ msg = "no viable alternative at input " + self.escapeWSAndQuote(input)
+ recognizer.notifyErrorListeners(msg, e.offendingToken, e)
+
+ #
+ # This is called by {@link #reportError} when the exception is an
+ # {@link InputMismatchException}.
+ #
+ # @see #reportError
+ #
+ # @param recognizer the parser instance
+ # @param e the recognition exception
+ #
+ def reportInputMismatch(self, recognizer:Parser, e:InputMismatchException):
+ msg = "mismatched input " + self.getTokenErrorDisplay(e.offendingToken) \
+ + " expecting " + e.getExpectedTokens().toString(recognizer.literalNames, recognizer.symbolicNames)
+ recognizer.notifyErrorListeners(msg, e.offendingToken, e)
+
+ #
+ # This is called by {@link #reportError} when the exception is a
+ # {@link FailedPredicateException}.
+ #
+ # @see #reportError
+ #
+ # @param recognizer the parser instance
+ # @param e the recognition exception
+ #
+ def reportFailedPredicate(self, recognizer, e):
+ ruleName = recognizer.ruleNames[recognizer._ctx.getRuleIndex()]
+ msg = "rule " + ruleName + " " + e.message
+ recognizer.notifyErrorListeners(msg, e.offendingToken, e)
+
+ # This method is called to report a syntax error which requires the removal
+ # of a token from the input stream. At the time this method is called, the
+ # erroneous symbol is current {@code LT(1)} symbol and has not yet been
+ # removed from the input stream. When this method returns,
+ # {@code recognizer} is in error recovery mode.
+ #
+ #
This method is called when {@link #singleTokenDeletion} identifies
+ # single-token deletion as a viable recovery strategy for a mismatched
+ # input error.
+ #
+ #
The default implementation simply returns if the handler is already in
+ # error recovery mode. Otherwise, it calls {@link #beginErrorCondition} to
+ # enter error recovery mode, followed by calling
+ # {@link Parser#notifyErrorListeners}.
+ #
+ # @param recognizer the parser instance
+ #
+ def reportUnwantedToken(self, recognizer:Parser):
+ if self.inErrorRecoveryMode(recognizer):
+ return
+
+ self.beginErrorCondition(recognizer)
+ t = recognizer.getCurrentToken()
+ tokenName = self.getTokenErrorDisplay(t)
+ expecting = self.getExpectedTokens(recognizer)
+ msg = "extraneous input " + tokenName + " expecting " \
+ + expecting.toString(recognizer.literalNames, recognizer.symbolicNames)
+ recognizer.notifyErrorListeners(msg, t, None)
+
+ # This method is called to report a syntax error which requires the
+ # insertion of a missing token into the input stream. At the time this
+ # method is called, the missing token has not yet been inserted. When this
+ # method returns, {@code recognizer} is in error recovery mode.
+ #
+ #
This method is called when {@link #singleTokenInsertion} identifies
+ # single-token insertion as a viable recovery strategy for a mismatched
+ # input error.
+ #
+ #
The default implementation simply returns if the handler is already in
+ # error recovery mode. Otherwise, it calls {@link #beginErrorCondition} to
+ # enter error recovery mode, followed by calling
+ # {@link Parser#notifyErrorListeners}.
The default implementation attempts to recover from the mismatched input
+ # by using single token insertion and deletion as described below. If the
+ # recovery attempt fails, this method throws an
+ # {@link InputMismatchException}.
+ #
+ #
EXTRA TOKEN (single token deletion)
+ #
+ #
{@code LA(1)} is not what we are looking for. If {@code LA(2)} has the
+ # right token, however, then assume {@code LA(1)} is some extra spurious
+ # token and delete it. Then consume and return the next token (which was
+ # the {@code LA(2)} token) as the successful result of the match operation.
+ #
+ #
This recovery strategy is implemented by {@link #singleTokenDeletion}.
+ #
+ #
MISSING TOKEN (single token insertion)
+ #
+ #
If current token (at {@code LA(1)}) is consistent with what could come
+ # after the expected {@code LA(1)} token, then assume the token is missing
+ # and use the parser's {@link TokenFactory} to create it on the fly. The
+ # "insertion" is performed by returning the created token as the successful
+ # result of the match operation.
+ #
+ #
This recovery strategy is implemented by {@link #singleTokenInsertion}.
+ #
+ #
EXAMPLE
+ #
+ #
For example, Input {@code i=(3;} is clearly missing the {@code ')'}. When
+ # the parser returns from the nested call to {@code expr}, it will have
+ # call chain:
+ #
+ #
+ # stat → expr → atom
+ #
+ #
+ # and it will be trying to match the {@code ')'} at this point in the
+ # derivation:
+ #
+ #
+ # => ID '=' '(' INT ')' ('+' atom)* ';'
+ # ^
+ #
+ #
+ # The attempt to match {@code ')'} will fail when it sees {@code ';'} and
+ # call {@link #recoverInline}. To recover, it sees that {@code LA(1)==';'}
+ # is in the set of tokens that can follow the {@code ')'} token reference
+ # in rule {@code atom}. It can assume that you forgot the {@code ')'}.
+ #
+ def recoverInline(self, recognizer:Parser):
+ # SINGLE TOKEN DELETION
+ matchedSymbol = self.singleTokenDeletion(recognizer)
+ if matchedSymbol is not None:
+ # we have deleted the extra token.
+ # now, move past ttype token as if all were ok
+ recognizer.consume()
+ return matchedSymbol
+
+ # SINGLE TOKEN INSERTION
+ if self.singleTokenInsertion(recognizer):
+ return self.getMissingSymbol(recognizer)
+
+ # even that didn't work; must throw the exception
+ raise InputMismatchException(recognizer)
+
+ #
+ # This method implements the single-token insertion inline error recovery
+ # strategy. It is called by {@link #recoverInline} if the single-token
+ # deletion strategy fails to recover from the mismatched input. If this
+ # method returns {@code true}, {@code recognizer} will be in error recovery
+ # mode.
+ #
+ #
This method determines whether or not single-token insertion is viable by
+ # checking if the {@code LA(1)} input symbol could be successfully matched
+ # if it were instead the {@code LA(2)} symbol. If this method returns
+ # {@code true}, the caller is responsible for creating and inserting a
+ # token with the correct type to produce this behavior.
+ #
+ # @param recognizer the parser instance
+ # @return {@code true} if single-token insertion is a viable recovery
+ # strategy for the current mismatched input, otherwise {@code false}
+ #
+ def singleTokenInsertion(self, recognizer:Parser):
+ currentSymbolType = recognizer.getTokenStream().LA(1)
+ # if current token is consistent with what could come after current
+ # ATN state, then we know we're missing a token; error recovery
+ # is free to conjure up and insert the missing token
+ atn = recognizer._interp.atn
+ currentState = atn.states[recognizer.state]
+ next = currentState.transitions[0].target
+ expectingAtLL2 = atn.nextTokens(next, recognizer._ctx)
+ if currentSymbolType in expectingAtLL2:
+ self.reportMissingToken(recognizer)
+ return True
+ else:
+ return False
+
+ # This method implements the single-token deletion inline error recovery
+ # strategy. It is called by {@link #recoverInline} to attempt to recover
+ # from mismatched input. If this method returns null, the parser and error
+ # handler state will not have changed. If this method returns non-null,
+ # {@code recognizer} will not be in error recovery mode since the
+ # returned token was a successful match.
+ #
+ #
If the single-token deletion is successful, this method calls
+ # {@link #reportUnwantedToken} to report the error, followed by
+ # {@link Parser#consume} to actually "delete" the extraneous token. Then,
+ # before returning {@link #reportMatch} is called to signal a successful
+ # match.
+ #
+ # @param recognizer the parser instance
+ # @return the successfully matched {@link Token} instance if single-token
+ # deletion successfully recovers from the mismatched input, otherwise
+ # {@code null}
+ #
+ def singleTokenDeletion(self, recognizer:Parser):
+ nextTokenType = recognizer.getTokenStream().LA(2)
+ expecting = self.getExpectedTokens(recognizer)
+ if nextTokenType in expecting:
+ self.reportUnwantedToken(recognizer)
+ # print("recoverFromMismatchedToken deleting " \
+ # + str(recognizer.getTokenStream().LT(1)) \
+ # + " since " + str(recognizer.getTokenStream().LT(2)) \
+ # + " is what we want", file=sys.stderr)
+ recognizer.consume() # simply delete extra token
+ # we want to return the token we're actually matching
+ matchedSymbol = recognizer.getCurrentToken()
+ self.reportMatch(recognizer) # we know current token is correct
+ return matchedSymbol
+ else:
+ return None
+
+ # Conjure up a missing token during error recovery.
+ #
+ # The recognizer attempts to recover from single missing
+ # symbols. But, actions might refer to that missing symbol.
+ # For example, x=ID {f($x);}. The action clearly assumes
+ # that there has been an identifier matched previously and that
+ # $x points at that token. If that token is missing, but
+ # the next token in the stream is what we want we assume that
+ # this token is missing and we keep going. Because we
+ # have to return some token to replace the missing token,
+ # we have to conjure one up. This method gives the user control
+ # over the tokens returned for missing tokens. Mostly,
+ # you will want to create something special for identifier
+ # tokens. For literals such as '{' and ',', the default
+ # action in the parser or tree parser works. It simply creates
+ # a CommonToken of the appropriate type. The text will be the token.
+ # If you change what tokens must be created by the lexer,
+ # override this method to create the appropriate tokens.
+ #
+ def getMissingSymbol(self, recognizer:Parser):
+ currentSymbol = recognizer.getCurrentToken()
+ expecting = self.getExpectedTokens(recognizer)
+ expectedTokenType = expecting[0] # get any element
+ if expectedTokenType==Token.EOF:
+ tokenText = ""
+ else:
+ name = None
+ if expectedTokenType < len(recognizer.literalNames):
+ name = recognizer.literalNames[expectedTokenType]
+ if name is None and expectedTokenType < len(recognizer.symbolicNames):
+ name = recognizer.symbolicNames[expectedTokenType]
+ tokenText = ""
+ current = currentSymbol
+ lookback = recognizer.getTokenStream().LT(-1)
+ if current.type==Token.EOF and lookback is not None:
+ current = lookback
+ return recognizer.getTokenFactory().create(current.source,
+ expectedTokenType, tokenText, Token.DEFAULT_CHANNEL,
+ -1, -1, current.line, current.column)
+
+ def getExpectedTokens(self, recognizer:Parser):
+ return recognizer.getExpectedTokens()
+
+ # How should a token be displayed in an error message? The default
+ # is to display just the text, but during development you might
+ # want to have a lot of information spit out. Override in that case
+ # to use t.toString() (which, for CommonToken, dumps everything about
+ # the token). This is better than forcing you to override a method in
+ # your token objects because you don't have to go modify your lexer
+ # so that it creates a new Java type.
+ #
+ def getTokenErrorDisplay(self, t:Token):
+ if t is None:
+ return ""
+ s = t.text
+ if s is None:
+ if t.type==Token.EOF:
+ s = ""
+ else:
+ s = "<" + str(t.type) + ">"
+ return self.escapeWSAndQuote(s)
+
+ def escapeWSAndQuote(self, s:str):
+ s = s.replace("\n","\\n")
+ s = s.replace("\r","\\r")
+ s = s.replace("\t","\\t")
+ return "'" + s + "'"
+
+ # Compute the error recovery set for the current rule. During
+ # rule invocation, the parser pushes the set of tokens that can
+ # follow that rule reference on the stack; this amounts to
+ # computing FIRST of what follows the rule reference in the
+ # enclosing rule. See LinearApproximator.FIRST().
+ # This local follow set only includes tokens
+ # from within the rule; i.e., the FIRST computation done by
+ # ANTLR stops at the end of a rule.
+ #
+ # EXAMPLE
+ #
+ # When you find a "no viable alt exception", the input is not
+ # consistent with any of the alternatives for rule r. The best
+ # thing to do is to consume tokens until you see something that
+ # can legally follow a call to r#or* any rule that called r.
+ # You don't want the exact set of viable next tokens because the
+ # input might just be missing a token--you might consume the
+ # rest of the input looking for one of the missing tokens.
+ #
+ # Consider grammar:
+ #
+ # a : '[' b ']'
+ # | '(' b ')'
+ # ;
+ # b : c '^' INT ;
+ # c : ID
+ # | INT
+ # ;
+ #
+ # At each rule invocation, the set of tokens that could follow
+ # that rule is pushed on a stack. Here are the various
+ # context-sensitive follow sets:
+ #
+ # FOLLOW(b1_in_a) = FIRST(']') = ']'
+ # FOLLOW(b2_in_a) = FIRST(')') = ')'
+ # FOLLOW(c_in_b) = FIRST('^') = '^'
+ #
+ # Upon erroneous input "[]", the call chain is
+ #
+ # a -> b -> c
+ #
+ # and, hence, the follow context stack is:
+ #
+ # depth follow set start of rule execution
+ # 0 a (from main())
+ # 1 ']' b
+ # 2 '^' c
+ #
+ # Notice that ')' is not included, because b would have to have
+ # been called from a different context in rule a for ')' to be
+ # included.
+ #
+ # For error recovery, we cannot consider FOLLOW(c)
+ # (context-sensitive or otherwise). We need the combined set of
+ # all context-sensitive FOLLOW sets--the set of all tokens that
+ # could follow any reference in the call chain. We need to
+ # resync to one of those tokens. Note that FOLLOW(c)='^' and if
+ # we resync'd to that token, we'd consume until EOF. We need to
+ # sync to context-sensitive FOLLOWs for a, b, and c: {']','^'}.
+ # In this case, for input "[]", LA(1) is ']' and in the set, so we would
+ # not consume anything. After printing an error, rule c would
+ # return normally. Rule b would not find the required '^' though.
+ # At this point, it gets a mismatched token error and throws an
+ # exception (since LA(1) is not in the viable following token
+ # set). The rule exception handler tries to recover, but finds
+ # the same recovery set and doesn't consume anything. Rule b
+ # exits normally returning to rule a. Now it finds the ']' (and
+ # with the successful match exits errorRecovery mode).
+ #
+ # So, you can see that the parser walks up the call chain looking
+ # for the token that was a member of the recovery set.
+ #
+ # Errors are not generated in errorRecovery mode.
+ #
+ # ANTLR's error recovery mechanism is based upon original ideas:
+ #
+ # "Algorithms + Data Structures = Programs" by Niklaus Wirth
+ #
+ # and
+ #
+ # "A note on error recovery in recursive descent parsers":
+ # http:#portal.acm.org/citation.cfm?id=947902.947905
+ #
+ # Later, Josef Grosch had some good ideas:
+ #
+ # "Efficient and Comfortable Error Recovery in Recursive Descent
+ # Parsers":
+ # ftp:#www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip
+ #
+ # Like Grosch I implement context-sensitive FOLLOW sets that are combined
+ # at run-time upon error to avoid overhead during parsing.
+ #
+ def getErrorRecoverySet(self, recognizer:Parser):
+ atn = recognizer._interp.atn
+ ctx = recognizer._ctx
+ recoverSet = IntervalSet()
+ while ctx is not None and ctx.invokingState>=0:
+ # compute what follows who invoked us
+ invokingState = atn.states[ctx.invokingState]
+ rt = invokingState.transitions[0]
+ follow = atn.nextTokens(rt.followState)
+ recoverSet.addSet(follow)
+ ctx = ctx.parentCtx
+ recoverSet.removeOne(Token.EPSILON)
+ return recoverSet
+
+ # Consume tokens until one matches the given token set.#
+ def consumeUntil(self, recognizer:Parser, set_:set):
+ ttype = recognizer.getTokenStream().LA(1)
+ while ttype != Token.EOF and not ttype in set_:
+ recognizer.consume()
+ ttype = recognizer.getTokenStream().LA(1)
+
+
+#
+# This implementation of {@link ANTLRErrorStrategy} responds to syntax errors
+# by immediately canceling the parse operation with a
+# {@link ParseCancellationException}. The implementation ensures that the
+# {@link ParserRuleContext#exception} field is set for all parse tree nodes
+# that were not completed prior to encountering the error.
+#
+#
+# This error strategy is useful in the following scenarios.
+#
+#
+#
Two-stage parsing: This error strategy allows the first
+# stage of two-stage parsing to immediately terminate if an error is
+# encountered, and immediately fall back to the second stage. In addition to
+# avoiding wasted work by attempting to recover from errors here, the empty
+# implementation of {@link BailErrorStrategy#sync} improves the performance of
+# the first stage.
+#
Silent validation: When syntax errors are not being
+# reported or logged, and the parse result is simply ignored if errors occur,
+# the {@link BailErrorStrategy} avoids wasting work on recovering from errors
+# when the result will be ignored either way.
+#
+# @see Parser#setErrorHandler(ANTLRErrorStrategy)
+#
+class BailErrorStrategy(DefaultErrorStrategy):
+ # Instead of recovering from exception {@code e}, re-throw it wrapped
+ # in a {@link ParseCancellationException} so it is not caught by the
+ # rule function catches. Use {@link Exception#getCause()} to get the
+ # original {@link RecognitionException}.
+ #
+ def recover(self, recognizer:Parser, e:RecognitionException):
+ context = recognizer._ctx
+ while context is not None:
+ context.exception = e
+ context = context.parentCtx
+ raise ParseCancellationException(e)
+
+ # Make sure we don't attempt to recover inline; if the parser
+ # successfully recovers, it won't throw an exception.
+ #
+ def recoverInline(self, recognizer:Parser):
+ self.recover(recognizer, InputMismatchException(recognizer))
+
+ # Make sure we don't attempt to recover from problems in subrules.#
+ def sync(self, recognizer:Parser):
+ pass
+
+del Parser
\ No newline at end of file
diff --git a/venv/Lib/site-packages/antlr4/error/Errors.py b/venv/Lib/site-packages/antlr4/error/Errors.py
new file mode 100644
index 0000000000000000000000000000000000000000..3f3449269349f4ad6edec71f81756e5ec2bad8a6
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/error/Errors.py
@@ -0,0 +1,173 @@
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+# need forward declaration
+Token = None
+Lexer = None
+Parser = None
+TokenStream = None
+ATNConfigSet = None
+ParserRulecontext = None
+PredicateTransition = None
+BufferedTokenStream = None
+
+class UnsupportedOperationException(Exception):
+
+ def __init__(self, msg:str):
+ super().__init__(msg)
+
+class IllegalStateException(Exception):
+
+ def __init__(self, msg:str):
+ super().__init__(msg)
+
+class CancellationException(IllegalStateException):
+
+ def __init__(self, msg:str):
+ super().__init__(msg)
+
+# The root of the ANTLR exception hierarchy. In general, ANTLR tracks just
+# 3 kinds of errors: prediction errors, failed predicate errors, and
+# mismatched input errors. In each case, the parser knows where it is
+# in the input, where it is in the ATN, the rule invocation stack,
+# and what kind of problem occurred.
+
+from antlr4.InputStream import InputStream
+from antlr4.ParserRuleContext import ParserRuleContext
+from antlr4.Recognizer import Recognizer
+
+class RecognitionException(Exception):
+
+
+ def __init__(self, message:str=None, recognizer:Recognizer=None, input:InputStream=None, ctx:ParserRulecontext=None):
+ super().__init__(message)
+ self.message = message
+ self.recognizer = recognizer
+ self.input = input
+ self.ctx = ctx
+ # The current {@link Token} when an error occurred. Since not all streams
+ # support accessing symbols by index, we have to track the {@link Token}
+ # instance itself.
+ self.offendingToken = None
+ # Get the ATN state number the parser was in at the time the error
+ # occurred. For {@link NoViableAltException} and
+ # {@link LexerNoViableAltException} exceptions, this is the
+ # {@link DecisionState} number. For others, it is the state whose outgoing
+ # edge we couldn't match.
+ self.offendingState = -1
+ if recognizer is not None:
+ self.offendingState = recognizer.state
+
+ #
If the state number is not known, this method returns -1.
+
+ #
+ # Gets the set of input symbols which could potentially follow the
+ # previously matched symbol at the time this exception was thrown.
+ #
+ #
If the set of expected tokens is not known and could not be computed,
+ # this method returns {@code null}.
+ #
+ # @return The set of token types that could potentially follow the current
+ # state in the ATN, or {@code null} if the information is not available.
+ #/
+ def getExpectedTokens(self):
+ if self.recognizer is not None:
+ return self.recognizer.atn.getExpectedTokens(self.offendingState, self.ctx)
+ else:
+ return None
+
+
+class LexerNoViableAltException(RecognitionException):
+
+ def __init__(self, lexer:Lexer, input:InputStream, startIndex:int, deadEndConfigs:ATNConfigSet):
+ super().__init__(message=None, recognizer=lexer, input=input, ctx=None)
+ self.startIndex = startIndex
+ self.deadEndConfigs = deadEndConfigs
+ self.message = ""
+
+ def __str__(self):
+ symbol = ""
+ if self.startIndex >= 0 and self.startIndex < self.input.size:
+ symbol = self.input.getText(self.startIndex, self.startIndex)
+ # TODO symbol = Utils.escapeWhitespace(symbol, false);
+ return "LexerNoViableAltException('" + symbol + "')"
+
+# Indicates that the parser could not decide which of two or more paths
+# to take based upon the remaining input. It tracks the starting token
+# of the offending input and also knows where the parser was
+# in the various paths when the error. Reported by reportNoViableAlternative()
+#
+class NoViableAltException(RecognitionException):
+
+ def __init__(self, recognizer:Parser, input:TokenStream=None, startToken:Token=None,
+ offendingToken:Token=None, deadEndConfigs:ATNConfigSet=None, ctx:ParserRuleContext=None):
+ if ctx is None:
+ ctx = recognizer._ctx
+ if offendingToken is None:
+ offendingToken = recognizer.getCurrentToken()
+ if startToken is None:
+ startToken = recognizer.getCurrentToken()
+ if input is None:
+ input = recognizer.getInputStream()
+ super().__init__(recognizer=recognizer, input=input, ctx=ctx)
+ # Which configurations did we try at input.index() that couldn't match input.LT(1)?#
+ self.deadEndConfigs = deadEndConfigs
+ # The token object at the start index; the input stream might
+ # not be buffering tokens so get a reference to it. (At the
+ # time the error occurred, of course the stream needs to keep a
+ # buffer all of the tokens but later we might not have access to those.)
+ self.startToken = startToken
+ self.offendingToken = offendingToken
+
+# This signifies any kind of mismatched input exceptions such as
+# when the current input does not match the expected token.
+#
+class InputMismatchException(RecognitionException):
+
+ def __init__(self, recognizer:Parser):
+ super().__init__(recognizer=recognizer, input=recognizer.getInputStream(), ctx=recognizer._ctx)
+ self.offendingToken = recognizer.getCurrentToken()
+
+
+# A semantic predicate failed during validation. Validation of predicates
+# occurs when normally parsing the alternative just like matching a token.
+# Disambiguating predicate evaluation occurs when we test a predicate during
+# prediction.
+
+class FailedPredicateException(RecognitionException):
+
+ def __init__(self, recognizer:Parser, predicate:str=None, message:str=None):
+ super().__init__(message=self.formatMessage(predicate,message), recognizer=recognizer,
+ input=recognizer.getInputStream(), ctx=recognizer._ctx)
+ s = recognizer._interp.atn.states[recognizer.state]
+ trans = s.transitions[0]
+ from antlr4.atn.Transition import PredicateTransition
+ if isinstance(trans, PredicateTransition):
+ self.ruleIndex = trans.ruleIndex
+ self.predicateIndex = trans.predIndex
+ else:
+ self.ruleIndex = 0
+ self.predicateIndex = 0
+ self.predicate = predicate
+ self.offendingToken = recognizer.getCurrentToken()
+
+ def formatMessage(self, predicate:str, message:str):
+ if message is not None:
+ return message
+ else:
+ return "failed predicate: {" + predicate + "}?"
+
+class ParseCancellationException(CancellationException):
+
+ pass
+
+del Token
+del Lexer
+del Parser
+del TokenStream
+del ATNConfigSet
+del ParserRulecontext
+del PredicateTransition
+del BufferedTokenStream
diff --git a/venv/Lib/site-packages/antlr4/error/__init__.py b/venv/Lib/site-packages/antlr4/error/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..216c000dc5ffc8e53cc9c596e420c1e67604d1aa
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/error/__init__.py
@@ -0,0 +1 @@
+__author__ = 'ericvergnaud'
diff --git a/venv/Lib/site-packages/antlr4/tree/Chunk.py b/venv/Lib/site-packages/antlr4/tree/Chunk.py
new file mode 100644
index 0000000000000000000000000000000000000000..081419a34f65463b370b848b141192bfe491befd
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/tree/Chunk.py
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+class Chunk(object):
+ pass
+
+class TagChunk(Chunk):
+ __slots__ = ('tag', 'label')
+
+ def __init__(self, tag:str, label:str=None):
+ self.tag = tag
+ self.label = label
+
+ def __str__(self):
+ if self.label is None:
+ return self.tag
+ else:
+ return self.label + ":" + self.tag
+
+class TextChunk(Chunk):
+ __slots__ = 'text'
+
+ def __init__(self, text:str):
+ self.text = text
+
+ def __str__(self):
+ return "'" + self.text + "'"
diff --git a/venv/Lib/site-packages/antlr4/tree/ParseTreeMatch.py b/venv/Lib/site-packages/antlr4/tree/ParseTreeMatch.py
new file mode 100644
index 0000000000000000000000000000000000000000..c02bc0357d26b343a72307cda77ff62fe307a44a
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/tree/ParseTreeMatch.py
@@ -0,0 +1,118 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+
+#
+# Represents the result of matching a {@link ParseTree} against a tree pattern.
+#
+from io import StringIO
+from antlr4.tree.ParseTreePattern import ParseTreePattern
+from antlr4.tree.Tree import ParseTree
+
+
+class ParseTreeMatch(object):
+ __slots__ = ('tree', 'pattern', 'labels', 'mismatchedNode')
+ #
+ # Constructs a new instance of {@link ParseTreeMatch} from the specified
+ # parse tree and pattern.
+ #
+ # @param tree The parse tree to match against the pattern.
+ # @param pattern The parse tree pattern.
+ # @param labels A mapping from label names to collections of
+ # {@link ParseTree} objects located by the tree pattern matching process.
+ # @param mismatchedNode The first node which failed to match the tree
+ # pattern during the matching process.
+ #
+ # @exception IllegalArgumentException if {@code tree} is {@code null}
+ # @exception IllegalArgumentException if {@code pattern} is {@code null}
+ # @exception IllegalArgumentException if {@code labels} is {@code null}
+ #
+ def __init__(self, tree:ParseTree, pattern:ParseTreePattern, labels:dict, mismatchedNode:ParseTree):
+ if tree is None:
+ raise Exception("tree cannot be null")
+ if pattern is None:
+ raise Exception("pattern cannot be null")
+ if labels is None:
+ raise Exception("labels cannot be null")
+ self.tree = tree
+ self.pattern = pattern
+ self.labels = labels
+ self.mismatchedNode = mismatchedNode
+
+ #
+ # Get the last node associated with a specific {@code label}.
+ #
+ #
For example, for pattern {@code }, {@code get("id")} returns the
+ # node matched for that {@code ID}. If more than one node
+ # matched the specified label, only the last is returned. If there is
+ # no node associated with the label, this returns {@code null}.
+ #
+ #
Pattern tags like {@code } and {@code } without labels are
+ # considered to be labeled with {@code ID} and {@code expr}, respectively.
+ #
+ # @param label The label to check.
+ #
+ # @return The last {@link ParseTree} to match a tag with the specified
+ # label, or {@code null} if no parse tree matched a tag with the label.
+ #
+ def get(self, label:str):
+ parseTrees = self.labels.get(label, None)
+ if parseTrees is None or len(parseTrees)==0:
+ return None
+ else:
+ return parseTrees[len(parseTrees)-1]
+
+ #
+ # Return all nodes matching a rule or token tag with the specified label.
+ #
+ #
If the {@code label} is the name of a parser rule or token in the
+ # grammar, the resulting list will contain both the parse trees matching
+ # rule or tags explicitly labeled with the label and the complete set of
+ # parse trees matching the labeled and unlabeled tags in the pattern for
+ # the parser rule or token. For example, if {@code label} is {@code "foo"},
+ # the result will contain all of the following.
+ #
+ #
+ #
Parse tree nodes matching tags of the form {@code } and
+ # {@code }.
+ #
Parse tree nodes matching tags of the form {@code }.
+ #
Parse tree nodes matching tags of the form {@code }.
+ #
+ #
+ # @param label The label.
+ #
+ # @return A collection of all {@link ParseTree} nodes matching tags with
+ # the specified {@code label}. If no nodes matched the label, an empty list
+ # is returned.
+ #
+ def getAll(self, label:str):
+ nodes = self.labels.get(label, None)
+ if nodes is None:
+ return list()
+ else:
+ return nodes
+
+
+ #
+ # Gets a value indicating whether the match operation succeeded.
+ #
+ # @return {@code true} if the match operation succeeded; otherwise,
+ # {@code false}.
+ #
+ def succeeded(self):
+ return self.mismatchedNode is None
+
+ #
+ # {@inheritDoc}
+ #
+ def __str__(self):
+ with StringIO() as buf:
+ buf.write("Match ")
+ buf.write("succeeded" if self.succeeded() else "failed")
+ buf.write("; found ")
+ buf.write(str(len(self.labels)))
+ buf.write(" labels")
+ return buf.getvalue()
diff --git a/venv/Lib/site-packages/antlr4/tree/ParseTreePattern.py b/venv/Lib/site-packages/antlr4/tree/ParseTreePattern.py
new file mode 100644
index 0000000000000000000000000000000000000000..b09bf1a542489d9b461a2fc83b703e4ae2481890
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/tree/ParseTreePattern.py
@@ -0,0 +1,72 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+#
+# A pattern like {@code = ;} converted to a {@link ParseTree} by
+# {@link ParseTreePatternMatcher#compile(String, int)}.
+#
+from antlr4.tree.ParseTreePatternMatcher import ParseTreePatternMatcher
+from antlr4.tree.Tree import ParseTree
+from antlr4.xpath.XPathLexer import XPathLexer
+
+
+class ParseTreePattern(object):
+ __slots__ = ('matcher', 'patternRuleIndex', 'pattern', 'patternTree')
+
+ # Construct a new instance of the {@link ParseTreePattern} class.
+ #
+ # @param matcher The {@link ParseTreePatternMatcher} which created this
+ # tree pattern.
+ # @param pattern The tree pattern in concrete syntax form.
+ # @param patternRuleIndex The parser rule which serves as the root of the
+ # tree pattern.
+ # @param patternTree The tree pattern in {@link ParseTree} form.
+ #
+ def __init__(self, matcher:ParseTreePatternMatcher, pattern:str, patternRuleIndex:int , patternTree:ParseTree):
+ self.matcher = matcher
+ self.patternRuleIndex = patternRuleIndex
+ self.pattern = pattern
+ self.patternTree = patternTree
+
+ #
+ # Match a specific parse tree against this tree pattern.
+ #
+ # @param tree The parse tree to match against this tree pattern.
+ # @return A {@link ParseTreeMatch} object describing the result of the
+ # match operation. The {@link ParseTreeMatch#succeeded()} method can be
+ # used to determine whether or not the match was successful.
+ #
+ def match(self, tree:ParseTree):
+ return self.matcher.match(tree, self)
+
+ #
+ # Determine whether or not a parse tree matches this tree pattern.
+ #
+ # @param tree The parse tree to match against this tree pattern.
+ # @return {@code true} if {@code tree} is a match for the current tree
+ # pattern; otherwise, {@code false}.
+ #
+ def matches(self, tree:ParseTree):
+ return self.matcher.match(tree, self).succeeded()
+
+ # Find all nodes using XPath and then try to match those subtrees against
+ # this tree pattern.
+ #
+ # @param tree The {@link ParseTree} to match against this pattern.
+ # @param xpath An expression matching the nodes
+ #
+ # @return A collection of {@link ParseTreeMatch} objects describing the
+ # successful matches. Unsuccessful matches are omitted from the result,
+ # regardless of the reason for the failure.
+ #
+ def findAll(self, tree:ParseTree, xpath:str):
+ subtrees = XPath.findAll(tree, xpath, self.matcher.parser)
+ matches = list()
+ for t in subtrees:
+ match = self.match(t)
+ if match.succeeded():
+ matches.append(match)
+ return matches
diff --git a/venv/Lib/site-packages/antlr4/tree/ParseTreePatternMatcher.py b/venv/Lib/site-packages/antlr4/tree/ParseTreePatternMatcher.py
new file mode 100644
index 0000000000000000000000000000000000000000..62fd197b0d143393fa187ead9b0c576112b486be
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/tree/ParseTreePatternMatcher.py
@@ -0,0 +1,374 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+#
+# A tree pattern matching mechanism for ANTLR {@link ParseTree}s.
+#
+#
Patterns are strings of source input text with special tags representing
+# token or rule references such as:
+#
+#
{@code = ;}
+#
+#
Given a pattern start rule such as {@code statement}, this object constructs
+# a {@link ParseTree} with placeholders for the {@code ID} and {@code expr}
+# subtree. Then the {@link #match} routines can compare an actual
+# {@link ParseTree} from a parse with this pattern. Tag {@code } matches
+# any {@code ID} token and tag {@code } references the result of the
+# {@code expr} rule (generally an instance of {@code ExprContext}.
+#
+#
Pattern {@code x = 0;} is a similar pattern that matches the same pattern
+# except that it requires the identifier to be {@code x} and the expression to
+# be {@code 0}.
+#
+#
The {@link #matches} routines return {@code true} or {@code false} based
+# upon a match for the tree rooted at the parameter sent in. The
+# {@link #match} routines return a {@link ParseTreeMatch} object that
+# contains the parse tree, the parse tree pattern, and a map from tag name to
+# matched nodes (more below). A subtree that fails to match, returns with
+# {@link ParseTreeMatch#mismatchedNode} set to the first tree node that did not
+# match.
+#
+#
For efficiency, you can compile a tree pattern in string form to a
+# {@link ParseTreePattern} object.
+#
+#
See {@code TestParseTreeMatcher} for lots of examples.
+# {@link ParseTreePattern} has two static helper methods:
+# {@link ParseTreePattern#findAll} and {@link ParseTreePattern#match} that
+# are easy to use but not super efficient because they create new
+# {@link ParseTreePatternMatcher} objects each time and have to compile the
+# pattern in string form before using it.
+#
+#
The lexer and parser that you pass into the {@link ParseTreePatternMatcher}
+# constructor are used to parse the pattern in string form. The lexer converts
+# the {@code = ;} into a sequence of four tokens (assuming lexer
+# throws out whitespace or puts it on a hidden channel). Be aware that the
+# input stream is reset for the lexer (but not the parser; a
+# {@link ParserInterpreter} is created to parse the input.). Any user-defined
+# fields you have put into the lexer might get changed when this mechanism asks
+# it to scan the pattern string.
+#
+#
Normally a parser does not accept token {@code } as a valid
+# {@code expr} but, from the parser passed in, we create a special version of
+# the underlying grammar representation (an {@link ATN}) that allows imaginary
+# tokens representing rules ({@code }) to match entire rules. We call
+# these bypass alternatives.
+#
+#
Delimiters are {@code <} and {@code >}, with {@code \} as the escape string
+# by default, but you can set them to whatever you want using
+# {@link #setDelimiters}. You must escape both start and stop strings
+# {@code \<} and {@code \>}.
+#
+from antlr4.CommonTokenStream import CommonTokenStream
+from antlr4.InputStream import InputStream
+from antlr4.ParserRuleContext import ParserRuleContext
+from antlr4.Lexer import Lexer
+from antlr4.ListTokenSource import ListTokenSource
+from antlr4.Token import Token
+from antlr4.error.ErrorStrategy import BailErrorStrategy
+from antlr4.error.Errors import RecognitionException, ParseCancellationException
+from antlr4.tree.Chunk import TagChunk, TextChunk
+from antlr4.tree.RuleTagToken import RuleTagToken
+from antlr4.tree.TokenTagToken import TokenTagToken
+from antlr4.tree.Tree import ParseTree, TerminalNode, RuleNode
+
+# need forward declaration
+Parser = None
+ParseTreePattern = None
+
+class CannotInvokeStartRule(Exception):
+
+ def __init__(self, e:Exception):
+ super().__init__(e)
+
+class StartRuleDoesNotConsumeFullPattern(Exception):
+
+ pass
+
+
+class ParseTreePatternMatcher(object):
+ __slots__ = ('lexer', 'parser', 'start', 'stop', 'escape')
+
+ # Constructs a {@link ParseTreePatternMatcher} or from a {@link Lexer} and
+ # {@link Parser} object. The lexer input stream is altered for tokenizing
+ # the tree patterns. The parser is used as a convenient mechanism to get
+ # the grammar name, plus token, rule names.
+ def __init__(self, lexer:Lexer, parser:Parser):
+ self.lexer = lexer
+ self.parser = parser
+ self.start = "<"
+ self.stop = ">"
+ self.escape = "\\" # e.g., \< and \> must escape BOTH!
+
+ # Set the delimiters used for marking rule and token tags within concrete
+ # syntax used by the tree pattern parser.
+ #
+ # @param start The start delimiter.
+ # @param stop The stop delimiter.
+ # @param escapeLeft The escape sequence to use for escaping a start or stop delimiter.
+ #
+ # @exception IllegalArgumentException if {@code start} is {@code null} or empty.
+ # @exception IllegalArgumentException if {@code stop} is {@code null} or empty.
+ #
+ def setDelimiters(self, start:str, stop:str, escapeLeft:str):
+ if start is None or len(start)==0:
+ raise Exception("start cannot be null or empty")
+ if stop is None or len(stop)==0:
+ raise Exception("stop cannot be null or empty")
+ self.start = start
+ self.stop = stop
+ self.escape = escapeLeft
+
+ # Does {@code pattern} matched as rule {@code patternRuleIndex} match {@code tree}?#
+ def matchesRuleIndex(self, tree:ParseTree, pattern:str, patternRuleIndex:int):
+ p = self.compileTreePattern(pattern, patternRuleIndex)
+ return self.matches(tree, p)
+
+ # Does {@code pattern} matched as rule patternRuleIndex match tree? Pass in a
+ # compiled pattern instead of a string representation of a tree pattern.
+ #
+ def matchesPattern(self, tree:ParseTree, pattern:ParseTreePattern):
+ mismatchedNode = self.matchImpl(tree, pattern.patternTree, dict())
+ return mismatchedNode is None
+
+ #
+ # Compare {@code pattern} matched as rule {@code patternRuleIndex} against
+ # {@code tree} and return a {@link ParseTreeMatch} object that contains the
+ # matched elements, or the node at which the match failed.
+ #
+ def matchRuleIndex(self, tree:ParseTree, pattern:str, patternRuleIndex:int):
+ p = self.compileTreePattern(pattern, patternRuleIndex)
+ return self.matchPattern(tree, p)
+
+ #
+ # Compare {@code pattern} matched against {@code tree} and return a
+ # {@link ParseTreeMatch} object that contains the matched elements, or the
+ # node at which the match failed. Pass in a compiled pattern instead of a
+ # string representation of a tree pattern.
+ #
+ def matchPattern(self, tree:ParseTree, pattern:ParseTreePattern):
+ labels = dict()
+ mismatchedNode = self.matchImpl(tree, pattern.patternTree, labels)
+ from antlr4.tree.ParseTreeMatch import ParseTreeMatch
+ return ParseTreeMatch(tree, pattern, labels, mismatchedNode)
+
+ #
+ # For repeated use of a tree pattern, compile it to a
+ # {@link ParseTreePattern} using this method.
+ #
+ def compileTreePattern(self, pattern:str, patternRuleIndex:int):
+ tokenList = self.tokenize(pattern)
+ tokenSrc = ListTokenSource(tokenList)
+ tokens = CommonTokenStream(tokenSrc)
+ from antlr4.ParserInterpreter import ParserInterpreter
+ parserInterp = ParserInterpreter(self.parser.grammarFileName, self.parser.tokenNames,
+ self.parser.ruleNames, self.parser.getATNWithBypassAlts(),tokens)
+ tree = None
+ try:
+ parserInterp.setErrorHandler(BailErrorStrategy())
+ tree = parserInterp.parse(patternRuleIndex)
+ except ParseCancellationException as e:
+ raise e.cause
+ except RecognitionException as e:
+ raise e
+ except Exception as e:
+ raise CannotInvokeStartRule(e)
+
+ # Make sure tree pattern compilation checks for a complete parse
+ if tokens.LA(1)!=Token.EOF:
+ raise StartRuleDoesNotConsumeFullPattern()
+
+ from antlr4.tree.ParseTreePattern import ParseTreePattern
+ return ParseTreePattern(self, pattern, patternRuleIndex, tree)
+
+ #
+ # Recursively walk {@code tree} against {@code patternTree}, filling
+ # {@code match.}{@link ParseTreeMatch#labels labels}.
+ #
+ # @return the first node encountered in {@code tree} which does not match
+ # a corresponding node in {@code patternTree}, or {@code null} if the match
+ # was successful. The specific node returned depends on the matching
+ # algorithm used by the implementation, and may be overridden.
+ #
+ def matchImpl(self, tree:ParseTree, patternTree:ParseTree, labels:dict):
+ if tree is None:
+ raise Exception("tree cannot be null")
+ if patternTree is None:
+ raise Exception("patternTree cannot be null")
+
+ # x and , x and y, or x and x; or could be mismatched types
+ if isinstance(tree, TerminalNode) and isinstance(patternTree, TerminalNode ):
+ mismatchedNode = None
+ # both are tokens and they have same type
+ if tree.symbol.type == patternTree.symbol.type:
+ if isinstance( patternTree.symbol, TokenTagToken ): # x and
+ tokenTagToken = patternTree.symbol
+ # track label->list-of-nodes for both token name and label (if any)
+ self.map(labels, tokenTagToken.tokenName, tree)
+ if tokenTagToken.label is not None:
+ self.map(labels, tokenTagToken.label, tree)
+ elif tree.getText()==patternTree.getText():
+ # x and x
+ pass
+ else:
+ # x and y
+ if mismatchedNode is None:
+ mismatchedNode = tree
+ else:
+ if mismatchedNode is None:
+ mismatchedNode = tree
+
+ return mismatchedNode
+
+ if isinstance(tree, ParserRuleContext) and isinstance(patternTree, ParserRuleContext):
+ mismatchedNode = None
+ # (expr ...) and
+ ruleTagToken = self.getRuleTagToken(patternTree)
+ if ruleTagToken is not None:
+ m = None
+ if tree.ruleContext.ruleIndex == patternTree.ruleContext.ruleIndex:
+ # track label->list-of-nodes for both rule name and label (if any)
+ self.map(labels, ruleTagToken.ruleName, tree)
+ if ruleTagToken.label is not None:
+ self.map(labels, ruleTagToken.label, tree)
+ else:
+ if mismatchedNode is None:
+ mismatchedNode = tree
+
+ return mismatchedNode
+
+ # (expr ...) and (expr ...)
+ if tree.getChildCount()!=patternTree.getChildCount():
+ if mismatchedNode is None:
+ mismatchedNode = tree
+ return mismatchedNode
+
+ n = tree.getChildCount()
+ for i in range(0, n):
+ childMatch = self.matchImpl(tree.getChild(i), patternTree.getChild(i), labels)
+ if childMatch is not None:
+ return childMatch
+
+ return mismatchedNode
+
+ # if nodes aren't both tokens or both rule nodes, can't match
+ return tree
+
+ def map(self, labels, label, tree):
+ v = labels.get(label, None)
+ if v is None:
+ v = list()
+ labels[label] = v
+ v.append(tree)
+
+ # Is {@code t} {@code (expr )} subtree?#
+ def getRuleTagToken(self, tree:ParseTree):
+ if isinstance( tree, RuleNode ):
+ if tree.getChildCount()==1 and isinstance(tree.getChild(0), TerminalNode ):
+ c = tree.getChild(0)
+ if isinstance( c.symbol, RuleTagToken ):
+ return c.symbol
+ return None
+
+ def tokenize(self, pattern:str):
+ # split pattern into chunks: sea (raw input) and islands (, )
+ chunks = self.split(pattern)
+
+ # create token stream from text and tags
+ tokens = list()
+ for chunk in chunks:
+ if isinstance( chunk, TagChunk ):
+ # add special rule token or conjure up new token from name
+ if chunk.tag[0].isupper():
+ ttype = self.parser.getTokenType(chunk.tag)
+ if ttype==Token.INVALID_TYPE:
+ raise Exception("Unknown token " + str(chunk.tag) + " in pattern: " + pattern)
+ tokens.append(TokenTagToken(chunk.tag, ttype, chunk.label))
+ elif chunk.tag[0].islower():
+ ruleIndex = self.parser.getRuleIndex(chunk.tag)
+ if ruleIndex==-1:
+ raise Exception("Unknown rule " + str(chunk.tag) + " in pattern: " + pattern)
+ ruleImaginaryTokenType = self.parser.getATNWithBypassAlts().ruleToTokenType[ruleIndex]
+ tokens.append(RuleTagToken(chunk.tag, ruleImaginaryTokenType, chunk.label))
+ else:
+ raise Exception("invalid tag: " + str(chunk.tag) + " in pattern: " + pattern)
+ else:
+ self.lexer.setInputStream(InputStream(chunk.text))
+ t = self.lexer.nextToken()
+ while t.type!=Token.EOF:
+ tokens.append(t)
+ t = self.lexer.nextToken()
+ return tokens
+
+ # Split {@code = ;} into 4 chunks for tokenizing by {@link #tokenize}.#
+ def split(self, pattern:str):
+ p = 0
+ n = len(pattern)
+ chunks = list()
+ # find all start and stop indexes first, then collect
+ starts = list()
+ stops = list()
+ while p < n :
+ if p == pattern.find(self.escape + self.start, p):
+ p += len(self.escape) + len(self.start)
+ elif p == pattern.find(self.escape + self.stop, p):
+ p += len(self.escape) + len(self.stop)
+ elif p == pattern.find(self.start, p):
+ starts.append(p)
+ p += len(self.start)
+ elif p == pattern.find(self.stop, p):
+ stops.append(p)
+ p += len(self.stop)
+ else:
+ p += 1
+
+ nt = len(starts)
+
+ if nt > len(stops):
+ raise Exception("unterminated tag in pattern: " + pattern)
+ if nt < len(stops):
+ raise Exception("missing start tag in pattern: " + pattern)
+
+ for i in range(0, nt):
+ if starts[i] >= stops[i]:
+ raise Exception("tag delimiters out of order in pattern: " + pattern)
+
+ # collect into chunks now
+ if nt==0:
+ chunks.append(TextChunk(pattern))
+
+ if nt>0 and starts[0]>0: # copy text up to first tag into chunks
+ text = pattern[0:starts[0]]
+ chunks.add(TextChunk(text))
+
+ for i in range(0, nt):
+ # copy inside of
+ tag = pattern[starts[i] + len(self.start) : stops[i]]
+ ruleOrToken = tag
+ label = None
+ colon = tag.find(':')
+ if colon >= 0:
+ label = tag[0:colon]
+ ruleOrToken = tag[colon+1 : len(tag)]
+ chunks.append(TagChunk(label, ruleOrToken))
+ if i+1 < len(starts):
+ # copy from end of to start of next
+ text = pattern[stops[i] + len(self.stop) : starts[i + 1]]
+ chunks.append(TextChunk(text))
+
+ if nt > 0 :
+ afterLastTag = stops[nt - 1] + len(self.stop)
+ if afterLastTag < n : # copy text from end of last tag to end
+ text = pattern[afterLastTag : n]
+ chunks.append(TextChunk(text))
+
+ # strip out the escape sequences from text chunks but not tags
+ for i in range(0, len(chunks)):
+ c = chunks[i]
+ if isinstance( c, TextChunk ):
+ unescaped = c.text.replace(self.escape, "")
+ if len(unescaped) < len(c.text):
+ chunks[i] = TextChunk(unescaped)
+ return chunks
diff --git a/venv/Lib/site-packages/antlr4/tree/RuleTagToken.py b/venv/Lib/site-packages/antlr4/tree/RuleTagToken.py
new file mode 100644
index 0000000000000000000000000000000000000000..a198f7da13643d538ce96aeeb6a8ff4f757f1ecd
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/tree/RuleTagToken.py
@@ -0,0 +1,50 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+#
+# A {@link Token} object representing an entire subtree matched by a parser
+# rule; e.g., {@code }. These tokens are created for {@link TagChunk}
+# chunks where the tag corresponds to a parser rule.
+#
+from antlr4.Token import Token
+
+
+class RuleTagToken(Token):
+ __slots__ = ('label', 'ruleName')
+ #
+ # Constructs a new instance of {@link RuleTagToken} with the specified rule
+ # name, bypass token type, and label.
+ #
+ # @param ruleName The name of the parser rule this rule tag matches.
+ # @param bypassTokenType The bypass token type assigned to the parser rule.
+ # @param label The label associated with the rule tag, or {@code null} if
+ # the rule tag is unlabeled.
+ #
+ # @exception IllegalArgumentException if {@code ruleName} is {@code null}
+ # or empty.
+
+ def __init__(self, ruleName:str, bypassTokenType:int, label:str=None):
+ if ruleName is None or len(ruleName)==0:
+ raise Exception("ruleName cannot be null or empty.")
+ self.source = None
+ self.type = bypassTokenType # token type of the token
+ self.channel = Token.DEFAULT_CHANNEL # The parser ignores everything not on DEFAULT_CHANNEL
+ self.start = -1 # optional; return -1 if not implemented.
+ self.stop = -1 # optional; return -1 if not implemented.
+ self.tokenIndex = -1 # from 0..n-1 of the token object in the input stream
+ self.line = 0 # line=1..n of the 1st character
+ self.column = -1 # beginning of the line at which it occurs, 0..n-1
+ self.label = label
+ self._text = self.getText() # text of the token.
+
+ self.ruleName = ruleName
+
+
+ def getText(self):
+ if self.label is None:
+ return "<" + self.ruleName + ">"
+ else:
+ return "<" + self.label + ":" + self.ruleName + ">"
diff --git a/venv/Lib/site-packages/antlr4/tree/TokenTagToken.py b/venv/Lib/site-packages/antlr4/tree/TokenTagToken.py
new file mode 100644
index 0000000000000000000000000000000000000000..b7beeb87684c06606e17053f0f74fcae36876959
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/tree/TokenTagToken.py
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+#
+# A {@link Token} object representing a token of a particular type; e.g.,
+# {@code }. These tokens are created for {@link TagChunk} chunks where the
+# tag corresponds to a lexer rule or token type.
+#
+from antlr4.Token import CommonToken
+
+
+class TokenTagToken(CommonToken):
+ __slots__ = ('tokenName', 'label')
+ # Constructs a new instance of {@link TokenTagToken} with the specified
+ # token name, type, and label.
+ #
+ # @param tokenName The token name.
+ # @param type The token type.
+ # @param label The label associated with the token tag, or {@code null} if
+ # the token tag is unlabeled.
+ #
+ def __init__(self, tokenName:str, type:int, label:str=None):
+ super().__init__(type=type)
+ self.tokenName = tokenName
+ self.label = label
+ self._text = self.getText()
+
+ #
+ # {@inheritDoc}
+ #
+ #
The implementation for {@link TokenTagToken} returns the token tag
+ # formatted with {@code <} and {@code >} delimiters.
The implementation for {@link TokenTagToken} returns a string of the form
+ # {@code tokenName:type}.
+ #
+ def __str__(self):
+ return self.tokenName + ":" + str(self.type)
diff --git a/venv/Lib/site-packages/antlr4/tree/Tree.py b/venv/Lib/site-packages/antlr4/tree/Tree.py
new file mode 100644
index 0000000000000000000000000000000000000000..812acc96bbee97860bc8a914feedcd0584def050
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/tree/Tree.py
@@ -0,0 +1,191 @@
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#/
+
+
+# The basic notion of a tree has a parent, a payload, and a list of children.
+# It is the most abstract interface for all the trees used by ANTLR.
+#/
+from antlr4.Token import Token
+
+INVALID_INTERVAL = (-1, -2)
+
+class Tree(object):
+ pass
+
+class SyntaxTree(Tree):
+ pass
+
+class ParseTree(SyntaxTree):
+ pass
+
+class RuleNode(ParseTree):
+ pass
+
+class TerminalNode(ParseTree):
+ pass
+
+class ErrorNode(TerminalNode):
+ pass
+
+class ParseTreeVisitor(object):
+ def visit(self, tree):
+ return tree.accept(self)
+
+ def visitChildren(self, node):
+ result = self.defaultResult()
+ n = node.getChildCount()
+ for i in range(n):
+ if not self.shouldVisitNextChild(node, result):
+ return result
+
+ c = node.getChild(i)
+ childResult = c.accept(self)
+ result = self.aggregateResult(result, childResult)
+
+ return result
+
+ def visitTerminal(self, node):
+ return self.defaultResult()
+
+ def visitErrorNode(self, node):
+ return self.defaultResult()
+
+ def defaultResult(self):
+ return None
+
+ def aggregateResult(self, aggregate, nextResult):
+ return nextResult
+
+ def shouldVisitNextChild(self, node, currentResult):
+ return True
+
+ParserRuleContext = None
+
+class ParseTreeListener(object):
+
+ def visitTerminal(self, node:TerminalNode):
+ pass
+
+ def visitErrorNode(self, node:ErrorNode):
+ pass
+
+ def enterEveryRule(self, ctx:ParserRuleContext):
+ pass
+
+ def exitEveryRule(self, ctx:ParserRuleContext):
+ pass
+
+del ParserRuleContext
+
+class TerminalNodeImpl(TerminalNode):
+ __slots__ = ('parentCtx', 'symbol')
+
+ def __init__(self, symbol:Token):
+ self.parentCtx = None
+ self.symbol = symbol
+ def __setattr__(self, key, value):
+ super().__setattr__(key, value)
+
+ def getChild(self, i:int):
+ return None
+
+ def getSymbol(self):
+ return self.symbol
+
+ def getParent(self):
+ return self.parentCtx
+
+ def getPayload(self):
+ return self.symbol
+
+ def getSourceInterval(self):
+ if self.symbol is None:
+ return INVALID_INTERVAL
+ tokenIndex = self.symbol.tokenIndex
+ return (tokenIndex, tokenIndex)
+
+ def getChildCount(self):
+ return 0
+
+ def accept(self, visitor:ParseTreeVisitor):
+ return visitor.visitTerminal(self)
+
+ def getText(self):
+ return self.symbol.text
+
+ def __str__(self):
+ if self.symbol.type == Token.EOF:
+ return ""
+ else:
+ return self.symbol.text
+
+# Represents a token that was consumed during resynchronization
+# rather than during a valid match operation. For example,
+# we will create this kind of a node during single token insertion
+# and deletion as well as during "consume until error recovery set"
+# upon no viable alternative exceptions.
+
+class ErrorNodeImpl(TerminalNodeImpl,ErrorNode):
+
+ def __init__(self, token:Token):
+ super().__init__(token)
+
+ def accept(self, visitor:ParseTreeVisitor):
+ return visitor.visitErrorNode(self)
+
+
+class ParseTreeWalker(object):
+
+ DEFAULT = None
+
+ def walk(self, listener:ParseTreeListener, t:ParseTree):
+ """
+ Performs a walk on the given parse tree starting at the root and going down recursively
+ with depth-first search. On each node, {@link ParseTreeWalker#enterRule} is called before
+ recursively walking down into child nodes, then
+ {@link ParseTreeWalker#exitRule} is called after the recursive call to wind up.
+ @param listener The listener used by the walker to process grammar rules
+ @param t The parse tree to be walked on
+ """
+ if isinstance(t, ErrorNode):
+ listener.visitErrorNode(t)
+ return
+ elif isinstance(t, TerminalNode):
+ listener.visitTerminal(t)
+ return
+ self.enterRule(listener, t)
+ for child in t.getChildren():
+ self.walk(listener, child)
+ self.exitRule(listener, t)
+
+ #
+ # The discovery of a rule node, involves sending two events: the generic
+ # {@link ParseTreeListener#enterEveryRule} and a
+ # {@link RuleContext}-specific event. First we trigger the generic and then
+ # the rule specific. We to them in reverse order upon finishing the node.
+ #
+ def enterRule(self, listener:ParseTreeListener, r:RuleNode):
+ """
+ Enters a grammar rule by first triggering the generic event {@link ParseTreeListener#enterEveryRule}
+ then by triggering the event specific to the given parse tree node
+ @param listener The listener responding to the trigger events
+ @param r The grammar rule containing the rule context
+ """
+ ctx = r.getRuleContext()
+ listener.enterEveryRule(ctx)
+ ctx.enterRule(listener)
+
+ def exitRule(self, listener:ParseTreeListener, r:RuleNode):
+ """
+ Exits a grammar rule by first triggering the event specific to the given parse tree node
+ then by triggering the generic event {@link ParseTreeListener#exitEveryRule}
+ @param listener The listener responding to the trigger events
+ @param r The grammar rule containing the rule context
+ """
+ ctx = r.getRuleContext()
+ ctx.exitRule(listener)
+ listener.exitEveryRule(ctx)
+
+ParseTreeWalker.DEFAULT = ParseTreeWalker()
diff --git a/venv/Lib/site-packages/antlr4/tree/Trees.py b/venv/Lib/site-packages/antlr4/tree/Trees.py
new file mode 100644
index 0000000000000000000000000000000000000000..686b8cb287b3058c2e0b33dfb1567320299f214e
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/tree/Trees.py
@@ -0,0 +1,111 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+
+# A set of utility routines useful for all kinds of ANTLR trees.#
+from io import StringIO
+from antlr4.Token import Token
+from antlr4.Utils import escapeWhitespace
+from antlr4.tree.Tree import RuleNode, ErrorNode, TerminalNode, Tree, ParseTree
+
+# need forward declaration
+Parser = None
+
+class Trees(object):
+
+ # Print out a whole tree in LISP form. {@link #getNodeText} is used on the
+ # node payloads to get the text for the nodes. Detect
+ # parse trees and extract data appropriately.
+ @classmethod
+ def toStringTree(cls, t:Tree, ruleNames:list=None, recog:Parser=None):
+ if recog is not None:
+ ruleNames = recog.ruleNames
+ s = escapeWhitespace(cls.getNodeText(t, ruleNames), False)
+ if t.getChildCount()==0:
+ return s
+ with StringIO() as buf:
+ buf.write("(")
+ buf.write(s)
+ buf.write(' ')
+ for i in range(0, t.getChildCount()):
+ if i > 0:
+ buf.write(' ')
+ buf.write(cls.toStringTree(t.getChild(i), ruleNames))
+ buf.write(")")
+ return buf.getvalue()
+
+ @classmethod
+ def getNodeText(cls, t:Tree, ruleNames:list=None, recog:Parser=None):
+ if recog is not None:
+ ruleNames = recog.ruleNames
+ if ruleNames is not None:
+ if isinstance(t, RuleNode):
+ if t.getAltNumber()!=0: # should use ATN.INVALID_ALT_NUMBER but won't compile
+ return ruleNames[t.getRuleIndex()]+":"+str(t.getAltNumber())
+ return ruleNames[t.getRuleIndex()]
+ elif isinstance( t, ErrorNode):
+ return str(t)
+ elif isinstance(t, TerminalNode):
+ if t.symbol is not None:
+ return t.symbol.text
+ # no recog for rule names
+ payload = t.getPayload()
+ if isinstance(payload, Token ):
+ return payload.text
+ return str(t.getPayload())
+
+
+ # Return ordered list of all children of this node
+ @classmethod
+ def getChildren(cls, t:Tree):
+ return [ t.getChild(i) for i in range(0, t.getChildCount()) ]
+
+ # Return a list of all ancestors of this node. The first node of
+ # list is the root and the last is the parent of this node.
+ #
+ @classmethod
+ def getAncestors(cls, t:Tree):
+ ancestors = []
+ t = t.getParent()
+ while t is not None:
+ ancestors.insert(0, t) # insert at start
+ t = t.getParent()
+ return ancestors
+
+ @classmethod
+ def findAllTokenNodes(cls, t:ParseTree, ttype:int):
+ return cls.findAllNodes(t, ttype, True)
+
+ @classmethod
+ def findAllRuleNodes(cls, t:ParseTree, ruleIndex:int):
+ return cls.findAllNodes(t, ruleIndex, False)
+
+ @classmethod
+ def findAllNodes(cls, t:ParseTree, index:int, findTokens:bool):
+ nodes = []
+ cls._findAllNodes(t, index, findTokens, nodes)
+ return nodes
+
+ @classmethod
+ def _findAllNodes(cls, t:ParseTree, index:int, findTokens:bool, nodes:list):
+ from antlr4.ParserRuleContext import ParserRuleContext
+ # check this node (the root) first
+ if findTokens and isinstance(t, TerminalNode):
+ if t.symbol.type==index:
+ nodes.append(t)
+ elif not findTokens and isinstance(t, ParserRuleContext):
+ if t.ruleIndex == index:
+ nodes.append(t)
+ # check children
+ for i in range(0, t.getChildCount()):
+ cls._findAllNodes(t.getChild(i), index, findTokens, nodes)
+
+ @classmethod
+ def descendants(cls, t:ParseTree):
+ nodes = [t]
+ for i in range(0, t.getChildCount()):
+ nodes.extend(cls.descendants(t.getChild(i)))
+ return nodes
diff --git a/venv/Lib/site-packages/antlr4/tree/__init__.py b/venv/Lib/site-packages/antlr4/tree/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/venv/Lib/site-packages/antlr4/xpath/XPath.py b/venv/Lib/site-packages/antlr4/xpath/XPath.py
new file mode 100644
index 0000000000000000000000000000000000000000..92f5e0dac3f00a1e7fbfdc40b3233361920d0469
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/xpath/XPath.py
@@ -0,0 +1,269 @@
+#
+# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
+# Use of this file is governed by the BSD 3-clause license that
+# can be found in the LICENSE.txt file in the project root.
+#
+
+#
+# Represent a subset of XPath XML path syntax for use in identifying nodes in
+# parse trees.
+#
+#
+# Split path into words and separators {@code /} and {@code //} via ANTLR
+# itself then walk path elements from left to right. At each separator-word
+# pair, find set of nodes. Next stage uses those as work list.
+#
+#
+# The basic interface is
+# {@link XPath#findAll ParseTree.findAll}{@code (tree, pathString, parser)}.
+# But that is just shorthand for:
+#
+#
+# {@link XPath} p = new {@link XPath#XPath XPath}(parser, pathString);
+# return p.{@link #evaluate evaluate}(tree);
+#
+#
+#
+# See {@code org.antlr.v4.test.TestXPath} for descriptions. In short, this
+# allows operators:
+#
+#
+#
/
root
+#
//
anywhere
+#
!
invert; this must appear directly after root or anywhere
+# operator
+#
+#
+#
+# and path elements:
+#
+#
+#
ID
token name
+#
'string'
any string literal token from the grammar
+#
expr
rule name
+#
*
wildcard matching any node
+#
+#
+#
+# Whitespace is not allowed.
+#
+from antlr4 import CommonTokenStream, DFA, PredictionContextCache, Lexer, LexerATNSimulator, ParserRuleContext, TerminalNode
+from antlr4.InputStream import InputStream
+from antlr4.Parser import Parser
+from antlr4.RuleContext import RuleContext
+from antlr4.Token import Token
+from antlr4.atn.ATNDeserializer import ATNDeserializer
+from antlr4.error.ErrorListener import ErrorListener
+from antlr4.error.Errors import LexerNoViableAltException
+from antlr4.tree.Tree import ParseTree
+from antlr4.tree.Trees import Trees
+from io import StringIO
+from antlr4.xpath.XPathLexer import XPathLexer
+
+
+class XPath(object):
+
+ WILDCARD = "*" # word not operator/separator
+ NOT = "!" # word for invert operator
+
+ def __init__(self, parser:Parser, path:str):
+ self.parser = parser
+ self.path = path
+ self.elements = self.split(path)
+
+ def split(self, path:str):
+ input = InputStream(path)
+ lexer = XPathLexer(input)
+ def recover(self, e):
+ raise e
+ lexer.recover = recover
+ lexer.removeErrorListeners()
+ lexer.addErrorListener(ErrorListener()) # XPathErrorListener does no more
+ tokenStream = CommonTokenStream(lexer)
+ try:
+ tokenStream.fill()
+ except LexerNoViableAltException as e:
+ pos = lexer.column
+ msg = "Invalid tokens or characters at index %d in path '%s'" % (pos, path)
+ raise Exception(msg, e)
+
+ tokens = iter(tokenStream.tokens)
+ elements = list()
+ for el in tokens:
+ invert = False
+ anywhere = False
+ # Check for path separators, if none assume root
+ if el.type in [XPathLexer.ROOT, XPathLexer.ANYWHERE]:
+ anywhere = el.type == XPathLexer.ANYWHERE
+ next_el = next(tokens, None)
+ if not next_el:
+ raise Exception('Missing element after %s' % el.getText())
+ else:
+ el = next_el
+ # Check for bangs
+ if el.type == XPathLexer.BANG:
+ invert = True
+ next_el = next(tokens, None)
+ if not next_el:
+ raise Exception('Missing element after %s' % el.getText())
+ else:
+ el = next_el
+ # Add searched element
+ if el.type in [XPathLexer.TOKEN_REF, XPathLexer.RULE_REF, XPathLexer.WILDCARD, XPathLexer.STRING]:
+ element = self.getXPathElement(el, anywhere)
+ element.invert = invert
+ elements.append(element)
+ elif el.type==Token.EOF:
+ break
+ else:
+ raise Exception("Unknown path element %s" % lexer.symbolicNames[el.type])
+ return elements
+
+ #
+ # Convert word like {@code#} or {@code ID} or {@code expr} to a path
+ # element. {@code anywhere} is {@code true} if {@code //} precedes the
+ # word.
+ #
+ def getXPathElement(self, wordToken:Token, anywhere:bool):
+ if wordToken.type==Token.EOF:
+ raise Exception("Missing path element at end of path")
+
+ word = wordToken.text
+ if wordToken.type==XPathLexer.WILDCARD :
+ return XPathWildcardAnywhereElement() if anywhere else XPathWildcardElement()
+
+ elif wordToken.type in [XPathLexer.TOKEN_REF, XPathLexer.STRING]:
+ tsource = self.parser.getTokenStream().tokenSource
+
+ ttype = Token.INVALID_TYPE
+ if wordToken.type == XPathLexer.TOKEN_REF:
+ if word in tsource.ruleNames:
+ ttype = tsource.ruleNames.index(word) + 1
+ else:
+ if word in tsource.literalNames:
+ ttype = tsource.literalNames.index(word)
+
+ if ttype == Token.INVALID_TYPE:
+ raise Exception("%s at index %d isn't a valid token name" % (word, wordToken.tokenIndex))
+ return XPathTokenAnywhereElement(word, ttype) if anywhere else XPathTokenElement(word, ttype)
+
+ else:
+ ruleIndex = self.parser.ruleNames.index(word) if word in self.parser.ruleNames else -1
+
+ if ruleIndex == -1:
+ raise Exception("%s at index %d isn't a valid rule name" % (word, wordToken.tokenIndex))
+ return XPathRuleAnywhereElement(word, ruleIndex) if anywhere else XPathRuleElement(word, ruleIndex)
+
+
+ @staticmethod
+ def findAll(tree:ParseTree, xpath:str, parser:Parser):
+ p = XPath(parser, xpath)
+ return p.evaluate(tree)
+
+ #
+ # Return a list of all nodes starting at {@code t} as root that satisfy the
+ # path. The root {@code /} is relative to the node passed to
+ # {@link #evaluate}.
+ #
+ def evaluate(self, t:ParseTree):
+ dummyRoot = ParserRuleContext()
+ dummyRoot.children = [t] # don't set t's parent.
+
+ work = [dummyRoot]
+ for element in self.elements:
+ work_next = list()
+ for node in work:
+ if not isinstance(node, TerminalNode) and node.children:
+ # only try to match next element if it has children
+ # e.g., //func/*/stat might have a token node for which
+ # we can't go looking for stat nodes.
+ matching = element.evaluate(node)
+
+ # See issue antlr#370 - Prevents XPath from returning the
+ # same node multiple times
+ matching = filter(lambda m: m not in work_next, matching)
+
+ work_next.extend(matching)
+ work = work_next
+
+ return work
+
+
+class XPathElement(object):
+
+ def __init__(self, nodeName:str):
+ self.nodeName = nodeName
+ self.invert = False
+
+ def __str__(self):
+ return type(self).__name__ + "[" + ("!" if self.invert else "") + self.nodeName + "]"
+
+
+
+#
+# Either {@code ID} at start of path or {@code ...//ID} in middle of path.
+#
+class XPathRuleAnywhereElement(XPathElement):
+
+ def __init__(self, ruleName:str, ruleIndex:int):
+ super().__init__(ruleName)
+ self.ruleIndex = ruleIndex
+
+ def evaluate(self, t:ParseTree):
+ # return all ParserRuleContext descendants of t that match ruleIndex (or do not match if inverted)
+ return filter(lambda c: isinstance(c, ParserRuleContext) and (self.invert ^ (c.getRuleIndex() == self.ruleIndex)), Trees.descendants(t))
+
+class XPathRuleElement(XPathElement):
+
+ def __init__(self, ruleName:str, ruleIndex:int):
+ super().__init__(ruleName)
+ self.ruleIndex = ruleIndex
+
+ def evaluate(self, t:ParseTree):
+ # return all ParserRuleContext children of t that match ruleIndex (or do not match if inverted)
+ return filter(lambda c: isinstance(c, ParserRuleContext) and (self.invert ^ (c.getRuleIndex() == self.ruleIndex)), Trees.getChildren(t))
+
+class XPathTokenAnywhereElement(XPathElement):
+
+ def __init__(self, ruleName:str, tokenType:int):
+ super().__init__(ruleName)
+ self.tokenType = tokenType
+
+ def evaluate(self, t:ParseTree):
+ # return all TerminalNode descendants of t that match tokenType (or do not match if inverted)
+ return filter(lambda c: isinstance(c, TerminalNode) and (self.invert ^ (c.symbol.type == self.tokenType)), Trees.descendants(t))
+
+class XPathTokenElement(XPathElement):
+
+ def __init__(self, ruleName:str, tokenType:int):
+ super().__init__(ruleName)
+ self.tokenType = tokenType
+
+ def evaluate(self, t:ParseTree):
+ # return all TerminalNode children of t that match tokenType (or do not match if inverted)
+ return filter(lambda c: isinstance(c, TerminalNode) and (self.invert ^ (c.symbol.type == self.tokenType)), Trees.getChildren(t))
+
+
+class XPathWildcardAnywhereElement(XPathElement):
+
+ def __init__(self):
+ super().__init__(XPath.WILDCARD)
+
+ def evaluate(self, t:ParseTree):
+ if self.invert:
+ return list() # !* is weird but valid (empty)
+ else:
+ return Trees.descendants(t)
+
+
+class XPathWildcardElement(XPathElement):
+
+ def __init__(self):
+ super().__init__(XPath.WILDCARD)
+
+
+ def evaluate(self, t:ParseTree):
+ if self.invert:
+ return list() # !* is weird but valid (empty)
+ else:
+ return Trees.getChildren(t)
diff --git a/venv/Lib/site-packages/antlr4/xpath/XPathLexer.py b/venv/Lib/site-packages/antlr4/xpath/XPathLexer.py
new file mode 100644
index 0000000000000000000000000000000000000000..d608d466a8ff177a3a7a0a02015996798fbd335c
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/xpath/XPathLexer.py
@@ -0,0 +1,95 @@
+# Generated from XPathLexer.g4 by ANTLR 4.13.1
+from antlr4 import *
+from io import StringIO
+import sys
+if sys.version_info[1] > 5:
+ from typing import TextIO
+else:
+ from typing.io import TextIO
+
+
+def serializedATN():
+ return [
+ 4,0,8,50,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,
+ 6,7,6,2,7,7,7,1,0,1,0,1,0,1,1,1,1,1,2,1,2,1,3,1,3,1,4,1,4,5,4,29,
+ 8,4,10,4,12,4,32,9,4,1,4,1,4,1,5,1,5,3,5,38,8,5,1,6,1,6,1,7,1,7,
+ 5,7,44,8,7,10,7,12,7,47,9,7,1,7,1,7,1,45,0,8,1,3,3,4,5,5,7,6,9,7,
+ 11,0,13,0,15,8,1,0,2,5,0,48,57,95,95,183,183,768,879,8255,8256,13,
+ 0,65,90,97,122,192,214,216,246,248,767,880,893,895,8191,8204,8205,
+ 8304,8591,11264,12271,12289,55295,63744,64975,65008,65533,50,0,1,
+ 1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,0,0,0,0,15,1,0,
+ 0,0,1,17,1,0,0,0,3,20,1,0,0,0,5,22,1,0,0,0,7,24,1,0,0,0,9,26,1,0,
+ 0,0,11,37,1,0,0,0,13,39,1,0,0,0,15,41,1,0,0,0,17,18,5,47,0,0,18,
+ 19,5,47,0,0,19,2,1,0,0,0,20,21,5,47,0,0,21,4,1,0,0,0,22,23,5,42,
+ 0,0,23,6,1,0,0,0,24,25,5,33,0,0,25,8,1,0,0,0,26,30,3,13,6,0,27,29,
+ 3,11,5,0,28,27,1,0,0,0,29,32,1,0,0,0,30,28,1,0,0,0,30,31,1,0,0,0,
+ 31,33,1,0,0,0,32,30,1,0,0,0,33,34,6,4,0,0,34,10,1,0,0,0,35,38,3,
+ 13,6,0,36,38,7,0,0,0,37,35,1,0,0,0,37,36,1,0,0,0,38,12,1,0,0,0,39,
+ 40,7,1,0,0,40,14,1,0,0,0,41,45,5,39,0,0,42,44,9,0,0,0,43,42,1,0,
+ 0,0,44,47,1,0,0,0,45,46,1,0,0,0,45,43,1,0,0,0,46,48,1,0,0,0,47,45,
+ 1,0,0,0,48,49,5,39,0,0,49,16,1,0,0,0,4,0,30,37,45,1,1,4,0
+ ]
+
+class XPathLexer(Lexer):
+
+ atn = ATNDeserializer().deserialize(serializedATN())
+
+ decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ]
+
+ TOKEN_REF = 1
+ RULE_REF = 2
+ ANYWHERE = 3
+ ROOT = 4
+ WILDCARD = 5
+ BANG = 6
+ ID = 7
+ STRING = 8
+
+ channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ]
+
+ modeNames = [ "DEFAULT_MODE" ]
+
+ literalNames = [ "",
+ "'//'", "'/'", "'*'", "'!'" ]
+
+ symbolicNames = [ "",
+ "TOKEN_REF", "RULE_REF", "ANYWHERE", "ROOT", "WILDCARD", "BANG",
+ "ID", "STRING" ]
+
+ ruleNames = [ "ANYWHERE", "ROOT", "WILDCARD", "BANG", "ID", "NameChar",
+ "NameStartChar", "STRING" ]
+
+ grammarFileName = "XPathLexer.g4"
+
+ def __init__(self, input=None, output:TextIO = sys.stdout):
+ super().__init__(input, output)
+ self.checkVersion("4.13.1")
+ self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache())
+ self._actions = None
+ self._predicates = None
+
+
+ def action(self, localctx:RuleContext, ruleIndex:int, actionIndex:int):
+ if self._actions is None:
+ actions = dict()
+ actions[4] = self.ID_action
+ self._actions = actions
+ action = self._actions.get(ruleIndex, None)
+ if action is not None:
+ action(localctx, actionIndex)
+ else:
+ raise Exception("No registered action for:" + str(ruleIndex))
+
+
+ def ID_action(self, localctx:RuleContext , actionIndex:int):
+ if actionIndex == 0:
+
+ char = self.text[0]
+ if char.isupper():
+ self.type = XPathLexer.TOKEN_REF
+ else:
+ self.type = XPathLexer.RULE_REF
+
+
+
+
diff --git a/venv/Lib/site-packages/antlr4/xpath/__init__.py b/venv/Lib/site-packages/antlr4/xpath/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..216c000dc5ffc8e53cc9c596e420c1e67604d1aa
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4/xpath/__init__.py
@@ -0,0 +1 @@
+__author__ = 'ericvergnaud'
diff --git a/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/INSTALLER b/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/INSTALLER
new file mode 100644
index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/METADATA b/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/METADATA
new file mode 100644
index 0000000000000000000000000000000000000000..06616d0521a8a1ca2584d61433f0b4825d9c936e
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/METADATA
@@ -0,0 +1,10 @@
+Metadata-Version: 2.1
+Name: antlr4-python3-runtime
+Version: 4.13.2
+Summary: ANTLR 4.13.2 runtime for Python 3
+Author: Terence Parr, Sam Harwell
+Author-email: Eric Vergnaud
+License: BSD
+Project-URL: Homepage, http://www.antlr.org
+Requires-Dist: typing ; python_version < "3.5"
+
diff --git a/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/RECORD b/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/RECORD
new file mode 100644
index 0000000000000000000000000000000000000000..5474422f826662218bfc6994292155411e20755a
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/RECORD
@@ -0,0 +1,123 @@
+../../Scripts/pygrun.exe,sha256=7NCqZVoOSClEud3VNY2jRZe_jOhgJ0DJatU2BrpDh3A,108389
+antlr4/BufferedTokenStream.py,sha256=_BwmzOH1TO6yL2yC_ZaUzkghq8wzc0UPHfI3UpnZUwM,10780
+antlr4/CommonTokenFactory.py,sha256=Tv16zg_pWD1Dv3IphsxFu8nwWdLeXYcqJ8CC5yHwjH8,2110
+antlr4/CommonTokenStream.py,sha256=NNJHXwRg2_Zn46ZhJyDxZtvZzsPWhb6JjXa7BjM45eg,2770
+antlr4/FileStream.py,sha256=-ZR_-jl_If9IIBYLINIwlQrlTSmu5k1VUKDc3ie7WR4,868
+antlr4/InputStream.py,sha256=sggjE2jEGvSgQmxFvqeeuT3aOVgcH5tS7mMybW8wKS4,2334
+antlr4/IntervalSet.py,sha256=Cd0WKhd_kYbiLYKkDNncgSM19GAuS7OaTOC4-5Yubs4,5965
+antlr4/LL1Analyzer.py,sha256=oJBvO7_S8cAlb_D4qWNxd2IlK0qP4ka-oeoDxx16CZ4,7752
+antlr4/Lexer.py,sha256=C72hqayfkympxb46AcSnhPD9kVZ0quWgboGxa6gcIcg,11542
+antlr4/ListTokenSource.py,sha256=IffLMo7YQnD_CjKryrrgNWSk0q5QSYd7puZyyUk7vOk,5356
+antlr4/Parser.py,sha256=F2Q25z0-__KHfa354KQhDu3ZOVzLFfag3s2ixJ4dl_o,22883
+antlr4/ParserInterpreter.py,sha256=-QU9kn4x3WCQ-LSA99R231HoicTqakiHZ5KM72l-hIo,7206
+antlr4/ParserRuleContext.py,sha256=wHAVdOxMAO5jkUqloTXVzn_xYnJhiHbvvuhZpth0ZF8,6762
+antlr4/PredictionContext.py,sha256=SjzTw83lr7MNUqhCe9onMkEJMh5kWyJePmu0WKwkpdw,23491
+antlr4/Recognizer.py,sha256=XLDaKA9TSdWo79CrKc2Yy2uc1DVUMOFKkrCGY3tce0E,5384
+antlr4/RuleContext.py,sha256=GiviRv2k_al1IBgdJOEEoD0ohJaVd-_h5T_CPG_Bsmg,8099
+antlr4/StdinStream.py,sha256=MMSH4zN8T6i_nu-3_TlN-3E4nPM4b5KgK4GT6n_FUQA,303
+antlr4/Token.py,sha256=OtWCab4Ut52X_nLLAA-8x4Zl6xaF6TEN-0033uaoaEo,5206
+antlr4/TokenStreamRewriter.py,sha256=cuErQTrXwC_0kqVv3MsTWGZSm-E1Vy1yzA-3SOhKd_s,10324
+antlr4/Utils.py,sha256=Oyg8CJCRL1TrF_QSB_LLlVdWOB4loVcKOgFNT-icO7c,931
+antlr4/__init__.py,sha256=g8UGpflnlMWcAyLtihejzrgAP1Uo3b9GhwfI8QnZjtw,1125
+antlr4/__pycache__/BufferedTokenStream.cpython-311.pyc,,
+antlr4/__pycache__/CommonTokenFactory.cpython-311.pyc,,
+antlr4/__pycache__/CommonTokenStream.cpython-311.pyc,,
+antlr4/__pycache__/FileStream.cpython-311.pyc,,
+antlr4/__pycache__/InputStream.cpython-311.pyc,,
+antlr4/__pycache__/IntervalSet.cpython-311.pyc,,
+antlr4/__pycache__/LL1Analyzer.cpython-311.pyc,,
+antlr4/__pycache__/Lexer.cpython-311.pyc,,
+antlr4/__pycache__/ListTokenSource.cpython-311.pyc,,
+antlr4/__pycache__/Parser.cpython-311.pyc,,
+antlr4/__pycache__/ParserInterpreter.cpython-311.pyc,,
+antlr4/__pycache__/ParserRuleContext.cpython-311.pyc,,
+antlr4/__pycache__/PredictionContext.cpython-311.pyc,,
+antlr4/__pycache__/Recognizer.cpython-311.pyc,,
+antlr4/__pycache__/RuleContext.cpython-311.pyc,,
+antlr4/__pycache__/StdinStream.cpython-311.pyc,,
+antlr4/__pycache__/Token.cpython-311.pyc,,
+antlr4/__pycache__/TokenStreamRewriter.cpython-311.pyc,,
+antlr4/__pycache__/Utils.cpython-311.pyc,,
+antlr4/__pycache__/__init__.cpython-311.pyc,,
+antlr4/__pycache__/_pygrun.cpython-311.pyc,,
+antlr4/_pygrun.py,sha256=0iyrI1ZYoDznH_IZdtqtazTNuyZSvqLz2D4WBnbVNbI,6289
+antlr4/atn/ATN.py,sha256=LYE8kT-D8FpUd5fpOtyOLqvXLFkUSa83TVFowhCWAiY,5789
+antlr4/atn/ATNConfig.py,sha256=tNdIC6_GrxXllHBx3npAWyDh6KrohLZDV_XyPrydRMY,6565
+antlr4/atn/ATNConfigSet.py,sha256=hyjV-UCZ67Sf-JEnd0Y4RWuWXkg72JIoyvLzfkk79d4,8338
+antlr4/atn/ATNDeserializationOptions.py,sha256=lUV_bGW6mxj7t20esda5Yv-X9m-U_x1-0xaLifhXIPo,1010
+antlr4/atn/ATNDeserializer.py,sha256=ZihaO-nsABeJ6QocgY4Wn-IoFRQHSxQ3yXDHrx0B2wU,18954
+antlr4/atn/ATNSimulator.py,sha256=mDc-G3GF3kSeqpfGDabUOLJ0WLVTqibxZlkvXQYmBRk,2298
+antlr4/atn/ATNState.py,sha256=NbndISWUwFDF_vuBfbTiZZ8GPHoQa6UXdqbD-yjJE7c,7663
+antlr4/atn/ATNType.py,sha256=xgv8AMVU7tc07U73_hRTm1AiZ7MvGhoaP5fTiOrrCGg,422
+antlr4/atn/LexerATNSimulator.py,sha256=kYXRwUvHptSRU8T_K9pSrGlCk9YypWeHlAcjgry1VVo,25465
+antlr4/atn/LexerAction.py,sha256=KUeJwKekBch0m1poSPskHIh-15dcKAG4lR7zlq98tzc,10014
+antlr4/atn/LexerActionExecutor.py,sha256=7rlg17THcwLsuTmh7NsLrTbRH4DTrm8qIdW9_235CEc,6420
+antlr4/atn/ParserATNSimulator.py,sha256=odvwc03AI-7Jpkbw6poFxdbh0jWKzDZDvwOFj5lK-BU,80825
+antlr4/atn/PredictionMode.py,sha256=i8B7MULA7v-qbXeCY_xp6sgi21kHM6kybqIrG6rSrro,22486
+antlr4/atn/SemanticContext.py,sha256=GRaQFv8K7qSoN5N-M-tLgfRdCCzuxJHgYrBVI_Lz2fU,10641
+antlr4/atn/Transition.py,sha256=ZAsEFpa5I_n-zxD6U-DauM5_33jFK65x3PWu6-NW0RA,8762
+antlr4/atn/__init__.py,sha256=gsnQdtTH8IUgCiVUpQfzhxx2pFRvksW76SjwIk3fYSk,28
+antlr4/atn/__pycache__/ATN.cpython-311.pyc,,
+antlr4/atn/__pycache__/ATNConfig.cpython-311.pyc,,
+antlr4/atn/__pycache__/ATNConfigSet.cpython-311.pyc,,
+antlr4/atn/__pycache__/ATNDeserializationOptions.cpython-311.pyc,,
+antlr4/atn/__pycache__/ATNDeserializer.cpython-311.pyc,,
+antlr4/atn/__pycache__/ATNSimulator.cpython-311.pyc,,
+antlr4/atn/__pycache__/ATNState.cpython-311.pyc,,
+antlr4/atn/__pycache__/ATNType.cpython-311.pyc,,
+antlr4/atn/__pycache__/LexerATNSimulator.cpython-311.pyc,,
+antlr4/atn/__pycache__/LexerAction.cpython-311.pyc,,
+antlr4/atn/__pycache__/LexerActionExecutor.cpython-311.pyc,,
+antlr4/atn/__pycache__/ParserATNSimulator.cpython-311.pyc,,
+antlr4/atn/__pycache__/PredictionMode.cpython-311.pyc,,
+antlr4/atn/__pycache__/SemanticContext.cpython-311.pyc,,
+antlr4/atn/__pycache__/Transition.cpython-311.pyc,,
+antlr4/atn/__pycache__/__init__.cpython-311.pyc,,
+antlr4/dfa/DFA.py,sha256=weIh0uaRfakP12mFvHo7U0tqO3GONV3-nHFkc2xk-ZE,5388
+antlr4/dfa/DFASerializer.py,sha256=1st_HO85yXLYy7gInTEnkztgA6am4CT-yReh-mazp9E,2518
+antlr4/dfa/DFAState.py,sha256=R7JwKf0GtAEs9J_MD_Y0WKcuzdt0BVX1sow-uv9yFYc,5583
+antlr4/dfa/__init__.py,sha256=gsnQdtTH8IUgCiVUpQfzhxx2pFRvksW76SjwIk3fYSk,28
+antlr4/dfa/__pycache__/DFA.cpython-311.pyc,,
+antlr4/dfa/__pycache__/DFASerializer.cpython-311.pyc,,
+antlr4/dfa/__pycache__/DFAState.cpython-311.pyc,,
+antlr4/dfa/__pycache__/__init__.cpython-311.pyc,,
+antlr4/error/DiagnosticErrorListener.py,sha256=EwS2D_Ox6CmvCa16NPJ9ud4QYPHmlPXt6-Wdn1h5Kg8,4430
+antlr4/error/ErrorListener.py,sha256=yP_MDguol4Cj0_pEPyNzeH3v4ZvUjW5iwDjhYTVAHbE,2722
+antlr4/error/ErrorStrategy.py,sha256=0mhzFL57ZVnjKkGrtadta93Zm3NXdF-HW10DVD07VXs,30391
+antlr4/error/Errors.py,sha256=MrGp-FvVnp1cGu2iERIhTjC0CHmoWRU0UjHzLiWtKH4,6785
+antlr4/error/__init__.py,sha256=gsnQdtTH8IUgCiVUpQfzhxx2pFRvksW76SjwIk3fYSk,28
+antlr4/error/__pycache__/DiagnosticErrorListener.cpython-311.pyc,,
+antlr4/error/__pycache__/ErrorListener.cpython-311.pyc,,
+antlr4/error/__pycache__/ErrorStrategy.cpython-311.pyc,,
+antlr4/error/__pycache__/Errors.cpython-311.pyc,,
+antlr4/error/__pycache__/__init__.cpython-311.pyc,,
+antlr4/tree/Chunk.py,sha256=oCIZjolLq9xkxtVDROEDxfUGgndcEnsDW0eUmLM7Gpk,695
+antlr4/tree/ParseTreeMatch.py,sha256=Dc6GVWSUqoIAFXUaUZqUwCUlZfTcgUbGLGzNf6QxQvE,4485
+antlr4/tree/ParseTreePattern.py,sha256=rGVYxhs9wYLNoR44sjdiNwXROkooJLwoPJAOxn8K4K8,2835
+antlr4/tree/ParseTreePatternMatcher.py,sha256=HtE9yi1Urr2QPLGLJDBvr0lxv6bjuj9CHl-4clahSe8,16388
+antlr4/tree/RuleTagToken.py,sha256=n4zXcmrrfsGyl91pj5ZYcc_CeKMhPrvYkUdppgMBpbY,2022
+antlr4/tree/TokenTagToken.py,sha256=S3o3DJhfzL5kpClxsKyI-Il-xvuuZQiBAIsLCKFjRHo,1576
+antlr4/tree/Tree.py,sha256=ZI7U_5IxBLm_IrnfJOtb12BCPIWyzfeZtLnhHKVVZIw,5572
+antlr4/tree/Trees.py,sha256=JtQ7cYWmKwI9TIBP6y9XIgjlNS4mYjv3ARwOfwWc5Vg,3968
+antlr4/tree/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+antlr4/tree/__pycache__/Chunk.cpython-311.pyc,,
+antlr4/tree/__pycache__/ParseTreeMatch.cpython-311.pyc,,
+antlr4/tree/__pycache__/ParseTreePattern.cpython-311.pyc,,
+antlr4/tree/__pycache__/ParseTreePatternMatcher.cpython-311.pyc,,
+antlr4/tree/__pycache__/RuleTagToken.cpython-311.pyc,,
+antlr4/tree/__pycache__/TokenTagToken.cpython-311.pyc,,
+antlr4/tree/__pycache__/Tree.cpython-311.pyc,,
+antlr4/tree/__pycache__/Trees.cpython-311.pyc,,
+antlr4/tree/__pycache__/__init__.cpython-311.pyc,,
+antlr4/xpath/XPath.py,sha256=qoihVNLvdI5AFi_M3YWoiBFwGO0-x68pCSNOfHgKQbI,9661
+antlr4/xpath/XPathLexer.py,sha256=tvbwugN5Fwfpt5ZkKpnBFvoW5SJMx0fuMGU0CFNjSKI,3448
+antlr4/xpath/__init__.py,sha256=gsnQdtTH8IUgCiVUpQfzhxx2pFRvksW76SjwIk3fYSk,28
+antlr4/xpath/__pycache__/XPath.cpython-311.pyc,,
+antlr4/xpath/__pycache__/XPathLexer.cpython-311.pyc,,
+antlr4/xpath/__pycache__/__init__.cpython-311.pyc,,
+antlr4_python3_runtime-4.13.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+antlr4_python3_runtime-4.13.2.dist-info/METADATA,sha256=Q8toUUsCLG0kDHLxZtejxgdfO4VFZfDL4CY7x9cN0U4,304
+antlr4_python3_runtime-4.13.2.dist-info/RECORD,,
+antlr4_python3_runtime-4.13.2.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
+antlr4_python3_runtime-4.13.2.dist-info/entry_points.txt,sha256=M2tWLwWgEVV1Djr6ugO3b3902YJIpTDHoM8BFMAt4P4,47
+antlr4_python3_runtime-4.13.2.dist-info/top_level.txt,sha256=OsoZsh9bb30wgXb2zBUjdDwYg46MfV-RVZA6Pk8pcB0,7
diff --git a/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/WHEEL b/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/WHEEL
new file mode 100644
index 0000000000000000000000000000000000000000..1a9c53588bf958814188ba9a6e13d50b924fdccd
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: setuptools (72.1.0)
+Root-Is-Purelib: true
+Tag: py3-none-any
+
diff --git a/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/entry_points.txt b/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/entry_points.txt
new file mode 100644
index 0000000000000000000000000000000000000000..32c27e63d238254aa07b5fdddce1ff046b291618
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/entry_points.txt
@@ -0,0 +1,2 @@
+[console_scripts]
+pygrun = antlr4._pygrun:main
diff --git a/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/top_level.txt b/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3dee19f3e13c2cbbb49b818e6ac67c63f77b865f
--- /dev/null
+++ b/venv/Lib/site-packages/antlr4_python3_runtime-4.13.2.dist-info/top_level.txt
@@ -0,0 +1 @@
+antlr4
diff --git a/venv/Lib/site-packages/anyio-4.14.0.dist-info/INSTALLER b/venv/Lib/site-packages/anyio-4.14.0.dist-info/INSTALLER
new file mode 100644
index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68
--- /dev/null
+++ b/venv/Lib/site-packages/anyio-4.14.0.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/Lib/site-packages/anyio-4.14.0.dist-info/METADATA b/venv/Lib/site-packages/anyio-4.14.0.dist-info/METADATA
new file mode 100644
index 0000000000000000000000000000000000000000..7840c30d940b845ac1efb8e40f8f2be59763aff8
--- /dev/null
+++ b/venv/Lib/site-packages/anyio-4.14.0.dist-info/METADATA
@@ -0,0 +1,107 @@
+Metadata-Version: 2.4
+Name: anyio
+Version: 4.14.0
+Summary: High-level concurrency and networking framework on top of asyncio or Trio
+Author-email: Alex GrΓΆnholm
+License-Expression: MIT
+Project-URL: Documentation, https://anyio.readthedocs.io/en/latest/
+Project-URL: Changelog, https://anyio.readthedocs.io/en/stable/versionhistory.html
+Project-URL: Source code, https://github.com/agronholm/anyio
+Project-URL: Issue tracker, https://github.com/agronholm/anyio/issues
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Framework :: AnyIO
+Classifier: Typing :: Typed
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
+Classifier: Programming Language :: Python :: 3.15
+Requires-Python: >=3.10
+Description-Content-Type: text/x-rst
+License-File: LICENSE
+Requires-Dist: exceptiongroup>=1.0.2; python_version < "3.11"
+Requires-Dist: idna>=2.8
+Requires-Dist: typing_extensions>=4.5; python_version < "3.13"
+Provides-Extra: trio
+Requires-Dist: trio>=0.32.0; extra == "trio"
+Dynamic: license-file
+
+.. image:: https://github.com/agronholm/anyio/actions/workflows/test.yml/badge.svg
+ :target: https://github.com/agronholm/anyio/actions/workflows/test.yml
+ :alt: Build Status
+.. image:: https://coveralls.io/repos/github/agronholm/anyio/badge.svg?branch=master
+ :target: https://coveralls.io/github/agronholm/anyio?branch=master
+ :alt: Code Coverage
+.. image:: https://readthedocs.org/projects/anyio/badge/?version=latest
+ :target: https://anyio.readthedocs.io/en/latest/?badge=latest
+ :alt: Documentation
+.. image:: https://badges.gitter.im/gitterHQ/gitter.svg
+ :target: https://gitter.im/python-trio/AnyIO
+ :alt: Gitter chat
+.. image:: https://tidelift.com/badges/package/pypi/anyio
+ :target: https://tidelift.com/subscription/pkg/pypi-anyio
+ :alt: Tidelift
+
+AnyIO is an asynchronous networking and concurrency library that works on top of either asyncio_ or
+Trio_. It implements Trio-like `structured concurrency`_ (SC) on top of asyncio and works in harmony
+with the native SC of Trio itself.
+
+Applications and libraries written against AnyIO's API will run unmodified on either asyncio_ or
+Trio_. AnyIO can also be adopted into a library or application incrementally β bit by bit, no full
+refactoring necessary. It will blend in with the native libraries of your chosen backend.
+
+To find out why you might want to use AnyIO's APIs instead of asyncio's, you can read about it
+`here `_.
+
+Documentation
+-------------
+
+View full documentation at: https://anyio.readthedocs.io/
+
+Features
+--------
+
+AnyIO offers the following functionality:
+
+* Task groups (nurseries_ in trio terminology)
+* High-level networking (TCP, UDP and UNIX sockets)
+
+ * `Happy eyeballs`_ algorithm for TCP connections (more robust than that of asyncio on Python
+ 3.8)
+ * async/await style UDP sockets (unlike asyncio where you still have to use Transports and
+ Protocols)
+
+* A versatile API for byte streams and object streams
+* Inter-task synchronization and communication (locks, conditions, events, semaphores, object
+ streams)
+* Worker threads
+* Subprocesses
+* Subinterpreter support for code parallelization (on Python 3.13 and later)
+* Asynchronous file I/O (using worker threads)
+* Signal handling
+* Asynchronous versions of the functools_ and itertools_ modules
+
+AnyIO also comes with its own pytest_ plugin which also supports asynchronous fixtures.
+It even works with the popular Hypothesis_ library.
+
+.. _asyncio: https://docs.python.org/3/library/asyncio.html
+.. _Trio: https://github.com/python-trio/trio
+.. _structured concurrency: https://en.wikipedia.org/wiki/Structured_concurrency
+.. _nurseries: https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning
+.. _Happy eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs
+.. _pytest: https://docs.pytest.org/en/latest/
+.. _functools: https://docs.python.org/3/library/functools.html
+.. _itertools: https://docs.python.org/3/library/itertools.html
+.. _Hypothesis: https://hypothesis.works/
+
+Security contact information
+----------------------------
+
+To report a security vulnerability, please use the `Tidelift security contact`_.
+Tidelift will coordinate the fix and disclosure.
+
+.. _Tidelift security contact: https://tidelift.com/security
diff --git a/venv/Lib/site-packages/anyio-4.14.0.dist-info/RECORD b/venv/Lib/site-packages/anyio-4.14.0.dist-info/RECORD
new file mode 100644
index 0000000000000000000000000000000000000000..2630359e3f18589e5db2fe0e91118985190f4407
--- /dev/null
+++ b/venv/Lib/site-packages/anyio-4.14.0.dist-info/RECORD
@@ -0,0 +1,94 @@
+anyio-4.14.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+anyio-4.14.0.dist-info/METADATA,sha256=ZozV8u8z7Ya7tmsk9Uetxz7-QFNpHH2nVBLy041h6xo,4645
+anyio-4.14.0.dist-info/RECORD,,
+anyio-4.14.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
+anyio-4.14.0.dist-info/entry_points.txt,sha256=_d6Yu6uiaZmNe0CydowirE9Cmg7zUL2g08tQpoS3Qvc,39
+anyio-4.14.0.dist-info/licenses/LICENSE,sha256=U2GsncWPLvX9LpsJxoKXwX8ElQkJu8gCO9uC6s8iwrA,1081
+anyio-4.14.0.dist-info/top_level.txt,sha256=QglSMiWX8_5dpoVAEIHdEYzvqFMdSYWmCj6tYw2ITkQ,6
+anyio/__init__.py,sha256=HitUIfzvAojSeaHVmJ9rFn8k_yI63G6s_jUL2QChf4U,6405
+anyio/__pycache__/__init__.cpython-311.pyc,,
+anyio/__pycache__/from_thread.cpython-311.pyc,,
+anyio/__pycache__/functools.cpython-311.pyc,,
+anyio/__pycache__/itertools.cpython-311.pyc,,
+anyio/__pycache__/lowlevel.cpython-311.pyc,,
+anyio/__pycache__/pytest_plugin.cpython-311.pyc,,
+anyio/__pycache__/to_interpreter.cpython-311.pyc,,
+anyio/__pycache__/to_process.cpython-311.pyc,,
+anyio/__pycache__/to_thread.cpython-311.pyc,,
+anyio/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+anyio/_backends/__pycache__/__init__.cpython-311.pyc,,
+anyio/_backends/__pycache__/_asyncio.cpython-311.pyc,,
+anyio/_backends/__pycache__/_trio.cpython-311.pyc,,
+anyio/_backends/_asyncio.py,sha256=kX_Zv3F_SnWqWqSLmfPsDFxvsJLaATSeivzg6Gho3Rs,101971
+anyio/_backends/_trio.py,sha256=vR0ZgxVnOo4AHhHcHVG0worMc-3ZNpAZ6Vxh0m0ZZC0,45189
+anyio/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+anyio/_core/__pycache__/__init__.cpython-311.pyc,,
+anyio/_core/__pycache__/_asyncio_selector_thread.cpython-311.pyc,,
+anyio/_core/__pycache__/_contextmanagers.cpython-311.pyc,,
+anyio/_core/__pycache__/_eventloop.cpython-311.pyc,,
+anyio/_core/__pycache__/_exceptions.cpython-311.pyc,,
+anyio/_core/__pycache__/_fileio.cpython-311.pyc,,
+anyio/_core/__pycache__/_resources.cpython-311.pyc,,
+anyio/_core/__pycache__/_signals.cpython-311.pyc,,
+anyio/_core/__pycache__/_sockets.cpython-311.pyc,,
+anyio/_core/__pycache__/_streams.cpython-311.pyc,,
+anyio/_core/__pycache__/_subprocesses.cpython-311.pyc,,
+anyio/_core/__pycache__/_synchronization.cpython-311.pyc,,
+anyio/_core/__pycache__/_tasks.cpython-311.pyc,,
+anyio/_core/__pycache__/_tempfile.cpython-311.pyc,,
+anyio/_core/__pycache__/_testing.cpython-311.pyc,,
+anyio/_core/__pycache__/_typedattr.cpython-311.pyc,,
+anyio/_core/_asyncio_selector_thread.py,sha256=2PdxFM3cs02Kp6BSppbvmRT7q7asreTW5FgBxEsflBo,5626
+anyio/_core/_contextmanagers.py,sha256=YInBCabiEeS-UaP_Jdxa1CaFC71ETPW8HZTHIM8Rsc8,7215
+anyio/_core/_eventloop.py,sha256=ByZUeJD9alMfcyTseRo5IzTO0IltEul_Gyq9iqSjqDk,6658
+anyio/_core/_exceptions.py,sha256=OfzLO4Z3Hog1TnipbIn72YNtkoYxS4lHW9MqKDeGc88,4936
+anyio/_core/_fileio.py,sha256=hHfyV0bXDL-R2ZNnInwse3nmTAd36AIz1cBxgmAwzAQ,31358
+anyio/_core/_resources.py,sha256=NbmU5O5UX3xEyACnkmYX28Fmwdl-f-ny0tHym26e0w0,435
+anyio/_core/_signals.py,sha256=mjTBB2hTKNPRlU0IhnijeQedpWOGERDiMjSlJQsFrug,1016
+anyio/_core/_sockets.py,sha256=9FU423j52XBBfGVr6MdzPTdyw8bGrzApZ5m338-AtsY,35286
+anyio/_core/_streams.py,sha256=FczFwIgDpnkK0bODWJXMpsUJYdvAD04kaUaGzJU8DK0,1806
+anyio/_core/_subprocesses.py,sha256=tkmkPKEkEaiMD8C9WRZBlmgjOYRDRbZdte6e-unay2E,7916
+anyio/_core/_synchronization.py,sha256=U14eUp9tqcP95OcCG7s3A1MZU9WLw84lOS4YB-H795s,21591
+anyio/_core/_tasks.py,sha256=ELL2jscaSW0Jw_xA6MtQlm3xwvFEzjTbc1u9Tteyt0I,13244
+anyio/_core/_tempfile.py,sha256=jE2w59FRF3yRo4vjkjfZF2YcqsBZvc66VWRwrJGDYGk,19624
+anyio/_core/_testing.py,sha256=u7MPqGXwpTxqI7hclSdNA30z2GH1Nw258uwKvy_RfBg,2340
+anyio/_core/_typedattr.py,sha256=P4ozZikn3-DbpoYcvyghS_FOYAgbmUxeoU8-L_07pZM,2508
+anyio/abc/__init__.py,sha256=6mWhcl_pGXhrgZVHP_TCfMvIXIOp9mroEFM90fYCU_U,2869
+anyio/abc/__pycache__/__init__.cpython-311.pyc,,
+anyio/abc/__pycache__/_eventloop.cpython-311.pyc,,
+anyio/abc/__pycache__/_resources.cpython-311.pyc,,
+anyio/abc/__pycache__/_sockets.cpython-311.pyc,,
+anyio/abc/__pycache__/_streams.cpython-311.pyc,,
+anyio/abc/__pycache__/_subprocesses.cpython-311.pyc,,
+anyio/abc/__pycache__/_tasks.cpython-311.pyc,,
+anyio/abc/__pycache__/_testing.cpython-311.pyc,,
+anyio/abc/_eventloop.py,sha256=OqWYSEj0TmwL_xniCJt3_jHFWsuMk9THk8tCTGsKapI,10681
+anyio/abc/_resources.py,sha256=DrYvkNN1hH6Uvv5_5uKySvDsnknGVDe8FCKfko0VtN8,783
+anyio/abc/_sockets.py,sha256=OmVDrfemVvF9c5K1tpBgQyV6fn5v0XyCExLAqBOGz9o,13124
+anyio/abc/_streams.py,sha256=HYvna1iZbWcwLROTO6IhLX79RTRLPShZMWe0sG1q54I,7481
+anyio/abc/_subprocesses.py,sha256=cumAPJTktOQtw63IqG0lDpyZqu_l1EElvQHMiwJgL08,2067
+anyio/abc/_tasks.py,sha256=m-FtE4phxeNIELSG7A3H7VUz3jA2Ib5J2JIew8-PS6o,6642
+anyio/abc/_testing.py,sha256=9YYM2AXsYFvf4PLjUEr6yRxDiUeB5QbY_gOg0X_C6lY,2034
+anyio/from_thread.py,sha256=JYsbaCaIB_Iit6kNhtXSteJGt4PcQ7ncq0nIpcelIrg,19265
+anyio/functools.py,sha256=T4JS8IXq-x1S0Lbo2owF8l9fza2KypO147QLeyz4cjs,11797
+anyio/itertools.py,sha256=QV-9mnRCr2yBph8g01QFvN-bQ_Yle-8Sl13YSydBlMI,16168
+anyio/lowlevel.py,sha256=WPtppHfI2qs1nokzjn8elL8LvyqI05AK5Zslhlo71A4,6242
+anyio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+anyio/pytest_plugin.py,sha256=paMpI_VMNQf2bir0LfvgMpXSiYJoHDzWdKUVTyoHmvQ,13609
+anyio/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+anyio/streams/__pycache__/__init__.cpython-311.pyc,,
+anyio/streams/__pycache__/buffered.cpython-311.pyc,,
+anyio/streams/__pycache__/file.cpython-311.pyc,,
+anyio/streams/__pycache__/memory.cpython-311.pyc,,
+anyio/streams/__pycache__/stapled.cpython-311.pyc,,
+anyio/streams/__pycache__/text.cpython-311.pyc,,
+anyio/streams/__pycache__/tls.cpython-311.pyc,,
+anyio/streams/buffered.py,sha256=v3xKtjFHgNV41g2SvMAkA_qd2t9WYlCI1_lNGCAatw0,6650
+anyio/streams/file.py,sha256=msnrotVKGMQomUu_Rj2qz9MvIdUp6d3JGr7MOEO8kV4,4428
+anyio/streams/memory.py,sha256=F0zwzvFJKAhX_LRZGoKzzqDC2oMM-f-yyTBrEYEGOaU,10740
+anyio/streams/stapled.py,sha256=T8Xqwf8K6EgURPxbt1N4i7A8BAk-gScv-GRhjLXIf_o,4390
+anyio/streams/text.py,sha256=BcVAGJw1VRvtIqnv-o0Rb0pwH7p8vwlvl21xHq522ag,5765
+anyio/streams/tls.py,sha256=DQVkXUvsTEYKkBO8dlVU7j_5H8QOtLy4sGi1Wrjqevo,15303
+anyio/to_interpreter.py,sha256=_mLngrMy97TMR6VbW4Y6YzDUk9ZuPcQMPlkuyRh3C9k,7100
+anyio/to_process.py,sha256=68qhLfce7MeXysid4fOpmhfWkgdo7Z7-9BC0VyUciIE,9809
+anyio/to_thread.py,sha256=f6h_k2d743GBv9FhAnhM_YpTvWgIrzBy9cOE0eJ1UJw,2693
diff --git a/venv/Lib/site-packages/anyio-4.14.0.dist-info/WHEEL b/venv/Lib/site-packages/anyio-4.14.0.dist-info/WHEEL
new file mode 100644
index 0000000000000000000000000000000000000000..14a883f292bc96b20c2b76a3081991f2676523a9
--- /dev/null
+++ b/venv/Lib/site-packages/anyio-4.14.0.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: setuptools (82.0.1)
+Root-Is-Purelib: true
+Tag: py3-none-any
+
diff --git a/venv/Lib/site-packages/anyio-4.14.0.dist-info/entry_points.txt b/venv/Lib/site-packages/anyio-4.14.0.dist-info/entry_points.txt
new file mode 100644
index 0000000000000000000000000000000000000000..44dd9bdc3039122cc98014c1439ca254313fd014
--- /dev/null
+++ b/venv/Lib/site-packages/anyio-4.14.0.dist-info/entry_points.txt
@@ -0,0 +1,2 @@
+[pytest11]
+anyio = anyio.pytest_plugin
diff --git a/venv/Lib/site-packages/anyio-4.14.0.dist-info/licenses/LICENSE b/venv/Lib/site-packages/anyio-4.14.0.dist-info/licenses/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..104eebf5a3002fccdaceef3a4cb936173c1c2035
--- /dev/null
+++ b/venv/Lib/site-packages/anyio-4.14.0.dist-info/licenses/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Alex GrΓΆnholm
+
+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.
diff --git a/venv/Lib/site-packages/anyio-4.14.0.dist-info/top_level.txt b/venv/Lib/site-packages/anyio-4.14.0.dist-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c77c069ecc9b7f8b1f97dbcfec905725db0253a8
--- /dev/null
+++ b/venv/Lib/site-packages/anyio-4.14.0.dist-info/top_level.txt
@@ -0,0 +1 @@
+anyio
diff --git a/venv/Lib/site-packages/anyio/__init__.py b/venv/Lib/site-packages/anyio/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..2502c760bcc1d640be2de20f620d52fc3364cb55
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/__init__.py
@@ -0,0 +1,115 @@
+from __future__ import annotations
+
+from ._core._contextmanagers import AsyncContextManagerMixin as AsyncContextManagerMixin
+from ._core._contextmanagers import ContextManagerMixin as ContextManagerMixin
+from ._core._eventloop import current_time as current_time
+from ._core._eventloop import get_all_backends as get_all_backends
+from ._core._eventloop import get_available_backends as get_available_backends
+from ._core._eventloop import get_cancelled_exc_class as get_cancelled_exc_class
+from ._core._eventloop import run as run
+from ._core._eventloop import sleep as sleep
+from ._core._eventloop import sleep_forever as sleep_forever
+from ._core._eventloop import sleep_until as sleep_until
+from ._core._exceptions import BrokenResourceError as BrokenResourceError
+from ._core._exceptions import BrokenWorkerInterpreter as BrokenWorkerInterpreter
+from ._core._exceptions import BrokenWorkerProcess as BrokenWorkerProcess
+from ._core._exceptions import BusyResourceError as BusyResourceError
+from ._core._exceptions import ClosedResourceError as ClosedResourceError
+from ._core._exceptions import ConnectionFailed as ConnectionFailed
+from ._core._exceptions import DelimiterNotFound as DelimiterNotFound
+from ._core._exceptions import EndOfStream as EndOfStream
+from ._core._exceptions import IncompleteRead as IncompleteRead
+from ._core._exceptions import NoEventLoopError as NoEventLoopError
+from ._core._exceptions import RunFinishedError as RunFinishedError
+from ._core._exceptions import TaskCancelled as TaskCancelled
+from ._core._exceptions import TaskFailed as TaskFailed
+from ._core._exceptions import TaskNotFinished as TaskNotFinished
+from ._core._exceptions import TypedAttributeLookupError as TypedAttributeLookupError
+from ._core._exceptions import WouldBlock as WouldBlock
+from ._core._fileio import AsyncFile as AsyncFile
+from ._core._fileio import Path as Path
+from ._core._fileio import open_file as open_file
+from ._core._fileio import wrap_file as wrap_file
+from ._core._resources import aclose_forcefully as aclose_forcefully
+from ._core._signals import open_signal_receiver as open_signal_receiver
+from ._core._sockets import TCPConnectable as TCPConnectable
+from ._core._sockets import UNIXConnectable as UNIXConnectable
+from ._core._sockets import as_connectable as as_connectable
+from ._core._sockets import connect_tcp as connect_tcp
+from ._core._sockets import connect_unix as connect_unix
+from ._core._sockets import create_connected_udp_socket as create_connected_udp_socket
+from ._core._sockets import (
+ create_connected_unix_datagram_socket as create_connected_unix_datagram_socket,
+)
+from ._core._sockets import create_tcp_listener as create_tcp_listener
+from ._core._sockets import create_udp_socket as create_udp_socket
+from ._core._sockets import create_unix_datagram_socket as create_unix_datagram_socket
+from ._core._sockets import create_unix_listener as create_unix_listener
+from ._core._sockets import getaddrinfo as getaddrinfo
+from ._core._sockets import getnameinfo as getnameinfo
+from ._core._sockets import notify_closing as notify_closing
+from ._core._sockets import wait_readable as wait_readable
+from ._core._sockets import wait_socket_readable as wait_socket_readable
+from ._core._sockets import wait_socket_writable as wait_socket_writable
+from ._core._sockets import wait_writable as wait_writable
+from ._core._streams import create_memory_object_stream as create_memory_object_stream
+from ._core._subprocesses import open_process as open_process
+from ._core._subprocesses import run_process as run_process
+from ._core._synchronization import CapacityLimiter as CapacityLimiter
+from ._core._synchronization import (
+ CapacityLimiterStatistics as CapacityLimiterStatistics,
+)
+from ._core._synchronization import Condition as Condition
+from ._core._synchronization import ConditionStatistics as ConditionStatistics
+from ._core._synchronization import Event as Event
+from ._core._synchronization import EventStatistics as EventStatistics
+from ._core._synchronization import Lock as Lock
+from ._core._synchronization import LockStatistics as LockStatistics
+from ._core._synchronization import ResourceGuard as ResourceGuard
+from ._core._synchronization import Semaphore as Semaphore
+from ._core._synchronization import SemaphoreStatistics as SemaphoreStatistics
+from ._core._tasks import TASK_STATUS_IGNORED as TASK_STATUS_IGNORED
+from ._core._tasks import CancelScope as CancelScope
+from ._core._tasks import TaskHandle as TaskHandle
+from ._core._tasks import create_task_group as create_task_group
+from ._core._tasks import current_effective_deadline as current_effective_deadline
+from ._core._tasks import fail_after as fail_after
+from ._core._tasks import move_on_after as move_on_after
+from ._core._tempfile import NamedTemporaryFile as NamedTemporaryFile
+from ._core._tempfile import SpooledTemporaryFile as SpooledTemporaryFile
+from ._core._tempfile import TemporaryDirectory as TemporaryDirectory
+from ._core._tempfile import TemporaryFile as TemporaryFile
+from ._core._tempfile import gettempdir as gettempdir
+from ._core._tempfile import gettempdirb as gettempdirb
+from ._core._tempfile import mkdtemp as mkdtemp
+from ._core._tempfile import mkstemp as mkstemp
+from ._core._testing import TaskInfo as TaskInfo
+from ._core._testing import get_current_task as get_current_task
+from ._core._testing import get_running_tasks as get_running_tasks
+from ._core._testing import wait_all_tasks_blocked as wait_all_tasks_blocked
+from ._core._typedattr import TypedAttributeProvider as TypedAttributeProvider
+from ._core._typedattr import TypedAttributeSet as TypedAttributeSet
+from ._core._typedattr import typed_attribute as typed_attribute
+
+# Re-export imports so they look like they live directly in this package
+for __value in list(locals().values()):
+ if getattr(__value, "__module__", "").startswith("anyio."):
+ __value.__module__ = __name__
+
+
+del __value
+
+
+def __getattr__(attr: str) -> type[BrokenWorkerInterpreter]:
+ """Support deprecated aliases."""
+ if attr == "BrokenWorkerIntepreter":
+ import warnings
+
+ warnings.warn(
+ "The 'BrokenWorkerIntepreter' alias is deprecated, use 'BrokenWorkerInterpreter' instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return BrokenWorkerInterpreter
+
+ raise AttributeError(f"module {__name__!r} has no attribute {attr!r}")
diff --git a/venv/Lib/site-packages/anyio/_backends/__init__.py b/venv/Lib/site-packages/anyio/_backends/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/venv/Lib/site-packages/anyio/_backends/_asyncio.py b/venv/Lib/site-packages/anyio/_backends/_asyncio.py
new file mode 100644
index 0000000000000000000000000000000000000000..a51a150376a93bf193e979779348d18d971a504c
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_backends/_asyncio.py
@@ -0,0 +1,3073 @@
+from __future__ import annotations
+
+import array
+import asyncio
+import concurrent.futures
+import contextvars
+import math
+import os
+import socket
+import sys
+import threading
+import weakref
+from asyncio import (
+ AbstractEventLoop,
+ CancelledError,
+ all_tasks,
+ create_task,
+ current_task,
+ get_running_loop,
+ sleep,
+)
+from asyncio.base_events import _run_until_complete_cb # type: ignore[attr-defined]
+from collections import OrderedDict, deque
+from collections.abc import (
+ AsyncGenerator,
+ AsyncIterator,
+ Awaitable,
+ Callable,
+ Collection,
+ Coroutine,
+ Iterable,
+ Sequence,
+)
+from concurrent.futures import Future
+from contextlib import AbstractContextManager
+from contextvars import Context, copy_context
+from dataclasses import dataclass, field
+from functools import partial, wraps
+from inspect import (
+ CORO_RUNNING,
+ CORO_SUSPENDED,
+ getcoroutinestate,
+)
+from io import IOBase
+from os import PathLike
+from queue import Queue
+from signal import Signals
+from socket import AddressFamily, SocketKind
+from threading import Thread
+from types import CodeType, TracebackType
+from typing import (
+ IO,
+ TYPE_CHECKING,
+ Any,
+ Literal,
+ ParamSpec,
+ TypeVar,
+ cast,
+)
+from weakref import WeakKeyDictionary
+
+from .. import (
+ CapacityLimiterStatistics,
+ EventStatistics,
+ LockStatistics,
+ TaskInfo,
+ abc,
+)
+from .._core._eventloop import (
+ claim_worker_thread,
+ set_current_async_library,
+ threadlocals,
+)
+from .._core._exceptions import (
+ BrokenResourceError,
+ BusyResourceError,
+ ClosedResourceError,
+ EndOfStream,
+ RunFinishedError,
+ WouldBlock,
+)
+from .._core._sockets import convert_ipv6_sockaddr
+from .._core._streams import create_memory_object_stream
+from .._core._synchronization import (
+ CapacityLimiter as BaseCapacityLimiter,
+)
+from .._core._synchronization import Event as BaseEvent
+from .._core._synchronization import Lock as BaseLock
+from .._core._synchronization import (
+ ResourceGuard,
+ SemaphoreStatistics,
+)
+from .._core._synchronization import Semaphore as BaseSemaphore
+from .._core._tasks import CancelScope as BaseCancelScope
+from .._core._tasks import TaskHandle
+from ..abc import (
+ AsyncBackend,
+ IPSockAddrType,
+ SocketListener,
+ UDPPacketType,
+ UNIXDatagramPacketType,
+)
+from ..abc._eventloop import StrOrBytesPath
+from ..abc._tasks import call_for_coroutine, get_callable_name
+from ..lowlevel import RunVar
+from ..streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
+
+if TYPE_CHECKING:
+ from _typeshed import FileDescriptorLike
+else:
+ FileDescriptorLike = object
+
+if sys.version_info >= (3, 11):
+ from asyncio import Runner
+ from typing import TypeVarTuple, Unpack
+else:
+ import contextvars
+ import enum
+ import signal
+ from asyncio import coroutines, events, exceptions, tasks
+
+ from exceptiongroup import BaseExceptionGroup
+ from typing_extensions import TypeVarTuple, Unpack
+
+ class _State(enum.Enum):
+ CREATED = "created"
+ INITIALIZED = "initialized"
+ CLOSED = "closed"
+
+ class Runner:
+ # Copied from CPython 3.11
+ def __init__(
+ self,
+ *,
+ debug: bool | None = None,
+ loop_factory: Callable[[], AbstractEventLoop] | None = None,
+ ):
+ self._state = _State.CREATED
+ self._debug = debug
+ self._loop_factory = loop_factory
+ self._loop: AbstractEventLoop | None = None
+ self._context = None
+ self._interrupt_count = 0
+ self._set_event_loop = False
+
+ def __enter__(self) -> Runner:
+ self._lazy_init()
+ return self
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ self.close()
+
+ def close(self) -> None:
+ """Shutdown and close event loop."""
+ loop = self._loop
+ if self._state is not _State.INITIALIZED or loop is None:
+ return
+ try:
+ _cancel_all_tasks(loop)
+ loop.run_until_complete(loop.shutdown_asyncgens())
+ if hasattr(loop, "shutdown_default_executor"):
+ loop.run_until_complete(loop.shutdown_default_executor())
+ else:
+ loop.run_until_complete(_shutdown_default_executor(loop))
+ finally:
+ if self._set_event_loop:
+ events.set_event_loop(None)
+ loop.close()
+ self._loop = None
+ self._state = _State.CLOSED
+
+ def get_loop(self) -> AbstractEventLoop:
+ """Return embedded event loop."""
+ self._lazy_init()
+ return self._loop
+
+ def run(self, coro: Coroutine[T_Retval], *, context=None) -> T_Retval:
+ """Run a coroutine inside the embedded event loop."""
+ if not coroutines.iscoroutine(coro):
+ raise ValueError(f"a coroutine was expected, got {coro!r}")
+
+ if events._get_running_loop() is not None:
+ # fail fast with short traceback
+ raise RuntimeError(
+ "Runner.run() cannot be called from a running event loop"
+ )
+
+ self._lazy_init()
+
+ if context is None:
+ context = self._context
+ task = context.run(self._loop.create_task, coro)
+
+ if (
+ threading.current_thread() is threading.main_thread()
+ and signal.getsignal(signal.SIGINT) is signal.default_int_handler
+ ):
+ sigint_handler = partial(self._on_sigint, main_task=task)
+ try:
+ signal.signal(signal.SIGINT, sigint_handler)
+ except ValueError:
+ # `signal.signal` may throw if `threading.main_thread` does
+ # not support signals (e.g. embedded interpreter with signals
+ # not registered - see gh-91880)
+ sigint_handler = None
+ else:
+ sigint_handler = None
+
+ self._interrupt_count = 0
+ try:
+ return self._loop.run_until_complete(task)
+ except exceptions.CancelledError:
+ if self._interrupt_count > 0:
+ uncancel = getattr(task, "uncancel", None)
+ if uncancel is not None and uncancel() == 0:
+ raise KeyboardInterrupt # noqa: B904
+ raise # CancelledError
+ finally:
+ if (
+ sigint_handler is not None
+ and signal.getsignal(signal.SIGINT) is sigint_handler
+ ):
+ signal.signal(signal.SIGINT, signal.default_int_handler)
+
+ def _lazy_init(self) -> None:
+ if self._state is _State.CLOSED:
+ raise RuntimeError("Runner is closed")
+ if self._state is _State.INITIALIZED:
+ return
+ if self._loop_factory is None:
+ self._loop = events.new_event_loop()
+ if not self._set_event_loop:
+ # Call set_event_loop only once to avoid calling
+ # attach_loop multiple times on child watchers
+ events.set_event_loop(self._loop)
+ self._set_event_loop = True
+ else:
+ self._loop = self._loop_factory()
+ if self._debug is not None:
+ self._loop.set_debug(self._debug)
+ self._context = contextvars.copy_context()
+ self._state = _State.INITIALIZED
+
+ def _on_sigint(self, signum, frame, main_task: asyncio.Task) -> None:
+ self._interrupt_count += 1
+ if self._interrupt_count == 1 and not main_task.done():
+ main_task.cancel()
+ # wakeup loop if it is blocked by select() with long timeout
+ self._loop.call_soon_threadsafe(lambda: None)
+ return
+ raise KeyboardInterrupt()
+
+ def _cancel_all_tasks(loop: AbstractEventLoop) -> None:
+ to_cancel = tasks.all_tasks(loop)
+ if not to_cancel:
+ return
+
+ for task in to_cancel:
+ task.cancel()
+
+ loop.run_until_complete(tasks.gather(*to_cancel, return_exceptions=True))
+
+ for task in to_cancel:
+ if task.cancelled():
+ continue
+ if task.exception() is not None:
+ loop.call_exception_handler(
+ {
+ "message": "unhandled exception during asyncio.run() shutdown",
+ "exception": task.exception(),
+ "task": task,
+ }
+ )
+
+ async def _shutdown_default_executor(loop: AbstractEventLoop) -> None:
+ """Schedule the shutdown of the default executor."""
+
+ def _do_shutdown(future: asyncio.futures.Future) -> None:
+ try:
+ loop._default_executor.shutdown(wait=True) # type: ignore[attr-defined]
+ loop.call_soon_threadsafe(future.set_result, None)
+ except Exception as ex:
+ loop.call_soon_threadsafe(future.set_exception, ex)
+
+ loop._executor_shutdown_called = True
+ if loop._default_executor is None:
+ return
+ future = loop.create_future()
+ thread = threading.Thread(target=_do_shutdown, args=(future,))
+ thread.start()
+ try:
+ await future
+ finally:
+ thread.join()
+
+
+T_Retval = TypeVar("T_Retval")
+T_co = TypeVar("T_co", covariant=True)
+T_contra = TypeVar("T_contra", contravariant=True)
+PosArgsT = TypeVarTuple("PosArgsT")
+P = ParamSpec("P")
+
+_root_task: RunVar[asyncio.Task | None] = RunVar("_root_task")
+
+
+def find_root_task() -> asyncio.Task:
+ root_task = _root_task.get(None)
+ if root_task is not None and not root_task.done():
+ return root_task
+
+ # Look for a task that has been started via run_until_complete()
+ for task in all_tasks():
+ if task._callbacks and not task.done():
+ callbacks = [cb for cb, context in task._callbacks]
+ for cb in callbacks:
+ if (
+ cb is _run_until_complete_cb
+ or getattr(cb, "__module__", None) == "uvloop.loop"
+ ):
+ _root_task.set(task)
+ return task
+
+ # Look up the topmost task in the AnyIO task tree, if possible
+ task = cast(asyncio.Task, current_task())
+ state = _task_states.get(task)
+ if state:
+ cancel_scope = state.cancel_scope
+ while cancel_scope and cancel_scope._parent_scope is not None:
+ cancel_scope = cancel_scope._parent_scope
+
+ if cancel_scope is not None:
+ return cast(asyncio.Task, cancel_scope._host_task)
+
+ return task
+
+
+#
+# Event loop
+#
+
+_run_vars: WeakKeyDictionary[asyncio.AbstractEventLoop, Any] = WeakKeyDictionary()
+
+
+def _task_started(task: asyncio.Task) -> bool:
+ """Return ``True`` if the task has been started and has not finished."""
+ # The task coro should never be None here, as we never add finished tasks to the
+ # task list
+ coro = task.get_coro()
+ assert coro is not None
+ return getcoroutinestate(coro) in (CORO_RUNNING, CORO_SUSPENDED)
+
+
+#
+# Timeouts and cancellation
+#
+
+
+def is_anyio_cancellation(exc: CancelledError) -> bool:
+ # Sometimes third party frameworks catch a CancelledError and raise a new one, so as
+ # a workaround we have to look at the previous ones in __context__ too for a
+ # matching cancel message
+ while True:
+ if (
+ exc.args
+ and isinstance(exc.args[0], str)
+ and exc.args[0].startswith("Cancelled via cancel scope ")
+ ):
+ return True
+
+ if isinstance(exc.__context__, CancelledError):
+ exc = exc.__context__
+ continue
+
+ return False
+
+
+class CancelScope(BaseCancelScope):
+ __slots__ = (
+ "_active",
+ "_cancel_called",
+ "_cancel_handle",
+ "_cancel_reason",
+ "_cancelled_caught",
+ "_child_scopes",
+ "_deadline",
+ "_host_task",
+ "_parent_scope",
+ "_pending_uncancellations",
+ "_shield",
+ "_tasks",
+ "_timeout_handle",
+ )
+
+ def __new__(
+ cls, *, deadline: float = math.inf, shield: bool = False
+ ) -> CancelScope:
+ return object.__new__(cls)
+
+ def __init__(self, deadline: float = math.inf, shield: bool = False):
+ self._deadline = deadline
+ self._shield = shield
+ self._parent_scope: CancelScope | None = None
+ self._child_scopes: set[CancelScope] = set()
+ self._cancel_called = False
+ self._cancel_reason: str | None = None
+ self._cancelled_caught = False
+ self._active = False
+ self._timeout_handle: asyncio.TimerHandle | None = None
+ self._cancel_handle: asyncio.Handle | None = None
+ self._tasks: set[asyncio.Task] = set()
+ self._host_task: asyncio.Task | None = None
+ if sys.version_info >= (3, 11):
+ self._pending_uncancellations: int | None = 0
+ else:
+ self._pending_uncancellations = None
+
+ def __enter__(self) -> CancelScope:
+ if self._active:
+ raise RuntimeError(
+ "Each CancelScope may only be used for a single 'with' block"
+ )
+
+ self._host_task = host_task = cast(asyncio.Task, current_task())
+ self._tasks.add(host_task)
+ try:
+ task_state = _task_states[host_task]
+ except KeyError:
+ task_state = TaskState(None, self)
+ _task_states[host_task] = task_state
+ else:
+ self._parent_scope = task_state.cancel_scope
+ task_state.cancel_scope = self
+ if self._parent_scope is not None:
+ # If using an eager task factory, the parent scope may not even contain
+ # the host task
+ self._parent_scope._child_scopes.add(self)
+ self._parent_scope._tasks.discard(host_task)
+
+ self._timeout()
+ self._active = True
+
+ # Start cancelling the host task if the scope was cancelled before entering
+ if self._cancel_called:
+ self._deliver_cancellation(self)
+
+ return self
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> bool:
+ del exc_tb
+
+ if not self._active:
+ raise RuntimeError("This cancel scope is not active")
+ if current_task() is not self._host_task:
+ raise RuntimeError(
+ "Attempted to exit cancel scope in a different task than it was "
+ "entered in"
+ )
+
+ assert self._host_task is not None
+ host_task_state = _task_states.get(self._host_task)
+ if host_task_state is None or host_task_state.cancel_scope is not self:
+ raise RuntimeError(
+ "Attempted to exit a cancel scope that isn't the current tasks's "
+ "current cancel scope"
+ )
+
+ try:
+ self._active = False
+ if self._timeout_handle:
+ self._timeout_handle.cancel()
+ self._timeout_handle = None
+
+ self._tasks.remove(self._host_task)
+ if self._parent_scope is not None:
+ self._parent_scope._child_scopes.remove(self)
+ self._parent_scope._tasks.add(self._host_task)
+
+ host_task_state.cancel_scope = self._parent_scope
+
+ # Restart the cancellation effort in the closest visible, cancelled parent
+ # scope if necessary
+ self._restart_cancellation_in_parent()
+
+ # We only swallow the exception iff it was an AnyIO CancelledError, either
+ # directly as exc_val or inside an exception group and there are no cancelled
+ # parent cancel scopes visible to us here
+ if self._cancel_called and not self._parent_cancellation_is_visible_to_us:
+ # For each level-cancel() call made on the host task, call uncancel()
+ while self._pending_uncancellations:
+ self._host_task.uncancel()
+ self._pending_uncancellations -= 1
+
+ # Update cancelled_caught and check for exceptions we must not swallow
+ if isinstance(exc_val, BaseExceptionGroup):
+ cancelleds_caught, remaining = exc_val.split(
+ lambda exc: (
+ isinstance(exc, CancelledError)
+ and is_anyio_cancellation(exc)
+ )
+ )
+
+ if cancelleds_caught is None:
+ return False
+
+ self._cancelled_caught = True
+
+ if remaining is None:
+ return True
+
+ context = remaining.__context__
+ try:
+ # Preserve __cause__ and __suppress_context__ by avoiding `raise
+ # ... from ...`
+ raise remaining
+ finally:
+ # Preserve __context__
+ remaining.__context__ = context
+ del context
+ else:
+ if isinstance(exc_val, CancelledError) and is_anyio_cancellation(
+ exc_val
+ ):
+ self._cancelled_caught = True
+ return True
+ else:
+ return False
+ else:
+ if self._pending_uncancellations:
+ assert self._parent_scope is not None
+ assert self._parent_scope._pending_uncancellations is not None
+ self._parent_scope._pending_uncancellations += (
+ self._pending_uncancellations
+ )
+ self._pending_uncancellations = 0
+
+ return False
+ finally:
+ self._host_task = None
+ del exc_val
+
+ @property
+ def _effectively_cancelled(self) -> bool:
+ cancel_scope: CancelScope | None = self
+ while cancel_scope is not None:
+ if cancel_scope._cancel_called:
+ return True
+
+ if cancel_scope.shield:
+ return False
+
+ cancel_scope = cancel_scope._parent_scope
+
+ return False
+
+ @property
+ def _parent_cancellation_is_visible_to_us(self) -> bool:
+ return (
+ self._parent_scope is not None
+ and not self.shield
+ and self._parent_scope._effectively_cancelled
+ )
+
+ def _timeout(self) -> None:
+ if self._deadline != math.inf:
+ loop = get_running_loop()
+ if loop.time() >= self._deadline:
+ self.cancel("deadline exceeded")
+ else:
+ self._timeout_handle = loop.call_at(self._deadline, self._timeout)
+
+ def _deliver_cancellation(self, origin: CancelScope) -> bool:
+ """
+ Deliver cancellation to directly contained tasks and nested cancel scopes.
+
+ Schedule another run at the end if we still have tasks eligible for
+ cancellation.
+
+ :param origin: the cancel scope that originated the cancellation
+ :return: ``True`` if the delivery needs to be retried on the next cycle
+
+ """
+ should_retry = False
+ current = current_task()
+ for task in self._tasks:
+ should_retry = True
+ if task._must_cancel: # type: ignore[attr-defined]
+ continue
+
+ # The task is eligible for cancellation if it has started
+ if task is not current and (task is self._host_task or _task_started(task)):
+ waiter = task._fut_waiter # type: ignore[attr-defined]
+ if not isinstance(waiter, asyncio.Future) or not waiter.done():
+ task.cancel(origin._cancel_reason)
+ if (
+ task is origin._host_task
+ and origin._pending_uncancellations is not None
+ ):
+ origin._pending_uncancellations += 1
+
+ # Deliver cancellation to child scopes that aren't shielded or running their own
+ # cancellation callbacks
+ for scope in self._child_scopes:
+ if not scope._shield and not scope.cancel_called:
+ should_retry = scope._deliver_cancellation(origin) or should_retry
+
+ # Schedule another callback if there are still tasks left
+ if origin is self:
+ if should_retry:
+ self._cancel_handle = get_running_loop().call_soon(
+ self._deliver_cancellation, origin
+ )
+ else:
+ self._cancel_handle = None
+
+ return should_retry
+
+ def _restart_cancellation_in_parent(self) -> None:
+ """
+ Restart the cancellation effort in the closest directly cancelled parent scope.
+
+ """
+ scope = self._parent_scope
+ while scope is not None:
+ if scope._cancel_called:
+ if scope._cancel_handle is None:
+ scope._deliver_cancellation(scope)
+
+ break
+
+ # No point in looking beyond any shielded scope
+ if scope._shield:
+ break
+
+ scope = scope._parent_scope
+
+ def cancel(self, reason: str | None = None) -> None:
+ if not self._cancel_called:
+ if self._timeout_handle:
+ self._timeout_handle.cancel()
+ self._timeout_handle = None
+
+ self._cancel_called = True
+ self._cancel_reason = f"Cancelled via cancel scope {id(self):x}"
+ if task := current_task():
+ self._cancel_reason += f" by {task}"
+
+ if reason:
+ self._cancel_reason += f"; reason: {reason}"
+
+ if self._host_task is not None:
+ self._deliver_cancellation(self)
+
+ @property
+ def deadline(self) -> float:
+ return self._deadline
+
+ @deadline.setter
+ def deadline(self, value: float) -> None:
+ self._deadline = float(value)
+ if self._timeout_handle is not None:
+ self._timeout_handle.cancel()
+ self._timeout_handle = None
+
+ if self._active and not self._cancel_called:
+ self._timeout()
+
+ @property
+ def cancel_called(self) -> bool:
+ return self._cancel_called
+
+ @property
+ def cancelled_caught(self) -> bool:
+ return self._cancelled_caught
+
+ @property
+ def shield(self) -> bool:
+ return self._shield
+
+ @shield.setter
+ def shield(self, value: bool) -> None:
+ if self._shield != value:
+ self._shield = value
+ if not value:
+ self._restart_cancellation_in_parent()
+
+
+#
+# Task states
+#
+
+
+class TaskState:
+ """
+ Encapsulates auxiliary task information that cannot be added to the Task instance
+ itself because there are no guarantees about its implementation.
+ """
+
+ __slots__ = "parent_id", "cancel_scope", "__weakref__"
+
+ def __init__(self, parent_id: int | None, cancel_scope: CancelScope | None):
+ self.parent_id = parent_id
+ self.cancel_scope = cancel_scope
+
+
+_task_states: WeakKeyDictionary[asyncio.Task, TaskState] = WeakKeyDictionary()
+
+
+#
+# Task groups
+#
+
+
+class _AsyncioTaskStatus(abc.TaskStatus):
+ def __init__(self, future: asyncio.Future, parent_id: int):
+ self._future = future
+ self._parent_id = parent_id
+
+ def started(self, value: T_contra | None = None) -> None:
+ try:
+ self._future.set_result(value)
+ except asyncio.InvalidStateError:
+ if not self._future.cancelled():
+ raise RuntimeError(
+ "called 'started' twice on the same task status"
+ ) from None
+
+ task = cast(asyncio.Task, current_task())
+ _task_states[task].parent_id = self._parent_id
+
+
+if sys.version_info >= (3, 12):
+ _eager_task_factory_code: CodeType | None = asyncio.eager_task_factory.__code__
+else:
+ _eager_task_factory_code = None
+
+
+class TaskGroup(abc.TaskGroup):
+ def __init__(self) -> None:
+ self.cancel_scope: CancelScope = CancelScope()
+ self._entered = False
+ self._exceptions: list[BaseException] = []
+ self._tasks: set[asyncio.Task] = set()
+ self._on_completed_fut: asyncio.Future[None] | None = None
+
+ async def __aenter__(self) -> TaskGroup:
+ if self._entered:
+ raise RuntimeError("TaskGroup cannot be entered more than once")
+
+ self._entered = True
+
+ self.cancel_scope.__enter__()
+ return self
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> bool:
+ try:
+ if exc_val is not None:
+ self.cancel_scope.cancel()
+ if not isinstance(exc_val, CancelledError):
+ self._exceptions.append(exc_val)
+
+ loop = get_running_loop()
+ try:
+ if self._tasks:
+ with CancelScope() as wait_scope:
+ while self._tasks:
+ self._on_completed_fut = loop.create_future()
+
+ try:
+ await self._on_completed_fut
+ except CancelledError as exc:
+ # Shield the scope against further cancellation attempts,
+ # as they're not productive (#695)
+ wait_scope.shield = True
+ self.cancel_scope.cancel()
+
+ # Set exc_val from the cancellation exception if it was
+ # previously unset. However, we should not replace a native
+ # cancellation exception with one raise by a cancel scope.
+ if exc_val is None or (
+ isinstance(exc_val, CancelledError)
+ and not is_anyio_cancellation(exc)
+ ):
+ exc_val = exc
+
+ self._on_completed_fut = None
+ else:
+ # If there are no child tasks to wait on, run at least one checkpoint
+ # anyway
+ await AsyncIOBackend.cancel_shielded_checkpoint()
+
+ if self._exceptions:
+ # The exception that got us here should already have been
+ # added to self._exceptions so it's ok to break exception
+ # chaining and avoid adding a "During handling of above..."
+ # for each nesting level.
+ raise BaseExceptionGroup(
+ "unhandled errors in a TaskGroup", self._exceptions
+ ) from None
+ elif exc_val:
+ raise exc_val
+ except BaseException as exc:
+ if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__):
+ return True
+
+ raise
+
+ return self.cancel_scope.__exit__(exc_type, exc_val, exc_tb)
+ finally:
+ del exc_val, exc_tb, self._exceptions
+
+ def _spawn(
+ self,
+ coro: Coroutine[Any, Any, T_co],
+ name: object,
+ task_status_future: asyncio.Future | None = None,
+ ) -> TaskHandle[T_co]:
+ def task_done(_task: asyncio.Task) -> None:
+ if sys.version_info >= (3, 14) and self.cancel_scope._host_task is not None:
+ asyncio.future_discard_from_awaited_by(
+ _task, self.cancel_scope._host_task
+ )
+
+ task_state = _task_states[_task]
+ assert task_state.cancel_scope is not None
+ assert _task in task_state.cancel_scope._tasks
+ task_state.cancel_scope._tasks.remove(_task)
+ self._tasks.remove(task)
+ del _task_states[_task]
+
+ if self._on_completed_fut is not None and not self._tasks:
+ try:
+ self._on_completed_fut.set_result(None)
+ except asyncio.InvalidStateError:
+ pass
+
+ try:
+ exc = _task.exception()
+ except CancelledError as e:
+ while isinstance(e.__context__, CancelledError):
+ e = e.__context__
+
+ exc = e
+
+ if exc is not None:
+ # The future can only be in the cancelled state if the host task was
+ # cancelled, so return immediately instead of adding one more
+ # CancelledError to the exceptions list
+ if task_status_future is not None and task_status_future.cancelled():
+ return
+
+ if task_status_future is None or task_status_future.done():
+ if not isinstance(exc, CancelledError):
+ self._exceptions.append(exc)
+
+ if not self.cancel_scope._effectively_cancelled:
+ self.cancel_scope.cancel()
+ else:
+ task_status_future.set_exception(exc)
+ elif task_status_future is not None and not task_status_future.done():
+ task_status_future.set_exception(
+ RuntimeError("Child exited without calling task_status.started()")
+ )
+
+ if task_status_future:
+ parent_id = id(current_task())
+ else:
+ parent_id = id(self.cancel_scope._host_task)
+
+ handle = TaskHandle(coro, name)
+ loop = asyncio.get_running_loop()
+ wrapper_coro = handle._run_coro()
+ if (
+ (factory := loop.get_task_factory())
+ and getattr(factory, "__code__", None) is _eager_task_factory_code
+ and (closure := getattr(factory, "__closure__", None))
+ ):
+ custom_task_constructor = closure[0].cell_contents
+ task = custom_task_constructor(wrapper_coro, loop=loop, name=handle.name)
+ else:
+ task = loop.create_task(wrapper_coro, name=handle.name)
+
+ # Make the spawned task inherit the task group's cancel scope
+ _task_states[task] = TaskState(
+ parent_id=parent_id, cancel_scope=self.cancel_scope
+ )
+ self.cancel_scope._tasks.add(task)
+ self._tasks.add(task)
+ if sys.version_info >= (3, 14) and self.cancel_scope._host_task is not None:
+ asyncio.future_add_to_awaited_by(task, self.cancel_scope._host_task)
+
+ task.add_done_callback(task_done)
+ return handle
+
+ def create_task(
+ self,
+ coro: Coroutine[Any, Any, T_co],
+ *,
+ name: object = None,
+ context: Context | None = None,
+ ) -> TaskHandle[T_co]:
+ if not isinstance(coro, Coroutine):
+ raise TypeError(f"expected a coroutine, got {coro.__class__.__qualname__}")
+
+ if not self._entered or not self.cancel_scope._active:
+ coro.close()
+ raise RuntimeError(
+ "This task group is not active; no new tasks can be started."
+ )
+
+ if context is not None:
+ return context.run(self._spawn, coro, name=name)
+ else:
+ return self._spawn(coro, name=name)
+
+ async def start(
+ self,
+ func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]],
+ *args: Unpack[PosArgsT],
+ name: object = None,
+ return_handle: Literal[False] | Literal[True] = False,
+ ) -> Any:
+ if not self._entered or not self.cancel_scope._active:
+ raise RuntimeError(
+ "This task group is not active; no new tasks can be started."
+ )
+
+ future: asyncio.Future = asyncio.Future()
+ final_name = get_callable_name(func, name)
+ task_status = _AsyncioTaskStatus(future, id(self.cancel_scope._host_task))
+ coro = call_for_coroutine(func, args, task_status=task_status)
+ handle = self._spawn(coro, final_name, future)
+
+ # If the task raises an exception after sending a start value without a switch
+ # point between, the task group is cancelled and this method never proceeds to
+ # process the completed future. That's why we have to have a shielded cancel
+ # scope here.
+ try:
+ await future
+ except BaseException:
+ if handle.status is TaskHandle.Status.PENDING:
+ # Cancel the task and wait for it to exit before returning
+ handle.cancel()
+ with CancelScope(shield=True):
+ await handle.wait()
+
+ raise
+
+ if return_handle:
+ handle._start_value = future.result()
+ return handle
+ else:
+ return future.result()
+
+
+#
+# Threads
+#
+
+_Retval_Queue_Type = tuple[T_Retval | None, BaseException | None]
+
+
+class WorkerThread(Thread):
+ MAX_IDLE_TIME = 10 # seconds
+
+ def __init__(
+ self,
+ root_task: asyncio.Task,
+ workers: set[WorkerThread],
+ idle_workers: deque[WorkerThread],
+ ):
+ super().__init__(name="AnyIO worker thread")
+ self.root_task = root_task
+ self.workers = workers
+ self.idle_workers = idle_workers
+ self.loop = root_task._loop
+ self.queue: Queue[
+ tuple[Context, Callable, tuple, asyncio.Future, CancelScope] | None
+ ] = Queue(2)
+ self.idle_since = AsyncIOBackend.current_time()
+ self.stopping = False
+
+ def _report_result(
+ self, future: asyncio.Future, result: Any, exc: BaseException | None
+ ) -> None:
+ self.idle_since = AsyncIOBackend.current_time()
+ if not self.stopping:
+ self.idle_workers.append(self)
+
+ if not future.cancelled():
+ if exc is not None:
+ if isinstance(exc, StopIteration):
+ new_exc = RuntimeError("coroutine raised StopIteration")
+ new_exc.__cause__ = exc
+ exc = new_exc
+
+ future.set_exception(exc)
+ else:
+ future.set_result(result)
+
+ def run(self) -> None:
+ with claim_worker_thread(AsyncIOBackend, self.loop):
+ while True:
+ item = self.queue.get()
+ if item is None:
+ # Shutdown command received
+ return
+
+ context, func, args, future, cancel_scope = item
+ if not future.cancelled():
+ result = None
+ exception: BaseException | None = None
+ threadlocals.current_cancel_scope = cancel_scope
+ try:
+ result = context.run(func, *args)
+ except BaseException as exc:
+ exception = exc
+ finally:
+ del threadlocals.current_cancel_scope
+
+ if not self.loop.is_closed():
+ self.loop.call_soon_threadsafe(
+ self._report_result, future, result, exception
+ )
+
+ del result, exception
+
+ self.queue.task_done()
+ del item, context, func, args, future, cancel_scope
+
+ def stop(self, f: asyncio.Task | None = None) -> None:
+ self.stopping = True
+ self.queue.put_nowait(None)
+ self.workers.discard(self)
+ try:
+ self.idle_workers.remove(self)
+ except ValueError:
+ pass
+
+
+_threadpool_idle_workers: RunVar[deque[WorkerThread]] = RunVar(
+ "_threadpool_idle_workers"
+)
+_threadpool_workers: RunVar[set[WorkerThread]] = RunVar("_threadpool_workers")
+
+
+#
+# Subprocesses
+#
+
+
+@dataclass(eq=False)
+class StreamReaderWrapper(abc.ByteReceiveStream):
+ _stream: asyncio.StreamReader
+
+ async def receive(self, max_bytes: int = 65536) -> bytes:
+ data = await self._stream.read(max_bytes)
+ if data:
+ return data
+ else:
+ raise EndOfStream
+
+ async def aclose(self) -> None:
+ self._stream.set_exception(ClosedResourceError())
+ await AsyncIOBackend.checkpoint()
+
+
+@dataclass(eq=False)
+class StreamWriterWrapper(abc.ByteSendStream):
+ _stream: asyncio.StreamWriter
+ _closed: bool = field(init=False, default=False)
+
+ async def send(self, item: bytes) -> None:
+ await AsyncIOBackend.checkpoint_if_cancelled()
+ stream_paused = self._stream._protocol._paused # type: ignore[attr-defined]
+ try:
+ self._stream.write(item)
+ await self._stream.drain()
+ except (ConnectionResetError, BrokenPipeError, RuntimeError) as exc:
+ # If closed by us and/or the peer:
+ # * on stdlib, drain() raises ConnectionResetError or BrokenPipeError
+ # * on uvloop and Winloop, write() eventually starts raising RuntimeError
+ if self._closed:
+ raise ClosedResourceError from exc
+ elif self._stream.is_closing():
+ raise BrokenResourceError from exc
+
+ raise
+
+ if not stream_paused:
+ await AsyncIOBackend.cancel_shielded_checkpoint()
+
+ async def aclose(self) -> None:
+ self._closed = True
+ self._stream.close()
+ await AsyncIOBackend.checkpoint()
+
+
+@dataclass(eq=False)
+class Process(abc.Process):
+ _process: asyncio.subprocess.Process
+ _stdin: StreamWriterWrapper | None
+ _stdout: StreamReaderWrapper | None
+ _stderr: StreamReaderWrapper | None
+
+ async def aclose(self) -> None:
+ with CancelScope(shield=True) as scope:
+ if self._stdin:
+ await self._stdin.aclose()
+ if self._stdout:
+ await self._stdout.aclose()
+ if self._stderr:
+ await self._stderr.aclose()
+
+ scope.shield = False
+ try:
+ await self.wait()
+ except BaseException:
+ scope.shield = True
+ self.kill()
+ await self.wait()
+ raise
+
+ async def wait(self) -> int:
+ return await self._process.wait()
+
+ def terminate(self) -> None:
+ self._process.terminate()
+
+ def kill(self) -> None:
+ self._process.kill()
+
+ def send_signal(self, signal: int) -> None:
+ self._process.send_signal(signal)
+
+ @property
+ def pid(self) -> int:
+ return self._process.pid
+
+ @property
+ def returncode(self) -> int | None:
+ return self._process.returncode
+
+ @property
+ def stdin(self) -> abc.ByteSendStream | None:
+ return self._stdin
+
+ @property
+ def stdout(self) -> abc.ByteReceiveStream | None:
+ return self._stdout
+
+ @property
+ def stderr(self) -> abc.ByteReceiveStream | None:
+ return self._stderr
+
+
+def _forcibly_shutdown_process_pool_on_exit(
+ workers: set[Process], _task: object
+) -> None:
+ """
+ Forcibly shuts down worker processes belonging to this event loop."""
+ child_watcher: asyncio.AbstractChildWatcher | None = None # type: ignore[name-defined]
+ if sys.version_info < (3, 12):
+ try:
+ child_watcher = asyncio.get_event_loop_policy().get_child_watcher()
+ except NotImplementedError:
+ pass
+
+ # Close as much as possible (w/o async/await) to avoid warnings
+ for process in workers.copy():
+ if process.returncode is not None:
+ continue
+
+ process._stdin._stream._transport.close() # type: ignore[union-attr]
+ process._stdout._stream._transport.close() # type: ignore[union-attr]
+ process._stderr._stream._transport.close() # type: ignore[union-attr]
+ process.kill()
+ if child_watcher:
+ child_watcher.remove_child_handler(process.pid)
+
+
+async def _shutdown_process_pool_on_exit(workers: set[abc.Process]) -> None:
+ """
+ Shuts down worker processes belonging to this event loop.
+
+ NOTE: this only works when the event loop was started using asyncio.run() or
+ anyio.run().
+
+ """
+ process: abc.Process
+ try:
+ await sleep(math.inf)
+ except asyncio.CancelledError:
+ workers = workers.copy()
+ for process in workers:
+ if process.returncode is None:
+ process.kill()
+
+ for process in workers:
+ await process.aclose()
+
+
+#
+# Sockets and networking
+#
+
+
+class StreamProtocol(asyncio.Protocol):
+ read_queue: deque[bytes]
+ read_event: asyncio.Event
+ write_event: asyncio.Event
+ exception: Exception | None = None
+ is_at_eof: bool = False
+
+ def connection_made(self, transport: asyncio.BaseTransport) -> None:
+ self.read_queue = deque()
+ self.read_event = asyncio.Event()
+ self.write_event = asyncio.Event()
+ self.write_event.set()
+ cast(asyncio.Transport, transport).set_write_buffer_limits(0)
+
+ def connection_lost(self, exc: Exception | None) -> None:
+ if exc:
+ self.exception = exc
+
+ self.read_event.set()
+ self.write_event.set()
+
+ def data_received(self, data: bytes) -> None:
+ # ProactorEventloop sometimes sends bytearray instead of bytes
+ self.read_queue.append(bytes(data))
+ self.read_event.set()
+
+ def eof_received(self) -> bool | None:
+ self.is_at_eof = True
+ self.read_event.set()
+ return True
+
+ def pause_writing(self) -> None:
+ self.write_event = asyncio.Event()
+
+ def resume_writing(self) -> None:
+ self.write_event.set()
+
+
+class DatagramProtocol(asyncio.DatagramProtocol):
+ read_queue: deque[tuple[bytes, IPSockAddrType]]
+ read_event: asyncio.Event
+ write_event: asyncio.Event
+ closed_event: asyncio.Event
+ exception: Exception | None = None
+
+ def connection_made(self, transport: asyncio.BaseTransport) -> None:
+ self.read_queue = deque(maxlen=100) # arbitrary value
+ self.read_event = asyncio.Event()
+ self.write_event = asyncio.Event()
+ self.closed_event = asyncio.Event()
+ self.write_event.set()
+
+ def connection_lost(self, exc: Exception | None) -> None:
+ self.read_event.set()
+ self.write_event.set()
+ self.closed_event.set()
+
+ def datagram_received(self, data: bytes, addr: IPSockAddrType) -> None:
+ addr = convert_ipv6_sockaddr(addr)
+ self.read_queue.append((data, addr))
+ self.read_event.set()
+
+ def error_received(self, exc: Exception) -> None:
+ self.exception = exc
+
+ def pause_writing(self) -> None:
+ self.write_event.clear()
+
+ def resume_writing(self) -> None:
+ self.write_event.set()
+
+
+class SocketStream(abc.SocketStream):
+ def __init__(self, transport: asyncio.Transport, protocol: StreamProtocol):
+ self._transport = transport
+ self._protocol = protocol
+ self._receive_guard = ResourceGuard("reading from")
+ self._send_guard = ResourceGuard("writing to")
+ self._closed = False
+
+ @property
+ def _raw_socket(self) -> socket.socket:
+ return self._transport.get_extra_info("socket")
+
+ async def receive(self, max_bytes: int = 65536) -> bytes:
+ with self._receive_guard:
+ if (
+ not self._protocol.read_event.is_set()
+ and not self._transport.is_closing()
+ and not self._protocol.is_at_eof
+ ):
+ self._transport.resume_reading()
+ await self._protocol.read_event.wait()
+ self._transport.pause_reading()
+ else:
+ await AsyncIOBackend.checkpoint()
+
+ try:
+ chunk = self._protocol.read_queue.popleft()
+ except IndexError:
+ if self._closed:
+ raise ClosedResourceError from None
+ elif self._protocol.exception:
+ raise BrokenResourceError from self._protocol.exception
+ else:
+ raise EndOfStream from None
+
+ if len(chunk) > max_bytes:
+ # Split the oversized chunk
+ chunk, leftover = chunk[:max_bytes], chunk[max_bytes:]
+ self._protocol.read_queue.appendleft(leftover)
+
+ # If the read queue is empty, clear the flag so that the next call will
+ # block until data is available
+ if not self._protocol.read_queue:
+ self._protocol.read_event.clear()
+
+ return chunk
+
+ async def send(self, item: bytes) -> None:
+ with self._send_guard:
+ await AsyncIOBackend.checkpoint()
+
+ if self._closed:
+ raise ClosedResourceError
+ elif self._protocol.exception is not None:
+ raise BrokenResourceError from self._protocol.exception
+
+ try:
+ self._transport.write(item)
+ except RuntimeError as exc:
+ if self._transport.is_closing():
+ raise BrokenResourceError from exc
+ else:
+ raise
+
+ await self._protocol.write_event.wait()
+
+ async def send_eof(self) -> None:
+ try:
+ self._transport.write_eof()
+ except OSError:
+ pass
+
+ async def aclose(self) -> None:
+ self._closed = True
+ if not self._transport.is_closing():
+ try:
+ self._transport.write_eof()
+ except OSError:
+ pass
+
+ self._transport.close()
+ await sleep(0)
+ self._transport.abort()
+
+
+class _RawSocketMixin:
+ _receive_future: asyncio.Future | None = None
+ _send_future: asyncio.Future | None = None
+ _closing = False
+
+ def __init__(self, raw_socket: socket.socket):
+ self.__raw_socket = raw_socket
+ self._receive_guard = ResourceGuard("reading from")
+ self._send_guard = ResourceGuard("writing to")
+
+ @property
+ def _raw_socket(self) -> socket.socket:
+ return self.__raw_socket
+
+ def _wait_until_readable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future:
+ def callback(f: object) -> None:
+ del self._receive_future
+ loop.remove_reader(self.__raw_socket)
+
+ f = self._receive_future = asyncio.Future()
+ loop.add_reader(self.__raw_socket, f.set_result, None)
+ f.add_done_callback(callback)
+ return f
+
+ def _wait_until_writable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future:
+ def callback(f: object) -> None:
+ del self._send_future
+ loop.remove_writer(self.__raw_socket)
+
+ f = self._send_future = asyncio.Future()
+ loop.add_writer(self.__raw_socket, f.set_result, None)
+ f.add_done_callback(callback)
+ return f
+
+ async def aclose(self) -> None:
+ if not self._closing:
+ self._closing = True
+ if self.__raw_socket.fileno() != -1:
+ self.__raw_socket.close()
+
+ if self._receive_future:
+ self._receive_future.set_result(None)
+ if self._send_future:
+ self._send_future.set_result(None)
+
+
+class UNIXSocketStream(_RawSocketMixin, abc.UNIXSocketStream):
+ async def send_eof(self) -> None:
+ with self._send_guard:
+ self._raw_socket.shutdown(socket.SHUT_WR)
+
+ async def receive(self, max_bytes: int = 65536) -> bytes:
+ loop = get_running_loop()
+ await AsyncIOBackend.checkpoint()
+ with self._receive_guard:
+ while True:
+ try:
+ data = self._raw_socket.recv(max_bytes)
+ except BlockingIOError:
+ await self._wait_until_readable(loop)
+ except OSError as exc:
+ if self._closing:
+ raise ClosedResourceError from None
+ else:
+ raise BrokenResourceError from exc
+ else:
+ if not data:
+ raise EndOfStream
+
+ return data
+
+ async def send(self, item: bytes) -> None:
+ loop = get_running_loop()
+ await AsyncIOBackend.checkpoint()
+ with self._send_guard:
+ view = memoryview(item)
+ while view:
+ try:
+ bytes_sent = self._raw_socket.send(view)
+ except BlockingIOError:
+ await self._wait_until_writable(loop)
+ except OSError as exc:
+ if self._closing:
+ raise ClosedResourceError from None
+ else:
+ raise BrokenResourceError from exc
+ else:
+ view = view[bytes_sent:]
+
+ async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]:
+ if not isinstance(msglen, int) or msglen < 0:
+ raise ValueError("msglen must be a non-negative integer")
+ if not isinstance(maxfds, int) or maxfds < 1:
+ raise ValueError("maxfds must be a positive integer")
+
+ loop = get_running_loop()
+ fds = array.array("i")
+ await AsyncIOBackend.checkpoint()
+ with self._receive_guard:
+ while True:
+ try:
+ message, ancdata, flags, addr = self._raw_socket.recvmsg(
+ msglen, socket.CMSG_LEN(maxfds * fds.itemsize)
+ )
+ except BlockingIOError:
+ await self._wait_until_readable(loop)
+ except OSError as exc:
+ if self._closing:
+ raise ClosedResourceError from None
+ else:
+ raise BrokenResourceError from exc
+ else:
+ if not message and not ancdata:
+ raise EndOfStream
+
+ break
+
+ for cmsg_level, cmsg_type, cmsg_data in ancdata:
+ if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS:
+ raise RuntimeError(
+ f"Received unexpected ancillary data; message = {message!r}, "
+ f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}"
+ )
+
+ fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
+
+ return message, list(fds)
+
+ async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None:
+ if not message:
+ raise ValueError("message must not be empty")
+ if not fds:
+ raise ValueError("fds must not be empty")
+
+ loop = get_running_loop()
+ filenos: list[int] = []
+ for fd in fds:
+ if isinstance(fd, int):
+ filenos.append(fd)
+ elif isinstance(fd, IOBase):
+ filenos.append(fd.fileno())
+
+ fdarray = array.array("i", filenos)
+ await AsyncIOBackend.checkpoint()
+ with self._send_guard:
+ while True:
+ try:
+ # The ignore can be removed after mypy picks up
+ # https://github.com/python/typeshed/pull/5545
+ self._raw_socket.sendmsg(
+ [message], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, fdarray)]
+ )
+ break
+ except BlockingIOError:
+ await self._wait_until_writable(loop)
+ except OSError as exc:
+ if self._closing:
+ raise ClosedResourceError from None
+ else:
+ raise BrokenResourceError from exc
+
+
+class TCPSocketListener(abc.SocketListener):
+ _accept_scope: CancelScope | None = None
+ _closed = False
+
+ def __init__(self, raw_socket: socket.socket):
+ self.__raw_socket = raw_socket
+ self._loop = cast(asyncio.BaseEventLoop, get_running_loop())
+ self._accept_guard = ResourceGuard("accepting connections from")
+
+ @property
+ def _raw_socket(self) -> socket.socket:
+ return self.__raw_socket
+
+ async def accept(self) -> abc.SocketStream:
+ if self._closed:
+ raise ClosedResourceError
+
+ with self._accept_guard:
+ await AsyncIOBackend.checkpoint()
+ with CancelScope() as self._accept_scope:
+ try:
+ client_sock, _addr = await self._loop.sock_accept(self._raw_socket)
+ except asyncio.CancelledError:
+ # Workaround for https://bugs.python.org/issue41317
+ try:
+ self._loop.remove_reader(self._raw_socket)
+ except (ValueError, NotImplementedError):
+ pass
+
+ if self._closed:
+ raise ClosedResourceError from None
+
+ raise
+ finally:
+ self._accept_scope = None
+
+ client_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+ transport, protocol = await self._loop.connect_accepted_socket(
+ StreamProtocol, client_sock
+ )
+ return SocketStream(transport, protocol)
+
+ async def aclose(self) -> None:
+ if self._closed:
+ return
+
+ self._closed = True
+ if self._accept_scope:
+ # Workaround for https://bugs.python.org/issue41317
+ try:
+ self._loop.remove_reader(self._raw_socket)
+ except (ValueError, NotImplementedError):
+ pass
+
+ self._accept_scope.cancel()
+ await sleep(0)
+
+ self._raw_socket.close()
+
+
+class UNIXSocketListener(abc.SocketListener):
+ def __init__(self, raw_socket: socket.socket):
+ self.__raw_socket = raw_socket
+ self._loop = get_running_loop()
+ self._accept_guard = ResourceGuard("accepting connections from")
+ self._closed = False
+
+ async def accept(self) -> abc.SocketStream:
+ await AsyncIOBackend.checkpoint()
+ with self._accept_guard:
+ while True:
+ try:
+ client_sock, _ = self.__raw_socket.accept()
+ client_sock.setblocking(False)
+ return UNIXSocketStream(client_sock)
+ except BlockingIOError:
+ f: asyncio.Future = asyncio.Future()
+ self._loop.add_reader(self.__raw_socket, f.set_result, None)
+ f.add_done_callback(
+ lambda _: self._loop.remove_reader(self.__raw_socket)
+ )
+ await f
+ except OSError as exc:
+ if self._closed:
+ raise ClosedResourceError from None
+ else:
+ raise BrokenResourceError from exc
+
+ async def aclose(self) -> None:
+ self._closed = True
+ self.__raw_socket.close()
+
+ @property
+ def _raw_socket(self) -> socket.socket:
+ return self.__raw_socket
+
+
+class UDPSocket(abc.UDPSocket):
+ def __init__(
+ self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol
+ ):
+ self._transport = transport
+ self._protocol = protocol
+ self._receive_guard = ResourceGuard("reading from")
+ self._send_guard = ResourceGuard("writing to")
+ self._closed = False
+
+ @property
+ def _raw_socket(self) -> socket.socket:
+ return self._transport.get_extra_info("socket")
+
+ async def aclose(self) -> None:
+ self._closed = True
+ if not self._transport.is_closing():
+ self._transport.close()
+
+ await self._protocol.closed_event.wait()
+
+ async def receive(self) -> tuple[bytes, IPSockAddrType]:
+ with self._receive_guard:
+ await AsyncIOBackend.checkpoint()
+
+ # If the buffer is empty, ask for more data
+ if not self._protocol.read_queue and not self._transport.is_closing():
+ self._protocol.read_event.clear()
+ await self._protocol.read_event.wait()
+
+ try:
+ return self._protocol.read_queue.popleft()
+ except IndexError:
+ if self._closed:
+ raise ClosedResourceError from None
+ else:
+ raise BrokenResourceError from None
+
+ async def send(self, item: UDPPacketType) -> None:
+ with self._send_guard:
+ await AsyncIOBackend.checkpoint()
+ await self._protocol.write_event.wait()
+ if self._closed:
+ raise ClosedResourceError
+ elif self._transport.is_closing():
+ raise BrokenResourceError
+ else:
+ self._transport.sendto(*item)
+
+
+class ConnectedUDPSocket(abc.ConnectedUDPSocket):
+ def __init__(
+ self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol
+ ):
+ self._transport = transport
+ self._protocol = protocol
+ self._receive_guard = ResourceGuard("reading from")
+ self._send_guard = ResourceGuard("writing to")
+ self._closed = False
+
+ @property
+ def _raw_socket(self) -> socket.socket:
+ return self._transport.get_extra_info("socket")
+
+ async def aclose(self) -> None:
+ self._closed = True
+ if not self._transport.is_closing():
+ self._transport.close()
+
+ await self._protocol.closed_event.wait()
+
+ async def receive(self) -> bytes:
+ with self._receive_guard:
+ await AsyncIOBackend.checkpoint()
+
+ # If the buffer is empty, ask for more data
+ if not self._protocol.read_queue and not self._transport.is_closing():
+ self._protocol.read_event.clear()
+ await self._protocol.read_event.wait()
+
+ try:
+ packet = self._protocol.read_queue.popleft()
+ except IndexError:
+ if self._closed:
+ raise ClosedResourceError from None
+ else:
+ raise BrokenResourceError from None
+
+ return packet[0]
+
+ async def send(self, item: bytes) -> None:
+ with self._send_guard:
+ await AsyncIOBackend.checkpoint()
+ await self._protocol.write_event.wait()
+ if self._closed:
+ raise ClosedResourceError
+ elif self._transport.is_closing():
+ raise BrokenResourceError
+ else:
+ self._transport.sendto(item)
+
+
+class UNIXDatagramSocket(_RawSocketMixin, abc.UNIXDatagramSocket):
+ async def receive(self) -> UNIXDatagramPacketType:
+ loop = get_running_loop()
+ await AsyncIOBackend.checkpoint()
+ with self._receive_guard:
+ while True:
+ try:
+ data = self._raw_socket.recvfrom(65536)
+ except BlockingIOError:
+ await self._wait_until_readable(loop)
+ except OSError as exc:
+ if self._closing:
+ raise ClosedResourceError from None
+ else:
+ raise BrokenResourceError from exc
+ else:
+ return data
+
+ async def send(self, item: UNIXDatagramPacketType) -> None:
+ loop = get_running_loop()
+ await AsyncIOBackend.checkpoint()
+ with self._send_guard:
+ while True:
+ try:
+ self._raw_socket.sendto(*item)
+ except BlockingIOError:
+ await self._wait_until_writable(loop)
+ except OSError as exc:
+ if self._closing:
+ raise ClosedResourceError from None
+ else:
+ raise BrokenResourceError from exc
+ else:
+ return
+
+
+class ConnectedUNIXDatagramSocket(_RawSocketMixin, abc.ConnectedUNIXDatagramSocket):
+ async def receive(self) -> bytes:
+ loop = get_running_loop()
+ await AsyncIOBackend.checkpoint()
+ with self._receive_guard:
+ while True:
+ try:
+ data = self._raw_socket.recv(65536)
+ except BlockingIOError:
+ await self._wait_until_readable(loop)
+ except OSError as exc:
+ if self._closing:
+ raise ClosedResourceError from None
+ else:
+ raise BrokenResourceError from exc
+ else:
+ return data
+
+ async def send(self, item: bytes) -> None:
+ loop = get_running_loop()
+ await AsyncIOBackend.checkpoint()
+ with self._send_guard:
+ while True:
+ try:
+ self._raw_socket.send(item)
+ except BlockingIOError:
+ await self._wait_until_writable(loop)
+ except OSError as exc:
+ if self._closing:
+ raise ClosedResourceError from None
+ else:
+ raise BrokenResourceError from exc
+ else:
+ return
+
+
+_read_events: RunVar[dict[int, asyncio.Future[bool]]] = RunVar("read_events")
+_write_events: RunVar[dict[int, asyncio.Future[bool]]] = RunVar("write_events")
+
+
+#
+# Synchronization
+#
+
+
+class Event(BaseEvent):
+ __slots__ = ("_event",)
+
+ def __new__(cls) -> Event:
+ return object.__new__(cls)
+
+ def __init__(self) -> None:
+ self._event = asyncio.Event()
+
+ def set(self) -> None:
+ self._event.set()
+
+ def is_set(self) -> bool:
+ return self._event.is_set()
+
+ async def wait(self) -> None:
+ if self.is_set():
+ await AsyncIOBackend.checkpoint()
+ else:
+ await self._event.wait()
+
+ def statistics(self) -> EventStatistics:
+ return EventStatistics(len(self._event._waiters))
+
+
+class Lock(BaseLock):
+ __slots__ = "_fast_acquire", "_owner_task", "_waiters"
+
+ def __new__(cls, *, fast_acquire: bool = False) -> Lock:
+ return object.__new__(cls)
+
+ def __init__(self, *, fast_acquire: bool = False) -> None:
+ self._fast_acquire = fast_acquire
+ self._owner_task: asyncio.Task | None = None
+ self._waiters: deque[tuple[asyncio.Task, asyncio.Future]] = deque()
+
+ async def acquire(self) -> None:
+ task = cast(asyncio.Task, current_task())
+ if self._owner_task is None and not self._waiters:
+ await AsyncIOBackend.checkpoint_if_cancelled()
+ self._owner_task = task
+
+ # Unless on the "fast path", yield control of the event loop so that other
+ # tasks can run too
+ if not self._fast_acquire:
+ try:
+ await AsyncIOBackend.cancel_shielded_checkpoint()
+ except CancelledError:
+ self.release()
+ raise
+
+ return
+
+ if self._owner_task == task:
+ raise RuntimeError("Attempted to acquire an already held Lock")
+
+ fut: asyncio.Future[None] = asyncio.Future()
+ item = task, fut
+ self._waiters.append(item)
+ try:
+ await fut
+ except CancelledError:
+ if fut.cancelled():
+ try:
+ self._waiters.remove(item)
+ except ValueError:
+ pass
+ else:
+ self.release()
+
+ raise
+
+ def acquire_nowait(self) -> None:
+ task = cast(asyncio.Task, current_task())
+ if self._owner_task is None and not self._waiters:
+ self._owner_task = task
+ return
+
+ if self._owner_task is task:
+ raise RuntimeError("Attempted to acquire an already held Lock")
+
+ raise WouldBlock
+
+ def locked(self) -> bool:
+ return self._owner_task is not None
+
+ def release(self) -> None:
+ if self._owner_task != current_task():
+ raise RuntimeError("The current task is not holding this lock")
+
+ # A cancelled waiter that already received ownership removes itself from
+ # _waiters before calling release(); any cancelled waiter still queued here
+ # was cancelled before being woken, so drop it.
+ while self._waiters:
+ task, fut = self._waiters.popleft()
+ if fut.cancelled():
+ continue
+
+ self._owner_task = task
+ fut.set_result(None)
+ return
+
+ self._owner_task = None
+
+ def statistics(self) -> LockStatistics:
+ task_info = AsyncIOTaskInfo(self._owner_task) if self._owner_task else None
+ return LockStatistics(self.locked(), task_info, len(self._waiters))
+
+
+class Semaphore(BaseSemaphore):
+ __slots__ = "_value", "_max_value", "_fast_acquire", "_waiters"
+
+ def __new__(
+ cls,
+ initial_value: int,
+ *,
+ max_value: int | None = None,
+ fast_acquire: bool = False,
+ ) -> Semaphore:
+ return object.__new__(cls)
+
+ def __init__(
+ self,
+ initial_value: int,
+ *,
+ max_value: int | None = None,
+ fast_acquire: bool = False,
+ ):
+ super().__init__(initial_value, max_value=max_value)
+ self._value = initial_value
+ self._max_value = max_value
+ self._fast_acquire = fast_acquire
+ self._waiters: deque[asyncio.Future[None]] = deque()
+
+ async def acquire(self) -> None:
+ if self._value > 0 and not self._waiters:
+ await AsyncIOBackend.checkpoint_if_cancelled()
+ self._value -= 1
+
+ # Unless on the "fast path", yield control of the event loop so that other
+ # tasks can run too
+ if not self._fast_acquire:
+ try:
+ await AsyncIOBackend.cancel_shielded_checkpoint()
+ except CancelledError:
+ self.release()
+ raise
+
+ return
+
+ fut: asyncio.Future[None] = asyncio.Future()
+ self._waiters.append(fut)
+ try:
+ await fut
+ except CancelledError:
+ if fut.cancelled():
+ try:
+ self._waiters.remove(fut)
+ except ValueError:
+ pass
+ else:
+ self.release()
+
+ raise
+
+ def acquire_nowait(self) -> None:
+ if self._value == 0:
+ raise WouldBlock
+
+ self._value -= 1
+
+ def release(self) -> None:
+ if self._max_value is not None and self._value == self._max_value:
+ raise ValueError("semaphore released too many times")
+
+ while self._waiters:
+ fut = self._waiters.popleft()
+ if fut.cancelled():
+ continue
+
+ fut.set_result(None)
+ return
+
+ self._value += 1
+
+ @property
+ def value(self) -> int:
+ return self._value
+
+ @property
+ def max_value(self) -> int | None:
+ return self._max_value
+
+ def statistics(self) -> SemaphoreStatistics:
+ return SemaphoreStatistics(len(self._waiters))
+
+
+class CapacityLimiter(BaseCapacityLimiter):
+ __slots__ = "_total_tokens", "_borrowers", "_wait_queue"
+
+ def __new__(cls, total_tokens: float) -> CapacityLimiter:
+ return object.__new__(cls)
+
+ def __init__(self, total_tokens: float):
+ self._total_tokens: float = 0
+ self._borrowers: set[Any] = set()
+ self._wait_queue: OrderedDict[Any, asyncio.Event] = OrderedDict()
+ self.total_tokens = total_tokens
+
+ async def __aenter__(self) -> None:
+ await self.acquire()
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ self.release()
+
+ @property
+ def total_tokens(self) -> float:
+ return self._total_tokens
+
+ @total_tokens.setter
+ def total_tokens(self, value: float) -> None:
+ if not isinstance(value, int) and not math.isinf(value):
+ raise TypeError("total_tokens must be an int or math.inf")
+
+ if value < 0:
+ raise ValueError("total_tokens must be >= 0")
+
+ waiters_to_notify = max(value - self._total_tokens, 0)
+ self._total_tokens = value
+
+ # Notify waiting tasks that they have acquired the limiter
+ while self._wait_queue and waiters_to_notify:
+ event = self._wait_queue.popitem(last=False)[1]
+ event.set()
+ waiters_to_notify -= 1
+
+ @property
+ def borrowed_tokens(self) -> int:
+ return len(self._borrowers)
+
+ @property
+ def available_tokens(self) -> float:
+ return self._total_tokens - len(self._borrowers)
+
+ def _notify_next_waiter(self) -> None:
+ """Notify the next task in line if this limiter has free capacity now."""
+ if self._wait_queue and len(self._borrowers) < self._total_tokens:
+ event = self._wait_queue.popitem(last=False)[1]
+ event.set()
+
+ def acquire_nowait(self) -> None:
+ self.acquire_on_behalf_of_nowait(current_task())
+
+ def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
+ if borrower in self._borrowers:
+ raise RuntimeError(
+ "this borrower is already holding one of this CapacityLimiter's tokens"
+ )
+
+ if self._wait_queue or len(self._borrowers) >= self._total_tokens:
+ raise WouldBlock
+
+ self._borrowers.add(borrower)
+
+ async def acquire(self) -> None:
+ return await self.acquire_on_behalf_of(current_task())
+
+ async def acquire_on_behalf_of(self, borrower: object) -> None:
+ await AsyncIOBackend.checkpoint_if_cancelled()
+ try:
+ self.acquire_on_behalf_of_nowait(borrower)
+ except WouldBlock:
+ event = asyncio.Event()
+ self._wait_queue[borrower] = event
+ try:
+ await event.wait()
+ except BaseException:
+ self._wait_queue.pop(borrower, None)
+ if event.is_set():
+ self._notify_next_waiter()
+
+ raise
+
+ self._borrowers.add(borrower)
+ else:
+ try:
+ await AsyncIOBackend.cancel_shielded_checkpoint()
+ except BaseException:
+ self.release()
+ raise
+
+ def release(self) -> None:
+ self.release_on_behalf_of(current_task())
+
+ def release_on_behalf_of(self, borrower: object) -> None:
+ try:
+ self._borrowers.remove(borrower)
+ except KeyError:
+ raise RuntimeError(
+ "this borrower isn't holding any of this CapacityLimiter's tokens"
+ ) from None
+
+ self._notify_next_waiter()
+
+ def statistics(self) -> CapacityLimiterStatistics:
+ return CapacityLimiterStatistics(
+ self.borrowed_tokens,
+ self.total_tokens,
+ tuple(self._borrowers),
+ len(self._wait_queue),
+ )
+
+
+_default_thread_limiter: RunVar[CapacityLimiter] = RunVar("_default_thread_limiter")
+
+
+#
+# Operating system signals
+#
+
+
+class _SignalReceiver:
+ def __init__(self, signals: tuple[Signals, ...]):
+ self._signals = signals
+ self._loop = get_running_loop()
+ self._signal_queue: deque[Signals] = deque()
+ self._future: asyncio.Future = asyncio.Future()
+ self._handled_signals: set[Signals] = set()
+
+ def _deliver(self, signum: Signals) -> None:
+ self._signal_queue.append(signum)
+ if not self._future.done():
+ self._future.set_result(None)
+
+ def __enter__(self) -> _SignalReceiver:
+ for sig in set(self._signals):
+ self._loop.add_signal_handler(sig, self._deliver, sig)
+ self._handled_signals.add(sig)
+
+ return self
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ for sig in self._handled_signals:
+ self._loop.remove_signal_handler(sig)
+
+ def __aiter__(self) -> _SignalReceiver:
+ return self
+
+ async def __anext__(self) -> Signals:
+ await AsyncIOBackend.checkpoint()
+ if not self._signal_queue:
+ self._future = asyncio.Future()
+ await self._future
+
+ return self._signal_queue.popleft()
+
+
+#
+# Testing and debugging
+#
+
+
+class AsyncIOTaskInfo(TaskInfo):
+ def __init__(self, task: asyncio.Task):
+ task_state = _task_states.get(task)
+ if task_state is None:
+ parent_id = None
+ else:
+ parent_id = task_state.parent_id
+
+ coro = task.get_coro()
+ assert coro is not None, "created TaskInfo from a completed Task"
+ super().__init__(id(task), parent_id, task.get_name(), coro)
+ self._task = weakref.ref(task)
+
+ def has_pending_cancellation(self) -> bool:
+ if not (task := self._task()):
+ # If the task isn't around anymore, it won't have a pending cancellation
+ return False
+
+ if task._must_cancel: # type: ignore[attr-defined]
+ return True
+ elif (
+ isinstance(task._fut_waiter, asyncio.Future) # type: ignore[attr-defined]
+ and task._fut_waiter.cancelled() # type: ignore[attr-defined]
+ ):
+ return True
+
+ if task_state := _task_states.get(task):
+ if cancel_scope := task_state.cancel_scope:
+ return cancel_scope._effectively_cancelled
+
+ return False
+
+
+class TestRunner(abc.TestRunner):
+ _send_stream: MemoryObjectSendStream[tuple[Awaitable[Any], asyncio.Future[Any]]]
+
+ def __init__(
+ self,
+ *,
+ debug: bool | None = None,
+ use_uvloop: bool = False,
+ loop_factory: Callable[[], AbstractEventLoop] | None = None,
+ ) -> None:
+ if use_uvloop and loop_factory is None:
+ if sys.platform != "win32":
+ import uvloop
+
+ loop_factory = uvloop.new_event_loop
+ else:
+ import winloop
+
+ loop_factory = winloop.new_event_loop
+
+ self._runner = Runner(debug=debug, loop_factory=loop_factory)
+ self._exceptions: list[BaseException] = []
+ self._runner_task: asyncio.Task | None = None
+
+ def __enter__(self) -> TestRunner:
+ self._runner.__enter__()
+ self.get_loop().set_exception_handler(self._exception_handler)
+ return self
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ self._runner.__exit__(exc_type, exc_val, exc_tb)
+
+ def get_loop(self) -> AbstractEventLoop:
+ return self._runner.get_loop()
+
+ def is_running(self) -> bool:
+ try:
+ asyncio.get_running_loop()
+ return True
+ except RuntimeError:
+ return False
+
+ def _exception_handler(
+ self, loop: asyncio.AbstractEventLoop, context: dict[str, Any]
+ ) -> None:
+ if isinstance(context.get("exception"), Exception):
+ self._exceptions.append(context["exception"])
+ else:
+ loop.default_exception_handler(context)
+
+ def _raise_async_exceptions(self) -> None:
+ # Re-raise any exceptions raised in asynchronous callbacks
+ if self._exceptions:
+ exceptions, self._exceptions = self._exceptions, []
+ if len(exceptions) == 1:
+ raise exceptions[0]
+ elif exceptions:
+ raise BaseExceptionGroup(
+ "Multiple exceptions occurred in asynchronous callbacks", exceptions
+ )
+
+ async def _run_tests_and_fixtures(
+ self,
+ receive_stream: MemoryObjectReceiveStream[
+ tuple[Awaitable[T_Retval], asyncio.Future[T_Retval]]
+ ],
+ ) -> None:
+ from _pytest.outcomes import OutcomeException
+
+ with receive_stream, self._send_stream:
+ async for coro, future in receive_stream:
+ try:
+ retval = await coro
+ except CancelledError as exc:
+ if not future.cancelled():
+ future.cancel(*exc.args)
+
+ raise
+ except BaseException as exc:
+ if not future.cancelled():
+ future.set_exception(exc)
+
+ if not isinstance(exc, (Exception, OutcomeException)):
+ raise
+ else:
+ if not future.cancelled():
+ future.set_result(retval)
+
+ async def _call_in_runner_task(
+ self,
+ func: Callable[P, Awaitable[T_Retval]],
+ /,
+ *args: P.args,
+ **kwargs: P.kwargs,
+ ) -> T_Retval:
+ if not self._runner_task:
+ self._send_stream, receive_stream = create_memory_object_stream[
+ tuple[Awaitable[Any], asyncio.Future]
+ ](1)
+ self._runner_task = self.get_loop().create_task(
+ self._run_tests_and_fixtures(receive_stream)
+ )
+
+ coro = func(*args, **kwargs)
+ future: asyncio.Future[T_Retval] = self.get_loop().create_future()
+ self._send_stream.send_nowait((coro, future))
+ return await future
+
+ def run_asyncgen_fixture(
+ self,
+ fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]],
+ kwargs: dict[str, Any],
+ ) -> Iterable[T_Retval]:
+ asyncgen = fixture_func(**kwargs)
+ fixturevalue: T_Retval = self.get_loop().run_until_complete(
+ self._call_in_runner_task(asyncgen.asend, None)
+ )
+ self._raise_async_exceptions()
+
+ yield fixturevalue
+
+ try:
+ self.get_loop().run_until_complete(
+ self._call_in_runner_task(asyncgen.asend, None)
+ )
+ except StopAsyncIteration:
+ self._raise_async_exceptions()
+ else:
+ self.get_loop().run_until_complete(asyncgen.aclose())
+ raise RuntimeError("Async generator fixture did not stop")
+
+ def run_fixture(
+ self,
+ fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]],
+ kwargs: dict[str, Any],
+ ) -> T_Retval:
+ retval = self.get_loop().run_until_complete(
+ self._call_in_runner_task(fixture_func, **kwargs)
+ )
+ self._raise_async_exceptions()
+ return retval
+
+ def run_test(
+ self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any]
+ ) -> None:
+ try:
+ self.get_loop().run_until_complete(
+ self._call_in_runner_task(test_func, **kwargs)
+ )
+ except Exception as exc:
+ self._exceptions.append(exc)
+ except BaseException:
+ # A BaseException (e.g. KeyboardInterrupt, SystemExit) interrupted the event loop before
+ # the test completed. Cancel _runner_task so it does not resume when the event
+ # loop is re-entered during async generator fixture teardown.
+ if self._runner_task is not None and not self._runner_task.done():
+ self._runner_task.cancel()
+ self._send_stream.close()
+ try:
+ self.get_loop().run_until_complete(self._runner_task)
+ except CancelledError:
+ pass
+ finally:
+ self._runner_task = None
+ raise
+ self._raise_async_exceptions()
+
+
+class AsyncIOBackend(AsyncBackend):
+ @classmethod
+ def run(
+ cls,
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+ args: tuple[Unpack[PosArgsT]],
+ kwargs: dict[str, Any],
+ options: dict[str, Any],
+ ) -> T_Retval:
+ @wraps(func)
+ async def wrapper() -> T_Retval:
+ task = cast(asyncio.Task, current_task())
+ task.set_name(get_callable_name(func))
+ _task_states[task] = TaskState(None, None)
+
+ try:
+ return await func(*args)
+ finally:
+ del _task_states[task]
+
+ debug = options.get("debug", None)
+ loop_factory = options.get("loop_factory", None)
+ if loop_factory is None and options.get("use_uvloop", False):
+ if sys.platform != "win32":
+ import uvloop
+
+ loop_factory = uvloop.new_event_loop
+ else:
+ import winloop
+
+ loop_factory = winloop.new_event_loop
+
+ with Runner(debug=debug, loop_factory=loop_factory) as runner:
+ return runner.run(wrapper())
+
+ @classmethod
+ def current_token(cls) -> object:
+ return get_running_loop()
+
+ @classmethod
+ def current_time(cls) -> float:
+ return get_running_loop().time()
+
+ @classmethod
+ def cancelled_exception_class(cls) -> type[BaseException]:
+ return CancelledError
+
+ @classmethod
+ async def checkpoint(cls) -> None:
+ await sleep(0)
+
+ @classmethod
+ async def checkpoint_if_cancelled(cls) -> None:
+ task = current_task()
+ if task is None:
+ return
+
+ try:
+ cancel_scope = _task_states[task].cancel_scope
+ except KeyError:
+ return
+
+ while cancel_scope:
+ if cancel_scope.cancel_called:
+ await sleep(0)
+ elif cancel_scope.shield:
+ break
+ else:
+ cancel_scope = cancel_scope._parent_scope
+
+ @classmethod
+ async def cancel_shielded_checkpoint(cls) -> None:
+ with CancelScope(shield=True):
+ await sleep(0)
+
+ @classmethod
+ async def sleep(cls, delay: float) -> None:
+ await sleep(delay)
+
+ @classmethod
+ def create_cancel_scope(
+ cls, *, deadline: float = math.inf, shield: bool = False
+ ) -> CancelScope:
+ return CancelScope(deadline=deadline, shield=shield)
+
+ @classmethod
+ def current_effective_deadline(cls) -> float:
+ if (task := current_task()) is None:
+ return math.inf
+
+ try:
+ cancel_scope = _task_states[task].cancel_scope
+ except KeyError:
+ return math.inf
+
+ deadline = math.inf
+ while cancel_scope:
+ deadline = min(deadline, cancel_scope.deadline)
+ if cancel_scope._cancel_called:
+ deadline = -math.inf
+ break
+ elif cancel_scope.shield:
+ break
+ else:
+ cancel_scope = cancel_scope._parent_scope
+
+ return deadline
+
+ @classmethod
+ def create_task_group(cls) -> abc.TaskGroup:
+ return TaskGroup()
+
+ @classmethod
+ def create_event(cls) -> abc.Event:
+ return Event()
+
+ @classmethod
+ def create_lock(cls, *, fast_acquire: bool) -> abc.Lock:
+ return Lock(fast_acquire=fast_acquire)
+
+ @classmethod
+ def create_semaphore(
+ cls,
+ initial_value: int,
+ *,
+ max_value: int | None = None,
+ fast_acquire: bool = False,
+ ) -> abc.Semaphore:
+ return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire)
+
+ @classmethod
+ def create_capacity_limiter(cls, total_tokens: float) -> abc.CapacityLimiter:
+ return CapacityLimiter(total_tokens)
+
+ @classmethod
+ async def run_sync_in_worker_thread( # type: ignore[return]
+ cls,
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
+ args: tuple[Unpack[PosArgsT]],
+ abandon_on_cancel: bool = False,
+ limiter: abc.CapacityLimiter | None = None,
+ ) -> T_Retval:
+ await cls.checkpoint()
+
+ # If this is the first run in this event loop thread, set up the necessary
+ # variables
+ try:
+ idle_workers = _threadpool_idle_workers.get()
+ workers = _threadpool_workers.get()
+ except LookupError:
+ idle_workers = deque()
+ workers = set()
+ _threadpool_idle_workers.set(idle_workers)
+ _threadpool_workers.set(workers)
+
+ async with limiter or cls.current_default_thread_limiter():
+ with CancelScope(shield=not abandon_on_cancel) as scope:
+ future = asyncio.Future[T_Retval]()
+ root_task = find_root_task()
+ if not idle_workers:
+ worker = WorkerThread(root_task, workers, idle_workers)
+ worker.start()
+ workers.add(worker)
+ root_task.add_done_callback(
+ worker.stop, context=contextvars.Context()
+ )
+ else:
+ worker = idle_workers.pop()
+
+ # Prune any other workers that have been idle for MAX_IDLE_TIME
+ # seconds or longer
+ now = cls.current_time()
+ while idle_workers:
+ if (
+ now - idle_workers[0].idle_since
+ < WorkerThread.MAX_IDLE_TIME
+ ):
+ break
+
+ expired_worker = idle_workers.popleft()
+ expired_worker.root_task.remove_done_callback(
+ expired_worker.stop
+ )
+ expired_worker.stop()
+
+ context = copy_context()
+ context.run(set_current_async_library, None)
+ if abandon_on_cancel or scope._parent_scope is None:
+ worker_scope = scope
+ else:
+ worker_scope = scope._parent_scope
+
+ worker.queue.put_nowait((context, func, args, future, worker_scope))
+ return await future
+
+ @classmethod
+ def check_cancelled(cls) -> None:
+ scope: CancelScope | None = threadlocals.current_cancel_scope
+ while scope is not None:
+ if scope.cancel_called:
+ raise CancelledError(f"Cancelled via cancel scope {id(scope):x}")
+
+ if scope.shield:
+ return
+
+ scope = scope._parent_scope
+
+ @classmethod
+ def run_async_from_thread(
+ cls,
+ func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]],
+ args: tuple[Unpack[PosArgsT]],
+ token: object,
+ ) -> T_co:
+ async def task_wrapper() -> T_co:
+ __tracebackhide__ = True
+ if scope is not None:
+ task = cast(asyncio.Task, current_task())
+ _task_states[task] = TaskState(None, scope)
+ scope._tasks.add(task)
+ try:
+ return await func(*args)
+ except CancelledError as exc:
+ raise concurrent.futures.CancelledError(str(exc)) from None
+ finally:
+ if scope is not None:
+ scope._tasks.discard(task)
+
+ loop = cast(
+ "AbstractEventLoop", token or threadlocals.current_token.native_token
+ )
+ if loop.is_closed():
+ raise RunFinishedError
+
+ context = copy_context()
+ context.run(set_current_async_library, "asyncio")
+ scope = getattr(threadlocals, "current_cancel_scope", None)
+ f: concurrent.futures.Future[T_co] = context.run(
+ asyncio.run_coroutine_threadsafe, task_wrapper(), loop=loop
+ )
+ return f.result()
+
+ @classmethod
+ def run_sync_from_thread(
+ cls,
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
+ args: tuple[Unpack[PosArgsT]],
+ token: object,
+ ) -> T_Retval:
+ @wraps(func)
+ def wrapper() -> None:
+ try:
+ set_current_async_library("asyncio")
+ f.set_result(func(*args))
+ except BaseException as exc:
+ f.set_exception(exc)
+ if not isinstance(exc, Exception):
+ raise
+
+ loop = cast(
+ "AbstractEventLoop", token or threadlocals.current_token.native_token
+ )
+ if loop.is_closed():
+ raise RunFinishedError
+
+ f: concurrent.futures.Future[T_Retval] = Future()
+ loop.call_soon_threadsafe(wrapper)
+ return f.result()
+
+ @classmethod
+ async def open_process(
+ cls,
+ command: StrOrBytesPath | Sequence[StrOrBytesPath],
+ *,
+ stdin: int | IO[Any] | None,
+ stdout: int | IO[Any] | None,
+ stderr: int | IO[Any] | None,
+ **kwargs: Any,
+ ) -> Process:
+ await cls.checkpoint()
+ if isinstance(command, PathLike):
+ command = os.fspath(command)
+
+ if isinstance(command, (str, bytes)):
+ process = await asyncio.create_subprocess_shell(
+ command,
+ stdin=stdin,
+ stdout=stdout,
+ stderr=stderr,
+ **kwargs,
+ )
+ else:
+ process = await asyncio.create_subprocess_exec(
+ *command,
+ stdin=stdin,
+ stdout=stdout,
+ stderr=stderr,
+ **kwargs,
+ )
+
+ stdin_stream = StreamWriterWrapper(process.stdin) if process.stdin else None
+ stdout_stream = StreamReaderWrapper(process.stdout) if process.stdout else None
+ stderr_stream = StreamReaderWrapper(process.stderr) if process.stderr else None
+ return Process(process, stdin_stream, stdout_stream, stderr_stream)
+
+ @classmethod
+ def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None:
+ create_task(
+ _shutdown_process_pool_on_exit(workers),
+ name="AnyIO process pool shutdown task",
+ )
+ find_root_task().add_done_callback(
+ partial(_forcibly_shutdown_process_pool_on_exit, workers) # type:ignore[arg-type]
+ )
+
+ @classmethod
+ async def connect_tcp(
+ cls, host: str, port: int, local_address: IPSockAddrType | None = None
+ ) -> abc.SocketStream:
+ transport, protocol = cast(
+ tuple[asyncio.Transport, StreamProtocol],
+ await get_running_loop().create_connection(
+ StreamProtocol, host, port, local_addr=local_address
+ ),
+ )
+ transport.pause_reading()
+ return SocketStream(transport, protocol)
+
+ @classmethod
+ async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream:
+ await cls.checkpoint()
+ loop = get_running_loop()
+ raw_socket = socket.socket(socket.AF_UNIX)
+ raw_socket.setblocking(False)
+ while True:
+ try:
+ raw_socket.connect(path)
+ except BlockingIOError:
+ f: asyncio.Future = asyncio.Future()
+ loop.add_writer(raw_socket, f.set_result, None)
+ f.add_done_callback(lambda _: loop.remove_writer(raw_socket))
+ await f
+ except BaseException:
+ raw_socket.close()
+ raise
+ else:
+ return UNIXSocketStream(raw_socket)
+
+ @classmethod
+ def create_tcp_listener(cls, sock: socket.socket) -> SocketListener:
+ return TCPSocketListener(sock)
+
+ @classmethod
+ def create_unix_listener(cls, sock: socket.socket) -> SocketListener:
+ return UNIXSocketListener(sock)
+
+ @classmethod
+ async def create_udp_socket(
+ cls,
+ family: AddressFamily,
+ local_address: IPSockAddrType | None,
+ remote_address: IPSockAddrType | None,
+ reuse_port: bool,
+ ) -> UDPSocket | ConnectedUDPSocket:
+ transport, protocol = await get_running_loop().create_datagram_endpoint(
+ DatagramProtocol,
+ local_addr=local_address,
+ remote_addr=remote_address,
+ family=family,
+ reuse_port=reuse_port,
+ )
+ if protocol.exception:
+ transport.close()
+ raise protocol.exception
+
+ if not remote_address:
+ return UDPSocket(transport, protocol)
+ else:
+ return ConnectedUDPSocket(transport, protocol)
+
+ @classmethod
+ async def create_unix_datagram_socket( # type: ignore[override]
+ cls, raw_socket: socket.socket, remote_path: str | bytes | None
+ ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket:
+ await cls.checkpoint()
+ loop = get_running_loop()
+
+ if remote_path:
+ while True:
+ try:
+ raw_socket.connect(remote_path)
+ except BlockingIOError:
+ f: asyncio.Future = asyncio.Future()
+ loop.add_writer(raw_socket, f.set_result, None)
+ f.add_done_callback(lambda _: loop.remove_writer(raw_socket))
+ await f
+ except BaseException:
+ raw_socket.close()
+ raise
+ else:
+ return ConnectedUNIXDatagramSocket(raw_socket)
+ else:
+ return UNIXDatagramSocket(raw_socket)
+
+ @classmethod
+ async def getaddrinfo(
+ cls,
+ host: bytes | str | None,
+ port: str | int | None,
+ *,
+ family: int | AddressFamily = 0,
+ type: int | SocketKind = 0,
+ proto: int = 0,
+ flags: int = 0,
+ ) -> Sequence[
+ tuple[
+ AddressFamily,
+ SocketKind,
+ int,
+ str,
+ tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
+ ]
+ ]:
+ return await get_running_loop().getaddrinfo(
+ host, port, family=family, type=type, proto=proto, flags=flags
+ )
+
+ @classmethod
+ async def getnameinfo(
+ cls, sockaddr: IPSockAddrType, flags: int = 0
+ ) -> tuple[str, str]:
+ return await get_running_loop().getnameinfo(sockaddr, flags)
+
+ @classmethod
+ async def wait_readable(cls, obj: FileDescriptorLike) -> None:
+ try:
+ read_events = _read_events.get()
+ except LookupError:
+ read_events = {}
+ _read_events.set(read_events)
+
+ fd = obj if isinstance(obj, int) else obj.fileno()
+ if read_events.get(fd):
+ raise BusyResourceError("reading from")
+
+ loop = get_running_loop()
+ fut: asyncio.Future[bool] = loop.create_future()
+
+ def cb() -> None:
+ try:
+ del read_events[fd]
+ except KeyError:
+ pass
+ else:
+ remove_reader(fd)
+
+ try:
+ fut.set_result(True)
+ except asyncio.InvalidStateError:
+ pass
+
+ try:
+ loop.add_reader(fd, cb)
+ except NotImplementedError:
+ from anyio._core._asyncio_selector_thread import get_selector
+
+ selector = get_selector()
+ selector.add_reader(fd, cb)
+ remove_reader = selector.remove_reader
+ else:
+ remove_reader = loop.remove_reader
+
+ read_events[fd] = fut
+ try:
+ success = await fut
+ finally:
+ try:
+ del read_events[fd]
+ except KeyError:
+ pass
+ else:
+ remove_reader(fd)
+
+ if not success:
+ raise ClosedResourceError
+
+ @classmethod
+ async def wait_writable(cls, obj: FileDescriptorLike) -> None:
+ try:
+ write_events = _write_events.get()
+ except LookupError:
+ write_events = {}
+ _write_events.set(write_events)
+
+ fd = obj if isinstance(obj, int) else obj.fileno()
+ if write_events.get(fd):
+ raise BusyResourceError("writing to")
+
+ loop = get_running_loop()
+ fut: asyncio.Future[bool] = loop.create_future()
+
+ def cb() -> None:
+ try:
+ del write_events[fd]
+ except KeyError:
+ pass
+ else:
+ remove_writer(fd)
+
+ try:
+ fut.set_result(True)
+ except asyncio.InvalidStateError:
+ pass
+
+ try:
+ loop.add_writer(fd, cb)
+ except NotImplementedError:
+ from anyio._core._asyncio_selector_thread import get_selector
+
+ selector = get_selector()
+ selector.add_writer(fd, cb)
+ remove_writer = selector.remove_writer
+ else:
+ remove_writer = loop.remove_writer
+
+ write_events[fd] = fut
+ try:
+ success = await fut
+ finally:
+ try:
+ del write_events[fd]
+ except KeyError:
+ pass
+ else:
+ remove_writer(fd)
+
+ if not success:
+ raise ClosedResourceError
+
+ @classmethod
+ def notify_closing(cls, obj: FileDescriptorLike) -> None:
+ fd = obj if isinstance(obj, int) else obj.fileno()
+ loop = get_running_loop()
+
+ try:
+ write_events = _write_events.get()
+ except LookupError:
+ pass
+ else:
+ try:
+ fut = write_events.pop(fd)
+ except KeyError:
+ pass
+ else:
+ try:
+ fut.set_result(False)
+ except asyncio.InvalidStateError:
+ pass
+
+ try:
+ loop.remove_writer(fd)
+ except NotImplementedError:
+ from anyio._core._asyncio_selector_thread import get_selector
+
+ get_selector().remove_writer(fd)
+
+ try:
+ read_events = _read_events.get()
+ except LookupError:
+ pass
+ else:
+ try:
+ fut = read_events.pop(fd)
+ except KeyError:
+ pass
+ else:
+ try:
+ fut.set_result(False)
+ except asyncio.InvalidStateError:
+ pass
+
+ try:
+ loop.remove_reader(fd)
+ except NotImplementedError:
+ from anyio._core._asyncio_selector_thread import get_selector
+
+ get_selector().remove_reader(fd)
+
+ @classmethod
+ async def wrap_listener_socket(cls, sock: socket.socket) -> SocketListener:
+ if hasattr(socket, "AF_UNIX") and sock.family == socket.AF_UNIX:
+ return UNIXSocketListener(sock)
+
+ return TCPSocketListener(sock)
+
+ @classmethod
+ async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream:
+ transport, protocol = await get_running_loop().create_connection(
+ StreamProtocol, sock=sock
+ )
+ return SocketStream(transport, protocol)
+
+ @classmethod
+ async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream:
+ return UNIXSocketStream(sock)
+
+ @classmethod
+ async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket:
+ transport, protocol = await get_running_loop().create_datagram_endpoint(
+ DatagramProtocol, sock=sock
+ )
+ return UDPSocket(transport, protocol)
+
+ @classmethod
+ async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket:
+ transport, protocol = await get_running_loop().create_datagram_endpoint(
+ DatagramProtocol, sock=sock
+ )
+ return ConnectedUDPSocket(transport, protocol)
+
+ @classmethod
+ async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket:
+ return UNIXDatagramSocket(sock)
+
+ @classmethod
+ async def wrap_connected_unix_datagram_socket(
+ cls, sock: socket.socket
+ ) -> ConnectedUNIXDatagramSocket:
+ return ConnectedUNIXDatagramSocket(sock)
+
+ @classmethod
+ def current_default_thread_limiter(cls) -> CapacityLimiter:
+ try:
+ return _default_thread_limiter.get()
+ except LookupError:
+ limiter = CapacityLimiter(40)
+ _default_thread_limiter.set(limiter)
+ return limiter
+
+ @classmethod
+ def open_signal_receiver(
+ cls, *signals: Signals
+ ) -> AbstractContextManager[AsyncIterator[Signals]]:
+ return _SignalReceiver(signals)
+
+ @classmethod
+ def get_current_task(cls) -> TaskInfo:
+ return AsyncIOTaskInfo(current_task()) # type: ignore[arg-type]
+
+ @classmethod
+ def get_running_tasks(cls) -> Sequence[TaskInfo]:
+ return [AsyncIOTaskInfo(task) for task in all_tasks() if not task.done()]
+
+ @classmethod
+ async def wait_all_tasks_blocked(cls) -> None:
+ await cls.checkpoint()
+ this_task = current_task()
+ while True:
+ for task in all_tasks():
+ if task is this_task:
+ continue
+
+ waiter = task._fut_waiter # type: ignore[attr-defined]
+ if waiter is None or waiter.done():
+ await sleep(0.1)
+ break
+ else:
+ return
+
+ @classmethod
+ def create_test_runner(cls, options: dict[str, Any]) -> TestRunner:
+ return TestRunner(**options)
+
+
+backend_class = AsyncIOBackend
diff --git a/venv/Lib/site-packages/anyio/_backends/_trio.py b/venv/Lib/site-packages/anyio/_backends/_trio.py
new file mode 100644
index 0000000000000000000000000000000000000000..091c78c56e38bacfd35909b54a8376c0fa748a0e
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_backends/_trio.py
@@ -0,0 +1,1456 @@
+from __future__ import annotations
+
+import array
+import math
+import os
+import socket
+import sys
+import types
+import weakref
+from collections.abc import (
+ AsyncGenerator,
+ AsyncIterator,
+ Awaitable,
+ Callable,
+ Collection,
+ Coroutine,
+ Iterable,
+ Sequence,
+)
+from contextlib import AbstractContextManager
+from contextvars import Context
+from dataclasses import dataclass
+from functools import partial, wraps
+from io import IOBase
+from os import PathLike
+from signal import Signals
+from socket import AddressFamily, SocketKind
+from types import TracebackType
+from typing import (
+ IO,
+ TYPE_CHECKING,
+ Any,
+ Generic,
+ Literal,
+ NoReturn,
+ ParamSpec,
+ TypeVar,
+ cast,
+ overload,
+)
+
+import trio.from_thread
+import trio.lowlevel
+from outcome import Error, Outcome, Value
+from trio.lowlevel import (
+ current_root_task,
+ current_task,
+ notify_closing,
+ wait_readable,
+ wait_writable,
+)
+from trio.socket import SocketType as TrioSocketType
+from trio.to_thread import run_sync
+
+from .. import (
+ CapacityLimiterStatistics,
+ EventStatistics,
+ LockStatistics,
+ RunFinishedError,
+ TaskInfo,
+ WouldBlock,
+ abc,
+)
+from .._core._eventloop import claim_worker_thread
+from .._core._exceptions import (
+ BrokenResourceError,
+ BusyResourceError,
+ ClosedResourceError,
+ EndOfStream,
+)
+from .._core._sockets import convert_ipv6_sockaddr
+from .._core._streams import create_memory_object_stream
+from .._core._synchronization import (
+ CapacityLimiter as BaseCapacityLimiter,
+)
+from .._core._synchronization import Event as BaseEvent
+from .._core._synchronization import Lock as BaseLock
+from .._core._synchronization import (
+ ResourceGuard,
+ SemaphoreStatistics,
+)
+from .._core._synchronization import Semaphore as BaseSemaphore
+from .._core._tasks import CancelScope as BaseCancelScope
+from .._core._tasks import TaskHandle
+from ..abc import IPSockAddrType, UDPPacketType, UNIXDatagramPacketType
+from ..abc._eventloop import AsyncBackend, StrOrBytesPath
+from ..abc._tasks import T_contra, call_for_coroutine, get_callable_name
+from ..streams.memory import MemoryObjectSendStream
+
+if TYPE_CHECKING:
+ from _typeshed import FileDescriptorLike
+
+if sys.version_info >= (3, 11):
+ from typing import TypeVarTuple, Unpack
+else:
+ from exceptiongroup import BaseExceptionGroup
+ from typing_extensions import TypeVarTuple, Unpack
+
+T = TypeVar("T")
+T_Retval = TypeVar("T_Retval")
+T_co = TypeVar("T_co", covariant=True)
+T_SockAddr = TypeVar("T_SockAddr", str, IPSockAddrType)
+PosArgsT = TypeVarTuple("PosArgsT")
+P = ParamSpec("P")
+
+
+def ensure_returns_coro(
+ func: Callable[P, Awaitable[T_Retval]],
+) -> Callable[P, Coroutine[Any, Any, T_Retval]]:
+ @wraps(func)
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, T_Retval]:
+ awaitable = func(*args, **kwargs)
+ # Check the common case first.
+ if isinstance(awaitable, Coroutine):
+ return awaitable
+ elif not isinstance(awaitable, Awaitable):
+ # The user violated the type annotations. Still, we should pass this on to
+ # Trio so it can raise with an appropriate message.
+ return awaitable
+ else:
+
+ @wraps(func)
+ async def inner_wrapper() -> T_Retval:
+ return await awaitable
+
+ return inner_wrapper()
+
+ return wrapper
+
+
+#
+# Event loop
+#
+
+RunVar = trio.lowlevel.RunVar
+
+
+#
+# Timeouts and cancellation
+#
+
+
+class CancelScope(BaseCancelScope):
+ __slots__ = ("__original",)
+
+ def __new__(
+ cls, original: trio.CancelScope | None = None, **kwargs: object
+ ) -> CancelScope:
+ return object.__new__(cls)
+
+ def __init__(self, original: trio.CancelScope | None = None, **kwargs: Any) -> None:
+ self.__original = original or trio.CancelScope(**kwargs)
+
+ def __enter__(self) -> CancelScope:
+ self.__original.__enter__()
+ return self
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> bool:
+ return self.__original.__exit__(exc_type, exc_val, exc_tb)
+
+ def cancel(self, reason: str | None = None) -> None:
+ self.__original.cancel(reason)
+
+ @property
+ def deadline(self) -> float:
+ return self.__original.deadline
+
+ @deadline.setter
+ def deadline(self, value: float) -> None:
+ self.__original.deadline = value
+
+ @property
+ def cancel_called(self) -> bool:
+ return self.__original.cancel_called
+
+ @property
+ def cancelled_caught(self) -> bool:
+ return self.__original.cancelled_caught
+
+ @property
+ def shield(self) -> bool:
+ return self.__original.shield
+
+ @shield.setter
+ def shield(self, value: bool) -> None:
+ self.__original.shield = value
+
+
+#
+# Task groups
+#
+
+empty_start_value = object()
+
+
+class _TrioTaskStatus(Generic[T_contra], abc.TaskStatus[T_contra]):
+ early_start_value: T_contra | object = empty_start_value
+ real_task_status: trio.TaskStatus[T_contra | None] | None = None
+
+ def started(self, value: T_contra | None = None) -> None:
+ if self.real_task_status is None:
+ if self.early_start_value is not empty_start_value:
+ raise RuntimeError("called 'started' twice on the same task status")
+
+ self.early_start_value = value
+ else:
+ self.real_task_status.started(value)
+
+
+class TaskGroup(abc.TaskGroup):
+ def __init__(self) -> None:
+ self._entered = False
+ self._active = False
+ self._nursery_manager = trio.open_nursery(strict_exception_groups=True)
+ self.cancel_scope = None # type: ignore[assignment]
+
+ async def __aenter__(self) -> TaskGroup:
+ if self._entered:
+ raise RuntimeError("TaskGroup cannot be entered more than once")
+
+ self._entered = True
+ self._active = True
+ self._nursery = await self._nursery_manager.__aenter__()
+ self.cancel_scope = CancelScope(self._nursery.cancel_scope)
+ return self
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> bool:
+ try:
+ # trio.Nursery.__exit__ returns bool; .open_nursery has wrong type
+ return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb) # type: ignore[return-value]
+ except BaseExceptionGroup as exc:
+ if not exc.split(trio.Cancelled)[1]:
+ raise trio.Cancelled._create() from exc
+
+ raise
+ finally:
+ del exc_val, exc_tb
+ self._active = False
+
+ def _check_active(self, coro: Coroutine | None = None) -> None:
+ if not self._active:
+ if coro is not None:
+ coro.close()
+
+ raise RuntimeError(
+ "This task group is not active; no new tasks can be started."
+ )
+
+ def create_task(
+ self,
+ coro: Coroutine[Any, Any, T_co],
+ *,
+ name: object = None,
+ context: Context | None = None,
+ ) -> TaskHandle[T_co]:
+ if not isinstance(coro, Coroutine):
+ raise TypeError(f"expected a coroutine, got {coro.__class__.__qualname__}")
+
+ self._check_active(coro)
+ handle = TaskHandle(coro, name)
+ if context is not None:
+ context.run(
+ partial(self._nursery.start_soon, handle._run_coro, name=handle.name)
+ )
+ else:
+ self._nursery.start_soon(handle._run_coro, name=handle.name)
+
+ return handle
+
+ async def start(
+ self,
+ func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]],
+ *args: Unpack[PosArgsT],
+ name: object = None,
+ return_handle: Literal[False] | Literal[True] = False,
+ ) -> Any:
+ handle: TaskHandle[T_co]
+
+ async def run_coro_with_task_status(
+ *, task_status: trio.TaskStatus[Any]
+ ) -> None:
+ nonlocal handle
+ wrapper_task_status = _TrioTaskStatus()
+ coro = call_for_coroutine(func, args, task_status=wrapper_task_status)
+ if wrapper_task_status.early_start_value is not empty_start_value:
+ task_status.started(wrapper_task_status.early_start_value)
+ else:
+ wrapper_task_status.real_task_status = task_status
+
+ handle = TaskHandle(coro, name)
+ await handle._run_coro()
+
+ self._check_active()
+ final_name = get_callable_name(func, name)
+ start_value = await self._nursery.start(
+ run_coro_with_task_status, name=final_name
+ )
+ if return_handle:
+ handle._start_value = start_value
+ return handle
+ else:
+ return start_value
+
+
+#
+# Subprocesses
+#
+
+
+@dataclass(eq=False)
+class ReceiveStreamWrapper(abc.ByteReceiveStream):
+ _stream: trio.abc.ReceiveStream
+
+ async def receive(self, max_bytes: int | None = None) -> bytes:
+ try:
+ data = await self._stream.receive_some(max_bytes)
+ except trio.ClosedResourceError as exc:
+ raise ClosedResourceError from exc.__cause__
+ except trio.BrokenResourceError as exc:
+ raise BrokenResourceError from exc.__cause__
+
+ if data:
+ return bytes(data)
+ else:
+ raise EndOfStream
+
+ async def aclose(self) -> None:
+ await self._stream.aclose()
+
+
+@dataclass(eq=False)
+class SendStreamWrapper(abc.ByteSendStream):
+ _stream: trio.abc.SendStream
+
+ async def send(self, item: bytes) -> None:
+ try:
+ await self._stream.send_all(item)
+ except trio.ClosedResourceError as exc:
+ raise ClosedResourceError from exc.__cause__
+ except trio.BrokenResourceError as exc:
+ raise BrokenResourceError from exc.__cause__
+
+ async def aclose(self) -> None:
+ await self._stream.aclose()
+
+
+@dataclass(eq=False)
+class Process(abc.Process):
+ _process: trio.Process
+ _stdin: abc.ByteSendStream | None
+ _stdout: abc.ByteReceiveStream | None
+ _stderr: abc.ByteReceiveStream | None
+
+ async def aclose(self) -> None:
+ with CancelScope(shield=True):
+ if self._stdin:
+ await self._stdin.aclose()
+ if self._stdout:
+ await self._stdout.aclose()
+ if self._stderr:
+ await self._stderr.aclose()
+
+ try:
+ await self.wait()
+ except BaseException:
+ self.kill()
+ with CancelScope(shield=True):
+ await self.wait()
+ raise
+
+ async def wait(self) -> int:
+ return await self._process.wait()
+
+ def terminate(self) -> None:
+ self._process.terminate()
+
+ def kill(self) -> None:
+ self._process.kill()
+
+ def send_signal(self, signal: Signals) -> None:
+ self._process.send_signal(signal)
+
+ @property
+ def pid(self) -> int:
+ return self._process.pid
+
+ @property
+ def returncode(self) -> int | None:
+ return self._process.returncode
+
+ @property
+ def stdin(self) -> abc.ByteSendStream | None:
+ return self._stdin
+
+ @property
+ def stdout(self) -> abc.ByteReceiveStream | None:
+ return self._stdout
+
+ @property
+ def stderr(self) -> abc.ByteReceiveStream | None:
+ return self._stderr
+
+
+class _ProcessPoolShutdownInstrument(trio.abc.Instrument):
+ def after_run(self) -> None:
+ super().after_run()
+
+
+current_default_worker_process_limiter: trio.lowlevel.RunVar = RunVar(
+ "current_default_worker_process_limiter"
+)
+
+
+async def _shutdown_process_pool(workers: set[abc.Process]) -> None:
+ try:
+ await trio.sleep(math.inf)
+ except trio.Cancelled:
+ for process in workers:
+ if process.returncode is None:
+ process.kill()
+
+ with CancelScope(shield=True):
+ for process in workers:
+ await process.aclose()
+
+
+#
+# Sockets and networking
+#
+
+
+class _TrioSocketMixin(Generic[T_SockAddr]):
+ def __init__(self, trio_socket: TrioSocketType) -> None:
+ self._trio_socket = trio_socket
+ self._closed = False
+
+ def _check_closed(self) -> None:
+ if self._closed:
+ raise ClosedResourceError
+ if self._trio_socket.fileno() < 0:
+ raise BrokenResourceError
+
+ @property
+ def _raw_socket(self) -> socket.socket:
+ return self._trio_socket._sock # type: ignore[attr-defined]
+
+ async def aclose(self) -> None:
+ if self._trio_socket.fileno() >= 0:
+ self._closed = True
+ self._trio_socket.close()
+
+ def _convert_socket_error(self, exc: BaseException) -> NoReturn:
+ if isinstance(exc, trio.ClosedResourceError):
+ raise ClosedResourceError from exc
+ elif self._trio_socket.fileno() < 0 and self._closed:
+ raise ClosedResourceError from None
+ elif isinstance(exc, OSError):
+ raise BrokenResourceError from exc
+ else:
+ raise exc
+
+
+class SocketStream(_TrioSocketMixin, abc.SocketStream):
+ def __init__(self, trio_socket: TrioSocketType) -> None:
+ super().__init__(trio_socket)
+ self._receive_guard = ResourceGuard("reading from")
+ self._send_guard = ResourceGuard("writing to")
+
+ async def receive(self, max_bytes: int = 65536) -> bytes:
+ with self._receive_guard:
+ try:
+ data = await self._trio_socket.recv(max_bytes)
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+ if data:
+ return data
+ else:
+ raise EndOfStream
+
+ async def send(self, item: bytes) -> None:
+ with self._send_guard:
+ view = memoryview(item)
+ while view:
+ try:
+ bytes_sent = await self._trio_socket.send(view)
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+ view = view[bytes_sent:]
+
+ async def send_eof(self) -> None:
+ self._trio_socket.shutdown(socket.SHUT_WR)
+
+
+class UNIXSocketStream(SocketStream, abc.UNIXSocketStream):
+ async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]:
+ if not isinstance(msglen, int) or msglen < 0:
+ raise ValueError("msglen must be a non-negative integer")
+ if not isinstance(maxfds, int) or maxfds < 1:
+ raise ValueError("maxfds must be a positive integer")
+
+ fds = array.array("i")
+ await trio.lowlevel.checkpoint()
+ with self._receive_guard:
+ while True:
+ try:
+ message, ancdata, flags, addr = await self._trio_socket.recvmsg(
+ msglen, socket.CMSG_LEN(maxfds * fds.itemsize)
+ )
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+ else:
+ if not message and not ancdata:
+ raise EndOfStream
+
+ break
+
+ for cmsg_level, cmsg_type, cmsg_data in ancdata:
+ if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS:
+ raise RuntimeError(
+ f"Received unexpected ancillary data; message = {message!r}, "
+ f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}"
+ )
+
+ fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
+
+ return message, list(fds)
+
+ async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None:
+ if not message:
+ raise ValueError("message must not be empty")
+ if not fds:
+ raise ValueError("fds must not be empty")
+
+ filenos: list[int] = []
+ for fd in fds:
+ if isinstance(fd, int):
+ filenos.append(fd)
+ elif isinstance(fd, IOBase):
+ filenos.append(fd.fileno())
+
+ fdarray = array.array("i", filenos)
+ await trio.lowlevel.checkpoint()
+ with self._send_guard:
+ while True:
+ try:
+ await self._trio_socket.sendmsg(
+ [message],
+ [
+ (
+ socket.SOL_SOCKET,
+ socket.SCM_RIGHTS,
+ fdarray,
+ )
+ ],
+ )
+ break
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+
+class TCPSocketListener(_TrioSocketMixin, abc.SocketListener):
+ def __init__(self, raw_socket: socket.socket):
+ super().__init__(trio.socket.from_stdlib_socket(raw_socket))
+ self._accept_guard = ResourceGuard("accepting connections from")
+
+ async def accept(self) -> SocketStream:
+ with self._accept_guard:
+ try:
+ trio_socket, _addr = await self._trio_socket.accept()
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+ trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+ return SocketStream(trio_socket)
+
+
+class UNIXSocketListener(_TrioSocketMixin, abc.SocketListener):
+ def __init__(self, raw_socket: socket.socket):
+ super().__init__(trio.socket.from_stdlib_socket(raw_socket))
+ self._accept_guard = ResourceGuard("accepting connections from")
+
+ async def accept(self) -> UNIXSocketStream:
+ with self._accept_guard:
+ try:
+ trio_socket, _addr = await self._trio_socket.accept()
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+ return UNIXSocketStream(trio_socket)
+
+
+class UDPSocket(_TrioSocketMixin[IPSockAddrType], abc.UDPSocket):
+ def __init__(self, trio_socket: TrioSocketType) -> None:
+ super().__init__(trio_socket)
+ self._receive_guard = ResourceGuard("reading from")
+ self._send_guard = ResourceGuard("writing to")
+
+ async def receive(self) -> tuple[bytes, IPSockAddrType]:
+ with self._receive_guard:
+ try:
+ data, addr = await self._trio_socket.recvfrom(65536)
+ return data, convert_ipv6_sockaddr(addr)
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+ async def send(self, item: UDPPacketType) -> None:
+ with self._send_guard:
+ try:
+ await self._trio_socket.sendto(*item)
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+
+class ConnectedUDPSocket(_TrioSocketMixin[IPSockAddrType], abc.ConnectedUDPSocket):
+ def __init__(self, trio_socket: TrioSocketType) -> None:
+ super().__init__(trio_socket)
+ self._receive_guard = ResourceGuard("reading from")
+ self._send_guard = ResourceGuard("writing to")
+
+ async def receive(self) -> bytes:
+ with self._receive_guard:
+ try:
+ return await self._trio_socket.recv(65536)
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+ async def send(self, item: bytes) -> None:
+ with self._send_guard:
+ try:
+ await self._trio_socket.send(item)
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+
+class UNIXDatagramSocket(_TrioSocketMixin[str], abc.UNIXDatagramSocket):
+ def __init__(self, trio_socket: TrioSocketType) -> None:
+ super().__init__(trio_socket)
+ self._receive_guard = ResourceGuard("reading from")
+ self._send_guard = ResourceGuard("writing to")
+
+ async def receive(self) -> UNIXDatagramPacketType:
+ with self._receive_guard:
+ try:
+ data, addr = await self._trio_socket.recvfrom(65536)
+ return data, addr
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+ async def send(self, item: UNIXDatagramPacketType) -> None:
+ with self._send_guard:
+ try:
+ await self._trio_socket.sendto(*item)
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+
+class ConnectedUNIXDatagramSocket(
+ _TrioSocketMixin[str], abc.ConnectedUNIXDatagramSocket
+):
+ def __init__(self, trio_socket: TrioSocketType) -> None:
+ super().__init__(trio_socket)
+ self._receive_guard = ResourceGuard("reading from")
+ self._send_guard = ResourceGuard("writing to")
+
+ async def receive(self) -> bytes:
+ with self._receive_guard:
+ try:
+ return await self._trio_socket.recv(65536)
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+ async def send(self, item: bytes) -> None:
+ with self._send_guard:
+ try:
+ await self._trio_socket.send(item)
+ except BaseException as exc:
+ self._convert_socket_error(exc)
+
+
+#
+# Synchronization
+#
+
+
+class Event(BaseEvent):
+ __slots__ = ("__original",)
+
+ def __new__(cls) -> Event:
+ return object.__new__(cls)
+
+ def __init__(self) -> None:
+ self.__original = trio.Event()
+
+ def is_set(self) -> bool:
+ return self.__original.is_set()
+
+ async def wait(self) -> None:
+ return await self.__original.wait()
+
+ def statistics(self) -> EventStatistics:
+ orig_statistics = self.__original.statistics()
+ return EventStatistics(tasks_waiting=orig_statistics.tasks_waiting)
+
+ def set(self) -> None:
+ self.__original.set()
+
+
+class Lock(BaseLock):
+ __slots__ = "_fast_acquire", "__original"
+
+ def __new__(cls, *, fast_acquire: bool = False) -> Lock:
+ return object.__new__(cls)
+
+ def __init__(self, *, fast_acquire: bool = False) -> None:
+ self._fast_acquire = fast_acquire
+ self.__original = trio.Lock()
+
+ @staticmethod
+ def _convert_runtime_error_msg(exc: RuntimeError) -> None:
+ if exc.args == ("attempt to re-acquire an already held Lock",):
+ exc.args = ("Attempted to acquire an already held Lock",)
+
+ async def acquire(self) -> None:
+ if not self._fast_acquire:
+ try:
+ await self.__original.acquire()
+ except RuntimeError as exc:
+ self._convert_runtime_error_msg(exc)
+ raise
+
+ return
+
+ # This is the "fast path" where we don't let other tasks run
+ await trio.lowlevel.checkpoint_if_cancelled()
+ try:
+ self.__original.acquire_nowait()
+ except trio.WouldBlock:
+ await self.__original._lot.park()
+ except RuntimeError as exc:
+ self._convert_runtime_error_msg(exc)
+ raise
+
+ def acquire_nowait(self) -> None:
+ try:
+ self.__original.acquire_nowait()
+ except trio.WouldBlock:
+ raise WouldBlock from None
+ except RuntimeError as exc:
+ self._convert_runtime_error_msg(exc)
+ raise
+
+ def locked(self) -> bool:
+ return self.__original.locked()
+
+ def release(self) -> None:
+ self.__original.release()
+
+ def statistics(self) -> LockStatistics:
+ orig_statistics = self.__original.statistics()
+ owner = TrioTaskInfo(orig_statistics.owner) if orig_statistics.owner else None
+ return LockStatistics(
+ orig_statistics.locked, owner, orig_statistics.tasks_waiting
+ )
+
+
+class Semaphore(BaseSemaphore):
+ __slots__ = ("__original",)
+
+ def __new__(
+ cls,
+ initial_value: int,
+ *,
+ max_value: int | None = None,
+ fast_acquire: bool = False,
+ ) -> Semaphore:
+ return object.__new__(cls)
+
+ def __init__(
+ self,
+ initial_value: int,
+ *,
+ max_value: int | None = None,
+ fast_acquire: bool = False,
+ ) -> None:
+ super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire)
+ self.__original = trio.Semaphore(initial_value, max_value=max_value)
+
+ async def acquire(self) -> None:
+ if not self._fast_acquire:
+ await self.__original.acquire()
+ return
+
+ # This is the "fast path" where we don't let other tasks run
+ await trio.lowlevel.checkpoint_if_cancelled()
+ try:
+ self.__original.acquire_nowait()
+ except trio.WouldBlock:
+ await self.__original._lot.park()
+
+ def acquire_nowait(self) -> None:
+ try:
+ self.__original.acquire_nowait()
+ except trio.WouldBlock:
+ raise WouldBlock from None
+
+ @property
+ def max_value(self) -> int | None:
+ return self.__original.max_value
+
+ @property
+ def value(self) -> int:
+ return self.__original.value
+
+ def release(self) -> None:
+ self.__original.release()
+
+ def statistics(self) -> SemaphoreStatistics:
+ orig_statistics = self.__original.statistics()
+ return SemaphoreStatistics(orig_statistics.tasks_waiting)
+
+
+class CapacityLimiter(BaseCapacityLimiter):
+ __slots__ = ("__original",)
+
+ def __new__(
+ cls,
+ total_tokens: float | None = None,
+ *,
+ original: trio.CapacityLimiter | None = None,
+ ) -> CapacityLimiter:
+ return object.__new__(cls)
+
+ def __init__(
+ self,
+ total_tokens: float | None = None,
+ *,
+ original: trio.CapacityLimiter | None = None,
+ ) -> None:
+ if original is not None:
+ self.__original = original
+ else:
+ assert total_tokens is not None
+ self.__original = trio.CapacityLimiter(total_tokens)
+
+ async def __aenter__(self) -> None:
+ return await self.__original.__aenter__()
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ await self.__original.__aexit__(exc_type, exc_val, exc_tb)
+
+ @property
+ def total_tokens(self) -> float:
+ return self.__original.total_tokens
+
+ @total_tokens.setter
+ def total_tokens(self, value: float) -> None:
+ self.__original.total_tokens = value
+
+ @property
+ def borrowed_tokens(self) -> int:
+ return self.__original.borrowed_tokens
+
+ @property
+ def available_tokens(self) -> float:
+ return self.__original.available_tokens
+
+ def acquire_nowait(self) -> None:
+ self.__original.acquire_nowait()
+
+ def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
+ self.__original.acquire_on_behalf_of_nowait(borrower)
+
+ async def acquire(self) -> None:
+ await self.__original.acquire()
+
+ async def acquire_on_behalf_of(self, borrower: object) -> None:
+ await self.__original.acquire_on_behalf_of(borrower)
+
+ def release(self) -> None:
+ return self.__original.release()
+
+ def release_on_behalf_of(self, borrower: object) -> None:
+ return self.__original.release_on_behalf_of(borrower)
+
+ def statistics(self) -> CapacityLimiterStatistics:
+ orig = self.__original.statistics()
+ return CapacityLimiterStatistics(
+ borrowed_tokens=orig.borrowed_tokens,
+ total_tokens=orig.total_tokens,
+ borrowers=tuple(orig.borrowers),
+ tasks_waiting=orig.tasks_waiting,
+ )
+
+
+_capacity_limiter_wrapper: trio.lowlevel.RunVar = RunVar("_capacity_limiter_wrapper")
+
+
+#
+# Signal handling
+#
+
+
+class _SignalReceiver:
+ _iterator: AsyncIterator[int]
+
+ def __init__(self, signals: tuple[Signals, ...]):
+ self._signals = signals
+
+ def __enter__(self) -> _SignalReceiver:
+ self._cm = trio.open_signal_receiver(*self._signals)
+ self._iterator = self._cm.__enter__()
+ return self
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> bool | None:
+ return self._cm.__exit__(exc_type, exc_val, exc_tb)
+
+ def __aiter__(self) -> _SignalReceiver:
+ return self
+
+ async def __anext__(self) -> Signals:
+ signum = await self._iterator.__anext__()
+ return Signals(signum)
+
+
+#
+# Testing and debugging
+#
+
+
+class TestRunner(abc.TestRunner):
+ def __init__(self, **options: Any) -> None:
+ from queue import Queue
+
+ self._call_queue: Queue[Callable[[], object]] = Queue()
+ self._send_stream: (
+ MemoryObjectSendStream[tuple[Awaitable[Any], list[Outcome]]] | None
+ ) = None
+ self._options = options
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: types.TracebackType | None,
+ ) -> None:
+ if self._send_stream:
+ self._send_stream.close()
+ while self._send_stream is not None:
+ self._call_queue.get()()
+
+ def is_running(self) -> bool:
+ return trio.lowlevel.in_trio_task()
+
+ async def _run_tests_and_fixtures(self) -> None:
+ self._send_stream, receive_stream = create_memory_object_stream[
+ tuple[Awaitable[Any], list[Outcome]]
+ ](1)
+ with receive_stream:
+ async for awaitable, outcome_holder in receive_stream:
+ try:
+ retval = await awaitable
+ except BaseException as exc:
+ outcome_holder.append(Error(exc))
+ else:
+ outcome_holder.append(Value(retval))
+
+ def _main_task_finished(self, outcome: object) -> None:
+ self._send_stream = None
+
+ def _call_in_runner_task(
+ self,
+ func: Callable[P, Awaitable[T_Retval]],
+ /,
+ *args: P.args,
+ **kwargs: P.kwargs,
+ ) -> T_Retval:
+ if self._send_stream is None:
+ trio.lowlevel.start_guest_run(
+ self._run_tests_and_fixtures,
+ run_sync_soon_threadsafe=self._call_queue.put,
+ done_callback=self._main_task_finished,
+ **self._options,
+ )
+ while self._send_stream is None:
+ self._call_queue.get()()
+
+ outcome_holder: list[Outcome] = []
+ self._send_stream.send_nowait((func(*args, **kwargs), outcome_holder))
+ while not outcome_holder:
+ self._call_queue.get()()
+
+ return outcome_holder[0].unwrap()
+
+ def run_asyncgen_fixture(
+ self,
+ fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]],
+ kwargs: dict[str, Any],
+ ) -> Iterable[T_Retval]:
+ asyncgen = fixture_func(**kwargs)
+ fixturevalue: T_Retval = self._call_in_runner_task(asyncgen.asend, None)
+
+ yield fixturevalue
+
+ try:
+ self._call_in_runner_task(asyncgen.asend, None)
+ except StopAsyncIteration:
+ pass
+ else:
+ self._call_in_runner_task(asyncgen.aclose)
+ raise RuntimeError("Async generator fixture did not stop")
+
+ def run_fixture(
+ self,
+ fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]],
+ kwargs: dict[str, Any],
+ ) -> T_Retval:
+ return self._call_in_runner_task(fixture_func, **kwargs)
+
+ def run_test(
+ self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any]
+ ) -> None:
+ self._call_in_runner_task(test_func, **kwargs)
+
+
+class TrioTaskInfo(TaskInfo):
+ def __init__(self, task: trio.lowlevel.Task):
+ parent_id = None
+ if task.parent_nursery and task.parent_nursery.parent_task:
+ parent_id = id(task.parent_nursery.parent_task)
+
+ super().__init__(id(task), parent_id, task.name, task.coro)
+ self._task = weakref.proxy(task)
+
+ def has_pending_cancellation(self) -> bool:
+ try:
+ return self._task._cancel_status.effectively_cancelled
+ except ReferenceError:
+ # If the task is no longer around, it surely doesn't have a cancellation
+ # pending
+ return False
+
+
+class TrioBackend(AsyncBackend):
+ @classmethod
+ def run(
+ cls,
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+ args: tuple[Unpack[PosArgsT]],
+ kwargs: dict[str, Any],
+ options: dict[str, Any],
+ ) -> T_Retval:
+ assert not kwargs, "unreachable, and not supported by Trio"
+ return trio.run(ensure_returns_coro(func), *args, **options)
+
+ @classmethod
+ def current_token(cls) -> object:
+ return trio.lowlevel.current_trio_token()
+
+ @classmethod
+ def current_time(cls) -> float:
+ return trio.current_time()
+
+ @classmethod
+ def cancelled_exception_class(cls) -> type[BaseException]:
+ return trio.Cancelled
+
+ @classmethod
+ async def checkpoint(cls) -> None:
+ await trio.lowlevel.checkpoint()
+
+ @classmethod
+ async def checkpoint_if_cancelled(cls) -> None:
+ await trio.lowlevel.checkpoint_if_cancelled()
+
+ @classmethod
+ async def cancel_shielded_checkpoint(cls) -> None:
+ await trio.lowlevel.cancel_shielded_checkpoint()
+
+ @classmethod
+ async def sleep(cls, delay: float) -> None:
+ await trio.sleep(delay)
+
+ @classmethod
+ def create_cancel_scope(
+ cls, *, deadline: float = math.inf, shield: bool = False
+ ) -> abc.CancelScope:
+ return CancelScope(deadline=deadline, shield=shield)
+
+ @classmethod
+ def current_effective_deadline(cls) -> float:
+ return trio.current_effective_deadline()
+
+ @classmethod
+ def create_task_group(cls) -> abc.TaskGroup:
+ return TaskGroup()
+
+ @classmethod
+ def create_event(cls) -> abc.Event:
+ return Event()
+
+ @classmethod
+ def create_lock(cls, *, fast_acquire: bool) -> Lock:
+ return Lock(fast_acquire=fast_acquire)
+
+ @classmethod
+ def create_semaphore(
+ cls,
+ initial_value: int,
+ *,
+ max_value: int | None = None,
+ fast_acquire: bool = False,
+ ) -> abc.Semaphore:
+ return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire)
+
+ @classmethod
+ def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter:
+ return CapacityLimiter(total_tokens)
+
+ @classmethod
+ async def run_sync_in_worker_thread(
+ cls,
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
+ args: tuple[Unpack[PosArgsT]],
+ abandon_on_cancel: bool = False,
+ limiter: abc.CapacityLimiter | None = None,
+ ) -> T_Retval:
+ def wrapper() -> T_Retval:
+ with claim_worker_thread(TrioBackend, token):
+ return func(*args)
+
+ token = TrioBackend.current_token()
+ return await run_sync(
+ wrapper,
+ abandon_on_cancel=abandon_on_cancel,
+ limiter=cast(trio.CapacityLimiter, limiter),
+ )
+
+ @classmethod
+ def check_cancelled(cls) -> None:
+ trio.from_thread.check_cancelled()
+
+ @classmethod
+ def run_async_from_thread(
+ cls,
+ func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]],
+ args: tuple[Unpack[PosArgsT]],
+ token: object,
+ ) -> T_co:
+ trio_token = cast("trio.lowlevel.TrioToken | None", token)
+ try:
+ return trio.from_thread.run(func, *args, trio_token=trio_token)
+ except trio.RunFinishedError:
+ raise RunFinishedError from None
+
+ @classmethod
+ def run_sync_from_thread(
+ cls,
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
+ args: tuple[Unpack[PosArgsT]],
+ token: object,
+ ) -> T_Retval:
+ trio_token = cast("trio.lowlevel.TrioToken | None", token)
+ try:
+ return trio.from_thread.run_sync(func, *args, trio_token=trio_token)
+ except trio.RunFinishedError:
+ raise RunFinishedError from None
+
+ @classmethod
+ async def open_process(
+ cls,
+ command: StrOrBytesPath | Sequence[StrOrBytesPath],
+ *,
+ stdin: int | IO[Any] | None,
+ stdout: int | IO[Any] | None,
+ stderr: int | IO[Any] | None,
+ **kwargs: Any,
+ ) -> Process:
+ def convert_item(item: StrOrBytesPath) -> str:
+ str_or_bytes = os.fspath(item)
+ if isinstance(str_or_bytes, str):
+ return str_or_bytes
+ else:
+ return os.fsdecode(str_or_bytes)
+
+ if isinstance(command, (str, bytes, PathLike)):
+ process = await trio.lowlevel.open_process(
+ convert_item(command),
+ stdin=stdin,
+ stdout=stdout,
+ stderr=stderr,
+ shell=True,
+ **kwargs,
+ )
+ else:
+ process = await trio.lowlevel.open_process(
+ [convert_item(item) for item in command],
+ stdin=stdin,
+ stdout=stdout,
+ stderr=stderr,
+ shell=False,
+ **kwargs,
+ )
+
+ stdin_stream = SendStreamWrapper(process.stdin) if process.stdin else None
+ stdout_stream = ReceiveStreamWrapper(process.stdout) if process.stdout else None
+ stderr_stream = ReceiveStreamWrapper(process.stderr) if process.stderr else None
+ return Process(process, stdin_stream, stdout_stream, stderr_stream)
+
+ @classmethod
+ def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None:
+ trio.lowlevel.spawn_system_task(_shutdown_process_pool, workers)
+
+ @classmethod
+ async def connect_tcp(
+ cls, host: str, port: int, local_address: IPSockAddrType | None = None
+ ) -> SocketStream:
+ family = socket.AF_INET6 if ":" in host else socket.AF_INET
+ trio_socket = trio.socket.socket(family)
+ trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+ if local_address:
+ await trio_socket.bind(local_address)
+
+ try:
+ await trio_socket.connect((host, port))
+ except BaseException:
+ trio_socket.close()
+ raise
+
+ return SocketStream(trio_socket)
+
+ @classmethod
+ async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream:
+ trio_socket = trio.socket.socket(socket.AF_UNIX)
+ try:
+ await trio_socket.connect(path)
+ except BaseException:
+ trio_socket.close()
+ raise
+
+ return UNIXSocketStream(trio_socket)
+
+ @classmethod
+ def create_tcp_listener(cls, sock: socket.socket) -> abc.SocketListener:
+ return TCPSocketListener(sock)
+
+ @classmethod
+ def create_unix_listener(cls, sock: socket.socket) -> abc.SocketListener:
+ return UNIXSocketListener(sock)
+
+ @classmethod
+ async def create_udp_socket(
+ cls,
+ family: socket.AddressFamily,
+ local_address: IPSockAddrType | None,
+ remote_address: IPSockAddrType | None,
+ reuse_port: bool,
+ ) -> UDPSocket | ConnectedUDPSocket:
+ trio_socket = trio.socket.socket(family=family, type=socket.SOCK_DGRAM)
+
+ if reuse_port:
+ trio_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
+
+ if local_address:
+ await trio_socket.bind(local_address)
+
+ if remote_address:
+ await trio_socket.connect(remote_address)
+ return ConnectedUDPSocket(trio_socket)
+ else:
+ return UDPSocket(trio_socket)
+
+ @classmethod
+ @overload
+ async def create_unix_datagram_socket(
+ cls, raw_socket: socket.socket, remote_path: None
+ ) -> abc.UNIXDatagramSocket: ...
+
+ @classmethod
+ @overload
+ async def create_unix_datagram_socket(
+ cls, raw_socket: socket.socket, remote_path: str | bytes
+ ) -> abc.ConnectedUNIXDatagramSocket: ...
+
+ @classmethod
+ async def create_unix_datagram_socket(
+ cls, raw_socket: socket.socket, remote_path: str | bytes | None
+ ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket:
+ trio_socket = trio.socket.from_stdlib_socket(raw_socket)
+
+ if remote_path:
+ await trio_socket.connect(remote_path)
+ return ConnectedUNIXDatagramSocket(trio_socket)
+ else:
+ return UNIXDatagramSocket(trio_socket)
+
+ @classmethod
+ async def getaddrinfo(
+ cls,
+ host: bytes | str | None,
+ port: str | int | None,
+ *,
+ family: int | AddressFamily = 0,
+ type: int | SocketKind = 0,
+ proto: int = 0,
+ flags: int = 0,
+ ) -> Sequence[
+ tuple[
+ AddressFamily,
+ SocketKind,
+ int,
+ str,
+ tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
+ ]
+ ]:
+ return await trio.socket.getaddrinfo(host, port, family, type, proto, flags)
+
+ @classmethod
+ async def getnameinfo(
+ cls, sockaddr: IPSockAddrType, flags: int = 0
+ ) -> tuple[str, str]:
+ return await trio.socket.getnameinfo(sockaddr, flags)
+
+ @classmethod
+ async def wait_readable(cls, obj: FileDescriptorLike) -> None:
+ try:
+ await wait_readable(obj)
+ except trio.ClosedResourceError as exc:
+ raise ClosedResourceError().with_traceback(exc.__traceback__) from None
+ except trio.BusyResourceError:
+ raise BusyResourceError("reading from") from None
+
+ @classmethod
+ async def wait_writable(cls, obj: FileDescriptorLike) -> None:
+ try:
+ await wait_writable(obj)
+ except trio.ClosedResourceError as exc:
+ raise ClosedResourceError().with_traceback(exc.__traceback__) from None
+ except trio.BusyResourceError:
+ raise BusyResourceError("writing to") from None
+
+ @classmethod
+ def notify_closing(cls, obj: FileDescriptorLike) -> None:
+ notify_closing(obj)
+
+ @classmethod
+ async def wrap_listener_socket(cls, sock: socket.socket) -> abc.SocketListener:
+ if hasattr(socket, "AF_UNIX") and sock.family == socket.AF_UNIX:
+ return UNIXSocketListener(sock)
+
+ return TCPSocketListener(sock)
+
+ @classmethod
+ async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream:
+ trio_sock = trio.socket.from_stdlib_socket(sock)
+ return SocketStream(trio_sock)
+
+ @classmethod
+ async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream:
+ trio_sock = trio.socket.from_stdlib_socket(sock)
+ return UNIXSocketStream(trio_sock)
+
+ @classmethod
+ async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket:
+ trio_sock = trio.socket.from_stdlib_socket(sock)
+ return UDPSocket(trio_sock)
+
+ @classmethod
+ async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket:
+ trio_sock = trio.socket.from_stdlib_socket(sock)
+ return ConnectedUDPSocket(trio_sock)
+
+ @classmethod
+ async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket:
+ trio_sock = trio.socket.from_stdlib_socket(sock)
+ return UNIXDatagramSocket(trio_sock)
+
+ @classmethod
+ async def wrap_connected_unix_datagram_socket(
+ cls, sock: socket.socket
+ ) -> ConnectedUNIXDatagramSocket:
+ trio_sock = trio.socket.from_stdlib_socket(sock)
+ return ConnectedUNIXDatagramSocket(trio_sock)
+
+ @classmethod
+ def current_default_thread_limiter(cls) -> CapacityLimiter:
+ try:
+ return _capacity_limiter_wrapper.get()
+ except LookupError:
+ limiter = CapacityLimiter(
+ original=trio.to_thread.current_default_thread_limiter()
+ )
+ _capacity_limiter_wrapper.set(limiter)
+ return limiter
+
+ @classmethod
+ def open_signal_receiver(
+ cls, *signals: Signals
+ ) -> AbstractContextManager[AsyncIterator[Signals]]:
+ return _SignalReceiver(signals)
+
+ @classmethod
+ def get_current_task(cls) -> TaskInfo:
+ task = current_task()
+ return TrioTaskInfo(task)
+
+ @classmethod
+ def get_running_tasks(cls) -> Sequence[TaskInfo]:
+ root_task = current_root_task()
+ assert root_task
+ task_infos = [TrioTaskInfo(root_task)]
+ nurseries = root_task.child_nurseries
+ while nurseries:
+ new_nurseries: list[trio.Nursery] = []
+ for nursery in nurseries:
+ for task in nursery.child_tasks:
+ task_infos.append(TrioTaskInfo(task))
+ new_nurseries.extend(task.child_nurseries)
+
+ nurseries = new_nurseries
+
+ return task_infos
+
+ @classmethod
+ async def wait_all_tasks_blocked(cls) -> None:
+ from trio.testing import wait_all_tasks_blocked
+
+ await wait_all_tasks_blocked()
+
+ @classmethod
+ def create_test_runner(cls, options: dict[str, Any]) -> TestRunner:
+ return TestRunner(**options)
+
+
+backend_class = TrioBackend
diff --git a/venv/Lib/site-packages/anyio/_core/__init__.py b/venv/Lib/site-packages/anyio/_core/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py b/venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f35bae568e33e6a9e1219761c83cc8350fa0532
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py
@@ -0,0 +1,167 @@
+from __future__ import annotations
+
+import asyncio
+import socket
+import threading
+from collections.abc import Callable
+from selectors import EVENT_READ, EVENT_WRITE, DefaultSelector
+from typing import TYPE_CHECKING, Any
+
+if TYPE_CHECKING:
+ from _typeshed import FileDescriptorLike
+
+_selector_lock = threading.Lock()
+_selector: Selector | None = None
+
+
+class Selector:
+ def __init__(self) -> None:
+ self._thread = threading.Thread(target=self.run, name="AnyIO socket selector")
+ self._selector = DefaultSelector()
+ self._send, self._receive = socket.socketpair()
+ self._send.setblocking(False)
+ self._receive.setblocking(False)
+ # This somewhat reduces the amount of memory wasted queueing up data
+ # for wakeups. With these settings, maximum number of 1-byte sends
+ # before getting BlockingIOError:
+ # Linux 4.8: 6
+ # macOS (darwin 15.5): 1
+ # Windows 10: 525347
+ # Windows you're weird. (And on Windows setting SNDBUF to 0 makes send
+ # blocking, even on non-blocking sockets, so don't do that.)
+ self._receive.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1)
+ self._send.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1)
+ # On Windows this is a TCP socket so this might matter. On other
+ # platforms this fails b/c AF_UNIX sockets aren't actually TCP.
+ try:
+ self._send.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+ except OSError:
+ pass
+
+ self._selector.register(self._receive, EVENT_READ)
+ self._closed = False
+
+ def start(self) -> None:
+ self._thread.start()
+ threading._register_atexit(self._stop) # type: ignore[attr-defined]
+
+ def _stop(self) -> None:
+ global _selector
+ self._closed = True
+ self._notify_self()
+ self._send.close()
+ self._thread.join()
+ self._selector.unregister(self._receive)
+ self._receive.close()
+ self._selector.close()
+ _selector = None
+ assert not self._selector.get_map(), (
+ "selector still has registered file descriptors after shutdown"
+ )
+
+ def _notify_self(self) -> None:
+ try:
+ self._send.send(b"\x00")
+ except BlockingIOError:
+ pass
+
+ def add_reader(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None:
+ loop = asyncio.get_running_loop()
+ try:
+ key = self._selector.get_key(fd)
+ except KeyError:
+ self._selector.register(fd, EVENT_READ, {EVENT_READ: (loop, callback)})
+ else:
+ if EVENT_READ in key.data:
+ raise ValueError(
+ "this file descriptor is already registered for reading"
+ )
+
+ key.data[EVENT_READ] = loop, callback
+ self._selector.modify(fd, key.events | EVENT_READ, key.data)
+
+ self._notify_self()
+
+ def add_writer(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None:
+ loop = asyncio.get_running_loop()
+ try:
+ key = self._selector.get_key(fd)
+ except KeyError:
+ self._selector.register(fd, EVENT_WRITE, {EVENT_WRITE: (loop, callback)})
+ else:
+ if EVENT_WRITE in key.data:
+ raise ValueError(
+ "this file descriptor is already registered for writing"
+ )
+
+ key.data[EVENT_WRITE] = loop, callback
+ self._selector.modify(fd, key.events | EVENT_WRITE, key.data)
+
+ self._notify_self()
+
+ def remove_reader(self, fd: FileDescriptorLike) -> bool:
+ try:
+ key = self._selector.get_key(fd)
+ except KeyError:
+ return False
+
+ if new_events := key.events ^ EVENT_READ:
+ del key.data[EVENT_READ]
+ self._selector.modify(fd, new_events, key.data)
+ else:
+ self._selector.unregister(fd)
+
+ return True
+
+ def remove_writer(self, fd: FileDescriptorLike) -> bool:
+ try:
+ key = self._selector.get_key(fd)
+ except KeyError:
+ return False
+
+ if new_events := key.events ^ EVENT_WRITE:
+ del key.data[EVENT_WRITE]
+ self._selector.modify(fd, new_events, key.data)
+ else:
+ self._selector.unregister(fd)
+
+ return True
+
+ def run(self) -> None:
+ while not self._closed:
+ for key, events in self._selector.select():
+ if key.fileobj is self._receive:
+ try:
+ while self._receive.recv(4096):
+ pass
+ except BlockingIOError:
+ pass
+
+ continue
+
+ if events & EVENT_READ:
+ loop, callback = key.data[EVENT_READ]
+ self.remove_reader(key.fd)
+ try:
+ loop.call_soon_threadsafe(callback)
+ except RuntimeError:
+ pass # the loop was already closed
+
+ if events & EVENT_WRITE:
+ loop, callback = key.data[EVENT_WRITE]
+ self.remove_writer(key.fd)
+ try:
+ loop.call_soon_threadsafe(callback)
+ except RuntimeError:
+ pass # the loop was already closed
+
+
+def get_selector() -> Selector:
+ global _selector
+
+ with _selector_lock:
+ if _selector is None:
+ _selector = Selector()
+ _selector.start()
+
+ return _selector
diff --git a/venv/Lib/site-packages/anyio/_core/_contextmanagers.py b/venv/Lib/site-packages/anyio/_core/_contextmanagers.py
new file mode 100644
index 0000000000000000000000000000000000000000..302f32b0c78a7071605b195c55054cfdb0b55f37
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_contextmanagers.py
@@ -0,0 +1,200 @@
+from __future__ import annotations
+
+from abc import abstractmethod
+from contextlib import AbstractAsyncContextManager, AbstractContextManager
+from inspect import isasyncgen, iscoroutine, isgenerator
+from types import TracebackType
+from typing import Protocol, TypeVar, cast, final
+
+_T_co = TypeVar("_T_co", covariant=True)
+_ExitT_co = TypeVar("_ExitT_co", covariant=True, bound="bool | None")
+
+
+class _SupportsCtxMgr(Protocol[_T_co, _ExitT_co]):
+ def __contextmanager__(self) -> AbstractContextManager[_T_co, _ExitT_co]: ...
+
+
+class _SupportsAsyncCtxMgr(Protocol[_T_co, _ExitT_co]):
+ def __asynccontextmanager__(
+ self,
+ ) -> AbstractAsyncContextManager[_T_co, _ExitT_co]: ...
+
+
+class ContextManagerMixin:
+ """
+ Mixin class providing context manager functionality via a generator-based
+ implementation.
+
+ This class allows you to implement a context manager via :meth:`__contextmanager__`
+ which should return a generator. The mechanics are meant to mirror those of
+ :func:`@contextmanager `.
+
+ .. note:: Classes using this mix-in are not reentrant as context managers, meaning
+ that once you enter it, you can't re-enter before first exiting it.
+
+ .. seealso:: :doc:`contextmanagers`
+ """
+
+ __cm: AbstractContextManager[object, bool | None] | None = None
+
+ @final
+ def __enter__(self: _SupportsCtxMgr[_T_co, bool | None]) -> _T_co:
+ # Needed for mypy to assume self still has the __cm member
+ assert isinstance(self, ContextManagerMixin)
+ if self.__cm is not None:
+ raise RuntimeError(
+ f"this {self.__class__.__qualname__} has already been entered"
+ )
+
+ cm = self.__contextmanager__()
+ if not isinstance(cm, AbstractContextManager):
+ if isgenerator(cm):
+ raise TypeError(
+ "__contextmanager__() returned a generator object instead of "
+ "a context manager. Did you forget to add the @contextmanager "
+ "decorator?"
+ )
+
+ raise TypeError(
+ f"__contextmanager__() did not return a context manager object, "
+ f"but {cm.__class__!r}"
+ )
+
+ if cm is self:
+ raise TypeError(
+ f"{self.__class__.__qualname__}.__contextmanager__() returned "
+ f"self. Did you forget to add the @contextmanager decorator and a "
+ f"'yield' statement?"
+ )
+
+ value = cm.__enter__()
+ self.__cm = cm
+ return value
+
+ @final
+ def __exit__(
+ self: _SupportsCtxMgr[object, _ExitT_co],
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> _ExitT_co:
+ # Needed for mypy to assume self still has the __cm member
+ assert isinstance(self, ContextManagerMixin)
+ if self.__cm is None:
+ raise RuntimeError(
+ f"this {self.__class__.__qualname__} has not been entered yet"
+ )
+
+ # Prevent circular references
+ cm = self.__cm
+ del self.__cm
+
+ return cast(_ExitT_co, cm.__exit__(exc_type, exc_val, exc_tb))
+
+ @abstractmethod
+ def __contextmanager__(self) -> AbstractContextManager[object, bool | None]:
+ """
+ Implement your context manager logic here.
+
+ This method **must** be decorated with
+ :func:`@contextmanager `.
+
+ .. note:: Remember that the ``yield`` will raise any exception raised in the
+ enclosed context block, so use a ``finally:`` block to clean up resources!
+
+ :return: a context manager object
+ """
+
+
+class AsyncContextManagerMixin:
+ """
+ Mixin class providing async context manager functionality via a generator-based
+ implementation.
+
+ This class allows you to implement a context manager via
+ :meth:`__asynccontextmanager__`. The mechanics are meant to mirror those of
+ :func:`@asynccontextmanager `.
+
+ .. note:: Classes using this mix-in are not reentrant as context managers, meaning
+ that once you enter it, you can't re-enter before first exiting it.
+
+ .. seealso:: :doc:`contextmanagers`
+ """
+
+ __cm: AbstractAsyncContextManager[object, bool | None] | None = None
+
+ @final
+ async def __aenter__(self: _SupportsAsyncCtxMgr[_T_co, bool | None]) -> _T_co:
+ # Needed for mypy to assume self still has the __cm member
+ assert isinstance(self, AsyncContextManagerMixin)
+ if self.__cm is not None:
+ raise RuntimeError(
+ f"this {self.__class__.__qualname__} has already been entered"
+ )
+
+ cm = self.__asynccontextmanager__()
+ if not isinstance(cm, AbstractAsyncContextManager):
+ if isasyncgen(cm):
+ raise TypeError(
+ "__asynccontextmanager__() returned an async generator instead of "
+ "an async context manager. Did you forget to add the "
+ "@asynccontextmanager decorator?"
+ )
+ elif iscoroutine(cm):
+ cm.close()
+ raise TypeError(
+ "__asynccontextmanager__() returned a coroutine object instead of "
+ "an async context manager. Did you forget to add the "
+ "@asynccontextmanager decorator and a 'yield' statement?"
+ )
+
+ raise TypeError(
+ f"__asynccontextmanager__() did not return an async context manager, "
+ f"but {cm.__class__!r}"
+ )
+
+ if cm is self:
+ raise TypeError(
+ f"{self.__class__.__qualname__}.__asynccontextmanager__() returned "
+ f"self. Did you forget to add the @asynccontextmanager decorator and a "
+ f"'yield' statement?"
+ )
+
+ value = await cm.__aenter__()
+ self.__cm = cm
+ return value
+
+ @final
+ async def __aexit__(
+ self: _SupportsAsyncCtxMgr[object, _ExitT_co],
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> _ExitT_co:
+ assert isinstance(self, AsyncContextManagerMixin)
+ if self.__cm is None:
+ raise RuntimeError(
+ f"this {self.__class__.__qualname__} has not been entered yet"
+ )
+
+ # Prevent circular references
+ cm = self.__cm
+ del self.__cm
+
+ return cast(_ExitT_co, await cm.__aexit__(exc_type, exc_val, exc_tb))
+
+ @abstractmethod
+ def __asynccontextmanager__(
+ self,
+ ) -> AbstractAsyncContextManager[object, bool | None]:
+ """
+ Implement your async context manager logic here.
+
+ This method **must** be decorated with
+ :func:`@asynccontextmanager `.
+
+ .. note:: Remember that the ``yield`` will raise any exception raised in the
+ enclosed context block, so use a ``finally:`` block to clean up resources!
+
+ :return: an async context manager object
+ """
diff --git a/venv/Lib/site-packages/anyio/_core/_eventloop.py b/venv/Lib/site-packages/anyio/_core/_eventloop.py
new file mode 100644
index 0000000000000000000000000000000000000000..a3e2ab1cc172f2fbd94f244ab110cb16aa7eb8eb
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_eventloop.py
@@ -0,0 +1,240 @@
+from __future__ import annotations
+
+import math
+import sys
+import threading
+from collections.abc import Awaitable, Callable, Generator
+from contextlib import contextmanager
+from contextvars import Token
+from importlib import import_module
+from typing import TYPE_CHECKING, Any, TypeVar
+
+from ._exceptions import NoEventLoopError
+
+if sys.version_info >= (3, 11):
+ from typing import TypeVarTuple, Unpack
+else:
+ from typing_extensions import TypeVarTuple, Unpack
+
+sniffio: Any
+try:
+ import sniffio
+except ModuleNotFoundError:
+ sniffio = None
+
+if TYPE_CHECKING:
+ from ..abc import AsyncBackend
+
+# This must be updated when new backends are introduced
+BACKENDS = "asyncio", "trio"
+
+T_Retval = TypeVar("T_Retval")
+PosArgsT = TypeVarTuple("PosArgsT")
+
+threadlocals = threading.local()
+loaded_backends: dict[str, type[AsyncBackend]] = {}
+
+
+def run(
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+ *args: Unpack[PosArgsT],
+ backend: str = "asyncio",
+ backend_options: dict[str, Any] | None = None,
+) -> T_Retval:
+ """
+ Run the given coroutine function in an asynchronous event loop.
+
+ The current thread must not be already running an event loop.
+
+ :param func: a coroutine function
+ :param args: positional arguments to ``func``
+ :param backend: name of the asynchronous event loop implementation β currently
+ either ``asyncio`` or ``trio``
+ :param backend_options: keyword arguments to call the backend ``run()``
+ implementation with (documented :ref:`here `)
+ :return: the return value of the coroutine function
+ :raises RuntimeError: if an asynchronous event loop is already running in this
+ thread
+ :raises LookupError: if the named backend is not found
+
+ """
+ if asynclib_name := current_async_library():
+ raise RuntimeError(f"Already running {asynclib_name} in this thread")
+
+ try:
+ async_backend = get_async_backend(backend)
+ except ImportError as exc:
+ if backend in BACKENDS:
+ raise LookupError(
+ f"Backend {backend!r} is not available. "
+ f"Install it with: pip install anyio[{backend}]"
+ ) from exc
+
+ raise LookupError(f"No such backend: {backend}") from exc
+
+ token = None
+ if asynclib_name is None:
+ # Since we're in control of the event loop, we can cache the name of the async
+ # library
+ token = set_current_async_library(backend)
+
+ try:
+ backend_options = backend_options or {}
+ return async_backend.run(func, args, {}, backend_options)
+ finally:
+ reset_current_async_library(token)
+
+
+async def sleep(delay: float) -> None:
+ """
+ Pause the current task for the specified duration.
+
+ :param delay: the duration, in seconds
+
+ """
+ return await get_async_backend().sleep(delay)
+
+
+async def sleep_forever() -> None:
+ """
+ Pause the current task until it's cancelled.
+
+ This is a shortcut for ``sleep(math.inf)``.
+
+ .. versionadded:: 3.1
+
+ """
+ await sleep(math.inf)
+
+
+async def sleep_until(deadline: float) -> None:
+ """
+ Pause the current task until the given time.
+
+ :param deadline: the absolute time to wake up at (according to the internal
+ monotonic clock of the event loop)
+
+ .. versionadded:: 3.1
+
+ """
+ now = current_time()
+ await sleep(max(deadline - now, 0))
+
+
+def current_time() -> float:
+ """
+ Return the current value of the event loop's internal clock.
+
+ :return: the clock value (seconds)
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ return get_async_backend().current_time()
+
+
+def get_all_backends() -> tuple[str, ...]:
+ """Return a tuple of the names of all built-in backends."""
+ return BACKENDS
+
+
+def get_available_backends() -> tuple[str, ...]:
+ """
+ Test for the availability of built-in backends.
+
+ :return a tuple of the built-in backend names that were successfully imported
+
+ .. versionadded:: 4.12
+
+ """
+ available_backends: list[str] = []
+ for backend_name in get_all_backends():
+ try:
+ get_async_backend(backend_name)
+ except ImportError:
+ continue
+
+ available_backends.append(backend_name)
+
+ return tuple(available_backends)
+
+
+def get_cancelled_exc_class() -> type[BaseException]:
+ """
+ Return the current async library's cancellation exception class.
+
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ return get_async_backend().cancelled_exception_class()
+
+
+#
+# Private API
+#
+
+
+@contextmanager
+def claim_worker_thread(
+ backend_class: type[AsyncBackend], token: object
+) -> Generator[Any, None, None]:
+ from ..lowlevel import EventLoopToken
+
+ threadlocals.current_token = EventLoopToken(backend_class, token)
+ try:
+ yield
+ finally:
+ del threadlocals.current_token
+
+
+def get_async_backend(asynclib_name: str | None = None) -> type[AsyncBackend]:
+ if asynclib_name is None:
+ asynclib_name = current_async_library()
+ if not asynclib_name:
+ raise NoEventLoopError(
+ f"Not currently running on any asynchronous event loop. "
+ f"Available async backends: {', '.join(get_all_backends())}"
+ )
+
+ # We use our own dict instead of sys.modules to get the already imported back-end
+ # class because the appropriate modules in sys.modules could potentially be only
+ # partially initialized
+ try:
+ return loaded_backends[asynclib_name]
+ except KeyError:
+ module = import_module(f"anyio._backends._{asynclib_name}")
+ loaded_backends[asynclib_name] = module.backend_class
+ return module.backend_class
+
+
+def current_async_library() -> str | None:
+ if sniffio is None:
+ # If sniffio is not installed, we assume we're either running asyncio or nothing
+ import asyncio
+
+ try:
+ asyncio.get_running_loop()
+ return "asyncio"
+ except RuntimeError:
+ pass
+ else:
+ try:
+ return sniffio.current_async_library()
+ except sniffio.AsyncLibraryNotFoundError:
+ pass
+
+ return None
+
+
+def set_current_async_library(asynclib_name: str | None) -> Token | None:
+ # no-op if sniffio is not installed
+ if sniffio is None:
+ return None
+
+ return sniffio.current_async_library_cvar.set(asynclib_name)
+
+
+def reset_current_async_library(token: Token | None) -> None:
+ if token is not None:
+ sniffio.current_async_library_cvar.reset(token)
diff --git a/venv/Lib/site-packages/anyio/_core/_exceptions.py b/venv/Lib/site-packages/anyio/_core/_exceptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..cd6eb9b5ca82c70014fc610670a34cd076b872fe
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_exceptions.py
@@ -0,0 +1,177 @@
+from __future__ import annotations
+
+import sys
+from collections.abc import Generator
+from textwrap import dedent
+from typing import Any
+
+if sys.version_info < (3, 11):
+ from exceptiongroup import BaseExceptionGroup
+
+
+class BrokenResourceError(Exception):
+ """
+ Raised when trying to use a resource that has been rendered unusable due to external
+ causes (e.g. a send stream whose peer has disconnected).
+ """
+
+
+class BrokenWorkerProcess(Exception):
+ """
+ Raised by :meth:`~anyio.to_process.run_sync` if the worker process terminates abruptly or
+ otherwise misbehaves.
+ """
+
+
+class BrokenWorkerInterpreter(Exception):
+ """
+ Raised by :meth:`~anyio.to_interpreter.run_sync` if an unexpected exception is
+ raised in the subinterpreter.
+ """
+
+ def __init__(self, excinfo: Any):
+ # This was adapted from concurrent.futures.interpreter.ExecutionFailed
+ msg = excinfo.formatted
+ if not msg:
+ if excinfo.type and excinfo.msg:
+ msg = f"{excinfo.type.__name__}: {excinfo.msg}"
+ else:
+ msg = excinfo.type.__name__ or excinfo.msg
+
+ super().__init__(msg)
+ self.excinfo = excinfo
+
+ def __str__(self) -> str:
+ try:
+ formatted = self.excinfo.errdisplay
+ except Exception:
+ return super().__str__()
+ else:
+ return dedent(
+ f"""
+ {super().__str__()}
+
+ Uncaught in the interpreter:
+
+ {formatted}
+ """.strip()
+ )
+
+
+class BusyResourceError(Exception):
+ """
+ Raised when two tasks are trying to read from or write to the same resource
+ concurrently.
+ """
+
+ def __init__(self, action: str):
+ super().__init__(f"Another task is already {action} this resource")
+
+
+class ClosedResourceError(Exception):
+ """Raised when trying to use a resource that has been closed."""
+
+
+class ConnectionFailed(OSError):
+ """
+ Raised when a connection attempt fails.
+
+ .. note:: This class inherits from :exc:`OSError` for backwards compatibility.
+ """
+
+
+def iterate_exceptions(
+ exception: BaseException,
+) -> Generator[BaseException, None, None]:
+ if isinstance(exception, BaseExceptionGroup):
+ for exc in exception.exceptions:
+ yield from iterate_exceptions(exc)
+ else:
+ yield exception
+
+
+class DelimiterNotFound(Exception):
+ """
+ Raised during
+ :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the
+ maximum number of bytes has been read without the delimiter being found.
+ """
+
+ def __init__(self, max_bytes: int) -> None:
+ super().__init__(
+ f"The delimiter was not found among the first {max_bytes} bytes"
+ )
+
+
+class EndOfStream(Exception):
+ """
+ Raised when trying to read from a stream that has been closed from the other end.
+ """
+
+
+class IncompleteRead(Exception):
+ """
+ Raised during
+ :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_exactly` or
+ :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the
+ connection is closed before the requested amount of bytes has been read.
+ """
+
+ def __init__(self) -> None:
+ super().__init__(
+ "The stream was closed before the read operation could be completed"
+ )
+
+
+class TypedAttributeLookupError(LookupError):
+ """
+ Raised by :meth:`~anyio.TypedAttributeProvider.extra` when the given typed attribute
+ is not found and no default value has been given.
+ """
+
+
+class WouldBlock(Exception):
+ """Raised by ``X_nowait`` functions if ``X()`` would block."""
+
+
+class NoEventLoopError(RuntimeError):
+ """
+ Raised by several functions that require an event loop to be running in the current
+ thread when there is no running event loop.
+
+ This is also raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync`
+ if not calling from an AnyIO worker thread, and no ``token`` was passed.
+ """
+
+
+class RunFinishedError(RuntimeError):
+ """
+ Raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync` if the event
+ loop associated with the explicitly passed token has already finished.
+ """
+
+ def __init__(self) -> None:
+ super().__init__(
+ "The event loop associated with the given token has already finished"
+ )
+
+
+class TaskFailed(Exception):
+ """
+ Raised when awaiting on, or attempting to access the return value of, a
+ :class:`.TaskHandle` that raised an exception.
+ """
+
+
+class TaskCancelled(TaskFailed):
+ """
+ Raised when awaiting on, or attempting to access the return value of, a
+ :class:`.TaskHandle` that was cancelled.
+ """
+
+
+class TaskNotFinished(Exception):
+ """
+ Raised when attempting to access the return value or exception of a
+ :class:`.TaskHandle` that is still pending completion.
+ """
diff --git a/venv/Lib/site-packages/anyio/_core/_fileio.py b/venv/Lib/site-packages/anyio/_core/_fileio.py
new file mode 100644
index 0000000000000000000000000000000000000000..692c754b3fd5b8a2e795d7c981b2785423161216
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_fileio.py
@@ -0,0 +1,960 @@
+from __future__ import annotations
+
+import os
+import pathlib
+import sys
+from collections.abc import (
+ AsyncIterator,
+ Callable,
+ Iterable,
+ Iterator,
+ Sequence,
+)
+from dataclasses import dataclass
+from functools import partial
+from os import PathLike
+from typing import (
+ IO,
+ TYPE_CHECKING,
+ Any,
+ AnyStr,
+ ClassVar,
+ Final,
+ Generic,
+ TypeVar,
+ overload,
+)
+
+from .. import to_thread
+from ..abc import AsyncResource
+from ._synchronization import CapacityLimiter
+
+if sys.version_info >= (3, 11):
+ from typing import Self
+else:
+ from typing_extensions import Self
+
+if sys.version_info >= (3, 14):
+ from pathlib.types import PathInfo
+
+if TYPE_CHECKING:
+ from types import ModuleType
+
+ from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer
+else:
+ ReadableBuffer = OpenBinaryMode = OpenTextMode = WriteableBuffer = object
+
+
+T = TypeVar("T", bound="Path")
+
+
+class AsyncFile(AsyncResource, Generic[AnyStr]):
+ """
+ An asynchronous file object.
+
+ This class wraps a standard file object and provides async friendly versions of the
+ following blocking methods (where available on the original file object):
+
+ * read
+ * read1
+ * readline
+ * readlines
+ * readinto
+ * readinto1
+ * write
+ * writelines
+ * truncate
+ * seek
+ * tell
+ * flush
+
+ All other methods are directly passed through.
+
+ This class supports the asynchronous context manager protocol which closes the
+ underlying file at the end of the context block.
+
+ This class also supports asynchronous iteration::
+
+ async with await open_file(...) as f:
+ async for line in f:
+ print(line)
+ """
+
+ def __init__(
+ self, fp: IO[AnyStr], *, limiter: CapacityLimiter | None = None
+ ) -> None:
+ if limiter is not None and not isinstance(limiter, CapacityLimiter):
+ raise TypeError(
+ f"limiter must be a CapacityLimiter or None, not "
+ f"{limiter.__class__.__name__}"
+ )
+
+ self._fp: Any = fp
+ self._limiter = limiter
+
+ def __getattr__(self, name: str) -> object:
+ return getattr(self._fp, name)
+
+ @property
+ def limiter(self) -> CapacityLimiter | None:
+ """The capacity limiter used by this file object, if not the global limiter."""
+ return self._limiter
+
+ @property
+ def wrapped(self) -> IO[AnyStr]:
+ """The wrapped file object."""
+ return self._fp
+
+ async def __aiter__(self) -> AsyncIterator[AnyStr]:
+ while True:
+ line = await self.readline()
+ if line:
+ yield line
+ else:
+ break
+
+ async def aclose(self) -> None:
+ return await to_thread.run_sync(self._fp.close, limiter=self._limiter)
+
+ async def read(self, size: int = -1) -> AnyStr:
+ return await to_thread.run_sync(self._fp.read, size, limiter=self._limiter)
+
+ async def read1(self: AsyncFile[bytes], size: int = -1) -> bytes:
+ return await to_thread.run_sync(self._fp.read1, size, limiter=self._limiter)
+
+ async def readline(self) -> AnyStr:
+ return await to_thread.run_sync(self._fp.readline, limiter=self._limiter)
+
+ async def readlines(self) -> list[AnyStr]:
+ return await to_thread.run_sync(self._fp.readlines, limiter=self._limiter)
+
+ async def readinto(self: AsyncFile[bytes], b: WriteableBuffer) -> int:
+ return await to_thread.run_sync(self._fp.readinto, b, limiter=self._limiter)
+
+ async def readinto1(self: AsyncFile[bytes], b: WriteableBuffer) -> int:
+ return await to_thread.run_sync(self._fp.readinto1, b, limiter=self._limiter)
+
+ @overload
+ async def write(self: AsyncFile[bytes], b: ReadableBuffer) -> int: ...
+
+ @overload
+ async def write(self: AsyncFile[str], b: str) -> int: ...
+
+ async def write(self, b: ReadableBuffer | str) -> int:
+ return await to_thread.run_sync(self._fp.write, b, limiter=self._limiter)
+
+ @overload
+ async def writelines(
+ self: AsyncFile[bytes], lines: Iterable[ReadableBuffer]
+ ) -> None: ...
+
+ @overload
+ async def writelines(self: AsyncFile[str], lines: Iterable[str]) -> None: ...
+
+ async def writelines(self, lines: Iterable[ReadableBuffer] | Iterable[str]) -> None:
+ return await to_thread.run_sync(
+ self._fp.writelines, lines, limiter=self._limiter
+ )
+
+ async def truncate(self, size: int | None = None) -> int:
+ return await to_thread.run_sync(self._fp.truncate, size, limiter=self._limiter)
+
+ async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int:
+ return await to_thread.run_sync(
+ self._fp.seek, offset, whence, limiter=self._limiter
+ )
+
+ async def tell(self) -> int:
+ return await to_thread.run_sync(self._fp.tell, limiter=self._limiter)
+
+ async def flush(self) -> None:
+ return await to_thread.run_sync(self._fp.flush, limiter=self._limiter)
+
+
+@overload
+async def open_file(
+ file: str | PathLike[str] | int,
+ mode: OpenBinaryMode,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ errors: str | None = ...,
+ newline: str | None = ...,
+ closefd: bool = ...,
+ opener: Callable[[str, int], int] | None = ...,
+ *,
+ limiter: CapacityLimiter | None = ...,
+) -> AsyncFile[bytes]: ...
+
+
+@overload
+async def open_file(
+ file: str | PathLike[str] | int,
+ mode: OpenTextMode = ...,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ errors: str | None = ...,
+ newline: str | None = ...,
+ closefd: bool = ...,
+ opener: Callable[[str, int], int] | None = ...,
+ *,
+ limiter: CapacityLimiter | None = ...,
+) -> AsyncFile[str]: ...
+
+
+async def open_file(
+ file: str | PathLike[str] | int,
+ mode: str = "r",
+ buffering: int = -1,
+ encoding: str | None = None,
+ errors: str | None = None,
+ newline: str | None = None,
+ closefd: bool = True,
+ opener: Callable[[str, int], int] | None = None,
+ *,
+ limiter: CapacityLimiter | None = None,
+) -> AsyncFile[Any]:
+ """
+ Open a file asynchronously.
+
+ Except for ``limiter``, the arguments are exactly the same as for the builtin :func:`open`.
+
+ :param limiter: an optional capacity limiter to use with the file
+ instead of the default one
+ :return: an asynchronous file object
+
+ .. versionchanged:: 4.14.0
+ Added the ``limiter`` keyword argument.
+
+ """
+ fp = await to_thread.run_sync(
+ open,
+ file,
+ mode,
+ buffering,
+ encoding,
+ errors,
+ newline,
+ closefd,
+ opener,
+ limiter=limiter,
+ )
+ return AsyncFile(fp, limiter=limiter)
+
+
+def wrap_file(
+ file: IO[AnyStr], *, limiter: CapacityLimiter | None = None
+) -> AsyncFile[AnyStr]:
+ """
+ Wrap an existing file as an asynchronous file.
+
+ :param file: an existing file-like object
+ :param limiter: an optional capacity limiter to use with the file
+ instead of the default one
+ :return: an asynchronous file object
+
+ .. versionchanged:: 4.14.0
+ Added the ``limiter`` keyword argument.
+
+ """
+ return AsyncFile(file, limiter=limiter)
+
+
+@dataclass(eq=False)
+class _PathIterator(AsyncIterator[T]):
+ iterator: Iterator[PathLike[str]]
+ limiter: CapacityLimiter | None
+ # This was added to ensure that iterating over a subclass of Path yields instances
+ # of that subclass rather than the base Path class.
+ path_cls: type[T]
+
+ async def __anext__(self) -> T:
+ nextval = await to_thread.run_sync(
+ next, self.iterator, None, abandon_on_cancel=True, limiter=self.limiter
+ )
+ if nextval is None:
+ raise StopAsyncIteration from None
+
+ return self.path_cls(nextval, limiter=self.limiter)
+
+
+class Path:
+ """
+ An asynchronous version of :class:`pathlib.Path`.
+
+ This class cannot be substituted for :class:`pathlib.Path` or
+ :class:`pathlib.PurePath`, but it is compatible with the :class:`os.PathLike`
+ interface.
+
+ It implements the Python 3.10 version of :class:`pathlib.Path` interface, except for
+ the deprecated :meth:`~pathlib.Path.link_to` method.
+
+ Some methods may be unavailable or have limited functionality, based on the Python
+ version:
+
+ * :meth:`~pathlib.Path.copy` (available on Python 3.14 or later)
+ * :meth:`~pathlib.Path.copy_into` (available on Python 3.14 or later)
+ * :meth:`~pathlib.Path.from_uri` (available on Python 3.13 or later)
+ * :meth:`~pathlib.PurePath.full_match` (available on Python 3.13 or later)
+ * :attr:`~pathlib.Path.info` (available on Python 3.14 or later)
+ * :meth:`~pathlib.Path.is_junction` (available on Python 3.12 or later)
+ * :meth:`~pathlib.PurePath.match` (the ``case_sensitive`` parameter is only
+ available on Python 3.13 or later)
+ * :meth:`~pathlib.Path.move` (available on Python 3.14 or later)
+ * :meth:`~pathlib.Path.move_into` (available on Python 3.14 or later)
+ * :meth:`~pathlib.PurePath.relative_to` (the ``walk_up`` parameter is only available
+ on Python 3.12 or later)
+ * :meth:`~pathlib.Path.walk` (available on Python 3.12 or later)
+
+ Any methods that do disk I/O need to be awaited on. These methods are:
+
+ * :meth:`~pathlib.Path.absolute`
+ * :meth:`~pathlib.Path.chmod`
+ * :meth:`~pathlib.Path.cwd`
+ * :meth:`~pathlib.Path.exists`
+ * :meth:`~pathlib.Path.expanduser`
+ * :meth:`~pathlib.Path.group`
+ * :meth:`~pathlib.Path.hardlink_to`
+ * :meth:`~pathlib.Path.home`
+ * :meth:`~pathlib.Path.is_block_device`
+ * :meth:`~pathlib.Path.is_char_device`
+ * :meth:`~pathlib.Path.is_dir`
+ * :meth:`~pathlib.Path.is_fifo`
+ * :meth:`~pathlib.Path.is_file`
+ * :meth:`~pathlib.Path.is_junction`
+ * :meth:`~pathlib.Path.is_mount`
+ * :meth:`~pathlib.Path.is_socket`
+ * :meth:`~pathlib.Path.is_symlink`
+ * :meth:`~pathlib.Path.lchmod`
+ * :meth:`~pathlib.Path.lstat`
+ * :meth:`~pathlib.Path.mkdir`
+ * :meth:`~pathlib.Path.open`
+ * :meth:`~pathlib.Path.owner`
+ * :meth:`~pathlib.Path.read_bytes`
+ * :meth:`~pathlib.Path.read_text`
+ * :meth:`~pathlib.Path.readlink`
+ * :meth:`~pathlib.Path.rename`
+ * :meth:`~pathlib.Path.replace`
+ * :meth:`~pathlib.Path.resolve`
+ * :meth:`~pathlib.Path.rmdir`
+ * :meth:`~pathlib.Path.samefile`
+ * :meth:`~pathlib.Path.stat`
+ * :meth:`~pathlib.Path.symlink_to`
+ * :meth:`~pathlib.Path.touch`
+ * :meth:`~pathlib.Path.unlink`
+ * :meth:`~pathlib.Path.walk`
+ * :meth:`~pathlib.Path.write_bytes`
+ * :meth:`~pathlib.Path.write_text`
+
+ Additionally, the following methods return an async iterator yielding
+ :class:`~.Path` objects:
+
+ * :meth:`~pathlib.Path.glob`
+ * :meth:`~pathlib.Path.iterdir`
+ * :meth:`~pathlib.Path.rglob`
+
+ .. versionchanged:: 4.14.0
+ Added the ``limiter`` keyword argument.
+ """
+
+ __slots__ = "_path", "_limiter", "__weakref__"
+
+ __weakref__: Any
+
+ def __init__(
+ self, *args: str | PathLike[str], limiter: CapacityLimiter | None = None
+ ) -> None:
+ if limiter is not None and not isinstance(limiter, CapacityLimiter):
+ raise TypeError(
+ f"limiter must be a CapacityLimiter or None, not "
+ f"{limiter.__class__.__name__}"
+ )
+
+ self._path: Final[pathlib.Path] = pathlib.Path(*args)
+ self._limiter = limiter
+
+ def __fspath__(self) -> str:
+ return self._path.__fspath__()
+
+ if sys.version_info >= (3, 15):
+
+ def __vfspath__(self) -> str:
+ return self._path.__vfspath__()
+
+ def __str__(self) -> str:
+ return self._path.__str__()
+
+ def __repr__(self) -> str:
+ return f"{self.__class__.__name__}({self.as_posix()!r})"
+
+ def __bytes__(self) -> bytes:
+ return self._path.__bytes__()
+
+ def __hash__(self) -> int:
+ return self._path.__hash__()
+
+ def __eq__(self, other: object) -> bool:
+ target = other._path if isinstance(other, Path) else other
+ return self._path.__eq__(target)
+
+ def __lt__(self, other: pathlib.PurePath | Path) -> bool:
+ target = other._path if isinstance(other, Path) else other
+ return self._path.__lt__(target)
+
+ def __le__(self, other: pathlib.PurePath | Path) -> bool:
+ target = other._path if isinstance(other, Path) else other
+ return self._path.__le__(target)
+
+ def __gt__(self, other: pathlib.PurePath | Path) -> bool:
+ target = other._path if isinstance(other, Path) else other
+ return self._path.__gt__(target)
+
+ def __ge__(self, other: pathlib.PurePath | Path) -> bool:
+ target = other._path if isinstance(other, Path) else other
+ return self._path.__ge__(target)
+
+ def __truediv__(self, other: str | PathLike[str]) -> Self:
+ return type(self)(self._path / other, limiter=self._limiter)
+
+ def __rtruediv__(self, other: str | PathLike[str]) -> Self:
+ return type(self)(other, limiter=self._limiter) / self
+
+ @property
+ def limiter(self) -> CapacityLimiter | None:
+ """The capacity limiter used by this path, if not the global limiter."""
+ return self._limiter
+
+ @property
+ def parts(self) -> tuple[str, ...]:
+ return self._path.parts
+
+ @property
+ def drive(self) -> str:
+ return self._path.drive
+
+ @property
+ def root(self) -> str:
+ return self._path.root
+
+ @property
+ def anchor(self) -> str:
+ return self._path.anchor
+
+ @property
+ def parents(self) -> Sequence[Self]:
+ return tuple(type(self)(p, limiter=self._limiter) for p in self._path.parents)
+
+ @property
+ def parent(self) -> Self:
+ return type(self)(self._path.parent, limiter=self._limiter)
+
+ @property
+ def name(self) -> str:
+ return self._path.name
+
+ @property
+ def suffix(self) -> str:
+ return self._path.suffix
+
+ @property
+ def suffixes(self) -> list[str]:
+ return self._path.suffixes
+
+ @property
+ def stem(self) -> str:
+ return self._path.stem
+
+ async def absolute(self) -> Self:
+ path = await to_thread.run_sync(self._path.absolute, limiter=self._limiter)
+ return type(self)(path, limiter=self._limiter)
+
+ def as_posix(self) -> str:
+ return self._path.as_posix()
+
+ def as_uri(self) -> str:
+ return self._path.as_uri()
+
+ if sys.version_info >= (3, 13):
+ parser: ClassVar[ModuleType] = pathlib.Path.parser
+
+ @classmethod
+ def from_uri(cls, uri: str, *, limiter: CapacityLimiter | None = None) -> Self:
+ return cls(pathlib.Path.from_uri(uri), limiter=limiter)
+
+ def full_match(
+ self, path_pattern: str, *, case_sensitive: bool | None = None
+ ) -> bool:
+ return self._path.full_match(path_pattern, case_sensitive=case_sensitive)
+
+ def match(
+ self, path_pattern: str, *, case_sensitive: bool | None = None
+ ) -> bool:
+ return self._path.match(path_pattern, case_sensitive=case_sensitive)
+ else:
+
+ def match(self, path_pattern: str) -> bool:
+ return self._path.match(path_pattern)
+
+ if sys.version_info >= (3, 14):
+
+ @property
+ def info(self) -> PathInfo:
+ return self._path.info
+
+ async def copy(
+ self,
+ target: str | os.PathLike[str],
+ *,
+ follow_symlinks: bool = True,
+ preserve_metadata: bool = False,
+ ) -> Self:
+ func = partial(
+ self._path.copy,
+ follow_symlinks=follow_symlinks,
+ preserve_metadata=preserve_metadata,
+ )
+ return type(self)(
+ await to_thread.run_sync(
+ func, pathlib.Path(target), limiter=self._limiter
+ ),
+ limiter=self._limiter,
+ )
+
+ async def copy_into(
+ self,
+ target_dir: str | os.PathLike[str],
+ *,
+ follow_symlinks: bool = True,
+ preserve_metadata: bool = False,
+ ) -> Self:
+ func = partial(
+ self._path.copy_into,
+ follow_symlinks=follow_symlinks,
+ preserve_metadata=preserve_metadata,
+ )
+ return type(self)(
+ await to_thread.run_sync(
+ func, pathlib.Path(target_dir), limiter=self._limiter
+ ),
+ limiter=self._limiter,
+ )
+
+ async def move(self, target: str | os.PathLike[str]) -> Self:
+ # Upstream does not handle anyio.Path properly as a PathLike
+ target = pathlib.Path(target)
+ return type(self)(
+ await to_thread.run_sync(
+ self._path.move, target, limiter=self._limiter
+ ),
+ limiter=self._limiter,
+ )
+
+ async def move_into(
+ self,
+ target_dir: str | os.PathLike[str],
+ ) -> Self:
+ return type(self)(
+ await to_thread.run_sync(
+ self._path.move_into, target_dir, limiter=self._limiter
+ ),
+ limiter=self._limiter,
+ )
+
+ def is_relative_to(self, other: str | PathLike[str]) -> bool:
+ try:
+ self.relative_to(other)
+ return True
+ except ValueError:
+ return False
+
+ async def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None:
+ func = partial(os.chmod, follow_symlinks=follow_symlinks)
+ return await to_thread.run_sync(func, self._path, mode, limiter=self._limiter)
+
+ @classmethod
+ async def cwd(cls, *, limiter: CapacityLimiter | None = None) -> Self:
+ path = await to_thread.run_sync(pathlib.Path.cwd, limiter=limiter)
+ return cls(path, limiter=limiter)
+
+ async def exists(self) -> bool:
+ return await to_thread.run_sync(
+ self._path.exists, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ async def expanduser(self) -> Self:
+ return type(self)(
+ await to_thread.run_sync(
+ self._path.expanduser, abandon_on_cancel=True, limiter=self._limiter
+ ),
+ limiter=self._limiter,
+ )
+
+ if sys.version_info < (3, 12):
+ # Python 3.11 and earlier
+ def glob(self, pattern: str) -> AsyncIterator[Self]:
+ gen = self._path.glob(pattern)
+ return _PathIterator(gen, self._limiter, type(self))
+ elif (3, 12) <= sys.version_info < (3, 13):
+ # changed in Python 3.12:
+ # - The case_sensitive parameter was added.
+ def glob(
+ self,
+ pattern: str,
+ *,
+ case_sensitive: bool | None = None,
+ ) -> AsyncIterator[Self]:
+ gen = self._path.glob(pattern, case_sensitive=case_sensitive)
+ return _PathIterator(gen, self._limiter, type(self))
+ elif sys.version_info >= (3, 13):
+ # Changed in Python 3.13:
+ # - The recurse_symlinks parameter was added.
+ # - The pattern parameter accepts a path-like object.
+ def glob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block
+ self,
+ pattern: str | PathLike[str],
+ *,
+ case_sensitive: bool | None = None,
+ recurse_symlinks: bool = False,
+ ) -> AsyncIterator[Self]:
+ gen = self._path.glob(
+ pattern, # type: ignore[arg-type]
+ case_sensitive=case_sensitive,
+ recurse_symlinks=recurse_symlinks,
+ )
+ return _PathIterator(gen, self._limiter, type(self))
+
+ async def group(self) -> str:
+ return await to_thread.run_sync(
+ self._path.group, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ async def hardlink_to(
+ self, target: str | bytes | PathLike[str] | PathLike[bytes]
+ ) -> None:
+ if isinstance(target, Path):
+ target = target._path
+
+ await to_thread.run_sync(os.link, target, self, limiter=self._limiter)
+
+ @classmethod
+ async def home(cls, *, limiter: CapacityLimiter | None = None) -> Self:
+ home_path = await to_thread.run_sync(pathlib.Path.home, limiter=limiter)
+ return cls(home_path, limiter=limiter)
+
+ def is_absolute(self) -> bool:
+ return self._path.is_absolute()
+
+ async def is_block_device(self) -> bool:
+ return await to_thread.run_sync(
+ self._path.is_block_device, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ async def is_char_device(self) -> bool:
+ return await to_thread.run_sync(
+ self._path.is_char_device, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ async def is_dir(self) -> bool:
+ return await to_thread.run_sync(
+ self._path.is_dir, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ async def is_fifo(self) -> bool:
+ return await to_thread.run_sync(
+ self._path.is_fifo, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ async def is_file(self) -> bool:
+ return await to_thread.run_sync(
+ self._path.is_file, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ if sys.version_info >= (3, 12):
+
+ async def is_junction(self) -> bool:
+ return await to_thread.run_sync(
+ self._path.is_junction, limiter=self._limiter
+ )
+
+ async def is_mount(self) -> bool:
+ return await to_thread.run_sync(
+ os.path.ismount, self._path, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ if sys.version_info < (3, 15):
+
+ def is_reserved(self) -> bool:
+ return self._path.is_reserved()
+
+ async def is_socket(self) -> bool:
+ return await to_thread.run_sync(
+ self._path.is_socket, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ async def is_symlink(self) -> bool:
+ return await to_thread.run_sync(
+ self._path.is_symlink, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ async def iterdir(self) -> AsyncIterator[Self]:
+ gen = (
+ self._path.iterdir()
+ if sys.version_info < (3, 13)
+ else await to_thread.run_sync(
+ self._path.iterdir, abandon_on_cancel=True, limiter=self._limiter
+ )
+ )
+ async for path in _PathIterator(gen, self._limiter, type(self)):
+ yield path
+
+ def joinpath(self, *args: str | PathLike[str]) -> Self:
+ return type(self)(self._path.joinpath(*args), limiter=self._limiter)
+
+ async def lchmod(self, mode: int) -> None:
+ await to_thread.run_sync(self._path.lchmod, mode, limiter=self._limiter)
+
+ async def lstat(self) -> os.stat_result:
+ return await to_thread.run_sync(
+ self._path.lstat, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ async def mkdir(
+ self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False
+ ) -> None:
+ await to_thread.run_sync(
+ self._path.mkdir, mode, parents, exist_ok, limiter=self._limiter
+ )
+
+ @overload
+ async def open(
+ self,
+ mode: OpenBinaryMode,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ errors: str | None = ...,
+ newline: str | None = ...,
+ ) -> AsyncFile[bytes]: ...
+
+ @overload
+ async def open(
+ self,
+ mode: OpenTextMode = ...,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ errors: str | None = ...,
+ newline: str | None = ...,
+ ) -> AsyncFile[str]: ...
+
+ async def open(
+ self,
+ mode: str = "r",
+ buffering: int = -1,
+ encoding: str | None = None,
+ errors: str | None = None,
+ newline: str | None = None,
+ ) -> AsyncFile[Any]:
+ fp = await to_thread.run_sync(
+ self._path.open,
+ mode,
+ buffering,
+ encoding,
+ errors,
+ newline,
+ limiter=self._limiter,
+ )
+ return AsyncFile(fp, limiter=self._limiter)
+
+ async def owner(self) -> str:
+ return await to_thread.run_sync(
+ self._path.owner, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ async def read_bytes(self) -> bytes:
+ return await to_thread.run_sync(self._path.read_bytes, limiter=self._limiter)
+
+ async def read_text(
+ self, encoding: str | None = None, errors: str | None = None
+ ) -> str:
+ return await to_thread.run_sync(
+ self._path.read_text, encoding, errors, limiter=self._limiter
+ )
+
+ if sys.version_info >= (3, 12):
+
+ def relative_to(
+ self, *other: str | PathLike[str], walk_up: bool = False
+ ) -> Self:
+ # relative_to() should work with any PathLike but it doesn't
+ others = [pathlib.Path(other) for other in other]
+ return type(self)(
+ self._path.relative_to(*others, walk_up=walk_up), limiter=self._limiter
+ )
+
+ else:
+
+ def relative_to(self, *other: str | PathLike[str]) -> Self:
+ return type(self)(self._path.relative_to(*other), limiter=self._limiter)
+
+ async def readlink(self) -> Self:
+ target = await to_thread.run_sync(
+ os.readlink, self._path, limiter=self._limiter
+ )
+ return type(self)(target, limiter=self._limiter)
+
+ async def rename(self, target: str | pathlib.PurePath | Path) -> Self:
+ if isinstance(target, Path):
+ target = target._path
+
+ await to_thread.run_sync(self._path.rename, target, limiter=self._limiter)
+ return type(self)(target, limiter=self._limiter)
+
+ async def replace(self, target: str | pathlib.PurePath | Path) -> Self:
+ if isinstance(target, Path):
+ target = target._path
+
+ await to_thread.run_sync(self._path.replace, target, limiter=self._limiter)
+ return type(self)(target, limiter=self._limiter)
+
+ async def resolve(self, strict: bool = False) -> Self:
+ func = partial(self._path.resolve, strict=strict)
+ return type(self)(
+ await to_thread.run_sync(
+ func, abandon_on_cancel=True, limiter=self._limiter
+ ),
+ limiter=self._limiter,
+ )
+
+ if sys.version_info < (3, 12):
+ # Pre Python 3.12
+ def rglob(self, pattern: str) -> AsyncIterator[Self]:
+ gen = self._path.rglob(pattern)
+ return _PathIterator(gen, self._limiter, type(self))
+ elif (3, 12) <= sys.version_info < (3, 13):
+ # Changed in Python 3.12:
+ # - The case_sensitive parameter was added.
+ def rglob(
+ self, pattern: str, *, case_sensitive: bool | None = None
+ ) -> AsyncIterator[Self]:
+ gen = self._path.rglob(pattern, case_sensitive=case_sensitive)
+ return _PathIterator(gen, self._limiter, type(self))
+ elif sys.version_info >= (3, 13):
+ # Changed in Python 3.13:
+ # - The recurse_symlinks parameter was added.
+ # - The pattern parameter accepts a path-like object.
+ def rglob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block
+ self,
+ pattern: str | PathLike[str],
+ *,
+ case_sensitive: bool | None = None,
+ recurse_symlinks: bool = False,
+ ) -> AsyncIterator[Self]:
+ gen = self._path.rglob(
+ pattern, # type: ignore[arg-type]
+ case_sensitive=case_sensitive,
+ recurse_symlinks=recurse_symlinks,
+ )
+ return _PathIterator(gen, self._limiter, type(self))
+
+ async def rmdir(self) -> None:
+ await to_thread.run_sync(self._path.rmdir, limiter=self._limiter)
+
+ async def samefile(self, other_path: str | PathLike[str]) -> bool:
+ if isinstance(other_path, Path):
+ other_path = other_path._path
+
+ return await to_thread.run_sync(
+ self._path.samefile,
+ other_path,
+ abandon_on_cancel=True,
+ limiter=self._limiter,
+ )
+
+ async def stat(self, *, follow_symlinks: bool = True) -> os.stat_result:
+ func = partial(os.stat, follow_symlinks=follow_symlinks)
+ return await to_thread.run_sync(
+ func, self._path, abandon_on_cancel=True, limiter=self._limiter
+ )
+
+ async def symlink_to(
+ self,
+ target: str | bytes | PathLike[str] | PathLike[bytes],
+ target_is_directory: bool = False,
+ ) -> None:
+ if isinstance(target, Path):
+ target = target._path
+
+ await to_thread.run_sync(
+ self._path.symlink_to, target, target_is_directory, limiter=self._limiter
+ )
+
+ async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
+ await to_thread.run_sync(
+ self._path.touch, mode, exist_ok, limiter=self._limiter
+ )
+
+ async def unlink(self, missing_ok: bool = False) -> None:
+ try:
+ await to_thread.run_sync(self._path.unlink, limiter=self._limiter)
+ except FileNotFoundError:
+ if not missing_ok:
+ raise
+
+ if sys.version_info >= (3, 12):
+
+ async def walk(
+ self,
+ top_down: bool = True,
+ on_error: Callable[[OSError], object] | None = None,
+ follow_symlinks: bool = False,
+ ) -> AsyncIterator[tuple[Self, list[str], list[str]]]:
+ def get_next_value() -> tuple[pathlib.Path, list[str], list[str]] | None:
+ try:
+ return next(gen)
+ except StopIteration:
+ return None
+
+ gen = self._path.walk(top_down, on_error, follow_symlinks)
+ while True:
+ value = await to_thread.run_sync(get_next_value, limiter=self._limiter)
+ if value is None:
+ return
+
+ root, dirs, paths = value
+ yield type(self)(root, limiter=self._limiter), dirs, paths
+
+ def with_name(self, name: str) -> Self:
+ return type(self)(self._path.with_name(name), limiter=self._limiter)
+
+ def with_stem(self, stem: str) -> Self:
+ return type(self)(
+ self._path.with_name(stem + self._path.suffix), limiter=self._limiter
+ )
+
+ def with_suffix(self, suffix: str) -> Self:
+ return type(self)(self._path.with_suffix(suffix), limiter=self._limiter)
+
+ def with_segments(self, *pathsegments: str | PathLike[str]) -> Self:
+ return type(self)(*pathsegments, limiter=self._limiter)
+
+ async def write_bytes(self, data: ReadableBuffer) -> int:
+ return await to_thread.run_sync(
+ self._path.write_bytes, data, limiter=self._limiter
+ )
+
+ async def write_text(
+ self,
+ data: str,
+ encoding: str | None = None,
+ errors: str | None = None,
+ newline: str | None = None,
+ ) -> int:
+ return await to_thread.run_sync(
+ self._path.write_text,
+ data,
+ encoding,
+ errors,
+ newline,
+ limiter=self._limiter,
+ )
+
+
+PathLike.register(Path)
diff --git a/venv/Lib/site-packages/anyio/_core/_resources.py b/venv/Lib/site-packages/anyio/_core/_resources.py
new file mode 100644
index 0000000000000000000000000000000000000000..b9a5344aef2962670f9b305a02cd0b11f2087d2f
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_resources.py
@@ -0,0 +1,18 @@
+from __future__ import annotations
+
+from ..abc import AsyncResource
+from ._tasks import CancelScope
+
+
+async def aclose_forcefully(resource: AsyncResource) -> None:
+ """
+ Close an asynchronous resource in a cancelled scope.
+
+ Doing this closes the resource without waiting on anything.
+
+ :param resource: the resource to close
+
+ """
+ with CancelScope() as scope:
+ scope.cancel()
+ await resource.aclose()
diff --git a/venv/Lib/site-packages/anyio/_core/_signals.py b/venv/Lib/site-packages/anyio/_core/_signals.py
new file mode 100644
index 0000000000000000000000000000000000000000..e24c79e10d4b76775679f7dd0dbe3f5860150451
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_signals.py
@@ -0,0 +1,29 @@
+from __future__ import annotations
+
+from collections.abc import AsyncIterator
+from contextlib import AbstractContextManager
+from signal import Signals
+
+from ._eventloop import get_async_backend
+
+
+def open_signal_receiver(
+ *signals: Signals,
+) -> AbstractContextManager[AsyncIterator[Signals]]:
+ """
+ Start receiving operating system signals.
+
+ :param signals: signals to receive (e.g. ``signal.SIGINT``)
+ :return: an asynchronous context manager for an asynchronous iterator which yields
+ signal numbers
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ .. warning:: Windows does not support signals natively so it is best to avoid
+ relying on this in cross-platform applications.
+
+ .. warning:: On asyncio, this permanently replaces any previous signal handler for
+ the given signals, as set via :meth:`~asyncio.loop.add_signal_handler`.
+
+ """
+ return get_async_backend().open_signal_receiver(*signals)
diff --git a/venv/Lib/site-packages/anyio/_core/_sockets.py b/venv/Lib/site-packages/anyio/_core/_sockets.py
new file mode 100644
index 0000000000000000000000000000000000000000..29f73324185d42ec4a924affc4c32994a2248f3e
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_sockets.py
@@ -0,0 +1,1011 @@
+from __future__ import annotations
+
+import errno
+import os
+import socket
+import ssl
+import stat
+import sys
+from collections.abc import Awaitable
+from dataclasses import dataclass
+from ipaddress import IPv4Address, IPv6Address, ip_address
+from os import PathLike, chmod
+from socket import AddressFamily, SocketKind
+from typing import TYPE_CHECKING, Any, Literal, cast, overload
+
+from .. import ConnectionFailed, to_thread
+from ..abc import (
+ ByteStreamConnectable,
+ ConnectedUDPSocket,
+ ConnectedUNIXDatagramSocket,
+ IPAddressType,
+ IPSockAddrType,
+ SocketListener,
+ SocketStream,
+ UDPSocket,
+ UNIXDatagramSocket,
+ UNIXSocketStream,
+)
+from ..streams.stapled import MultiListener
+from ..streams.tls import TLSConnectable, TLSStream
+from ._eventloop import get_async_backend
+from ._resources import aclose_forcefully
+from ._synchronization import Event
+from ._tasks import create_task_group, move_on_after
+
+if TYPE_CHECKING:
+ from _typeshed import FileDescriptorLike
+else:
+ FileDescriptorLike = object
+
+if sys.version_info < (3, 11):
+ from exceptiongroup import ExceptionGroup
+
+if sys.version_info >= (3, 12):
+ from typing import override
+else:
+ from typing_extensions import override
+
+if sys.version_info < (3, 13):
+ from typing_extensions import deprecated
+else:
+ from warnings import deprecated
+
+IPPROTO_IPV6 = getattr(socket, "IPPROTO_IPV6", 41) # https://bugs.python.org/issue29515
+
+AnyIPAddressFamily = Literal[
+ AddressFamily.AF_UNSPEC, AddressFamily.AF_INET, AddressFamily.AF_INET6
+]
+IPAddressFamily = Literal[AddressFamily.AF_INET, AddressFamily.AF_INET6]
+
+
+# tls_hostname given
+@overload
+async def connect_tcp(
+ remote_host: IPAddressType,
+ remote_port: int,
+ *,
+ local_host: IPAddressType | None = ...,
+ local_port: int | None = ...,
+ ssl_context: ssl.SSLContext | None = ...,
+ tls_standard_compatible: bool = ...,
+ tls_hostname: str,
+ happy_eyeballs_delay: float = ...,
+) -> TLSStream: ...
+
+
+# ssl_context given
+@overload
+async def connect_tcp(
+ remote_host: IPAddressType,
+ remote_port: int,
+ *,
+ local_host: IPAddressType | None = ...,
+ local_port: int | None = ...,
+ ssl_context: ssl.SSLContext,
+ tls_standard_compatible: bool = ...,
+ tls_hostname: str | None = ...,
+ happy_eyeballs_delay: float = ...,
+) -> TLSStream: ...
+
+
+# tls=True
+@overload
+async def connect_tcp(
+ remote_host: IPAddressType,
+ remote_port: int,
+ *,
+ local_host: IPAddressType | None = ...,
+ local_port: int | None = ...,
+ tls: Literal[True],
+ ssl_context: ssl.SSLContext | None = ...,
+ tls_standard_compatible: bool = ...,
+ tls_hostname: str | None = ...,
+ happy_eyeballs_delay: float = ...,
+) -> TLSStream: ...
+
+
+# tls=False
+@overload
+async def connect_tcp(
+ remote_host: IPAddressType,
+ remote_port: int,
+ *,
+ local_host: IPAddressType | None = ...,
+ local_port: int | None = ...,
+ tls: Literal[False],
+ ssl_context: ssl.SSLContext | None = ...,
+ tls_standard_compatible: bool = ...,
+ tls_hostname: str | None = ...,
+ happy_eyeballs_delay: float = ...,
+) -> SocketStream: ...
+
+
+# No TLS arguments
+@overload
+async def connect_tcp(
+ remote_host: IPAddressType,
+ remote_port: int,
+ *,
+ local_host: IPAddressType | None = ...,
+ local_port: int | None = ...,
+ happy_eyeballs_delay: float = ...,
+) -> SocketStream: ...
+
+
+async def connect_tcp(
+ remote_host: IPAddressType,
+ remote_port: int,
+ *,
+ local_host: IPAddressType | None = None,
+ local_port: int | None = None,
+ tls: bool = False,
+ ssl_context: ssl.SSLContext | None = None,
+ tls_standard_compatible: bool = True,
+ tls_hostname: str | None = None,
+ happy_eyeballs_delay: float = 0.25,
+) -> SocketStream | TLSStream:
+ """
+ Connect to a host using the TCP protocol.
+
+ This function implements the stateless version of the Happy Eyeballs algorithm (RFC
+ 6555). If ``remote_host`` is a host name that resolves to multiple IP addresses,
+ each one is tried until one connection attempt succeeds. If the first attempt does
+ not connected within 250 milliseconds, a second attempt is started using the next
+ address in the list, and so on. On IPv6 enabled systems, an IPv6 address (if
+ available) is tried first.
+
+ When the connection has been established, a TLS handshake will be done if either
+ ``ssl_context`` or ``tls_hostname`` is not ``None``, or if ``tls`` is ``True``.
+
+ :param remote_host: the IP address or host name to connect to
+ :param remote_port: port on the target host to connect to
+ :param local_host: the interface address or name to bind the socket to before
+ connecting
+ :param local_port: the local port to bind to (requires ``local_host`` to also be
+ set)
+ :param tls: ``True`` to do a TLS handshake with the connected stream and return a
+ :class:`~anyio.streams.tls.TLSStream` instead
+ :param ssl_context: the SSL context object to use (if omitted, a default context is
+ created)
+ :param tls_standard_compatible: If ``True``, performs the TLS shutdown handshake
+ before closing the stream and requires that the server does this as well.
+ Otherwise, :exc:`~ssl.SSLEOFError` may be raised during reads from the stream.
+ Some protocols, such as HTTP, require this option to be ``False``.
+ See :meth:`~ssl.SSLContext.wrap_socket` for details.
+ :param tls_hostname: host name to check the server certificate against (defaults to
+ the value of ``remote_host``)
+ :param happy_eyeballs_delay: delay (in seconds) before starting the next connection
+ attempt
+ :return: a socket stream object if no TLS handshake was done, otherwise a TLS stream
+ :raises ConnectionFailed: if the connection fails
+
+ """
+ # Placed here due to https://github.com/python/mypy/issues/7057
+ connected_stream: SocketStream | None = None
+
+ async def try_connect(remote_host: str, event: Event) -> None:
+ nonlocal connected_stream
+ try:
+ stream = await asynclib.connect_tcp(remote_host, remote_port, local_address)
+ except OSError as exc:
+ oserrors.append(exc)
+ return
+ else:
+ if connected_stream is None:
+ connected_stream = stream
+ tg.cancel_scope.cancel()
+ else:
+ await stream.aclose()
+ finally:
+ event.set()
+
+ asynclib = get_async_backend()
+ local_address: IPSockAddrType | None = None
+ family = socket.AF_UNSPEC
+ if local_host:
+ gai_res = await getaddrinfo(str(local_host), local_port)
+ family, *_, local_address = gai_res[0]
+
+ target_host = str(remote_host)
+ try:
+ addr_obj = ip_address(remote_host)
+ except ValueError:
+ addr_obj = None
+
+ if addr_obj is not None:
+ if isinstance(addr_obj, IPv6Address):
+ target_addrs = [(socket.AF_INET6, addr_obj.compressed)]
+ else:
+ target_addrs = [(socket.AF_INET, addr_obj.compressed)]
+ else:
+ # getaddrinfo() will raise an exception if name resolution fails
+ gai_res = await getaddrinfo(
+ target_host, remote_port, family=family, type=socket.SOCK_STREAM
+ )
+
+ # Organize the list so that the first address is an IPv6 address (if available)
+ # and the second one is an IPv4 addresses. The rest can be in whatever order.
+ v6_found = v4_found = False
+ target_addrs = []
+ for af, *_, sa in gai_res:
+ if af == socket.AF_INET6 and not v6_found:
+ v6_found = True
+ target_addrs.insert(0, (af, sa[0]))
+ elif af == socket.AF_INET and not v4_found and v6_found:
+ v4_found = True
+ target_addrs.insert(1, (af, sa[0]))
+ else:
+ target_addrs.append((af, sa[0]))
+
+ oserrors: list[OSError] = []
+ try:
+ async with create_task_group() as tg:
+ for _af, addr in target_addrs:
+ event = Event()
+ tg.start_soon(try_connect, addr, event)
+ with move_on_after(happy_eyeballs_delay):
+ await event.wait()
+
+ if connected_stream is None:
+ cause = (
+ oserrors[0]
+ if len(oserrors) == 1
+ else ExceptionGroup("multiple connection attempts failed", oserrors)
+ )
+ raise OSError("All connection attempts failed") from cause
+ finally:
+ oserrors.clear()
+
+ if tls or tls_hostname or ssl_context:
+ try:
+ return await TLSStream.wrap(
+ connected_stream,
+ server_side=False,
+ hostname=tls_hostname or str(remote_host),
+ ssl_context=ssl_context,
+ standard_compatible=tls_standard_compatible,
+ )
+ except BaseException:
+ await aclose_forcefully(connected_stream)
+ raise
+
+ return connected_stream
+
+
+async def connect_unix(path: str | bytes | PathLike[Any]) -> UNIXSocketStream:
+ """
+ Connect to the given UNIX socket.
+
+ Not available on Windows.
+
+ :param path: path to the socket
+ :return: a socket stream object
+ :raises ConnectionFailed: if the connection fails
+
+ """
+ path = os.fspath(path)
+ return await get_async_backend().connect_unix(path)
+
+
+async def create_tcp_listener(
+ *,
+ local_host: IPAddressType | None = None,
+ local_port: int = 0,
+ family: AnyIPAddressFamily = socket.AddressFamily.AF_UNSPEC,
+ backlog: int = 65536,
+ reuse_port: bool = False,
+) -> MultiListener[SocketStream]:
+ """
+ Create a TCP socket listener.
+
+ :param local_port: port number to listen on
+ :param local_host: IP address of the interface to listen on. If omitted, listen on
+ all IPv4 and IPv6 interfaces. To listen on all interfaces on a specific address
+ family, use ``0.0.0.0`` for IPv4 or ``::`` for IPv6.
+ :param family: address family (used if ``local_host`` was omitted)
+ :param backlog: maximum number of queued incoming connections (up to a maximum of
+ 2**16, or 65536)
+ :param reuse_port: ``True`` to allow multiple sockets to bind to the same
+ address/port (not supported on Windows)
+ :return: a multi-listener object containing one or more socket listeners
+ :raises OSError: if there's an error creating a socket, or binding to one or more
+ interfaces failed
+
+ """
+ asynclib = get_async_backend()
+ backlog = min(backlog, 65536)
+ local_host = str(local_host) if local_host is not None else None
+
+ def setup_raw_socket(
+ fam: AddressFamily,
+ bind_addr: tuple[str, int] | tuple[str, int, int, int],
+ *,
+ v6only: bool = True,
+ ) -> socket.socket:
+ sock = socket.socket(fam)
+ try:
+ sock.setblocking(False)
+
+ if fam == AddressFamily.AF_INET6:
+ sock.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, v6only)
+
+ # For Windows, enable exclusive address use. For others, enable address
+ # reuse.
+ if sys.platform == "win32":
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1)
+ else:
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+
+ if reuse_port:
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
+
+ # Workaround for #554
+ if fam == socket.AF_INET6 and "%" in bind_addr[0]:
+ addr, scope_id = bind_addr[0].split("%", 1)
+ bind_addr = (addr, bind_addr[1], 0, int(scope_id))
+
+ sock.bind(bind_addr)
+ sock.listen(backlog)
+ except BaseException:
+ sock.close()
+ raise
+
+ return sock
+
+ # We passing type=0 on non-Windows platforms as a workaround for a uvloop bug
+ # where we don't get the correct scope ID for IPv6 link-local addresses when passing
+ # type=socket.SOCK_STREAM to getaddrinfo():
+ # https://github.com/MagicStack/uvloop/issues/539
+ gai_res = await getaddrinfo(
+ local_host,
+ local_port,
+ family=family,
+ type=socket.SOCK_STREAM if sys.platform == "win32" else 0,
+ flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
+ )
+
+ # The set comprehension is here to work around a glibc bug:
+ # https://sourceware.org/bugzilla/show_bug.cgi?id=14969
+ sockaddrs = sorted({res for res in gai_res if res[1] == SocketKind.SOCK_STREAM})
+
+ # Special case for dual-stack binding on the "any" interface
+ if (
+ local_host is None
+ and family == AddressFamily.AF_UNSPEC
+ and socket.has_dualstack_ipv6()
+ and any(fam == AddressFamily.AF_INET6 for fam, *_ in gai_res)
+ ):
+ raw_socket = setup_raw_socket(
+ AddressFamily.AF_INET6, ("::", local_port), v6only=False
+ )
+ listener = asynclib.create_tcp_listener(raw_socket)
+ return MultiListener([listener])
+
+ errors: list[OSError] = []
+ try:
+ for _ in range(len(sockaddrs)):
+ listeners: list[SocketListener] = []
+ bound_ephemeral_port = local_port
+ try:
+ for fam, *_, sockaddr in sockaddrs:
+ sockaddr = sockaddr[0], bound_ephemeral_port, *sockaddr[2:]
+ raw_socket = setup_raw_socket(fam, sockaddr)
+
+ # Store the assigned port if an ephemeral port was requested, so
+ # we'll bind to the same port on all interfaces
+ if local_port == 0 and len(gai_res) > 1:
+ bound_ephemeral_port = raw_socket.getsockname()[1]
+
+ listeners.append(asynclib.create_tcp_listener(raw_socket))
+ except BaseException as exc:
+ for listener in listeners:
+ await listener.aclose()
+
+ # If an ephemeral port was requested but binding the assigned port
+ # failed for another interface, rotate the address list and try again
+ if (
+ isinstance(exc, OSError)
+ and exc.errno == errno.EADDRINUSE
+ and local_port == 0
+ and bound_ephemeral_port
+ ):
+ errors.append(exc)
+ sockaddrs.append(sockaddrs.pop(0))
+ continue
+
+ raise
+
+ return MultiListener(listeners)
+
+ raise OSError(
+ f"Could not create {len(sockaddrs)} listeners with a consistent port"
+ ) from ExceptionGroup("Several bind attempts failed", errors)
+ finally:
+ del errors # Prevent reference cycles
+
+
+async def create_unix_listener(
+ path: str | bytes | PathLike[Any],
+ *,
+ mode: int | None = None,
+ backlog: int = 65536,
+) -> SocketListener:
+ """
+ Create a UNIX socket listener.
+
+ Not available on Windows.
+
+ :param path: path of the socket
+ :param mode: permissions to set on the socket
+ :param backlog: maximum number of queued incoming connections (up to a maximum of
+ 2**16, or 65536)
+ :return: a listener object
+
+ .. versionchanged:: 3.0
+ If a socket already exists on the file system in the given path, it will be
+ removed first.
+
+ """
+ backlog = min(backlog, 65536)
+ raw_socket = await setup_unix_local_socket(path, mode, socket.SOCK_STREAM)
+ try:
+ raw_socket.listen(backlog)
+ return get_async_backend().create_unix_listener(raw_socket)
+ except BaseException:
+ raw_socket.close()
+ raise
+
+
+async def create_udp_socket(
+ family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC,
+ *,
+ local_host: IPAddressType | None = None,
+ local_port: int = 0,
+ reuse_port: bool = False,
+) -> UDPSocket:
+ """
+ Create a UDP socket.
+
+ If ``port`` has been given, the socket will be bound to this port on the local
+ machine, making this socket suitable for providing UDP based services.
+
+ :param family: address family (``AF_INET`` or ``AF_INET6``) β automatically
+ determined from ``local_host`` if omitted
+ :param local_host: IP address or host name of the local interface to bind to
+ :param local_port: local port to bind to
+ :param reuse_port: ``True`` to allow multiple sockets to bind to the same
+ address/port (not supported on Windows)
+ :return: a UDP socket
+
+ """
+ if family is AddressFamily.AF_UNSPEC and not local_host:
+ raise ValueError('Either "family" or "local_host" must be given')
+
+ if local_host:
+ gai_res = await getaddrinfo(
+ str(local_host),
+ local_port,
+ family=family,
+ type=socket.SOCK_DGRAM,
+ flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
+ )
+ family = cast(AnyIPAddressFamily, gai_res[0][0])
+ local_address = gai_res[0][-1]
+ elif family is AddressFamily.AF_INET6:
+ local_address = ("::", 0)
+ else:
+ local_address = ("0.0.0.0", 0)
+
+ sock = await get_async_backend().create_udp_socket(
+ family, local_address, None, reuse_port
+ )
+ return cast(UDPSocket, sock)
+
+
+async def create_connected_udp_socket(
+ remote_host: IPAddressType,
+ remote_port: int,
+ *,
+ family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC,
+ local_host: IPAddressType | None = None,
+ local_port: int = 0,
+ reuse_port: bool = False,
+) -> ConnectedUDPSocket:
+ """
+ Create a connected UDP socket.
+
+ Connected UDP sockets can only communicate with the specified remote host/port, an
+ any packets sent from other sources are dropped.
+
+ :param remote_host: remote host to set as the default target
+ :param remote_port: port on the remote host to set as the default target
+ :param family: address family (``AF_INET`` or ``AF_INET6``) β automatically
+ determined from ``local_host`` or ``remote_host`` if omitted
+ :param local_host: IP address or host name of the local interface to bind to
+ :param local_port: local port to bind to
+ :param reuse_port: ``True`` to allow multiple sockets to bind to the same
+ address/port (not supported on Windows)
+ :return: a connected UDP socket
+
+ """
+ local_address = None
+ if local_host:
+ gai_res = await getaddrinfo(
+ str(local_host),
+ local_port,
+ family=family,
+ type=socket.SOCK_DGRAM,
+ flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
+ )
+ family = cast(AnyIPAddressFamily, gai_res[0][0])
+ local_address = gai_res[0][-1]
+
+ gai_res = await getaddrinfo(
+ str(remote_host), remote_port, family=family, type=socket.SOCK_DGRAM
+ )
+ family = cast(AnyIPAddressFamily, gai_res[0][0])
+ remote_address = gai_res[0][-1]
+
+ sock = await get_async_backend().create_udp_socket(
+ family, local_address, remote_address, reuse_port
+ )
+ return cast(ConnectedUDPSocket, sock)
+
+
+async def create_unix_datagram_socket(
+ *,
+ local_path: None | str | bytes | PathLike[Any] = None,
+ local_mode: int | None = None,
+) -> UNIXDatagramSocket:
+ """
+ Create a UNIX datagram socket.
+
+ Not available on Windows.
+
+ If ``local_path`` has been given, the socket will be bound to this path, making this
+ socket suitable for receiving datagrams from other processes. Other processes can
+ send datagrams to this socket only if ``local_path`` is set.
+
+ If a socket already exists on the file system in the ``local_path``, it will be
+ removed first.
+
+ :param local_path: the path on which to bind to
+ :param local_mode: permissions to set on the local socket
+ :return: a UNIX datagram socket
+
+ """
+ raw_socket = await setup_unix_local_socket(
+ local_path, local_mode, socket.SOCK_DGRAM
+ )
+ return await get_async_backend().create_unix_datagram_socket(raw_socket, None)
+
+
+async def create_connected_unix_datagram_socket(
+ remote_path: str | bytes | PathLike[Any],
+ *,
+ local_path: None | str | bytes | PathLike[Any] = None,
+ local_mode: int | None = None,
+) -> ConnectedUNIXDatagramSocket:
+ """
+ Create a connected UNIX datagram socket.
+
+ Connected datagram sockets can only communicate with the specified remote path.
+
+ If ``local_path`` has been given, the socket will be bound to this path, making
+ this socket suitable for receiving datagrams from other processes. Other processes
+ can send datagrams to this socket only if ``local_path`` is set.
+
+ If a socket already exists on the file system in the ``local_path``, it will be
+ removed first.
+
+ :param remote_path: the path to set as the default target
+ :param local_path: the path on which to bind to
+ :param local_mode: permissions to set on the local socket
+ :return: a connected UNIX datagram socket
+
+ """
+ remote_path = os.fspath(remote_path)
+ raw_socket = await setup_unix_local_socket(
+ local_path, local_mode, socket.SOCK_DGRAM
+ )
+ return await get_async_backend().create_unix_datagram_socket(
+ raw_socket, remote_path
+ )
+
+
+async def getaddrinfo(
+ host: bytes | str | None,
+ port: str | int | None,
+ *,
+ family: int | AddressFamily = 0,
+ type: int | SocketKind = 0,
+ proto: int = 0,
+ flags: int = 0,
+) -> list[tuple[AddressFamily, SocketKind, int, str, tuple[str, int]]]:
+ """
+ Look up a numeric IP address given a host name.
+
+ Internationalized domain names are translated according to the (non-transitional)
+ IDNA 2008 standard.
+
+ .. note:: 4-tuple IPv6 socket addresses are automatically converted to 2-tuples of
+ (host, port), unlike what :func:`socket.getaddrinfo` does.
+
+ :param host: host name
+ :param port: port number
+ :param family: socket family (`'AF_INET``, ...)
+ :param type: socket type (``SOCK_STREAM``, ...)
+ :param proto: protocol number
+ :param flags: flags to pass to upstream ``getaddrinfo()``
+ :return: list of tuples containing (family, type, proto, canonname, sockaddr)
+
+ .. seealso:: :func:`socket.getaddrinfo`
+
+ """
+ # Handle unicode hostnames
+ if isinstance(host, str):
+ try:
+ encoded_host: bytes | None = host.encode("ascii")
+ except UnicodeEncodeError:
+ import idna
+
+ encoded_host = idna.encode(host, uts46=True)
+ else:
+ encoded_host = host
+
+ gai_res = await get_async_backend().getaddrinfo(
+ encoded_host, port, family=family, type=type, proto=proto, flags=flags
+ )
+ return [
+ (family, type, proto, canonname, convert_ipv6_sockaddr(sockaddr))
+ for family, type, proto, canonname, sockaddr in gai_res
+ # filter out IPv6 results when IPv6 is disabled
+ if not isinstance(sockaddr[0], int)
+ ]
+
+
+def getnameinfo(sockaddr: IPSockAddrType, flags: int = 0) -> Awaitable[tuple[str, str]]:
+ """
+ Look up the host name of an IP address.
+
+ :param sockaddr: socket address (e.g. (ipaddress, port) for IPv4)
+ :param flags: flags to pass to upstream ``getnameinfo()``
+ :return: a tuple of (host name, service name)
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ .. seealso:: :func:`socket.getnameinfo`
+
+ """
+ return get_async_backend().getnameinfo(sockaddr, flags)
+
+
+@deprecated("This function is deprecated; use `wait_readable` instead")
+def wait_socket_readable(sock: socket.socket) -> Awaitable[None]:
+ """
+ .. deprecated:: 4.7.0
+ Use :func:`wait_readable` instead.
+
+ Wait until the given socket has data to be read.
+
+ .. warning:: Only use this on raw sockets that have not been wrapped by any higher
+ level constructs like socket streams!
+
+ :param sock: a socket object
+ :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the
+ socket to become readable
+ :raises ~anyio.BusyResourceError: if another task is already waiting for the socket
+ to become readable
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ return get_async_backend().wait_readable(sock.fileno())
+
+
+@deprecated("This function is deprecated; use `wait_writable` instead")
+def wait_socket_writable(sock: socket.socket) -> Awaitable[None]:
+ """
+ .. deprecated:: 4.7.0
+ Use :func:`wait_writable` instead.
+
+ Wait until the given socket can be written to.
+
+ This does **NOT** work on Windows when using the asyncio backend with a proactor
+ event loop (default on py3.8+).
+
+ .. warning:: Only use this on raw sockets that have not been wrapped by any higher
+ level constructs like socket streams!
+
+ :param sock: a socket object
+ :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the
+ socket to become writable
+ :raises ~anyio.BusyResourceError: if another task is already waiting for the socket
+ to become writable
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ return get_async_backend().wait_writable(sock.fileno())
+
+
+def wait_readable(obj: FileDescriptorLike) -> Awaitable[None]:
+ """
+ Wait until the given object has data to be read.
+
+ On Unix systems, ``obj`` must either be an integer file descriptor, or else an
+ object with a ``.fileno()`` method which returns an integer file descriptor. Any
+ kind of file descriptor can be passed, though the exact semantics will depend on
+ your kernel. For example, this probably won't do anything useful for on-disk files.
+
+ On Windows systems, ``obj`` must either be an integer ``SOCKET`` handle, or else an
+ object with a ``.fileno()`` method which returns an integer ``SOCKET`` handle. File
+ descriptors aren't supported, and neither are handles that refer to anything besides
+ a ``SOCKET``.
+
+ On backends where this functionality is not natively provided (asyncio
+ ``ProactorEventLoop`` on Windows), it is provided using a separate selector thread
+ which is set to shut down when the interpreter shuts down.
+
+ .. warning:: Don't use this on raw sockets that have been wrapped by any higher
+ level constructs like socket streams!
+
+ :param obj: an object with a ``.fileno()`` method or an integer handle
+ :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the
+ object to become readable
+ :raises ~anyio.BusyResourceError: if another task is already waiting for the object
+ to become readable
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ return get_async_backend().wait_readable(obj)
+
+
+def wait_writable(obj: FileDescriptorLike) -> Awaitable[None]:
+ """
+ Wait until the given object can be written to.
+
+ :param obj: an object with a ``.fileno()`` method or an integer handle
+ :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the
+ object to become writable
+ :raises ~anyio.BusyResourceError: if another task is already waiting for the object
+ to become writable
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ .. seealso:: See the documentation of :func:`wait_readable` for the definition of
+ ``obj`` and notes on backend compatibility.
+
+ .. warning:: Don't use this on raw sockets that have been wrapped by any higher
+ level constructs like socket streams!
+
+ """
+ return get_async_backend().wait_writable(obj)
+
+
+def notify_closing(obj: FileDescriptorLike) -> None:
+ """
+ Call this before closing a file descriptor (on Unix) or socket (on
+ Windows). This will cause any `wait_readable` or `wait_writable`
+ calls on the given object to immediately wake up and raise
+ `~anyio.ClosedResourceError`.
+
+ This doesn't actually close the object β you still have to do that
+ yourself afterwards. Also, you want to be careful to make sure no
+ new tasks start waiting on the object in between when you call this
+ and when it's actually closed. So to close something properly, you
+ usually want to do these steps in order:
+
+ 1. Explicitly mark the object as closed, so that any new attempts
+ to use it will abort before they start.
+ 2. Call `notify_closing` to wake up any already-existing users.
+ 3. Actually close the object.
+
+ It's also possible to do them in a different order if that's more
+ convenient, *but only if* you make sure not to have any checkpoints in
+ between the steps. This way they all happen in a single atomic
+ step, so other tasks won't be able to tell what order they happened
+ in anyway.
+
+ :param obj: an object with a ``.fileno()`` method or an integer handle
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ get_async_backend().notify_closing(obj)
+
+
+#
+# Private API
+#
+
+
+def convert_ipv6_sockaddr(
+ sockaddr: tuple[str, int, int, int] | tuple[str, int],
+) -> tuple[str, int]:
+ """
+ Convert a 4-tuple IPv6 socket address to a 2-tuple (address, port) format.
+
+ If the scope ID is nonzero, it is added to the address, separated with ``%``.
+ Otherwise the flow id and scope id are simply cut off from the tuple.
+ Any other kinds of socket addresses are returned as-is.
+
+ :param sockaddr: the result of :meth:`~socket.socket.getsockname`
+ :return: the converted socket address
+
+ """
+ # This is more complicated than it should be because of MyPy
+ if isinstance(sockaddr, tuple) and len(sockaddr) == 4:
+ host, port, flowinfo, scope_id = sockaddr
+ if scope_id:
+ # PyPy (as of v7.3.11) leaves the interface name in the result, so
+ # we discard it and only get the scope ID from the end
+ # (https://foss.heptapod.net/pypy/pypy/-/issues/3938)
+ host = host.split("%")[0]
+
+ # Add scope_id to the address
+ return f"{host}%{scope_id}", port
+ else:
+ return host, port
+ else:
+ return sockaddr
+
+
+async def setup_unix_local_socket(
+ path: None | str | bytes | PathLike[Any],
+ mode: int | None,
+ socktype: int,
+) -> socket.socket:
+ """
+ Create a UNIX local socket object, deleting the socket at the given path if it
+ exists.
+
+ Not available on Windows.
+
+ :param path: path of the socket
+ :param mode: permissions to set on the socket
+ :param socktype: socket.SOCK_STREAM or socket.SOCK_DGRAM
+
+ """
+ path_str: str | None
+ if path is not None:
+ path_str = os.fsdecode(path)
+
+ # Linux abstract namespace sockets aren't backed by a concrete file so skip stat call
+ if not path_str.startswith("\0"):
+ # Copied from pathlib...
+ try:
+ stat_result = os.stat(path)
+ except OSError as e:
+ if e.errno not in (
+ errno.ENOENT,
+ errno.ENOTDIR,
+ errno.EBADF,
+ errno.ELOOP,
+ ):
+ raise
+ else:
+ if stat.S_ISSOCK(stat_result.st_mode):
+ os.unlink(path)
+ else:
+ path_str = None
+
+ raw_socket = socket.socket(socket.AF_UNIX, socktype)
+ raw_socket.setblocking(False)
+
+ if path_str is not None:
+ try:
+ await to_thread.run_sync(raw_socket.bind, path_str, abandon_on_cancel=True)
+ if mode is not None:
+ await to_thread.run_sync(chmod, path_str, mode, abandon_on_cancel=True)
+ except BaseException:
+ raw_socket.close()
+ raise
+
+ return raw_socket
+
+
+@dataclass
+class TCPConnectable(ByteStreamConnectable):
+ """
+ Connects to a TCP server at the given host and port.
+
+ :param host: host name or IP address of the server
+ :param port: TCP port number of the server
+ """
+
+ host: str | IPv4Address | IPv6Address
+ port: int
+
+ def __post_init__(self) -> None:
+ if self.port < 1 or self.port > 65535:
+ raise ValueError("TCP port number out of range")
+
+ @override
+ async def connect(self) -> SocketStream:
+ try:
+ return await connect_tcp(self.host, self.port)
+ except OSError as exc:
+ raise ConnectionFailed(
+ f"error connecting to {self.host}:{self.port}: {exc}"
+ ) from exc
+
+
+@dataclass
+class UNIXConnectable(ByteStreamConnectable):
+ """
+ Connects to a UNIX domain socket at the given path.
+
+ :param path: the file system path of the socket
+ """
+
+ path: str | bytes | PathLike[str] | PathLike[bytes]
+
+ @override
+ async def connect(self) -> UNIXSocketStream:
+ try:
+ return await connect_unix(self.path)
+ except OSError as exc:
+ raise ConnectionFailed(f"error connecting to {self.path!r}: {exc}") from exc
+
+
+def as_connectable(
+ remote: ByteStreamConnectable
+ | tuple[str | IPv4Address | IPv6Address, int]
+ | str
+ | bytes
+ | PathLike[str],
+ /,
+ *,
+ tls: bool = False,
+ ssl_context: ssl.SSLContext | None = None,
+ tls_hostname: str | None = None,
+ tls_standard_compatible: bool = True,
+) -> ByteStreamConnectable:
+ """
+ Return a byte stream connectable from the given object.
+
+ If a bytestream connectable is given, it is returned unchanged.
+ If a tuple of (host, port) is given, a TCP connectable is returned.
+ If a string or bytes path is given, a UNIX connectable is returned.
+
+ If ``tls=True``, the connectable will be wrapped in a
+ :class:`~.streams.tls.TLSConnectable`.
+
+ :param remote: a connectable, a tuple of (host, port) or a path to a UNIX socket
+ :param tls: if ``True``, wrap the plaintext connectable in a
+ :class:`~.streams.tls.TLSConnectable`, using the provided TLS settings)
+ :param ssl_context: if ``tls=True``, the SSLContext object to use (if not provided,
+ a secure default will be created)
+ :param tls_hostname: if ``tls=True``, host name of the server to use for checking
+ the server certificate (defaults to the host portion of the address for TCP
+ connectables)
+ :param tls_standard_compatible: if ``False`` and ``tls=True``, makes the TLS stream
+ skip the closing handshake when closing the connection, so it won't raise an
+ exception if the server does the same
+
+ """
+ connectable: TCPConnectable | UNIXConnectable | TLSConnectable
+ if isinstance(remote, ByteStreamConnectable):
+ return remote
+ elif isinstance(remote, tuple) and len(remote) == 2:
+ connectable = TCPConnectable(*remote)
+ elif isinstance(remote, (str, bytes, PathLike)):
+ connectable = UNIXConnectable(remote)
+ else:
+ raise TypeError(f"cannot convert {remote!r} to a connectable")
+
+ if tls:
+ if not tls_hostname and isinstance(connectable, TCPConnectable):
+ tls_hostname = str(connectable.host)
+
+ connectable = TLSConnectable(
+ connectable,
+ ssl_context=ssl_context,
+ hostname=tls_hostname,
+ standard_compatible=tls_standard_compatible,
+ )
+
+ return connectable
diff --git a/venv/Lib/site-packages/anyio/_core/_streams.py b/venv/Lib/site-packages/anyio/_core/_streams.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b9c7df200f9520357503c754bcdea1c047bdda3
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_streams.py
@@ -0,0 +1,52 @@
+from __future__ import annotations
+
+import math
+from typing import TypeVar
+from warnings import warn
+
+from ..streams.memory import (
+ MemoryObjectReceiveStream,
+ MemoryObjectSendStream,
+ _MemoryObjectStreamState,
+)
+
+T_Item = TypeVar("T_Item")
+
+
+class create_memory_object_stream(
+ tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]],
+):
+ """
+ Create a memory object stream.
+
+ The stream's item type can be annotated like
+ :func:`create_memory_object_stream[T_Item]`.
+
+ :param max_buffer_size: number of items held in the buffer until ``send()`` starts
+ blocking
+ :param item_type: old way of marking the streams with the right generic type for
+ static typing (does nothing on AnyIO 4)
+
+ .. deprecated:: 4.0
+ Use ``create_memory_object_stream[YourItemType](...)`` instead.
+ :return: a tuple of (send stream, receive stream)
+
+ """
+
+ def __new__( # type: ignore[misc]
+ cls, max_buffer_size: float = 0, item_type: object = None
+ ) -> tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]]:
+ if max_buffer_size != math.inf and not isinstance(max_buffer_size, int):
+ raise ValueError("max_buffer_size must be either an integer or math.inf")
+ if max_buffer_size < 0:
+ raise ValueError("max_buffer_size cannot be negative")
+ if item_type is not None:
+ warn(
+ "The item_type argument has been deprecated in AnyIO 4.0. "
+ "Use create_memory_object_stream[YourItemType](...) instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+
+ state = _MemoryObjectStreamState[T_Item](max_buffer_size)
+ return (MemoryObjectSendStream(state), MemoryObjectReceiveStream(state))
diff --git a/venv/Lib/site-packages/anyio/_core/_subprocesses.py b/venv/Lib/site-packages/anyio/_core/_subprocesses.py
new file mode 100644
index 0000000000000000000000000000000000000000..9796f8bb99403616fcb0b764a0f8283792599e45
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_subprocesses.py
@@ -0,0 +1,196 @@
+from __future__ import annotations
+
+from collections.abc import AsyncIterable, Iterable, Mapping, Sequence
+from io import BytesIO
+from os import PathLike
+from subprocess import PIPE, CalledProcessError, CompletedProcess
+from typing import IO, Any, TypeAlias, cast
+
+from ..abc import Process
+from ._eventloop import get_async_backend
+from ._tasks import create_task_group
+
+StrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes]
+
+
+async def run_process(
+ command: StrOrBytesPath | Sequence[StrOrBytesPath],
+ *,
+ input: bytes | None = None,
+ stdin: int | IO[Any] | None = None,
+ stdout: int | IO[Any] | None = PIPE,
+ stderr: int | IO[Any] | None = PIPE,
+ check: bool = True,
+ cwd: StrOrBytesPath | None = None,
+ env: Mapping[str, str] | None = None,
+ startupinfo: Any = None,
+ creationflags: int = 0,
+ start_new_session: bool = False,
+ pass_fds: Sequence[int] = (),
+ user: str | int | None = None,
+ group: str | int | None = None,
+ extra_groups: Iterable[str | int] | None = None,
+ umask: int = -1,
+) -> CompletedProcess[bytes]:
+ """
+ Run an external command in a subprocess and wait until it completes.
+
+ .. seealso:: :func:`subprocess.run`
+
+ :param command: either a string to pass to the shell, or an iterable of strings
+ containing the executable name or path and its arguments
+ :param input: bytes passed to the standard input of the subprocess
+ :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
+ a file-like object, or `None`; ``input`` overrides this
+ :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
+ a file-like object, or `None`
+ :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
+ :data:`subprocess.STDOUT`, a file-like object, or `None`
+ :param check: if ``True``, raise :exc:`~subprocess.CalledProcessError` if the
+ process terminates with a return code other than 0
+ :param cwd: If not ``None``, change the working directory to this before running the
+ command
+ :param env: if not ``None``, this mapping replaces the inherited environment
+ variables from the parent process
+ :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used
+ to specify process startup parameters (Windows only)
+ :param creationflags: flags that can be used to control the creation of the
+ subprocess (see :class:`subprocess.Popen` for the specifics)
+ :param start_new_session: if ``true`` the setsid() system call will be made in the
+ child process prior to the execution of the subprocess. (POSIX only)
+ :param pass_fds: sequence of file descriptors to keep open between the parent and
+ child processes. (POSIX only)
+ :param user: effective user to run the process as (Python >= 3.9, POSIX only)
+ :param group: effective group to run the process as (Python >= 3.9, POSIX only)
+ :param extra_groups: supplementary groups to set in the subprocess (Python >= 3.9,
+ POSIX only)
+ :param umask: if not negative, this umask is applied in the child process before
+ running the given command (Python >= 3.9, POSIX only)
+ :return: an object representing the completed process
+ :raises ~subprocess.CalledProcessError: if ``check`` is ``True`` and the process
+ exits with a nonzero return code
+
+ """
+
+ async def drain_stream(stream: AsyncIterable[bytes], index: int) -> None:
+ buffer = BytesIO()
+ async for chunk in stream:
+ buffer.write(chunk)
+
+ stream_contents[index] = buffer.getvalue()
+
+ if stdin is not None and input is not None:
+ raise ValueError("only one of stdin and input is allowed")
+
+ async with await open_process(
+ command,
+ stdin=PIPE if input else stdin,
+ stdout=stdout,
+ stderr=stderr,
+ cwd=cwd,
+ env=env,
+ startupinfo=startupinfo,
+ creationflags=creationflags,
+ start_new_session=start_new_session,
+ pass_fds=pass_fds,
+ user=user,
+ group=group,
+ extra_groups=extra_groups,
+ umask=umask,
+ ) as process:
+ stream_contents: list[bytes | None] = [None, None]
+ async with create_task_group() as tg:
+ if process.stdout:
+ tg.start_soon(drain_stream, process.stdout, 0)
+
+ if process.stderr:
+ tg.start_soon(drain_stream, process.stderr, 1)
+
+ if process.stdin and input:
+ await process.stdin.send(input)
+ await process.stdin.aclose()
+
+ await process.wait()
+
+ output, errors = stream_contents
+ if check and process.returncode != 0:
+ raise CalledProcessError(cast(int, process.returncode), command, output, errors)
+
+ return CompletedProcess(command, cast(int, process.returncode), output, errors)
+
+
+async def open_process(
+ command: StrOrBytesPath | Sequence[StrOrBytesPath],
+ *,
+ stdin: int | IO[Any] | None = PIPE,
+ stdout: int | IO[Any] | None = PIPE,
+ stderr: int | IO[Any] | None = PIPE,
+ cwd: StrOrBytesPath | None = None,
+ env: Mapping[str, str] | None = None,
+ startupinfo: Any = None,
+ creationflags: int = 0,
+ start_new_session: bool = False,
+ pass_fds: Sequence[int] = (),
+ user: str | int | None = None,
+ group: str | int | None = None,
+ extra_groups: Iterable[str | int] | None = None,
+ umask: int = -1,
+) -> Process:
+ """
+ Start an external command in a subprocess.
+
+ .. seealso:: :class:`subprocess.Popen`
+
+ :param command: either a string to pass to the shell, or an iterable of strings
+ containing the executable name or path and its arguments
+ :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, a
+ file-like object, or ``None``
+ :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
+ a file-like object, or ``None``
+ :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
+ :data:`subprocess.STDOUT`, a file-like object, or ``None``
+ :param cwd: If not ``None``, the working directory is changed before executing
+ :param env: If env is not ``None``, it must be a mapping that defines the
+ environment variables for the new process
+ :param creationflags: flags that can be used to control the creation of the
+ subprocess (see :class:`subprocess.Popen` for the specifics)
+ :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used
+ to specify process startup parameters (Windows only)
+ :param start_new_session: if ``true`` the setsid() system call will be made in the
+ child process prior to the execution of the subprocess. (POSIX only)
+ :param pass_fds: sequence of file descriptors to keep open between the parent and
+ child processes. (POSIX only)
+ :param user: effective user to run the process as (POSIX only)
+ :param group: effective group to run the process as (POSIX only)
+ :param extra_groups: supplementary groups to set in the subprocess (POSIX only)
+ :param umask: if not negative, this umask is applied in the child process before
+ running the given command (POSIX only)
+ :return: an asynchronous process object
+
+ """
+ kwargs: dict[str, Any] = {}
+ if user is not None:
+ kwargs["user"] = user
+
+ if group is not None:
+ kwargs["group"] = group
+
+ if extra_groups is not None:
+ kwargs["extra_groups"] = group
+
+ if umask >= 0:
+ kwargs["umask"] = umask
+
+ return await get_async_backend().open_process(
+ command,
+ stdin=stdin,
+ stdout=stdout,
+ stderr=stderr,
+ cwd=cwd,
+ env=env,
+ startupinfo=startupinfo,
+ creationflags=creationflags,
+ start_new_session=start_new_session,
+ pass_fds=pass_fds,
+ **kwargs,
+ )
diff --git a/venv/Lib/site-packages/anyio/_core/_synchronization.py b/venv/Lib/site-packages/anyio/_core/_synchronization.py
new file mode 100644
index 0000000000000000000000000000000000000000..ed191164c69305a8f3833922fc5a2e4707b37b46
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_synchronization.py
@@ -0,0 +1,772 @@
+from __future__ import annotations
+
+import math
+from collections import deque
+from collections.abc import Callable
+from dataclasses import dataclass
+from types import TracebackType
+from typing import TypeVar
+
+from ..lowlevel import checkpoint_if_cancelled
+from ._eventloop import get_async_backend
+from ._exceptions import BusyResourceError, NoEventLoopError
+from ._tasks import CancelScope
+from ._testing import TaskInfo, get_current_task
+
+T = TypeVar("T")
+
+
+@dataclass(frozen=True)
+class EventStatistics:
+ """
+ :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Event.wait`
+ """
+
+ tasks_waiting: int
+
+
+@dataclass(frozen=True)
+class CapacityLimiterStatistics:
+ """
+ :ivar int borrowed_tokens: number of tokens currently borrowed by tasks
+ :ivar float total_tokens: total number of available tokens
+ :ivar tuple borrowers: tasks or other objects currently holding tokens borrowed from
+ this limiter
+ :ivar int tasks_waiting: number of tasks waiting on
+ :meth:`~.CapacityLimiter.acquire` or
+ :meth:`~.CapacityLimiter.acquire_on_behalf_of`
+ """
+
+ borrowed_tokens: int
+ total_tokens: float
+ borrowers: tuple[object, ...]
+ tasks_waiting: int
+
+
+@dataclass(frozen=True)
+class LockStatistics:
+ """
+ :ivar bool locked: flag indicating if this lock is locked or not
+ :ivar ~anyio.TaskInfo owner: task currently holding the lock (or ``None`` if the
+ lock is not held by any task)
+ :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Lock.acquire`
+ """
+
+ locked: bool
+ owner: TaskInfo | None
+ tasks_waiting: int
+
+
+@dataclass(frozen=True)
+class ConditionStatistics:
+ """
+ :ivar int tasks_waiting: number of tasks blocked on :meth:`~.Condition.wait`
+ :ivar ~anyio.LockStatistics lock_statistics: statistics of the underlying
+ :class:`~.Lock`
+ """
+
+ tasks_waiting: int
+ lock_statistics: LockStatistics
+
+
+@dataclass(frozen=True)
+class SemaphoreStatistics:
+ """
+ :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Semaphore.acquire`
+
+ """
+
+ tasks_waiting: int
+
+
+class Event:
+ __slots__ = ("__weakref__",)
+
+ def __new__(cls) -> Event:
+ try:
+ return get_async_backend().create_event()
+ except NoEventLoopError:
+ return EventAdapter()
+
+ def set(self) -> None:
+ """Set the flag, notifying all listeners."""
+ raise NotImplementedError
+
+ def is_set(self) -> bool:
+ """Return ``True`` if the flag is set, ``False`` if not."""
+ raise NotImplementedError
+
+ async def wait(self) -> None:
+ """
+ Wait until the flag has been set.
+
+ If the flag has already been set when this method is called, it returns
+ immediately.
+
+ """
+ raise NotImplementedError
+
+ def statistics(self) -> EventStatistics:
+ """Return statistics about the current state of this event."""
+ raise NotImplementedError
+
+
+class EventAdapter(Event):
+ __slots__ = "_internal_event", "_is_set"
+
+ def __new__(cls) -> EventAdapter:
+ return object.__new__(cls)
+
+ def __init__(self) -> None:
+ self._internal_event: Event | None = None
+ self._is_set = False
+
+ @property
+ def _event(self) -> Event:
+ if self._internal_event is None:
+ self._internal_event = get_async_backend().create_event()
+ if self._is_set:
+ self._internal_event.set()
+
+ return self._internal_event
+
+ def set(self) -> None:
+ if self._internal_event is None:
+ self._is_set = True
+ else:
+ self._event.set()
+
+ def is_set(self) -> bool:
+ if self._internal_event is None:
+ return self._is_set
+
+ return self._internal_event.is_set()
+
+ async def wait(self) -> None:
+ await self._event.wait()
+
+ def statistics(self) -> EventStatistics:
+ if self._internal_event is None:
+ return EventStatistics(tasks_waiting=0)
+
+ return self._internal_event.statistics()
+
+
+class Lock:
+ __slots__ = ("__weakref__",)
+
+ def __new__(cls, *, fast_acquire: bool = False) -> Lock:
+ try:
+ return get_async_backend().create_lock(fast_acquire=fast_acquire)
+ except NoEventLoopError:
+ return LockAdapter(fast_acquire=fast_acquire)
+
+ async def __aenter__(self) -> None:
+ await self.acquire()
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ self.release()
+
+ async def acquire(self) -> None:
+ """Acquire the lock."""
+ raise NotImplementedError
+
+ def acquire_nowait(self) -> None:
+ """
+ Acquire the lock, without blocking.
+
+ :raises ~anyio.WouldBlock: if the operation would block
+
+ """
+ raise NotImplementedError
+
+ def release(self) -> None:
+ """Release the lock."""
+ raise NotImplementedError
+
+ def locked(self) -> bool:
+ """Return True if the lock is currently held."""
+ raise NotImplementedError
+
+ def statistics(self) -> LockStatistics:
+ """
+ Return statistics about the current state of this lock.
+
+ .. versionadded:: 3.0
+ """
+ raise NotImplementedError
+
+
+class LockAdapter(Lock):
+ __slots__ = "_internal_lock", "_fast_acquire"
+
+ def __new__(cls, *, fast_acquire: bool = False) -> LockAdapter:
+ return object.__new__(cls)
+
+ def __init__(self, *, fast_acquire: bool = False):
+ self._internal_lock: Lock | None = None
+ self._fast_acquire = fast_acquire
+
+ @property
+ def _lock(self) -> Lock:
+ if self._internal_lock is None:
+ self._internal_lock = get_async_backend().create_lock(
+ fast_acquire=self._fast_acquire
+ )
+
+ return self._internal_lock
+
+ async def __aenter__(self) -> None:
+ await self._lock.acquire()
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ if self._internal_lock is not None:
+ self._internal_lock.release()
+
+ async def acquire(self) -> None:
+ """Acquire the lock."""
+ await self._lock.acquire()
+
+ def acquire_nowait(self) -> None:
+ """
+ Acquire the lock, without blocking.
+
+ :raises ~anyio.WouldBlock: if the operation would block
+
+ """
+ self._lock.acquire_nowait()
+
+ def release(self) -> None:
+ """Release the lock."""
+ self._lock.release()
+
+ def locked(self) -> bool:
+ """Return True if the lock is currently held."""
+ return self._lock.locked()
+
+ def statistics(self) -> LockStatistics:
+ """
+ Return statistics about the current state of this lock.
+
+ .. versionadded:: 3.0
+
+ """
+ if self._internal_lock is None:
+ return LockStatistics(False, None, 0)
+
+ return self._internal_lock.statistics()
+
+
+class Condition:
+ __slots__ = "__weakref__", "_owner_task", "_lock", "_waiters"
+
+ def __init__(self, lock: Lock | None = None):
+ self._owner_task: TaskInfo | None = None
+ self._lock = lock or Lock()
+ self._waiters: deque[Event] = deque()
+
+ async def __aenter__(self) -> None:
+ await self.acquire()
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ self.release()
+
+ def _check_acquired(self) -> None:
+ if self._owner_task != get_current_task():
+ raise RuntimeError("The current task is not holding the underlying lock")
+
+ async def acquire(self) -> None:
+ """Acquire the underlying lock."""
+ await self._lock.acquire()
+ self._owner_task = get_current_task()
+
+ def acquire_nowait(self) -> None:
+ """
+ Acquire the underlying lock, without blocking.
+
+ :raises ~anyio.WouldBlock: if the operation would block
+
+ """
+ self._lock.acquire_nowait()
+ self._owner_task = get_current_task()
+
+ def release(self) -> None:
+ """Release the underlying lock."""
+ self._lock.release()
+
+ def locked(self) -> bool:
+ """Return True if the lock is set."""
+ return self._lock.locked()
+
+ def notify(self, n: int = 1) -> None:
+ """Notify exactly n listeners."""
+ self._check_acquired()
+ for _ in range(n):
+ try:
+ event = self._waiters.popleft()
+ except IndexError:
+ break
+
+ event.set()
+
+ def notify_all(self) -> None:
+ """Notify all the listeners."""
+ self._check_acquired()
+ for event in self._waiters:
+ event.set()
+
+ self._waiters.clear()
+
+ async def wait(self) -> None:
+ """Wait for a notification."""
+ await checkpoint_if_cancelled()
+ self._check_acquired()
+ event = Event()
+ self._waiters.append(event)
+ self.release()
+ try:
+ await event.wait()
+ except BaseException:
+ if not event.is_set():
+ self._waiters.remove(event)
+ elif self._waiters:
+ # This task was notified by could not act on it, so pass
+ # it on to the next task
+ self._waiters.popleft().set()
+
+ raise
+ finally:
+ with CancelScope(shield=True):
+ await self.acquire()
+
+ async def wait_for(self, predicate: Callable[[], T]) -> T:
+ """
+ Wait until a predicate becomes true.
+
+ :param predicate: a callable that returns a truthy value when the condition is
+ met
+ :return: the result of the predicate
+
+ .. versionadded:: 4.11.0
+
+ """
+ while not (result := predicate()):
+ await self.wait()
+
+ return result
+
+ def statistics(self) -> ConditionStatistics:
+ """
+ Return statistics about the current state of this condition.
+
+ .. versionadded:: 3.0
+ """
+ return ConditionStatistics(len(self._waiters), self._lock.statistics())
+
+
+class Semaphore:
+ __slots__ = "__weakref__", "_fast_acquire"
+
+ def __new__(
+ cls,
+ initial_value: int,
+ *,
+ max_value: int | None = None,
+ fast_acquire: bool = False,
+ ) -> Semaphore:
+ try:
+ return get_async_backend().create_semaphore(
+ initial_value, max_value=max_value, fast_acquire=fast_acquire
+ )
+ except NoEventLoopError:
+ return SemaphoreAdapter(initial_value, max_value=max_value)
+
+ def __init__(
+ self,
+ initial_value: int,
+ *,
+ max_value: int | None = None,
+ fast_acquire: bool = False,
+ ):
+ if not isinstance(initial_value, int):
+ raise TypeError("initial_value must be an integer")
+ if initial_value < 0:
+ raise ValueError("initial_value must be >= 0")
+ if max_value is not None:
+ if not isinstance(max_value, int):
+ raise TypeError("max_value must be an integer or None")
+ if max_value < initial_value:
+ raise ValueError(
+ "max_value must be equal to or higher than initial_value"
+ )
+
+ self._fast_acquire = fast_acquire
+
+ async def __aenter__(self) -> Semaphore:
+ await self.acquire()
+ return self
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ self.release()
+
+ async def acquire(self) -> None:
+ """Decrement the semaphore value, blocking if necessary."""
+ raise NotImplementedError
+
+ def acquire_nowait(self) -> None:
+ """
+ Acquire the underlying lock, without blocking.
+
+ :raises ~anyio.WouldBlock: if the operation would block
+
+ """
+ raise NotImplementedError
+
+ def release(self) -> None:
+ """Increment the semaphore value."""
+ raise NotImplementedError
+
+ @property
+ def value(self) -> int:
+ """The current value of the semaphore."""
+ raise NotImplementedError
+
+ @property
+ def max_value(self) -> int | None:
+ """The maximum value of the semaphore."""
+ raise NotImplementedError
+
+ def statistics(self) -> SemaphoreStatistics:
+ """
+ Return statistics about the current state of this semaphore.
+
+ .. versionadded:: 3.0
+ """
+ raise NotImplementedError
+
+
+class SemaphoreAdapter(Semaphore):
+ __slots__ = "_internal_semaphore", "_initial_value", "_max_value"
+
+ def __new__(
+ cls,
+ initial_value: int,
+ *,
+ max_value: int | None = None,
+ fast_acquire: bool = False,
+ ) -> SemaphoreAdapter:
+ return object.__new__(cls)
+
+ def __init__(
+ self,
+ initial_value: int,
+ *,
+ max_value: int | None = None,
+ fast_acquire: bool = False,
+ ) -> None:
+ super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire)
+ self._internal_semaphore: Semaphore | None = None
+ self._initial_value = initial_value
+ self._max_value = max_value
+
+ @property
+ def _semaphore(self) -> Semaphore:
+ if self._internal_semaphore is None:
+ self._internal_semaphore = get_async_backend().create_semaphore(
+ self._initial_value, max_value=self._max_value
+ )
+
+ return self._internal_semaphore
+
+ async def acquire(self) -> None:
+ await self._semaphore.acquire()
+
+ def acquire_nowait(self) -> None:
+ self._semaphore.acquire_nowait()
+
+ def release(self) -> None:
+ self._semaphore.release()
+
+ @property
+ def value(self) -> int:
+ if self._internal_semaphore is None:
+ return self._initial_value
+
+ return self._semaphore.value
+
+ @property
+ def max_value(self) -> int | None:
+ return self._max_value
+
+ def statistics(self) -> SemaphoreStatistics:
+ if self._internal_semaphore is None:
+ return SemaphoreStatistics(tasks_waiting=0)
+
+ return self._semaphore.statistics()
+
+
+class CapacityLimiter:
+ __slots__ = ("__weakref__",)
+
+ def __new__(cls, total_tokens: float) -> CapacityLimiter:
+ try:
+ return get_async_backend().create_capacity_limiter(total_tokens)
+ except NoEventLoopError:
+ return CapacityLimiterAdapter(total_tokens)
+
+ async def __aenter__(self) -> None:
+ raise NotImplementedError
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ raise NotImplementedError
+
+ @property
+ def total_tokens(self) -> float:
+ """
+ The total number of tokens available for borrowing.
+
+ This is a read-write property. If the total number of tokens is increased, the
+ proportionate number of tasks waiting on this limiter will be granted their
+ tokens.
+
+ .. versionchanged:: 3.0
+ The property is now writable.
+ .. versionchanged:: 4.12
+ The value can now be set to 0.
+
+ """
+ raise NotImplementedError
+
+ @total_tokens.setter
+ def total_tokens(self, value: float) -> None:
+ raise NotImplementedError
+
+ @property
+ def borrowed_tokens(self) -> int:
+ """The number of tokens that have currently been borrowed."""
+ raise NotImplementedError
+
+ @property
+ def available_tokens(self) -> float:
+ """The number of tokens currently available to be borrowed"""
+ raise NotImplementedError
+
+ def acquire_nowait(self) -> None:
+ """
+ Acquire a token for the current task without waiting for one to become
+ available.
+
+ :raises ~anyio.WouldBlock: if there are no tokens available for borrowing
+
+ """
+ raise NotImplementedError
+
+ def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
+ """
+ Acquire a token without waiting for one to become available.
+
+ :param borrower: the entity borrowing a token
+ :raises ~anyio.WouldBlock: if there are no tokens available for borrowing
+
+ """
+ raise NotImplementedError
+
+ async def acquire(self) -> None:
+ """
+ Acquire a token for the current task, waiting if necessary for one to become
+ available.
+
+ """
+ raise NotImplementedError
+
+ async def acquire_on_behalf_of(self, borrower: object) -> None:
+ """
+ Acquire a token, waiting if necessary for one to become available.
+
+ :param borrower: the entity borrowing a token
+
+ """
+ raise NotImplementedError
+
+ def release(self) -> None:
+ """
+ Release the token held by the current task.
+
+ :raises RuntimeError: if the current task has not borrowed a token from this
+ limiter.
+
+ """
+ raise NotImplementedError
+
+ def release_on_behalf_of(self, borrower: object) -> None:
+ """
+ Release the token held by the given borrower.
+
+ :raises RuntimeError: if the borrower has not borrowed a token from this
+ limiter.
+
+ """
+ raise NotImplementedError
+
+ def statistics(self) -> CapacityLimiterStatistics:
+ """
+ Return statistics about the current state of this limiter.
+
+ .. versionadded:: 3.0
+
+ """
+ raise NotImplementedError
+
+
+class CapacityLimiterAdapter(CapacityLimiter):
+ __slots__ = "_internal_limiter", "_total_tokens"
+
+ def __new__(cls, total_tokens: float) -> CapacityLimiterAdapter:
+ return object.__new__(cls)
+
+ def __init__(self, total_tokens: float) -> None:
+ self._internal_limiter: CapacityLimiter | None = None
+ self.total_tokens = total_tokens
+
+ @property
+ def _limiter(self) -> CapacityLimiter:
+ if self._internal_limiter is None:
+ self._internal_limiter = get_async_backend().create_capacity_limiter(
+ self._total_tokens
+ )
+
+ return self._internal_limiter
+
+ async def __aenter__(self) -> None:
+ await self._limiter.__aenter__()
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ return await self._limiter.__aexit__(exc_type, exc_val, exc_tb)
+
+ @property
+ def total_tokens(self) -> float:
+ if self._internal_limiter is None:
+ return self._total_tokens
+
+ return self._internal_limiter.total_tokens
+
+ @total_tokens.setter
+ def total_tokens(self, value: float) -> None:
+ if not isinstance(value, int) and value is not math.inf:
+ raise TypeError("total_tokens must be an int or math.inf")
+ elif value < 1:
+ raise ValueError("total_tokens must be >= 1")
+
+ if self._internal_limiter is None:
+ self._total_tokens = value
+ return
+
+ self._limiter.total_tokens = value
+
+ @property
+ def borrowed_tokens(self) -> int:
+ if self._internal_limiter is None:
+ return 0
+
+ return self._internal_limiter.borrowed_tokens
+
+ @property
+ def available_tokens(self) -> float:
+ if self._internal_limiter is None:
+ return self._total_tokens
+
+ return self._internal_limiter.available_tokens
+
+ def acquire_nowait(self) -> None:
+ self._limiter.acquire_nowait()
+
+ def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
+ self._limiter.acquire_on_behalf_of_nowait(borrower)
+
+ async def acquire(self) -> None:
+ await self._limiter.acquire()
+
+ async def acquire_on_behalf_of(self, borrower: object) -> None:
+ await self._limiter.acquire_on_behalf_of(borrower)
+
+ def release(self) -> None:
+ self._limiter.release()
+
+ def release_on_behalf_of(self, borrower: object) -> None:
+ self._limiter.release_on_behalf_of(borrower)
+
+ def statistics(self) -> CapacityLimiterStatistics:
+ if self._internal_limiter is None:
+ return CapacityLimiterStatistics(
+ borrowed_tokens=0,
+ total_tokens=self.total_tokens,
+ borrowers=(),
+ tasks_waiting=0,
+ )
+
+ return self._internal_limiter.statistics()
+
+
+class ResourceGuard:
+ """
+ A context manager for ensuring that a resource is only used by a single task at a
+ time.
+
+ Entering this context manager while the previous has not exited it yet will trigger
+ :exc:`BusyResourceError`.
+
+ :param action: the action to guard against (visible in the :exc:`BusyResourceError`
+ when triggered, e.g. "Another task is already {action} this resource")
+
+ .. versionadded:: 4.1
+ """
+
+ __slots__ = "__weakref__", "action", "_guarded"
+
+ def __init__(self, action: str = "using"):
+ self.action: str = action
+ self._guarded = False
+
+ def __enter__(self) -> None:
+ if self._guarded:
+ raise BusyResourceError(self.action)
+
+ self._guarded = True
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ self._guarded = False
diff --git a/venv/Lib/site-packages/anyio/_core/_tasks.py b/venv/Lib/site-packages/anyio/_core/_tasks.py
new file mode 100644
index 0000000000000000000000000000000000000000..108393e8cb56dfd705233cdcd78c509225283797
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_tasks.py
@@ -0,0 +1,415 @@
+from __future__ import annotations
+
+import math
+import sys
+from collections.abc import (
+ Coroutine,
+ Generator,
+)
+from contextlib import (
+ contextmanager,
+)
+from contextvars import ContextVar
+from enum import Enum, auto
+from inspect import iscoroutine
+from types import TracebackType
+from typing import Any, Generic, final
+
+from ..abc import TaskGroup, TaskStatus
+from ._eventloop import get_async_backend, get_cancelled_exc_class
+from ._exceptions import TaskCancelled, TaskFailed, TaskNotFinished
+
+if sys.version_info >= (3, 13):
+ from typing import TypeVar
+else:
+ from typing_extensions import TypeVar
+
+if sys.version_info >= (3, 11):
+ from typing import Never, TypeVarTuple
+else:
+ from typing_extensions import Never, TypeVarTuple
+
+T = TypeVar("T")
+T_co = TypeVar("T_co", covariant=True)
+T_startval = TypeVar("T_startval", covariant=True, default=Never)
+PosArgsT = TypeVarTuple("PosArgsT")
+
+_current_task_handle: ContextVar[TaskHandle] = ContextVar("_current_task_handle")
+
+
+class _IgnoredTaskStatus(TaskStatus[object]):
+ def started(self, value: object = None) -> None:
+ pass
+
+
+TASK_STATUS_IGNORED = _IgnoredTaskStatus()
+
+
+class CancelScope:
+ """
+ Wraps a unit of work that can be made separately cancellable.
+
+ :param deadline: The time (clock value) when this scope is cancelled automatically
+ :param shield: ``True`` to shield the cancel scope from external cancellation
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+ """
+
+ __slots__ = ("__weakref__",)
+
+ def __new__(
+ cls, *, deadline: float = math.inf, shield: bool = False
+ ) -> CancelScope:
+ return get_async_backend().create_cancel_scope(shield=shield, deadline=deadline)
+
+ def cancel(self, reason: str | None = None) -> None:
+ """
+ Cancel this scope immediately.
+
+ :param reason: a message describing the reason for the cancellation
+
+ """
+ raise NotImplementedError
+
+ @property
+ def deadline(self) -> float:
+ """
+ The time (clock value) when this scope is cancelled automatically.
+
+ Will be ``float('inf')`` if no timeout has been set.
+
+ """
+ raise NotImplementedError
+
+ @deadline.setter
+ def deadline(self, value: float) -> None:
+ raise NotImplementedError
+
+ @property
+ def cancel_called(self) -> bool:
+ """``True`` if :meth:`cancel` has been called."""
+ raise NotImplementedError
+
+ @property
+ def cancelled_caught(self) -> bool:
+ """
+ ``True`` if this scope suppressed a cancellation exception it itself raised.
+
+ This is typically used to check if any work was interrupted, or to see if the
+ scope was cancelled due to its deadline being reached. The value will, however,
+ only be ``True`` if the cancellation was triggered by the scope itself (and not
+ an outer scope).
+
+ """
+ raise NotImplementedError
+
+ @property
+ def shield(self) -> bool:
+ """
+ ``True`` if this scope is shielded from external cancellation.
+
+ While a scope is shielded, it will not receive cancellations from outside.
+
+ """
+ raise NotImplementedError
+
+ @shield.setter
+ def shield(self, value: bool) -> None:
+ raise NotImplementedError
+
+ def __enter__(self) -> CancelScope:
+ raise NotImplementedError
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> bool:
+ raise NotImplementedError
+
+
+@contextmanager
+def fail_after(
+ delay: float | None, shield: bool = False
+) -> Generator[CancelScope, None, None]:
+ """
+ Create a context manager which raises a :class:`TimeoutError` if does not finish in
+ time.
+
+ :param delay: maximum allowed time (in seconds) before raising the exception, or
+ ``None`` to disable the timeout
+ :param shield: ``True`` to shield the cancel scope from external cancellation
+ :return: a context manager that yields a cancel scope
+ :rtype: :class:`~typing.ContextManager`\\[:class:`~anyio.CancelScope`\\]
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ current_time = get_async_backend().current_time
+ deadline = (current_time() + delay) if delay is not None else math.inf
+ with get_async_backend().create_cancel_scope(
+ deadline=deadline, shield=shield
+ ) as cancel_scope:
+ yield cancel_scope
+
+ if cancel_scope.cancelled_caught and current_time() >= cancel_scope.deadline:
+ raise TimeoutError
+
+
+def move_on_after(delay: float | None, shield: bool = False) -> CancelScope:
+ """
+ Create a cancel scope with a deadline that expires after the given delay.
+
+ :param delay: maximum allowed time (in seconds) before exiting the context block, or
+ ``None`` to disable the timeout
+ :param shield: ``True`` to shield the cancel scope from external cancellation
+ :return: a cancel scope
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ deadline = (
+ (get_async_backend().current_time() + delay) if delay is not None else math.inf
+ )
+ return get_async_backend().create_cancel_scope(deadline=deadline, shield=shield)
+
+
+def current_effective_deadline() -> float:
+ """
+ Return the nearest deadline among all the cancel scopes effective for the current
+ task.
+
+ :return: a clock value from the event loop's internal clock (or ``float('inf')`` if
+ there is no deadline in effect, or ``float('-inf')`` if the current scope has
+ been cancelled)
+ :rtype: float
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ return get_async_backend().current_effective_deadline()
+
+
+def create_task_group() -> TaskGroup:
+ """
+ Create a task group.
+
+ :return: a task group
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ return get_async_backend().create_task_group()
+
+
+@final
+class TaskHandle(Generic[T_co, T_startval]):
+ """
+ Returned from the task-spawning methods of :class:`TaskGroup`. Can be awaited on to
+ get the return value of the task (or the raised exception). If the task was
+ terminated by a :exc:`BaseException`, :exc:`TaskFailed` will be raised (or its
+ subclass :exc:`TaskCancelled` if the task was cancelled).
+
+ .. versionadded:: 4.14.0
+ """
+
+ class Status(Enum):
+ """
+ The status of a task handle.
+
+ .. attribute:: PENDING
+
+ The task has not finished yet.
+ .. attribute:: FINISHED
+
+ The task has finished with a return value.
+ .. attribute:: CANCELLING
+
+ The task has been cancelled but has not finished yet.
+ .. attribute:: CANCELLED
+
+ The task was cancelled and has finished since.
+ .. attribute:: FAILED
+
+ The task raised an exception.
+ """
+
+ PENDING = auto()
+ FINISHED = auto()
+ CANCELLING = auto()
+ CANCELLED = auto()
+ FAILED = auto()
+
+ __slots__ = (
+ "__weakref__",
+ "_coro",
+ "_name",
+ "_cancel_scope",
+ "_finished_event",
+ "_return_value",
+ "_start_value",
+ "_exception",
+ )
+
+ _return_value: T_co
+ _start_value: T_startval
+
+ def __init__(self, coro: Coroutine[Any, Any, T_co], name: object) -> None:
+ from ._synchronization import Event
+
+ self._coro = coro
+ self._cancel_scope = CancelScope()
+ self._finished_event = Event()
+ self._exception: BaseException | None = None
+
+ if name is not None:
+ self._name = str(name)
+ elif iscoroutine(coro):
+ self._name = coro.__qualname__
+ else:
+ self._name = str(coro) # coroutine-like object (e.g. asend() objects)
+
+ async def _run_coro(self) -> None:
+ __tracebackhide__ = True
+
+ with self._cancel_scope:
+ try:
+ retval = await self._coro
+ except BaseException as exc:
+ self._exception = exc
+ raise
+ else:
+ self._return_value = retval
+ finally:
+ self._finished_event.set()
+ del self # Break the reference cycle
+
+ def cancel(self) -> None:
+ """
+ Set the task to a cancelled state.
+
+ This will interrupt any interruptible asynchronous operation, and will cause
+ any further awaits on this task to get immediately cancelled, unless done in
+ a shielded cancel scope.
+
+ If the task has already finished, this method has no effect.
+ """
+ if not self._finished_event.is_set():
+ self._cancel_scope.cancel()
+
+ @property
+ def coro(self) -> Coroutine[Any, Any, T_co]:
+ """
+ The coroutine object that was passed to one of the task-spawning methods in
+ :class:`TaskGroup`.
+ """
+ return self._coro
+
+ @property
+ def status(self) -> TaskHandle.Status:
+ """
+ The current status of the task.
+
+ Every task starts in the :attr:`~TaskHandle.Status.PENDING` state.
+ If a task is cancelled while in this state, it will transition to the
+ :attr:`~TaskHandle.Status.CANCELLING` state. When the task finishes, it will
+ transition to one of the three final states (
+ :attr:`~TaskHandle.Status.FINISHED`, :attr:`~TaskHandle.Status.FAILED`, or
+ :attr:`~TaskHandle.Status.CANCELLING`) depending on the exception the task
+ raised, if any. No other status transitions will happen.
+ """
+ if not self._finished_event.is_set():
+ if self._cancel_scope.cancel_called:
+ return TaskHandle.Status.CANCELLING
+ else:
+ return TaskHandle.Status.PENDING
+ elif self._exception is not None:
+ if isinstance(self._exception, get_cancelled_exc_class()):
+ return TaskHandle.Status.CANCELLED
+ else:
+ return TaskHandle.Status.FAILED
+ else:
+ return TaskHandle.Status.FINISHED
+
+ @property
+ def name(self) -> str:
+ """The name of the task."""
+ return self._name
+
+ @property
+ def exception(self) -> BaseException | None:
+ """
+ The exception raised by the task, or ``None`` if it finished without raising.
+
+ :raises TaskNotFinished: if the task has not finished yet
+ :raises TaskCancelled: if the task was cancelled
+
+ """
+ match self.status:
+ case TaskHandle.Status.PENDING:
+ raise TaskNotFinished("the task has not finished yet")
+ case TaskHandle.Status.FINISHED:
+ return None
+ case TaskHandle.Status.CANCELLING:
+ raise TaskCancelled("the task was cancelled")
+ case TaskHandle.Status.CANCELLED:
+ raise TaskCancelled("the task was cancelled") from self._exception
+ case TaskHandle.Status.FAILED:
+ return self._exception
+
+ @property
+ def return_value(self) -> T_co:
+ """
+ The return value of the task.
+
+ :raises TaskNotFinished: if the task has not finished yet
+ :raises TaskCancelled: if the task was cancelled
+ :raises TaskFailed: if the task raised an exception
+
+ """
+ match self.status:
+ case TaskHandle.Status.PENDING:
+ raise TaskNotFinished("the task has not finished yet")
+ case TaskHandle.Status.FINISHED:
+ return self._return_value
+ case TaskHandle.Status.CANCELLING:
+ raise TaskCancelled("the task was cancelled")
+ case TaskHandle.Status.CANCELLED:
+ raise TaskCancelled("the task was cancelled") from self._exception
+ case TaskHandle.Status.FAILED:
+ raise TaskFailed("the task raised an exception") from self._exception
+
+ @property
+ def start_value(self) -> T_startval:
+ """
+ The value passed to :meth:`task_status.started() <.abc.TaskStatus.started>`,
+
+ :raises RuntimeError: if the task was not started with :meth:`TaskGroup.start()
+ <.abc.TaskGroup.start>`
+ """
+ try:
+ return self._start_value
+ except AttributeError:
+ raise RuntimeError(
+ "the task was not started with TaskGroup.start()"
+ ) from None
+
+ async def wait(self) -> None:
+ """
+ Wait for the task to finish.
+
+ This method will return as soon as the task has finished, no matter how it
+ happened.
+ """
+ await self._finished_event.wait()
+
+ def __await__(self) -> Generator[Any, Any, T_co]:
+ yield from self._finished_event.wait().__await__()
+ return self.return_value
+
+ def __repr__(self) -> str:
+ return (
+ f"<{self.__class__.__name__} {self.status.name.lower()} "
+ f"name={self._name!r} coro={self._coro!r}>"
+ )
diff --git a/venv/Lib/site-packages/anyio/_core/_tempfile.py b/venv/Lib/site-packages/anyio/_core/_tempfile.py
new file mode 100644
index 0000000000000000000000000000000000000000..75a09f793744b8e60375ce2efab98307d077bc21
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_tempfile.py
@@ -0,0 +1,613 @@
+from __future__ import annotations
+
+import os
+import sys
+import tempfile
+from collections.abc import Iterable
+from io import BytesIO, TextIOWrapper
+from types import TracebackType
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ AnyStr,
+ Generic,
+ overload,
+)
+
+from .. import to_thread
+from .._core._fileio import AsyncFile
+from ..lowlevel import checkpoint_if_cancelled
+
+if TYPE_CHECKING:
+ from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer
+
+
+class TemporaryFile(Generic[AnyStr]):
+ """
+ An asynchronous temporary file that is automatically created and cleaned up.
+
+ This class provides an asynchronous context manager interface to a temporary file.
+ The file is created using Python's standard `tempfile.TemporaryFile` function in a
+ background thread, and is wrapped as an asynchronous file using `AsyncFile`.
+
+ :param mode: The mode in which the file is opened. Defaults to "w+b".
+ :param buffering: The buffering policy (-1 means the default buffering).
+ :param encoding: The encoding used to decode or encode the file. Only applicable in
+ text mode.
+ :param newline: Controls how universal newlines mode works (only applicable in text
+ mode).
+ :param suffix: The suffix for the temporary file name.
+ :param prefix: The prefix for the temporary file name.
+ :param dir: The directory in which the temporary file is created.
+ :param errors: The error handling scheme used for encoding/decoding errors.
+ """
+
+ _async_file: AsyncFile[AnyStr]
+
+ @overload
+ def __init__(
+ self: TemporaryFile[bytes],
+ mode: OpenBinaryMode = ...,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ newline: str | None = ...,
+ suffix: str | None = ...,
+ prefix: str | None = ...,
+ dir: str | None = ...,
+ *,
+ errors: str | None = ...,
+ ): ...
+ @overload
+ def __init__(
+ self: TemporaryFile[str],
+ mode: OpenTextMode,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ newline: str | None = ...,
+ suffix: str | None = ...,
+ prefix: str | None = ...,
+ dir: str | None = ...,
+ *,
+ errors: str | None = ...,
+ ): ...
+
+ def __init__(
+ self,
+ mode: OpenTextMode | OpenBinaryMode = "w+b",
+ buffering: int = -1,
+ encoding: str | None = None,
+ newline: str | None = None,
+ suffix: str | None = None,
+ prefix: str | None = None,
+ dir: str | None = None,
+ *,
+ errors: str | None = None,
+ ) -> None:
+ self.mode = mode
+ self.buffering = buffering
+ self.encoding = encoding
+ self.newline = newline
+ self.suffix: str | None = suffix
+ self.prefix: str | None = prefix
+ self.dir: str | None = dir
+ self.errors = errors
+
+ async def __aenter__(self) -> AsyncFile[AnyStr]:
+ fp = await to_thread.run_sync(
+ lambda: tempfile.TemporaryFile(
+ self.mode,
+ self.buffering,
+ self.encoding,
+ self.newline,
+ self.suffix,
+ self.prefix,
+ self.dir,
+ errors=self.errors,
+ )
+ )
+ self._async_file = AsyncFile(fp)
+ return self._async_file
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_value: BaseException | None,
+ traceback: TracebackType | None,
+ ) -> None:
+ await self._async_file.aclose()
+
+
+class NamedTemporaryFile(Generic[AnyStr]):
+ """
+ An asynchronous named temporary file that is automatically created and cleaned up.
+
+ This class provides an asynchronous context manager for a temporary file with a
+ visible name in the file system. It uses Python's standard
+ :func:`~tempfile.NamedTemporaryFile` function and wraps the file object with
+ :class:`AsyncFile` for asynchronous operations.
+
+ :param mode: The mode in which the file is opened. Defaults to "w+b".
+ :param buffering: The buffering policy (-1 means the default buffering).
+ :param encoding: The encoding used to decode or encode the file. Only applicable in
+ text mode.
+ :param newline: Controls how universal newlines mode works (only applicable in text
+ mode).
+ :param suffix: The suffix for the temporary file name.
+ :param prefix: The prefix for the temporary file name.
+ :param dir: The directory in which the temporary file is created.
+ :param delete: Whether to delete the file when it is closed.
+ :param errors: The error handling scheme used for encoding/decoding errors.
+ :param delete_on_close: (Python 3.12+) Whether to delete the file on close.
+ """
+
+ _async_file: AsyncFile[AnyStr]
+
+ @overload
+ def __init__(
+ self: NamedTemporaryFile[bytes],
+ mode: OpenBinaryMode = ...,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ newline: str | None = ...,
+ suffix: str | None = ...,
+ prefix: str | None = ...,
+ dir: str | None = ...,
+ delete: bool = ...,
+ *,
+ errors: str | None = ...,
+ delete_on_close: bool = ...,
+ ): ...
+ @overload
+ def __init__(
+ self: NamedTemporaryFile[str],
+ mode: OpenTextMode,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ newline: str | None = ...,
+ suffix: str | None = ...,
+ prefix: str | None = ...,
+ dir: str | None = ...,
+ delete: bool = ...,
+ *,
+ errors: str | None = ...,
+ delete_on_close: bool = ...,
+ ): ...
+
+ def __init__(
+ self,
+ mode: OpenBinaryMode | OpenTextMode = "w+b",
+ buffering: int = -1,
+ encoding: str | None = None,
+ newline: str | None = None,
+ suffix: str | None = None,
+ prefix: str | None = None,
+ dir: str | None = None,
+ delete: bool = True,
+ *,
+ errors: str | None = None,
+ delete_on_close: bool = True,
+ ) -> None:
+ self._params: dict[str, Any] = {
+ "mode": mode,
+ "buffering": buffering,
+ "encoding": encoding,
+ "newline": newline,
+ "suffix": suffix,
+ "prefix": prefix,
+ "dir": dir,
+ "delete": delete,
+ "errors": errors,
+ }
+ if sys.version_info >= (3, 12):
+ self._params["delete_on_close"] = delete_on_close
+
+ async def __aenter__(self) -> AsyncFile[AnyStr]:
+ fp = await to_thread.run_sync(
+ lambda: tempfile.NamedTemporaryFile(**self._params)
+ )
+ self._async_file = AsyncFile(fp)
+ return self._async_file
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_value: BaseException | None,
+ traceback: TracebackType | None,
+ ) -> None:
+ await self._async_file.aclose()
+
+
+class SpooledTemporaryFile(AsyncFile[AnyStr]):
+ """
+ An asynchronous spooled temporary file that starts in memory and is spooled to disk.
+
+ This class provides an asynchronous interface to a spooled temporary file, much like
+ Python's standard :class:`~tempfile.SpooledTemporaryFile`. It supports asynchronous
+ write operations and provides a method to force a rollover to disk.
+
+ :param max_size: Maximum size in bytes before the file is rolled over to disk.
+ :param mode: The mode in which the file is opened. Defaults to "w+b".
+ :param buffering: The buffering policy (-1 means the default buffering).
+ :param encoding: The encoding used to decode or encode the file (text mode only).
+ :param newline: Controls how universal newlines mode works (text mode only).
+ :param suffix: The suffix for the temporary file name.
+ :param prefix: The prefix for the temporary file name.
+ :param dir: The directory in which the temporary file is created.
+ :param errors: The error handling scheme used for encoding/decoding errors.
+ """
+
+ _rolled: bool = False
+
+ @overload
+ def __init__(
+ self: SpooledTemporaryFile[bytes],
+ max_size: int = ...,
+ mode: OpenBinaryMode = ...,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ newline: str | None = ...,
+ suffix: str | None = ...,
+ prefix: str | None = ...,
+ dir: str | None = ...,
+ *,
+ errors: str | None = ...,
+ ): ...
+ @overload
+ def __init__(
+ self: SpooledTemporaryFile[str],
+ max_size: int = ...,
+ mode: OpenTextMode = ...,
+ buffering: int = ...,
+ encoding: str | None = ...,
+ newline: str | None = ...,
+ suffix: str | None = ...,
+ prefix: str | None = ...,
+ dir: str | None = ...,
+ *,
+ errors: str | None = ...,
+ ): ...
+
+ def __init__(
+ self,
+ max_size: int = 0,
+ mode: OpenBinaryMode | OpenTextMode = "w+b",
+ buffering: int = -1,
+ encoding: str | None = None,
+ newline: str | None = None,
+ suffix: str | None = None,
+ prefix: str | None = None,
+ dir: str | None = None,
+ *,
+ errors: str | None = None,
+ ) -> None:
+ self._tempfile_params: dict[str, Any] = {
+ "mode": mode,
+ "buffering": buffering,
+ "encoding": encoding,
+ "newline": newline,
+ "suffix": suffix,
+ "prefix": prefix,
+ "dir": dir,
+ "errors": errors,
+ }
+ self._max_size = max_size
+ if "b" in mode:
+ super().__init__(BytesIO()) # type: ignore[arg-type]
+ else:
+ super().__init__(
+ TextIOWrapper( # type: ignore[arg-type]
+ BytesIO(),
+ encoding=encoding,
+ errors=errors,
+ newline=newline,
+ write_through=True,
+ )
+ )
+
+ async def aclose(self) -> None:
+ if not self._rolled:
+ self._fp.close()
+ return
+
+ await super().aclose()
+
+ async def _check(self) -> None:
+ if self._rolled or self._fp.tell() <= self._max_size:
+ return
+
+ await self.rollover()
+
+ async def rollover(self) -> None:
+ if self._rolled:
+ return
+
+ self._rolled = True
+ buffer = self._fp
+ buffer.seek(0)
+ self._fp = await to_thread.run_sync(
+ lambda: tempfile.TemporaryFile(**self._tempfile_params)
+ )
+ await self.write(buffer.read())
+ buffer.close()
+
+ @property
+ def closed(self) -> bool:
+ return self._fp.closed
+
+ async def read(self, size: int = -1) -> AnyStr:
+ if not self._rolled:
+ await checkpoint_if_cancelled()
+ return self._fp.read(size)
+
+ return await super().read(size) # type: ignore[return-value]
+
+ async def read1(self: SpooledTemporaryFile[bytes], size: int = -1) -> bytes:
+ if not self._rolled:
+ await checkpoint_if_cancelled()
+ return self._fp.read1(size)
+
+ return await super().read1(size)
+
+ async def readline(self) -> AnyStr:
+ if not self._rolled:
+ await checkpoint_if_cancelled()
+ return self._fp.readline()
+
+ return await super().readline() # type: ignore[return-value]
+
+ async def readlines(self) -> list[AnyStr]:
+ if not self._rolled:
+ await checkpoint_if_cancelled()
+ return self._fp.readlines()
+
+ return await super().readlines() # type: ignore[return-value]
+
+ async def readinto(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int:
+ if not self._rolled:
+ await checkpoint_if_cancelled()
+ self._fp.readinto(b)
+
+ return await super().readinto(b)
+
+ async def readinto1(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int:
+ if not self._rolled:
+ await checkpoint_if_cancelled()
+ self._fp.readinto(b)
+
+ return await super().readinto1(b)
+
+ async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int:
+ if not self._rolled:
+ await checkpoint_if_cancelled()
+ return self._fp.seek(offset, whence)
+
+ return await super().seek(offset, whence)
+
+ async def tell(self) -> int:
+ if not self._rolled:
+ await checkpoint_if_cancelled()
+ return self._fp.tell()
+
+ return await super().tell()
+
+ async def truncate(self, size: int | None = None) -> int:
+ if not self._rolled:
+ await checkpoint_if_cancelled()
+ return self._fp.truncate(size)
+
+ return await super().truncate(size)
+
+ @overload
+ async def write(self: SpooledTemporaryFile[bytes], b: ReadableBuffer) -> int: ...
+ @overload
+ async def write(self: SpooledTemporaryFile[str], b: str) -> int: ...
+
+ async def write(self, b: ReadableBuffer | str) -> int:
+ """
+ Asynchronously write data to the spooled temporary file.
+
+ If the file has not yet been rolled over, the data is written synchronously,
+ and a rollover is triggered if the size exceeds the maximum size.
+
+ :param s: The data to write.
+ :return: The number of bytes written.
+ :raises RuntimeError: If the underlying file is not initialized.
+
+ """
+ if not self._rolled:
+ await checkpoint_if_cancelled()
+ result = self._fp.write(b)
+ await self._check()
+ return result
+
+ return await super().write(b) # type: ignore[misc]
+
+ @overload
+ async def writelines(
+ self: SpooledTemporaryFile[bytes], lines: Iterable[ReadableBuffer]
+ ) -> None: ...
+ @overload
+ async def writelines(
+ self: SpooledTemporaryFile[str], lines: Iterable[str]
+ ) -> None: ...
+
+ async def writelines(self, lines: Iterable[str] | Iterable[ReadableBuffer]) -> None:
+ """
+ Asynchronously write a list of lines to the spooled temporary file.
+
+ If the file has not yet been rolled over, the lines are written synchronously,
+ and a rollover is triggered if the size exceeds the maximum size.
+
+ :param lines: An iterable of lines to write.
+ :raises RuntimeError: If the underlying file is not initialized.
+
+ """
+ if not self._rolled:
+ await checkpoint_if_cancelled()
+ result = self._fp.writelines(lines)
+ await self._check()
+ return result
+
+ return await super().writelines(lines) # type: ignore[misc]
+
+
+class TemporaryDirectory(Generic[AnyStr]):
+ """
+ An asynchronous temporary directory that is created and cleaned up automatically.
+
+ This class provides an asynchronous context manager for creating a temporary
+ directory. It wraps Python's standard :class:`~tempfile.TemporaryDirectory` to
+ perform directory creation and cleanup operations in a background thread.
+
+ :param suffix: Suffix to be added to the temporary directory name.
+ :param prefix: Prefix to be added to the temporary directory name.
+ :param dir: The parent directory where the temporary directory is created.
+ :param ignore_cleanup_errors: Whether to ignore errors during cleanup
+ :param delete: Whether to delete the directory upon closing (Python 3.12+).
+ """
+
+ def __init__(
+ self,
+ suffix: AnyStr | None = None,
+ prefix: AnyStr | None = None,
+ dir: AnyStr | None = None,
+ *,
+ ignore_cleanup_errors: bool = False,
+ delete: bool = True,
+ ) -> None:
+ self.suffix: AnyStr | None = suffix
+ self.prefix: AnyStr | None = prefix
+ self.dir: AnyStr | None = dir
+ self.ignore_cleanup_errors = ignore_cleanup_errors
+ self.delete = delete
+
+ self._tempdir: tempfile.TemporaryDirectory | None = None
+
+ async def __aenter__(self) -> str:
+ params: dict[str, Any] = {
+ "suffix": self.suffix,
+ "prefix": self.prefix,
+ "dir": self.dir,
+ "ignore_cleanup_errors": self.ignore_cleanup_errors,
+ }
+ if sys.version_info >= (3, 12):
+ params["delete"] = self.delete
+
+ self._tempdir = await to_thread.run_sync(
+ lambda: tempfile.TemporaryDirectory(**params)
+ )
+ return await to_thread.run_sync(self._tempdir.__enter__)
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_value: BaseException | None,
+ traceback: TracebackType | None,
+ ) -> None:
+ if self._tempdir is not None:
+ await to_thread.run_sync(
+ self._tempdir.__exit__, exc_type, exc_value, traceback
+ )
+
+ async def cleanup(self) -> None:
+ if self._tempdir is not None:
+ await to_thread.run_sync(self._tempdir.cleanup)
+
+
+@overload
+async def mkstemp(
+ suffix: str | None = None,
+ prefix: str | None = None,
+ dir: str | None = None,
+ text: bool = False,
+) -> tuple[int, str]: ...
+
+
+@overload
+async def mkstemp(
+ suffix: bytes | None = None,
+ prefix: bytes | None = None,
+ dir: bytes | None = None,
+ text: bool = False,
+) -> tuple[int, bytes]: ...
+
+
+async def mkstemp(
+ suffix: AnyStr | None = None,
+ prefix: AnyStr | None = None,
+ dir: AnyStr | None = None,
+ text: bool = False,
+) -> tuple[int, str | bytes]:
+ """
+ Asynchronously create a temporary file and return an OS-level handle and the file
+ name.
+
+ This function wraps `tempfile.mkstemp` and executes it in a background thread.
+
+ :param suffix: Suffix to be added to the file name.
+ :param prefix: Prefix to be added to the file name.
+ :param dir: Directory in which the temporary file is created.
+ :param text: Whether the file is opened in text mode.
+ :return: A tuple containing the file descriptor and the file name.
+
+ """
+ return await to_thread.run_sync(tempfile.mkstemp, suffix, prefix, dir, text)
+
+
+@overload
+async def mkdtemp(
+ suffix: str | None = None,
+ prefix: str | None = None,
+ dir: str | None = None,
+) -> str: ...
+
+
+@overload
+async def mkdtemp(
+ suffix: bytes | None = None,
+ prefix: bytes | None = None,
+ dir: bytes | None = None,
+) -> bytes: ...
+
+
+async def mkdtemp(
+ suffix: AnyStr | None = None,
+ prefix: AnyStr | None = None,
+ dir: AnyStr | None = None,
+) -> str | bytes:
+ """
+ Asynchronously create a temporary directory and return its path.
+
+ This function wraps `tempfile.mkdtemp` and executes it in a background thread.
+
+ :param suffix: Suffix to be added to the directory name.
+ :param prefix: Prefix to be added to the directory name.
+ :param dir: Parent directory where the temporary directory is created.
+ :return: The path of the created temporary directory.
+
+ """
+ return await to_thread.run_sync(tempfile.mkdtemp, suffix, prefix, dir)
+
+
+async def gettempdir() -> str:
+ """
+ Asynchronously return the name of the directory used for temporary files.
+
+ This function wraps `tempfile.gettempdir` and executes it in a background thread.
+
+ :return: The path of the temporary directory as a string.
+
+ """
+ return await to_thread.run_sync(tempfile.gettempdir)
+
+
+async def gettempdirb() -> bytes:
+ """
+ Asynchronously return the name of the directory used for temporary files in bytes.
+
+ This function wraps `tempfile.gettempdirb` and executes it in a background thread.
+
+ :return: The path of the temporary directory as bytes.
+
+ """
+ return await to_thread.run_sync(tempfile.gettempdirb)
diff --git a/venv/Lib/site-packages/anyio/_core/_testing.py b/venv/Lib/site-packages/anyio/_core/_testing.py
new file mode 100644
index 0000000000000000000000000000000000000000..369e65c068a426e99b7e8571209e80ce35b71f47
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_testing.py
@@ -0,0 +1,82 @@
+from __future__ import annotations
+
+from collections.abc import Awaitable, Generator
+from typing import Any, cast
+
+from ._eventloop import get_async_backend
+
+
+class TaskInfo:
+ """
+ Represents an asynchronous task.
+
+ :ivar int id: the unique identifier of the task
+ :ivar parent_id: the identifier of the parent task, if any
+ :vartype parent_id: Optional[int]
+ :ivar str name: the description of the task (if any)
+ :ivar ~collections.abc.Coroutine coro: the coroutine object of the task
+ """
+
+ __slots__ = "_name", "id", "parent_id", "name", "coro"
+
+ def __init__(
+ self,
+ id: int,
+ parent_id: int | None,
+ name: str | None,
+ coro: Generator[Any, Any, Any] | Awaitable[Any],
+ ):
+ func = get_current_task
+ self._name = f"{func.__module__}.{func.__qualname__}"
+ self.id: int = id
+ self.parent_id: int | None = parent_id
+ self.name: str | None = name
+ self.coro: Generator[Any, Any, Any] | Awaitable[Any] = coro
+
+ def __eq__(self, other: object) -> bool:
+ if isinstance(other, TaskInfo):
+ return self.id == other.id
+
+ return NotImplemented
+
+ def __hash__(self) -> int:
+ return hash(self.id)
+
+ def __repr__(self) -> str:
+ return f"{self.__class__.__name__}(id={self.id!r}, name={self.name!r})"
+
+ def has_pending_cancellation(self) -> bool:
+ """
+ Return ``True`` if the task has a cancellation pending, ``False`` otherwise.
+
+ """
+ return False
+
+
+def get_current_task() -> TaskInfo:
+ """
+ Return the current task.
+
+ :return: a representation of the current task
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ return get_async_backend().get_current_task()
+
+
+def get_running_tasks() -> list[TaskInfo]:
+ """
+ Return a list of running tasks in the current event loop.
+
+ :return: a list of task info objects
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ return cast("list[TaskInfo]", get_async_backend().get_running_tasks())
+
+
+async def wait_all_tasks_blocked() -> None:
+ """Wait until all other tasks are waiting for something."""
+ await get_async_backend().wait_all_tasks_blocked()
diff --git a/venv/Lib/site-packages/anyio/_core/_typedattr.py b/venv/Lib/site-packages/anyio/_core/_typedattr.py
new file mode 100644
index 0000000000000000000000000000000000000000..f358a448cb12739fd4eda4f4859d3a24ddd1de63
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/_core/_typedattr.py
@@ -0,0 +1,81 @@
+from __future__ import annotations
+
+from collections.abc import Callable, Mapping
+from typing import Any, TypeVar, final, overload
+
+from ._exceptions import TypedAttributeLookupError
+
+T_Attr = TypeVar("T_Attr")
+T_Default = TypeVar("T_Default")
+undefined = object()
+
+
+def typed_attribute() -> Any:
+ """Return a unique object, used to mark typed attributes."""
+ return object()
+
+
+class TypedAttributeSet:
+ """
+ Superclass for typed attribute collections.
+
+ Checks that every public attribute of every subclass has a type annotation.
+ """
+
+ def __init_subclass__(cls) -> None:
+ annotations: dict[str, Any] = getattr(cls, "__annotations__", {})
+ for attrname in dir(cls):
+ if not attrname.startswith("_") and attrname not in annotations:
+ raise TypeError(
+ f"Attribute {attrname!r} is missing its type annotation"
+ )
+
+ super().__init_subclass__()
+
+
+class TypedAttributeProvider:
+ """Base class for classes that wish to provide typed extra attributes."""
+
+ @property
+ def extra_attributes(self) -> Mapping[T_Attr, Callable[[], T_Attr]]:
+ """
+ A mapping of the extra attributes to callables that return the corresponding
+ values.
+
+ If the provider wraps another provider, the attributes from that wrapper should
+ also be included in the returned mapping (but the wrapper may override the
+ callables from the wrapped instance).
+
+ """
+ return {}
+
+ @overload
+ def extra(self, attribute: T_Attr) -> T_Attr: ...
+
+ @overload
+ def extra(self, attribute: T_Attr, default: T_Default) -> T_Attr | T_Default: ...
+
+ @final
+ def extra(self, attribute: Any, default: object = undefined) -> object:
+ """
+ extra(attribute, default=undefined)
+
+ Return the value of the given typed extra attribute.
+
+ :param attribute: the attribute (member of a :class:`~TypedAttributeSet`) to
+ look for
+ :param default: the value that should be returned if no value is found for the
+ attribute
+ :raises ~anyio.TypedAttributeLookupError: if the search failed and no default
+ value was given
+
+ """
+ try:
+ getter = self.extra_attributes[attribute]
+ except KeyError:
+ if default is undefined:
+ raise TypedAttributeLookupError("Attribute not found") from None
+ else:
+ return default
+
+ return getter()
diff --git a/venv/Lib/site-packages/anyio/abc/__init__.py b/venv/Lib/site-packages/anyio/abc/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d560ce3f1fa45a7ee4a3bc8958aa59702caa9d0c
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/abc/__init__.py
@@ -0,0 +1,58 @@
+from __future__ import annotations
+
+from ._eventloop import AsyncBackend as AsyncBackend
+from ._resources import AsyncResource as AsyncResource
+from ._sockets import ConnectedUDPSocket as ConnectedUDPSocket
+from ._sockets import ConnectedUNIXDatagramSocket as ConnectedUNIXDatagramSocket
+from ._sockets import IPAddressType as IPAddressType
+from ._sockets import IPSockAddrType as IPSockAddrType
+from ._sockets import SocketAttribute as SocketAttribute
+from ._sockets import SocketListener as SocketListener
+from ._sockets import SocketStream as SocketStream
+from ._sockets import UDPPacketType as UDPPacketType
+from ._sockets import UDPSocket as UDPSocket
+from ._sockets import UNIXDatagramPacketType as UNIXDatagramPacketType
+from ._sockets import UNIXDatagramSocket as UNIXDatagramSocket
+from ._sockets import UNIXSocketStream as UNIXSocketStream
+from ._streams import AnyByteReceiveStream as AnyByteReceiveStream
+from ._streams import AnyByteSendStream as AnyByteSendStream
+from ._streams import AnyByteStream as AnyByteStream
+from ._streams import AnyByteStreamConnectable as AnyByteStreamConnectable
+from ._streams import AnyUnreliableByteReceiveStream as AnyUnreliableByteReceiveStream
+from ._streams import AnyUnreliableByteSendStream as AnyUnreliableByteSendStream
+from ._streams import AnyUnreliableByteStream as AnyUnreliableByteStream
+from ._streams import ByteReceiveStream as ByteReceiveStream
+from ._streams import ByteSendStream as ByteSendStream
+from ._streams import ByteStream as ByteStream
+from ._streams import ByteStreamConnectable as ByteStreamConnectable
+from ._streams import Listener as Listener
+from ._streams import ObjectReceiveStream as ObjectReceiveStream
+from ._streams import ObjectSendStream as ObjectSendStream
+from ._streams import ObjectStream as ObjectStream
+from ._streams import ObjectStreamConnectable as ObjectStreamConnectable
+from ._streams import UnreliableObjectReceiveStream as UnreliableObjectReceiveStream
+from ._streams import UnreliableObjectSendStream as UnreliableObjectSendStream
+from ._streams import UnreliableObjectStream as UnreliableObjectStream
+from ._subprocesses import Process as Process
+from ._tasks import TaskGroup as TaskGroup
+from ._tasks import TaskStatus as TaskStatus
+from ._testing import TestRunner as TestRunner
+
+# Re-exported here, for backwards compatibility
+# isort: off
+from .._core._synchronization import (
+ CapacityLimiter as CapacityLimiter,
+ Condition as Condition,
+ Event as Event,
+ Lock as Lock,
+ Semaphore as Semaphore,
+)
+from .._core._tasks import CancelScope as CancelScope
+from ..from_thread import BlockingPortal as BlockingPortal
+
+# Re-export imports so they look like they live directly in this package
+for __value in list(locals().values()):
+ if getattr(__value, "__module__", "").startswith("anyio.abc."):
+ __value.__module__ = __name__
+
+del __value
diff --git a/venv/Lib/site-packages/anyio/abc/_eventloop.py b/venv/Lib/site-packages/anyio/abc/_eventloop.py
new file mode 100644
index 0000000000000000000000000000000000000000..cad3fa76370ff573469c1c52fd82d2eff0bc83eb
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/abc/_eventloop.py
@@ -0,0 +1,410 @@
+from __future__ import annotations
+
+import math
+import sys
+from abc import ABCMeta, abstractmethod
+from collections.abc import AsyncIterator, Awaitable, Callable, Coroutine, Sequence
+from contextlib import AbstractContextManager
+from os import PathLike
+from signal import Signals
+from socket import AddressFamily, SocketKind, socket
+from typing import (
+ IO,
+ TYPE_CHECKING,
+ Any,
+ TypeAlias,
+ TypeVar,
+ overload,
+)
+
+if sys.version_info >= (3, 11):
+ from typing import TypeVarTuple, Unpack
+else:
+ from typing_extensions import TypeVarTuple, Unpack
+
+if TYPE_CHECKING:
+ from _typeshed import FileDescriptorLike
+
+ from .._core._synchronization import CapacityLimiter, Event, Lock, Semaphore
+ from .._core._tasks import CancelScope
+ from .._core._testing import TaskInfo
+ from ._sockets import (
+ ConnectedUDPSocket,
+ ConnectedUNIXDatagramSocket,
+ IPSockAddrType,
+ SocketListener,
+ SocketStream,
+ UDPSocket,
+ UNIXDatagramSocket,
+ UNIXSocketStream,
+ )
+ from ._subprocesses import Process
+ from ._tasks import TaskGroup
+ from ._testing import TestRunner
+
+T_Retval = TypeVar("T_Retval")
+T_co = TypeVar("T_co", covariant=True)
+PosArgsT = TypeVarTuple("PosArgsT")
+StrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes]
+
+
+class AsyncBackend(metaclass=ABCMeta):
+ @classmethod
+ @abstractmethod
+ def run(
+ cls,
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+ args: tuple[Unpack[PosArgsT]],
+ kwargs: dict[str, Any],
+ options: dict[str, Any],
+ ) -> T_Retval:
+ """
+ Run the given coroutine function in an asynchronous event loop.
+
+ The current thread must not be already running an event loop.
+
+ :param func: a coroutine function
+ :param args: positional arguments to ``func``
+ :param kwargs: positional arguments to ``func``
+ :param options: keyword arguments to call the backend ``run()`` implementation
+ with
+ :return: the return value of the coroutine function
+ """
+
+ @classmethod
+ @abstractmethod
+ def current_token(cls) -> object:
+ """
+ Return an object that allows other threads to run code inside the event loop.
+
+ :return: a token object, specific to the event loop running in the current
+ thread
+ """
+
+ @classmethod
+ @abstractmethod
+ def current_time(cls) -> float:
+ """
+ Return the current value of the event loop's internal clock.
+
+ :return: the clock value (seconds)
+ """
+
+ @classmethod
+ @abstractmethod
+ def cancelled_exception_class(cls) -> type[BaseException]:
+ """Return the exception class that is raised in a task if it's cancelled."""
+
+ @classmethod
+ @abstractmethod
+ async def checkpoint(cls) -> None:
+ """
+ Check if the task has been cancelled, and allow rescheduling of other tasks.
+
+ This is effectively the same as running :meth:`checkpoint_if_cancelled` and then
+ :meth:`cancel_shielded_checkpoint`.
+ """
+
+ @classmethod
+ async def checkpoint_if_cancelled(cls) -> None:
+ """
+ Check if the current task group has been cancelled.
+
+ This will check if the task has been cancelled, but will not allow other tasks
+ to be scheduled if not.
+
+ """
+ if cls.current_effective_deadline() == -math.inf:
+ await cls.checkpoint()
+
+ @classmethod
+ async def cancel_shielded_checkpoint(cls) -> None:
+ """
+ Allow the rescheduling of other tasks.
+
+ This will give other tasks the opportunity to run, but without checking if the
+ current task group has been cancelled, unlike with :meth:`checkpoint`.
+
+ """
+ with cls.create_cancel_scope(shield=True):
+ await cls.sleep(0)
+
+ @classmethod
+ @abstractmethod
+ async def sleep(cls, delay: float) -> None:
+ """
+ Pause the current task for the specified duration.
+
+ :param delay: the duration, in seconds
+ """
+
+ @classmethod
+ @abstractmethod
+ def create_cancel_scope(
+ cls, *, deadline: float = math.inf, shield: bool = False
+ ) -> CancelScope:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def current_effective_deadline(cls) -> float:
+ """
+ Return the nearest deadline among all the cancel scopes effective for the
+ current task.
+
+ :return:
+ - a clock value from the event loop's internal clock
+ - ``inf`` if there is no deadline in effect
+ - ``-inf`` if the current scope has been cancelled
+ :rtype: float
+ """
+
+ @classmethod
+ @abstractmethod
+ def create_task_group(cls) -> TaskGroup:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def create_event(cls) -> Event:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def create_lock(cls, *, fast_acquire: bool) -> Lock:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def create_semaphore(
+ cls,
+ initial_value: int,
+ *,
+ max_value: int | None = None,
+ fast_acquire: bool = False,
+ ) -> Semaphore:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def run_sync_in_worker_thread(
+ cls,
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
+ args: tuple[Unpack[PosArgsT]],
+ abandon_on_cancel: bool = False,
+ limiter: CapacityLimiter | None = None,
+ ) -> T_Retval:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def check_cancelled(cls) -> None:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def run_async_from_thread(
+ cls,
+ func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]],
+ args: tuple[Unpack[PosArgsT]],
+ token: object,
+ ) -> T_co:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def run_sync_from_thread(
+ cls,
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
+ args: tuple[Unpack[PosArgsT]],
+ token: object,
+ ) -> T_Retval:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def open_process(
+ cls,
+ command: StrOrBytesPath | Sequence[StrOrBytesPath],
+ *,
+ stdin: int | IO[Any] | None,
+ stdout: int | IO[Any] | None,
+ stderr: int | IO[Any] | None,
+ **kwargs: Any,
+ ) -> Process:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def setup_process_pool_exit_at_shutdown(cls, workers: set[Process]) -> None:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def connect_tcp(
+ cls, host: str, port: int, local_address: IPSockAddrType | None = None
+ ) -> SocketStream:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def connect_unix(cls, path: str | bytes) -> UNIXSocketStream:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def create_tcp_listener(cls, sock: socket) -> SocketListener:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def create_unix_listener(cls, sock: socket) -> SocketListener:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def create_udp_socket(
+ cls,
+ family: AddressFamily,
+ local_address: IPSockAddrType | None,
+ remote_address: IPSockAddrType | None,
+ reuse_port: bool,
+ ) -> UDPSocket | ConnectedUDPSocket:
+ pass
+
+ @classmethod
+ @overload
+ async def create_unix_datagram_socket(
+ cls, raw_socket: socket, remote_path: None
+ ) -> UNIXDatagramSocket: ...
+
+ @classmethod
+ @overload
+ async def create_unix_datagram_socket(
+ cls, raw_socket: socket, remote_path: str | bytes
+ ) -> ConnectedUNIXDatagramSocket: ...
+
+ @classmethod
+ @abstractmethod
+ async def create_unix_datagram_socket(
+ cls, raw_socket: socket, remote_path: str | bytes | None
+ ) -> UNIXDatagramSocket | ConnectedUNIXDatagramSocket:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def getaddrinfo(
+ cls,
+ host: bytes | str | None,
+ port: str | int | None,
+ *,
+ family: int | AddressFamily = 0,
+ type: int | SocketKind = 0,
+ proto: int = 0,
+ flags: int = 0,
+ ) -> Sequence[
+ tuple[
+ AddressFamily,
+ SocketKind,
+ int,
+ str,
+ tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
+ ]
+ ]:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def getnameinfo(
+ cls, sockaddr: IPSockAddrType, flags: int = 0
+ ) -> tuple[str, str]:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def wait_readable(cls, obj: FileDescriptorLike) -> None:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def wait_writable(cls, obj: FileDescriptorLike) -> None:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def notify_closing(cls, obj: FileDescriptorLike) -> None:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def wrap_listener_socket(cls, sock: socket) -> SocketListener:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def wrap_stream_socket(cls, sock: socket) -> SocketStream:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def wrap_unix_stream_socket(cls, sock: socket) -> UNIXSocketStream:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def wrap_udp_socket(cls, sock: socket) -> UDPSocket:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def wrap_connected_udp_socket(cls, sock: socket) -> ConnectedUDPSocket:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def wrap_unix_datagram_socket(cls, sock: socket) -> UNIXDatagramSocket:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def wrap_connected_unix_datagram_socket(
+ cls, sock: socket
+ ) -> ConnectedUNIXDatagramSocket:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def current_default_thread_limiter(cls) -> CapacityLimiter:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def open_signal_receiver(
+ cls, *signals: Signals
+ ) -> AbstractContextManager[AsyncIterator[Signals]]:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def get_current_task(cls) -> TaskInfo:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def get_running_tasks(cls) -> Sequence[TaskInfo]:
+ pass
+
+ @classmethod
+ @abstractmethod
+ async def wait_all_tasks_blocked(cls) -> None:
+ pass
+
+ @classmethod
+ @abstractmethod
+ def create_test_runner(cls, options: dict[str, Any]) -> TestRunner:
+ pass
diff --git a/venv/Lib/site-packages/anyio/abc/_resources.py b/venv/Lib/site-packages/anyio/abc/_resources.py
new file mode 100644
index 0000000000000000000000000000000000000000..10df115a7b9f975493476da763cc1e26dbd822e5
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/abc/_resources.py
@@ -0,0 +1,33 @@
+from __future__ import annotations
+
+from abc import ABCMeta, abstractmethod
+from types import TracebackType
+from typing import TypeVar
+
+T = TypeVar("T")
+
+
+class AsyncResource(metaclass=ABCMeta):
+ """
+ Abstract base class for all closeable asynchronous resources.
+
+ Works as an asynchronous context manager which returns the instance itself on enter,
+ and calls :meth:`aclose` on exit.
+ """
+
+ __slots__ = ()
+
+ async def __aenter__(self: T) -> T:
+ return self
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ await self.aclose()
+
+ @abstractmethod
+ async def aclose(self) -> None:
+ """Close the resource."""
diff --git a/venv/Lib/site-packages/anyio/abc/_sockets.py b/venv/Lib/site-packages/anyio/abc/_sockets.py
new file mode 100644
index 0000000000000000000000000000000000000000..feb26bd44a240acb20fd0f2498dff5631b8e2fb3
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/abc/_sockets.py
@@ -0,0 +1,399 @@
+from __future__ import annotations
+
+import errno
+import socket
+from abc import abstractmethod
+from collections.abc import Callable, Collection, Mapping
+from contextlib import AsyncExitStack
+from io import IOBase
+from ipaddress import IPv4Address, IPv6Address
+from socket import AddressFamily
+from typing import Any, TypeAlias, TypeVar
+
+from .._core._eventloop import get_async_backend
+from .._core._typedattr import (
+ TypedAttributeProvider,
+ TypedAttributeSet,
+ typed_attribute,
+)
+from ._streams import ByteStream, Listener, UnreliableObjectStream
+from ._tasks import TaskGroup
+
+IPAddressType: TypeAlias = str | IPv4Address | IPv6Address
+IPSockAddrType: TypeAlias = tuple[str, int]
+SockAddrType: TypeAlias = IPSockAddrType | str
+UDPPacketType: TypeAlias = tuple[bytes, IPSockAddrType]
+UNIXDatagramPacketType: TypeAlias = tuple[bytes, str]
+T_Retval = TypeVar("T_Retval")
+
+
+def _validate_socket(
+ sock_or_fd: socket.socket | int,
+ sock_type: socket.SocketKind,
+ addr_family: socket.AddressFamily = socket.AF_UNSPEC,
+ *,
+ require_connected: bool = False,
+ require_bound: bool = False,
+) -> socket.socket:
+ if isinstance(sock_or_fd, int):
+ try:
+ sock = socket.socket(fileno=sock_or_fd)
+ except OSError as exc:
+ if exc.errno == errno.ENOTSOCK:
+ raise ValueError(
+ "the file descriptor does not refer to a socket"
+ ) from exc
+ elif require_connected:
+ raise ValueError("the socket must be connected") from exc
+ elif require_bound:
+ raise ValueError("the socket must be bound to a local address") from exc
+ else:
+ raise
+ elif isinstance(sock_or_fd, socket.socket):
+ sock = sock_or_fd
+ else:
+ raise TypeError(
+ f"expected an int or socket, got {type(sock_or_fd).__qualname__} instead"
+ )
+
+ try:
+ if require_connected:
+ try:
+ sock.getpeername()
+ except OSError as exc:
+ raise ValueError("the socket must be connected") from exc
+
+ if require_bound:
+ try:
+ if sock.family in (socket.AF_INET, socket.AF_INET6):
+ bound_addr = sock.getsockname()[1]
+ else:
+ bound_addr = sock.getsockname()
+ except OSError:
+ bound_addr = None
+
+ if not bound_addr:
+ raise ValueError("the socket must be bound to a local address")
+
+ if addr_family != socket.AF_UNSPEC and sock.family != addr_family:
+ raise ValueError(
+ f"address family mismatch: expected {addr_family.name}, got "
+ f"{sock.family.name}"
+ )
+
+ if sock.type != sock_type:
+ raise ValueError(
+ f"socket type mismatch: expected {sock_type.name}, got {sock.type.name}"
+ )
+ except BaseException:
+ # Avoid ResourceWarning from the locally constructed socket object
+ if isinstance(sock_or_fd, int):
+ sock.detach()
+
+ raise
+
+ sock.setblocking(False)
+ return sock
+
+
+class SocketAttribute(TypedAttributeSet):
+ """
+ .. attribute:: family
+ :type: socket.AddressFamily
+
+ the address family of the underlying socket
+
+ .. attribute:: local_address
+ :type: tuple[str, int] | str
+
+ the local address the underlying socket is connected to
+
+ .. attribute:: local_port
+ :type: int
+
+ for IP based sockets, the local port the underlying socket is bound to
+
+ .. attribute:: raw_socket
+ :type: socket.socket
+
+ the underlying stdlib socket object
+
+ .. attribute:: remote_address
+ :type: tuple[str, int] | str
+
+ the remote address the underlying socket is connected to
+
+ .. attribute:: remote_port
+ :type: int
+
+ for IP based sockets, the remote port the underlying socket is connected to
+ """
+
+ family: AddressFamily = typed_attribute()
+ local_address: SockAddrType = typed_attribute()
+ local_port: int = typed_attribute()
+ raw_socket: socket.socket = typed_attribute()
+ remote_address: SockAddrType = typed_attribute()
+ remote_port: int = typed_attribute()
+
+
+class _SocketProvider(TypedAttributeProvider):
+ @property
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
+ from .._core._sockets import convert_ipv6_sockaddr as convert
+
+ attributes: dict[Any, Callable[[], Any]] = {
+ SocketAttribute.family: lambda: self._raw_socket.family,
+ SocketAttribute.local_address: lambda: convert(
+ self._raw_socket.getsockname()
+ ),
+ SocketAttribute.raw_socket: lambda: self._raw_socket,
+ }
+ try:
+ peername: tuple[str, int] | None = convert(self._raw_socket.getpeername())
+ except OSError:
+ peername = None
+
+ # Provide the remote address for connected sockets
+ if peername is not None:
+ attributes[SocketAttribute.remote_address] = lambda: peername
+
+ # Provide local and remote ports for IP based sockets
+ if self._raw_socket.family in (AddressFamily.AF_INET, AddressFamily.AF_INET6):
+ attributes[SocketAttribute.local_port] = lambda: (
+ self._raw_socket.getsockname()[1]
+ )
+ if peername is not None:
+ remote_port = peername[1]
+ attributes[SocketAttribute.remote_port] = lambda: remote_port
+
+ return attributes
+
+ @property
+ @abstractmethod
+ def _raw_socket(self) -> socket.socket:
+ pass
+
+
+class SocketStream(ByteStream, _SocketProvider):
+ """
+ Transports bytes over a socket.
+
+ Supports all relevant extra attributes from :class:`~SocketAttribute`.
+ """
+
+ @classmethod
+ async def from_socket(cls, sock_or_fd: socket.socket | int) -> SocketStream:
+ """
+ Wrap an existing socket object or file descriptor as a socket stream.
+
+ The newly created socket wrapper takes ownership of the socket being passed in.
+ The existing socket must already be connected.
+
+ :param sock_or_fd: a socket object or file descriptor
+ :return: a socket stream
+
+ """
+ sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_connected=True)
+ return await get_async_backend().wrap_stream_socket(sock)
+
+
+class UNIXSocketStream(SocketStream):
+ @classmethod
+ async def from_socket(cls, sock_or_fd: socket.socket | int) -> UNIXSocketStream:
+ """
+ Wrap an existing socket object or file descriptor as a UNIX socket stream.
+
+ The newly created socket wrapper takes ownership of the socket being passed in.
+ The existing socket must already be connected.
+
+ :param sock_or_fd: a socket object or file descriptor
+ :return: a UNIX socket stream
+
+ """
+ sock = _validate_socket(
+ sock_or_fd, socket.SOCK_STREAM, socket.AF_UNIX, require_connected=True
+ )
+ return await get_async_backend().wrap_unix_stream_socket(sock)
+
+ @abstractmethod
+ async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None:
+ """
+ Send file descriptors along with a message to the peer.
+
+ :param message: a non-empty bytestring
+ :param fds: a collection of files (either numeric file descriptors or open file
+ or socket objects)
+ """
+
+ @abstractmethod
+ async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]:
+ """
+ Receive file descriptors along with a message from the peer.
+
+ :param msglen: length of the message to expect from the peer
+ :param maxfds: maximum number of file descriptors to expect from the peer
+ :return: a tuple of (message, file descriptors)
+ """
+
+
+class SocketListener(Listener[SocketStream], _SocketProvider):
+ """
+ Listens to incoming socket connections.
+
+ Supports all relevant extra attributes from :class:`~SocketAttribute`.
+ """
+
+ @classmethod
+ async def from_socket(
+ cls,
+ sock_or_fd: socket.socket | int,
+ ) -> SocketListener:
+ """
+ Wrap an existing socket object or file descriptor as a socket listener.
+
+ The newly created listener takes ownership of the socket being passed in.
+
+ :param sock_or_fd: a socket object or file descriptor
+ :return: a socket listener
+
+ """
+ sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_bound=True)
+ return await get_async_backend().wrap_listener_socket(sock)
+
+ @abstractmethod
+ async def accept(self) -> SocketStream:
+ """Accept an incoming connection."""
+
+ async def serve(
+ self,
+ handler: Callable[[SocketStream], Any],
+ task_group: TaskGroup | None = None,
+ ) -> None:
+ from .. import create_task_group
+
+ async with AsyncExitStack() as stack:
+ if task_group is None:
+ task_group = await stack.enter_async_context(create_task_group())
+
+ while True:
+ stream = await self.accept()
+ task_group.start_soon(handler, stream)
+
+
+class UDPSocket(UnreliableObjectStream[UDPPacketType], _SocketProvider):
+ """
+ Represents an unconnected UDP socket.
+
+ Supports all relevant extra attributes from :class:`~SocketAttribute`.
+ """
+
+ @classmethod
+ async def from_socket(cls, sock_or_fd: socket.socket | int) -> UDPSocket:
+ """
+ Wrap an existing socket object or file descriptor as a UDP socket.
+
+ The newly created socket wrapper takes ownership of the socket being passed in.
+ The existing socket must be bound to a local address.
+
+ :param sock_or_fd: a socket object or file descriptor
+ :return: a UDP socket
+
+ """
+ sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, require_bound=True)
+ return await get_async_backend().wrap_udp_socket(sock)
+
+ async def sendto(self, data: bytes, host: str, port: int) -> None:
+ """
+ Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, (host, port))).
+
+ """
+ return await self.send((data, (host, port)))
+
+
+class ConnectedUDPSocket(UnreliableObjectStream[bytes], _SocketProvider):
+ """
+ Represents an connected UDP socket.
+
+ Supports all relevant extra attributes from :class:`~SocketAttribute`.
+ """
+
+ @classmethod
+ async def from_socket(cls, sock_or_fd: socket.socket | int) -> ConnectedUDPSocket:
+ """
+ Wrap an existing socket object or file descriptor as a connected UDP socket.
+
+ The newly created socket wrapper takes ownership of the socket being passed in.
+ The existing socket must already be connected.
+
+ :param sock_or_fd: a socket object or file descriptor
+ :return: a connected UDP socket
+
+ """
+ sock = _validate_socket(
+ sock_or_fd,
+ socket.SOCK_DGRAM,
+ require_connected=True,
+ )
+ return await get_async_backend().wrap_connected_udp_socket(sock)
+
+
+class UNIXDatagramSocket(
+ UnreliableObjectStream[UNIXDatagramPacketType], _SocketProvider
+):
+ """
+ Represents an unconnected Unix datagram socket.
+
+ Supports all relevant extra attributes from :class:`~SocketAttribute`.
+ """
+
+ @classmethod
+ async def from_socket(
+ cls,
+ sock_or_fd: socket.socket | int,
+ ) -> UNIXDatagramSocket:
+ """
+ Wrap an existing socket object or file descriptor as a UNIX datagram
+ socket.
+
+ The newly created socket wrapper takes ownership of the socket being passed in.
+
+ :param sock_or_fd: a socket object or file descriptor
+ :return: a UNIX datagram socket
+
+ """
+ sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX)
+ return await get_async_backend().wrap_unix_datagram_socket(sock)
+
+ async def sendto(self, data: bytes, path: str) -> None:
+ """Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, path))."""
+ return await self.send((data, path))
+
+
+class ConnectedUNIXDatagramSocket(UnreliableObjectStream[bytes], _SocketProvider):
+ """
+ Represents a connected Unix datagram socket.
+
+ Supports all relevant extra attributes from :class:`~SocketAttribute`.
+ """
+
+ @classmethod
+ async def from_socket(
+ cls,
+ sock_or_fd: socket.socket | int,
+ ) -> ConnectedUNIXDatagramSocket:
+ """
+ Wrap an existing socket object or file descriptor as a connected UNIX datagram
+ socket.
+
+ The newly created socket wrapper takes ownership of the socket being passed in.
+ The existing socket must already be connected.
+
+ :param sock_or_fd: a socket object or file descriptor
+ :return: a connected UNIX datagram socket
+
+ """
+ sock = _validate_socket(
+ sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX, require_connected=True
+ )
+ return await get_async_backend().wrap_connected_unix_datagram_socket(sock)
diff --git a/venv/Lib/site-packages/anyio/abc/_streams.py b/venv/Lib/site-packages/anyio/abc/_streams.py
new file mode 100644
index 0000000000000000000000000000000000000000..186e3f503a9a71ce96ac2087cf8bfdedc490c534
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/abc/_streams.py
@@ -0,0 +1,233 @@
+from __future__ import annotations
+
+from abc import ABCMeta, abstractmethod
+from collections.abc import Callable
+from typing import Any, Generic, TypeAlias, TypeVar
+
+from .._core._exceptions import EndOfStream
+from .._core._typedattr import TypedAttributeProvider
+from ._resources import AsyncResource
+from ._tasks import TaskGroup
+
+T_Item = TypeVar("T_Item")
+T_co = TypeVar("T_co", covariant=True)
+T_contra = TypeVar("T_contra", contravariant=True)
+
+
+class UnreliableObjectReceiveStream(
+ Generic[T_co], AsyncResource, TypedAttributeProvider
+):
+ """
+ An interface for receiving objects.
+
+ This interface makes no guarantees that the received messages arrive in the order in
+ which they were sent, or that no messages are missed.
+
+ Asynchronously iterating over objects of this type will yield objects matching the
+ given type parameter.
+ """
+
+ def __aiter__(self) -> UnreliableObjectReceiveStream[T_co]:
+ return self
+
+ async def __anext__(self) -> T_co:
+ try:
+ return await self.receive()
+ except EndOfStream:
+ raise StopAsyncIteration from None
+
+ @abstractmethod
+ async def receive(self) -> T_co:
+ """
+ Receive the next item.
+
+ :raises ~anyio.ClosedResourceError: if the receive stream has been explicitly
+ closed
+ :raises ~anyio.EndOfStream: if this stream has been closed from the other end
+ :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable
+ due to external causes
+ """
+
+
+class UnreliableObjectSendStream(
+ Generic[T_contra], AsyncResource, TypedAttributeProvider
+):
+ """
+ An interface for sending objects.
+
+ This interface makes no guarantees that the messages sent will reach the
+ recipient(s) in the same order in which they were sent, or at all.
+ """
+
+ @abstractmethod
+ async def send(self, item: T_contra) -> None:
+ """
+ Send an item to the peer(s).
+
+ :param item: the item to send
+ :raises ~anyio.ClosedResourceError: if the send stream has been explicitly
+ closed
+ :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable
+ due to external causes
+ """
+
+
+class UnreliableObjectStream(
+ UnreliableObjectReceiveStream[T_Item], UnreliableObjectSendStream[T_Item]
+):
+ """
+ A bidirectional message stream which does not guarantee the order or reliability of
+ message delivery.
+ """
+
+
+class ObjectReceiveStream(UnreliableObjectReceiveStream[T_co]):
+ """
+ A receive message stream which guarantees that messages are received in the same
+ order in which they were sent, and that no messages are missed.
+ """
+
+
+class ObjectSendStream(UnreliableObjectSendStream[T_contra]):
+ """
+ A send message stream which guarantees that messages are delivered in the same order
+ in which they were sent, without missing any messages in the middle.
+ """
+
+
+class ObjectStream(
+ ObjectReceiveStream[T_Item],
+ ObjectSendStream[T_Item],
+ UnreliableObjectStream[T_Item],
+):
+ """
+ A bidirectional message stream which guarantees the order and reliability of message
+ delivery.
+ """
+
+ @abstractmethod
+ async def send_eof(self) -> None:
+ """
+ Send an end-of-file indication to the peer.
+
+ You should not try to send any further data to this stream after calling this
+ method. This method is idempotent (does nothing on successive calls).
+ """
+
+
+class ByteReceiveStream(AsyncResource, TypedAttributeProvider):
+ """
+ An interface for receiving bytes from a single peer.
+
+ Iterating this byte stream will yield a byte string of arbitrary length, but no more
+ than 65536 bytes.
+ """
+
+ def __aiter__(self) -> ByteReceiveStream:
+ return self
+
+ async def __anext__(self) -> bytes:
+ try:
+ return await self.receive()
+ except EndOfStream:
+ raise StopAsyncIteration from None
+
+ @abstractmethod
+ async def receive(self, max_bytes: int = 65536) -> bytes:
+ """
+ Receive at most ``max_bytes`` bytes from the peer.
+
+ .. note:: Implementers of this interface should not return an empty
+ :class:`bytes` object, and users should ignore them.
+
+ :param max_bytes: maximum number of bytes to receive
+ :return: the received bytes
+ :raises ~anyio.EndOfStream: if this stream has been closed from the other end
+ """
+
+
+class ByteSendStream(AsyncResource, TypedAttributeProvider):
+ """An interface for sending bytes to a single peer."""
+
+ @abstractmethod
+ async def send(self, item: bytes) -> None:
+ """
+ Send the given bytes to the peer.
+
+ :param item: the bytes to send
+ """
+
+
+class ByteStream(ByteReceiveStream, ByteSendStream):
+ """A bidirectional byte stream."""
+
+ @abstractmethod
+ async def send_eof(self) -> None:
+ """
+ Send an end-of-file indication to the peer.
+
+ You should not try to send any further data to this stream after calling this
+ method. This method is idempotent (does nothing on successive calls).
+ """
+
+
+#: Type alias for all unreliable bytes-oriented receive streams.
+AnyUnreliableByteReceiveStream: TypeAlias = (
+ UnreliableObjectReceiveStream[bytes] | ByteReceiveStream
+)
+#: Type alias for all unreliable bytes-oriented send streams.
+AnyUnreliableByteSendStream: TypeAlias = (
+ UnreliableObjectSendStream[bytes] | ByteSendStream
+)
+#: Type alias for all unreliable bytes-oriented streams.
+AnyUnreliableByteStream: TypeAlias = UnreliableObjectStream[bytes] | ByteStream
+#: Type alias for all bytes-oriented receive streams.
+AnyByteReceiveStream: TypeAlias = ObjectReceiveStream[bytes] | ByteReceiveStream
+#: Type alias for all bytes-oriented send streams.
+AnyByteSendStream: TypeAlias = ObjectSendStream[bytes] | ByteSendStream
+#: Type alias for all bytes-oriented streams.
+AnyByteStream: TypeAlias = ObjectStream[bytes] | ByteStream
+
+
+class Listener(Generic[T_co], AsyncResource, TypedAttributeProvider):
+ """An interface for objects that let you accept incoming connections."""
+
+ @abstractmethod
+ async def serve(
+ self, handler: Callable[[T_co], Any], task_group: TaskGroup | None = None
+ ) -> None:
+ """
+ Accept incoming connections as they come in and start tasks to handle them.
+
+ :param handler: a callable that will be used to handle each accepted connection
+ :param task_group: the task group that will be used to start tasks for handling
+ each accepted connection (if omitted, an ad-hoc task group will be created)
+ """
+
+
+class ObjectStreamConnectable(Generic[T_co], metaclass=ABCMeta):
+ @abstractmethod
+ async def connect(self) -> ObjectStream[T_co]:
+ """
+ Connect to the remote endpoint.
+
+ :return: an object stream connected to the remote end
+ :raises ConnectionFailed: if the connection fails
+ """
+
+
+class ByteStreamConnectable(metaclass=ABCMeta):
+ @abstractmethod
+ async def connect(self) -> ByteStream:
+ """
+ Connect to the remote endpoint.
+
+ :return: a bytestream connected to the remote end
+ :raises ConnectionFailed: if the connection fails
+ """
+
+
+#: Type alias for all connectables returning bytestreams or bytes-oriented object streams
+AnyByteStreamConnectable: TypeAlias = (
+ ObjectStreamConnectable[bytes] | ByteStreamConnectable
+)
diff --git a/venv/Lib/site-packages/anyio/abc/_subprocesses.py b/venv/Lib/site-packages/anyio/abc/_subprocesses.py
new file mode 100644
index 0000000000000000000000000000000000000000..ce0564ceac8aac425675b5c8f7f7205d08061fd3
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/abc/_subprocesses.py
@@ -0,0 +1,79 @@
+from __future__ import annotations
+
+from abc import abstractmethod
+from signal import Signals
+
+from ._resources import AsyncResource
+from ._streams import ByteReceiveStream, ByteSendStream
+
+
+class Process(AsyncResource):
+ """An asynchronous version of :class:`subprocess.Popen`."""
+
+ @abstractmethod
+ async def wait(self) -> int:
+ """
+ Wait until the process exits.
+
+ :return: the exit code of the process
+ """
+
+ @abstractmethod
+ def terminate(self) -> None:
+ """
+ Terminates the process, gracefully if possible.
+
+ On Windows, this calls ``TerminateProcess()``.
+ On POSIX systems, this sends ``SIGTERM`` to the process.
+
+ .. seealso:: :meth:`subprocess.Popen.terminate`
+ """
+
+ @abstractmethod
+ def kill(self) -> None:
+ """
+ Kills the process.
+
+ On Windows, this calls ``TerminateProcess()``.
+ On POSIX systems, this sends ``SIGKILL`` to the process.
+
+ .. seealso:: :meth:`subprocess.Popen.kill`
+ """
+
+ @abstractmethod
+ def send_signal(self, signal: Signals) -> None:
+ """
+ Send a signal to the subprocess.
+
+ .. seealso:: :meth:`subprocess.Popen.send_signal`
+
+ :param signal: the signal number (e.g. :data:`signal.SIGHUP`)
+ """
+
+ @property
+ @abstractmethod
+ def pid(self) -> int:
+ """The process ID of the process."""
+
+ @property
+ @abstractmethod
+ def returncode(self) -> int | None:
+ """
+ The return code of the process. If the process has not yet terminated, this will
+ be ``None``.
+ """
+
+ @property
+ @abstractmethod
+ def stdin(self) -> ByteSendStream | None:
+ """The stream for the standard input of the process."""
+
+ @property
+ @abstractmethod
+ def stdout(self) -> ByteReceiveStream | None:
+ """The stream for the standard output of the process."""
+
+ @property
+ @abstractmethod
+ def stderr(self) -> ByteReceiveStream | None:
+ """The stream for the standard error output of the process."""
diff --git a/venv/Lib/site-packages/anyio/abc/_tasks.py b/venv/Lib/site-packages/anyio/abc/_tasks.py
new file mode 100644
index 0000000000000000000000000000000000000000..44ee3a70028b609e0c264b10ef5cee2127437fee
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/abc/_tasks.py
@@ -0,0 +1,209 @@
+from __future__ import annotations
+
+import sys
+from abc import ABCMeta, abstractmethod
+from collections.abc import Callable, Coroutine
+from contextvars import Context
+from types import TracebackType
+from typing import TYPE_CHECKING, Any, Literal, Protocol, final, overload
+
+if sys.version_info >= (3, 13):
+ from typing import TypeVar
+else:
+ from typing_extensions import TypeVar
+
+if sys.version_info >= (3, 11):
+ from typing import TypeVarTuple, Unpack
+else:
+ from typing_extensions import TypeVarTuple, Unpack
+
+if TYPE_CHECKING:
+ from .._core._tasks import CancelScope, TaskHandle
+
+T_co = TypeVar("T_co", covariant=True)
+T_contra = TypeVar("T_contra", contravariant=True, default=None)
+PosArgsT = TypeVarTuple("PosArgsT")
+
+
+def get_callable_name(func: Callable, override: object = None) -> str:
+ if override is not None:
+ return str(override)
+
+ module = getattr(func, "__module__", None)
+ qualname = getattr(func, "__qualname__", None)
+ return ".".join([x for x in (module, qualname) if x])
+
+
+def call_for_coroutine(
+ func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]],
+ args: tuple[Unpack[PosArgsT]],
+ **kwargs: Any,
+) -> Coroutine[Any, Any, T_co]:
+ """
+ Call the given function with the given positional and keyword arguments.
+
+ :return: the resulting coroutine
+ :raises TypeError: if the return value was not a coroutine object
+
+ """
+ coro = func(*args, **kwargs)
+ if not isinstance(coro, Coroutine):
+ prefix = f"{func.__module__}." if hasattr(func, "__module__") else ""
+ raise TypeError(
+ f"Expected {prefix}{func.__qualname__}() to return a coroutine, but "
+ f"the return value ({coro!r}) is not a coroutine object"
+ )
+
+ return coro
+
+
+class TaskStatus(Protocol[T_contra]):
+ @overload
+ def started(self: TaskStatus[None]) -> None: ...
+
+ @overload
+ def started(self, value: T_contra) -> None: ...
+
+ def started(self, value: T_contra | None = None) -> None:
+ """
+ Signal that the task has started.
+
+ :param value: object passed back to the starter of the task
+ """
+
+
+class TaskGroup(metaclass=ABCMeta):
+ """
+ Groups several asynchronous tasks together.
+
+ :ivar cancel_scope: the cancel scope inherited by all child tasks
+ :vartype cancel_scope: CancelScope
+
+ .. note:: On asyncio, support for eager task factories is considered to be
+ **experimental**. In particular, they don't follow the usual semantics of new
+ tasks being scheduled on the next iteration of the event loop, and may thus
+ cause unexpected behavior in code that wasn't written with such semantics in
+ mind.
+ """
+
+ cancel_scope: CancelScope
+
+ def cancel(self, reason: str | None = None) -> None:
+ """
+ Cancel this task group's cancel scope immediately.
+
+ This is a shortcut for calling ``.cancel_scope.cancel()`` on the task group.
+
+ :param reason: a message describing the reason for the cancellation
+
+ .. versionadded:: 4.14.0
+
+ """
+ self.cancel_scope.cancel(reason)
+
+ @abstractmethod
+ def create_task(
+ self,
+ coro: Coroutine[Any, Any, T_co],
+ *,
+ name: object = None,
+ context: Context | None = None,
+ ) -> TaskHandle[T_co]:
+ """
+ Create a new task from a coroutine object and schedule it to run.
+
+ :param coro: a coroutine object
+ :param name: optional name to give the task
+ :param context: optional context to run the task in
+ :return: a task handle
+
+ .. versionadded:: 4.14.0
+ """
+
+ @final
+ def start_soon(
+ self,
+ func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]],
+ *args: Unpack[PosArgsT],
+ name: object = None,
+ ) -> TaskHandle[T_co]:
+ """
+ Start a new task in this task group.
+
+ :param func: a coroutine function
+ :param args: positional arguments to call the function with
+ :param name: name of the task, for the purposes of introspection and debugging
+ :return: a task handle
+
+ .. versionadded:: 3.0
+ .. versionchanged:: 4.14.0
+ This method now returns a task handle.
+
+ """
+ final_name = get_callable_name(func, name)
+ return self.create_task(call_for_coroutine(func, args), name=final_name)
+
+ @overload
+ async def start(
+ self,
+ func: Callable[..., Coroutine[Any, Any, T_co]],
+ *args: object,
+ name: object = None,
+ return_handle: Literal[False] = ...,
+ ) -> Any: ...
+
+ @overload
+ async def start(
+ self,
+ func: Callable[..., Coroutine[Any, Any, T_co]],
+ *args: object,
+ name: object = None,
+ return_handle: Literal[True],
+ ) -> TaskHandle[T_co, Any]: ...
+
+ @abstractmethod
+ async def start(
+ self,
+ func: Callable[..., Coroutine[Any, Any, T_co]],
+ *args: object,
+ name: object = None,
+ return_handle: Literal[False] | Literal[True] = False,
+ ) -> Any:
+ """
+ Start a new task and wait until it signals for readiness.
+
+ The target callable must accept a keyword argument ``task_status`` (of type
+ :class:`TaskStatus`). Awaiting on this method will return whatever was passed to
+ ``task_status.started()`` (``None`` by default).
+
+ .. note:: The :class:`TaskStatus` class is generic, and the type argument should
+ indicate the type of the value that will be passed to
+ ``task_status.started()``.
+
+ :param func: a coroutine function that accepts the ``task_status`` keyword
+ argument
+ :param args: positional arguments to call the function with
+ :param name: an optional name for the task, for introspection and debugging
+ :param return_handle: if ``True``, return a :class:`TaskHandle` which also
+ contains the start value in ``start_value``
+ :return: the value passed to ``task_status.started()``
+ :raises RuntimeError: if the task finishes without calling
+ ``task_status.started()``
+
+ .. seealso:: :ref:`start_initialize`
+
+ .. versionadded:: 3.0
+ """
+
+ @abstractmethod
+ async def __aenter__(self) -> TaskGroup:
+ """Enter the task group context and allow starting new tasks."""
+
+ @abstractmethod
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> bool:
+ """Exit the task group context waiting for all tasks to finish."""
diff --git a/venv/Lib/site-packages/anyio/abc/_testing.py b/venv/Lib/site-packages/anyio/abc/_testing.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a93fb7cc31533f08f5be52c0528e10147aaac57
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/abc/_testing.py
@@ -0,0 +1,73 @@
+from __future__ import annotations
+
+import types
+from abc import ABCMeta, abstractmethod
+from collections.abc import AsyncGenerator, Callable, Coroutine, Iterable
+from typing import Any, TypeVar
+
+_T = TypeVar("_T")
+
+
+class TestRunner(metaclass=ABCMeta):
+ """
+ Encapsulates a running event loop. Every call made through this object will use the
+ same event loop.
+ """
+
+ def __enter__(self) -> TestRunner:
+ return self
+
+ @abstractmethod
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: types.TracebackType | None,
+ ) -> bool | None: ...
+
+ @abstractmethod
+ def run_asyncgen_fixture(
+ self,
+ fixture_func: Callable[..., AsyncGenerator[_T, Any]],
+ kwargs: dict[str, Any],
+ ) -> Iterable[_T]:
+ """
+ Run an async generator fixture.
+
+ :param fixture_func: the fixture function
+ :param kwargs: keyword arguments to call the fixture function with
+ :return: an iterator yielding the value yielded from the async generator
+ """
+
+ @abstractmethod
+ def run_fixture(
+ self,
+ fixture_func: Callable[..., Coroutine[Any, Any, _T]],
+ kwargs: dict[str, Any],
+ ) -> _T:
+ """
+ Run an async fixture.
+
+ :param fixture_func: the fixture function
+ :param kwargs: keyword arguments to call the fixture function with
+ :return: the return value of the fixture function
+ """
+
+ @abstractmethod
+ def run_test(
+ self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any]
+ ) -> None:
+ """
+ Run an async test function.
+
+ :param test_func: the test function
+ :param kwargs: keyword arguments to call the test function with
+ """
+
+ @abstractmethod
+ def is_running(self) -> bool:
+ """
+ Check if the test runner is running.
+
+ :return: ``True`` if the coroutine is currently being run, ``False`` otherwise.
+ """
diff --git a/venv/Lib/site-packages/anyio/from_thread.py b/venv/Lib/site-packages/anyio/from_thread.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c7914c2ffff281fd5a0f0273e7d7f5d8a35e459
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/from_thread.py
@@ -0,0 +1,582 @@
+from __future__ import annotations
+
+__all__ = (
+ "BlockingPortal",
+ "BlockingPortalProvider",
+ "check_cancelled",
+ "run",
+ "run_sync",
+ "start_blocking_portal",
+)
+
+import sys
+from collections.abc import Awaitable, Callable, Coroutine, Generator
+from concurrent.futures import Future
+from contextlib import (
+ AbstractAsyncContextManager,
+ AbstractContextManager,
+ contextmanager,
+)
+from dataclasses import dataclass, field
+from functools import partial
+from inspect import isawaitable
+from threading import Lock, Thread, current_thread, get_ident
+from types import TracebackType
+from typing import (
+ Any,
+ Generic,
+ TypeVar,
+ cast,
+ overload,
+)
+
+from ._core._eventloop import (
+ get_cancelled_exc_class,
+ threadlocals,
+)
+from ._core._eventloop import run as run_eventloop
+from ._core._exceptions import NoEventLoopError
+from ._core._synchronization import Event
+from ._core._tasks import CancelScope, create_task_group
+from .abc._tasks import TaskStatus
+from .lowlevel import EventLoopToken, current_token
+
+if sys.version_info >= (3, 11):
+ from typing import TypeVarTuple, Unpack
+else:
+ from typing_extensions import TypeVarTuple, Unpack
+
+T_Retval = TypeVar("T_Retval")
+T_co = TypeVar("T_co", covariant=True)
+PosArgsT = TypeVarTuple("PosArgsT")
+
+
+def _token_or_error(token: EventLoopToken | None) -> EventLoopToken:
+ if token is not None:
+ return token
+
+ try:
+ return threadlocals.current_token
+ except AttributeError:
+ raise NoEventLoopError(
+ "Not running inside an AnyIO worker thread, and no event loop token was "
+ "provided"
+ ) from None
+
+
+def run(
+ func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]],
+ *args: Unpack[PosArgsT],
+ token: EventLoopToken | None = None,
+) -> T_co:
+ """
+ Call a coroutine function from a worker thread.
+
+ :param func: a coroutine function
+ :param args: positional arguments for the callable
+ :param token: an event loop token to use to get back to the event loop thread
+ (required if calling this function from outside an AnyIO worker thread)
+ :return: the return value of the coroutine function
+ :raises MissingTokenError: if no token was provided and called from outside an
+ AnyIO worker thread
+ :raises RunFinishedError: if the event loop tied to ``token`` is no longer running
+
+ .. versionchanged:: 4.11.0
+ Added the ``token`` parameter.
+
+ """
+ explicit_token = token is not None
+ token = _token_or_error(token)
+ return token.backend_class.run_async_from_thread(
+ func, args, token=token.native_token if explicit_token else None
+ )
+
+
+def run_sync(
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
+ *args: Unpack[PosArgsT],
+ token: EventLoopToken | None = None,
+) -> T_Retval:
+ """
+ Call a function in the event loop thread from a worker thread.
+
+ :param func: a callable
+ :param args: positional arguments for the callable
+ :param token: an event loop token to use to get back to the event loop thread
+ (required if calling this function from outside an AnyIO worker thread)
+ :return: the return value of the callable
+ :raises MissingTokenError: if no token was provided and called from outside an
+ AnyIO worker thread
+ :raises RunFinishedError: if the event loop tied to ``token`` is no longer running
+
+ .. versionchanged:: 4.11.0
+ Added the ``token`` parameter.
+
+ """
+ explicit_token = token is not None
+ token = _token_or_error(token)
+ return token.backend_class.run_sync_from_thread(
+ func, args, token=token.native_token if explicit_token else None
+ )
+
+
+class _BlockingAsyncContextManager(Generic[T_co], AbstractContextManager):
+ _enter_future: Future[T_co]
+ _exit_future: Future[bool | None]
+ _exit_event: Event
+ _exit_exc_info: tuple[
+ type[BaseException] | None, BaseException | None, TracebackType | None
+ ] = (None, None, None)
+
+ def __init__(
+ self, async_cm: AbstractAsyncContextManager[T_co], portal: BlockingPortal
+ ):
+ self._async_cm = async_cm
+ self._portal = portal
+
+ async def run_async_cm(self) -> bool | None:
+ try:
+ self._exit_event = Event()
+ value = await self._async_cm.__aenter__()
+ except BaseException as exc:
+ self._enter_future.set_exception(exc)
+ raise
+ else:
+ self._enter_future.set_result(value)
+
+ try:
+ # Wait for the sync context manager to exit.
+ # This next statement can raise `get_cancelled_exc_class()` if
+ # something went wrong in a task group in this async context
+ # manager.
+ await self._exit_event.wait()
+ finally:
+ # In case of cancellation, it could be that we end up here before
+ # `_BlockingAsyncContextManager.__exit__` is called, and an
+ # `_exit_exc_info` has been set.
+ result = await self._async_cm.__aexit__(*self._exit_exc_info)
+
+ return result
+
+ def __enter__(self) -> T_co:
+ self._enter_future = Future()
+ self._exit_future = self._portal.start_task_soon(self.run_async_cm)
+ return self._enter_future.result()
+
+ def __exit__(
+ self,
+ __exc_type: type[BaseException] | None,
+ __exc_value: BaseException | None,
+ __traceback: TracebackType | None,
+ ) -> bool | None:
+ self._exit_exc_info = __exc_type, __exc_value, __traceback
+ self._portal.call(self._exit_event.set)
+ return self._exit_future.result()
+
+
+class _BlockingPortalTaskStatus(TaskStatus):
+ def __init__(self, future: Future):
+ self._future = future
+
+ def started(self, value: object = None) -> None:
+ self._future.set_result(value)
+
+
+class BlockingPortal:
+ """
+ An object that lets external threads run code in an asynchronous event loop.
+
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+ """
+
+ def __init__(self) -> None:
+ self._token = current_token()
+ self._event_loop_thread_id: int | None = get_ident()
+ self._stop_event = Event()
+ self._task_group = create_task_group()
+
+ async def __aenter__(self) -> BlockingPortal:
+ await self._task_group.__aenter__()
+ return self
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> bool:
+ await self.stop()
+ return await self._task_group.__aexit__(exc_type, exc_val, exc_tb)
+
+ def _check_running(self) -> None:
+ if self._event_loop_thread_id is None:
+ raise RuntimeError("This portal is not running")
+ if self._event_loop_thread_id == get_ident():
+ raise RuntimeError(
+ "This method cannot be called from the event loop thread"
+ )
+
+ async def sleep_until_stopped(self) -> None:
+ """Sleep until :meth:`stop` is called."""
+ await self._stop_event.wait()
+
+ async def stop(self, cancel_remaining: bool = False) -> None:
+ """
+ Signal the portal to shut down.
+
+ This marks the portal as no longer accepting new calls and exits from
+ :meth:`sleep_until_stopped`.
+
+ :param cancel_remaining: ``True`` to cancel all the remaining tasks, ``False``
+ to let them finish before returning
+
+ """
+ self._event_loop_thread_id = None
+ self._stop_event.set()
+ if cancel_remaining:
+ self._task_group.cancel_scope.cancel("the blocking portal is shutting down")
+
+ async def _call_func(
+ self,
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval],
+ args: tuple[Unpack[PosArgsT]],
+ kwargs: dict[str, Any],
+ future: Future[T_Retval],
+ ) -> None:
+ event_loop_thread_id = self._event_loop_thread_id
+
+ def callback(f: Future[T_Retval]) -> None:
+ if f.cancelled():
+ if event_loop_thread_id == get_ident():
+ scope.cancel("the future was cancelled")
+ elif event_loop_thread_id is not None:
+ run_sync(
+ scope.cancel, "the future was cancelled", token=self._token
+ )
+
+ try:
+ retval_or_awaitable = func(*args, **kwargs)
+ if isawaitable(retval_or_awaitable):
+ with CancelScope() as scope:
+ future.add_done_callback(callback)
+ retval = await retval_or_awaitable
+ else:
+ retval = retval_or_awaitable
+ except get_cancelled_exc_class():
+ future.cancel()
+ future.set_running_or_notify_cancel()
+ except BaseException as exc:
+ if not future.cancelled():
+ future.set_exception(exc)
+
+ # Let base exceptions fall through
+ if not isinstance(exc, Exception):
+ raise
+ else:
+ if not future.cancelled():
+ future.set_result(retval)
+ finally:
+ scope = None # type: ignore[assignment]
+
+ def _spawn_task_from_thread(
+ self,
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval],
+ args: tuple[Unpack[PosArgsT]],
+ kwargs: dict[str, Any],
+ name: object,
+ future: Future[T_Retval],
+ ) -> None:
+ """
+ Spawn a new task using the given callable.
+
+ :param func: a callable
+ :param args: positional arguments to be passed to the callable
+ :param kwargs: keyword arguments to be passed to the callable
+ :param name: name of the task (will be coerced to a string if not ``None``)
+ :param future: a future that will resolve to the return value of the callable,
+ or the exception raised during its execution
+
+ """
+ run_sync(
+ partial(self._task_group.start_soon, name=name),
+ self._call_func,
+ func,
+ args,
+ kwargs,
+ future,
+ token=self._token,
+ )
+
+ @overload
+ def call(
+ self,
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+ *args: Unpack[PosArgsT],
+ ) -> T_Retval: ...
+
+ @overload
+ def call(
+ self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT]
+ ) -> T_Retval: ...
+
+ def call(
+ self,
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval],
+ *args: Unpack[PosArgsT],
+ ) -> T_Retval:
+ """
+ Call the given function in the event loop thread.
+
+ If the callable returns a coroutine object, it is awaited on.
+
+ :param func: any callable
+ :raises RuntimeError: if the portal is not running or if this method is called
+ from within the event loop thread
+
+ """
+ return cast(T_Retval, self.start_task_soon(func, *args).result())
+
+ @overload
+ def start_task_soon(
+ self,
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+ *args: Unpack[PosArgsT],
+ name: object = None,
+ ) -> Future[T_Retval]: ...
+
+ @overload
+ def start_task_soon(
+ self,
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
+ *args: Unpack[PosArgsT],
+ name: object = None,
+ ) -> Future[T_Retval]: ...
+
+ def start_task_soon(
+ self,
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval],
+ *args: Unpack[PosArgsT],
+ name: object = None,
+ ) -> Future[T_Retval]:
+ """
+ Start a task in the portal's task group.
+
+ The task will be run inside a cancel scope which can be cancelled by cancelling
+ the returned future.
+
+ :param func: the target function
+ :param args: positional arguments passed to ``func``
+ :param name: name of the task (will be coerced to a string if not ``None``)
+ :return: a future that resolves with the return value of the callable if the
+ task completes successfully, or with the exception raised in the task
+ :raises RuntimeError: if the portal is not running or if this method is called
+ from within the event loop thread
+ :rtype: concurrent.futures.Future[T_Retval]
+
+ .. versionadded:: 3.0
+
+ """
+ self._check_running()
+ f: Future[T_Retval] = Future()
+ self._spawn_task_from_thread(func, args, {}, name, f)
+ return f
+
+ def start_task(
+ self,
+ func: Callable[..., Awaitable[T_Retval]],
+ *args: object,
+ name: object = None,
+ ) -> tuple[Future[T_Retval], Any]:
+ """
+ Start a task in the portal's task group and wait until it signals for readiness.
+
+ This method works the same way as :meth:`.abc.TaskGroup.start`.
+
+ :param func: the target function
+ :param args: positional arguments passed to ``func``
+ :param name: name of the task (will be coerced to a string if not ``None``)
+ :return: a tuple of (future, task_status_value) where the ``task_status_value``
+ is the value passed to ``task_status.started()`` from within the target
+ function
+ :rtype: tuple[concurrent.futures.Future[T_Retval], Any]
+
+ .. versionadded:: 3.0
+
+ """
+
+ def task_done(future: Future[T_Retval]) -> None:
+ if not task_status_future.done():
+ if future.cancelled():
+ task_status_future.cancel()
+ elif future.exception():
+ task_status_future.set_exception(future.exception())
+ else:
+ exc = RuntimeError(
+ "Task exited without calling task_status.started()"
+ )
+ task_status_future.set_exception(exc)
+
+ self._check_running()
+ task_status_future: Future = Future()
+ task_status = _BlockingPortalTaskStatus(task_status_future)
+ f: Future = Future()
+ f.add_done_callback(task_done)
+ self._spawn_task_from_thread(func, args, {"task_status": task_status}, name, f)
+ return f, task_status_future.result()
+
+ def wrap_async_context_manager(
+ self, cm: AbstractAsyncContextManager[T_co]
+ ) -> AbstractContextManager[T_co]:
+ """
+ Wrap an async context manager as a synchronous context manager via this portal.
+
+ Spawns a task that will call both ``__aenter__()`` and ``__aexit__()``, stopping
+ in the middle until the synchronous context manager exits.
+
+ :param cm: an asynchronous context manager
+ :return: a synchronous context manager
+
+ .. versionadded:: 2.1
+
+ """
+ return _BlockingAsyncContextManager(cm, self)
+
+
+@dataclass
+class BlockingPortalProvider:
+ """
+ A manager for a blocking portal. Used as a context manager. The first thread to
+ enter this context manager causes a blocking portal to be started with the specific
+ parameters, and the last thread to exit causes the portal to be shut down. Thus,
+ there will be exactly one blocking portal running in this context as long as at
+ least one thread has entered this context manager.
+
+ The parameters are the same as for :func:`~anyio.run`.
+
+ :param backend: name of the backend
+ :param backend_options: backend options
+
+ .. versionadded:: 4.4
+ """
+
+ backend: str = "asyncio"
+ backend_options: dict[str, Any] | None = None
+ _lock: Lock = field(init=False, default_factory=Lock)
+ _leases: int = field(init=False, default=0)
+ _portal: BlockingPortal = field(init=False)
+ _portal_cm: AbstractContextManager[BlockingPortal] | None = field(
+ init=False, default=None
+ )
+
+ def __enter__(self) -> BlockingPortal:
+ with self._lock:
+ if self._portal_cm is None:
+ self._portal_cm = start_blocking_portal(
+ self.backend, self.backend_options
+ )
+ self._portal = self._portal_cm.__enter__()
+
+ self._leases += 1
+ return self._portal
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ portal_cm: AbstractContextManager[BlockingPortal] | None = None
+ with self._lock:
+ assert self._portal_cm
+ assert self._leases > 0
+ self._leases -= 1
+ if not self._leases:
+ portal_cm = self._portal_cm
+ self._portal_cm = None
+ del self._portal
+
+ if portal_cm:
+ portal_cm.__exit__(None, None, None)
+
+
+@contextmanager
+def start_blocking_portal(
+ backend: str = "asyncio",
+ backend_options: dict[str, Any] | None = None,
+ *,
+ name: str | None = None,
+) -> Generator[BlockingPortal, Any, None]:
+ """
+ Start a new event loop in a new thread and run a blocking portal in its main task.
+
+ The parameters are the same as for :func:`~anyio.run`.
+
+ :param backend: name of the backend
+ :param backend_options: backend options
+ :param name: name of the thread
+ :return: a context manager that yields a blocking portal
+
+ .. versionchanged:: 3.0
+ Usage as a context manager is now required.
+
+ """
+
+ async def run_portal() -> None:
+ async with BlockingPortal() as portal_:
+ if name is None:
+ current_thread().name = f"{backend}-portal-{id(portal_):x}"
+
+ future.set_result(portal_)
+ await portal_.sleep_until_stopped()
+
+ def run_blocking_portal() -> None:
+ if future.set_running_or_notify_cancel():
+ try:
+ run_eventloop(
+ run_portal, backend=backend, backend_options=backend_options
+ )
+ except BaseException as exc:
+ if not future.done():
+ future.set_exception(exc)
+
+ future: Future[BlockingPortal] = Future()
+ thread = Thread(target=run_blocking_portal, daemon=True, name=name)
+ thread.start()
+ try:
+ cancel_remaining_tasks = False
+ portal = future.result()
+ try:
+ yield portal
+ except BaseException:
+ cancel_remaining_tasks = True
+ raise
+ finally:
+ try:
+ portal.call(portal.stop, cancel_remaining_tasks)
+ except RuntimeError:
+ pass
+ finally:
+ thread.join()
+
+
+def check_cancelled() -> None:
+ """
+ Check if the cancel scope of the host task's running the current worker thread has
+ been cancelled.
+
+ If the host task's current cancel scope has indeed been cancelled, the
+ backend-specific cancellation exception will be raised.
+
+ :raises RuntimeError: if the current thread was not spawned by
+ :func:`.to_thread.run_sync`
+
+ """
+ try:
+ token: EventLoopToken = threadlocals.current_token
+ except AttributeError:
+ raise NoEventLoopError(
+ "This function can only be called inside an AnyIO worker thread"
+ ) from None
+
+ token.backend_class.check_cancelled()
diff --git a/venv/Lib/site-packages/anyio/functools.py b/venv/Lib/site-packages/anyio/functools.py
new file mode 100644
index 0000000000000000000000000000000000000000..b0bdfb4585efc4e4799388547668fba86fb5c687
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/functools.py
@@ -0,0 +1,400 @@
+from __future__ import annotations
+
+__all__ = (
+ "AsyncCacheInfo",
+ "AsyncCacheParameters",
+ "AsyncLRUCacheWrapper",
+ "cache",
+ "lru_cache",
+ "reduce",
+)
+
+import functools
+from collections import OrderedDict
+from collections.abc import (
+ AsyncIterable,
+ Awaitable,
+ Callable,
+ Coroutine,
+ Hashable,
+ Iterable,
+)
+from functools import update_wrapper
+from inspect import iscoroutinefunction
+from typing import (
+ Any,
+ Generic,
+ NamedTuple,
+ ParamSpec,
+ TypedDict,
+ TypeVar,
+ cast,
+ final,
+ overload,
+)
+from weakref import WeakKeyDictionary
+
+from ._core._eventloop import current_time
+from ._core._synchronization import Lock
+from .lowlevel import RunVar, checkpoint
+
+T = TypeVar("T")
+S = TypeVar("S")
+P = ParamSpec("P")
+lru_cache_items: RunVar[
+ WeakKeyDictionary[
+ AsyncLRUCacheWrapper[Any, Any],
+ OrderedDict[
+ Hashable,
+ tuple[_InitialMissingType, Lock, float | None]
+ | tuple[Any, None, float | None],
+ ],
+ ]
+] = RunVar("lru_cache_items")
+
+
+class _InitialMissingType:
+ pass
+
+
+initial_missing: _InitialMissingType = _InitialMissingType()
+
+
+class AsyncCacheInfo(NamedTuple):
+ hits: int
+ misses: int
+ maxsize: int | None
+ currsize: int
+ ttl: int | None
+
+
+class AsyncCacheParameters(TypedDict):
+ maxsize: int | None
+ typed: bool
+ always_checkpoint: bool
+ ttl: int | None
+
+
+class _LRUMethodWrapper(Generic[T]):
+ def __init__(self, wrapper: AsyncLRUCacheWrapper[..., T], instance: object):
+ self.__wrapper = wrapper
+ self.__instance = instance
+
+ def cache_info(self) -> AsyncCacheInfo:
+ return self.__wrapper.cache_info()
+
+ def cache_parameters(self) -> AsyncCacheParameters:
+ return self.__wrapper.cache_parameters()
+
+ def cache_clear(self) -> None:
+ self.__wrapper.cache_clear()
+
+ async def __call__(self, *args: Any, **kwargs: Any) -> T:
+ if self.__instance is None:
+ return await self.__wrapper(*args, **kwargs)
+
+ return await self.__wrapper(self.__instance, *args, **kwargs)
+
+
+@final
+class AsyncLRUCacheWrapper(Generic[P, T]):
+ def __init__(
+ self,
+ func: Callable[P, Awaitable[T]],
+ maxsize: int | None,
+ typed: bool,
+ always_checkpoint: bool,
+ ttl: int | None,
+ ):
+ self.__wrapped__ = func
+ self._hits: int = 0
+ self._misses: int = 0
+ self._maxsize = max(maxsize, 0) if maxsize is not None else None
+ self._currsize: int = 0
+ self._typed = typed
+ self._always_checkpoint = always_checkpoint
+ self._ttl = ttl
+ update_wrapper(self, func)
+
+ def cache_info(self) -> AsyncCacheInfo:
+ return AsyncCacheInfo(
+ self._hits, self._misses, self._maxsize, self._currsize, self._ttl
+ )
+
+ def cache_parameters(self) -> AsyncCacheParameters:
+ return {
+ "maxsize": self._maxsize,
+ "typed": self._typed,
+ "always_checkpoint": self._always_checkpoint,
+ "ttl": self._ttl,
+ }
+
+ def cache_clear(self) -> None:
+ if cache := lru_cache_items.get(None):
+ cache.pop(self, None)
+ self._hits = self._misses = self._currsize = 0
+
+ async def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
+ # Easy case first: if maxsize == 0, no caching is done
+ if self._maxsize == 0:
+ value = await self.__wrapped__(*args, **kwargs)
+ self._misses += 1
+ return value
+
+ # The key is constructed as a flat tuple to avoid memory overhead
+ key: tuple[Any, ...] = args
+ if kwargs:
+ # initial_missing is used as a separator
+ key += (initial_missing,) + sum(kwargs.items(), ())
+
+ if self._typed:
+ key += tuple(type(arg) for arg in args)
+ if kwargs:
+ key += (initial_missing,) + tuple(type(val) for val in kwargs.values())
+
+ try:
+ cache = lru_cache_items.get()
+ except LookupError:
+ cache = WeakKeyDictionary()
+ lru_cache_items.set(cache)
+
+ try:
+ cache_entry = cache[self]
+ except KeyError:
+ cache_entry = cache[self] = OrderedDict()
+
+ cached_value: T | _InitialMissingType
+ try:
+ cached_value, lock, expires_at = cache_entry[key]
+ except KeyError:
+ # We're the first task to call this function
+ cached_value, lock, expires_at = (
+ initial_missing,
+ Lock(fast_acquire=not self._always_checkpoint),
+ None,
+ )
+ cache_entry[key] = cached_value, lock, expires_at
+
+ if lock is None:
+ if expires_at is not None and current_time() >= expires_at:
+ self._currsize -= 1
+ cached_value, lock, expires_at = (
+ initial_missing,
+ Lock(fast_acquire=not self._always_checkpoint),
+ None,
+ )
+ cache_entry[key] = cached_value, lock, expires_at
+ else:
+ # The value was already cached
+ self._hits += 1
+ cache_entry.move_to_end(key)
+ if self._always_checkpoint:
+ await checkpoint()
+
+ return cast(T, cached_value)
+
+ async with lock:
+ # Check if another task filled the cache while we acquired the lock
+ if (cached_value := cache_entry[key][0]) is initial_missing:
+ self._misses += 1
+ if self._maxsize is not None and self._currsize >= self._maxsize:
+ cache_entry.popitem(last=False)
+ else:
+ self._currsize += 1
+
+ value = await self.__wrapped__(*args, **kwargs)
+ expires_at = (
+ current_time() + self._ttl if self._ttl is not None else None
+ )
+ cache_entry[key] = value, None, expires_at
+ else:
+ # Another task filled the cache while we were waiting for the lock
+ self._hits += 1
+ cache_entry.move_to_end(key)
+ value = cast(T, cached_value)
+
+ return value
+
+ def __get__(
+ self, instance: object, owner: type | None = None
+ ) -> _LRUMethodWrapper[T]:
+ wrapper = _LRUMethodWrapper(self, instance)
+ update_wrapper(wrapper, self.__wrapped__)
+ return wrapper
+
+
+class _LRUCacheWrapper:
+ def __init__(
+ self, maxsize: int | None, typed: bool, always_checkpoint: bool, ttl: int | None
+ ):
+ self._maxsize = maxsize
+ self._typed = typed
+ self._always_checkpoint = always_checkpoint
+ self._ttl = ttl
+
+ @overload
+ def __call__( # type: ignore[overload-overlap]
+ self, func: Callable[P, Coroutine[Any, Any, T]], /
+ ) -> AsyncLRUCacheWrapper[P, T]: ...
+
+ @overload
+ def __call__(
+ self, func: Callable[..., T], /
+ ) -> functools._lru_cache_wrapper[T]: ...
+
+ def __call__(
+ self, f: Callable[P, Coroutine[Any, Any, T]] | Callable[..., T], /
+ ) -> AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T]:
+ if iscoroutinefunction(f):
+ return AsyncLRUCacheWrapper(
+ f, self._maxsize, self._typed, self._always_checkpoint, self._ttl
+ )
+
+ return functools.lru_cache(maxsize=self._maxsize, typed=self._typed)(f) # type: ignore[arg-type]
+
+
+@overload
+def cache( # type: ignore[overload-overlap]
+ func: Callable[P, Coroutine[Any, Any, T]], /
+) -> AsyncLRUCacheWrapper[P, T]: ...
+
+
+@overload
+def cache(func: Callable[..., T], /) -> functools._lru_cache_wrapper[T]: ...
+
+
+def cache(func: Callable[..., Any] | Callable[P, Coroutine[Any, Any, Any]], /) -> Any:
+ """
+ A convenient shortcut for :func:`lru_cache` with ``maxsize=None``.
+
+ This is the asynchronous equivalent to :func:`functools.cache`.
+
+ """
+ return lru_cache(maxsize=None)(func)
+
+
+@overload
+def lru_cache(
+ *,
+ maxsize: int | None = ...,
+ typed: bool = ...,
+ always_checkpoint: bool = ...,
+ ttl: int | None = ...,
+) -> _LRUCacheWrapper: ...
+
+
+@overload
+def lru_cache( # type: ignore[overload-overlap]
+ func: Callable[P, Coroutine[Any, Any, T]], /
+) -> AsyncLRUCacheWrapper[P, T]: ...
+
+
+@overload
+def lru_cache(func: Callable[..., T], /) -> functools._lru_cache_wrapper[T]: ...
+
+
+def lru_cache(
+ func: Callable[..., Coroutine[Any, Any, Any]] | Callable[..., Any] | None = None,
+ /,
+ *,
+ maxsize: int | None = 128,
+ typed: bool = False,
+ always_checkpoint: bool = False,
+ ttl: int | None = None,
+) -> Any:
+ """
+ An asynchronous version of :func:`functools.lru_cache`.
+
+ If a synchronous function is passed, the standard library
+ :func:`functools.lru_cache` is applied instead.
+
+ :param always_checkpoint: if ``True``, every call to the cached function will be
+ guaranteed to yield control to the event loop at least once
+ :param ttl: time in seconds after which to invalidate cache entries
+
+ .. note:: Caches and locks are managed on a per-event loop basis.
+
+ """
+ if func is None:
+ return _LRUCacheWrapper(maxsize, typed, always_checkpoint, ttl)
+
+ if not callable(func):
+ raise TypeError("the first argument must be callable")
+
+ return _LRUCacheWrapper(maxsize, typed, always_checkpoint, ttl)(func)
+
+
+@overload
+async def reduce(
+ function: Callable[[T, S], Awaitable[T]],
+ iterable: Iterable[S] | AsyncIterable[S],
+ /,
+ initial: T,
+) -> T: ...
+
+
+@overload
+async def reduce(
+ function: Callable[[T, T], Awaitable[T]],
+ iterable: Iterable[T] | AsyncIterable[T],
+ /,
+) -> T: ...
+
+
+async def reduce( # type: ignore[misc]
+ function: Callable[[T, T], Awaitable[T]] | Callable[[T, S], Awaitable[T]],
+ iterable: Iterable[T] | Iterable[S] | AsyncIterable[T] | AsyncIterable[S],
+ /,
+ initial: T | _InitialMissingType = initial_missing,
+) -> T:
+ """
+ Asynchronous version of :func:`functools.reduce`.
+
+ :param function: a coroutine function that takes two arguments: the accumulated
+ value and the next element from the iterable
+ :param iterable: an iterable or async iterable
+ :param initial: the initial value (if missing, the first element of the iterable is
+ used as the initial value)
+
+ """
+ element: Any
+ function_called = False
+ if isinstance(iterable, AsyncIterable):
+ async_it = iterable.__aiter__()
+ if initial is initial_missing:
+ try:
+ value = cast(T, await async_it.__anext__())
+ except StopAsyncIteration:
+ raise TypeError(
+ "reduce() of empty sequence with no initial value"
+ ) from None
+ else:
+ value = cast(T, initial)
+
+ async for element in async_it:
+ value = await function(value, element)
+ function_called = True
+ elif isinstance(iterable, Iterable):
+ it = iter(iterable)
+ if initial is initial_missing:
+ try:
+ value = cast(T, next(it))
+ except StopIteration:
+ raise TypeError(
+ "reduce() of empty sequence with no initial value"
+ ) from None
+ else:
+ value = cast(T, initial)
+
+ for element in it:
+ value = await function(value, element)
+ function_called = True
+ else:
+ raise TypeError("reduce() argument 2 must be an iterable or async iterable")
+
+ # Make sure there is at least one checkpoint, even if an empty iterable and an
+ # initial value were given
+ if not function_called:
+ await checkpoint()
+
+ return value
diff --git a/venv/Lib/site-packages/anyio/itertools.py b/venv/Lib/site-packages/anyio/itertools.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e5248e4b8f99556cdbb98b024a188d65cdfce83
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/itertools.py
@@ -0,0 +1,626 @@
+from __future__ import annotations
+
+__all__ = (
+ "accumulate",
+ "batched",
+ "Chain",
+ "combinations",
+ "combinations_with_replacement",
+ "compress",
+ "count",
+ "cycle",
+ "dropwhile",
+ "filterfalse",
+ "groupby",
+ "islice",
+ "pairwise",
+ "permutations",
+ "product",
+ "repeat",
+ "starmap",
+ "tee",
+ "takewhile",
+ "zip_longest",
+)
+
+import itertools
+import operator
+import sys
+from collections.abc import (
+ AsyncGenerator,
+ AsyncIterable,
+ AsyncIterator,
+ Awaitable,
+ Callable,
+ Iterable,
+ Iterator,
+)
+from dataclasses import dataclass, field
+from typing import Any, Generic, TypeVar, cast, overload
+
+from ._core._synchronization import Lock
+from ._core._tasks import CancelScope
+from .lowlevel import cancel_shielded_checkpoint, checkpoint, checkpoint_if_cancelled
+
+T = TypeVar("T")
+R = TypeVar("R")
+_tee_end = object()
+
+
+@dataclass(eq=False)
+class _IterableAsyncIterator(AsyncIterator[T]):
+ iterator: Iterator[T]
+
+ async def __anext__(self) -> T:
+ await checkpoint_if_cancelled()
+ try:
+ result = next(self.iterator)
+ except StopIteration:
+ await cancel_shielded_checkpoint()
+ raise StopAsyncIteration from None
+
+ await cancel_shielded_checkpoint()
+ return result
+
+
+def _iterate(iterable: Iterable[T] | AsyncIterable[T]) -> AsyncIterator[T]:
+ if isinstance(iterable, AsyncIterator):
+ return iterable
+
+ if isinstance(iterable, AsyncIterable):
+ return iterable.__aiter__()
+
+ return _IterableAsyncIterator(iter(iterable))
+
+
+@dataclass(eq=False)
+class _TeeLink(Generic[T]):
+ value: object | None = None
+ next: _TeeLink[T] | None = None
+ filled: bool = False
+
+
+@dataclass(eq=False)
+class _TeeState(Generic[T]):
+ iterator: AsyncIterator[T]
+ lock: Lock = field(default_factory=Lock)
+
+ async def fill(self, link: _TeeLink[T]) -> bool:
+ if link.filled:
+ return False
+
+ async with self.lock:
+ if link.filled:
+ return True
+
+ link.value = await anext(self.iterator, _tee_end)
+ if link.value is not _tee_end:
+ link.next = _TeeLink()
+
+ link.filled = True
+ return True
+
+
+class _TeeAsyncIterator(AsyncIterator[T]):
+ _state: _TeeState[T]
+ _link: _TeeLink[T]
+ _element_yielded: bool
+
+ def __init__(
+ self, iterable: Iterable[T] | AsyncIterable[T] | _TeeAsyncIterator[T]
+ ) -> None:
+ if isinstance(iterable, _TeeAsyncIterator):
+ self._state = iterable._state
+ self._link = iterable._link
+ else:
+ self._state = _TeeState(_iterate(iterable))
+ self._link = _TeeLink()
+
+ self._element_yielded = False
+
+ async def __anext__(self) -> T:
+ had_yieldpoint = await self._state.fill(self._link)
+ if self._link.value is _tee_end:
+ if not self._element_yielded:
+ await checkpoint()
+
+ raise StopAsyncIteration
+
+ if not had_yieldpoint:
+ await checkpoint_if_cancelled()
+
+ self._element_yielded = True
+ value = cast(T, self._link.value)
+ next_link = self._link.next
+ assert next_link is not None
+ self._link = next_link
+ if not had_yieldpoint:
+ await cancel_shielded_checkpoint()
+
+ return value
+
+
+async def _operator_add(x: T, y: T) -> T:
+ return operator.add(x, y)
+
+
+async def accumulate(
+ iterable: Iterable[T] | AsyncIterable[T],
+ function: Callable[[T, T], Awaitable[T]] = _operator_add,
+ *,
+ initial: T | None = None,
+) -> AsyncGenerator[T, None]:
+ iterator = _iterate(iterable)
+ if initial is None:
+ try:
+ total = await anext(iterator)
+ except StopAsyncIteration:
+ await checkpoint()
+ return
+ else:
+ await checkpoint_if_cancelled()
+ total = initial
+ await cancel_shielded_checkpoint()
+
+ yield total
+
+ async for element in iterator:
+ total = await function(total, element)
+ yield total
+
+
+async def batched(
+ iterable: Iterable[T] | AsyncIterable[T], n: int, *, strict: bool = False
+) -> AsyncGenerator[tuple[T, ...], None]:
+ if n < 1:
+ raise ValueError("n must be at least one")
+
+ iterator = _iterate(iterable)
+
+ while True:
+ batch: list[T] = []
+ for _ in range(n):
+ try:
+ batch.append(await anext(iterator))
+ except StopAsyncIteration:
+ if not batch:
+ await checkpoint()
+ return
+ if strict:
+ raise ValueError("batched(): incomplete batch") from None
+
+ yield tuple(batch)
+ return
+
+ yield tuple(batch)
+
+
+class Chain:
+ def __call__(
+ self, *iterables: Iterable[T] | AsyncIterable[T]
+ ) -> AsyncGenerator[T, None]:
+ return self.from_iterable(iterables)
+
+ async def from_iterable(
+ self,
+ iterables: (
+ Iterable[Iterable[T] | AsyncIterable[T]]
+ | AsyncIterable[Iterable[T] | AsyncIterable[T]]
+ ),
+ ) -> AsyncGenerator[T, None]:
+ element_yielded = False
+ outer_iter = _iterate(iterables)
+
+ try:
+ async for iterable in outer_iter:
+ async for element in _iterate(iterable):
+ element_yielded = True
+ yield element
+ finally:
+ aclose = getattr(outer_iter, "aclose", None)
+ if aclose is not None:
+ with CancelScope(shield=True):
+ await aclose()
+
+ if not element_yielded:
+ await checkpoint()
+
+
+chain: Chain = Chain()
+
+
+async def combinations(
+ iterable: Iterable[T] | AsyncIterable[T], r: int
+) -> AsyncGenerator[tuple[T, ...], None]:
+ pool: list[T] = [element async for element in _iterate(iterable)]
+ async for combination in _iterate(itertools.combinations(pool, r)):
+ yield combination
+
+
+async def combinations_with_replacement(
+ iterable: Iterable[T] | AsyncIterable[T], r: int
+) -> AsyncGenerator[tuple[T, ...], None]:
+ pool: list[T] = [element async for element in _iterate(iterable)]
+ async for combination in _iterate(itertools.combinations_with_replacement(pool, r)):
+ yield combination
+
+
+async def compress(
+ data: Iterable[T] | AsyncIterable[T],
+ selectors: Iterable[object] | AsyncIterable[object],
+) -> AsyncGenerator[T, None]:
+ data_iterator = _iterate(data)
+ selector_iterator = _iterate(selectors)
+ element_yielded = False
+
+ while True:
+ try:
+ datum = await anext(data_iterator)
+ selector = await anext(selector_iterator)
+ except StopAsyncIteration:
+ if not element_yielded:
+ await checkpoint()
+
+ return
+
+ if selector:
+ element_yielded = True
+ yield datum
+
+
+async def count(start: int = 0, step: int = 1) -> AsyncGenerator[int, None]:
+ n = start
+ while True:
+ await checkpoint_if_cancelled()
+ value = n
+ n += step
+ await cancel_shielded_checkpoint()
+ yield value
+
+
+async def cycle(
+ iterable: Iterable[T] | AsyncIterable[T],
+) -> AsyncGenerator[T, None]:
+ saved: list[T] = []
+ async for element in _iterate(iterable):
+ saved.append(element)
+ yield element
+
+ if not saved:
+ await checkpoint()
+ return
+
+ while True:
+ for element in saved:
+ await checkpoint()
+ yield element
+
+
+async def dropwhile(
+ predicate: Callable[[T], Awaitable[object]],
+ iterable: Iterable[T] | AsyncIterable[T],
+) -> AsyncGenerator[T, None]:
+ element_yielded = False
+ dropping = True
+
+ async for element in _iterate(iterable):
+ if dropping and await predicate(element):
+ continue
+
+ dropping = False
+ element_yielded = True
+ yield element
+
+ if not element_yielded:
+ await checkpoint()
+
+
+async def filterfalse(
+ predicate: Callable[[T], Awaitable[object]],
+ iterable: Iterable[T] | AsyncIterable[T],
+) -> AsyncGenerator[T, None]:
+ element_yielded = False
+
+ async for element in _iterate(iterable):
+ if not await predicate(element):
+ element_yielded = True
+ yield element
+
+ if not element_yielded:
+ await checkpoint()
+
+
+@overload
+def groupby(
+ iterable: Iterable[T] | AsyncIterable[T],
+) -> AsyncGenerator[tuple[T, list[T]], None]: ...
+
+
+@overload
+def groupby(
+ iterable: Iterable[T] | AsyncIterable[T],
+ key: Callable[[T], Awaitable[R]],
+) -> AsyncGenerator[tuple[R, list[T]], None]: ...
+
+
+async def groupby(
+ iterable: Iterable[T] | AsyncIterable[T],
+ key: Callable[[T], Awaitable[object]] | None = None,
+) -> AsyncGenerator[tuple[object, list[T]], None]:
+ iterator = _iterate(iterable)
+ try:
+ element = await anext(iterator)
+ except StopAsyncIteration:
+ await checkpoint()
+ return
+
+ group_key = element if key is None else await key(element)
+ values = [element]
+
+ async for element in iterator:
+ next_key = element if key is None else await key(element)
+ if next_key != group_key:
+ completed_group = group_key, values
+ group_key = next_key
+ values = [element]
+ yield completed_group
+ else:
+ values.append(element)
+
+ yield group_key, values
+
+
+@overload
+def islice(
+ iterable: Iterable[T] | AsyncIterable[T],
+ stop: int | None,
+ /,
+) -> AsyncGenerator[T, None]: ...
+
+
+@overload
+def islice(
+ iterable: Iterable[T] | AsyncIterable[T],
+ start: int | None,
+ stop: int | None,
+ step: int | None = 1,
+ /,
+) -> AsyncGenerator[T, None]: ...
+
+
+async def islice(
+ iterable: Iterable[T] | AsyncIterable[T],
+ *args: int | None,
+) -> AsyncGenerator[T, None]:
+ if not args:
+ raise TypeError("islice expected at least 2 arguments, got 1")
+ if len(args) > 3:
+ raise TypeError(f"islice expected at most 4 arguments, got {len(args) + 1}")
+
+ slice_args = slice(*args)
+
+ start_message = (
+ "Indices for islice() must be None or an integer: 0 <= x <= sys.maxsize."
+ )
+ stop_message = (
+ "Stop argument for islice() must be None or an integer: 0 <= x <= sys.maxsize."
+ )
+ step_message = "Step for islice() must be a positive integer or None."
+
+ def normalize_index(value: object, message: str) -> int:
+ try:
+ index = operator.index(cast(Any, value))
+ except TypeError:
+ raise ValueError(message) from None
+
+ if index < 0 or index > sys.maxsize:
+ raise ValueError(message)
+
+ return index
+
+ start = (
+ 0
+ if slice_args.start is None
+ else normalize_index(slice_args.start, start_message)
+ )
+ stop = (
+ None
+ if slice_args.stop is None
+ else normalize_index(slice_args.stop, stop_message)
+ )
+ step = (
+ 1 if slice_args.step is None else normalize_index(slice_args.step, step_message)
+ )
+
+ if step <= 0:
+ raise ValueError(step_message)
+
+ if stop == 0 or start == stop:
+ await checkpoint()
+ return
+
+ iterator = _iterate(iterable)
+ index = 0
+ element_yielded = False
+
+ while stop is None or index < stop:
+ try:
+ element = await anext(iterator)
+ except StopAsyncIteration:
+ if not element_yielded:
+ await checkpoint()
+
+ return
+
+ if index >= start and (index - start) % step == 0:
+ index += 1
+ element_yielded = True
+ yield element
+ else:
+ index += 1
+
+ if not element_yielded:
+ await checkpoint()
+
+
+async def pairwise(
+ iterable: Iterable[T] | AsyncIterable[T],
+) -> AsyncGenerator[tuple[T, T], None]:
+ iterator = _iterate(iterable)
+ try:
+ previous = await anext(iterator)
+ except StopAsyncIteration:
+ await checkpoint()
+ return
+
+ element_yielded = False
+ async for element in iterator:
+ element_yielded = True
+ pair = (previous, element)
+ previous = element
+ yield pair
+
+ if not element_yielded:
+ await checkpoint()
+
+
+async def permutations(
+ iterable: Iterable[T] | AsyncIterable[T], r: int | None = None
+) -> AsyncGenerator[tuple[T, ...], None]:
+ pool: list[T] = [element async for element in _iterate(iterable)]
+ n = len(pool)
+ if r is None:
+ r = n
+ elif not isinstance(r, int):
+ raise TypeError("Expected int as r")
+ elif r < 0:
+ raise ValueError("r must be non-negative")
+
+ async for permutation in _iterate(itertools.permutations(pool, r)):
+ yield permutation
+
+
+async def product(
+ *iterables: Iterable[T] | AsyncIterable[T], repeat: int = 1
+) -> AsyncGenerator[tuple[T, ...], None]:
+ repeat = operator.index(repeat)
+ if repeat < 0:
+ raise ValueError("repeat argument cannot be negative")
+
+ pools: list[tuple[T, ...]] = []
+ for iterable in iterables:
+ pool: list[T] = [element async for element in _iterate(iterable)]
+ pools.append(tuple(pool))
+
+ async for value in _iterate(itertools.product(*pools, repeat=repeat)):
+ yield value
+
+
+async def repeat(element: T, times: int | None = None) -> AsyncGenerator[T, None]:
+ if times is None:
+ while True:
+ await checkpoint()
+ yield element
+
+ remaining = operator.index(cast(Any, times))
+ if remaining <= 0:
+ await checkpoint()
+ return
+
+ while remaining > 0:
+ await checkpoint_if_cancelled()
+ remaining -= 1
+ await cancel_shielded_checkpoint()
+ yield element
+
+
+async def starmap(
+ function: Callable[..., Awaitable[R]],
+ iterable: (
+ Iterable[Iterable[object] | AsyncIterable[object]]
+ | AsyncIterable[Iterable[object] | AsyncIterable[object]]
+ ),
+) -> AsyncGenerator[R, None]:
+ result_yielded = False
+
+ async for args_iterable in _iterate(iterable):
+ args = [element async for element in _iterate(args_iterable)]
+ result_yielded = True
+ yield await function(*args)
+
+ if not result_yielded:
+ await checkpoint()
+
+
+def tee(
+ iterable: Iterable[T] | AsyncIterable[T], n: int = 2
+) -> tuple[AsyncIterator[T], ...]:
+ n = operator.index(cast(Any, n))
+ if n < 0:
+ raise ValueError("n must be >= 0")
+ if n == 0:
+ return ()
+
+ iterator = _TeeAsyncIterator(iterable)
+ iterators: list[AsyncIterator[T]] = [iterator]
+ iterators.extend(_TeeAsyncIterator(iterator) for _ in range(n - 1))
+ return tuple(iterators)
+
+
+async def takewhile(
+ predicate: Callable[[T], Awaitable[object]],
+ iterable: Iterable[T] | AsyncIterable[T],
+) -> AsyncGenerator[T, None]:
+ element_yielded = False
+
+ async for element in _iterate(iterable):
+ if not await predicate(element):
+ if not element_yielded:
+ await checkpoint()
+
+ return
+
+ element_yielded = True
+ yield element
+
+ if not element_yielded:
+ await checkpoint()
+
+
+async def zip_longest(
+ *iterables: Iterable[object] | AsyncIterable[object],
+ fillvalue: object = None,
+) -> AsyncGenerator[tuple[object, ...], None]:
+ iterators = [_iterate(iterable) for iterable in iterables]
+ num_active = len(iterators)
+ if not num_active:
+ await checkpoint()
+ return
+
+ active = [True] * num_active
+ tuple_yielded = False
+
+ while True:
+ values: list[object] = []
+ for index, iterator in enumerate(iterators):
+ if not active[index]:
+ values.append(fillvalue)
+ continue
+
+ try:
+ value = await anext(iterator)
+ except StopAsyncIteration:
+ active[index] = False
+ num_active -= 1
+ if not num_active:
+ if not tuple_yielded:
+ await checkpoint()
+
+ return
+
+ value = fillvalue
+
+ values.append(value)
+
+ tuple_yielded = True
+ yield tuple(values)
diff --git a/venv/Lib/site-packages/anyio/lowlevel.py b/venv/Lib/site-packages/anyio/lowlevel.py
new file mode 100644
index 0000000000000000000000000000000000000000..d04579180f5d925fec2bac68fe379886011dc75a
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/lowlevel.py
@@ -0,0 +1,226 @@
+from __future__ import annotations
+
+__all__ = (
+ "EventLoopToken",
+ "RunvarToken",
+ "RunVar",
+ "checkpoint",
+ "checkpoint_if_cancelled",
+ "cancel_shielded_checkpoint",
+ "current_token",
+)
+
+import enum
+from dataclasses import dataclass
+from types import TracebackType
+from typing import Any, Generic, Literal, TypeVar, final, overload
+from weakref import WeakKeyDictionary
+
+from ._core._eventloop import get_async_backend
+from .abc import AsyncBackend
+
+T = TypeVar("T")
+D = TypeVar("D")
+
+
+async def checkpoint() -> None:
+ """
+ Check for cancellation and allow the scheduler to switch to another task.
+
+ Equivalent to (but more efficient than)::
+
+ await checkpoint_if_cancelled()
+ await cancel_shielded_checkpoint()
+
+ .. versionadded:: 3.0
+
+ """
+ await get_async_backend().checkpoint()
+
+
+async def checkpoint_if_cancelled() -> None:
+ """
+ Enter a checkpoint if the enclosing cancel scope has been cancelled.
+
+ This does not allow the scheduler to switch to a different task.
+
+ .. versionadded:: 3.0
+
+ """
+ await get_async_backend().checkpoint_if_cancelled()
+
+
+async def cancel_shielded_checkpoint() -> None:
+ """
+ Allow the scheduler to switch to another task but without checking for cancellation.
+
+ Equivalent to (but potentially more efficient than)::
+
+ with CancelScope(shield=True):
+ await checkpoint()
+
+ .. versionadded:: 3.0
+
+ """
+ await get_async_backend().cancel_shielded_checkpoint()
+
+
+@final
+@dataclass(frozen=True, repr=False)
+class EventLoopToken:
+ """
+ An opaque object that holds a reference to an event loop.
+
+ .. versionadded:: 4.11.0
+ """
+
+ backend_class: type[AsyncBackend]
+ native_token: object
+
+
+def current_token() -> EventLoopToken:
+ """
+ Return a token object that can be used to call code in the current event loop from
+ another thread.
+
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ .. versionadded:: 4.11.0
+
+ """
+ backend_class = get_async_backend()
+ raw_token = backend_class.current_token()
+ return EventLoopToken(backend_class, raw_token)
+
+
+_run_vars: WeakKeyDictionary[object, dict[RunVar[Any], Any]] = WeakKeyDictionary()
+
+
+class _NoValueSet(enum.Enum):
+ NO_VALUE_SET = enum.auto()
+
+
+class RunvarToken(Generic[T]):
+ """
+ A token that can be used to restore a :class:`RunVar` to its previous value.
+
+ Returned by :meth:`RunVar.set`. Can be used as a context manager to automatically
+ reset the variable on exit, or passed directly to :meth:`RunVar.reset`.
+ """
+
+ __slots__ = "_var", "_value", "_redeemed"
+
+ def __init__(self, var: RunVar[T], value: T | Literal[_NoValueSet.NO_VALUE_SET]):
+ self._var = var
+ self._value: T | Literal[_NoValueSet.NO_VALUE_SET] = value
+ self._redeemed = False
+
+ def __enter__(self) -> RunvarToken[T]:
+ return self
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ self._var.reset(self)
+
+
+class RunVar(Generic[T]):
+ """
+ Like a :class:`~contextvars.ContextVar`, except scoped to the running event loop.
+
+ Can be used as a context manager, Just like :class:`~contextvars.ContextVar`, that
+ will reset the variable to its previous value when the context block is exited.
+ """
+
+ __slots__ = "_name", "_default"
+
+ NO_VALUE_SET: Literal[_NoValueSet.NO_VALUE_SET] = _NoValueSet.NO_VALUE_SET
+
+ def __init__(
+ self, name: str, default: T | Literal[_NoValueSet.NO_VALUE_SET] = NO_VALUE_SET
+ ):
+ self._name = name
+ self._default = default
+
+ @property
+ def _current_vars(self) -> dict[RunVar[T], T]:
+ native_token = current_token().native_token
+ try:
+ return _run_vars[native_token]
+ except KeyError:
+ run_vars = _run_vars[native_token] = {}
+ return run_vars
+
+ @overload
+ def get(self, default: D) -> T | D: ...
+
+ @overload
+ def get(self) -> T: ...
+
+ def get(
+ self, default: D | Literal[_NoValueSet.NO_VALUE_SET] = NO_VALUE_SET
+ ) -> T | D:
+ """
+ Return the current value of this run variable.
+
+ :param default: a fallback value to return if no value has been set
+ :return: the current value, the provided default, or the variable's own default
+ :raises LookupError: if no value is set and no default is available
+
+ """
+ try:
+ return self._current_vars[self]
+ except KeyError:
+ if default is not RunVar.NO_VALUE_SET:
+ return default
+ elif self._default is not RunVar.NO_VALUE_SET:
+ return self._default
+
+ raise LookupError(
+ f'Run variable "{self._name}" has no value and no default set'
+ )
+
+ def set(self, value: T) -> RunvarToken[T]:
+ """
+ Set the value of this run variable for the current event loop.
+
+ :param value: the new value
+ :return: a token that can be used to restore the previous value
+
+ """
+ current_vars = self._current_vars
+ token = RunvarToken(self, current_vars.get(self, RunVar.NO_VALUE_SET))
+ current_vars[self] = value
+ return token
+
+ def reset(self, token: RunvarToken[T]) -> None:
+ """
+ Restore this run variable to the value it held before the matching :meth:`set`.
+
+ :param token: the token returned by :meth:`set`
+ :raises ValueError: if the token belongs to a different :class:`RunVar` or the token
+ has already been used
+
+ """
+ if token._var is not self:
+ raise ValueError("This token does not belong to this RunVar")
+
+ if token._redeemed:
+ raise ValueError("This token has already been used")
+
+ if token._value is _NoValueSet.NO_VALUE_SET:
+ try:
+ del self._current_vars[self]
+ except KeyError:
+ pass
+ else:
+ self._current_vars[self] = token._value
+
+ token._redeemed = True
+
+ def __repr__(self) -> str:
+ return f""
diff --git a/venv/Lib/site-packages/anyio/py.typed b/venv/Lib/site-packages/anyio/py.typed
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/venv/Lib/site-packages/anyio/pytest_plugin.py b/venv/Lib/site-packages/anyio/pytest_plugin.py
new file mode 100644
index 0000000000000000000000000000000000000000..5c667597d02f268b8f5427d8f80957116992c6ee
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/pytest_plugin.py
@@ -0,0 +1,375 @@
+from __future__ import annotations
+
+import dataclasses
+import socket
+import sys
+from collections.abc import Callable, Generator, Iterator
+from contextlib import ExitStack, contextmanager
+from inspect import isasyncgenfunction, iscoroutinefunction, ismethod
+from typing import Any, cast
+
+import pytest
+from _pytest.fixtures import FuncFixtureInfo, SubRequest
+from _pytest.outcomes import Exit
+from _pytest.python import CallSpec2
+from _pytest.scope import Scope
+
+from . import get_available_backends
+from ._core._eventloop import (
+ current_async_library,
+ get_async_backend,
+ reset_current_async_library,
+ set_current_async_library,
+)
+from ._core._exceptions import iterate_exceptions
+from .abc import TestRunner
+
+if sys.version_info < (3, 11):
+ from exceptiongroup import ExceptionGroup
+
+_current_runner: TestRunner | None = None
+_runner_stack: ExitStack | None = None
+_runner_leases = 0
+
+
+def extract_backend_and_options(backend: object) -> tuple[str, dict[str, Any]]:
+ if isinstance(backend, str):
+ return backend, {}
+ elif isinstance(backend, tuple) and len(backend) == 2:
+ if isinstance(backend[0], str) and isinstance(backend[1], dict):
+ return cast(tuple[str, dict[str, Any]], backend)
+
+ raise TypeError("anyio_backend must be either a string or tuple of (string, dict)")
+
+
+@contextmanager
+def get_runner(
+ backend_name: str, backend_options: dict[str, Any]
+) -> Iterator[TestRunner]:
+ global _current_runner, _runner_leases, _runner_stack
+ if _current_runner is None:
+ asynclib = get_async_backend(backend_name)
+ _runner_stack = ExitStack()
+ if current_async_library() is None:
+ # Since we're in control of the event loop, we can cache the name of the
+ # async library
+ token = set_current_async_library(backend_name)
+ _runner_stack.callback(reset_current_async_library, token)
+
+ backend_options = backend_options or {}
+ _current_runner = _runner_stack.enter_context(
+ asynclib.create_test_runner(backend_options)
+ )
+
+ _runner_leases += 1
+ try:
+ yield _current_runner
+ finally:
+ _runner_leases -= 1
+ if not _runner_leases:
+ assert _runner_stack is not None
+ _runner_stack.close()
+ _runner_stack = _current_runner = None
+
+
+def pytest_addoption(parser: pytest.Parser) -> None:
+ parser.addini(
+ "anyio_mode",
+ default="strict",
+ help='AnyIO plugin mode (either "strict" or "auto")',
+ )
+
+
+def pytest_configure(config: pytest.Config) -> None:
+ config.addinivalue_line(
+ "markers",
+ "anyio: mark the (coroutine function) test to be run asynchronously via anyio.",
+ )
+ if (
+ config.getini("anyio_mode") == "auto"
+ and config.pluginmanager.has_plugin("asyncio")
+ and config.getini("asyncio_mode") == "auto"
+ ):
+ config.issue_config_time_warning(
+ pytest.PytestConfigWarning(
+ "AnyIO auto mode has been enabled together with pytest-asyncio auto "
+ "mode. This may cause unexpected behavior."
+ ),
+ 1,
+ )
+
+
+@pytest.hookimpl(hookwrapper=True)
+def pytest_fixture_setup(fixturedef: Any, request: Any) -> Generator[Any]:
+ def wrapper(anyio_backend: Any, request: SubRequest, **kwargs: Any) -> Any:
+ # Rebind any fixture methods to the request instance
+ if (
+ request.instance
+ and ismethod(func)
+ and type(func.__self__) is type(request.instance)
+ ):
+ local_func = func.__func__.__get__(request.instance)
+ else:
+ local_func = func
+
+ backend_name, backend_options = extract_backend_and_options(anyio_backend)
+ if has_backend_arg:
+ kwargs["anyio_backend"] = anyio_backend
+
+ if has_request_arg:
+ kwargs["request"] = request
+
+ with get_runner(backend_name, backend_options) as runner:
+ # re-entrant call into the test runner detected. this happens when an async fixture
+ # is dynamically requested via request.getfixturevalue() from inside a running async
+ # test or fixture. on asyncio this raises RuntimeError: This event loop is already
+ # running, on trio the runner deadlocks - the host loop blocks waiting for the
+ # coroutine to return, but the coroutine is waiting for the host loop. raising here
+ # prevents the hang and gives a consistent error across backends.
+ if runner.is_running():
+ raise RuntimeError(
+ "Cannot schedule a coroutine in the test runner while another is already running; "
+ "likely caused by request.getfixturevalue() on an async fixture."
+ )
+
+ if isasyncgenfunction(local_func):
+ yield from runner.run_asyncgen_fixture(local_func, kwargs)
+ else:
+ yield runner.run_fixture(local_func, kwargs)
+
+ # Only apply this to coroutine functions and async generator functions in requests
+ # that involve the anyio_backend fixture
+ func = fixturedef.func
+ if isasyncgenfunction(func) or iscoroutinefunction(func):
+ if "anyio_backend" in request.fixturenames:
+ fixturedef.func = wrapper
+ original_argname = fixturedef.argnames
+
+ if not (has_backend_arg := "anyio_backend" in fixturedef.argnames):
+ fixturedef.argnames += ("anyio_backend",)
+
+ if not (has_request_arg := "request" in fixturedef.argnames):
+ fixturedef.argnames += ("request",)
+
+ try:
+ return (yield)
+ finally:
+ fixturedef.func = func
+ fixturedef.argnames = original_argname
+
+ return (yield)
+
+
+@pytest.hookimpl(tryfirst=True)
+def pytest_pycollect_makeitem(
+ collector: pytest.Module | pytest.Class, name: str, obj: object
+) -> None:
+ if collector.istestfunction(obj, name):
+ inner_func = obj.hypothesis.inner_test if hasattr(obj, "hypothesis") else obj
+ if iscoroutinefunction(inner_func):
+ anyio_auto_mode = collector.config.getini("anyio_mode") == "auto"
+ marker = collector.get_closest_marker("anyio")
+ own_markers = getattr(obj, "pytestmark", ())
+ if (
+ anyio_auto_mode
+ or marker
+ or any(marker.name == "anyio" for marker in own_markers)
+ ):
+ pytest.mark.usefixtures("anyio_backend")(obj)
+
+
+def pytest_collection_finish(session: pytest.Session) -> None:
+ for i, item in reversed(list(enumerate(session.items))):
+ if (
+ isinstance(item, pytest.Function)
+ and iscoroutinefunction(item.function)
+ and item.get_closest_marker("anyio") is not None
+ and "anyio_backend" not in item.fixturenames
+ ):
+ new_items = []
+ try:
+ cs_fields = {f.name for f in dataclasses.fields(CallSpec2)}
+ except TypeError:
+ cs_fields = set()
+
+ for param_index, backend in enumerate(get_available_backends()):
+ if "_arg2scope" in cs_fields: # pytest >= 8
+ callspec = CallSpec2(
+ params={"anyio_backend": backend},
+ indices={"anyio_backend": param_index},
+ _arg2scope={"anyio_backend": Scope.Module},
+ _idlist=[backend],
+ marks=[],
+ )
+ else: # pytest 7.x
+ callspec = CallSpec2( # type: ignore[call-arg]
+ funcargs={},
+ params={"anyio_backend": backend},
+ indices={"anyio_backend": param_index},
+ arg2scope={"anyio_backend": Scope.Module},
+ idlist=[backend],
+ marks=[],
+ )
+
+ fi = item._fixtureinfo
+ new_names_closure = list(fi.names_closure)
+ if "anyio_backend" not in new_names_closure:
+ new_names_closure.append("anyio_backend")
+
+ new_fixtureinfo = FuncFixtureInfo(
+ argnames=fi.argnames,
+ initialnames=fi.initialnames,
+ names_closure=new_names_closure,
+ name2fixturedefs=fi.name2fixturedefs,
+ )
+ new_item = pytest.Function.from_parent(
+ item.parent,
+ name=f"{item.originalname}[{backend}]",
+ callspec=callspec,
+ callobj=item.obj,
+ fixtureinfo=new_fixtureinfo,
+ keywords=item.keywords,
+ originalname=item.originalname,
+ )
+ new_items.append(new_item)
+
+ session.items[i : i + 1] = new_items
+
+
+@pytest.hookimpl(tryfirst=True)
+def pytest_pyfunc_call(pyfuncitem: Any) -> bool | None:
+ def run_with_hypothesis(**kwargs: Any) -> None:
+ with get_runner(backend_name, backend_options) as runner:
+ runner.run_test(original_func, kwargs)
+
+ backend = pyfuncitem.funcargs.get("anyio_backend")
+ if backend:
+ backend_name, backend_options = extract_backend_and_options(backend)
+
+ if hasattr(pyfuncitem.obj, "hypothesis"):
+ # Wrap the inner test function unless it's already wrapped
+ original_func = pyfuncitem.obj.hypothesis.inner_test
+ if original_func.__qualname__ != run_with_hypothesis.__qualname__:
+ if iscoroutinefunction(original_func):
+ pyfuncitem.obj.hypothesis.inner_test = run_with_hypothesis
+
+ return None
+
+ if iscoroutinefunction(pyfuncitem.obj):
+ funcargs = pyfuncitem.funcargs
+ testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames}
+ with get_runner(backend_name, backend_options) as runner:
+ try:
+ runner.run_test(pyfuncitem.obj, testargs)
+ except ExceptionGroup as excgrp:
+ for exc in iterate_exceptions(excgrp):
+ if isinstance(exc, (Exit, KeyboardInterrupt, SystemExit)):
+ raise exc from excgrp
+
+ raise
+
+ return True
+
+ return None
+
+
+@pytest.fixture(scope="module", params=get_available_backends())
+def anyio_backend(request: Any) -> Any:
+ return request.param
+
+
+@pytest.fixture
+def anyio_backend_name(anyio_backend: Any) -> str:
+ if isinstance(anyio_backend, str):
+ return anyio_backend
+ else:
+ return anyio_backend[0]
+
+
+@pytest.fixture
+def anyio_backend_options(anyio_backend: Any) -> dict[str, Any]:
+ if isinstance(anyio_backend, str):
+ return {}
+ else:
+ return anyio_backend[1]
+
+
+class FreePortFactory:
+ """
+ Manages port generation based on specified socket kind, ensuring no duplicate
+ ports are generated.
+
+ This class provides functionality for generating available free ports on the
+ system. It is initialized with a specific socket kind and can generate ports
+ for given address families while avoiding reuse of previously generated ports.
+
+ Users should not instantiate this class directly, but use the
+ ``free_tcp_port_factory`` and ``free_udp_port_factory`` fixtures instead. For simple
+ uses cases, ``free_tcp_port`` and ``free_udp_port`` can be used instead.
+ """
+
+ def __init__(self, kind: socket.SocketKind) -> None:
+ self._kind = kind
+ self._generated = set[int]()
+
+ @property
+ def kind(self) -> socket.SocketKind:
+ """
+ The type of socket connection (e.g., :data:`~socket.SOCK_STREAM` or
+ :data:`~socket.SOCK_DGRAM`) used to bind for checking port availability
+
+ """
+ return self._kind
+
+ def __call__(self, family: socket.AddressFamily | None = None) -> int:
+ """
+ Return an unbound port for the given address family.
+
+ :param family: if omitted, both IPv4 and IPv6 addresses will be tried
+ :return: a port number
+
+ """
+ if family is not None:
+ families = [family]
+ else:
+ families = [socket.AF_INET]
+ if socket.has_ipv6:
+ families.append(socket.AF_INET6)
+
+ while True:
+ port = 0
+ with ExitStack() as stack:
+ for family in families:
+ sock = stack.enter_context(socket.socket(family, self._kind))
+ addr = "::1" if family == socket.AF_INET6 else "127.0.0.1"
+ try:
+ sock.bind((addr, port))
+ except OSError:
+ break
+
+ if not port:
+ port = sock.getsockname()[1]
+ else:
+ if port not in self._generated:
+ self._generated.add(port)
+ return port
+
+
+@pytest.fixture(scope="session")
+def free_tcp_port_factory() -> FreePortFactory:
+ return FreePortFactory(socket.SOCK_STREAM)
+
+
+@pytest.fixture(scope="session")
+def free_udp_port_factory() -> FreePortFactory:
+ return FreePortFactory(socket.SOCK_DGRAM)
+
+
+@pytest.fixture
+def free_tcp_port(free_tcp_port_factory: Callable[[], int]) -> int:
+ return free_tcp_port_factory()
+
+
+@pytest.fixture
+def free_udp_port(free_udp_port_factory: Callable[[], int]) -> int:
+ return free_udp_port_factory()
diff --git a/venv/Lib/site-packages/anyio/streams/__init__.py b/venv/Lib/site-packages/anyio/streams/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/venv/Lib/site-packages/anyio/streams/buffered.py b/venv/Lib/site-packages/anyio/streams/buffered.py
new file mode 100644
index 0000000000000000000000000000000000000000..acf312ba280f26c4990234670f78ea5860f7783d
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/streams/buffered.py
@@ -0,0 +1,198 @@
+from __future__ import annotations
+
+__all__ = (
+ "BufferedByteReceiveStream",
+ "BufferedByteStream",
+ "BufferedConnectable",
+)
+
+import sys
+from collections.abc import Callable, Iterable, Mapping
+from dataclasses import dataclass, field
+from typing import Any, SupportsIndex
+
+from .. import ClosedResourceError, DelimiterNotFound, EndOfStream, IncompleteRead
+from ..abc import (
+ AnyByteReceiveStream,
+ AnyByteStream,
+ AnyByteStreamConnectable,
+ ByteReceiveStream,
+ ByteStream,
+ ByteStreamConnectable,
+)
+
+if sys.version_info >= (3, 12):
+ from typing import override
+else:
+ from typing_extensions import override
+
+
+@dataclass(eq=False)
+class BufferedByteReceiveStream(ByteReceiveStream):
+ """
+ Wraps any bytes-based receive stream and uses a buffer to provide sophisticated
+ receiving capabilities in the form of a byte stream.
+ """
+
+ receive_stream: AnyByteReceiveStream
+ _buffer: bytearray = field(init=False, default_factory=bytearray)
+ _closed: bool = field(init=False, default=False)
+
+ async def aclose(self) -> None:
+ await self.receive_stream.aclose()
+ self._closed = True
+
+ @property
+ def buffer(self) -> bytes:
+ """The bytes currently in the buffer."""
+ return bytes(self._buffer)
+
+ @property
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
+ return self.receive_stream.extra_attributes
+
+ def feed_data(self, data: Iterable[SupportsIndex], /) -> None:
+ """
+ Append data directly into the buffer.
+
+ Any data in the buffer will be consumed by receive operations before receiving
+ anything from the wrapped stream.
+
+ :param data: the data to append to the buffer (can be bytes or anything else
+ that supports ``__index__()``)
+
+ """
+ self._buffer.extend(data)
+
+ async def receive(self, max_bytes: int = 65536) -> bytes:
+ if self._closed:
+ raise ClosedResourceError
+
+ if self._buffer:
+ chunk = bytes(self._buffer[:max_bytes])
+ del self._buffer[:max_bytes]
+ return chunk
+ elif isinstance(self.receive_stream, ByteReceiveStream):
+ return await self.receive_stream.receive(max_bytes)
+ else:
+ # With a bytes-oriented object stream, we need to handle any surplus bytes
+ # we get from the receive() call
+ chunk = await self.receive_stream.receive()
+ if len(chunk) > max_bytes:
+ # Save the surplus bytes in the buffer
+ self._buffer.extend(chunk[max_bytes:])
+ return chunk[:max_bytes]
+ else:
+ return chunk
+
+ async def receive_exactly(self, nbytes: int) -> bytes:
+ """
+ Read exactly the given amount of bytes from the stream.
+
+ :param nbytes: the number of bytes to read
+ :return: the bytes read
+ :raises ~anyio.IncompleteRead: if the stream was closed before the requested
+ amount of bytes could be read from the stream
+
+ """
+ while True:
+ remaining = nbytes - len(self._buffer)
+ if remaining <= 0:
+ retval = self._buffer[:nbytes]
+ del self._buffer[:nbytes]
+ return bytes(retval)
+
+ try:
+ if isinstance(self.receive_stream, ByteReceiveStream):
+ chunk = await self.receive_stream.receive(remaining)
+ else:
+ chunk = await self.receive_stream.receive()
+ except EndOfStream as exc:
+ raise IncompleteRead from exc
+
+ self._buffer.extend(chunk)
+
+ async def receive_until(self, delimiter: bytes, max_bytes: int) -> bytes:
+ """
+ Read from the stream until the delimiter is found or max_bytes have been read.
+
+ :param delimiter: the marker to look for in the stream
+ :param max_bytes: maximum number of bytes that will be read before raising
+ :exc:`~anyio.DelimiterNotFound`
+ :return: the bytes read (not including the delimiter)
+ :raises ~anyio.IncompleteRead: if the stream was closed before the delimiter
+ was found
+ :raises ~anyio.DelimiterNotFound: if the delimiter is not found within the
+ bytes read up to the maximum allowed
+
+ """
+ delimiter_size = len(delimiter)
+ offset = 0
+ while True:
+ # Check if the delimiter can be found in the current buffer
+ index = self._buffer.find(delimiter, offset)
+ if index >= 0:
+ found = self._buffer[:index]
+ del self._buffer[: index + len(delimiter) :]
+ return bytes(found)
+
+ # Check if the buffer is already at or over the limit
+ if len(self._buffer) >= max_bytes:
+ raise DelimiterNotFound(max_bytes)
+
+ # Read more data into the buffer from the socket
+ try:
+ data = await self.receive_stream.receive()
+ except EndOfStream as exc:
+ raise IncompleteRead from exc
+
+ # Move the offset forward and add the new data to the buffer
+ offset = max(len(self._buffer) - delimiter_size + 1, 0)
+ self._buffer.extend(data)
+
+
+class BufferedByteStream(BufferedByteReceiveStream, ByteStream):
+ """
+ A full-duplex variant of :class:`BufferedByteReceiveStream`. All writes are passed
+ through to the wrapped stream as-is.
+ """
+
+ def __init__(self, stream: AnyByteStream):
+ """
+ :param stream: the stream to be wrapped
+
+ """
+ super().__init__(stream)
+ self._stream = stream
+
+ @override
+ async def send_eof(self) -> None:
+ await self._stream.send_eof()
+
+ @override
+ async def send(self, item: bytes) -> None:
+ await self._stream.send(item)
+
+
+class BufferedConnectable(ByteStreamConnectable):
+ """
+ Wraps a byte stream connectable to produce :class:`BufferedByteStream` connections.
+
+ Use this when you want the streams returned by :meth:`connect` to have the buffered
+ receive API (e.g. :meth:`~BufferedByteReceiveStream.receive_exactly` and
+ :meth:`~BufferedByteReceiveStream.receive_until`).
+
+ :param connectable: the byte stream connectable to wrap
+ """
+
+ def __init__(self, connectable: AnyByteStreamConnectable):
+ """
+ :param connectable: the connectable to wrap
+
+ """
+ self.connectable = connectable
+
+ @override
+ async def connect(self) -> BufferedByteStream:
+ stream = await self.connectable.connect()
+ return BufferedByteStream(stream)
diff --git a/venv/Lib/site-packages/anyio/streams/file.py b/venv/Lib/site-packages/anyio/streams/file.py
new file mode 100644
index 0000000000000000000000000000000000000000..79c3d500beae578832b7e960a76ead95c80be01e
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/streams/file.py
@@ -0,0 +1,154 @@
+from __future__ import annotations
+
+__all__ = (
+ "FileReadStream",
+ "FileStreamAttribute",
+ "FileWriteStream",
+)
+
+from collections.abc import Callable, Mapping
+from io import SEEK_SET, UnsupportedOperation
+from os import PathLike
+from pathlib import Path
+from typing import IO, Any
+
+from .. import (
+ BrokenResourceError,
+ ClosedResourceError,
+ EndOfStream,
+ TypedAttributeSet,
+ to_thread,
+ typed_attribute,
+)
+from ..abc import ByteReceiveStream, ByteSendStream
+
+
+class FileStreamAttribute(TypedAttributeSet):
+ #: the open file descriptor
+ file: IO[bytes] = typed_attribute()
+ #: the path of the file on the file system, if available (file must be a real file)
+ path: Path = typed_attribute()
+ #: the file number, if available (file must be a real file or a TTY)
+ fileno: int = typed_attribute()
+
+
+class _BaseFileStream:
+ def __init__(self, file: IO[bytes]):
+ self._file = file
+
+ async def aclose(self) -> None:
+ await to_thread.run_sync(self._file.close)
+
+ @property
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
+ attributes: dict[Any, Callable[[], Any]] = {
+ FileStreamAttribute.file: lambda: self._file,
+ }
+
+ if hasattr(self._file, "name"):
+ attributes[FileStreamAttribute.path] = lambda: Path(self._file.name)
+
+ try:
+ self._file.fileno()
+ except UnsupportedOperation:
+ pass
+ else:
+ attributes[FileStreamAttribute.fileno] = lambda: self._file.fileno()
+
+ return attributes
+
+
+class FileReadStream(_BaseFileStream, ByteReceiveStream):
+ """
+ A byte stream that reads from a file in the file system.
+
+ :param file: a file that has been opened for reading in binary mode
+
+ .. versionadded:: 3.0
+ """
+
+ @classmethod
+ async def from_path(cls, path: str | PathLike[str]) -> FileReadStream:
+ """
+ Create a file read stream by opening the given file.
+
+ :param path: path of the file to read from
+
+ """
+ file = await to_thread.run_sync(Path(path).open, "rb")
+ return cls(file)
+
+ async def receive(self, max_bytes: int = 65536) -> bytes:
+ try:
+ data = await to_thread.run_sync(self._file.read, max_bytes)
+ except ValueError:
+ raise ClosedResourceError from None
+ except OSError as exc:
+ raise BrokenResourceError from exc
+
+ if data:
+ return data
+ else:
+ raise EndOfStream
+
+ async def seek(self, position: int, whence: int = SEEK_SET) -> int:
+ """
+ Seek the file to the given position.
+
+ .. seealso:: :meth:`io.IOBase.seek`
+
+ .. note:: Not all file descriptors are seekable.
+
+ :param position: position to seek the file to
+ :param whence: controls how ``position`` is interpreted
+ :return: the new absolute position
+ :raises OSError: if the file is not seekable
+
+ """
+ return await to_thread.run_sync(self._file.seek, position, whence)
+
+ async def tell(self) -> int:
+ """
+ Return the current stream position.
+
+ .. note:: Not all file descriptors are seekable.
+
+ :return: the current absolute position
+ :raises OSError: if the file is not seekable
+
+ """
+ return await to_thread.run_sync(self._file.tell)
+
+
+class FileWriteStream(_BaseFileStream, ByteSendStream):
+ """
+ A byte stream that writes to a file in the file system.
+
+ :param file: a file that has been opened for writing in binary mode
+
+ .. versionadded:: 3.0
+ """
+
+ @classmethod
+ async def from_path(
+ cls, path: str | PathLike[str], append: bool = False
+ ) -> FileWriteStream:
+ """
+ Create a file write stream by opening the given file for writing.
+
+ :param path: path of the file to write to
+ :param append: if ``True``, open the file for appending; if ``False``, any
+ existing file at the given path will be truncated
+
+ """
+ mode = "ab" if append else "wb"
+ file = await to_thread.run_sync(Path(path).open, mode)
+ return cls(file)
+
+ async def send(self, item: bytes) -> None:
+ try:
+ await to_thread.run_sync(self._file.write, item)
+ except ValueError:
+ raise ClosedResourceError from None
+ except OSError as exc:
+ raise BrokenResourceError from exc
diff --git a/venv/Lib/site-packages/anyio/streams/memory.py b/venv/Lib/site-packages/anyio/streams/memory.py
new file mode 100644
index 0000000000000000000000000000000000000000..a3fa0c3d9783f34fb5225938f6ce5d1d31b9b85c
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/streams/memory.py
@@ -0,0 +1,325 @@
+from __future__ import annotations
+
+__all__ = (
+ "MemoryObjectReceiveStream",
+ "MemoryObjectSendStream",
+ "MemoryObjectStreamStatistics",
+)
+
+import warnings
+from collections import OrderedDict, deque
+from dataclasses import dataclass, field
+from types import TracebackType
+from typing import Generic, NamedTuple, TypeVar
+
+from .. import (
+ BrokenResourceError,
+ ClosedResourceError,
+ EndOfStream,
+ WouldBlock,
+)
+from .._core._testing import TaskInfo, get_current_task
+from ..abc import Event, ObjectReceiveStream, ObjectSendStream
+from ..lowlevel import checkpoint
+
+T_Item = TypeVar("T_Item")
+T_co = TypeVar("T_co", covariant=True)
+T_contra = TypeVar("T_contra", contravariant=True)
+
+
+class MemoryObjectStreamStatistics(NamedTuple):
+ current_buffer_used: int #: number of items stored in the buffer
+ #: maximum number of items that can be stored on this stream (or :data:`math.inf`)
+ max_buffer_size: float
+ open_send_streams: int #: number of unclosed clones of the send stream
+ open_receive_streams: int #: number of unclosed clones of the receive stream
+ #: number of tasks blocked on :meth:`MemoryObjectSendStream.send`
+ tasks_waiting_send: int
+ #: number of tasks blocked on :meth:`MemoryObjectReceiveStream.receive`
+ tasks_waiting_receive: int
+
+
+@dataclass(eq=False)
+class _MemoryObjectItemReceiver(Generic[T_Item]):
+ task_info: TaskInfo = field(init=False, default_factory=get_current_task)
+ item: T_Item = field(init=False)
+
+ def __repr__(self) -> str:
+ # When item is not defined, we get following error with default __repr__:
+ # AttributeError: 'MemoryObjectItemReceiver' object has no attribute 'item'
+ item = getattr(self, "item", None)
+ return f"{self.__class__.__name__}(task_info={self.task_info}, item={item!r})"
+
+
+@dataclass(eq=False)
+class _MemoryObjectStreamState(Generic[T_Item]):
+ max_buffer_size: float = field()
+ buffer: deque[T_Item] = field(init=False, default_factory=deque)
+ open_send_channels: int = field(init=False, default=0)
+ open_receive_channels: int = field(init=False, default=0)
+ waiting_receivers: OrderedDict[Event, _MemoryObjectItemReceiver[T_Item]] = field(
+ init=False, default_factory=OrderedDict
+ )
+ waiting_senders: OrderedDict[Event, T_Item] = field(
+ init=False, default_factory=OrderedDict
+ )
+
+ def statistics(self) -> MemoryObjectStreamStatistics:
+ return MemoryObjectStreamStatistics(
+ len(self.buffer),
+ self.max_buffer_size,
+ self.open_send_channels,
+ self.open_receive_channels,
+ len(self.waiting_senders),
+ len(self.waiting_receivers),
+ )
+
+
+@dataclass(eq=False)
+class MemoryObjectReceiveStream(Generic[T_co], ObjectReceiveStream[T_co]):
+ _state: _MemoryObjectStreamState[T_co]
+ _closed: bool = field(init=False, default=False)
+
+ def __post_init__(self) -> None:
+ self._state.open_receive_channels += 1
+
+ def receive_nowait(self) -> T_co:
+ """
+ Receive the next item if it can be done without waiting.
+
+ :return: the received item
+ :raises ~anyio.ClosedResourceError: if this send stream has been closed
+ :raises ~anyio.EndOfStream: if the buffer is empty and this stream has been
+ closed from the sending end
+ :raises ~anyio.WouldBlock: if there are no items in the buffer and no tasks
+ waiting to send
+
+ """
+ if self._closed:
+ raise ClosedResourceError
+
+ if self._state.waiting_senders:
+ # Get the item from the next sender
+ send_event, item = self._state.waiting_senders.popitem(last=False)
+ self._state.buffer.append(item)
+ send_event.set()
+
+ if self._state.buffer:
+ return self._state.buffer.popleft()
+ elif not self._state.open_send_channels:
+ raise EndOfStream
+
+ raise WouldBlock
+
+ async def receive(self) -> T_co:
+ await checkpoint()
+ try:
+ return self.receive_nowait()
+ except WouldBlock:
+ # Add ourselves in the queue
+ receive_event = Event()
+ receiver = _MemoryObjectItemReceiver[T_co]()
+ self._state.waiting_receivers[receive_event] = receiver
+
+ try:
+ await receive_event.wait()
+ finally:
+ self._state.waiting_receivers.pop(receive_event, None)
+
+ try:
+ return receiver.item
+ except AttributeError:
+ raise EndOfStream from None
+
+ def clone(self) -> MemoryObjectReceiveStream[T_co]:
+ """
+ Create a clone of this receive stream.
+
+ Each clone can be closed separately. Only when all clones have been closed will
+ the receiving end of the memory stream be considered closed by the sending ends.
+
+ :return: the cloned stream
+
+ """
+ if self._closed:
+ raise ClosedResourceError
+
+ return MemoryObjectReceiveStream(_state=self._state)
+
+ def close(self) -> None:
+ """
+ Close the stream.
+
+ This works the exact same way as :meth:`aclose`, but is provided as a special
+ case for the benefit of synchronous callbacks.
+
+ """
+ if not self._closed:
+ self._closed = True
+ self._state.open_receive_channels -= 1
+ if self._state.open_receive_channels == 0:
+ send_events = list(self._state.waiting_senders.keys())
+ for event in send_events:
+ event.set()
+
+ async def aclose(self) -> None:
+ self.close()
+
+ def statistics(self) -> MemoryObjectStreamStatistics:
+ """
+ Return statistics about the current state of this stream.
+
+ .. versionadded:: 3.0
+ """
+ return self._state.statistics()
+
+ def __enter__(self) -> MemoryObjectReceiveStream[T_co]:
+ return self
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ self.close()
+
+ def __del__(self) -> None:
+ if not self._closed:
+ warnings.warn(
+ f"Unclosed <{self.__class__.__name__} at {id(self):x}>",
+ ResourceWarning,
+ stacklevel=1,
+ source=self,
+ )
+
+
+@dataclass(eq=False)
+class MemoryObjectSendStream(Generic[T_contra], ObjectSendStream[T_contra]):
+ _state: _MemoryObjectStreamState[T_contra]
+ _closed: bool = field(init=False, default=False)
+
+ def __post_init__(self) -> None:
+ self._state.open_send_channels += 1
+
+ def send_nowait(self, item: T_contra) -> None:
+ """
+ Send an item immediately if it can be done without waiting.
+
+ :param item: the item to send
+ :raises ~anyio.ClosedResourceError: if this send stream has been closed
+ :raises ~anyio.BrokenResourceError: if the stream has been closed from the
+ receiving end
+ :raises ~anyio.WouldBlock: if the buffer is full and there are no tasks waiting
+ to receive
+
+ """
+ if self._closed:
+ raise ClosedResourceError
+ if not self._state.open_receive_channels:
+ raise BrokenResourceError
+
+ while self._state.waiting_receivers:
+ receive_event, receiver = self._state.waiting_receivers.popitem(last=False)
+ if not receiver.task_info.has_pending_cancellation():
+ receiver.item = item
+ receive_event.set()
+ return
+
+ if len(self._state.buffer) < self._state.max_buffer_size:
+ self._state.buffer.append(item)
+ else:
+ raise WouldBlock
+
+ async def send(self, item: T_contra) -> None:
+ """
+ Send an item to the stream.
+
+ If the buffer is full, this method blocks until there is again room in the
+ buffer or the item can be sent directly to a receiver.
+
+ :param item: the item to send
+ :raises ~anyio.ClosedResourceError: if this send stream has been closed
+ :raises ~anyio.BrokenResourceError: if the stream has been closed from the
+ receiving end
+
+ """
+ await checkpoint()
+ try:
+ self.send_nowait(item)
+ except WouldBlock:
+ # Wait until there's someone on the receiving end
+ send_event = Event()
+ self._state.waiting_senders[send_event] = item
+ try:
+ await send_event.wait()
+ except BaseException:
+ self._state.waiting_senders.pop(send_event, None)
+ raise
+
+ if send_event in self._state.waiting_senders:
+ del self._state.waiting_senders[send_event]
+ raise BrokenResourceError from None
+
+ def clone(self) -> MemoryObjectSendStream[T_contra]:
+ """
+ Create a clone of this send stream.
+
+ Each clone can be closed separately. Only when all clones have been closed will
+ the sending end of the memory stream be considered closed by the receiving ends.
+
+ :return: the cloned stream
+
+ """
+ if self._closed:
+ raise ClosedResourceError
+
+ return MemoryObjectSendStream(_state=self._state)
+
+ def close(self) -> None:
+ """
+ Close the stream.
+
+ This works the exact same way as :meth:`aclose`, but is provided as a special
+ case for the benefit of synchronous callbacks.
+
+ """
+ if not self._closed:
+ self._closed = True
+ self._state.open_send_channels -= 1
+ if self._state.open_send_channels == 0:
+ receive_events = list(self._state.waiting_receivers.keys())
+ self._state.waiting_receivers.clear()
+ for event in receive_events:
+ event.set()
+
+ async def aclose(self) -> None:
+ self.close()
+
+ def statistics(self) -> MemoryObjectStreamStatistics:
+ """
+ Return statistics about the current state of this stream.
+
+ .. versionadded:: 3.0
+ """
+ return self._state.statistics()
+
+ def __enter__(self) -> MemoryObjectSendStream[T_contra]:
+ return self
+
+ def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ self.close()
+
+ def __del__(self) -> None:
+ if not self._closed:
+ warnings.warn(
+ f"Unclosed <{self.__class__.__name__} at {id(self):x}>",
+ ResourceWarning,
+ stacklevel=1,
+ source=self,
+ )
diff --git a/venv/Lib/site-packages/anyio/streams/stapled.py b/venv/Lib/site-packages/anyio/streams/stapled.py
new file mode 100644
index 0000000000000000000000000000000000000000..9248b68abfbff90ddd64646fbe9cabb9f0ebe869
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/streams/stapled.py
@@ -0,0 +1,147 @@
+from __future__ import annotations
+
+__all__ = (
+ "MultiListener",
+ "StapledByteStream",
+ "StapledObjectStream",
+)
+
+from collections.abc import Callable, Mapping, Sequence
+from dataclasses import dataclass
+from typing import Any, Generic, TypeVar
+
+from ..abc import (
+ ByteReceiveStream,
+ ByteSendStream,
+ ByteStream,
+ Listener,
+ ObjectReceiveStream,
+ ObjectSendStream,
+ ObjectStream,
+ TaskGroup,
+)
+
+T_Item = TypeVar("T_Item")
+T_Stream = TypeVar("T_Stream")
+
+
+@dataclass(eq=False)
+class StapledByteStream(ByteStream):
+ """
+ Combines two byte streams into a single, bidirectional byte stream.
+
+ Extra attributes will be provided from both streams, with the receive stream
+ providing the values in case of a conflict.
+
+ :param ByteSendStream send_stream: the sending byte stream
+ :param ByteReceiveStream receive_stream: the receiving byte stream
+ """
+
+ send_stream: ByteSendStream
+ receive_stream: ByteReceiveStream
+
+ async def receive(self, max_bytes: int = 65536) -> bytes:
+ return await self.receive_stream.receive(max_bytes)
+
+ async def send(self, item: bytes) -> None:
+ await self.send_stream.send(item)
+
+ async def send_eof(self) -> None:
+ await self.send_stream.aclose()
+
+ async def aclose(self) -> None:
+ await self.send_stream.aclose()
+ await self.receive_stream.aclose()
+
+ @property
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
+ return {
+ **self.send_stream.extra_attributes,
+ **self.receive_stream.extra_attributes,
+ }
+
+
+@dataclass(eq=False)
+class StapledObjectStream(Generic[T_Item], ObjectStream[T_Item]):
+ """
+ Combines two object streams into a single, bidirectional object stream.
+
+ Extra attributes will be provided from both streams, with the receive stream
+ providing the values in case of a conflict.
+
+ :param ObjectSendStream send_stream: the sending object stream
+ :param ObjectReceiveStream receive_stream: the receiving object stream
+ """
+
+ send_stream: ObjectSendStream[T_Item]
+ receive_stream: ObjectReceiveStream[T_Item]
+
+ async def receive(self) -> T_Item:
+ return await self.receive_stream.receive()
+
+ async def send(self, item: T_Item) -> None:
+ await self.send_stream.send(item)
+
+ async def send_eof(self) -> None:
+ await self.send_stream.aclose()
+
+ async def aclose(self) -> None:
+ await self.send_stream.aclose()
+ await self.receive_stream.aclose()
+
+ @property
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
+ return {
+ **self.send_stream.extra_attributes,
+ **self.receive_stream.extra_attributes,
+ }
+
+
+@dataclass(eq=False)
+class MultiListener(Generic[T_Stream], Listener[T_Stream]):
+ """
+ Combines multiple listeners into one, serving connections from all of them at once.
+
+ Any MultiListeners in the given collection of listeners will have their listeners
+ moved into this one.
+
+ Extra attributes are provided from each listener, with each successive listener
+ overriding any conflicting attributes from the previous one.
+
+ :param listeners: listeners to serve
+ :type listeners: Sequence[Listener[T_Stream]]
+ """
+
+ listeners: Sequence[Listener[T_Stream]]
+
+ def __post_init__(self) -> None:
+ listeners: list[Listener[T_Stream]] = []
+ for listener in self.listeners:
+ if isinstance(listener, MultiListener):
+ listeners.extend(listener.listeners)
+ del listener.listeners[:] # type: ignore[attr-defined]
+ else:
+ listeners.append(listener)
+
+ self.listeners = listeners
+
+ async def serve(
+ self, handler: Callable[[T_Stream], Any], task_group: TaskGroup | None = None
+ ) -> None:
+ from .. import create_task_group
+
+ async with create_task_group() as tg:
+ for listener in self.listeners:
+ tg.start_soon(listener.serve, handler, task_group)
+
+ async def aclose(self) -> None:
+ for listener in self.listeners:
+ await listener.aclose()
+
+ @property
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
+ attributes: dict = {}
+ for listener in self.listeners:
+ attributes.update(listener.extra_attributes)
+
+ return attributes
diff --git a/venv/Lib/site-packages/anyio/streams/text.py b/venv/Lib/site-packages/anyio/streams/text.py
new file mode 100644
index 0000000000000000000000000000000000000000..296cd250459f3848bb333301fff1ac32973f219a
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/streams/text.py
@@ -0,0 +1,176 @@
+from __future__ import annotations
+
+__all__ = (
+ "TextConnectable",
+ "TextReceiveStream",
+ "TextSendStream",
+ "TextStream",
+)
+
+import codecs
+import sys
+from collections.abc import Callable, Mapping
+from dataclasses import InitVar, dataclass, field
+from typing import Any
+
+from ..abc import (
+ AnyByteReceiveStream,
+ AnyByteSendStream,
+ AnyByteStream,
+ AnyByteStreamConnectable,
+ ObjectReceiveStream,
+ ObjectSendStream,
+ ObjectStream,
+ ObjectStreamConnectable,
+)
+
+if sys.version_info >= (3, 12):
+ from typing import override
+else:
+ from typing_extensions import override
+
+
+@dataclass(eq=False)
+class TextReceiveStream(ObjectReceiveStream[str]):
+ """
+ Stream wrapper that decodes bytes to strings using the given encoding.
+
+ Decoding is done using :class:`~codecs.IncrementalDecoder` which returns any
+ completely received unicode characters as soon as they come in.
+
+ :param transport_stream: any bytes-based receive stream
+ :param encoding: character encoding to use for decoding bytes to strings (defaults
+ to ``utf-8``)
+ :param errors: handling scheme for decoding errors (defaults to ``strict``; see the
+ `codecs module documentation`_ for a comprehensive list of options)
+
+ .. _codecs module documentation:
+ https://docs.python.org/3/library/codecs.html#codec-objects
+ """
+
+ transport_stream: AnyByteReceiveStream
+ encoding: InitVar[str] = "utf-8"
+ errors: InitVar[str] = "strict"
+ _decoder: codecs.IncrementalDecoder = field(init=False)
+
+ def __post_init__(self, encoding: str, errors: str) -> None:
+ decoder_class = codecs.getincrementaldecoder(encoding)
+ self._decoder = decoder_class(errors=errors)
+
+ async def receive(self) -> str:
+ while True:
+ chunk = await self.transport_stream.receive()
+ decoded = self._decoder.decode(chunk)
+ if decoded:
+ return decoded
+
+ async def aclose(self) -> None:
+ await self.transport_stream.aclose()
+ self._decoder.reset()
+
+ @property
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
+ return self.transport_stream.extra_attributes
+
+
+@dataclass(eq=False)
+class TextSendStream(ObjectSendStream[str]):
+ """
+ Sends strings to the wrapped stream as bytes using the given encoding.
+
+ :param AnyByteSendStream transport_stream: any bytes-based send stream
+ :param str encoding: character encoding to use for encoding strings to bytes
+ (defaults to ``utf-8``)
+ :param str errors: handling scheme for encoding errors (defaults to ``strict``; see
+ the `codecs module documentation`_ for a comprehensive list of options)
+
+ .. _codecs module documentation:
+ https://docs.python.org/3/library/codecs.html#codec-objects
+ """
+
+ transport_stream: AnyByteSendStream
+ encoding: InitVar[str] = "utf-8"
+ errors: str = "strict"
+ _encoder: Callable[..., tuple[bytes, int]] = field(init=False)
+
+ def __post_init__(self, encoding: str) -> None:
+ self._encoder = codecs.getencoder(encoding)
+
+ async def send(self, item: str) -> None:
+ encoded = self._encoder(item, self.errors)[0]
+ await self.transport_stream.send(encoded)
+
+ async def aclose(self) -> None:
+ await self.transport_stream.aclose()
+
+ @property
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
+ return self.transport_stream.extra_attributes
+
+
+@dataclass(eq=False)
+class TextStream(ObjectStream[str]):
+ """
+ A bidirectional stream that decodes bytes to strings on receive and encodes strings
+ to bytes on send.
+
+ Extra attributes will be provided from both streams, with the receive stream
+ providing the values in case of a conflict.
+
+ :param AnyByteStream transport_stream: any bytes-based stream
+ :param str encoding: character encoding to use for encoding/decoding strings to/from
+ bytes (defaults to ``utf-8``)
+ :param str errors: handling scheme for encoding errors (defaults to ``strict``; see
+ the `codecs module documentation`_ for a comprehensive list of options)
+
+ .. _codecs module documentation:
+ https://docs.python.org/3/library/codecs.html#codec-objects
+ """
+
+ transport_stream: AnyByteStream
+ encoding: InitVar[str] = "utf-8"
+ errors: InitVar[str] = "strict"
+ _receive_stream: TextReceiveStream = field(init=False)
+ _send_stream: TextSendStream = field(init=False)
+
+ def __post_init__(self, encoding: str, errors: str) -> None:
+ self._receive_stream = TextReceiveStream(
+ self.transport_stream, encoding=encoding, errors=errors
+ )
+ self._send_stream = TextSendStream(
+ self.transport_stream, encoding=encoding, errors=errors
+ )
+
+ async def receive(self) -> str:
+ return await self._receive_stream.receive()
+
+ async def send(self, item: str) -> None:
+ await self._send_stream.send(item)
+
+ async def send_eof(self) -> None:
+ await self.transport_stream.send_eof()
+
+ async def aclose(self) -> None:
+ await self._send_stream.aclose()
+ await self._receive_stream.aclose()
+
+ @property
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
+ return {
+ **self._send_stream.extra_attributes,
+ **self._receive_stream.extra_attributes,
+ }
+
+
+class TextConnectable(ObjectStreamConnectable[str]):
+ def __init__(self, connectable: AnyByteStreamConnectable):
+ """
+ :param connectable: the bytestream endpoint to wrap
+
+ """
+ self.connectable = connectable
+
+ @override
+ async def connect(self) -> TextStream:
+ stream = await self.connectable.connect()
+ return TextStream(stream)
diff --git a/venv/Lib/site-packages/anyio/streams/tls.py b/venv/Lib/site-packages/anyio/streams/tls.py
new file mode 100644
index 0000000000000000000000000000000000000000..e2a7ca5b17b9b6c2d3f0f39e86b22342d0b4df65
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/streams/tls.py
@@ -0,0 +1,421 @@
+from __future__ import annotations
+
+__all__ = (
+ "TLSAttribute",
+ "TLSConnectable",
+ "TLSListener",
+ "TLSStream",
+)
+
+import logging
+import re
+import ssl
+import sys
+from collections.abc import Callable, Mapping
+from dataclasses import dataclass
+from functools import wraps
+from ssl import SSLContext
+from typing import Any, TypeAlias, TypeVar
+
+from .. import (
+ BrokenResourceError,
+ EndOfStream,
+ aclose_forcefully,
+ get_cancelled_exc_class,
+ to_thread,
+)
+from .._core._typedattr import TypedAttributeSet, typed_attribute
+from ..abc import (
+ AnyByteStream,
+ AnyByteStreamConnectable,
+ ByteStream,
+ ByteStreamConnectable,
+ Listener,
+ TaskGroup,
+)
+
+if sys.version_info >= (3, 11):
+ from typing import TypeVarTuple, Unpack
+else:
+ from typing_extensions import TypeVarTuple, Unpack
+
+if sys.version_info >= (3, 12):
+ from typing import override
+else:
+ from typing_extensions import override
+
+T_Retval = TypeVar("T_Retval")
+PosArgsT = TypeVarTuple("PosArgsT")
+_PCTRTT: TypeAlias = tuple[tuple[str, str], ...]
+_PCTRTTT: TypeAlias = tuple[_PCTRTT, ...]
+
+
+class TLSAttribute(TypedAttributeSet):
+ """Contains Transport Layer Security related attributes."""
+
+ #: the selected ALPN protocol
+ alpn_protocol: str | None = typed_attribute()
+ #: the channel binding for type ``tls-unique``
+ channel_binding_tls_unique: bytes = typed_attribute()
+ #: the selected cipher
+ cipher: tuple[str, str, int] = typed_attribute()
+ #: the peer certificate in dictionary form (see :meth:`ssl.SSLSocket.getpeercert`
+ # for more information)
+ peer_certificate: None | (dict[str, str | _PCTRTTT | _PCTRTT]) = typed_attribute()
+ #: the peer certificate in binary form
+ peer_certificate_binary: bytes | None = typed_attribute()
+ #: ``True`` if this is the server side of the connection
+ server_side: bool = typed_attribute()
+ #: ciphers shared by the client during the TLS handshake (``None`` if this is the
+ #: client side)
+ shared_ciphers: list[tuple[str, str, int]] | None = typed_attribute()
+ #: the :class:`~ssl.SSLObject` used for encryption
+ ssl_object: ssl.SSLObject = typed_attribute()
+ #: ``True`` if this stream does (and expects) a closing TLS handshake when the
+ #: stream is being closed
+ standard_compatible: bool = typed_attribute()
+ #: the TLS protocol version (e.g. ``TLSv1.2``)
+ tls_version: str = typed_attribute()
+
+
+@dataclass(eq=False)
+class TLSStream(ByteStream):
+ """
+ A stream wrapper that encrypts all sent data and decrypts received data.
+
+ This class has no public initializer; use :meth:`wrap` instead.
+ All extra attributes from :class:`~TLSAttribute` are supported.
+
+ :var AnyByteStream transport_stream: the wrapped stream
+
+ """
+
+ transport_stream: AnyByteStream
+ standard_compatible: bool
+ _ssl_object: ssl.SSLObject
+ _read_bio: ssl.MemoryBIO
+ _write_bio: ssl.MemoryBIO
+
+ @classmethod
+ async def wrap(
+ cls,
+ transport_stream: AnyByteStream,
+ *,
+ server_side: bool | None = None,
+ hostname: str | None = None,
+ ssl_context: ssl.SSLContext | None = None,
+ standard_compatible: bool = True,
+ ) -> TLSStream:
+ """
+ Wrap an existing stream with Transport Layer Security.
+
+ This performs a TLS handshake with the peer.
+
+ :param transport_stream: a bytes-transporting stream to wrap
+ :param server_side: ``True`` if this is the server side of the connection,
+ ``False`` if this is the client side (if omitted, will be set to ``False``
+ if ``hostname`` has been provided, ``False`` otherwise). Used only to create
+ a default context when an explicit context has not been provided.
+ :param hostname: host name of the peer (if host name checking is desired)
+ :param ssl_context: the SSLContext object to use (if not provided, a secure
+ default will be created)
+ :param standard_compatible: if ``False``, skip the closing handshake when
+ closing the connection, and don't raise an exception if the peer does the
+ same
+ :raises ~ssl.SSLError: if the TLS handshake fails
+
+ """
+ if server_side is None:
+ server_side = not hostname
+
+ if not ssl_context:
+ purpose = (
+ ssl.Purpose.CLIENT_AUTH if server_side else ssl.Purpose.SERVER_AUTH
+ )
+ ssl_context = ssl.create_default_context(purpose)
+
+ # Re-enable detection of unexpected EOFs if it was disabled by Python
+ if hasattr(ssl, "OP_IGNORE_UNEXPECTED_EOF"):
+ ssl_context.options &= ~ssl.OP_IGNORE_UNEXPECTED_EOF
+
+ bio_in = ssl.MemoryBIO()
+ bio_out = ssl.MemoryBIO()
+
+ # External SSLContext implementations may do blocking I/O in wrap_bio(),
+ # but the standard library implementation won't
+ if type(ssl_context) is ssl.SSLContext:
+ ssl_object = ssl_context.wrap_bio(
+ bio_in, bio_out, server_side=server_side, server_hostname=hostname
+ )
+ else:
+ ssl_object = await to_thread.run_sync(
+ ssl_context.wrap_bio,
+ bio_in,
+ bio_out,
+ server_side,
+ hostname,
+ None,
+ )
+
+ wrapper = cls(
+ transport_stream=transport_stream,
+ standard_compatible=standard_compatible,
+ _ssl_object=ssl_object,
+ _read_bio=bio_in,
+ _write_bio=bio_out,
+ )
+ await wrapper._call_sslobject_method(ssl_object.do_handshake)
+ return wrapper
+
+ async def _call_sslobject_method(
+ self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT]
+ ) -> T_Retval:
+ while True:
+ try:
+ result = func(*args)
+ except ssl.SSLWantReadError:
+ try:
+ # Flush any pending writes first
+ if self._write_bio.pending:
+ await self.transport_stream.send(self._write_bio.read())
+
+ data = await self.transport_stream.receive()
+ except EndOfStream:
+ self._read_bio.write_eof()
+ except OSError as exc:
+ self._read_bio.write_eof()
+ self._write_bio.write_eof()
+ raise BrokenResourceError from exc
+ else:
+ self._read_bio.write(data)
+ except ssl.SSLWantWriteError:
+ await self.transport_stream.send(self._write_bio.read())
+ except ssl.SSLSyscallError as exc:
+ self._read_bio.write_eof()
+ self._write_bio.write_eof()
+ raise BrokenResourceError from exc
+ except ssl.SSLError as exc:
+ self._read_bio.write_eof()
+ self._write_bio.write_eof()
+ if isinstance(exc, ssl.SSLEOFError) or (
+ exc.strerror and "UNEXPECTED_EOF_WHILE_READING" in exc.strerror
+ ):
+ if self.standard_compatible:
+ raise BrokenResourceError from exc
+ else:
+ raise EndOfStream from None
+
+ raise
+ else:
+ # Flush any pending writes first
+ if self._write_bio.pending:
+ await self.transport_stream.send(self._write_bio.read())
+
+ return result
+
+ async def unwrap(self) -> tuple[AnyByteStream, bytes]:
+ """
+ Does the TLS closing handshake.
+
+ :return: a tuple of (wrapped byte stream, bytes left in the read buffer)
+
+ """
+ await self._call_sslobject_method(self._ssl_object.unwrap)
+ self._read_bio.write_eof()
+ self._write_bio.write_eof()
+ return self.transport_stream, self._read_bio.read()
+
+ async def aclose(self) -> None:
+ if self.standard_compatible:
+ try:
+ await self.unwrap()
+ except BaseException:
+ await aclose_forcefully(self.transport_stream)
+ raise
+
+ await self.transport_stream.aclose()
+
+ async def receive(self, max_bytes: int = 65536) -> bytes:
+ data = await self._call_sslobject_method(self._ssl_object.read, max_bytes)
+ if not data:
+ raise EndOfStream
+
+ return data
+
+ async def send(self, item: bytes) -> None:
+ await self._call_sslobject_method(self._ssl_object.write, item)
+
+ async def send_eof(self) -> None:
+ tls_version = self.extra(TLSAttribute.tls_version)
+ match = re.match(r"TLSv(\d+)(?:\.(\d+))?", tls_version)
+ if match:
+ major, minor = int(match.group(1)), int(match.group(2) or 0)
+ if (major, minor) < (1, 3):
+ raise NotImplementedError(
+ f"send_eof() requires at least TLSv1.3; current "
+ f"session uses {tls_version}"
+ )
+
+ raise NotImplementedError(
+ "send_eof() has not yet been implemented for TLS streams"
+ )
+
+ @property
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
+ return {
+ **self.transport_stream.extra_attributes,
+ TLSAttribute.alpn_protocol: self._ssl_object.selected_alpn_protocol,
+ TLSAttribute.channel_binding_tls_unique: (
+ self._ssl_object.get_channel_binding
+ ),
+ TLSAttribute.cipher: self._ssl_object.cipher,
+ TLSAttribute.peer_certificate: lambda: self._ssl_object.getpeercert(False),
+ TLSAttribute.peer_certificate_binary: lambda: self._ssl_object.getpeercert(
+ True
+ ),
+ TLSAttribute.server_side: lambda: self._ssl_object.server_side,
+ TLSAttribute.shared_ciphers: lambda: (
+ self._ssl_object.shared_ciphers()
+ if self._ssl_object.server_side
+ else None
+ ),
+ TLSAttribute.standard_compatible: lambda: self.standard_compatible,
+ TLSAttribute.ssl_object: lambda: self._ssl_object,
+ TLSAttribute.tls_version: self._ssl_object.version,
+ }
+
+
+@dataclass(eq=False)
+class TLSListener(Listener[TLSStream]):
+ """
+ A convenience listener that wraps another listener and auto-negotiates a TLS session
+ on every accepted connection.
+
+ If the TLS handshake times out or raises an exception,
+ :meth:`handle_handshake_error` is called to do whatever post-mortem processing is
+ deemed necessary.
+
+ Supports only the :attr:`~TLSAttribute.standard_compatible` extra attribute.
+
+ :param Listener listener: the listener to wrap
+ :param ssl_context: the SSL context object
+ :param standard_compatible: a flag passed through to :meth:`TLSStream.wrap`
+ :param handshake_timeout: time limit for the TLS handshake
+ (passed to :func:`~anyio.fail_after`)
+ """
+
+ listener: Listener[Any]
+ ssl_context: ssl.SSLContext
+ standard_compatible: bool = True
+ handshake_timeout: float = 30
+
+ @staticmethod
+ async def handle_handshake_error(exc: BaseException, stream: AnyByteStream) -> None:
+ """
+ Handle an exception raised during the TLS handshake.
+
+ This method does 3 things:
+
+ #. Forcefully closes the original stream
+ #. Logs the exception (unless it was a cancellation exception) using the
+ ``anyio.streams.tls`` logger
+ #. Reraises the exception if it was a base exception or a cancellation exception
+
+ :param exc: the exception
+ :param stream: the original stream
+
+ """
+ await aclose_forcefully(stream)
+
+ # Log all except cancellation exceptions
+ if not isinstance(exc, get_cancelled_exc_class()):
+ # CPython (as of 3.11.5) returns incorrect `sys.exc_info()` here when using
+ # any asyncio implementation, so we explicitly pass the exception to log
+ # (https://github.com/python/cpython/issues/108668). Trio does not have this
+ # issue because it works around the CPython bug.
+ logging.getLogger(__name__).exception(
+ "Error during TLS handshake", exc_info=exc
+ )
+
+ # Only reraise base exceptions and cancellation exceptions
+ if not isinstance(exc, Exception) or isinstance(exc, get_cancelled_exc_class()):
+ raise
+
+ async def serve(
+ self,
+ handler: Callable[[TLSStream], Any],
+ task_group: TaskGroup | None = None,
+ ) -> None:
+ @wraps(handler)
+ async def handler_wrapper(stream: AnyByteStream) -> None:
+ from .. import fail_after
+
+ try:
+ with fail_after(self.handshake_timeout):
+ wrapped_stream = await TLSStream.wrap(
+ stream,
+ ssl_context=self.ssl_context,
+ standard_compatible=self.standard_compatible,
+ )
+ except BaseException as exc:
+ await self.handle_handshake_error(exc, stream)
+ else:
+ await handler(wrapped_stream)
+
+ await self.listener.serve(handler_wrapper, task_group)
+
+ async def aclose(self) -> None:
+ await self.listener.aclose()
+
+ @property
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
+ return {
+ TLSAttribute.standard_compatible: lambda: self.standard_compatible,
+ }
+
+
+class TLSConnectable(ByteStreamConnectable):
+ """
+ Wraps another connectable and does TLS negotiation after a successful connection.
+
+ :param connectable: the connectable to wrap
+ :param hostname: host name of the server (if host name checking is desired)
+ :param ssl_context: the SSLContext object to use (if not provided, a secure default
+ will be created)
+ :param standard_compatible: if ``False``, skip the closing handshake when closing
+ the connection, and don't raise an exception if the server does the same
+ """
+
+ def __init__(
+ self,
+ connectable: AnyByteStreamConnectable,
+ *,
+ hostname: str | None = None,
+ ssl_context: ssl.SSLContext | None = None,
+ standard_compatible: bool = True,
+ ) -> None:
+ self.connectable = connectable
+ self.ssl_context: SSLContext = ssl_context or ssl.create_default_context(
+ ssl.Purpose.SERVER_AUTH
+ )
+ if not isinstance(self.ssl_context, ssl.SSLContext):
+ raise TypeError(
+ "ssl_context must be an instance of ssl.SSLContext, not "
+ f"{type(self.ssl_context).__name__}"
+ )
+ self.hostname = hostname
+ self.standard_compatible = standard_compatible
+
+ @override
+ async def connect(self) -> TLSStream:
+ stream = await self.connectable.connect()
+ try:
+ return await TLSStream.wrap(
+ stream,
+ hostname=self.hostname,
+ ssl_context=self.ssl_context,
+ standard_compatible=self.standard_compatible,
+ )
+ except BaseException:
+ await aclose_forcefully(stream)
+ raise
diff --git a/venv/Lib/site-packages/anyio/to_interpreter.py b/venv/Lib/site-packages/anyio/to_interpreter.py
new file mode 100644
index 0000000000000000000000000000000000000000..694dbe77bc8581032ee72316afe4e0590311ba00
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/to_interpreter.py
@@ -0,0 +1,246 @@
+from __future__ import annotations
+
+__all__ = (
+ "run_sync",
+ "current_default_interpreter_limiter",
+)
+
+import atexit
+import os
+import sys
+from collections import deque
+from collections.abc import Callable
+from typing import Any, Final, TypeVar
+
+from . import current_time, to_thread
+from ._core._exceptions import BrokenWorkerInterpreter
+from ._core._synchronization import CapacityLimiter
+from .lowlevel import RunVar
+
+if sys.version_info >= (3, 11):
+ from typing import TypeVarTuple, Unpack
+else:
+ from typing_extensions import TypeVarTuple, Unpack
+
+if sys.version_info >= (3, 14):
+ from concurrent.interpreters import ExecutionFailed, create
+
+ def _interp_call(
+ func: Callable[..., Any], args: tuple[Any, ...]
+ ) -> tuple[Any, bool]:
+ try:
+ retval = func(*args)
+ except BaseException as exc:
+ return exc, True
+ else:
+ return retval, False
+
+ class _Worker:
+ last_used: float = 0
+
+ def __init__(self) -> None:
+ self._interpreter = create()
+
+ def destroy(self) -> None:
+ self._interpreter.close()
+
+ def call(
+ self,
+ func: Callable[..., T_Retval],
+ args: tuple[Any, ...],
+ ) -> T_Retval:
+ try:
+ res, is_exception = self._interpreter.call(_interp_call, func, args)
+ except ExecutionFailed as exc:
+ raise BrokenWorkerInterpreter(exc.excinfo) from exc
+
+ if is_exception:
+ raise res
+
+ return res
+elif sys.version_info >= (3, 13):
+ import _interpqueues
+ import _interpreters
+
+ UNBOUND: Final = 2 # I have no clue how this works, but it was used in the stdlib
+ FMT_UNPICKLED: Final = 0
+ FMT_PICKLED: Final = 1
+ QUEUE_PICKLE_ARGS: Final = (FMT_PICKLED, UNBOUND)
+ QUEUE_UNPICKLE_ARGS: Final = (FMT_UNPICKLED, UNBOUND)
+
+ _run_func = compile(
+ """
+import _interpqueues
+from _interpreters import NotShareableError
+from pickle import loads, dumps, HIGHEST_PROTOCOL
+
+QUEUE_PICKLE_ARGS = (1, 2)
+QUEUE_UNPICKLE_ARGS = (0, 2)
+
+item = _interpqueues.get(queue_id)[0]
+try:
+ func, args = loads(item)
+ retval = func(*args)
+except BaseException as exc:
+ is_exception = True
+ retval = exc
+else:
+ is_exception = False
+
+try:
+ _interpqueues.put(queue_id, (retval, is_exception), *QUEUE_UNPICKLE_ARGS)
+except NotShareableError:
+ retval = dumps(retval, HIGHEST_PROTOCOL)
+ _interpqueues.put(queue_id, (retval, is_exception), *QUEUE_PICKLE_ARGS)
+ """,
+ "",
+ "exec",
+ )
+
+ class _Worker:
+ last_used: float = 0
+
+ def __init__(self) -> None:
+ self._interpreter_id = _interpreters.create()
+ self._queue_id = _interpqueues.create(1, *QUEUE_UNPICKLE_ARGS)
+ _interpreters.set___main___attrs(
+ self._interpreter_id, {"queue_id": self._queue_id}
+ )
+
+ def destroy(self) -> None:
+ _interpqueues.destroy(self._queue_id)
+ _interpreters.destroy(self._interpreter_id)
+
+ def call(
+ self,
+ func: Callable[..., T_Retval],
+ args: tuple[Any, ...],
+ ) -> T_Retval:
+ import pickle
+
+ item = pickle.dumps((func, args), pickle.HIGHEST_PROTOCOL)
+ _interpqueues.put(self._queue_id, item, *QUEUE_PICKLE_ARGS)
+ exc_info = _interpreters.exec(self._interpreter_id, _run_func)
+ if exc_info:
+ raise BrokenWorkerInterpreter(exc_info)
+
+ res = _interpqueues.get(self._queue_id)
+ (res, is_exception), fmt = res[:2]
+ if fmt == FMT_PICKLED:
+ res = pickle.loads(res)
+
+ if is_exception:
+ raise res
+
+ return res
+else:
+
+ class _Worker:
+ last_used: float = 0
+
+ def __init__(self) -> None:
+ raise RuntimeError("subinterpreters require at least Python 3.13")
+
+ def call(
+ self,
+ func: Callable[..., T_Retval],
+ args: tuple[Any, ...],
+ ) -> T_Retval:
+ raise NotImplementedError
+
+ def destroy(self) -> None:
+ pass
+
+
+DEFAULT_CPU_COUNT: Final = 8 # this is just an arbitrarily selected value
+MAX_WORKER_IDLE_TIME = (
+ 30 # seconds a subinterpreter can be idle before becoming eligible for pruning
+)
+
+T_Retval = TypeVar("T_Retval")
+PosArgsT = TypeVarTuple("PosArgsT")
+
+_idle_workers = RunVar[deque[_Worker]]("_available_workers")
+_default_interpreter_limiter = RunVar[CapacityLimiter]("_default_interpreter_limiter")
+
+
+def _stop_workers(workers: deque[_Worker]) -> None:
+ for worker in workers:
+ worker.destroy()
+
+ workers.clear()
+
+
+async def run_sync(
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
+ *args: Unpack[PosArgsT],
+ limiter: CapacityLimiter | None = None,
+) -> T_Retval:
+ """
+ Call the given function with the given arguments in a subinterpreter.
+
+ .. warning:: On Python 3.13, the :mod:`concurrent.interpreters` module was not yet
+ available, so the code path for that Python version relies on an undocumented,
+ private API. As such, it is recommended to not rely on this function for anything
+ mission-critical on Python 3.13.
+
+ :param func: a callable
+ :param args: the positional arguments for the callable
+ :param limiter: capacity limiter to use to limit the total number of subinterpreters
+ running (if omitted, the default limiter is used)
+ :return: the result of the call
+ :raises BrokenWorkerInterpreter: if there's an internal error in a subinterpreter
+
+ """
+ if limiter is None:
+ limiter = current_default_interpreter_limiter()
+
+ try:
+ idle_workers = _idle_workers.get()
+ except LookupError:
+ idle_workers = deque()
+ _idle_workers.set(idle_workers)
+ atexit.register(_stop_workers, idle_workers)
+
+ async with limiter:
+ try:
+ worker = idle_workers.pop()
+ except IndexError:
+ worker = _Worker()
+
+ try:
+ return await to_thread.run_sync(
+ worker.call,
+ func,
+ args,
+ limiter=limiter,
+ )
+ finally:
+ # Prune workers that have been idle for too long
+ now = current_time()
+ while idle_workers:
+ if now - idle_workers[0].last_used <= MAX_WORKER_IDLE_TIME:
+ break
+
+ await to_thread.run_sync(idle_workers.popleft().destroy, limiter=limiter)
+
+ worker.last_used = current_time()
+ idle_workers.append(worker)
+
+
+def current_default_interpreter_limiter() -> CapacityLimiter:
+ """
+ Return the capacity limiter used by default to limit the number of concurrently
+ running subinterpreters.
+
+ Defaults to the number of CPU cores.
+
+ :return: a capacity limiter object
+
+ """
+ try:
+ return _default_interpreter_limiter.get()
+ except LookupError:
+ limiter = CapacityLimiter(os.cpu_count() or DEFAULT_CPU_COUNT)
+ _default_interpreter_limiter.set(limiter)
+ return limiter
diff --git a/venv/Lib/site-packages/anyio/to_process.py b/venv/Lib/site-packages/anyio/to_process.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd65b18c64d7f8f102dae5e7ea0a775de5c5c7f9
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/to_process.py
@@ -0,0 +1,268 @@
+from __future__ import annotations
+
+__all__ = (
+ "current_default_process_limiter",
+ "process_worker",
+ "run_sync",
+)
+
+import os
+import pickle
+import runpy
+import subprocess
+import sys
+from collections import deque
+from collections.abc import Callable
+from types import ModuleType
+from typing import TypeVar, cast
+
+from ._core._eventloop import current_time, get_async_backend, get_cancelled_exc_class
+from ._core._exceptions import BrokenWorkerProcess
+from ._core._subprocesses import open_process
+from ._core._synchronization import CapacityLimiter
+from ._core._tasks import CancelScope, fail_after
+from .abc import ByteReceiveStream, ByteSendStream, Process
+from .lowlevel import RunVar, checkpoint_if_cancelled
+from .streams.buffered import BufferedByteReceiveStream
+
+if sys.version_info >= (3, 11):
+ from typing import TypeVarTuple, Unpack
+else:
+ from typing_extensions import TypeVarTuple, Unpack
+
+WORKER_MAX_IDLE_TIME = 300 # 5 minutes
+
+T_Retval = TypeVar("T_Retval")
+PosArgsT = TypeVarTuple("PosArgsT")
+
+_process_pool_workers: RunVar[set[Process]] = RunVar("_process_pool_workers")
+_process_pool_idle_workers: RunVar[deque[tuple[Process, float]]] = RunVar(
+ "_process_pool_idle_workers"
+)
+_default_process_limiter: RunVar[CapacityLimiter] = RunVar("_default_process_limiter")
+
+
+async def run_sync( # type: ignore[return]
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
+ *args: Unpack[PosArgsT],
+ cancellable: bool = False,
+ limiter: CapacityLimiter | None = None,
+) -> T_Retval:
+ """
+ Call the given function with the given arguments in a worker process.
+
+ If the ``cancellable`` option is enabled and the task waiting for its completion is
+ cancelled, the worker process running it will be abruptly terminated using SIGKILL
+ (or ``terminateProcess()`` on Windows).
+
+ :param func: a callable
+ :param args: positional arguments for the callable
+ :param cancellable: ``True`` to allow cancellation of the operation while it's
+ running
+ :param limiter: capacity limiter to use to limit the total amount of processes
+ running (if omitted, the default limiter is used)
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+ :return: an awaitable that yields the return value of the function.
+
+ """
+
+ async def send_raw_command(pickled_cmd: bytes) -> object:
+ try:
+ await stdin.send(pickled_cmd)
+ response = await buffered.receive_until(b"\n", 50)
+ status, length = response.split(b" ")
+ if status not in (b"RETURN", b"EXCEPTION"):
+ raise RuntimeError(
+ f"Worker process returned unexpected response: {response!r}"
+ )
+
+ pickled_response = await buffered.receive_exactly(int(length))
+ except BaseException as exc:
+ workers.discard(process)
+ try:
+ process.kill()
+ with CancelScope(shield=True):
+ await process.aclose()
+ except ProcessLookupError:
+ pass
+
+ if isinstance(exc, get_cancelled_exc_class()):
+ raise
+ else:
+ raise BrokenWorkerProcess from exc
+
+ retval = pickle.loads(pickled_response)
+ if status == b"EXCEPTION":
+ assert isinstance(retval, BaseException)
+ raise retval
+ else:
+ return retval
+
+ # First pickle the request before trying to reserve a worker process
+ await checkpoint_if_cancelled()
+ request = pickle.dumps(("run", func, args), protocol=pickle.HIGHEST_PROTOCOL)
+
+ # If this is the first run in this event loop thread, set up the necessary variables
+ try:
+ workers = _process_pool_workers.get()
+ idle_workers = _process_pool_idle_workers.get()
+ except LookupError:
+ workers = set()
+ idle_workers = deque()
+ _process_pool_workers.set(workers)
+ _process_pool_idle_workers.set(idle_workers)
+ get_async_backend().setup_process_pool_exit_at_shutdown(workers)
+
+ async with limiter or current_default_process_limiter():
+ # Pop processes from the pool (starting from the most recently used) until we
+ # find one that hasn't exited yet
+ process: Process
+ while idle_workers:
+ process, idle_since = idle_workers.pop()
+ if process.returncode is None:
+ stdin = cast(ByteSendStream, process.stdin)
+ buffered = BufferedByteReceiveStream(
+ cast(ByteReceiveStream, process.stdout)
+ )
+
+ # Prune any other workers that have been idle for WORKER_MAX_IDLE_TIME
+ # seconds or longer
+ now = current_time()
+ killed_processes: list[Process] = []
+ while idle_workers:
+ if now - idle_workers[0][1] < WORKER_MAX_IDLE_TIME:
+ break
+
+ process_to_kill, idle_since = idle_workers.popleft()
+ process_to_kill.kill()
+ workers.remove(process_to_kill)
+ killed_processes.append(process_to_kill)
+
+ with CancelScope(shield=True):
+ for killed_process in killed_processes:
+ await killed_process.aclose()
+
+ break
+
+ workers.remove(process)
+ else:
+ command = [sys.executable, "-u", "-m", __name__]
+ process = await open_process(
+ command, stdin=subprocess.PIPE, stdout=subprocess.PIPE
+ )
+ try:
+ stdin = cast(ByteSendStream, process.stdin)
+ buffered = BufferedByteReceiveStream(
+ cast(ByteReceiveStream, process.stdout)
+ )
+ with fail_after(20):
+ message = await buffered.receive(6)
+
+ if message != b"READY\n":
+ raise BrokenWorkerProcess(
+ f"Worker process returned unexpected response: {message!r}"
+ )
+
+ main_module_path = getattr(sys.modules["__main__"], "__file__", None)
+ pickled = pickle.dumps(
+ ("init", sys.path, main_module_path),
+ protocol=pickle.HIGHEST_PROTOCOL,
+ )
+ await send_raw_command(pickled)
+ except (BrokenWorkerProcess, get_cancelled_exc_class()):
+ raise
+ except BaseException as exc:
+ process.kill()
+ raise BrokenWorkerProcess(
+ "Error during worker process initialization"
+ ) from exc
+
+ workers.add(process)
+
+ with CancelScope(shield=not cancellable):
+ try:
+ return cast(T_Retval, await send_raw_command(request))
+ finally:
+ if process in workers:
+ idle_workers.append((process, current_time()))
+
+
+def current_default_process_limiter() -> CapacityLimiter:
+ """
+ Return the capacity limiter that is used by default to limit the number of worker
+ processes.
+
+ :return: a capacity limiter object
+
+ """
+ try:
+ return _default_process_limiter.get()
+ except LookupError:
+ limiter = CapacityLimiter(os.cpu_count() or 2)
+ _default_process_limiter.set(limiter)
+ return limiter
+
+
+def process_worker() -> None:
+ # Redirect standard streams to os.devnull so that user code won't interfere with the
+ # parent-worker communication
+ stdin = sys.stdin
+ stdout = sys.stdout
+ sys.stdin = open(os.devnull)
+ sys.stdout = open(os.devnull, "w")
+
+ stdout.buffer.write(b"READY\n")
+ while True:
+ retval = exception = None
+ try:
+ command, *args = pickle.load(stdin.buffer)
+ except EOFError:
+ return
+ except BaseException as exc:
+ exception = exc
+ else:
+ if command == "run":
+ func, args = args
+ try:
+ retval = func(*args)
+ except BaseException as exc:
+ exception = exc
+ elif command == "init":
+ main_module_path: str | None
+ sys.path, main_module_path = args
+ del sys.modules["__main__"]
+ if main_module_path and os.path.isfile(main_module_path):
+ # Load the parent's main module but as __mp_main__ instead of
+ # __main__ (like multiprocessing does) to avoid infinite recursion
+ try:
+ main = ModuleType("__mp_main__")
+ main_content = runpy.run_path(
+ main_module_path, run_name="__mp_main__"
+ )
+ main.__dict__.update(main_content)
+ sys.modules["__main__"] = sys.modules["__mp_main__"] = main
+ except BaseException as exc:
+ exception = exc
+ try:
+ if exception is not None:
+ status = b"EXCEPTION"
+ pickled = pickle.dumps(exception, pickle.HIGHEST_PROTOCOL)
+ else:
+ status = b"RETURN"
+ pickled = pickle.dumps(retval, pickle.HIGHEST_PROTOCOL)
+ except BaseException as exc:
+ exception = exc
+ status = b"EXCEPTION"
+ pickled = pickle.dumps(exc, pickle.HIGHEST_PROTOCOL)
+
+ stdout.buffer.write(b"%s %d\n" % (status, len(pickled)))
+ stdout.buffer.write(pickled)
+
+ # Respect SIGTERM
+ if isinstance(exception, SystemExit):
+ raise exception
+
+
+if __name__ == "__main__":
+ process_worker()
diff --git a/venv/Lib/site-packages/anyio/to_thread.py b/venv/Lib/site-packages/anyio/to_thread.py
new file mode 100644
index 0000000000000000000000000000000000000000..83c79d1cd4029ccdaf23b22a9ad10074a0979ec2
--- /dev/null
+++ b/venv/Lib/site-packages/anyio/to_thread.py
@@ -0,0 +1,78 @@
+from __future__ import annotations
+
+__all__ = (
+ "run_sync",
+ "current_default_thread_limiter",
+)
+
+import sys
+from collections.abc import Callable
+from typing import TypeVar
+from warnings import warn
+
+from ._core._eventloop import get_async_backend
+from .abc import CapacityLimiter
+
+if sys.version_info >= (3, 11):
+ from typing import TypeVarTuple, Unpack
+else:
+ from typing_extensions import TypeVarTuple, Unpack
+
+T_Retval = TypeVar("T_Retval")
+PosArgsT = TypeVarTuple("PosArgsT")
+
+
+async def run_sync(
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
+ *args: Unpack[PosArgsT],
+ abandon_on_cancel: bool = False,
+ cancellable: bool | None = None,
+ limiter: CapacityLimiter | None = None,
+) -> T_Retval:
+ """
+ Call the given function with the given arguments in a worker thread.
+
+ If the ``abandon_on_cancel`` option is enabled and the task waiting for its
+ completion is cancelled, the thread will still run its course but its
+ return value (or any raised exception) will be ignored.
+
+ :param func: a callable
+ :param args: positional arguments for the callable
+ :param abandon_on_cancel: ``True`` to abandon the thread (leaving it to run
+ unchecked on own) if the host task is cancelled, ``False`` to ignore
+ cancellations in the host task until the operation has completed in the worker
+ thread
+ :param cancellable: deprecated alias of ``abandon_on_cancel``; will override
+ ``abandon_on_cancel`` if both parameters are passed
+ :param limiter: capacity limiter to use to limit the total amount of threads running
+ (if omitted, the default limiter is used)
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+ :return: an awaitable that yields the return value of the function.
+
+ """
+ if cancellable is not None:
+ abandon_on_cancel = cancellable
+ warn(
+ "The `cancellable=` keyword argument to `anyio.to_thread.run_sync` is "
+ "deprecated since AnyIO 4.1.0; use `abandon_on_cancel=` instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+
+ return await get_async_backend().run_sync_in_worker_thread(
+ func, args, abandon_on_cancel=abandon_on_cancel, limiter=limiter
+ )
+
+
+def current_default_thread_limiter() -> CapacityLimiter:
+ """
+ Return the capacity limiter that is used by default to limit the number of
+ concurrent threads.
+
+ :return: a capacity limiter object
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+ current thread
+
+ """
+ return get_async_backend().current_default_thread_limiter()
diff --git a/venv/Lib/site-packages/appdirs-1.4.4.dist-info/INSTALLER b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/INSTALLER
new file mode 100644
index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68
--- /dev/null
+++ b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/Lib/site-packages/appdirs-1.4.4.dist-info/LICENSE.txt b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..107c61405e3b4a3266a83064073910b6c8d4a42a
--- /dev/null
+++ b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/LICENSE.txt
@@ -0,0 +1,23 @@
+# This is the MIT license
+
+Copyright (c) 2010 ActiveState Software Inc.
+
+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.
+
diff --git a/venv/Lib/site-packages/appdirs-1.4.4.dist-info/METADATA b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/METADATA
new file mode 100644
index 0000000000000000000000000000000000000000..f95073104453fbfb5c3d7ef1dd065544bc63ff2a
--- /dev/null
+++ b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/METADATA
@@ -0,0 +1,264 @@
+Metadata-Version: 2.1
+Name: appdirs
+Version: 1.4.4
+Summary: A small Python module for determining appropriate platform-specific dirs, e.g. a "user data dir".
+Home-page: http://github.com/ActiveState/appdirs
+Author: Trent Mick
+Author-email: trentm@gmail.com
+Maintainer: Jeff Rouse
+Maintainer-email: jr@its.to
+License: MIT
+Keywords: application directory log cache user
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+
+
+.. image:: https://secure.travis-ci.org/ActiveState/appdirs.png
+ :target: http://travis-ci.org/ActiveState/appdirs
+
+the problem
+===========
+
+What directory should your app use for storing user data? If running on Mac OS X, you
+should use::
+
+ ~/Library/Application Support/
+
+If on Windows (at least English Win XP) that should be::
+
+ C:\Documents and Settings\\Application Data\Local Settings\\
+
+or possibly::
+
+ C:\Documents and Settings\\Application Data\\
+
+for `roaming profiles `_ but that is another story.
+
+On Linux (and other Unices) the dir, according to the `XDG
+spec `_, is::
+
+ ~/.local/share/
+
+
+``appdirs`` to the rescue
+=========================
+
+This kind of thing is what the ``appdirs`` module is for. ``appdirs`` will
+help you choose an appropriate:
+
+- user data dir (``user_data_dir``)
+- user config dir (``user_config_dir``)
+- user cache dir (``user_cache_dir``)
+- site data dir (``site_data_dir``)
+- site config dir (``site_config_dir``)
+- user log dir (``user_log_dir``)
+
+and also:
+
+- is a single module so other Python packages can include their own private copy
+- is slightly opinionated on the directory names used. Look for "OPINION" in
+ documentation and code for when an opinion is being applied.
+
+
+some example output
+===================
+
+On Mac OS X::
+
+ >>> from appdirs import *
+ >>> appname = "SuperApp"
+ >>> appauthor = "Acme"
+ >>> user_data_dir(appname, appauthor)
+ '/Users/trentm/Library/Application Support/SuperApp'
+ >>> site_data_dir(appname, appauthor)
+ '/Library/Application Support/SuperApp'
+ >>> user_cache_dir(appname, appauthor)
+ '/Users/trentm/Library/Caches/SuperApp'
+ >>> user_log_dir(appname, appauthor)
+ '/Users/trentm/Library/Logs/SuperApp'
+
+On Windows 7::
+
+ >>> from appdirs import *
+ >>> appname = "SuperApp"
+ >>> appauthor = "Acme"
+ >>> user_data_dir(appname, appauthor)
+ 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp'
+ >>> user_data_dir(appname, appauthor, roaming=True)
+ 'C:\\Users\\trentm\\AppData\\Roaming\\Acme\\SuperApp'
+ >>> user_cache_dir(appname, appauthor)
+ 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Cache'
+ >>> user_log_dir(appname, appauthor)
+ 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Logs'
+
+On Linux::
+
+ >>> from appdirs import *
+ >>> appname = "SuperApp"
+ >>> appauthor = "Acme"
+ >>> user_data_dir(appname, appauthor)
+ '/home/trentm/.local/share/SuperApp
+ >>> site_data_dir(appname, appauthor)
+ '/usr/local/share/SuperApp'
+ >>> site_data_dir(appname, appauthor, multipath=True)
+ '/usr/local/share/SuperApp:/usr/share/SuperApp'
+ >>> user_cache_dir(appname, appauthor)
+ '/home/trentm/.cache/SuperApp'
+ >>> user_log_dir(appname, appauthor)
+ '/home/trentm/.cache/SuperApp/log'
+ >>> user_config_dir(appname)
+ '/home/trentm/.config/SuperApp'
+ >>> site_config_dir(appname)
+ '/etc/xdg/SuperApp'
+ >>> os.environ['XDG_CONFIG_DIRS'] = '/etc:/usr/local/etc'
+ >>> site_config_dir(appname, multipath=True)
+ '/etc/SuperApp:/usr/local/etc/SuperApp'
+
+
+``AppDirs`` for convenience
+===========================
+
+::
+
+ >>> from appdirs import AppDirs
+ >>> dirs = AppDirs("SuperApp", "Acme")
+ >>> dirs.user_data_dir
+ '/Users/trentm/Library/Application Support/SuperApp'
+ >>> dirs.site_data_dir
+ '/Library/Application Support/SuperApp'
+ >>> dirs.user_cache_dir
+ '/Users/trentm/Library/Caches/SuperApp'
+ >>> dirs.user_log_dir
+ '/Users/trentm/Library/Logs/SuperApp'
+
+
+
+Per-version isolation
+=====================
+
+If you have multiple versions of your app in use that you want to be
+able to run side-by-side, then you may want version-isolation for these
+dirs::
+
+ >>> from appdirs import AppDirs
+ >>> dirs = AppDirs("SuperApp", "Acme", version="1.0")
+ >>> dirs.user_data_dir
+ '/Users/trentm/Library/Application Support/SuperApp/1.0'
+ >>> dirs.site_data_dir
+ '/Library/Application Support/SuperApp/1.0'
+ >>> dirs.user_cache_dir
+ '/Users/trentm/Library/Caches/SuperApp/1.0'
+ >>> dirs.user_log_dir
+ '/Users/trentm/Library/Logs/SuperApp/1.0'
+
+
+
+appdirs Changelog
+=================
+
+appdirs 1.4.4
+-------------
+- [PR #92] Don't import appdirs from setup.py
+
+Project officially classified as Stable which is important
+for inclusion in other distros such as ActivePython.
+
+First of several incremental releases to catch up on maintenance.
+
+appdirs 1.4.3
+-------------
+- [PR #76] Python 3.6 invalid escape sequence deprecation fixes
+- Fix for Python 3.6 support
+
+appdirs 1.4.2
+-------------
+- [PR #84] Allow installing without setuptools
+- [PR #86] Fix string delimiters in setup.py description
+- Add Python 3.6 support
+
+appdirs 1.4.1
+-------------
+- [issue #38] Fix _winreg import on Windows Py3
+- [issue #55] Make appname optional
+
+appdirs 1.4.0
+-------------
+- [PR #42] AppAuthor is now optional on Windows
+- [issue 41] Support Jython on Windows, Mac, and Unix-like platforms. Windows
+ support requires `JNA `_.
+- [PR #44] Fix incorrect behaviour of the site_config_dir method
+
+appdirs 1.3.0
+-------------
+- [Unix, issue 16] Conform to XDG standard, instead of breaking it for
+ everybody
+- [Unix] Removes gratuitous case mangling of the case, since \*nix-es are
+ usually case sensitive, so mangling is not wise
+- [Unix] Fixes the utterly wrong behaviour in ``site_data_dir``, return result
+ based on XDG_DATA_DIRS and make room for respecting the standard which
+ specifies XDG_DATA_DIRS is a multiple-value variable
+- [Issue 6] Add ``*_config_dir`` which are distinct on nix-es, according to
+ XDG specs; on Windows and Mac return the corresponding ``*_data_dir``
+
+appdirs 1.2.0
+-------------
+
+- [Unix] Put ``user_log_dir`` under the *cache* dir on Unix. Seems to be more
+ typical.
+- [issue 9] Make ``unicode`` work on py3k.
+
+appdirs 1.1.0
+-------------
+
+- [issue 4] Add ``AppDirs.user_log_dir``.
+- [Unix, issue 2, issue 7] appdirs now conforms to `XDG base directory spec
+ `_.
+- [Mac, issue 5] Fix ``site_data_dir()`` on Mac.
+- [Mac] Drop use of 'Carbon' module in favour of hardcoded paths; supports
+ Python3 now.
+- [Windows] Append "Cache" to ``user_cache_dir`` on Windows by default. Use
+ ``opinion=False`` option to disable this.
+- Add ``appdirs.AppDirs`` convenience class. Usage:
+
+ >>> dirs = AppDirs("SuperApp", "Acme", version="1.0")
+ >>> dirs.user_data_dir
+ '/Users/trentm/Library/Application Support/SuperApp/1.0'
+
+- [Windows] Cherry-pick Komodo's change to downgrade paths to the Windows short
+ paths if there are high bit chars.
+- [Linux] Change default ``user_cache_dir()`` on Linux to be singular, e.g.
+ "~/.superapp/cache".
+- [Windows] Add ``roaming`` option to ``user_data_dir()`` (for use on Windows only)
+ and change the default ``user_data_dir`` behaviour to use a *non*-roaming
+ profile dir (``CSIDL_LOCAL_APPDATA`` instead of ``CSIDL_APPDATA``). Why? Because
+ a large roaming profile can cause login speed issues. The "only syncs on
+ logout" behaviour can cause surprises in appdata info.
+
+
+appdirs 1.0.1 (never released)
+------------------------------
+
+Started this changelog 27 July 2010. Before that this module originated in the
+`Komodo `_ product as ``applib.py`` and then
+as `applib/location.py
+`_ (used by
+`PyPM `_ in `ActivePython
+`_). This is basically a fork of
+applib.py 1.0.1 and applib/location.py 1.0.1.
+
+
+
diff --git a/venv/Lib/site-packages/appdirs-1.4.4.dist-info/RECORD b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/RECORD
new file mode 100644
index 0000000000000000000000000000000000000000..1920a31f606327713d00a5b2daa526c140629ccc
--- /dev/null
+++ b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/RECORD
@@ -0,0 +1,8 @@
+__pycache__/appdirs.cpython-311.pyc,,
+appdirs-1.4.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+appdirs-1.4.4.dist-info/LICENSE.txt,sha256=Nt200KdFqTqyAyA9cZCBSxuJcn0lTK_0jHp6-71HAAs,1097
+appdirs-1.4.4.dist-info/METADATA,sha256=k5TVfXMNKGHTfp2wm6EJKTuGwGNuoQR5TqQgH8iwG8M,8981
+appdirs-1.4.4.dist-info/RECORD,,
+appdirs-1.4.4.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110
+appdirs-1.4.4.dist-info/top_level.txt,sha256=nKncE8CUqZERJ6VuQWL4_bkunSPDNfn7KZqb4Tr5YEM,8
+appdirs.py,sha256=g99s2sXhnvTEm79oj4bWI0Toapc-_SmKKNXvOXHkVic,24720
diff --git a/venv/Lib/site-packages/appdirs-1.4.4.dist-info/WHEEL b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/WHEEL
new file mode 100644
index 0000000000000000000000000000000000000000..ef99c6cf3283b50a273ac4c6d009a0aa85597070
--- /dev/null
+++ b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/WHEEL
@@ -0,0 +1,6 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.34.2)
+Root-Is-Purelib: true
+Tag: py2-none-any
+Tag: py3-none-any
+
diff --git a/venv/Lib/site-packages/appdirs-1.4.4.dist-info/top_level.txt b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d64bc321a11c17064f6e048ffcee9044688aa819
--- /dev/null
+++ b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/top_level.txt
@@ -0,0 +1 @@
+appdirs
diff --git a/venv/Lib/site-packages/appdirs.py b/venv/Lib/site-packages/appdirs.py
new file mode 100644
index 0000000000000000000000000000000000000000..2acd1debeb1d3b981fc577b777a77106c765c391
--- /dev/null
+++ b/venv/Lib/site-packages/appdirs.py
@@ -0,0 +1,608 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (c) 2005-2010 ActiveState Software Inc.
+# Copyright (c) 2013 Eddy PetriΘor
+
+"""Utilities for determining application-specific dirs.
+
+See for details and usage.
+"""
+# Dev Notes:
+# - MSDN on where to store app data files:
+# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120
+# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html
+# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+
+__version__ = "1.4.4"
+__version_info__ = tuple(int(segment) for segment in __version__.split("."))
+
+
+import sys
+import os
+
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+ unicode = str
+
+if sys.platform.startswith('java'):
+ import platform
+ os_name = platform.java_ver()[3][0]
+ if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc.
+ system = 'win32'
+ elif os_name.startswith('Mac'): # "Mac OS X", etc.
+ system = 'darwin'
+ else: # "Linux", "SunOS", "FreeBSD", etc.
+ # Setting this to "linux2" is not ideal, but only Windows or Mac
+ # are actually checked for and the rest of the module expects
+ # *sys.platform* style strings.
+ system = 'linux2'
+else:
+ system = sys.platform
+
+
+
+def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
+ r"""Return full path to the user-specific data dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be ".".
+ Only applied when appname is present.
+ "roaming" (boolean, default False) can be set True to use the Windows
+ roaming appdata directory. That means that for users on a Windows
+ network setup for roaming profiles, this user data will be
+ sync'd on login. See
+
+ for a discussion of issues.
+
+ Typical user data directories are:
+ Mac OS X: ~/Library/Application Support/
+ Unix: ~/.local/share/ # or in $XDG_DATA_HOME, if defined
+ Win XP (not roaming): C:\Documents and Settings\\Application Data\\
+ Win XP (roaming): C:\Documents and Settings\\Local Settings\Application Data\\
+ Win 7 (not roaming): C:\Users\\AppData\Local\\
+ Win 7 (roaming): C:\Users\\AppData\Roaming\\
+
+ For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
+ That means, by default "~/.local/share/".
+ """
+ if system == "win32":
+ if appauthor is None:
+ appauthor = appname
+ const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"
+ path = os.path.normpath(_get_win_folder(const))
+ if appname:
+ if appauthor is not False:
+ path = os.path.join(path, appauthor, appname)
+ else:
+ path = os.path.join(path, appname)
+ elif system == 'darwin':
+ path = os.path.expanduser('~/Library/Application Support/')
+ if appname:
+ path = os.path.join(path, appname)
+ else:
+ path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share"))
+ if appname:
+ path = os.path.join(path, appname)
+ if appname and version:
+ path = os.path.join(path, version)
+ return path
+
+
+def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
+ r"""Return full path to the user-shared data dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be ".".
+ Only applied when appname is present.
+ "multipath" is an optional parameter only applicable to *nix
+ which indicates that the entire list of data dirs should be
+ returned. By default, the first item from XDG_DATA_DIRS is
+ returned, or '/usr/local/share/',
+ if XDG_DATA_DIRS is not set
+
+ Typical site data directories are:
+ Mac OS X: /Library/Application Support/
+ Unix: /usr/local/share/ or /usr/share/
+ Win XP: C:\Documents and Settings\All Users\Application Data\\
+ Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
+ Win 7: C:\ProgramData\\ # Hidden, but writeable on Win 7.
+
+ For Unix, this is using the $XDG_DATA_DIRS[0] default.
+
+ WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
+ """
+ if system == "win32":
+ if appauthor is None:
+ appauthor = appname
+ path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))
+ if appname:
+ if appauthor is not False:
+ path = os.path.join(path, appauthor, appname)
+ else:
+ path = os.path.join(path, appname)
+ elif system == 'darwin':
+ path = os.path.expanduser('/Library/Application Support')
+ if appname:
+ path = os.path.join(path, appname)
+ else:
+ # XDG default for $XDG_DATA_DIRS
+ # only first, if multipath is False
+ path = os.getenv('XDG_DATA_DIRS',
+ os.pathsep.join(['/usr/local/share', '/usr/share']))
+ pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
+ if appname:
+ if version:
+ appname = os.path.join(appname, version)
+ pathlist = [os.sep.join([x, appname]) for x in pathlist]
+
+ if multipath:
+ path = os.pathsep.join(pathlist)
+ else:
+ path = pathlist[0]
+ return path
+
+ if appname and version:
+ path = os.path.join(path, version)
+ return path
+
+
+def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
+ r"""Return full path to the user-specific config dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be ".".
+ Only applied when appname is present.
+ "roaming" (boolean, default False) can be set True to use the Windows
+ roaming appdata directory. That means that for users on a Windows
+ network setup for roaming profiles, this user data will be
+ sync'd on login. See
+
+ for a discussion of issues.
+
+ Typical user config directories are:
+ Mac OS X: same as user_data_dir
+ Unix: ~/.config/ # or in $XDG_CONFIG_HOME, if defined
+ Win *: same as user_data_dir
+
+ For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.
+ That means, by default "~/.config/".
+ """
+ if system in ["win32", "darwin"]:
+ path = user_data_dir(appname, appauthor, None, roaming)
+ else:
+ path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config"))
+ if appname:
+ path = os.path.join(path, appname)
+ if appname and version:
+ path = os.path.join(path, version)
+ return path
+
+
+def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
+ r"""Return full path to the user-shared data dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be ".".
+ Only applied when appname is present.
+ "multipath" is an optional parameter only applicable to *nix
+ which indicates that the entire list of config dirs should be
+ returned. By default, the first item from XDG_CONFIG_DIRS is
+ returned, or '/etc/xdg/', if XDG_CONFIG_DIRS is not set
+
+ Typical site config directories are:
+ Mac OS X: same as site_data_dir
+ Unix: /etc/xdg/ or $XDG_CONFIG_DIRS[i]/ for each value in
+ $XDG_CONFIG_DIRS
+ Win *: same as site_data_dir
+ Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
+
+ For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False
+
+ WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
+ """
+ if system in ["win32", "darwin"]:
+ path = site_data_dir(appname, appauthor)
+ if appname and version:
+ path = os.path.join(path, version)
+ else:
+ # XDG default for $XDG_CONFIG_DIRS
+ # only first, if multipath is False
+ path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg')
+ pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
+ if appname:
+ if version:
+ appname = os.path.join(appname, version)
+ pathlist = [os.sep.join([x, appname]) for x in pathlist]
+
+ if multipath:
+ path = os.pathsep.join(pathlist)
+ else:
+ path = pathlist[0]
+ return path
+
+
+def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
+ r"""Return full path to the user-specific cache dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be ".".
+ Only applied when appname is present.
+ "opinion" (boolean) can be False to disable the appending of
+ "Cache" to the base app data dir for Windows. See
+ discussion below.
+
+ Typical user cache directories are:
+ Mac OS X: ~/Library/Caches/
+ Unix: ~/.cache/ (XDG default)
+ Win XP: C:\Documents and Settings\\Local Settings\Application Data\\\Cache
+ Vista: C:\Users\\AppData\Local\\\Cache
+
+ On Windows the only suggestion in the MSDN docs is that local settings go in
+ the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming
+ app data dir (the default returned by `user_data_dir` above). Apps typically
+ put cache data somewhere *under* the given dir here. Some examples:
+ ...\Mozilla\Firefox\Profiles\\Cache
+ ...\Acme\SuperApp\Cache\1.0
+ OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.
+ This can be disabled with the `opinion=False` option.
+ """
+ if system == "win32":
+ if appauthor is None:
+ appauthor = appname
+ path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
+ if appname:
+ if appauthor is not False:
+ path = os.path.join(path, appauthor, appname)
+ else:
+ path = os.path.join(path, appname)
+ if opinion:
+ path = os.path.join(path, "Cache")
+ elif system == 'darwin':
+ path = os.path.expanduser('~/Library/Caches')
+ if appname:
+ path = os.path.join(path, appname)
+ else:
+ path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache'))
+ if appname:
+ path = os.path.join(path, appname)
+ if appname and version:
+ path = os.path.join(path, version)
+ return path
+
+
+def user_state_dir(appname=None, appauthor=None, version=None, roaming=False):
+ r"""Return full path to the user-specific state dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be ".".
+ Only applied when appname is present.
+ "roaming" (boolean, default False) can be set True to use the Windows
+ roaming appdata directory. That means that for users on a Windows
+ network setup for roaming profiles, this user data will be
+ sync'd on login. See
+
+ for a discussion of issues.
+
+ Typical user state directories are:
+ Mac OS X: same as user_data_dir
+ Unix: ~/.local/state/ # or in $XDG_STATE_HOME, if defined
+ Win *: same as user_data_dir
+
+ For Unix, we follow this Debian proposal
+ to extend the XDG spec and support $XDG_STATE_HOME.
+
+ That means, by default "~/.local/state/".
+ """
+ if system in ["win32", "darwin"]:
+ path = user_data_dir(appname, appauthor, None, roaming)
+ else:
+ path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state"))
+ if appname:
+ path = os.path.join(path, appname)
+ if appname and version:
+ path = os.path.join(path, version)
+ return path
+
+
+def user_log_dir(appname=None, appauthor=None, version=None, opinion=True):
+ r"""Return full path to the user-specific log dir for this application.
+
+ "appname" is the name of application.
+ If None, just the system directory is returned.
+ "appauthor" (only used on Windows) is the name of the
+ appauthor or distributing body for this application. Typically
+ it is the owning company name. This falls back to appname. You may
+ pass False to disable it.
+ "version" is an optional version path element to append to the
+ path. You might want to use this if you want multiple versions
+ of your app to be able to run independently. If used, this
+ would typically be ".".
+ Only applied when appname is present.
+ "opinion" (boolean) can be False to disable the appending of
+ "Logs" to the base app data dir for Windows, and "log" to the
+ base cache dir for Unix. See discussion below.
+
+ Typical user log directories are:
+ Mac OS X: ~/Library/Logs/
+ Unix: ~/.cache//log # or under $XDG_CACHE_HOME if defined
+ Win XP: C:\Documents and Settings\\Local Settings\Application Data\\\Logs
+ Vista: C:\Users\\AppData\Local\\\Logs
+
+ On Windows the only suggestion in the MSDN docs is that local settings
+ go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in
+ examples of what some windows apps use for a logs dir.)
+
+ OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA`
+ value for Windows and appends "log" to the user cache dir for Unix.
+ This can be disabled with the `opinion=False` option.
+ """
+ if system == "darwin":
+ path = os.path.join(
+ os.path.expanduser('~/Library/Logs'),
+ appname)
+ elif system == "win32":
+ path = user_data_dir(appname, appauthor, version)
+ version = False
+ if opinion:
+ path = os.path.join(path, "Logs")
+ else:
+ path = user_cache_dir(appname, appauthor, version)
+ version = False
+ if opinion:
+ path = os.path.join(path, "log")
+ if appname and version:
+ path = os.path.join(path, version)
+ return path
+
+
+class AppDirs(object):
+ """Convenience wrapper for getting application dirs."""
+ def __init__(self, appname=None, appauthor=None, version=None,
+ roaming=False, multipath=False):
+ self.appname = appname
+ self.appauthor = appauthor
+ self.version = version
+ self.roaming = roaming
+ self.multipath = multipath
+
+ @property
+ def user_data_dir(self):
+ return user_data_dir(self.appname, self.appauthor,
+ version=self.version, roaming=self.roaming)
+
+ @property
+ def site_data_dir(self):
+ return site_data_dir(self.appname, self.appauthor,
+ version=self.version, multipath=self.multipath)
+
+ @property
+ def user_config_dir(self):
+ return user_config_dir(self.appname, self.appauthor,
+ version=self.version, roaming=self.roaming)
+
+ @property
+ def site_config_dir(self):
+ return site_config_dir(self.appname, self.appauthor,
+ version=self.version, multipath=self.multipath)
+
+ @property
+ def user_cache_dir(self):
+ return user_cache_dir(self.appname, self.appauthor,
+ version=self.version)
+
+ @property
+ def user_state_dir(self):
+ return user_state_dir(self.appname, self.appauthor,
+ version=self.version)
+
+ @property
+ def user_log_dir(self):
+ return user_log_dir(self.appname, self.appauthor,
+ version=self.version)
+
+
+#---- internal support stuff
+
+def _get_win_folder_from_registry(csidl_name):
+ """This is a fallback technique at best. I'm not sure if using the
+ registry for this guarantees us the correct answer for all CSIDL_*
+ names.
+ """
+ if PY3:
+ import winreg as _winreg
+ else:
+ import _winreg
+
+ shell_folder_name = {
+ "CSIDL_APPDATA": "AppData",
+ "CSIDL_COMMON_APPDATA": "Common AppData",
+ "CSIDL_LOCAL_APPDATA": "Local AppData",
+ }[csidl_name]
+
+ key = _winreg.OpenKey(
+ _winreg.HKEY_CURRENT_USER,
+ r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
+ )
+ dir, type = _winreg.QueryValueEx(key, shell_folder_name)
+ return dir
+
+
+def _get_win_folder_with_pywin32(csidl_name):
+ from win32com.shell import shellcon, shell
+ dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0)
+ # Try to make this a unicode path because SHGetFolderPath does
+ # not return unicode strings when there is unicode data in the
+ # path.
+ try:
+ dir = unicode(dir)
+
+ # Downgrade to short path name if have highbit chars. See
+ # .
+ has_high_char = False
+ for c in dir:
+ if ord(c) > 255:
+ has_high_char = True
+ break
+ if has_high_char:
+ try:
+ import win32api
+ dir = win32api.GetShortPathName(dir)
+ except ImportError:
+ pass
+ except UnicodeError:
+ pass
+ return dir
+
+
+def _get_win_folder_with_ctypes(csidl_name):
+ import ctypes
+
+ csidl_const = {
+ "CSIDL_APPDATA": 26,
+ "CSIDL_COMMON_APPDATA": 35,
+ "CSIDL_LOCAL_APPDATA": 28,
+ }[csidl_name]
+
+ buf = ctypes.create_unicode_buffer(1024)
+ ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
+
+ # Downgrade to short path name if have highbit chars. See
+ # .
+ has_high_char = False
+ for c in buf:
+ if ord(c) > 255:
+ has_high_char = True
+ break
+ if has_high_char:
+ buf2 = ctypes.create_unicode_buffer(1024)
+ if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
+ buf = buf2
+
+ return buf.value
+
+def _get_win_folder_with_jna(csidl_name):
+ import array
+ from com.sun import jna
+ from com.sun.jna.platform import win32
+
+ buf_size = win32.WinDef.MAX_PATH * 2
+ buf = array.zeros('c', buf_size)
+ shell = win32.Shell32.INSTANCE
+ shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf)
+ dir = jna.Native.toString(buf.tostring()).rstrip("\0")
+
+ # Downgrade to short path name if have highbit chars. See
+ # .
+ has_high_char = False
+ for c in dir:
+ if ord(c) > 255:
+ has_high_char = True
+ break
+ if has_high_char:
+ buf = array.zeros('c', buf_size)
+ kernel = win32.Kernel32.INSTANCE
+ if kernel.GetShortPathName(dir, buf, buf_size):
+ dir = jna.Native.toString(buf.tostring()).rstrip("\0")
+
+ return dir
+
+if system == "win32":
+ try:
+ import win32com.shell
+ _get_win_folder = _get_win_folder_with_pywin32
+ except ImportError:
+ try:
+ from ctypes import windll
+ _get_win_folder = _get_win_folder_with_ctypes
+ except ImportError:
+ try:
+ import com.sun.jna
+ _get_win_folder = _get_win_folder_with_jna
+ except ImportError:
+ _get_win_folder = _get_win_folder_from_registry
+
+
+#---- self test code
+
+if __name__ == "__main__":
+ appname = "MyApp"
+ appauthor = "MyCompany"
+
+ props = ("user_data_dir",
+ "user_config_dir",
+ "user_cache_dir",
+ "user_state_dir",
+ "user_log_dir",
+ "site_data_dir",
+ "site_config_dir")
+
+ print("-- app dirs %s --" % __version__)
+
+ print("-- app dirs (with optional 'version')")
+ dirs = AppDirs(appname, appauthor, version="1.0")
+ for prop in props:
+ print("%s: %s" % (prop, getattr(dirs, prop)))
+
+ print("\n-- app dirs (without optional 'version')")
+ dirs = AppDirs(appname, appauthor)
+ for prop in props:
+ print("%s: %s" % (prop, getattr(dirs, prop)))
+
+ print("\n-- app dirs (without optional 'appauthor')")
+ dirs = AppDirs(appname)
+ for prop in props:
+ print("%s: %s" % (prop, getattr(dirs, prop)))
+
+ print("\n-- app dirs (with disabled 'appauthor')")
+ dirs = AppDirs(appname, appauthor=False)
+ for prop in props:
+ print("%s: %s" % (prop, getattr(dirs, prop)))
diff --git a/venv/Lib/site-packages/autograd-1.8.0.dist-info/INSTALLER b/venv/Lib/site-packages/autograd-1.8.0.dist-info/INSTALLER
new file mode 100644
index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68
--- /dev/null
+++ b/venv/Lib/site-packages/autograd-1.8.0.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/Lib/site-packages/autograd-1.8.0.dist-info/METADATA b/venv/Lib/site-packages/autograd-1.8.0.dist-info/METADATA
new file mode 100644
index 0000000000000000000000000000000000000000..d07b3cdb6497ae7b2e6fc75f8be18732c93687b0
--- /dev/null
+++ b/venv/Lib/site-packages/autograd-1.8.0.dist-info/METADATA
@@ -0,0 +1,157 @@
+Metadata-Version: 2.4
+Name: autograd
+Version: 1.8.0
+Summary: Efficiently computes derivatives of NumPy code.
+Project-URL: Source, https://github.com/HIPS/autograd
+Author-email: Dougal Maclaurin , David Duvenaud , Matthew Johnson , Jamie Townsend
+Maintainer-email: Jamie Townsend , Fabian Joswig , Agriya Khetarpal
+License: The MIT License (MIT)
+
+ Copyright (c) 2025 by the President and Fellows of Harvard University
+
+ 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.
+Keywords: Automatic differentiation,NumPy,Python,SciPy,backpropagation,gradients,machine learning,neural networks,optimization
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Information Technology
+Classifier: Intended Audience :: Science/Research
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Topic :: Scientific/Engineering
+Requires-Python: >=3.9
+Requires-Dist: numpy<3
+Provides-Extra: scipy
+Requires-Dist: scipy; extra == 'scipy'
+Provides-Extra: test
+Requires-Dist: pytest; extra == 'test'
+Requires-Dist: pytest-cov; extra == 'test'
+Requires-Dist: pytest-xdist; extra == 'test'
+Description-Content-Type: text/markdown
+
+# Autograd [![Checks status][checks-badge]][checks-url] [![Tests status][tests-badge]][tests-url] [![Publish status][publish-badge]][publish-url] [![asv][asv-badge]](#)
+
+[publish-badge]: https://github.com/HIPS/autograd/actions/workflows/publish.yml/badge.svg
+[checks-badge]: https://github.com/HIPS/autograd/actions/workflows/check.yml/badge.svg
+[tests-badge]: https://github.com/HIPS/autograd/actions/workflows/test.yml/badge.svg
+[asv-badge]: http://img.shields.io/badge/benchmarked%20by-asv-green.svg?style=flat
+[publish-url]: https://github.com/HIPS/autograd/actions/workflows/publish.yml
+[checks-url]: https://github.com/HIPS/autograd/actions/workflows/check.yml
+[tests-url]: https://github.com/HIPS/autograd/actions/workflows/test.yml
+
+Autograd can automatically differentiate native Python and Numpy code. It can
+handle a large subset of Python's features, including loops, ifs, recursion and
+closures, and it can even take derivatives of derivatives of derivatives. It
+supports reverse-mode differentiation (a.k.a. backpropagation), which means it
+can efficiently take gradients of scalar-valued functions with respect to
+array-valued arguments, as well as forward-mode differentiation, and the two can
+be composed arbitrarily. The main intended application of Autograd is
+gradient-based optimization. For more information, check out the
+[tutorial](docs/tutorial.md) and the [examples directory](examples/).
+
+Example use:
+
+```python
+>>> import autograd.numpy as np # Thinly-wrapped numpy
+>>> from autograd import grad # The only autograd function you may ever need
+>>>
+>>> def tanh(x): # Define a function
+... return (1.0 - np.exp((-2 * x))) / (1.0 + np.exp(-(2 * x)))
+...
+>>> grad_tanh = grad(tanh) # Obtain its gradient function
+>>> grad_tanh(1.0) # Evaluate the gradient at x = 1.0
+np.float64(0.419974341614026)
+>>> (tanh(1.0001) - tanh(0.9999)) / 0.0002 # Compare to finite differences
+np.float64(0.41997434264973155)
+```
+
+We can continue to differentiate as many times as we like, and use numpy's
+vectorization of scalar-valued functions across many different input values:
+
+```python
+>>> from autograd import elementwise_grad as egrad # for functions that vectorize over inputs
+>>> import matplotlib.pyplot as plt
+>>> x = np.linspace(-7, 7, 700)
+>>> plt.plot(x, tanh(x),
+... x, egrad(tanh)(x), # first derivative
+... x, egrad(egrad(tanh))(x), # second derivative
+... x, egrad(egrad(egrad(tanh)))(x), # third derivative
+... x, egrad(egrad(egrad(egrad(tanh))))(x), # fourth derivative
+>>> plt.show()
+```
+
+
+
+See the [tanh example file](examples/tanh.py) for the code.
+
+## Documentation
+
+You can find a tutorial [here.](docs/tutorial.md)
+
+## End-to-end examples
+
+* [Simple neural net](examples/neural_net.py)
+* [Convolutional neural net](examples/convnet.py)
+* [Recurrent neural net](examples/rnn.py)
+* [LSTM](examples/lstm.py)
+* [Neural Turing Machine](https://github.com/DoctorTeeth/diffmem/blob/512aadeefd6dbafc1bdd253a64b6be192a435dc3/ntm/ntm.py)
+* [Backpropagating through a fluid simulation](examples/fluidsim/fluidsim.py)
+
+
+
+* [Variational inference in Bayesian neural network](examples/bayesian_neural_net.py)
+* [Gaussian process regression](examples/gaussian_process.py)
+* [Sampyl, a pure Python MCMC package with HMC and NUTS](https://github.com/mcleonard/sampyl)
+
+## How to install
+
+Install Autograd using Pip:
+
+```shell
+pip install autograd
+```
+
+Some features require SciPy, which you can install separately or as an
+optional dependency along with Autograd:
+
+```shell
+pip install "autograd[scipy]"
+```
+
+## Authors and maintainers
+
+Autograd was written by [Dougal Maclaurin](https://dougalmaclaurin.com),
+[David Duvenaud](https://www.cs.toronto.edu/~duvenaud/),
+[Matt Johnson](http://people.csail.mit.edu/mattjj/),
+[Jamie Townsend](https://github.com/j-towns)
+and many other contributors. The package is currently being maintained by
+[Agriya Khetarpal](https://github.com/agriyakhetarpal),
+[Fabian Joswig](https://github.com/fjosw) and
+[Jamie Townsend](https://github.com/j-towns).
+Please feel free to submit any bugs or
+feature requests. We'd also love to hear about your experiences with Autograd
+in general. Drop us an email!
+
+We want to thank Jasper Snoek and the rest of the HIPS group (led by Prof. Ryan
+P. Adams) for helpful contributions and advice; Barak Pearlmutter for
+foundational work on automatic differentiation and for guidance on our
+implementation; and Analog Devices Inc. (Lyric Labs) and Samsung Advanced Institute
+of Technology for their generous support.
diff --git a/venv/Lib/site-packages/autograd-1.8.0.dist-info/RECORD b/venv/Lib/site-packages/autograd-1.8.0.dist-info/RECORD
new file mode 100644
index 0000000000000000000000000000000000000000..4abefe4fed6929eb8f368dd6e5a9d0acd3ffac0b
--- /dev/null
+++ b/venv/Lib/site-packages/autograd-1.8.0.dist-info/RECORD
@@ -0,0 +1,78 @@
+autograd-1.8.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+autograd-1.8.0.dist-info/METADATA,sha256=KJWWs0DjmLfTDT6Lb6ViEtHMZlevwHmGdFrFZkOY2lA,7487
+autograd-1.8.0.dist-info/RECORD,,
+autograd-1.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
+autograd/__init__.py,sha256=OdsBCO2iJ6itz_X9JX3aKoaJoCGuUlfWNVQTipNcBYA,528
+autograd/__pycache__/__init__.cpython-311.pyc,,
+autograd/__pycache__/builtins.cpython-311.pyc,,
+autograd/__pycache__/core.cpython-311.pyc,,
+autograd/__pycache__/differential_operators.cpython-311.pyc,,
+autograd/__pycache__/extend.cpython-311.pyc,,
+autograd/__pycache__/test_util.cpython-311.pyc,,
+autograd/__pycache__/tracer.cpython-311.pyc,,
+autograd/__pycache__/util.cpython-311.pyc,,
+autograd/__pycache__/wrap_util.cpython-311.pyc,,
+autograd/builtins.py,sha256=ot5Y2Tc25-23Ns0nHaXbATKtPkEKf_MqpduNRLgGyCQ,6475
+autograd/core.py,sha256=anFx_j_ZSUOZV838hW9lSXDzZlx_5RALOSDN7sN8Rf8,11985
+autograd/differential_operators.py,sha256=vpqCpMoABA7_8gMbwPKNsQK1Xdt7QMyS5cfr8I5WZEo,8468
+autograd/extend.py,sha256=Ovd_pT1Vcui8jn1taUuuKP-3tiXy3eNCJHA9MJTcNMk,317
+autograd/misc/__init__.py,sha256=Eaaaz73YXIzNzdKXCFlbRMBQI6xSE78xBwOVrCcUAsA,62
+autograd/misc/__pycache__/__init__.cpython-311.pyc,,
+autograd/misc/__pycache__/fixed_points.cpython-311.pyc,,
+autograd/misc/__pycache__/flatten.cpython-311.pyc,,
+autograd/misc/__pycache__/optimizers.cpython-311.pyc,,
+autograd/misc/__pycache__/tracers.cpython-311.pyc,,
+autograd/misc/fixed_points.py,sha256=zuzBfcCD2T1L5mExcQJwY7UIJ6MSwzNbD1qNZPnTJ0w,748
+autograd/misc/flatten.py,sha256=od84_4cIMaaBkvYEHHQFxH3Vta-ImmapB0WYq8s0KmM,1125
+autograd/misc/optimizers.py,sha256=XosiBjH4zXcuCBa_HUKU4W9hVhZxjW1kp4gtJYjJukk,2714
+autograd/misc/tracers.py,sha256=zqf2QDtJdfskmJt-ZRAWl2XbYtpM4e1vcG76vSVy68o,2220
+autograd/numpy/__init__.py,sha256=gE9KNPyPr9Bf2PPRS1BRRCpTQ2zUGirWg-wDa7LSfPM,171
+autograd/numpy/__pycache__/__init__.cpython-311.pyc,,
+autograd/numpy/__pycache__/fft.cpython-311.pyc,,
+autograd/numpy/__pycache__/linalg.cpython-311.pyc,,
+autograd/numpy/__pycache__/numpy_boxes.cpython-311.pyc,,
+autograd/numpy/__pycache__/numpy_jvps.cpython-311.pyc,,
+autograd/numpy/__pycache__/numpy_vjps.cpython-311.pyc,,
+autograd/numpy/__pycache__/numpy_vspaces.cpython-311.pyc,,
+autograd/numpy/__pycache__/numpy_wrapper.cpython-311.pyc,,
+autograd/numpy/__pycache__/random.cpython-311.pyc,,
+autograd/numpy/fft.py,sha256=TRkVy2zoedg76epWArC9IFJcLMqCYllNg2JfMK7jKTM,5101
+autograd/numpy/linalg.py,sha256=L-lzZUdxzkRxjq_Xd-XPVnBBAwDphbTkZSUlAY1PZnw,10970
+autograd/numpy/numpy_boxes.py,sha256=2wzdanYHDiAG_yGosqDw-WyudESi0HJXyQbPzmnHoGw,4212
+autograd/numpy/numpy_jvps.py,sha256=QP1GDrjzpeS8nf6a7B3ferzhTnXKewDLN67h1j1FQsg,10115
+autograd/numpy/numpy_vjps.py,sha256=8-ZwZHMApWIfJJ2aWyYVcJHMR3OiN8uoW299gBth0yI,32360
+autograd/numpy/numpy_vspaces.py,sha256=1j6mvNgwJxW0aNve5b-alLJlxXj4yJmzHDiuTfJsHFk,3673
+autograd/numpy/numpy_wrapper.py,sha256=dYWNAUGelJ3mcmoivBblkA4gI_tTRzQpH489ARg40so,5553
+autograd/numpy/random.py,sha256=aNbhrWtqoc02Rwjo_ebX5pBOZUW8RlY6HPAo-kukGGk,111
+autograd/scipy/__init__.py,sha256=8BsQtuGwYgS5401twkj2ZbOZGnLiii1DlAYIYySt-2M,48
+autograd/scipy/__pycache__/__init__.cpython-311.pyc,,
+autograd/scipy/__pycache__/integrate.cpython-311.pyc,,
+autograd/scipy/__pycache__/linalg.cpython-311.pyc,,
+autograd/scipy/__pycache__/signal.cpython-311.pyc,,
+autograd/scipy/__pycache__/special.cpython-311.pyc,,
+autograd/scipy/integrate.py,sha256=n5jPhoU15WSwEfnvt9zvF62O2vjMv7-thQgCYy9k_yM,2782
+autograd/scipy/linalg.py,sha256=_XCDBECHX9mSbOhf_acpE5uAaiUTkmmb2CJGqstv2oI,4291
+autograd/scipy/signal.py,sha256=QwUK_fbnE1OO7ZG8kVULirIcTeJi3PivcageRv9k_Xo,5750
+autograd/scipy/special.py,sha256=dikDHSP3wM_Xek_Tw-D5OoTMCAhAA6aMGQEM0VNikSk,5083
+autograd/scipy/stats/__init__.py,sha256=6VrdQNhYwKCOwsTLuDKN26EndW_zNnyrMh0hvEKG3DI,287
+autograd/scipy/stats/__pycache__/__init__.cpython-311.pyc,,
+autograd/scipy/stats/__pycache__/beta.cpython-311.pyc,,
+autograd/scipy/stats/__pycache__/chi2.cpython-311.pyc,,
+autograd/scipy/stats/__pycache__/dirichlet.cpython-311.pyc,,
+autograd/scipy/stats/__pycache__/gamma.cpython-311.pyc,,
+autograd/scipy/stats/__pycache__/multivariate_normal.cpython-311.pyc,,
+autograd/scipy/stats/__pycache__/norm.cpython-311.pyc,,
+autograd/scipy/stats/__pycache__/poisson.cpython-311.pyc,,
+autograd/scipy/stats/__pycache__/t.cpython-311.pyc,,
+autograd/scipy/stats/beta.py,sha256=ngq3_awip-6N0KeKCEXxgevBM-fiiflmJ8MvjmR6xZw,1334
+autograd/scipy/stats/chi2.py,sha256=RLV8JfXsPD3hOtZcK1chGZGNGEKabhEenT3yud0YzvM,800
+autograd/scipy/stats/dirichlet.py,sha256=eMXu4YRCu4YYRLiuf8r6Es5_aUrk_9mpKD9D_sgn_OE,684
+autograd/scipy/stats/gamma.py,sha256=mfHqghqWp3gb4MTN7Nk1hMQjicT4LBUJ7GFXsHJG_Ac,970
+autograd/scipy/stats/multivariate_normal.py,sha256=b_qP2DRRsxnDtZfcA6T3tk5s3eXWa3U5fT9DJ_RUJbA,2505
+autograd/scipy/stats/norm.py,sha256=dr1iQkFejF4wegwbL_qMkpAq7EW-JnNe7f_W3ueuYYA,2749
+autograd/scipy/stats/poisson.py,sha256=02HRdTJyIr2U5PZw8bhTSgbitEptbfAfZ0uu-msB8vY,684
+autograd/scipy/stats/t.py,sha256=n5fny17Iu7I8ehm7Y_LVbswAmCzBZgThAeL9fNZkF18,2728
+autograd/test_util.py,sha256=0lmHs62YkBHmHDEg-9sL6voSfJL4YMVTfJjhpT1c9Lo,2796
+autograd/tracer.py,sha256=cO9DJg-T6m45XUIgIdqNPu-v1zd0UZIeRtKaeR1VTFU,3906
+autograd/util.py,sha256=4PX0351pgcn2fhPflSdBlu3jaihplbSL9hVKC8fvKfk,1394
+autograd/wrap_util.py,sha256=NB_ww3-5jDbuNaOCB35tE0_okIf6MzYhFrpaBNKiG9M,1635
diff --git a/venv/Lib/site-packages/autograd-1.8.0.dist-info/WHEEL b/venv/Lib/site-packages/autograd-1.8.0.dist-info/WHEEL
new file mode 100644
index 0000000000000000000000000000000000000000..12228d414b6cfed7c39d3781c85c63256a1d7fb5
--- /dev/null
+++ b/venv/Lib/site-packages/autograd-1.8.0.dist-info/WHEEL
@@ -0,0 +1,4 @@
+Wheel-Version: 1.0
+Generator: hatchling 1.27.0
+Root-Is-Purelib: true
+Tag: py3-none-any
diff --git a/venv/Lib/site-packages/autograd/__init__.py b/venv/Lib/site-packages/autograd/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..c177927d108b6aa5ef379a12856dfb13235a6926
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/__init__.py
@@ -0,0 +1,24 @@
+from autograd.core import primitive_with_deprecation_warnings as primitive
+
+from .builtins import dict, isinstance, list, tuple, type
+from .differential_operators import (
+ checkpoint,
+ deriv,
+ elementwise_grad,
+ grad,
+ grad_and_aux,
+ grad_named,
+ hessian,
+ hessian_tensor_product,
+ hessian_vector_product,
+ holomorphic_grad,
+ jacobian,
+ make_ggnvp,
+ make_hvp,
+ make_jvp,
+ make_vjp,
+ multigrad_dict,
+ tensor_jacobian_product,
+ value_and_grad,
+ vector_jacobian_product,
+)
diff --git a/venv/Lib/site-packages/autograd/builtins.py b/venv/Lib/site-packages/autograd/builtins.py
new file mode 100644
index 0000000000000000000000000000000000000000..e62d8457cebac4af92ed14f6d86c8b4367979d1b
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/builtins.py
@@ -0,0 +1,286 @@
+from .extend import (
+ Box,
+ SparseObject,
+ VSpace,
+ defjvp,
+ defjvp_argnum,
+ defvjp,
+ defvjp_argnum,
+ notrace_primitive,
+ primitive,
+ vspace,
+)
+from .util import subvals
+
+isinstance_ = isinstance
+isinstance = notrace_primitive(isinstance)
+
+type_ = type
+type = notrace_primitive(type)
+
+tuple_, list_, dict_ = tuple, list, dict
+
+
+@primitive
+def container_take(A, idx):
+ return A[idx]
+
+
+def grad_container_take(ans, A, idx):
+ return lambda g: container_untake(g, idx, vspace(A))
+
+
+defvjp(container_take, grad_container_take)
+defjvp(container_take, "same")
+
+
+class SequenceBox(Box):
+ __slots__ = []
+ __getitem__ = container_take
+
+ def __len__(self):
+ return len(self._value)
+
+ def __add__(self, other):
+ return sequence_extend_right(self, *other)
+
+ def __radd__(self, other):
+ return sequence_extend_left(self, *other)
+
+ def __contains__(self, elt):
+ return elt in self._value
+
+ def index(self, elt):
+ return self._value.index(elt)
+
+
+SequenceBox.register(tuple_)
+SequenceBox.register(list_)
+
+
+class DictBox(Box):
+ __slots__ = []
+ __getitem__ = container_take
+
+ def __len__(self):
+ return len(self._value)
+
+ def __iter__(self):
+ return self._value.__iter__()
+
+ def __contains__(self, elt):
+ return elt in self._value
+
+ def items(self):
+ return list(self.iteritems())
+
+ def keys(self):
+ return list(self.iterkeys())
+
+ def values(self):
+ return list(self.itervalues())
+
+ def iteritems(self):
+ return ((k, self[k]) for k in self)
+
+ def iterkeys(self):
+ return iter(self)
+
+ def itervalues(self):
+ return (self[k] for k in self)
+
+ def get(self, k, d=None):
+ return self[k] if k in self else d
+
+
+DictBox.register(dict_)
+
+
+@primitive
+def container_untake(x, idx, vs):
+ if isinstance(idx, slice):
+ accum = lambda result: [elt_vs._mut_add(a, b) for elt_vs, a, b in zip(vs.shape[idx], result, x)]
+ else:
+ accum = lambda result: vs.shape[idx]._mut_add(result, x)
+
+ def mut_add(A):
+ return vs._subval(A, idx, accum(A[idx]))
+
+ return SparseObject(vs, mut_add)
+
+
+defvjp(container_untake, lambda ans, x, idx, _: lambda g: container_take(g, idx))
+defjvp(container_untake, "same")
+
+
+@primitive
+def sequence_extend_right(seq, *elts):
+ return seq + type(seq)(elts)
+
+
+def grad_sequence_extend_right(argnum, ans, args, kwargs):
+ seq, elts = args[0], args[1:]
+ return lambda g: g[: len(seq)] if argnum == 0 else g[len(seq) + argnum - 1]
+
+
+defvjp_argnum(sequence_extend_right, grad_sequence_extend_right)
+
+
+@primitive
+def sequence_extend_left(seq, *elts):
+ return type(seq)(elts) + seq
+
+
+def grad_sequence_extend_left(argnum, ans, args, kwargs):
+ seq, elts = args[0], args[1:]
+ return lambda g: g[len(elts) :] if argnum == 0 else g[argnum - 1]
+
+
+defvjp_argnum(sequence_extend_left, grad_sequence_extend_left)
+
+
+@primitive
+def make_sequence(seq_type, *args):
+ return seq_type(args)
+
+
+defvjp_argnum(make_sequence, lambda argnum, *args: lambda g: g[argnum - 1])
+
+
+def fwd_grad_make_sequence(argnum, g, ans, seq_type, *args, **kwargs):
+ return container_untake(g, argnum - 1, vspace(ans))
+
+
+defjvp_argnum(make_sequence, fwd_grad_make_sequence)
+
+
+class TupleMeta(type(tuple_)):
+ def __instancecheck__(self, instance):
+ return isinstance(instance, tuple_)
+
+
+class tuple(tuple_, metaclass=TupleMeta):
+ def __new__(cls, xs):
+ return make_sequence(tuple_, *xs)
+
+
+class ListMeta(type_):
+ def __instancecheck__(self, instance):
+ return isinstance(instance, list_)
+
+
+class list(list_, metaclass=ListMeta):
+ def __new__(cls, xs):
+ return make_sequence(list_, *xs)
+
+
+class DictMeta(type_):
+ def __instancecheck__(self, instance):
+ return isinstance(instance, dict_)
+
+
+class dict(dict_, metaclass=DictMeta):
+ def __new__(cls, *args, **kwargs):
+ result = dict_(*args, **kwargs)
+ if result:
+ return _make_dict(result.keys(), list(result.values()))
+ return result
+
+
+@primitive
+def _make_dict(keys, vals):
+ return dict_(zip(keys, vals))
+
+
+defvjp(_make_dict, lambda ans, keys, vals: lambda g: list(g[key] for key in keys), argnums=(1,))
+
+
+class ContainerVSpace(VSpace):
+ def __init__(self, value):
+ self.shape = value
+ self.shape = self._map(vspace)
+
+ @property
+ def size(self):
+ return sum(self._values(self._map(lambda vs: vs.size)))
+
+ def zeros(self):
+ return self._map(lambda vs: vs.zeros())
+
+ def ones(self):
+ return self._map(lambda vs: vs.ones())
+
+ def randn(self):
+ return self._map(lambda vs: vs.randn())
+
+ def standard_basis(self):
+ zero = self.zeros()
+ for i, vs in self._kv_pairs(self.shape):
+ for x in vs.standard_basis():
+ yield self._subval(zero, i, x)
+
+ def _add(self, xs, ys):
+ return self._map(lambda vs, x, y: vs._add(x, y), xs, ys)
+
+ def _mut_add(self, xs, ys):
+ return self._map(lambda vs, x, y: vs._mut_add(x, y), xs, ys)
+
+ def _scalar_mul(self, xs, a):
+ return self._map(lambda vs, x: vs._scalar_mul(x, a), xs)
+
+ def _inner_prod(self, xs, ys):
+ return sum(self._values(self._map(lambda vs, x, y: vs._inner_prod(x, y), xs, ys)))
+
+ def _covector(self, xs):
+ return self._map(lambda vs, x: vs._covector(x), xs)
+
+
+class SequenceVSpace(ContainerVSpace):
+ def _values(self, x):
+ return x
+
+ def _kv_pairs(self, x):
+ return enumerate(x)
+
+ def _map(self, f, *args):
+ return self.seq_type(map(f, self.shape, *args))
+
+ def _subval(self, xs, idx, x):
+ return self.seq_type(subvals(xs, [(idx, x)]))
+
+
+class ListVSpace(SequenceVSpace):
+ seq_type = list_
+
+
+class TupleVSpace(SequenceVSpace):
+ seq_type = tuple_
+
+
+class DictVSpace(ContainerVSpace):
+ def _values(self, x):
+ return x.values()
+
+ def _kv_pairs(self, x):
+ return x.items()
+
+ def _map(self, f, *args):
+ return {k: f(vs, *[x[k] for x in args]) for k, vs in self.shape.items()}
+
+ def _subval(self, xs, idx, x):
+ d = dict(xs.items())
+ d[idx] = x
+ return d
+
+
+ListVSpace.register(list_)
+TupleVSpace.register(tuple_)
+DictVSpace.register(dict_)
+
+
+class NamedTupleVSpace(SequenceVSpace):
+ def _map(self, f, *args):
+ return self.seq_type(*map(f, self.shape, *args))
+
+ def _subval(self, xs, idx, x):
+ return self.seq_type(*subvals(xs, [(idx, x)]))
diff --git a/venv/Lib/site-packages/autograd/core.py b/venv/Lib/site-packages/autograd/core.py
new file mode 100644
index 0000000000000000000000000000000000000000..2116589bafffe9d95444d349bc221d76c5a89807
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/core.py
@@ -0,0 +1,416 @@
+from functools import reduce
+from itertools import count
+
+from .tracer import Box, Node, getval, isbox, primitive, toposort, trace
+from .util import func, subval
+
+# -------------------- reverse mode --------------------
+
+
+def make_vjp(fun, x):
+ start_node = VJPNode.new_root()
+ end_value, end_node = trace(start_node, fun, x)
+ if end_node is None:
+
+ def vjp(g):
+ return vspace(x).zeros()
+ else:
+
+ def vjp(g):
+ return backward_pass(g, end_node)
+
+ return vjp, end_value
+
+
+def backward_pass(g, end_node):
+ outgrads = {end_node: (g, False)}
+ for node in toposort(end_node):
+ outgrad = outgrads.pop(node)
+ ingrads = node.vjp(outgrad[0])
+ for parent, ingrad in zip(node.parents, ingrads):
+ outgrads[parent] = add_outgrads(outgrads.get(parent), ingrad)
+ return outgrad[0]
+
+
+class VJPNode(Node):
+ __slots__ = ["parents", "vjp"]
+
+ def __init__(self, value, fun, args, kwargs, parent_argnums, parents):
+ self.parents = parents
+ try:
+ vjpmaker = primitive_vjps[fun]
+ except KeyError:
+ fun_name = getattr(fun, "__name__", fun)
+ raise NotImplementedError(f"VJP of {fun_name} wrt argnums {parent_argnums} not defined")
+ self.vjp = vjpmaker(parent_argnums, value, args, kwargs)
+
+ def initialize_root(self):
+ self.parents = []
+ self.vjp = lambda g: ()
+
+
+primitive_vjps = {}
+
+
+def defvjp_argnums(fun, vjpmaker):
+ primitive_vjps[fun] = vjpmaker
+
+
+def defvjp_argnum(fun, vjpmaker):
+ def vjp_argnums(argnums, *args):
+ vjps = [vjpmaker(argnum, *args) for argnum in argnums]
+ return lambda g: (vjp(g) for vjp in vjps)
+
+ defvjp_argnums(fun, vjp_argnums)
+
+
+def defvjp(fun, *vjpmakers, **kwargs):
+ argnums = kwargs.get("argnums", count())
+ vjps_dict = {
+ argnum: translate_vjp(vjpmaker, fun, argnum) for argnum, vjpmaker in zip(argnums, vjpmakers)
+ }
+
+ def vjp_argnums(argnums, ans, args, kwargs):
+ L = len(argnums)
+ # These first two cases are just optimizations
+ if L == 1:
+ argnum = argnums[0]
+ try:
+ vjpfun = vjps_dict[argnum]
+ except KeyError:
+ raise NotImplementedError(f"VJP of {fun.__name__} wrt argnum 0 not defined")
+ vjp = vjpfun(ans, *args, **kwargs)
+ return lambda g: (vjp(g),)
+ elif L == 2:
+ argnum_0, argnum_1 = argnums
+ try:
+ vjp_0_fun = vjps_dict[argnum_0]
+ vjp_1_fun = vjps_dict[argnum_1]
+ except KeyError:
+ raise NotImplementedError(f"VJP of {fun.__name__} wrt argnums 0, 1 not defined")
+ vjp_0 = vjp_0_fun(ans, *args, **kwargs)
+ vjp_1 = vjp_1_fun(ans, *args, **kwargs)
+ return lambda g: (vjp_0(g), vjp_1(g))
+ else:
+ vjps = [vjps_dict[argnum](ans, *args, **kwargs) for argnum in argnums]
+ return lambda g: (vjp(g) for vjp in vjps)
+
+ defvjp_argnums(fun, vjp_argnums)
+
+
+def translate_vjp(vjpfun, fun, argnum):
+ if vjpfun is None:
+ return lambda ans, *args, **kwargs: lambda g: vspace(args[argnum]).zeros()
+ elif callable(vjpfun):
+ return vjpfun
+ else:
+ raise Exception(f"Bad VJP '{vjpfun}' for '{fun.__name__}'")
+
+
+# -------------------- forward mode --------------------
+
+
+def make_jvp(fun, x):
+ def jvp(g):
+ start_node = JVPNode.new_root(g)
+ end_value, end_node = trace(start_node, fun, x)
+ if end_node is None:
+ return end_value, vspace(end_value).zeros()
+ else:
+ return end_value, end_node.g
+
+ return jvp
+
+
+class JVPNode(Node):
+ __slots__ = ["g"]
+
+ def __init__(self, value, fun, args, kwargs, parent_argnums, parents):
+ parent_gs = [parent.g for parent in parents]
+ try:
+ jvpmaker = primitive_jvps[fun]
+ except KeyError:
+ name = getattr(fun, "__name__", fun)
+ raise NotImplementedError(f"JVP of {name} wrt argnums {parent_argnums} not defined")
+ self.g = jvpmaker(parent_argnums, parent_gs, value, args, kwargs)
+
+ def initialize_root(self, g):
+ self.g = g
+
+
+primitive_jvps = {}
+
+
+def defjvp_argnums(fun, jvpmaker):
+ primitive_jvps[fun] = jvpmaker
+
+
+def defjvp_argnum(fun, jvpmaker):
+ def jvp_argnums(argnums, gs, ans, args, kwargs):
+ return sum_outgrads(jvpmaker(argnum, g, ans, args, kwargs) for argnum, g in zip(argnums, gs))
+
+ defjvp_argnums(fun, jvp_argnums)
+
+
+def defjvp(fun, *jvpfuns, **kwargs):
+ argnums = kwargs.get("argnums", count())
+ jvps_dict = {argnum: translate_jvp(jvpfun, fun, argnum) for argnum, jvpfun in zip(argnums, jvpfuns)}
+
+ def jvp_argnums(argnums, gs, ans, args, kwargs):
+ return sum_outgrads(jvps_dict[argnum](g, ans, *args, **kwargs) for argnum, g in zip(argnums, gs))
+
+ defjvp_argnums(fun, jvp_argnums)
+
+
+def translate_jvp(jvpfun, fun, argnum):
+ if jvpfun is None:
+ return lambda g, ans, *a, **k: vspace(ans).zeros()
+ elif jvpfun == "same":
+ return lambda g, ans, *args, **kwargs: fun(*subval(args, argnum, g), **kwargs)
+ elif callable(jvpfun):
+ return jvpfun
+ else:
+ raise Exception(f"Bad JVP '{jvpfun}' for '{fun.__name__}'")
+
+
+def def_linear(fun):
+ """Flags that a function is linear wrt all args"""
+ defjvp_argnum(fun, lambda argnum, g, ans, args, kwargs: fun(*subval(args, argnum, g), **kwargs))
+
+
+# -------------------- vector behavior --------------------
+
+
+def add_outgrads(prev_g_flagged, g):
+ sparse = type(g) in sparse_object_types
+ if prev_g_flagged:
+ vs = vspace(g)
+ prev_g, mutable = prev_g_flagged
+ if mutable:
+ if sparse:
+ return sparse_add(vs, prev_g, g), True
+ else:
+ return vs.mut_add(prev_g, g), True
+ else:
+ if sparse:
+ prev_g_mutable = vs.mut_add(None, prev_g)
+ return sparse_add(vs, prev_g_mutable, g), True
+ else:
+ return vs.add(prev_g, g), True
+ else:
+ if sparse:
+ return sparse_add(vspace(g), None, g), True
+ else:
+ return g, False
+
+
+def sum_outgrads(gs):
+ return reduce(add_outgrads, gs, None)[0]
+
+
+@primitive
+def sparse_add(vs, x_prev, x_new):
+ x_prev = x_prev if x_prev is not None else vs.zeros()
+ return x_new.mut_add(x_prev)
+
+
+class VSpace:
+ __slots__ = []
+ mappings = {}
+ iscomplex = False
+
+ def __init__(self, value):
+ pass
+
+ def zeros(self):
+ assert False, repr(self)
+
+ def ones(self):
+ assert False, repr(self)
+
+ def standard_basis(self):
+ assert False, repr(self)
+
+ def randn(self):
+ assert False, repr(self)
+
+ @primitive
+ def mut_add(self, x_prev, x_new):
+ x_prev = x_prev if x_prev is not None else self.zeros()
+ return self._mut_add(x_prev, x_new)
+
+ @primitive
+ def add(self, x_prev, x_new):
+ return self._add(x_prev, x_new)
+
+ @primitive
+ def scalar_mul(self, x, a):
+ return self._scalar_mul(x, a)
+
+ @primitive
+ def inner_prod(self, x, y):
+ return self._inner_prod(x, y)
+
+ @primitive
+ def covector(self, x):
+ return self._covector(x)
+
+ def _add(self, x, y):
+ return x + y
+
+ def _mut_add(self, x, y):
+ x += y
+ return x
+
+ def _scalar_mul(self, x, a):
+ return x * a
+
+ def _inner_prod(self, x, y):
+ assert False
+
+ def _covector(self, x):
+ return x
+
+ def __eq__(self, other):
+ return type(self) == type(other) and self.__dict__ == other.__dict__
+
+ def __repr__(self):
+ return f"{type(self).__name__}_{self.__dict__}"
+
+ @classmethod
+ def register(cls, value_type, vspace_maker=None):
+ if vspace_maker:
+ VSpace.mappings[value_type] = vspace_maker
+ else:
+ VSpace.mappings[value_type] = cls
+
+
+def vspace(value):
+ try:
+ return VSpace.mappings[type(value)](value)
+ except KeyError:
+ if isbox(value):
+ return vspace(getval(value))
+ else:
+ raise TypeError(
+ "Can't find vector space for value {} of type {}. Valid types are {}".format(
+ value, type(value), VSpace.mappings.keys()
+ )
+ )
+
+
+class SparseBox(Box):
+ __slots__ = []
+
+
+class SparseObject:
+ __slots__ = ["vs", "mut_add"]
+
+ def __init__(self, vs, mut_add):
+ self.vs = vs
+ self.mut_add = mut_add
+
+
+VSpace.register(SparseObject, lambda x: x.vs)
+SparseBox.register(SparseObject)
+sparse_object_types = {SparseObject, SparseBox}
+
+# -------------------- core reverse mode grads --------------------
+
+identity_vjp = lambda argnums, *args: lambda g: g
+defvjp(sparse_add, None, identity_vjp, identity_vjp)
+defvjp(func(VSpace.add), None, identity_vjp, identity_vjp)
+defvjp(func(VSpace.mut_add), None, identity_vjp, identity_vjp)
+defvjp(
+ func(VSpace.inner_prod),
+ None,
+ lambda ans, vs, x, y: lambda g: vs.covector(vs.scalar_mul(y, g)),
+ lambda ans, vs, x, y: lambda g: vs.covector(vs.scalar_mul(x, g)),
+)
+defvjp(func(VSpace.covector), None, lambda ans, vs, x: lambda g: vs.covector(g))
+defvjp(
+ func(VSpace.scalar_mul),
+ None,
+ lambda ans, vs, x, a: lambda g: vs.covector(vs.scalar_mul(vs.covector(g), a)),
+ lambda ans, vs, x, a: lambda g: vs.inner_prod(g, vs.covector(x)),
+)
+
+# -------------------- core forward mode grads --------------------
+
+identity_jvp = lambda g, *args, **kwargs: g
+defjvp(sparse_add, None, identity_jvp, identity_jvp)
+defjvp(func(VSpace.mut_add), None, identity_jvp, identity_jvp)
+defjvp(func(VSpace.add), None, identity_jvp, identity_jvp)
+defjvp(func(VSpace.scalar_mul), None, "same", "same")
+defjvp(func(VSpace.inner_prod), None, "same", "same")
+defjvp(func(VSpace.covector), None, "same")
+
+# -------------------- deprecation warnings -----------------------
+
+import warnings
+
+deprecated_defvjp_message = """
+The {} method is deprecated. See the update guide and tutorial:
+https://github.com/HIPS/autograd/blob/master/docs/updateguide.md
+https://github.com/HIPS/autograd/blob/master/docs/tutorial.md"""
+
+
+def deprecated_defvjp(primitive_fun):
+ deprecation_msg = deprecated_defvjp_message.format("defvjp")
+ vjpfuns = {}
+
+ def defvjp_unstaged(vjpmaker, argnum=0):
+ warnings.warn(deprecation_msg)
+
+ def staged_vjpmaker(ans, *args, **kwargs):
+ def vjp(g):
+ vs, gvs = vspace(args[argnum]), vspace(g)
+ return vjpmaker(g, ans, vs, gvs, *args, **kwargs)
+
+ return vjp
+
+ vjpfuns[argnum] = staged_vjpmaker
+ argnums, vjpmakers = zip(*[(argnum, vjpfuns[argnum]) for argnum in sorted(vjpfuns.keys())])
+ defvjp(primitive_fun, *vjpmakers, argnums=argnums)
+
+ return defvjp_unstaged
+
+
+def deprecated_defvjp_is_zero(primitive_fun):
+ deprecation_msg = deprecated_defvjp_message.format("defvjp_is_zero")
+ zero_vjps = [set()]
+
+ def defvjp_is_zero(argnums=(0,)):
+ warnings.warn(deprecation_msg)
+ zero_vjps[0] |= set(argnums)
+ nones = [None] * len(zero_vjps[0])
+ defvjp(primitive_fun, *nones, argnums=sorted(zero_vjps[0]))
+
+ return defvjp_is_zero
+
+
+def deprecated_defgrad(primitive_fun):
+ deprecation_msg = deprecated_defvjp_message.format("defgrad")
+ gradfuns = {}
+
+ def defgrad(gradfun, argnum=0):
+ warnings.warn(deprecation_msg)
+ gradfuns[argnum] = gradfun
+ argnums, vjpmakers = zip(*[(argnum, gradfuns[argnum]) for argnum in sorted(gradfuns.keys())])
+ defvjp(primitive_fun, *vjpmakers, argnums=argnums)
+
+ return defgrad
+
+
+primitive_ = primitive
+
+
+def primitive_with_deprecation_warnings(f_raw):
+ f_wrapped = primitive_(f_raw)
+ f_wrapped.defvjp = deprecated_defvjp(f_wrapped)
+ f_wrapped.defvjp_is_zero = deprecated_defvjp_is_zero(f_wrapped)
+ f_wrapped.defgrad = deprecated_defgrad(f_wrapped)
+ return f_wrapped
+
+
+primitive = primitive_with_deprecation_warnings
diff --git a/venv/Lib/site-packages/autograd/differential_operators.py b/venv/Lib/site-packages/autograd/differential_operators.py
new file mode 100644
index 0000000000000000000000000000000000000000..21c35eed612e1432e9ebac9419dd1f03fedd46bf
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/differential_operators.py
@@ -0,0 +1,242 @@
+"""Convenience functions built on top of `make_vjp`."""
+
+from collections import OrderedDict
+
+try:
+ from inspect import getfullargspec as _getargspec # Python 3
+except ImportError:
+ from inspect import getargspec as _getargspec # Python 2
+import warnings
+
+import autograd.numpy as np
+
+from .builtins import tuple as atuple
+from .core import make_jvp as _make_jvp
+from .core import make_vjp as _make_vjp
+from .extend import defvjp_argnum, primitive, vspace
+from .wrap_util import unary_to_nary
+
+make_vjp = unary_to_nary(_make_vjp)
+make_jvp = unary_to_nary(_make_jvp)
+
+
+@unary_to_nary
+def grad(fun, x):
+ """
+ Returns a function which computes the gradient of `fun` with respect to
+ positional argument number `argnum`. The returned function takes the same
+ arguments as `fun`, but returns the gradient instead. The function `fun`
+ should be scalar-valued. The gradient has the same type as the argument."""
+ vjp, ans = _make_vjp(fun, x)
+ if not vspace(ans).size == 1:
+ raise TypeError(
+ "Grad only applies to real scalar-output functions. "
+ "Try jacobian, elementwise_grad or holomorphic_grad."
+ )
+ return vjp(vspace(ans).ones())
+
+
+@unary_to_nary
+def elementwise_grad(fun, x):
+ """
+ Returns a function that computes the sum of each column of the Jacobian of
+ `fun`, in one pass. If the Jacobian is diagonal, then this is the diagonal
+ of the Jacobian.
+ """
+ vjp, ans = _make_vjp(fun, x)
+ if vspace(ans).iscomplex:
+ raise TypeError("Elementwise_grad only applies to real-output functions.")
+ return vjp(vspace(ans).ones())
+
+
+@unary_to_nary
+def deriv(fun, x):
+ return _make_jvp(fun, x)(vspace(x).ones())[1]
+
+
+@unary_to_nary
+def jacobian(fun, x):
+ """
+ Returns a function which computes the Jacobian of `fun` with respect to
+ positional argument number `argnum`, which must be a scalar or array. Unlike
+ `grad` it is not restricted to scalar-output functions, but also it cannot
+ take derivatives with respect to some argument types (like lists or dicts).
+ If the input to `fun` has shape (in1, in2, ...) and the output has shape
+ (out1, out2, ...) then the Jacobian has shape (out1, out2, ..., in1, in2, ...).
+ """
+ vjp, ans = _make_vjp(fun, x)
+ ans_vspace = vspace(ans)
+ jacobian_shape = ans_vspace.shape + vspace(x).shape
+ grads = map(vjp, ans_vspace.standard_basis())
+ return np.reshape(np.stack(grads), jacobian_shape)
+
+
+@unary_to_nary
+def holomorphic_grad(fun, x):
+ if not vspace(x).iscomplex:
+ warnings.warn("Input to holomorphic_grad is not complex")
+ return grad(lambda x: np.real(fun(x)))(x)
+
+
+def grad_named(fun, argname):
+ """Takes gradients with respect to a named argument.
+ Doesn't work on *args or **kwargs."""
+ arg_index = _getargspec(fun).args.index(argname)
+ return grad(fun, arg_index)
+
+
+@unary_to_nary
+def hessian(fun, x):
+ "Returns a function that computes the exact Hessian."
+ return jacobian(jacobian(fun))(x)
+
+
+@unary_to_nary
+def make_hvp(fun, x):
+ """Builds a function for evaluating the Hessian-vector product at a point,
+ which may be useful when evaluating many Hessian-vector products at the same
+ point while caching the results of the forward pass."""
+ return _make_vjp(grad(fun), x)
+
+
+def hessian_tensor_product(fun, argnum=0):
+ """Builds a function that returns the exact Hessian-tensor product.
+ The returned function has arguments (*args, tensor, **kwargs), and for
+ vectors takes roughly 4x as long to evaluate as the original function."""
+ fun_grad = grad(fun, argnum)
+
+ def vector_dot_grad(*args, **kwargs):
+ args, vector = args[:-1], args[-1]
+ return np.tensordot(fun_grad(*args, **kwargs), vector, np.ndim(vector))
+
+ return grad(vector_dot_grad, argnum)
+
+
+hessian_vector_product = hessian_tensor_product
+
+
+def tensor_jacobian_product(fun, argnum=0):
+ """Builds a function that returns the exact tensor-Jacobian product, that
+ is the Jacobian matrix left-multiplied by tensor. The returned function
+ has arguments (*args, tensor, **kwargs)."""
+
+ def vector_dot_fun(*args, **kwargs):
+ args, vector = args[:-1], args[-1]
+ return np.tensordot(vector, fun(*args, **kwargs), axes=np.ndim(vector))
+
+ return jacobian(vector_dot_fun, argnum)
+
+
+vector_jacobian_product = tensor_jacobian_product
+
+
+@unary_to_nary
+def make_jvp_reversemode(fun, x):
+ """Builds a function for evaluating the Jacobian-vector product at a
+ point. Roughly 1.5x more FLOPs than forward-mode, plus memory requirements
+ that scale with the number of primitives applied in the evaluation of f, as
+ well as other overheads. See j-towns.github.io/2017/06/12/A-new-trick.html."""
+ vjp, y = _make_vjp(fun, x)
+ vjp_vjp, _ = _make_vjp(vjp, vspace(y).zeros())
+ return vjp_vjp # vjp_vjp is just jvp by linearity
+
+
+# TODO(mattjj): update this function using make_jvp and const_graph
+def make_ggnvp(f, g=lambda x: 1.0 / 2 * np.sum(x**2, axis=-1), f_argnum=0):
+ """Builds a function for evaluating generalized-Gauss-Newton-vector products
+ at a point. Slightly more expensive than mixed-mode."""
+
+ @unary_to_nary
+ def _make_ggnvp(f, x):
+ f_vjp, f_x = _make_vjp(f, x)
+ g_hvp, grad_g_x = _make_vjp(grad(g), f_x)
+ f_jvp, _ = _make_vjp(f_vjp, vspace(grad_g_x).zeros())
+
+ def ggnvp(v):
+ return f_vjp(g_hvp(f_jvp(v)))
+
+ return ggnvp
+
+ return _make_ggnvp(f, f_argnum)
+
+
+@unary_to_nary
+def value_and_grad(fun, x):
+ """Returns a function that returns both value and gradient. Suitable for use
+ in scipy.optimize"""
+ vjp, ans = _make_vjp(fun, x)
+ if not vspace(ans).size == 1:
+ raise TypeError(
+ "value_and_grad only applies to real scalar-output "
+ "functions. Try jacobian, elementwise_grad or "
+ "holomorphic_grad."
+ )
+ return ans, vjp(vspace(ans).ones())
+
+
+@unary_to_nary
+def grad_and_aux(fun, x):
+ """Builds a function that returns the gradient of the first output and the
+ (unmodified) second output of a function that returns two outputs."""
+ vjp, (ans, aux) = _make_vjp(lambda x: atuple(fun(x)), x)
+ return vjp((vspace(ans).ones(), vspace(aux).zeros())), aux
+
+
+def multigrad_dict(fun):
+ "Takes gradients wrt all arguments simultaneously,"
+ "returns a dict mapping 'argname' to 'gradval'"
+
+ import funcsigs
+
+ sig = funcsigs.signature(fun)
+
+ def select(preds, lst):
+ idx = lambda item: next((i for i, pred in enumerate(preds) if pred(item)), len(preds))
+ results = [[] for _ in preds] + [[]]
+ for item in lst:
+ results[idx(item)].append(item)
+ return results
+
+ is_var_pos = lambda name: sig.parameters[name].kind == sig.parameters[name].VAR_POSITIONAL
+ is_var_kwd = lambda name: sig.parameters[name].kind == sig.parameters[name].VAR_KEYWORD
+ var_pos, var_kwd, argnames = select([is_var_pos, is_var_kwd], sig.parameters)
+
+ todict = lambda dct: {key: dct[key] for key in dct}
+
+ def apply_defaults(arguments):
+ defaults = {
+ name: param.default for name, param in sig.parameters.items() if param.default is not param.empty
+ }
+ return OrderedDict(
+ (name, arguments[name] if name in arguments else defaults[name]) for name in sig.parameters
+ )
+
+ def gradfun(*args, **kwargs):
+ bindings = sig.bind(*args, **kwargs)
+
+ args = lambda dct: tuple(dct[var_pos[0]]) if var_pos else ()
+ kwargs = lambda dct: todict(dct[var_kwd[0]]) if var_kwd else {}
+ others = lambda dct: tuple(dct[argname] for argname in argnames if argname not in var_kwd + var_pos)
+
+ newfun = lambda dct: fun(*(others(dct) + args(dct)), **kwargs(dct))
+
+ argdict = apply_defaults(bindings.arguments)
+ grad_dict = grad(newfun)(dict(argdict))
+ return OrderedDict((argname, grad_dict[argname]) for argname in argdict)
+
+ return gradfun
+
+
+def checkpoint(fun):
+ """Returns a checkpointed version of `fun`, where intermediate values
+ computed during the forward pass of `fun` are discarded and then recomputed
+ for the backward pass. Useful to save memory, effectively trading off time
+ and memory. See e.g. arxiv.org/abs/1604.06174.
+ """
+
+ def wrapped_grad(argnum, ans, args, kwargs):
+ return make_vjp(fun, argnum)(*args, **kwargs)[0]
+
+ wrapped = primitive(fun)
+ defvjp_argnum(wrapped, wrapped_grad)
+ return wrapped
diff --git a/venv/Lib/site-packages/autograd/extend.py b/venv/Lib/site-packages/autograd/extend.py
new file mode 100644
index 0000000000000000000000000000000000000000..7c0638ee10851cde19aba0cd77e9ba0ab7f8cfba
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/extend.py
@@ -0,0 +1,16 @@
+# Exposes API for extending autograd
+from .core import (
+ JVPNode,
+ SparseObject,
+ VJPNode,
+ VSpace,
+ def_linear,
+ defjvp,
+ defjvp_argnum,
+ defjvp_argnums,
+ defvjp,
+ defvjp_argnum,
+ defvjp_argnums,
+ vspace,
+)
+from .tracer import Box, notrace_primitive, primitive, register_notrace
diff --git a/venv/Lib/site-packages/autograd/misc/__init__.py b/venv/Lib/site-packages/autograd/misc/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..4f77dbf48e5c9833187731150cf25e6060fbf860
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/misc/__init__.py
@@ -0,0 +1,2 @@
+from .flatten import flatten
+from .tracers import const_graph
diff --git a/venv/Lib/site-packages/autograd/misc/fixed_points.py b/venv/Lib/site-packages/autograd/misc/fixed_points.py
new file mode 100644
index 0000000000000000000000000000000000000000..aab87a2da04f4f1c19b54e3c5866f4bf429f90cd
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/misc/fixed_points.py
@@ -0,0 +1,26 @@
+from autograd import make_vjp
+from autograd.builtins import tuple
+from autograd.extend import defvjp, primitive, vspace
+
+
+@primitive
+def fixed_point(f, a, x0, distance, tol):
+ _f = f(a)
+ x, x_prev = _f(x0), x0
+ while distance(x, x_prev) > tol:
+ x, x_prev = _f(x), x
+ return x
+
+
+def fixed_point_vjp(ans, f, a, x0, distance, tol):
+ def rev_iter(params):
+ a, x_star, x_star_bar = params
+ vjp_x, _ = make_vjp(f(a))(x_star)
+ vs = vspace(x_star)
+ return lambda g: vs.add(vjp_x(g), x_star_bar)
+
+ vjp_a, _ = make_vjp(lambda x, y: f(x)(y))(a, ans)
+ return lambda g: vjp_a(fixed_point(rev_iter, tuple((a, ans, g)), vspace(x0).zeros(), distance, tol))
+
+
+defvjp(fixed_point, None, fixed_point_vjp, None)
diff --git a/venv/Lib/site-packages/autograd/misc/flatten.py b/venv/Lib/site-packages/autograd/misc/flatten.py
new file mode 100644
index 0000000000000000000000000000000000000000..7a600d7a3be76c7a6b529b85f26c65a860e02036
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/misc/flatten.py
@@ -0,0 +1,38 @@
+"""
+Handy functions for flattening nested containers containing numpy
+arrays. The main purpose is to make examples and optimizers simpler.
+"""
+
+import autograd.numpy as np
+from autograd import make_vjp
+from autograd.builtins import type
+
+
+def flatten(value):
+ """Flattens any nesting of tuples, lists, or dicts, with numpy arrays or
+ scalars inside. Returns 1D numpy array and an unflatten function.
+ Doesn't preserve mixed numeric types (e.g. floats and ints). Assumes dict
+ keys are sortable."""
+ unflatten, flat_value = make_vjp(_flatten)(value)
+ return flat_value, unflatten
+
+
+def _flatten(value):
+ t = type(value)
+ if t in (list, tuple):
+ return _concatenate(map(_flatten, value))
+ elif t is dict:
+ return _concatenate(_flatten(value[k]) for k in sorted(value))
+ else:
+ return np.ravel(value)
+
+
+def _concatenate(lst):
+ lst = list(lst)
+ return np.concatenate(lst) if lst else np.array([])
+
+
+def flatten_func(func, example):
+ _ex, unflatten = flatten(example)
+ _func = lambda _x, *args: flatten(func(unflatten(_x), *args))[0]
+ return _func, unflatten, _ex
diff --git a/venv/Lib/site-packages/autograd/misc/optimizers.py b/venv/Lib/site-packages/autograd/misc/optimizers.py
new file mode 100644
index 0000000000000000000000000000000000000000..d2ee2d70d708126dfde23fb22d3b299be62be588
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/misc/optimizers.py
@@ -0,0 +1,75 @@
+"""Some standard gradient-based stochastic optimizers.
+
+These are just standard routines that don't make any use of autograd,
+though you could take gradients of these functions too if you want
+to do meta-optimization.
+
+These routines can optimize functions whose inputs are structured
+objects, such as dicts of numpy arrays."""
+
+import autograd.numpy as np
+from autograd.misc import flatten
+from autograd.wrap_util import wraps
+
+
+def unflatten_optimizer(optimize):
+ """Takes an optimizer that operates on flat 1D numpy arrays and returns a
+ wrapped version that handles trees of nested containers (lists/tuples/dicts)
+ with arrays/scalars at the leaves."""
+
+ @wraps(optimize)
+ def _optimize(grad, x0, callback=None, *args, **kwargs):
+ _x0, unflatten = flatten(x0)
+ _grad = lambda x, i: flatten(grad(unflatten(x), i))[0]
+ if callback:
+ _callback = lambda x, i, g: callback(unflatten(x), i, unflatten(g))
+ else:
+ _callback = None
+ return unflatten(optimize(_grad, _x0, _callback, *args, **kwargs))
+
+ return _optimize
+
+
+@unflatten_optimizer
+def sgd(grad, x, callback=None, num_iters=200, step_size=0.1, mass=0.9):
+ """Stochastic gradient descent with momentum.
+ grad() must have signature grad(x, i), where i is the iteration number."""
+ velocity = np.zeros(len(x))
+ for i in range(num_iters):
+ g = grad(x, i)
+ if callback:
+ callback(x, i, g)
+ velocity = mass * velocity - (1.0 - mass) * g
+ x = x + step_size * velocity
+ return x
+
+
+@unflatten_optimizer
+def rmsprop(grad, x, callback=None, num_iters=100, step_size=0.1, gamma=0.9, eps=10**-8):
+ """Root mean squared prop: See Adagrad paper for details."""
+ avg_sq_grad = np.ones(len(x))
+ for i in range(num_iters):
+ g = grad(x, i)
+ if callback:
+ callback(x, i, g)
+ avg_sq_grad = avg_sq_grad * gamma + g**2 * (1 - gamma)
+ x = x - step_size * g / (np.sqrt(avg_sq_grad) + eps)
+ return x
+
+
+@unflatten_optimizer
+def adam(grad, x, callback=None, num_iters=100, step_size=0.001, b1=0.9, b2=0.999, eps=10**-8):
+ """Adam as described in http://arxiv.org/pdf/1412.6980.pdf.
+ It's basically RMSprop with momentum and some correction terms."""
+ m = np.zeros(len(x))
+ v = np.zeros(len(x))
+ for i in range(num_iters):
+ g = grad(x, i)
+ if callback:
+ callback(x, i, g)
+ m = (1 - b1) * g + b1 * m # First moment estimate.
+ v = (1 - b2) * (g**2) + b2 * v # Second moment estimate.
+ mhat = m / (1 - b1 ** (i + 1)) # Bias correction.
+ vhat = v / (1 - b2 ** (i + 1))
+ x = x - step_size * mhat / (np.sqrt(vhat) + eps)
+ return x
diff --git a/venv/Lib/site-packages/autograd/misc/tracers.py b/venv/Lib/site-packages/autograd/misc/tracers.py
new file mode 100644
index 0000000000000000000000000000000000000000..20dd555fd56cc787ad4bec09d29841657f64c5ba
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/misc/tracers.py
@@ -0,0 +1,75 @@
+from functools import partial
+from itertools import repeat
+
+from autograd.tracer import Node, trace
+from autograd.util import subvals, toposort
+from autograd.wrap_util import wraps
+
+
+class ConstGraphNode(Node):
+ __slots__ = ["parents", "partial_fun"]
+
+ def __init__(self, value, fun, args, kwargs, parent_argnums, parents):
+ args = subvals(args, zip(parent_argnums, repeat(None)))
+
+ def partial_fun(partial_args):
+ return fun(*subvals(args, zip(parent_argnums, partial_args)), **kwargs)
+
+ self.parents = parents
+ self.partial_fun = partial_fun
+
+ def initialize_root(self):
+ self.parents = []
+
+
+def const_graph_unary(fun):
+ graph = []
+ _fun = [fun] # Allow fun to be freed, since it may have bound args
+
+ def maybe_cached_fun(x):
+ if graph:
+ _graph = graph[0]
+ vals = {_graph[0]: x}
+ for node in _graph[1:]:
+ vals[node] = node.partial_fun([vals[p] for p in node.parents])
+ return vals[node]
+ else:
+ start_node = ConstGraphNode.new_root()
+ end_value, end_node = trace(start_node, _fun.pop(), x)
+ if end_node is None:
+ raise Exception("Output is independent of input")
+ graph.append(list(toposort(end_node))[::-1])
+ return end_value
+
+ return maybe_cached_fun
+
+
+def const_graph(fun, *args, **kwargs):
+ partial_fun = partial(fun, *args, **kwargs)
+ unary_fun = lambda args: partial_fun(*args)
+ maybe_cached_unary_fun = const_graph_unary(unary_fun)
+
+ @wraps(fun)
+ def _fun(*args):
+ return maybe_cached_unary_fun(args)
+
+ return _fun
+
+
+class FullGraphNode(Node):
+ __slots__ = ["value", "recipe"]
+
+ def __init__(self, value, fun, args, kwargs, parent_argnums, parents):
+ self.value = value
+ self.recipe = (fun, args, kwargs, zip(parent_argnums, parents))
+
+ def initialize_root(self):
+ self.value = None
+ self.recipe = (lambda x: x, (), {}, [])
+
+
+def full_graph(fun, *args, **kwargs):
+ unary_fun = lambda args: fun(*args, **kwargs)
+ start_node = FullGraphNode.new_root()
+ end_value, end_node = trace(start_node, unary_fun, args)
+ return end_node
diff --git a/venv/Lib/site-packages/autograd/numpy/__init__.py b/venv/Lib/site-packages/autograd/numpy/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..732843e04a7f17a5b0b62ba71227ed94fe1272b2
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/numpy/__init__.py
@@ -0,0 +1,3 @@
+from . import fft, linalg, numpy_boxes, numpy_jvps, numpy_vjps, numpy_vspaces, random
+from .numpy_wrapper import *
+from .numpy_wrapper import numpy_version as __version__
diff --git a/venv/Lib/site-packages/autograd/numpy/fft.py b/venv/Lib/site-packages/autograd/numpy/fft.py
new file mode 100644
index 0000000000000000000000000000000000000000..e401b4cc8f3fa4f3e4870322167c759e157a8a04
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/numpy/fft.py
@@ -0,0 +1,161 @@
+import numpy.fft as ffto
+
+from autograd.extend import defvjp, primitive, vspace
+
+from . import numpy_wrapper as anp
+from .numpy_vjps import match_complex
+from .numpy_wrapper import wrap_namespace
+
+wrap_namespace(ffto.__dict__, globals())
+
+
+# TODO: make fft gradient work for a repeated axis,
+# e.g. by replacing fftn with repeated calls to 1d fft along each axis
+def fft_grad(get_args, fft_fun, ans, x, *args, **kwargs):
+ axes, s, norm = get_args(x, *args, **kwargs)
+ check_no_repeated_axes(axes)
+ vs = vspace(x)
+ return lambda g: match_complex(x, truncate_pad(fft_fun(g, *args, **kwargs), vs.shape))
+
+
+defvjp(fft, lambda *args, **kwargs: fft_grad(get_fft_args, fft, *args, **kwargs))
+defvjp(ifft, lambda *args, **kwargs: fft_grad(get_fft_args, ifft, *args, **kwargs))
+
+defvjp(fft2, lambda *args, **kwargs: fft_grad(get_fft_args, fft2, *args, **kwargs))
+defvjp(ifft2, lambda *args, **kwargs: fft_grad(get_fft_args, ifft2, *args, **kwargs))
+
+defvjp(fftn, lambda *args, **kwargs: fft_grad(get_fft_args, fftn, *args, **kwargs))
+defvjp(ifftn, lambda *args, **kwargs: fft_grad(get_fft_args, ifftn, *args, **kwargs))
+
+
+def rfft_grad(get_args, irfft_fun, ans, x, *args, **kwargs):
+ axes, s, norm = get_args(x, *args, **kwargs)
+ vs = vspace(x)
+ gvs = vspace(ans)
+ check_no_repeated_axes(axes)
+ if s is None:
+ s = [vs.shape[i] for i in axes]
+ check_even_shape(s)
+
+ # s is the full fft shape
+ # gs is the compressed shape
+ gs = list(s)
+ gs[-1] = gs[-1] // 2 + 1
+ fac = make_rfft_factors(axes, gvs.shape, gs, s, norm)
+
+ def vjp(g):
+ g = anp.conj(g / fac)
+ r = match_complex(x, truncate_pad((irfft_fun(g, *args, **kwargs)), vs.shape))
+ return r
+
+ return vjp
+
+
+def irfft_grad(get_args, rfft_fun, ans, x, *args, **kwargs):
+ axes, gs, norm = get_args(x, *args, **kwargs)
+ vs = vspace(x)
+ gvs = vspace(ans)
+ check_no_repeated_axes(axes)
+ if gs is None:
+ gs = [gvs.shape[i] for i in axes]
+ check_even_shape(gs)
+
+ # gs is the full fft shape
+ # s is the compressed shape
+ s = list(gs)
+ s[-1] = s[-1] // 2 + 1
+
+ def vjp(g):
+ r = match_complex(x, truncate_pad((rfft_fun(g, *args, **kwargs)), vs.shape))
+ fac = make_rfft_factors(axes, vs.shape, s, gs, norm)
+ r = anp.conj(r) * fac
+ return r
+
+ return vjp
+
+
+defvjp(rfft, lambda *args, **kwargs: rfft_grad(get_fft_args, irfft, *args, **kwargs))
+
+defvjp(irfft, lambda *args, **kwargs: irfft_grad(get_fft_args, rfft, *args, **kwargs))
+
+defvjp(rfft2, lambda *args, **kwargs: rfft_grad(get_fft2_args, irfft2, *args, **kwargs))
+
+defvjp(irfft2, lambda *args, **kwargs: irfft_grad(get_fft2_args, rfft2, *args, **kwargs))
+
+defvjp(rfftn, lambda *args, **kwargs: rfft_grad(get_fftn_args, irfftn, *args, **kwargs))
+
+defvjp(irfftn, lambda *args, **kwargs: irfft_grad(get_fftn_args, rfftn, *args, **kwargs))
+
+defvjp(
+ fftshift, lambda ans, x, axes=None: lambda g: match_complex(x, anp.conj(ifftshift(anp.conj(g), axes)))
+)
+defvjp(
+ ifftshift, lambda ans, x, axes=None: lambda g: match_complex(x, anp.conj(fftshift(anp.conj(g), axes)))
+)
+
+
+@primitive
+def truncate_pad(x, shape):
+ # truncate/pad x to have the appropriate shape
+ slices = [slice(n) for n in shape]
+ pads = tuple(
+ zip(anp.zeros(len(shape), dtype=int), anp.maximum(0, anp.array(shape) - anp.array(x.shape)))
+ )
+ return anp.pad(x, pads, "constant")[tuple(slices)]
+
+
+defvjp(truncate_pad, lambda ans, x, shape: lambda g: match_complex(x, truncate_pad(g, vspace(x).shape)))
+
+
+## TODO: could be made less stringent, to fail only when repeated axis has different values of s
+def check_no_repeated_axes(axes):
+ axes_set = set(axes)
+ if len(axes) != len(axes_set):
+ raise NotImplementedError("FFT gradient for repeated axes not implemented.")
+
+
+def check_even_shape(shape):
+ if shape[-1] % 2 != 0:
+ raise NotImplementedError("Real FFT gradient for odd lengthed last axes is not implemented.")
+
+
+def get_fft_args(a, d=None, axis=-1, norm=None, *args, **kwargs):
+ axes = [axis]
+ if d is not None:
+ d = [d]
+ return axes, d, norm
+
+
+def get_fft2_args(a, s=None, axes=(-2, -1), norm=None, *args, **kwargs):
+ return axes, s, norm
+
+
+def get_fftn_args(a, s=None, axes=None, norm=None, *args, **kwargs):
+ if axes is None:
+ axes = list(range(a.ndim))
+ return axes, s, norm
+
+
+def make_rfft_factors(axes, resshape, facshape, normshape, norm):
+ """make the compression factors and compute the normalization
+ for irfft and rfft.
+ """
+ N = 1.0
+ for n in normshape:
+ N = N * n
+
+ # inplace modification is fine because we produce a constant
+ # which doesn't go into autograd.
+ # For same reason could have used numpy rather than anp.
+ # but we already imported anp, so use it instead.
+ fac = anp.zeros(resshape)
+ fac[...] = 2
+ index = [slice(None)] * len(resshape)
+ if facshape[-1] <= resshape[axes[-1]]:
+ index[axes[-1]] = (0, facshape[-1] - 1)
+ else:
+ index[axes[-1]] = (0,)
+ fac[tuple(index)] = 1
+ if norm is None:
+ fac /= N
+ return fac
diff --git a/venv/Lib/site-packages/autograd/numpy/linalg.py b/venv/Lib/site-packages/autograd/numpy/linalg.py
new file mode 100644
index 0000000000000000000000000000000000000000..b400a55826a334cf5d516ad0c7f3b47bbf67f587
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/numpy/linalg.py
@@ -0,0 +1,338 @@
+from functools import partial
+
+import numpy.linalg as npla
+
+from autograd.extend import defjvp, defvjp
+
+from . import numpy_wrapper as anp
+from .numpy_wrapper import wrap_namespace
+
+wrap_namespace(npla.__dict__, globals())
+
+# Some formulas are from
+# "An extended collection of matrix derivative results
+# for forward and reverse mode algorithmic differentiation"
+# by Mike Giles
+# https://people.maths.ox.ac.uk/gilesm/files/NA-08-01.pdf
+
+
+# transpose by swapping last two dimensions
+def T(x):
+ return anp.swapaxes(x, -1, -2)
+
+
+_dot = partial(anp.einsum, "...ij,...jk->...ik")
+
+# batched diag
+_diag = lambda a: anp.eye(a.shape[-1]) * a
+
+
+# batched diagonal, similar to matrix_diag in tensorflow
+def _matrix_diag(a):
+ reps = anp.array(a.shape)
+ reps[:-1] = 1
+ reps[-1] = a.shape[-1]
+ newshape = list(a.shape) + [a.shape[-1]]
+ return _diag(anp.tile(a, reps).reshape(newshape))
+
+
+# add two dimensions to the end of x
+def add2d(x):
+ return anp.reshape(x, anp.shape(x) + (1, 1))
+
+
+defvjp(det, lambda ans, x: lambda g: add2d(g) * add2d(ans) * T(inv(x)))
+defvjp(slogdet, lambda ans, x: lambda g: add2d(g[1]) * T(inv(x)))
+
+
+def grad_inv(ans, x):
+ return lambda g: -_dot(_dot(T(ans), g), T(ans))
+
+
+defvjp(inv, grad_inv)
+
+
+def grad_pinv(ans, x):
+ # https://mathoverflow.net/questions/25778/analytical-formula-for-numerical-derivative-of-the-matrix-pseudo-inverse
+ return lambda g: T(
+ -_dot(_dot(ans, T(g)), ans)
+ + _dot(_dot(_dot(ans, T(ans)), g), anp.eye(x.shape[-2]) - _dot(x, ans))
+ + _dot(_dot(_dot(anp.eye(ans.shape[-2]) - _dot(ans, x), g), T(ans)), ans)
+ )
+
+
+defvjp(pinv, grad_pinv)
+
+
+def grad_solve(argnum, ans, a, b):
+ updim = lambda x: x if x.ndim == a.ndim else x[..., None]
+ if argnum == 0:
+ return lambda g: -_dot(updim(solve(T(a), g)), T(updim(ans)))
+ else:
+ return lambda g: solve(T(a), g)
+
+
+defvjp(solve, partial(grad_solve, 0), partial(grad_solve, 1))
+
+
+def norm_vjp(ans, x, ord=None, axis=None):
+ def check_implemented():
+ matrix_norm = (x.ndim == 2 and axis is None) or isinstance(axis, tuple)
+
+ if matrix_norm:
+ if not (ord is None or ord == "fro" or ord == "nuc"):
+ raise NotImplementedError("Gradient of matrix norm not implemented for ord={}".format(ord))
+ elif not (ord is None or ord > 1):
+ raise NotImplementedError("Gradient of norm not implemented for ord={}".format(ord))
+
+ if axis is None:
+ expand = lambda a: a
+ elif isinstance(axis, tuple):
+ row_axis, col_axis = axis
+ if row_axis > col_axis:
+ row_axis = row_axis - 1
+ expand = lambda a: anp.expand_dims(anp.expand_dims(a, row_axis), col_axis)
+ else:
+ expand = lambda a: anp.expand_dims(a, axis=axis)
+
+ if ord == "nuc":
+ if axis is None:
+ roll = lambda a: a
+ unroll = lambda a: a
+ else:
+ row_axis, col_axis = axis
+ if row_axis > col_axis:
+ row_axis = row_axis - 1
+ # Roll matrix axes to the back
+ roll = lambda a: anp.rollaxis(anp.rollaxis(a, col_axis, a.ndim), row_axis, a.ndim - 1)
+ # Roll matrix axes to their original position
+ unroll = lambda a: anp.rollaxis(anp.rollaxis(a, a.ndim - 2, row_axis), a.ndim - 1, col_axis)
+
+ check_implemented()
+
+ def vjp(g):
+ if ord in (None, 2, "fro"):
+ return expand(g / ans) * x
+ elif ord == "nuc":
+ x_rolled = roll(x)
+ u, s, vt = svd(x_rolled, full_matrices=False)
+ uvt_rolled = _dot(u, vt)
+ # Roll the matrix axes back to their correct positions
+ uvt = unroll(uvt_rolled)
+ g = expand(g)
+ return g * uvt
+ else:
+ # see https://en.wikipedia.org/wiki/Norm_(mathematics)#p-norm
+ return expand(g / ans ** (ord - 1)) * x * anp.abs(x) ** (ord - 2)
+
+ return vjp
+
+
+defvjp(norm, norm_vjp)
+
+
+def norm_jvp(g, ans, x, ord=None, axis=None):
+ def check_implemented():
+ matrix_norm = (x.ndim == 2 and axis is None) or isinstance(axis, tuple)
+
+ if matrix_norm:
+ if not (ord is None or ord == "fro" or ord == "nuc"):
+ raise NotImplementedError("Gradient of matrix norm not implemented for ord={}".format(ord))
+ elif not (ord is None or ord > 1):
+ raise NotImplementedError("Gradient of norm not implemented for ord={}".format(ord))
+
+ if axis is None:
+ contract = lambda a: anp.sum(a)
+ else:
+ contract = partial(anp.sum, axis=axis)
+
+ if ord == "nuc":
+ if axis is None:
+ roll = lambda a: a
+ unroll = lambda a: a
+ else:
+ row_axis, col_axis = axis
+ if row_axis > col_axis:
+ row_axis = row_axis - 1
+ # Roll matrix axes to the back
+ roll = lambda a: anp.rollaxis(anp.rollaxis(a, col_axis, a.ndim), row_axis, a.ndim - 1)
+ # Roll matrix axes to their original position
+ unroll = lambda a: anp.rollaxis(anp.rollaxis(a, a.ndim - 2, row_axis), a.ndim - 1, col_axis)
+
+ check_implemented()
+ if ord in (None, 2, "fro"):
+ return contract(g * x) / ans
+ elif ord == "nuc":
+ x_rolled = roll(x)
+ u, s, vt = svd(x_rolled, full_matrices=False)
+ uvt_rolled = _dot(u, vt)
+ # Roll the matrix axes back to their correct positions
+ uvt = unroll(uvt_rolled)
+ return contract(g * uvt)
+ else:
+ # see https://en.wikipedia.org/wiki/Norm_(mathematics)#p-norm
+ return contract(g * x * anp.abs(x) ** (ord - 2)) / ans ** (ord - 1)
+
+
+defjvp(norm, norm_jvp)
+
+
+def grad_eigh(ans, x, UPLO="L"):
+ """Gradient for eigenvalues and vectors of a symmetric matrix."""
+ N = x.shape[-1]
+ w, v = ans # Eigenvalues, eigenvectors.
+ vc = anp.conj(v)
+
+ def vjp(g):
+ wg, vg = g # Gradient w.r.t. eigenvalues, eigenvectors.
+ w_repeated = anp.repeat(w[..., anp.newaxis], N, axis=-1)
+
+ # Eigenvalue part
+ vjp_temp = _dot(vc * wg[..., anp.newaxis, :], T(v))
+
+ # Add eigenvector part only if non-zero backward signal is present.
+ # This can avoid NaN results for degenerate cases if the function depends
+ # on the eigenvalues only.
+ if anp.any(vg):
+ off_diag = anp.ones((N, N)) - anp.eye(N)
+ F = off_diag / (T(w_repeated) - w_repeated + anp.eye(N))
+ vjp_temp += _dot(_dot(vc, F * _dot(T(v), vg)), T(v))
+
+ # eigh always uses only the lower or the upper part of the matrix
+ # we also have to make sure broadcasting works
+ reps = anp.array(x.shape)
+ reps[-2:] = 1
+
+ if UPLO == "L":
+ tri = anp.tile(anp.tril(anp.ones(N), -1), reps)
+ elif UPLO == "U":
+ tri = anp.tile(anp.triu(anp.ones(N), 1), reps)
+
+ return anp.real(vjp_temp) * anp.eye(vjp_temp.shape[-1]) + (vjp_temp + anp.conj(T(vjp_temp))) * tri
+
+ return vjp
+
+
+defvjp(eigh, grad_eigh)
+
+
+# https://arxiv.org/pdf/1701.00392.pdf Eq(4.77)
+# Note the formula from Sec3.1 in https://people.maths.ox.ac.uk/gilesm/files/NA-08-01.pdf is incomplete
+def grad_eig(ans, x):
+ """Gradient of a general square (complex valued) matrix"""
+ e, u = ans # eigenvalues as 1d array, eigenvectors in columns
+ n = e.shape[-1]
+
+ def vjp(g):
+ ge, gu = g
+ ge = _matrix_diag(ge)
+ f = 1 / (e[..., anp.newaxis, :] - e[..., :, anp.newaxis] + 1.0e-20)
+ f -= _diag(f)
+ ut = anp.swapaxes(u, -1, -2)
+ r1 = f * _dot(ut, gu)
+ r2 = -f * (_dot(_dot(ut, anp.conj(u)), anp.real(_dot(ut, gu)) * anp.eye(n)))
+ r = _dot(_dot(inv(ut), ge + r1 + r2), ut)
+ if not anp.iscomplexobj(x):
+ r = anp.real(r)
+ # the derivative is still complex for real input (imaginary delta is allowed), real output
+ # but the derivative should be real in real input case when imaginary delta is forbidden
+ return r
+
+ return vjp
+
+
+defvjp(eig, grad_eig)
+
+
+def grad_cholesky(L, A):
+ # Based on Iain Murray's note http://arxiv.org/abs/1602.07527
+ # scipy's dtrtrs wrapper, solve_triangular, doesn't broadcast along leading
+ # dimensions, so we just call a generic LU solve instead of directly using
+ # backsubstitution (also, we factor twice...)
+ solve_trans = lambda a, b: solve(T(a), b)
+ phi = lambda X: anp.tril(X) / (1.0 + anp.eye(X.shape[-1]))
+
+ def conjugate_solve(L, X):
+ # X -> L^{-T} X L^{-1}
+ return solve_trans(L, T(solve_trans(L, T(X))))
+
+ def vjp(g):
+ S = conjugate_solve(L, phi(anp.einsum("...ki,...kj->...ij", L, g)))
+ return (S + T(S)) / 2.0
+
+ return vjp
+
+
+defvjp(cholesky, grad_cholesky)
+
+
+# https://j-towns.github.io/papers/svd-derivative.pdf
+# https://arxiv.org/abs/1909.02659
+def grad_svd(usv_, a, full_matrices=True, compute_uv=True):
+ def vjp(g):
+ usv = usv_
+
+ if not compute_uv:
+ s = usv
+
+ # Need U and V so do the whole svd anyway...
+ usv = svd(a, full_matrices=False)
+ u = usv[0]
+ v = anp.conj(T(usv[2]))
+
+ return _dot(anp.conj(u) * g[..., anp.newaxis, :], T(v))
+
+ elif full_matrices:
+ raise NotImplementedError("Gradient of svd not implemented for full_matrices=True")
+
+ else:
+ u = usv[0]
+ s = usv[1]
+ v = anp.conj(T(usv[2]))
+
+ m, n = a.shape[-2:]
+
+ k = anp.min((m, n))
+ # broadcastable identity array with shape (1, 1, ..., 1, k, k)
+ i = anp.reshape(anp.eye(k), anp.concatenate((anp.ones(a.ndim - 2, dtype=int), (k, k))))
+
+ f = 1 / (s[..., anp.newaxis, :] ** 2 - s[..., :, anp.newaxis] ** 2 + i)
+
+ gu = g[0]
+ gs = g[1]
+ gv = anp.conj(T(g[2]))
+
+ utgu = _dot(T(u), gu)
+ vtgv = _dot(T(v), gv)
+ t1 = (f * (utgu - anp.conj(T(utgu)))) * s[..., anp.newaxis, :]
+ t1 = t1 + i * gs[..., :, anp.newaxis]
+ t1 = t1 + s[..., :, anp.newaxis] * (f * (vtgv - anp.conj(T(vtgv))))
+
+ if anp.iscomplexobj(u):
+ t1 = t1 + 1j * anp.imag(_diag(utgu)) / s[..., anp.newaxis, :]
+
+ t1 = _dot(_dot(anp.conj(u), t1), T(v))
+
+ if m < n:
+ i_minus_vvt = anp.reshape(
+ anp.eye(n), anp.concatenate((anp.ones(a.ndim - 2, dtype=int), (n, n)))
+ ) - _dot(v, anp.conj(T(v)))
+ t1 = t1 + anp.conj(_dot(_dot(u / s[..., anp.newaxis, :], T(gv)), i_minus_vvt))
+
+ return t1
+
+ elif m == n:
+ return t1
+
+ elif m > n:
+ i_minus_uut = anp.reshape(
+ anp.eye(m), anp.concatenate((anp.ones(a.ndim - 2, dtype=int), (m, m)))
+ ) - _dot(u, anp.conj(T(u)))
+ t1 = t1 + T(_dot(_dot(v / s[..., anp.newaxis, :], T(gu)), i_minus_uut))
+
+ return t1
+
+ return vjp
+
+
+defvjp(svd, grad_svd)
diff --git a/venv/Lib/site-packages/autograd/numpy/numpy_boxes.py b/venv/Lib/site-packages/autograd/numpy/numpy_boxes.py
new file mode 100644
index 0000000000000000000000000000000000000000..b9c73963ba6919b443db903f248a08a18926f5a4
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/numpy/numpy_boxes.py
@@ -0,0 +1,179 @@
+from typing import Union
+
+import numpy as np
+
+from autograd.builtins import SequenceBox
+from autograd.extend import Box, primitive
+
+from . import numpy_wrapper as anp
+
+Box.__array_priority__ = 90.0
+
+
+class ArrayBox(Box):
+ __slots__ = []
+ __array_priority__ = 100.0
+
+ @primitive
+ def __getitem__(A, idx):
+ return A[idx]
+
+ # Constants w.r.t float data just pass though
+ shape = property(lambda self: self._value.shape)
+ ndim = property(lambda self: self._value.ndim)
+ size = property(lambda self: self._value.size)
+ dtype = property(lambda self: self._value.dtype)
+ T = property(lambda self: anp.transpose(self))
+
+ def __array_namespace__(self, *, api_version: Union[str, None] = None):
+ return anp
+
+ def __len__(self):
+ return len(self._value)
+
+ def astype(self, *args, **kwargs):
+ return anp._astype(self, *args, **kwargs)
+
+ def __neg__(self):
+ return anp.negative(self)
+
+ def __add__(self, other):
+ return anp.add(self, other)
+
+ def __sub__(self, other):
+ return anp.subtract(self, other)
+
+ def __mul__(self, other):
+ return anp.multiply(self, other)
+
+ def __pow__(self, other):
+ return anp.power(self, other)
+
+ def __div__(self, other):
+ return anp.divide(self, other)
+
+ def __mod__(self, other):
+ return anp.mod(self, other)
+
+ def __truediv__(self, other):
+ return anp.true_divide(self, other)
+
+ def __matmul__(self, other):
+ return anp.matmul(self, other)
+
+ def __radd__(self, other):
+ return anp.add(other, self)
+
+ def __rsub__(self, other):
+ return anp.subtract(other, self)
+
+ def __rmul__(self, other):
+ return anp.multiply(other, self)
+
+ def __rpow__(self, other):
+ return anp.power(other, self)
+
+ def __rdiv__(self, other):
+ return anp.divide(other, self)
+
+ def __rmod__(self, other):
+ return anp.mod(other, self)
+
+ def __rtruediv__(self, other):
+ return anp.true_divide(other, self)
+
+ def __rmatmul__(self, other):
+ return anp.matmul(other, self)
+
+ def __eq__(self, other):
+ return anp.equal(self, other)
+
+ def __ne__(self, other):
+ return anp.not_equal(self, other)
+
+ def __gt__(self, other):
+ return anp.greater(self, other)
+
+ def __ge__(self, other):
+ return anp.greater_equal(self, other)
+
+ def __lt__(self, other):
+ return anp.less(self, other)
+
+ def __le__(self, other):
+ return anp.less_equal(self, other)
+
+ def __abs__(self):
+ return anp.abs(self)
+
+ def __hash__(self):
+ return id(self)
+
+
+ArrayBox.register(np.ndarray)
+for type_ in [
+ float,
+ np.longdouble,
+ np.float64,
+ np.float32,
+ np.float16,
+ complex,
+ np.clongdouble,
+ np.complex64,
+ np.complex128,
+]:
+ ArrayBox.register(type_)
+
+# These numpy.ndarray methods are just refs to an equivalent numpy function
+nondiff_methods = [
+ "all",
+ "any",
+ "argmax",
+ "argmin",
+ "argpartition",
+ "argsort",
+ "nonzero",
+ "searchsorted",
+ "round",
+]
+diff_methods = [
+ "clip",
+ "compress",
+ "cumprod",
+ "cumsum",
+ "diagonal",
+ "max",
+ "mean",
+ "min",
+ "prod",
+ "ptp",
+ "ravel",
+ "repeat",
+ "reshape",
+ "squeeze",
+ "std",
+ "sum",
+ "swapaxes",
+ "take",
+ "trace",
+ "transpose",
+ "var",
+]
+for method_name in nondiff_methods + diff_methods:
+ setattr(ArrayBox, method_name, anp.__dict__[method_name])
+
+# Flatten has no function, only a method.
+setattr(ArrayBox, "flatten", anp.__dict__["ravel"])
+
+if np.lib.NumpyVersion(np.__version__) >= "2.0.0":
+ SequenceBox.register(np.linalg._linalg.EigResult)
+ SequenceBox.register(np.linalg._linalg.EighResult)
+ SequenceBox.register(np.linalg._linalg.QRResult)
+ SequenceBox.register(np.linalg._linalg.SlogdetResult)
+ SequenceBox.register(np.linalg._linalg.SVDResult)
+elif np.__version__ >= "1.25":
+ SequenceBox.register(np.linalg.linalg.EigResult)
+ SequenceBox.register(np.linalg.linalg.EighResult)
+ SequenceBox.register(np.linalg.linalg.QRResult)
+ SequenceBox.register(np.linalg.linalg.SlogdetResult)
+ SequenceBox.register(np.linalg.linalg.SVDResult)
diff --git a/venv/Lib/site-packages/autograd/numpy/numpy_jvps.py b/venv/Lib/site-packages/autograd/numpy/numpy_jvps.py
new file mode 100644
index 0000000000000000000000000000000000000000..4dba485bee43885e431b75d37e70437a0ca44e77
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/numpy/numpy_jvps.py
@@ -0,0 +1,297 @@
+import numpy as onp
+
+from autograd.extend import JVPNode, def_linear, defjvp, defjvp_argnum, register_notrace, vspace
+
+from ..util import func
+from . import numpy_wrapper as anp
+from .numpy_boxes import ArrayBox
+from .numpy_vjps import (
+ balanced_eq,
+ dot_adjoint_0,
+ dot_adjoint_1,
+ match_complex,
+ nograd_functions,
+ replace_zero,
+ tensordot_adjoint_0,
+ tensordot_adjoint_1,
+ untake,
+)
+
+for fun in nograd_functions:
+ register_notrace(JVPNode, fun)
+
+defjvp(func(ArrayBox.__getitem__), "same")
+defjvp(untake, "same")
+
+defjvp_argnum(anp.array_from_args, lambda argnum, g, ans, args, kwargs: untake(g, argnum - 2, vspace(ans)))
+defjvp(
+ anp._array_from_scalar_or_array,
+ None,
+ None,
+ lambda g, ans, args, kwargs, _: anp._array_from_scalar_or_array(args, kwargs, g),
+)
+
+# ----- Functions that are constant w.r.t. continuous inputs -----
+defjvp(anp.nan_to_num, lambda g, ans, x: anp.where(anp.isfinite(x), g, 0.0))
+
+# ----- Binary ufuncs (linear) -----
+def_linear(anp.multiply)
+
+# ----- Binary ufuncs -----
+defjvp(anp.add, lambda g, ans, x, y: broadcast(g, ans), lambda g, ans, x, y: broadcast(g, ans))
+defjvp(anp.subtract, lambda g, ans, x, y: broadcast(g, ans), lambda g, ans, x, y: broadcast(-g, ans))
+defjvp(anp.divide, "same", lambda g, ans, x, y: -g * x / y**2)
+defjvp(
+ anp.maximum,
+ lambda g, ans, x, y: g * balanced_eq(x, ans, y),
+ lambda g, ans, x, y: g * balanced_eq(y, ans, x),
+)
+defjvp(
+ anp.minimum,
+ lambda g, ans, x, y: g * balanced_eq(x, ans, y),
+ lambda g, ans, x, y: g * balanced_eq(y, ans, x),
+)
+defjvp(
+ anp.fmax,
+ lambda g, ans, x, y: g * balanced_eq(x, ans, y),
+ lambda g, ans, x, y: g * balanced_eq(y, ans, x),
+)
+defjvp(
+ anp.fmin,
+ lambda g, ans, x, y: g * balanced_eq(x, ans, y),
+ lambda g, ans, x, y: g * balanced_eq(y, ans, x),
+)
+defjvp(anp.logaddexp, lambda g, ans, x, y: g * anp.exp(x - ans), lambda g, ans, x, y: g * anp.exp(y - ans))
+defjvp(anp.logaddexp2, lambda g, ans, x, y: g * 2 ** (x - ans), lambda g, ans, x, y: g * 2 ** (y - ans))
+defjvp(anp.true_divide, "same", lambda g, ans, x, y: -g * x / y**2)
+defjvp(anp.mod, lambda g, ans, x, y: broadcast(g, ans), lambda g, ans, x, y: -g * anp.floor(x / y))
+defjvp(anp.remainder, lambda g, ans, x, y: broadcast(g, ans), lambda g, ans, x, y: -g * anp.floor(x / y))
+defjvp(
+ anp.power,
+ lambda g, ans, x, y: g * y * x ** anp.where(y, y - 1, 1.0),
+ lambda g, ans, x, y: g * anp.log(replace_zero(x, 1.0)) * ans,
+)
+defjvp(anp.arctan2, lambda g, ans, x, y: g * y / (x**2 + y**2), lambda g, ans, x, y: g * -x / (x**2 + y**2))
+
+# ----- Simple grads (linear) -----
+defjvp(anp.negative, "same")
+defjvp(anp.rad2deg, "same")
+defjvp(anp.degrees, "same")
+defjvp(anp.deg2rad, "same")
+defjvp(anp.radians, "same")
+defjvp(anp.reshape, "same")
+defjvp(anp.roll, "same")
+defjvp(anp.array_split, "same")
+defjvp(anp.split, "same")
+defjvp(anp.vsplit, "same")
+defjvp(anp.hsplit, "same")
+defjvp(anp.dsplit, "same")
+defjvp(anp.ravel, "same")
+defjvp(anp.expand_dims, "same")
+defjvp(anp.squeeze, "same")
+defjvp(anp.diag, "same")
+defjvp(anp.diagonal, "same")
+defjvp(anp.make_diagonal, "same")
+defjvp(anp.flipud, "same")
+defjvp(anp.fliplr, "same")
+defjvp(anp.rot90, "same")
+defjvp(anp.trace, "same")
+defjvp(anp.full, "same", argnums=(1,))
+defjvp(anp.triu, "same")
+defjvp(anp.tril, "same")
+defjvp(anp.swapaxes, "same")
+defjvp(anp.rollaxis, "same")
+defjvp(anp.moveaxis, "same")
+defjvp(anp.broadcast_to, "same")
+def_linear(anp.cross)
+
+# ----- Simple grads -----
+defjvp(anp.abs, lambda g, ans, x: anp.real(g * replace_zero(anp.conj(x), 0.0)) / replace_zero(ans, 1.0))
+defjvp(anp.fabs, lambda g, ans, x: anp.sign(x) * g) # fabs doesn't take complex numbers.
+defjvp(anp.absolute, lambda g, ans, x: anp.real(g * anp.conj(x)) / ans)
+defjvp(anp.reciprocal, lambda g, ans, x: -g / x**2)
+defjvp(anp.exp, lambda g, ans, x: ans * g)
+defjvp(anp.exp2, lambda g, ans, x: ans * anp.log(2) * g)
+defjvp(anp.expm1, lambda g, ans, x: (ans + 1) * g)
+defjvp(anp.log, lambda g, ans, x: g / x)
+defjvp(anp.log2, lambda g, ans, x: g / x / anp.log(2))
+defjvp(anp.log10, lambda g, ans, x: g / x / anp.log(10))
+defjvp(anp.log1p, lambda g, ans, x: g / (x + 1))
+defjvp(anp.sin, lambda g, ans, x: g * anp.cos(x))
+defjvp(anp.cos, lambda g, ans, x: -g * anp.sin(x))
+defjvp(anp.tan, lambda g, ans, x: g / anp.cos(x) ** 2)
+defjvp(anp.arcsin, lambda g, ans, x: g / anp.sqrt(1 - x**2))
+defjvp(anp.arccos, lambda g, ans, x: -g / anp.sqrt(1 - x**2))
+defjvp(anp.arctan, lambda g, ans, x: g / (1 + x**2))
+defjvp(anp.sinh, lambda g, ans, x: g * anp.cosh(x))
+defjvp(anp.cosh, lambda g, ans, x: g * anp.sinh(x))
+defjvp(anp.tanh, lambda g, ans, x: g / anp.cosh(x) ** 2)
+defjvp(anp.arcsinh, lambda g, ans, x: g / anp.sqrt(x**2 + 1))
+defjvp(anp.arccosh, lambda g, ans, x: g / anp.sqrt(x**2 - 1))
+defjvp(anp.arctanh, lambda g, ans, x: g / (1 - x**2))
+defjvp(anp.square, lambda g, ans, x: g * 2 * x)
+defjvp(anp.sqrt, lambda g, ans, x: g * 0.5 * x**-0.5)
+defjvp(
+ anp.sinc,
+ lambda g, ans, x: g * (anp.cos(anp.pi * x) * anp.pi * x - anp.sin(anp.pi * x)) / (anp.pi * x**2),
+)
+defjvp(anp.clip, lambda g, ans, x, a_min, a_max: g * anp.logical_and(ans != a_min, ans != a_max))
+defjvp(anp.real_if_close, lambda g, ans, x: match_complex(ans, g))
+defjvp(anp.real, lambda g, ans, x: anp.real(g))
+defjvp(anp.imag, lambda g, ans, x: match_complex(ans, -1j * g))
+defjvp(anp.conj, lambda g, ans, x: anp.conj(g))
+defjvp(anp.angle, lambda g, ans, x: match_complex(ans, g * anp.conj(x * 1j) / anp.abs(x) ** 2))
+defjvp(
+ anp.where,
+ None,
+ lambda g, ans, c, x=None, y=None: anp.where(c, g, anp.zeros(anp.shape(g))),
+ lambda g, ans, c, x=None, y=None: anp.where(c, anp.zeros(g.shape), g),
+)
+
+# ----- Trickier grads -----
+defjvp(anp.kron, "same", "same")
+defjvp(anp.diff, "same")
+defjvp(anp.gradient, "same")
+defjvp(anp.repeat, "same")
+defjvp(anp.tile, "same")
+defjvp(anp.transpose, "same")
+defjvp(anp.sum, "same")
+defjvp(anp.mean, "same")
+defjvp(
+ anp.prod, lambda g, ans, x, axis=None, keepdims=False: ans * anp.sum(g / x, axis=axis, keepdims=keepdims)
+)
+defjvp(
+ anp.linspace,
+ lambda g, ans, start, stop, *args, **kwargs: anp.linspace(g, 0, *args, **kwargs),
+ lambda g, ans, start, stop, *args, **kwargs: anp.linspace(0, g, *args, **kwargs),
+)
+
+
+def forward_grad_np_var(g, ans, x, axis=None, ddof=0, keepdims=False):
+ if axis is None:
+ num_reps = anp.size(g)
+ elif isinstance(axis, int):
+ num_reps = anp.shape(g)[axis]
+ elif isinstance(axis, tuple):
+ num_reps = anp.prod(anp.array(np.shape(g))[list(axis)])
+
+ x_minus_mean = anp.conj(x - anp.mean(x, axis=axis, keepdims=True))
+ return 2.0 * anp.sum(anp.real(g * x_minus_mean), axis=axis, keepdims=keepdims) / (num_reps - ddof)
+
+
+defjvp(anp.var, forward_grad_np_var)
+
+
+def forward_grad_np_std(g, ans, x, axis=None, ddof=0, keepdims=False):
+ if axis is None:
+ num_reps = anp.size(g)
+ elif isinstance(axis, int):
+ num_reps = anp.shape(g)[axis]
+ elif isinstance(axis, tuple):
+ num_reps = anp.prod(anp.array(anp.shape(g))[list(axis)])
+
+ if num_reps <= 1:
+ return anp.zeros_like(ans)
+ x_minus_mean = anp.conj(x - anp.mean(x, axis=axis, keepdims=True))
+ return anp.sum(anp.real(g * x_minus_mean), axis=axis, keepdims=keepdims) / ((num_reps - ddof) * ans)
+
+
+defjvp(anp.std, forward_grad_np_std)
+
+
+def fwd_grad_chooser(g, ans, x, axis=None, keepdims=False):
+ if anp.isscalar(x):
+ return g
+ if not keepdims:
+ if isinstance(axis, int):
+ ans = anp.expand_dims(ans, axis)
+ elif isinstance(axis, tuple):
+ for ax in sorted(axis):
+ ans = anp.expand_dims(ans, ax)
+ chosen_locations = x == ans
+ return anp.sum((g * chosen_locations), axis=axis, keepdims=keepdims) / anp.sum(
+ chosen_locations, axis=axis, keepdims=keepdims
+ )
+
+
+defjvp(anp.max, fwd_grad_chooser)
+defjvp(anp.min, fwd_grad_chooser)
+defjvp(anp.amax, fwd_grad_chooser)
+defjvp(anp.amin, fwd_grad_chooser)
+
+defjvp(anp.cumsum, "same")
+
+def_linear(anp.inner)
+def_linear(anp.matmul)
+def_linear(anp.dot)
+def_linear(anp.tensordot)
+def_linear(anp.outer)
+
+def_linear(dot_adjoint_0)
+def_linear(dot_adjoint_1)
+
+def_linear(tensordot_adjoint_0)
+def_linear(tensordot_adjoint_1)
+
+
+def fwd_grad_concatenate_args(argnum, g, ans, axis_args, kwargs):
+ result = []
+ for i in range(1, len(axis_args)):
+ if i == argnum:
+ result.append(g)
+ else:
+ result.append(anp.zeros_like(axis_args[i]))
+ return anp.concatenate_args(axis_args[0], *result)
+
+
+defjvp_argnum(anp.concatenate_args, fwd_grad_concatenate_args)
+
+
+def fwd_grad_sort(g, ans, x, axis=-1, kind="quicksort", order=None):
+ sort_perm = anp.argsort(x, axis, kind, order)
+ return g[sort_perm]
+
+
+defjvp(anp.sort, fwd_grad_sort)
+if onp.lib.NumpyVersion(onp.__version__) < "2.0.0":
+ defjvp(anp.msort, lambda g, ans, x: fwd_grad_sort(g, ans, x, axis=0))
+
+
+def fwd_grad_partition(g, ans, x, kth, axis=-1, kind="introselect", order=None):
+ partition_perm = anp.argpartition(x, kth, axis, kind, order)
+ return g[partition_perm]
+
+
+defjvp(anp.partition, fwd_grad_partition)
+
+
+def atleast_jvpmaker(fun):
+ def jvp(g, ans, *arys):
+ if len(arys) > 1:
+ raise NotImplementedError("Can't handle multiple arguments yet.")
+ return fun(g)
+
+ return jvp
+
+
+defjvp(anp.atleast_1d, atleast_jvpmaker(anp.atleast_1d))
+defjvp(anp.atleast_2d, atleast_jvpmaker(anp.atleast_2d))
+defjvp(anp.atleast_3d, atleast_jvpmaker(anp.atleast_3d))
+
+def_linear(anp.einsum)
+
+
+# TODO(mattjj): can we call np.broadcast_to or a related function instead?
+def broadcast(x, target):
+ target_shape, target_ndim, target_dtype, target_iscomplex = anp.metadata(target)
+ while anp.ndim(x) < target_ndim:
+ x = anp.expand_dims(x, 0)
+ for axis, size in enumerate(anp.shape(x)):
+ if size == 1:
+ x = anp.repeat(x, target_shape[axis], axis=axis)
+ if target_iscomplex and not anp.iscomplexobj(x):
+ x = x + 0j # TODO(mattjj): this might promote the dtype
+ return x
+
+
+defjvp(anp.pad, lambda g, ans, array, width, mode, **kwargs: anp.pad(g, width, mode))
diff --git a/venv/Lib/site-packages/autograd/numpy/numpy_vjps.py b/venv/Lib/site-packages/autograd/numpy/numpy_vjps.py
new file mode 100644
index 0000000000000000000000000000000000000000..08d4e1b7c4b257e1ca2c18a85b055b20b86bdfb8
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/numpy/numpy_vjps.py
@@ -0,0 +1,971 @@
+from functools import partial
+
+import numpy as onp
+
+from autograd.extend import SparseObject, VJPNode, defvjp, defvjp_argnum, primitive, register_notrace, vspace
+
+from ..util import func
+from . import numpy_wrapper as anp
+from .numpy_boxes import ArrayBox
+
+# ----- Non-differentiable functions -----
+
+nograd_functions = [
+ anp.floor,
+ anp.ceil,
+ anp.round,
+ anp.rint,
+ anp.around,
+ anp.fix,
+ anp.trunc,
+ anp.all,
+ anp.any,
+ anp.argmax,
+ anp.argmin,
+ anp.argpartition,
+ anp.argsort,
+ anp.argwhere,
+ anp.nonzero,
+ anp.flatnonzero,
+ anp.count_nonzero,
+ anp.searchsorted,
+ anp.sign,
+ anp.ndim,
+ anp.shape,
+ anp.floor_divide,
+ anp.logical_and,
+ anp.logical_or,
+ anp.logical_not,
+ anp.logical_xor,
+ anp.isfinite,
+ anp.isinf,
+ anp.isnan,
+ anp.isneginf,
+ anp.isposinf,
+ anp.allclose,
+ anp.isclose,
+ anp.array_equal,
+ anp.array_equiv,
+ anp.greater,
+ anp.greater_equal,
+ anp.less,
+ anp.less_equal,
+ anp.equal,
+ anp.not_equal,
+ anp.iscomplexobj,
+ anp.iscomplex,
+ anp.size,
+ anp.isscalar,
+ anp.isreal,
+ anp.zeros_like,
+ anp.ones_like,
+ anp.result_type,
+]
+
+for fun in nograd_functions:
+ register_notrace(VJPNode, fun)
+
+# ----- Functions that are constant w.r.t. continuous inputs -----
+
+defvjp(anp.nan_to_num, lambda ans, x: lambda g: anp.where(anp.isfinite(x), g, 0.0))
+
+# ----- Binary ufuncs -----
+
+defvjp(
+ anp.add, lambda ans, x, y: unbroadcast_f(x, lambda g: g), lambda ans, x, y: unbroadcast_f(y, lambda g: g)
+)
+defvjp(
+ anp.multiply,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: y * g),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: x * g),
+)
+defvjp(
+ anp.subtract,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: -g),
+)
+defvjp(
+ anp.divide,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g / y),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: -g * x / y**2),
+)
+defvjp(
+ anp.maximum,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g * balanced_eq(x, ans, y)),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: g * balanced_eq(y, ans, x)),
+)
+defvjp(
+ anp.minimum,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g * balanced_eq(x, ans, y)),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: g * balanced_eq(y, ans, x)),
+)
+defvjp(
+ anp.fmax,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g * balanced_eq(x, ans, y)),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: g * balanced_eq(y, ans, x)),
+)
+defvjp(
+ anp.fmin,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g * balanced_eq(x, ans, y)),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: g * balanced_eq(y, ans, x)),
+)
+defvjp(
+ anp.logaddexp,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g * anp.exp(x - ans)),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: g * anp.exp(y - ans)),
+)
+defvjp(
+ anp.logaddexp2,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g * 2 ** (x - ans)),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: g * 2 ** (y - ans)),
+)
+defvjp(
+ anp.true_divide,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g / y),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: -g * x / y**2),
+)
+defvjp(
+ anp.mod,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: -g * anp.floor(x / y)),
+)
+defvjp(
+ anp.remainder,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: -g * anp.floor(x / y)),
+)
+defvjp(
+ anp.power,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g * y * x ** anp.where(y, y - 1, 1.0)),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: g * anp.log(replace_zero(x, 1.0)) * ans),
+)
+defvjp(
+ anp.arctan2,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g * y / (x**2 + y**2)),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: g * -x / (x**2 + y**2)),
+)
+defvjp(
+ anp.hypot,
+ lambda ans, x, y: unbroadcast_f(x, lambda g: g * x / ans),
+ lambda ans, x, y: unbroadcast_f(y, lambda g: g * y / ans),
+)
+
+# ----- Simple grads -----
+
+defvjp(anp.negative, lambda ans, x: lambda g: -g)
+defvjp(anp.abs, lambda ans, x: lambda g: g * replace_zero(anp.conj(x), 0.0) / replace_zero(ans, 1.0))
+defvjp(anp.fabs, lambda ans, x: lambda g: anp.sign(x) * g) # fabs doesn't take complex numbers.
+defvjp(anp.absolute, lambda ans, x: lambda g: g * anp.conj(x) / ans)
+defvjp(anp.reciprocal, lambda ans, x: lambda g: -g / x**2)
+defvjp(anp.exp, lambda ans, x: lambda g: ans * g)
+defvjp(anp.exp2, lambda ans, x: lambda g: ans * anp.log(2) * g)
+defvjp(anp.expm1, lambda ans, x: lambda g: (ans + 1) * g)
+defvjp(anp.log, lambda ans, x: lambda g: g / x)
+defvjp(anp.log2, lambda ans, x: lambda g: g / x / anp.log(2))
+defvjp(anp.log10, lambda ans, x: lambda g: g / x / anp.log(10))
+defvjp(anp.log1p, lambda ans, x: lambda g: g / (x + 1))
+defvjp(anp.sin, lambda ans, x: lambda g: g * anp.cos(x))
+defvjp(anp.cos, lambda ans, x: lambda g: -g * anp.sin(x))
+defvjp(anp.tan, lambda ans, x: lambda g: g / anp.cos(x) ** 2)
+defvjp(anp.arcsin, lambda ans, x: lambda g: g / anp.sqrt(1 - x**2))
+defvjp(anp.arccos, lambda ans, x: lambda g: -g / anp.sqrt(1 - x**2))
+defvjp(anp.arctan, lambda ans, x: lambda g: g / (1 + x**2))
+defvjp(anp.sinh, lambda ans, x: lambda g: g * anp.cosh(x))
+defvjp(anp.cosh, lambda ans, x: lambda g: g * anp.sinh(x))
+defvjp(anp.tanh, lambda ans, x: lambda g: g / anp.cosh(x) ** 2)
+defvjp(anp.arcsinh, lambda ans, x: lambda g: g / anp.sqrt(x**2 + 1))
+defvjp(anp.arccosh, lambda ans, x: lambda g: g / anp.sqrt(x**2 - 1))
+defvjp(anp.arctanh, lambda ans, x: lambda g: g / (1 - x**2))
+defvjp(anp.rad2deg, lambda ans, x: lambda g: g / anp.pi * 180.0)
+defvjp(anp.degrees, lambda ans, x: lambda g: g / anp.pi * 180.0)
+defvjp(anp.deg2rad, lambda ans, x: lambda g: g * anp.pi / 180.0)
+defvjp(anp.radians, lambda ans, x: lambda g: g * anp.pi / 180.0)
+defvjp(anp.square, lambda ans, x: lambda g: g * 2 * x)
+defvjp(anp.sqrt, lambda ans, x: lambda g: g * 0.5 * x**-0.5)
+defvjp(
+ anp.sinc,
+ lambda ans, x: lambda g: g * (anp.cos(anp.pi * x) * anp.pi * x - anp.sin(anp.pi * x)) / (anp.pi * x**2),
+)
+defvjp(anp.reshape, lambda ans, x, shape, order=None: lambda g: anp.reshape(g, anp.shape(x), order=order))
+defvjp(anp.roll, lambda ans, x, shift, axis=None: lambda g: anp.roll(g, -shift, axis=axis))
+defvjp(anp.array_split, lambda ans, ary, idxs, axis=0: lambda g: anp.concatenate(g, axis=axis))
+defvjp(anp.split, lambda ans, ary, idxs, axis=0: lambda g: anp.concatenate(g, axis=axis))
+defvjp(anp.vsplit, lambda ans, ary, idxs: lambda g: anp.concatenate(g, axis=0))
+defvjp(anp.hsplit, lambda ans, ary, idxs: lambda g: anp.concatenate(g, axis=1))
+defvjp(anp.dsplit, lambda ans, ary, idxs: lambda g: anp.concatenate(g, axis=2))
+defvjp(anp.ravel, lambda ans, x, order=None: lambda g: anp.reshape(g, anp.shape(x), order=order))
+defvjp(anp.expand_dims, lambda ans, x, axis: lambda g: anp.reshape(g, anp.shape(x)))
+defvjp(anp.squeeze, lambda ans, x, axis=None: lambda g: anp.reshape(g, anp.shape(x)))
+defvjp(anp.diag, lambda ans, x, k=0: lambda g: anp.diag(g, k))
+defvjp(anp.flipud, lambda ans, x,: lambda g: anp.flipud(g))
+defvjp(anp.fliplr, lambda ans, x,: lambda g: anp.fliplr(g))
+defvjp(anp.rot90, lambda ans, x, k=1: lambda g: anp.rot90(g, -k))
+defvjp(
+ anp.trace,
+ lambda ans, x, offset=0: lambda g: anp.einsum(
+ "ij,...->ij...", anp.eye(x.shape[0], x.shape[1], k=offset), g
+ ),
+)
+defvjp(anp.full, lambda ans, shape, fill_value, dtype=None: lambda g: anp.sum(g), argnums=(1,))
+defvjp(anp.triu, lambda ans, x, k=0: lambda g: anp.triu(g, k=k))
+defvjp(anp.tril, lambda ans, x, k=0: lambda g: anp.tril(g, k=k))
+defvjp(anp.clip, lambda ans, x, a_min, a_max: lambda g: g * anp.logical_and(ans != a_min, ans != a_max))
+defvjp(anp.swapaxes, lambda ans, x, axis1, axis2: lambda g: anp.swapaxes(g, axis2, axis1))
+defvjp(anp.moveaxis, lambda ans, a, source, destination: lambda g: anp.moveaxis(g, destination, source))
+defvjp(anp.real_if_close, lambda ans, x: lambda g: match_complex(x, g))
+defvjp(anp.real, lambda ans, x: lambda g: match_complex(x, g))
+defvjp(anp.imag, lambda ans, x: lambda g: match_complex(x, -1j * g))
+defvjp(anp.conj, lambda ans, x: lambda g: anp.conj(g))
+defvjp(anp.conjugate, lambda ans, x: lambda g: anp.conj(g))
+defvjp(anp.angle, lambda ans, x: lambda g: match_complex(x, g * anp.conj(x * 1j) / anp.abs(x) ** 2))
+defvjp(
+ anp.where,
+ None,
+ lambda ans, c, x=None, y=None: lambda g: anp.where(c, g, anp.zeros(g.shape)),
+ lambda ans, c, x=None, y=None: lambda g: anp.where(c, anp.zeros(g.shape), g),
+)
+defvjp(
+ anp.cross,
+ lambda ans, a, b, axisa=-1, axisb=-1, axisc=-1, axis=None: lambda g: anp.cross(
+ b, g, axisb, axisc, axisa, axis
+ ),
+ lambda ans, a, b, axisa=-1, axisb=-1, axisc=-1, axis=None: lambda g: anp.cross(
+ g, a, axisc, axisa, axisb, axis
+ ),
+)
+defvjp(
+ anp.linspace,
+ lambda ans, start, stop, num: lambda g: anp.dot(anp.linspace(1.0, 0.0, num), g),
+ lambda ans, start, stop, num: lambda g: anp.dot(anp.linspace(0.0, 1.0, num), g),
+)
+
+defvjp(
+ anp._astype,
+ lambda ans, A, dtype, order="K", casting="unsafe", subok=True, copy=True: lambda g: anp._astype(
+ g, A.dtype
+ ),
+)
+
+
+# ----- Trickier grads -----
+def grad_rollaxis(ans, a, axis, start=0):
+ if axis < 0:
+ raise NotImplementedError(
+ "Gradient of rollaxis not implemented for axis < 0. Please use moveaxis instead."
+ )
+ elif start < 0:
+ raise NotImplementedError(
+ "Gradient of rollaxis not implemented for start < 0. Please use moveaxis instead."
+ )
+ return lambda g: anp.rollaxis(g, start - 1, axis) if start > axis else anp.rollaxis(g, start, axis + 1)
+
+
+defvjp(anp.rollaxis, grad_rollaxis)
+
+
+def grad_diff(ans, a, n=1, axis=-1):
+ nd = anp.ndim(a)
+ ans_shape = anp.shape(ans)
+ sl1 = [slice(None)] * nd
+ sl1[axis] = slice(None, 1)
+
+ sl2 = [slice(None)] * nd
+ sl2[axis] = slice(-1, None)
+
+ def undiff(g):
+ if g.shape[axis] > 0:
+ return anp.concatenate((-g[tuple(sl1)], -anp.diff(g, axis=axis), g[tuple(sl2)]), axis=axis)
+ shape = list(ans_shape)
+ shape[axis] = 1
+ return anp.zeros(shape)
+
+ def helper(g, n):
+ if n == 0:
+ return g
+ return helper(undiff(g), n - 1)
+
+ return lambda g: helper(g, n)
+
+
+defvjp(anp.diff, grad_diff)
+
+
+def grad_gradient(ans, x, *vargs, **kwargs):
+ axis = kwargs.pop("axis", None)
+ if vargs or kwargs:
+ raise NotImplementedError("The only optional argument currently supported for np.gradient is axis.")
+ if axis is None:
+ axis = range(x.ndim)
+ elif type(axis) is int:
+ axis = [axis]
+ else:
+ axis = list(axis)
+
+ x_dtype = x.dtype
+ x_shape = x.shape
+ nd = x.ndim
+
+ def vjp(g):
+ if anp.ndim(g) == nd:
+ # add axis if gradient was along one axis only
+ g = g[anp.newaxis]
+
+ # accumulate gradient
+ out = anp.zeros(x_shape, dtype=x_dtype)
+
+ for i, a in enumerate(axis):
+ # swap gradient axis to the front
+ g_swap = anp.swapaxes(g[i], 0, a)[:, anp.newaxis]
+
+ out_axis = anp.concatenate(
+ (
+ -g_swap[0] - 0.5 * g_swap[1],
+ g_swap[0] - 0.5 * g_swap[2],
+ (-1.0) * anp.gradient(g_swap, axis=0)[2:-2, 0],
+ 0.5 * g_swap[-3] - g_swap[-1],
+ 0.5 * g_swap[-2] + g_swap[-1],
+ ),
+ axis=0,
+ )
+
+ out = out + anp.swapaxes(out_axis, 0, a)
+
+ return out
+
+ return vjp
+
+
+defvjp(anp.gradient, grad_gradient)
+
+
+def grad_repeat(ans, x, repeats, axis=None):
+ shape = anp.shape(x)
+
+ def vjp(g):
+ if axis is None: # If axis is none, np.repeat() repeats the flattened array.
+ expanded = anp.reshape(g, (anp.prod(shape),) + (repeats,))
+ return anp.reshape(anp.sum(expanded, axis=1, keepdims=False), shape)
+ else:
+ if shape[axis] == 1: # For this common case, the logic is simple.
+ return anp.sum(g, axis=axis, keepdims=True)
+ else:
+ expanded = anp.reshape(g, shape[0 : axis + 1] + (repeats,) + shape[axis + 1 :])
+ return anp.sum(expanded, axis=axis + 1, keepdims=False)
+
+ return vjp
+
+
+defvjp(anp.repeat, grad_repeat)
+
+
+def grad_tile(ans, x, reps):
+ reps = [reps] if anp.isscalar(reps) else reps
+ x_shape = anp.shape(x)
+
+ def vjp(g):
+ for axis, rep in enumerate(reps):
+ g = sum(anp.split(g, rep, axis))
+ return anp.reshape(g, x_shape)
+
+ return vjp
+
+
+defvjp(anp.tile, grad_tile)
+
+
+def grad_kron(argnum, ans, orig_A, orig_B):
+ # kron has different promotion rules than dot. the reshapes are necessary if
+ # and only if (1) orig_B is 1D or (2) orig_A and/or orig_B are 0D
+ orig_A_shape = anp.shape(orig_A)
+ orig_B_shape = anp.shape(orig_B)
+
+ def vjp(G):
+ A, B = anp.atleast_2d(orig_A), anp.atleast_2d(orig_B)
+ shape = list(A.shape + B.shape)
+ n = anp.ndim(A)
+ shape[n - 1], shape[n] = shape[n], shape[n - 1]
+ reshaped_G = anp.swapaxes(anp.reshape(G, shape), n - 1, n)
+ if argnum == 0:
+ return match_complex(
+ orig_A, anp.reshape(anp.tensordot(reshaped_G, B, axes=anp.ndim(B)), orig_A_shape)
+ )
+ else:
+ return match_complex(
+ orig_B, anp.reshape(anp.tensordot(A, reshaped_G, axes=anp.ndim(A)), orig_B_shape)
+ )
+
+ return vjp
+
+
+defvjp(anp.kron, partial(grad_kron, 0), partial(grad_kron, 1))
+
+
+def grad_transpose(ans, x, axes=None):
+ if axes is not None:
+ axes = anp.argsort(axes)
+ return lambda g: anp.transpose(g, axes)
+
+
+defvjp(anp.transpose, grad_transpose)
+
+
+def repeat_to_match_shape(g, shape, dtype, axis, keepdims):
+ """Returns the array g repeated along axis to fit vector space vs.
+ Also returns the number of repetitions of the array."""
+ if shape == ():
+ return g, 1
+ axis = list(axis) if isinstance(axis, tuple) else axis
+ new_shape = onp.array(shape)
+ new_shape[axis] = 1
+ num_reps = onp.prod(onp.array(shape)[axis])
+ # Can't use broadcast_to because of numpy bug: https://github.com/numpy/numpy/issues/9165
+ # return anp.broadcast_to(anp.reshape(g, new_shape), shape), num_reps
+ return anp.reshape(g, new_shape) + onp.zeros(shape, dtype=dtype), num_reps
+
+
+def grad_broadcast_to(ans, x, new_shape):
+ old_shape = anp.shape(x)
+ assert anp.shape(ans) == new_shape
+ assert len(old_shape) == len(new_shape), "Can't handle extra leading dims"
+ broadcast_axes = tuple(
+ onp.where(onp.logical_and(onp.array(old_shape) == 1, onp.array(new_shape) > 1))[0]
+ )
+ return lambda g: anp.sum(g, axis=broadcast_axes, keepdims=True)
+
+
+defvjp(anp.broadcast_to, grad_broadcast_to)
+
+
+def grad_np_sum(ans, x, axis=None, keepdims=False, dtype=None):
+ shape, dtype = anp.shape(x), anp.result_type(x)
+ return lambda g: repeat_to_match_shape(g, shape, dtype, axis, keepdims)[0]
+
+
+defvjp(anp.sum, grad_np_sum)
+
+
+def grad_np_mean(ans, x, axis=None, keepdims=False):
+ shape, dtype = anp.shape(x), anp.result_type(x)
+
+ def vjp(g):
+ g_repeated, num_reps = repeat_to_match_shape(g, shape, dtype, axis, keepdims)
+ return g_repeated / num_reps
+
+ return vjp
+
+
+defvjp(anp.mean, grad_np_mean)
+
+
+def grad_np_prod(ans, x, axis=None, keepdims=False): # TODO: Support tuples of axes.
+ shape, dtype = anp.shape(x), anp.result_type(x)
+
+ def vjp(g):
+ g_repeated, _ = repeat_to_match_shape(g * ans, shape, dtype, axis, keepdims)
+ return g_repeated / x
+
+ return vjp
+
+
+defvjp(anp.prod, grad_np_prod)
+
+
+def grad_np_var(ans, x, axis=None, ddof=0, keepdims=False):
+ shape, _, dtype, iscomplex = anp.metadata(x)
+
+ def vjp(g):
+ if iscomplex:
+ g = g + 0j
+ g_repeated, num_reps = repeat_to_match_shape(g, shape, dtype, axis, keepdims)
+ x_minus_mean = anp.conj(x - anp.mean(x, axis=axis, keepdims=True))
+ return 2.0 * g_repeated * x_minus_mean / (num_reps - ddof)
+
+ return vjp
+
+
+defvjp(anp.var, grad_np_var)
+
+
+def grad_np_std(ans, x, axis=None, ddof=0, keepdims=False):
+ shape, _, dtype, iscomplex = anp.metadata(x)
+
+ def vjp(g):
+ if iscomplex:
+ g = g + 0j
+ g_repeated, num_reps = repeat_to_match_shape(
+ g, shape, dtype, axis, keepdims
+ ) # Avoid division by zero.
+ if num_reps <= 1:
+ return g_repeated * 0.0
+ else:
+ g_repeated, num_reps = repeat_to_match_shape(g / ans, shape, dtype, axis, keepdims)
+ x_minus_mean = anp.conj(x - anp.mean(x, axis=axis, keepdims=True))
+ return g_repeated * x_minus_mean / (num_reps - ddof)
+
+ return vjp
+
+
+defvjp(anp.std, grad_np_std)
+
+
+def grad_chooser(ans, x, axis=None, keepdims=None):
+ shape, dtype = anp.shape(x), anp.result_type(x)
+
+ def vjp(g):
+ """Builds gradient of functions that choose a single item, such as min or max."""
+ g_repeated, _ = repeat_to_match_shape(g, shape, dtype, axis, keepdims)
+ argmax_locations = x == repeat_to_match_shape(ans, shape, dtype, axis, keepdims)[0]
+ return g_repeated * argmax_locations / onp.sum(argmax_locations, axis=axis, keepdims=True)
+
+ return vjp
+
+
+defvjp(anp.max, grad_chooser)
+defvjp(anp.min, grad_chooser)
+defvjp(anp.amax, grad_chooser)
+defvjp(anp.amin, grad_chooser)
+
+
+def reverse_axis(x, axis):
+ x = x.swapaxes(axis, 0)
+ x = x[::-1, ...]
+ return x.swapaxes(0, axis)
+
+
+def grad_np_cumsum(ans, x, axis=None):
+ def vjp(g):
+ if axis:
+ return reverse_axis(anp.cumsum(reverse_axis(g, axis), axis), axis)
+ else:
+ return anp.reshape(anp.cumsum(g[::-1], axis)[::-1], x.shape)
+
+ return vjp
+
+
+defvjp(anp.cumsum, grad_np_cumsum)
+
+
+def grad_inner(argnum, ans, A, B):
+ A_ndim, B_ndim = anp.ndim(A), anp.ndim(B)
+ if A_ndim == 0 or B_ndim == 0:
+ axes = ([], [])
+ else:
+ axes = ([A_ndim - 1], [B_ndim - 1])
+ if argnum == 0:
+ return lambda G: tensordot_adjoint_0(B, G, axes, A_ndim, B_ndim)
+ elif argnum == 1:
+ return lambda G: tensordot_adjoint_1(A, G, axes, A_ndim, B_ndim)
+
+
+defvjp(anp.inner, partial(grad_inner, 0), partial(grad_inner, 1))
+
+
+def matmul_adjoint_0(B, G, A_meta, B_ndim):
+ if anp.ndim(G) == 0: # A_ndim == B_ndim == 1
+ return unbroadcast(G * B, A_meta)
+ _, A_ndim, _, _ = A_meta
+ if A_ndim == 1:
+ G = anp.expand_dims(G, anp.ndim(G) - 1)
+ if B_ndim == 1: # The result we need is an outer product
+ B = anp.expand_dims(B, 0)
+ G = anp.expand_dims(G, anp.ndim(G))
+ else: # We need to swap the last two axes of B
+ B = anp.swapaxes(B, B_ndim - 2, B_ndim - 1)
+ result = anp.matmul(G, B)
+ return unbroadcast(result, A_meta)
+
+
+def matmul_adjoint_1(A, G, A_ndim, B_meta):
+ if anp.ndim(G) == 0: # A_ndim == B_ndim == 1
+ return unbroadcast(G * A, B_meta)
+ _, B_ndim, _, _ = B_meta
+ B_is_vec = B_ndim == 1
+ if B_is_vec:
+ G = anp.expand_dims(G, anp.ndim(G))
+ if A_ndim == 1: # The result we need is an outer product
+ A = anp.expand_dims(A, 1)
+ G = anp.expand_dims(G, anp.ndim(G) - 1)
+ else: # We need to swap the last two axes of A
+ A = anp.swapaxes(A, A_ndim - 2, A_ndim - 1)
+ result = anp.matmul(A, G)
+ if B_is_vec:
+ result = anp.squeeze(result, anp.ndim(G) - 1)
+ return unbroadcast(result, B_meta)
+
+
+def matmul_vjp_0(ans, A, B):
+ A_meta = anp.metadata(A)
+ B_ndim = anp.ndim(B)
+ return lambda g: matmul_adjoint_0(B, g, A_meta, B_ndim)
+
+
+def matmul_vjp_1(ans, A, B):
+ A_ndim = anp.ndim(A)
+ B_meta = anp.metadata(B)
+ return lambda g: matmul_adjoint_1(A, g, A_ndim, B_meta)
+
+
+defvjp(anp.matmul, matmul_vjp_0, matmul_vjp_1)
+
+
+@primitive
+def dot_adjoint_0(B, G, A_meta, B_meta):
+ _, A_ndim, A_dtype, _ = A_meta
+ _, B_ndim, _, _ = B_meta
+ if B_ndim == 0 or B_ndim == 1 or A_ndim == 0:
+ contract_num = max(0, B_ndim - (A_ndim != 0))
+ out = onp.tensordot(G, B, contract_num)
+ else:
+ out = onp.tensordot(G, onp.swapaxes(B, -1, -2), B_ndim - 1)
+ return onp.asarray(out, dtype=A_dtype)
+
+
+@primitive
+def dot_adjoint_1(A, G, A_meta, B_meta):
+ _, A_ndim, _, _ = A_meta
+ _, B_ndim, B_dtype, _ = B_meta
+ needs_transpose = B_ndim > 1 and A_ndim != 0
+ swap = (lambda x: onp.swapaxes(x, -1, -2)) if needs_transpose else (lambda x: x)
+ if A_ndim == 0 or A_ndim == 1 or B_ndim == 0:
+ contract_num = max(0, A_ndim - (B_ndim != 0))
+ out = swap(onp.tensordot(G, A, contract_num))
+ else:
+ out = swap(onp.tensordot(G, A, [range(-A_ndim - B_ndim + 2, -B_ndim + 1), range(A_ndim - 1)]))
+ return onp.asarray(out, dtype=B_dtype)
+
+
+def dot_vjp_0(ans, A, B):
+ A_meta, B_meta = anp.metadata(A), anp.metadata(B)
+ return lambda g: match_complex(A, dot_adjoint_0(B, g, A_meta, B_meta))
+
+
+def dot_vjp_1(ans, A, B):
+ A_meta, B_meta = anp.metadata(A), anp.metadata(B)
+ return lambda g: match_complex(B, dot_adjoint_1(A, g, A_meta, B_meta))
+
+
+defvjp(anp.dot, dot_vjp_0, dot_vjp_1)
+
+defvjp(
+ dot_adjoint_0,
+ lambda ans, B, g, An, Bn: lambda A: match_complex(B, dot_adjoint_1(A, g, An, Bn)),
+ lambda ans, B, g, An, Bn: lambda A: match_complex(g, anp.dot(A, B)),
+)
+
+defvjp(
+ dot_adjoint_1,
+ lambda ans, A, g, An, Bn: lambda B: match_complex(A, dot_adjoint_0(B, g, An, Bn)),
+ lambda ans, A, g, An, Bn: lambda B: match_complex(g, anp.dot(A, B)),
+)
+
+
+@primitive
+def tensordot_adjoint_0(B, G, axes, A_ndim, B_ndim):
+ # The adjoint of the operator
+ # A |--> np.tensordot(A, B, axes)
+ if B_ndim == 0:
+ return G * B
+
+ G_axes = onp.arange(onp.ndim(G))
+ if type(axes) is int:
+ axes = max(axes, 0)
+ B_axes = onp.arange(B_ndim)
+ return onp.tensordot(G, B, [G_axes[A_ndim - axes :], B_axes[axes:]])
+ else:
+ axes0 = [axes[0]] if type(axes[0]) is int else axes[0]
+ axes1 = [axes[1]] if type(axes[1]) is int else axes[1]
+ axes = [axes0, axes1]
+ A_axes = onp.arange(A_ndim)
+ B_axes = onp.arange(B_ndim)
+ summed_axes = [
+ onp.asarray(axes[0], dtype="int64") % A_ndim,
+ onp.asarray(axes[1], dtype="int64") % B_ndim,
+ ]
+ other_axes = [onp.delete(A_axes, summed_axes[0]), onp.delete(B_axes, summed_axes[1])]
+ out = onp.tensordot(G, B, [G_axes[len(other_axes[0]) :], other_axes[1]])
+ perm = onp.argsort(onp.concatenate((other_axes[0], summed_axes[0][onp.argsort(summed_axes[1])])))
+ return onp.transpose(out, perm)
+
+
+@primitive
+def tensordot_adjoint_1(A, G, axes, A_ndim, B_ndim):
+ # The adjoint of the operator
+ # B |--> np.tensordot(A, B, axes)
+ if A_ndim == 0:
+ return G * A
+
+ G_axes = onp.arange(onp.ndim(G))
+ if type(axes) is int:
+ axes = max(axes, 0)
+ A_axes = onp.arange(A_ndim)
+ return onp.tensordot(A, G, [A_axes[: A_ndim - axes], G_axes[: A_ndim - axes]])
+ else:
+ axes0 = [axes[0]] if type(axes[0]) is int else axes[0]
+ axes1 = [axes[1]] if type(axes[1]) is int else axes[1]
+ axes = [axes0, axes1]
+ A_axes = onp.arange(A_ndim)
+ B_axes = onp.arange(B_ndim)
+ summed_axes = [
+ onp.asarray(axes[0], dtype="int64") % A_ndim,
+ onp.asarray(axes[1], dtype="int64") % B_ndim,
+ ]
+ other_axes = [onp.delete(A_axes, summed_axes[0]), onp.delete(B_axes, summed_axes[1])]
+ out = onp.tensordot(A, G, [other_axes[0], G_axes[: len(other_axes[0])]])
+ perm = onp.argsort(onp.concatenate((summed_axes[1][onp.argsort(summed_axes[0])], other_axes[1])))
+ return onp.transpose(out, perm)
+
+
+def tensordot_vjp_0(ans, A, B, axes=2):
+ A_ndim, B_ndim = anp.ndim(A), anp.ndim(B)
+ return lambda G: match_complex(A, tensordot_adjoint_0(B, G, axes, A_ndim, B_ndim))
+
+
+def tensordot_vjp_1(ans, A, B, axes=2):
+ A_ndim, B_ndim = anp.ndim(A), anp.ndim(B)
+ return lambda G: match_complex(B, tensordot_adjoint_1(A, G, axes, A_ndim, B_ndim))
+
+
+defvjp(anp.tensordot, tensordot_vjp_0, tensordot_vjp_1)
+defvjp(
+ tensordot_adjoint_0,
+ lambda ans, B, G, axes, An, Bn: lambda A: match_complex(B, tensordot_adjoint_1(A, G, axes, An, Bn)),
+ lambda ans, B, G, axes, An, Bn: lambda A: match_complex(G, anp.tensordot(A, B, axes)),
+)
+defvjp(
+ tensordot_adjoint_1,
+ lambda ans, A, G, axes, An, Bn: lambda B: match_complex(A, tensordot_adjoint_0(B, G, axes, An, Bn)),
+ lambda ans, A, G, axes, An, Bn: lambda B: match_complex(G, anp.tensordot(A, B, axes)),
+)
+defvjp(
+ anp.outer,
+ lambda ans, a, b: lambda g: match_complex(a, anp.dot(g, b.T)),
+ lambda ans, a, b: lambda g: match_complex(b, anp.dot(a.T, g)),
+)
+
+
+def grad_concatenate_args(argnum, ans, axis_args, kwargs):
+ axis, args = axis_args[0], axis_args[1:]
+ sizes = [anp.shape(a)[axis] for a in args[:argnum]]
+ start = sum(sizes[:-1])
+ idxs = [slice(None)] * ans.ndim
+ idxs[axis] = slice(start, start + sizes[-1])
+ return lambda g: g[tuple(idxs)]
+
+
+defvjp_argnum(anp.concatenate_args, grad_concatenate_args)
+
+
+def wrapped_reshape(x, *args, **kwargs):
+ # The reshape method can be called like A.reshape((5,4)) or A.reshape(5,4).
+ # The reshape function doesn't support both ways, so we have to wrap it.
+ if isinstance(args[0], int):
+ return anp.reshape(x, args, **kwargs)
+ else:
+ return anp.reshape(x, *args, **kwargs)
+
+
+setattr(ArrayBox, "reshape", wrapped_reshape)
+
+
+def grad_sort(ans, x, axis=-1, kind="quicksort", order=None):
+ # TODO: Cast input with np.asanyarray()
+ if len(x.shape) > 1:
+ raise NotImplementedError("Gradient of sort not implemented for multi-dimensional arrays.")
+ sort_perm = anp.argsort(x, axis, kind, order)
+ return lambda g: unpermuter(g, sort_perm)
+
+
+defvjp(anp.sort, grad_sort)
+if onp.lib.NumpyVersion(onp.__version__) < "2.0.0":
+ defvjp(anp.msort, grad_sort) # Until multi-D is allowed, these are the same.
+
+
+def grad_partition(ans, x, kth, axis=-1, kind="introselect", order=None):
+ # TODO: Cast input with np.asanyarray()
+ if len(x.shape) > 1:
+ raise NotImplementedError("Gradient of partition not implemented for multi-dimensional arrays.")
+ partition_perm = anp.argpartition(x, kth, axis, kind, order)
+ return lambda g: unpermuter(g, partition_perm)
+
+
+defvjp(anp.partition, grad_partition)
+
+
+def unpermuter(g, permutation):
+ unsort = anp.zeros(len(permutation), dtype=int)
+ unsort[permutation] = list(range(len(permutation)))
+ return g[unsort]
+
+
+def grad_reshape_list(ans, *arys):
+ if len(arys) > 1:
+ raise NotImplementedError("Can't handle multiple arguments yet.")
+ return lambda g: anp.reshape(g, anp.shape(arys[0]))
+
+
+defvjp(anp.atleast_1d, grad_reshape_list)
+defvjp(anp.atleast_2d, grad_reshape_list)
+defvjp(anp.atleast_3d, grad_reshape_list)
+
+
+def grad_einsum(argnum, ans, operands_, kwargs):
+ result_meta = anp.metadata(operands_[argnum])
+
+ def vjp(g):
+ operands = operands_
+ if isinstance(operands[0], str): # using "ijk" convention.
+ in_subs, out_subs, _ = anp.parse_einsum_input(*operands)
+ string, operands = operands[0], operands[1:]
+
+ in_subs_list = in_subs.split(",")
+ op_num = argnum - 1
+ subs_wrt = in_subs_list[op_num]
+ rest_of_ops = operands[:op_num] + operands[op_num + 1 :]
+ rest_of_subs = in_subs_list[:op_num] + in_subs_list[op_num + 1 :]
+
+ # subscripts that only appear in subs_wrt (and not in other subscript lists
+ # or in the output) are implicitly being summed out, as if contracted
+ # against a tensor of ones. we make that tensor of ones explicit to handle
+ # the necessary vjp broadcasting inside einsum.
+ other_named_subs = set("".join([out_subs] + rest_of_subs))
+ naked_summed = [(i, sub) for i, sub in enumerate(subs_wrt) if sub not in other_named_subs]
+ if naked_summed:
+ naked_summed_dims, ones_subs = zip(*naked_summed)
+ ones_subs = "".join(ones_subs)
+ ones = onp.ones(onp.array(operands[op_num].shape)[list(naked_summed_dims)])
+ new_input_subs = ",".join([out_subs, ones_subs] + rest_of_subs)
+ new_operands = (g, ones) + rest_of_ops
+ else:
+ new_input_subs = ",".join([out_subs] + rest_of_subs)
+ new_operands = (g,) + rest_of_ops
+
+ new_subscripts = new_input_subs + "->" + subs_wrt
+ return unbroadcast(anp.einsum(new_subscripts, *new_operands), result_meta)
+ else: # using (op0, sublist0, op1, sublist1, ..., sublistout) convention
+ if len(operands) % 2 == 0:
+ raise NotImplementedError("Need sublistout argument")
+ operands = list(operands)
+ rest_of_ops = (
+ [operands[-1]] + operands[:argnum] + operands[(argnum + 2) : -1] + [operands[argnum + 1]]
+ )
+ return unbroadcast_einsum(anp.einsum(g, *rest_of_ops), result_meta, operands[argnum + 1])
+
+ return vjp
+
+
+defvjp_argnum(anp.einsum, grad_einsum)
+
+defvjp(
+ anp.diagonal,
+ lambda ans, A, offset=0, axis1=0, axis2=1: lambda g: anp.make_diagonal(g, offset, axis1, axis2),
+)
+defvjp(
+ anp.make_diagonal,
+ lambda ans, D, offset=0, axis1=0, axis2=1: lambda g: anp.diagonal(g, offset, axis1, axis2),
+)
+
+
+def match_complex(target, x):
+ target_iscomplex = anp.iscomplexobj(target)
+ x_iscomplex = anp.iscomplexobj(x)
+ if x_iscomplex and not target_iscomplex:
+ return anp.real(x)
+ elif not x_iscomplex and target_iscomplex:
+ return x + 0j
+ else:
+ return x
+
+
+def unbroadcast(x, target_meta, broadcast_idx=0):
+ target_shape, target_ndim, dtype, target_iscomplex = target_meta
+ while anp.ndim(x) > target_ndim:
+ x = anp.sum(x, axis=broadcast_idx)
+ for axis, size in enumerate(target_shape):
+ if size == 1:
+ x = anp.sum(x, axis=axis, keepdims=True)
+ if anp.iscomplexobj(x) and not target_iscomplex:
+ x = anp.real(x)
+ return x
+
+
+def unbroadcast_f(target, f):
+ target_meta = anp.metadata(target)
+ return lambda g: unbroadcast(f(g), target_meta)
+
+
+def unbroadcast_einsum(x, target_meta, subscript):
+ if Ellipsis not in subscript:
+ return x
+ elif subscript[0] == Ellipsis:
+ return unbroadcast(x, target_meta, 0)
+ elif subscript[-1] == Ellipsis:
+ return unbroadcast(x, target_meta, -1)
+ else:
+ return unbroadcast(x, target_meta, subscript.index(Ellipsis))
+
+
+def balanced_eq(x, z, y):
+ return (x == z) / (1.0 + (x == y))
+
+
+def replace_zero(x, val):
+ return anp.where(x, x, val)
+
+
+# ----- extra functions used internally -----
+
+
+def array_from_args_gradmaker(argnum, ans, args, kwargs):
+ return lambda g: g[argnum - 2]
+
+
+defvjp_argnum(anp.array_from_args, array_from_args_gradmaker)
+
+
+def array_from_scalar_or_array_gradmaker(ans, array_args, array_kwargs, scarray):
+ ndmin = array_kwargs.get("ndmin", 0)
+ scarray_ndim = anp.ndim(scarray)
+ if ndmin > scarray_ndim:
+ return lambda g: anp.squeeze(g, axis=tuple(range(ndmin - scarray_ndim)))
+ else:
+ return lambda g: g
+
+
+defvjp(anp._array_from_scalar_or_array, array_from_scalar_or_array_gradmaker, argnums=(2, 3))
+
+
+@primitive
+def untake(x, idx, vs):
+ if isinstance(idx, list) and (len(idx) == 0 or not isinstance(idx[0], slice)):
+ idx = onp.array(idx, dtype="int64")
+
+ def mut_add(A):
+ onp.add.at(A, idx, x)
+ return A
+
+ return SparseObject(vs, mut_add)
+
+
+defvjp(func(ArrayBox.__getitem__), lambda ans, A, idx: lambda g: untake(g, idx, vspace(A)))
+defvjp(untake, lambda ans, x, idx, _: lambda g: g[idx])
+
+
+def _unpad(array, width):
+ if anp.isscalar(width):
+ width = [[width, width]]
+ elif anp.shape(width) == (1,):
+ width = [anp.concatenate((width, width))]
+ elif anp.shape(width) == (2,):
+ width = [width]
+ if anp.shape(width)[0] == 1:
+ width = anp.repeat(width, anp.ndim(array), 0)
+ idxs = tuple(slice(l, -u or None) for l, u in width)
+ return array[idxs]
+
+
+def pad_vjp(ans, array, pad_width, mode, **kwargs):
+ assert mode == "constant", "Only constant mode padding is supported."
+ return lambda g: _unpad(g, pad_width)
+
+
+defvjp(anp.pad, pad_vjp)
diff --git a/venv/Lib/site-packages/autograd/numpy/numpy_vspaces.py b/venv/Lib/site-packages/autograd/numpy/numpy_vspaces.py
new file mode 100644
index 0000000000000000000000000000000000000000..c1f77f4aa01f0720537a431f22b5610e6be39336
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/numpy/numpy_vspaces.py
@@ -0,0 +1,121 @@
+import numpy as np
+
+from autograd.builtins import NamedTupleVSpace
+from autograd.extend import VSpace
+
+
+class ArrayVSpace(VSpace):
+ def __init__(self, value):
+ value = np.asarray(value)
+ self.shape = value.shape
+ self.dtype = value.dtype
+
+ @property
+ def size(self):
+ return np.prod(self.shape)
+
+ @property
+ def ndim(self):
+ return len(self.shape)
+
+ def zeros(self):
+ return np.zeros(self.shape, dtype=self.dtype)
+
+ def ones(self):
+ return np.ones(self.shape, dtype=self.dtype)
+
+ def standard_basis(self):
+ for idxs in np.ndindex(*self.shape):
+ vect = np.zeros(self.shape, dtype=self.dtype)
+ vect[idxs] = 1
+ yield vect
+
+ def randn(self):
+ return np.array(np.random.randn(*self.shape)).astype(self.dtype)
+
+ def _inner_prod(self, x, y):
+ return np.dot(np.ravel(x), np.ravel(y))
+
+
+class ComplexArrayVSpace(ArrayVSpace):
+ iscomplex = True
+
+ @property
+ def size(self):
+ return np.prod(self.shape) * 2
+
+ def ones(self):
+ return np.ones(self.shape, dtype=self.dtype) + 1.0j * np.ones(self.shape, dtype=self.dtype)
+
+ def standard_basis(self):
+ for idxs in np.ndindex(*self.shape):
+ for v in [1.0, 1.0j]:
+ vect = np.zeros(self.shape, dtype=self.dtype)
+ vect[idxs] = v
+ yield vect
+
+ def randn(self):
+ return np.array(np.random.randn(*self.shape)).astype(self.dtype) + 1.0j * np.array(
+ np.random.randn(*self.shape)
+ ).astype(self.dtype)
+
+ def _inner_prod(self, x, y):
+ return np.real(np.dot(np.conj(np.ravel(x)), np.ravel(y)))
+
+ def _covector(self, x):
+ return np.conj(x)
+
+
+VSpace.register(np.ndarray, lambda x: ComplexArrayVSpace(x) if np.iscomplexobj(x) else ArrayVSpace(x))
+
+for type_ in [float, np.longdouble, np.float64, np.float32, np.float16]:
+ ArrayVSpace.register(type_)
+
+for type_ in [complex, np.clongdouble, np.complex64, np.complex128]:
+ ComplexArrayVSpace.register(type_)
+
+
+if np.lib.NumpyVersion(np.__version__) >= "2.0.0":
+
+ class EigResultVSpace(NamedTupleVSpace):
+ seq_type = np.linalg._linalg.EigResult
+
+ class EighResultVSpace(NamedTupleVSpace):
+ seq_type = np.linalg._linalg.EighResult
+
+ class QRResultVSpace(NamedTupleVSpace):
+ seq_type = np.linalg._linalg.QRResult
+
+ class SlogdetResultVSpace(NamedTupleVSpace):
+ seq_type = np.linalg._linalg.SlogdetResult
+
+ class SVDResultVSpace(NamedTupleVSpace):
+ seq_type = np.linalg._linalg.SVDResult
+
+ EigResultVSpace.register(np.linalg._linalg.EigResult)
+ EighResultVSpace.register(np.linalg._linalg.EighResult)
+ QRResultVSpace.register(np.linalg._linalg.QRResult)
+ SlogdetResultVSpace.register(np.linalg._linalg.SlogdetResult)
+ SVDResultVSpace.register(np.linalg._linalg.SVDResult)
+elif np.__version__ >= "1.25":
+
+ class EigResultVSpace(NamedTupleVSpace):
+ seq_type = np.linalg.linalg.EigResult
+
+ class EighResultVSpace(NamedTupleVSpace):
+ seq_type = np.linalg.linalg.EighResult
+
+ class QRResultVSpace(NamedTupleVSpace):
+ seq_type = np.linalg.linalg.QRResult
+
+ class SlogdetResultVSpace(NamedTupleVSpace):
+ seq_type = np.linalg.linalg.SlogdetResult
+
+ class SVDResultVSpace(NamedTupleVSpace):
+ seq_type = np.linalg.linalg.SVDResult
+
+ EigResultVSpace.register(np.linalg.linalg.EigResult)
+ EighResultVSpace.register(np.linalg.linalg.EighResult)
+ QRResultVSpace.register(np.linalg.linalg.QRResult)
+ SlogdetResultVSpace.register(np.linalg.linalg.SlogdetResult)
+ SVDResultVSpace.register(np.linalg.linalg.SVDResult)
diff --git a/venv/Lib/site-packages/autograd/numpy/numpy_wrapper.py b/venv/Lib/site-packages/autograd/numpy/numpy_wrapper.py
new file mode 100644
index 0000000000000000000000000000000000000000..ab97f21461006becb6b03892998a68badb898f39
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/numpy/numpy_wrapper.py
@@ -0,0 +1,187 @@
+import warnings
+
+import numpy as _np
+
+import autograd.builtins as builtins
+from autograd.extend import notrace_primitive, primitive
+
+if _np.lib.NumpyVersion(_np.__version__) >= "2.0.0":
+ from numpy._core.einsumfunc import _parse_einsum_input
+else:
+ from numpy.core.einsumfunc import _parse_einsum_input
+
+numpy_version = _np.__version__
+
+notrace_functions = [_np.ndim, _np.shape, _np.iscomplexobj, _np.result_type]
+
+
+def wrap_intdtype(cls):
+ class IntdtypeSubclass(cls):
+ __new__ = notrace_primitive(cls.__new__)
+
+ return IntdtypeSubclass
+
+
+def wrap_namespace(old, new):
+ unchanged_types = {float, int, type(None), type}
+ int_types = {_np.int8, _np.int16, _np.int32, _np.int64, _np.integer}
+ for name, obj in old.items():
+ if obj in notrace_functions:
+ new[name] = notrace_primitive(obj)
+ elif callable(obj) and type(obj) is not type:
+ new[name] = primitive(obj)
+ elif type(obj) is type and obj in int_types:
+ new[name] = wrap_intdtype(obj)
+ elif type(obj) in unchanged_types:
+ new[name] = obj
+
+
+wrap_namespace(_np.__dict__, globals())
+
+# ----- Special treatment of list-input functions -----
+
+
+@primitive
+def concatenate_args(axis, *args):
+ return _np.concatenate(args, axis).view(ndarray)
+
+
+concatenate = lambda arr_list, axis=0: concatenate_args(axis, *arr_list)
+vstack = row_stack = lambda tup: concatenate([atleast_2d(_m) for _m in tup], axis=0)
+
+
+def hstack(tup):
+ arrs = [atleast_1d(_m) for _m in tup]
+ if arrs[0].ndim == 1:
+ return concatenate(arrs, 0)
+ return concatenate(arrs, 1)
+
+
+def column_stack(tup):
+ arrays = []
+ for v in tup:
+ arr = array(v)
+ if arr.ndim < 2:
+ arr = array(arr, ndmin=2).T
+ arrays.append(arr)
+ return concatenate(arrays, 1)
+
+
+def array(A, *args, **kwargs):
+ t = builtins.type(A)
+ if t in (list, tuple):
+ return array_from_args(args, kwargs, *map(array, A))
+ else:
+ return _array_from_scalar_or_array(args, kwargs, A)
+
+
+def wrap_if_boxes_inside(raw_array, slow_op_name=None):
+ if raw_array.dtype is _np.dtype("O"):
+ if slow_op_name:
+ warnings.warn("{} is slow for array inputs. np.concatenate() is faster.".format(slow_op_name))
+ return array_from_args((), {}, *raw_array.ravel()).reshape(raw_array.shape)
+ else:
+ return raw_array
+
+
+@primitive
+def _array_from_scalar_or_array(array_args, array_kwargs, scalar):
+ return _np.array(scalar, *array_args, **array_kwargs)
+
+
+@primitive
+def array_from_args(array_args, array_kwargs, *args):
+ return _np.array(args, *array_args, **array_kwargs)
+
+
+def select(condlist, choicelist, default=0):
+ raw_array = _np.select(list(condlist), list(choicelist), default=default)
+ return array(list(raw_array.ravel())).reshape(raw_array.shape)
+
+
+def stack(arrays, axis=0):
+ # this code is basically copied from numpy/core/shape_base.py's stack
+ # we need it here because we want to re-implement stack in terms of the
+ # primitives defined in this file
+
+ arrays = [array(arr) for arr in arrays]
+ if not arrays:
+ raise ValueError("need at least one array to stack")
+
+ shapes = {arr.shape for arr in arrays}
+ if len(shapes) != 1:
+ raise ValueError("all input arrays must have the same shape")
+
+ result_ndim = arrays[0].ndim + 1
+ if not -result_ndim <= axis < result_ndim:
+ raise IndexError("axis {0} out of bounds [-{1}, {1})".format(axis, result_ndim))
+ if axis < 0:
+ axis += result_ndim
+
+ sl = (slice(None),) * axis + (None,)
+ return concatenate([arr[sl] for arr in arrays], axis=axis)
+
+
+def append(arr, values, axis=None):
+ # this code is basically copied from numpy/lib/function_base.py's append
+ arr = array(arr)
+ if axis is None:
+ if ndim(arr) != 1:
+ arr = ravel(arr)
+ values = ravel(array(values))
+ axis = ndim(arr) - 1
+ return concatenate((arr, values), axis=axis)
+
+
+# ----- Enable functions called using [] ----
+
+
+class r_class:
+ def __getitem__(self, args):
+ raw_array = _np.r_[args]
+ return wrap_if_boxes_inside(raw_array, slow_op_name="r_")
+
+
+r_ = r_class()
+
+
+class c_class:
+ def __getitem__(self, args):
+ raw_array = _np.c_[args]
+ return wrap_if_boxes_inside(raw_array, slow_op_name="c_")
+
+
+c_ = c_class()
+
+
+# ----- misc -----
+@primitive
+def make_diagonal(D, offset=0, axis1=0, axis2=1):
+ # Numpy doesn't offer a complement to np.diagonal: a function to create new
+ # diagonal arrays with extra dimensions. We need such a function for the
+ # gradient of np.diagonal and it's also quite handy to have. So here it is.
+ if not (offset == 0 and axis1 == -1 and axis2 == -2):
+ raise NotImplementedError("Currently make_diagonal only supports offset=0, axis1=-1, axis2=-2")
+
+ # We use a trick: calling np.diagonal returns a view on the original array,
+ # so we can modify it in-place. (only valid for numpy version >= 1.10.)
+ new_array = _np.zeros(D.shape + (D.shape[-1],))
+ new_array_diag = _np.diagonal(new_array, offset=0, axis1=-1, axis2=-2)
+ new_array_diag.flags.writeable = True
+ new_array_diag[:] = D
+ return new_array
+
+
+@notrace_primitive
+def metadata(A):
+ return _np.shape(A), _np.ndim(A), _np.result_type(A), _np.iscomplexobj(A)
+
+
+@notrace_primitive
+def parse_einsum_input(*args):
+ return _parse_einsum_input(args)
+
+
+@primitive
+def _astype(A, dtype, order="K", casting="unsafe", subok=True, copy=True):
+ return A.astype(dtype, order, casting, subok, copy)
diff --git a/venv/Lib/site-packages/autograd/numpy/random.py b/venv/Lib/site-packages/autograd/numpy/random.py
new file mode 100644
index 0000000000000000000000000000000000000000..7f78ce81abab5bc32f76f17dd5d52af90ad21fee
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/numpy/random.py
@@ -0,0 +1,5 @@
+import numpy.random as npr
+
+from .numpy_wrapper import wrap_namespace
+
+wrap_namespace(npr.__dict__, globals())
diff --git a/venv/Lib/site-packages/autograd/scipy/__init__.py b/venv/Lib/site-packages/autograd/scipy/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d41fa043a235851c5b8ad7b25744a9f7b0cbb315
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/__init__.py
@@ -0,0 +1 @@
+from . import integrate, signal, special, stats
diff --git a/venv/Lib/site-packages/autograd/scipy/integrate.py b/venv/Lib/site-packages/autograd/scipy/integrate.py
new file mode 100644
index 0000000000000000000000000000000000000000..401e5a9710595d8c7474ccd31c3494390f31d92b
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/integrate.py
@@ -0,0 +1,80 @@
+import scipy.integrate
+
+import autograd.numpy as np
+from autograd import make_vjp
+from autograd.builtins import tuple
+from autograd.extend import defvjp_argnums, primitive
+from autograd.misc import flatten
+
+odeint = primitive(scipy.integrate.odeint)
+
+
+def grad_odeint(yt, func, y0, t, func_args, **kwargs):
+ # Extended from "Scalable Inference of Ordinary Differential
+ # Equation Models of Biochemical Processes", Sec. 2.4.2
+ # Fabian Froehlich, Carolin Loos, Jan Hasenauer, 2017
+ # https://arxiv.org/abs/1711.08079
+
+ T, D = np.shape(yt)
+ flat_args, unflatten = flatten(func_args)
+
+ def flat_func(y, t, flat_args):
+ return func(y, t, *unflatten(flat_args))
+
+ def unpack(x):
+ # y, vjp_y, vjp_t, vjp_args
+ return x[0:D], x[D : 2 * D], x[2 * D], x[2 * D + 1 :]
+
+ def augmented_dynamics(augmented_state, t, flat_args):
+ # Orginal system augmented with vjp_y, vjp_t and vjp_args.
+ y, vjp_y, _, _ = unpack(augmented_state)
+ vjp_all, dy_dt = make_vjp(flat_func, argnum=(0, 1, 2))(y, t, flat_args)
+ vjp_y, vjp_t, vjp_args = vjp_all(-vjp_y)
+ return np.hstack((dy_dt, vjp_y, vjp_t, vjp_args))
+
+ def vjp_all(g):
+ vjp_y = g[-1, :]
+ vjp_t0 = 0
+ time_vjp_list = []
+ vjp_args = np.zeros(np.size(flat_args))
+
+ for i in range(T - 1, 0, -1):
+ # Compute effect of moving measurement time.
+ vjp_cur_t = np.dot(func(yt[i, :], t[i], *func_args), g[i, :])
+ time_vjp_list.append(vjp_cur_t)
+ vjp_t0 = vjp_t0 - vjp_cur_t
+
+ # Run augmented system backwards to the previous observation.
+ aug_y0 = np.hstack((yt[i, :], vjp_y, vjp_t0, vjp_args))
+ aug_ans = odeint(
+ augmented_dynamics, aug_y0, np.array([t[i], t[i - 1]]), tuple((flat_args,)), **kwargs
+ )
+ _, vjp_y, vjp_t0, vjp_args = unpack(aug_ans[1])
+
+ # Add gradient from current output.
+ vjp_y = vjp_y + g[i - 1, :]
+
+ time_vjp_list.append(vjp_t0)
+ vjp_times = np.hstack(time_vjp_list)[::-1]
+
+ return None, vjp_y, vjp_times, unflatten(vjp_args)
+
+ return vjp_all
+
+
+def argnums_unpack(all_vjp_builder):
+ # A generic autograd helper function. Takes a function that
+ # builds vjps for all arguments, and wraps it to return only required vjps.
+ def build_selected_vjps(argnums, ans, combined_args, kwargs):
+ vjp_func = all_vjp_builder(ans, *combined_args, **kwargs)
+
+ def chosen_vjps(g): # Returns whichever vjps were asked for.
+ all_vjps = vjp_func(g)
+ return [all_vjps[argnum] for argnum in argnums]
+
+ return chosen_vjps
+
+ return build_selected_vjps
+
+
+defvjp_argnums(odeint, argnums_unpack(grad_odeint))
diff --git a/venv/Lib/site-packages/autograd/scipy/linalg.py b/venv/Lib/site-packages/autograd/scipy/linalg.py
new file mode 100644
index 0000000000000000000000000000000000000000..d2cc886a94141a28ffa188f8fd5a807b7f1dba94
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/linalg.py
@@ -0,0 +1,148 @@
+from functools import partial
+
+import scipy.linalg
+
+import autograd.numpy as anp
+from autograd.extend import defjvp, defjvp_argnums, defvjp, defvjp_argnums
+from autograd.numpy.numpy_wrapper import wrap_namespace
+
+wrap_namespace(scipy.linalg.__dict__, globals()) # populates module namespace
+
+
+def _vjp_sqrtm(ans, A, disp=True, blocksize=64):
+ assert disp, "sqrtm vjp not implemented for disp=False"
+ ans_transp = anp.transpose(ans)
+
+ def vjp(g):
+ return anp.real(solve_sylvester(ans_transp, ans_transp, g))
+
+ return vjp
+
+
+defvjp(sqrtm, _vjp_sqrtm)
+
+
+def _flip(a, trans):
+ if anp.iscomplexobj(a):
+ return "H" if trans in ("N", 0) else "N"
+ else:
+ return "T" if trans in ("N", 0) else "N"
+
+
+def grad_solve_triangular(ans, a, b, trans=0, lower=False, **kwargs):
+ tri = anp.tril if (lower ^ (_flip(a, trans) == "N")) else anp.triu
+ transpose = lambda x: x if _flip(a, trans) != "N" else x.T
+ al2d = lambda x: x if x.ndim > 1 else x[..., None]
+
+ def vjp(g):
+ v = al2d(solve_triangular(a, g, trans=_flip(a, trans), lower=lower))
+ return -transpose(tri(anp.dot(v, al2d(ans).T)))
+
+ return vjp
+
+
+defvjp(
+ solve_triangular,
+ grad_solve_triangular,
+ lambda ans, a, b, trans=0, lower=False, **kwargs: lambda g: solve_triangular(
+ a, g, trans=_flip(a, trans), lower=lower
+ ),
+)
+
+
+def grad_solve_banded(argnum, ans, l_and_u, a, b):
+ updim = lambda x: x if x.ndim == a.ndim else x[..., None]
+
+ def transpose_banded(l_and_u, a):
+ # Compute the transpose of a banded matrix.
+ # The transpose is itself a banded matrix.
+
+ num_rows = a.shape[0]
+
+ shifts = anp.arange(-l_and_u[1], l_and_u[0] + 1)
+
+ T_a = anp.roll(a[:1, :], shifts[0])
+ for rr in range(1, num_rows):
+ T_a = anp.vstack([T_a, anp.flipud(anp.roll(a[rr : rr + 1, :], shifts[rr]))])
+ T_a = anp.flipud(T_a)
+
+ T_l_and_u = anp.flip(l_and_u)
+
+ return T_l_and_u, T_a
+
+ def banded_dot(l_and_u, uu, vv):
+ # Compute tensor product of vectors uu and vv.
+ # Tensor product elements are resticted to the bands specified by l_and_u.
+
+ # TODO: replace the brute-force ravel() by smarter dimension handeling of uu and vv
+
+ # main diagonal
+ banded_uv = anp.ravel(uu) * anp.ravel(vv)
+
+ # stack below the sub-diagonals
+ for rr in range(1, l_and_u[0] + 1):
+ banded_uv_rr = anp.hstack([anp.ravel(uu)[rr:] * anp.ravel(vv)[:-rr], anp.zeros(rr)])
+ banded_uv = anp.vstack([banded_uv, banded_uv_rr])
+
+ # stack above the sup-diagonals
+ for rr in range(1, l_and_u[1] + 1):
+ banded_uv_rr = anp.hstack([anp.zeros(rr), anp.ravel(uu)[:-rr] * anp.ravel(vv)[rr:]])
+ banded_uv = anp.vstack([banded_uv_rr, banded_uv])
+
+ return banded_uv
+
+ T_l_and_u, T_a = transpose_banded(l_and_u, a)
+
+ if argnum == 1:
+ return lambda g: -banded_dot(
+ l_and_u, updim(solve_banded(T_l_and_u, T_a, g)), anp.transpose(updim(ans))
+ )
+ elif argnum == 2:
+ return lambda g: solve_banded(T_l_and_u, T_a, g)
+
+
+defvjp(solve_banded, partial(grad_solve_banded, 1), partial(grad_solve_banded, 2), argnums=[1, 2])
+
+
+def _jvp_sqrtm(dA, ans, A, disp=True, blocksize=64):
+ assert disp, "sqrtm jvp not implemented for disp=False"
+ return solve_sylvester(ans, ans, dA)
+
+
+defjvp(sqrtm, _jvp_sqrtm)
+
+
+def _jvp_sylvester(argnums, dms, ans, args, _):
+ a, b, q = args
+ if 0 in argnums:
+ da = dms[0]
+ db = dms[1] if 1 in argnums else 0
+ else:
+ da = 0
+ db = dms[0] if 1 in argnums else 0
+ dq = dms[-1] if 2 in argnums else 0
+ rhs = dq - anp.dot(da, ans) - anp.dot(ans, db)
+ return solve_sylvester(a, b, rhs)
+
+
+defjvp_argnums(solve_sylvester, _jvp_sylvester)
+
+
+def _vjp_sylvester(argnums, ans, args, _):
+ a, b, q = args
+
+ def vjp(g):
+ vjps = []
+ q_vjp = solve_sylvester(anp.transpose(a), anp.transpose(b), g)
+ if 0 in argnums:
+ vjps.append(-anp.dot(q_vjp, anp.transpose(ans)))
+ if 1 in argnums:
+ vjps.append(-anp.dot(anp.transpose(ans), q_vjp))
+ if 2 in argnums:
+ vjps.append(q_vjp)
+ return tuple(vjps)
+
+ return vjp
+
+
+defvjp_argnums(solve_sylvester, _vjp_sylvester)
diff --git a/venv/Lib/site-packages/autograd/scipy/signal.py b/venv/Lib/site-packages/autograd/scipy/signal.py
new file mode 100644
index 0000000000000000000000000000000000000000..49b76194caf3a1dca216d6df2186b7bb38e2073a
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/signal.py
@@ -0,0 +1,162 @@
+from functools import partial
+
+import numpy as npo # original numpy
+from numpy.lib.stride_tricks import as_strided
+
+import autograd.numpy as np
+from autograd.extend import defvjp, primitive
+
+
+@primitive
+def convolve(A, B, axes=None, dot_axes=[(), ()], mode="full"):
+ assert mode in ["valid", "full"], f"Mode {mode} not yet implemented"
+ if axes is None:
+ axes = [list(range(A.ndim)), list(range(A.ndim))]
+ wrong_order = any([B.shape[ax_B] < A.shape[ax_A] for ax_A, ax_B in zip(*axes)])
+ if wrong_order:
+ if mode == "valid" and not all([B.shape[ax_B] <= A.shape[ax_A] for ax_A, ax_B in zip(*axes)]):
+ raise Exception("One array must be larger than the other along all convolved dimensions")
+ elif mode != "full" or B.size <= A.size: # Tie breaker
+ i1 = B.ndim - len(dot_axes[1]) - len(axes[1]) # B ignore
+ i2 = i1 + A.ndim - len(dot_axes[0]) - len(axes[0]) # A ignore
+ i3 = i2 + len(axes[0])
+ ignore_B = list(range(i1))
+ ignore_A = list(range(i1, i2))
+ conv = list(range(i2, i3))
+ return convolve(B, A, axes=axes[::-1], dot_axes=dot_axes[::-1], mode=mode).transpose(
+ ignore_A + ignore_B + conv
+ )
+
+ if mode == "full":
+ B = pad_to_full(B, A, axes[::-1])
+ B_view_shape = list(B.shape)
+ B_view_strides = list(B.strides)
+ flipped_idxs = [slice(None)] * A.ndim
+ for ax_A, ax_B in zip(*axes):
+ B_view_shape.append(abs(B.shape[ax_B] - A.shape[ax_A]) + 1)
+ B_view_strides.append(B.strides[ax_B])
+ B_view_shape[ax_B] = A.shape[ax_A]
+ flipped_idxs[ax_A] = slice(None, None, -1)
+ B_view = as_strided(B, B_view_shape, B_view_strides)
+ A_view = A[tuple(flipped_idxs)]
+ all_axes = [list(axes[i]) + list(dot_axes[i]) for i in [0, 1]]
+ return einsum_tensordot(A_view, B_view, all_axes)
+
+
+def einsum_tensordot(A, B, axes, reverse=False):
+ # Does tensor dot product using einsum, which shouldn't require a copy.
+ A_axnums = list(range(A.ndim))
+ B_axnums = list(range(A.ndim, A.ndim + B.ndim))
+ sum_axnum = A.ndim + B.ndim
+ for i_sum, (i_A, i_B) in enumerate(zip(*axes)):
+ A_axnums[i_A] = sum_axnum + i_sum
+ B_axnums[i_B] = sum_axnum + i_sum
+ return npo.einsum(A, A_axnums, B, B_axnums)
+
+
+def pad_to_full(A, B, axes):
+ A_pad = [(0, 0)] * A.ndim
+ for ax_A, ax_B in zip(*axes):
+ A_pad[ax_A] = (B.shape[ax_B] - 1,) * 2
+ return npo.pad(A, A_pad, mode="constant")
+
+
+def parse_axes(A_shape, B_shape, conv_axes, dot_axes, mode):
+ A_ndim, B_ndim = len(A_shape), len(B_shape)
+ if conv_axes is None:
+ conv_axes = (
+ tuple(range(A_ndim)),
+ tuple(range(A_ndim)),
+ )
+ axes = {
+ "A": {
+ "conv": tuple(conv_axes[0]),
+ "dot": tuple(dot_axes[0]),
+ "ignore": tuple(i for i in range(A_ndim) if i not in conv_axes[0] and i not in dot_axes[0]),
+ },
+ "B": {
+ "conv": tuple(conv_axes[1]),
+ "dot": tuple(dot_axes[1]),
+ "ignore": tuple(i for i in range(B_ndim) if i not in conv_axes[1] and i not in dot_axes[1]),
+ },
+ }
+ assert len(axes["A"]["dot"]) == len(axes["B"]["dot"])
+ assert len(axes["A"]["conv"]) == len(axes["B"]["conv"])
+ i1 = len(axes["A"]["ignore"])
+ i2 = i1 + len(axes["B"]["ignore"])
+ i3 = i2 + len(axes["A"]["conv"])
+ axes["out"] = {
+ "ignore_A": tuple(range(i1)),
+ "ignore_B": tuple(range(i1, i2)),
+ "conv": tuple(range(i2, i3)),
+ }
+ conv_shape = (
+ compute_conv_size(A_shape[i], B_shape[j], mode) for i, j in zip(axes["A"]["conv"], axes["B"]["conv"])
+ )
+ shapes = {
+ "A": {s: tuple(A_shape[i] for i in ax) for s, ax in axes["A"].items()},
+ "B": {s: tuple(B_shape[i] for i in ax) for s, ax in axes["B"].items()},
+ }
+ shapes["out"] = {
+ "ignore_A": shapes["A"]["ignore"],
+ "ignore_B": shapes["B"]["ignore"],
+ "conv": conv_shape,
+ }
+ return axes, shapes
+
+
+def compute_conv_size(A_size, B_size, mode):
+ if mode == "full":
+ return A_size + B_size - 1
+ elif mode == "same":
+ return A_size
+ elif mode == "valid":
+ return abs(A_size - B_size) + 1
+ else:
+ raise Exception(f"Mode {mode} not recognized")
+
+
+def flipped_idxs(ndim, axes):
+ new_idxs = [slice(None)] * ndim
+ for ax in axes:
+ new_idxs[ax] = slice(None, None, -1)
+ return tuple(new_idxs)
+
+
+def grad_convolve(argnum, ans, A, B, axes=None, dot_axes=[(), ()], mode="full"):
+ assert mode in ["valid", "full"], f"Grad for mode {mode} not yet implemented"
+ axes, shapes = parse_axes(A.shape, B.shape, axes, dot_axes, mode)
+ if argnum == 0:
+ X, Y = A, B
+ _X_, _Y_ = "A", "B"
+ ignore_Y = "ignore_B"
+ elif argnum == 1:
+ X, Y = B, A
+ _X_, _Y_ = "B", "A"
+ ignore_Y = "ignore_A"
+ else:
+ raise NotImplementedError(f"Can't take grad of convolve w.r.t. arg {argnum}")
+
+ if mode == "full":
+ new_mode = "valid"
+ else:
+ if any([x_size > y_size for x_size, y_size in zip(shapes[_X_]["conv"], shapes[_Y_]["conv"])]):
+ new_mode = "full"
+ else:
+ new_mode = "valid"
+
+ def vjp(g):
+ result = convolve(
+ g,
+ Y[flipped_idxs(Y.ndim, axes[_Y_]["conv"])],
+ axes=[axes["out"]["conv"], axes[_Y_]["conv"]],
+ dot_axes=[axes["out"][ignore_Y], axes[_Y_]["ignore"]],
+ mode=new_mode,
+ )
+ new_order = npo.argsort(axes[_X_]["ignore"] + axes[_X_]["dot"] + axes[_X_]["conv"])
+ return np.transpose(result, new_order)
+
+ return vjp
+
+
+defvjp(convolve, partial(grad_convolve, 0), partial(grad_convolve, 1))
diff --git a/venv/Lib/site-packages/autograd/scipy/special.py b/venv/Lib/site-packages/autograd/scipy/special.py
new file mode 100644
index 0000000000000000000000000000000000000000..2e435900ad74bb25d66c1f34795e5ab83241d174
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/special.py
@@ -0,0 +1,147 @@
+import scipy.special
+
+import autograd.numpy as np
+from autograd.extend import defjvp, defvjp, primitive
+from autograd.numpy.numpy_vjps import repeat_to_match_shape, unbroadcast_f
+
+### Beta function ###
+beta = primitive(scipy.special.beta)
+betainc = primitive(scipy.special.betainc)
+betaln = primitive(scipy.special.betaln)
+
+defvjp(
+ beta,
+ lambda ans, a, b: unbroadcast_f(a, lambda g: g * ans * (psi(a) - psi(a + b))),
+ lambda ans, a, b: unbroadcast_f(b, lambda g: g * ans * (psi(b) - psi(a + b))),
+)
+defvjp(
+ betainc,
+ lambda ans, a, b, x: unbroadcast_f(
+ x, lambda g: g * np.power(x, a - 1) * np.power(1 - x, b - 1) / beta(a, b)
+ ),
+ argnums=[2],
+)
+defvjp(
+ betaln,
+ lambda ans, a, b: unbroadcast_f(a, lambda g: g * (psi(a) - psi(a + b))),
+ lambda ans, a, b: unbroadcast_f(b, lambda g: g * (psi(b) - psi(a + b))),
+)
+
+### Gamma functions ###
+polygamma = primitive(scipy.special.polygamma)
+psi = primitive(scipy.special.psi) # psi(x) is just polygamma(0, x)
+digamma = primitive(scipy.special.digamma) # digamma is another name for psi.
+gamma = primitive(scipy.special.gamma)
+gammaln = primitive(scipy.special.gammaln)
+gammainc = primitive(scipy.special.gammainc)
+gammaincc = primitive(scipy.special.gammaincc)
+gammasgn = primitive(scipy.special.gammasgn)
+rgamma = primitive(scipy.special.rgamma)
+multigammaln = primitive(scipy.special.multigammaln)
+
+defvjp(gammasgn, None)
+defvjp(polygamma, None, lambda ans, n, x: lambda g: g * polygamma(n + 1, x))
+defvjp(psi, lambda ans, x: lambda g: g * polygamma(1, x))
+defvjp(digamma, lambda ans, x: lambda g: g * polygamma(1, x))
+defvjp(gamma, lambda ans, x: lambda g: g * ans * psi(x))
+defvjp(gammaln, lambda ans, x: lambda g: g * psi(x))
+defvjp(rgamma, lambda ans, x: lambda g: g * psi(x) / -gamma(x))
+defvjp(
+ multigammaln,
+ lambda ans, a, d: lambda g: g * np.sum(digamma(np.expand_dims(a, -1) - np.arange(d) / 2.0), -1),
+ None,
+)
+
+
+def make_gammainc_vjp_arg1(sign):
+ def gammainc_vjp_arg1(ans, a, x):
+ coeffs = sign * np.exp(-x) * np.power(x, a - 1) / gamma(a)
+ return unbroadcast_f(x, lambda g: g * coeffs)
+
+ return gammainc_vjp_arg1
+
+
+defvjp(gammainc, make_gammainc_vjp_arg1(1), argnums=[1])
+defvjp(gammaincc, make_gammainc_vjp_arg1(-1), argnums=[1])
+
+### Bessel functions ###
+
+j0 = primitive(scipy.special.j0)
+y0 = primitive(scipy.special.y0)
+j1 = primitive(scipy.special.j1)
+y1 = primitive(scipy.special.y1)
+jn = primitive(scipy.special.jn)
+yn = primitive(scipy.special.yn)
+
+defvjp(j0, lambda ans, x: lambda g: -g * j1(x))
+defvjp(y0, lambda ans, x: lambda g: -g * y1(x))
+defvjp(j1, lambda ans, x: lambda g: g * (j0(x) - jn(2, x)) / 2.0)
+defvjp(y1, lambda ans, x: lambda g: g * (y0(x) - yn(2, x)) / 2.0)
+defvjp(jn, None, lambda ans, n, x: lambda g: g * (jn(n - 1, x) - jn(n + 1, x)) / 2.0)
+defvjp(yn, None, lambda ans, n, x: lambda g: g * (yn(n - 1, x) - yn(n + 1, x)) / 2.0)
+
+
+### Faster versions of common Bessel functions ###
+i0 = primitive(scipy.special.i0)
+i1 = primitive(scipy.special.i1)
+iv = primitive(scipy.special.iv)
+ive = primitive(scipy.special.ive)
+
+defvjp(i0, lambda ans, x: lambda g: g * i1(x))
+defvjp(i1, lambda ans, x: lambda g: g * (i0(x) + iv(2, x)) / 2.0)
+defvjp(iv, None, lambda ans, n, x: lambda g: g * (iv(n - 1, x) + iv(n + 1, x)) / 2.0)
+defvjp(ive, None, lambda ans, n, x: lambda g: g * (ans * (n / x - np.sign(x)) + ive(n + 1, x)))
+
+### Error Function ###
+inv_root_pi = 0.56418958354775627928
+erf = primitive(scipy.special.erf)
+erfc = primitive(scipy.special.erfc)
+
+defvjp(erf, lambda ans, x: lambda g: 2.0 * g * inv_root_pi * np.exp(-(x**2)))
+defvjp(erfc, lambda ans, x: lambda g: -2.0 * g * inv_root_pi * np.exp(-(x**2)))
+
+
+### Inverse error function ###
+root_pi = 1.7724538509055159
+erfinv = primitive(scipy.special.erfinv)
+erfcinv = primitive(scipy.special.erfcinv)
+
+defvjp(erfinv, lambda ans, x: lambda g: g * root_pi / 2 * np.exp(erfinv(x) ** 2))
+defvjp(erfcinv, lambda ans, x: lambda g: -g * root_pi / 2 * np.exp(erfcinv(x) ** 2))
+
+### Logit and Expit ###
+logit = primitive(scipy.special.logit)
+expit = primitive(scipy.special.expit)
+
+defvjp(logit, lambda ans, x: lambda g: g / (x * (1 - x)))
+defvjp(expit, lambda ans, x: lambda g: g * ans * (1 - ans))
+
+### logsumexp ###
+logsumexp = primitive(scipy.special.logsumexp)
+
+
+def make_grad_logsumexp(ans, x, axis=None, b=1.0, keepdims=False):
+ shape, dtype = np.shape(x), np.result_type(x)
+
+ def vjp(g):
+ g_repeated, _ = repeat_to_match_shape(g, shape, dtype, axis, keepdims)
+ ans_repeated, _ = repeat_to_match_shape(ans, shape, dtype, axis, keepdims)
+ return g_repeated * b * np.exp(x - ans_repeated)
+
+ return vjp
+
+
+defvjp(logsumexp, make_grad_logsumexp)
+
+
+def fwd_grad_logsumexp(g, ans, x, axis=None, b=1.0, keepdims=False):
+ if not keepdims:
+ if isinstance(axis, int):
+ ans = np.expand_dims(ans, axis)
+ elif isinstance(axis, tuple):
+ for ax in sorted(axis):
+ ans = np.expand_dims(ans, ax)
+ return np.sum(g * b * np.exp(x - ans), axis=axis, keepdims=keepdims)
+
+
+defjvp(logsumexp, fwd_grad_logsumexp)
diff --git a/venv/Lib/site-packages/autograd/scipy/stats/__init__.py b/venv/Lib/site-packages/autograd/scipy/stats/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..80e50cc91583f2636148e7142a42fda5df77ee50
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/stats/__init__.py
@@ -0,0 +1,13 @@
+from . import beta, chi2, gamma, norm, poisson, t
+
+# Try block needed in case the user has an
+# old version of scipy without multivariate normal.
+try:
+ from . import multivariate_normal
+except AttributeError:
+ pass
+
+try:
+ from . import dirichlet
+except AttributeError:
+ pass
diff --git a/venv/Lib/site-packages/autograd/scipy/stats/beta.py b/venv/Lib/site-packages/autograd/scipy/stats/beta.py
new file mode 100644
index 0000000000000000000000000000000000000000..4c2716095fa2d72a63d353c50b444a50cca5c099
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/stats/beta.py
@@ -0,0 +1,43 @@
+import scipy.stats
+
+import autograd.numpy as np
+from autograd.extend import defvjp, primitive
+from autograd.numpy.numpy_vjps import unbroadcast_f
+from autograd.scipy.special import beta, psi
+
+cdf = primitive(scipy.stats.beta.cdf)
+logpdf = primitive(scipy.stats.beta.logpdf)
+pdf = primitive(scipy.stats.beta.pdf)
+
+
+def grad_beta_logpdf_arg0(x, a, b):
+ return (1 + a * (x - 1) + x * (b - 2)) / (x * (x - 1))
+
+
+def grad_beta_logpdf_arg1(x, a, b):
+ return np.log(x) - psi(a) + psi(a + b)
+
+
+def grad_beta_logpdf_arg2(x, a, b):
+ return np.log1p(-x) - psi(b) + psi(a + b)
+
+
+defvjp(
+ cdf,
+ lambda ans, x, a, b: unbroadcast_f(
+ x, lambda g: g * np.power(x, a - 1) * np.power(1 - x, b - 1) / beta(a, b)
+ ),
+ argnums=[0],
+)
+defvjp(
+ logpdf,
+ lambda ans, x, a, b: unbroadcast_f(x, lambda g: g * grad_beta_logpdf_arg0(x, a, b)),
+ lambda ans, x, a, b: unbroadcast_f(a, lambda g: g * grad_beta_logpdf_arg1(x, a, b)),
+ lambda ans, x, a, b: unbroadcast_f(b, lambda g: g * grad_beta_logpdf_arg2(x, a, b)),
+)
+defvjp(
+ pdf,
+ lambda ans, x, a, b: unbroadcast_f(x, lambda g: g * ans * grad_beta_logpdf_arg0(x, a, b)),
+ lambda ans, x, a, b: unbroadcast_f(a, lambda g: g * ans * grad_beta_logpdf_arg1(x, a, b)),
+ lambda ans, x, a, b: unbroadcast_f(b, lambda g: g * ans * grad_beta_logpdf_arg2(x, a, b)),
+)
diff --git a/venv/Lib/site-packages/autograd/scipy/stats/chi2.py b/venv/Lib/site-packages/autograd/scipy/stats/chi2.py
new file mode 100644
index 0000000000000000000000000000000000000000..e15b116319bf1ca3ff65ec61d07018ea71a63428
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/stats/chi2.py
@@ -0,0 +1,25 @@
+import scipy.stats
+
+import autograd.numpy as np
+from autograd.extend import defvjp, primitive
+from autograd.numpy.numpy_vjps import unbroadcast_f
+from autograd.scipy.special import gamma
+
+cdf = primitive(scipy.stats.chi2.cdf)
+logpdf = primitive(scipy.stats.chi2.logpdf)
+pdf = primitive(scipy.stats.chi2.pdf)
+
+
+def grad_chi2_logpdf(x, df):
+ return np.where(df % 1 == 0, (df - x - 2) / (2 * x), 0)
+
+
+defvjp(
+ cdf,
+ lambda ans, x, df: unbroadcast_f(
+ x, lambda g: g * np.power(2.0, -df / 2) * np.exp(-x / 2) * np.power(x, df / 2 - 1) / gamma(df / 2)
+ ),
+ argnums=[0],
+)
+defvjp(logpdf, lambda ans, x, df: unbroadcast_f(x, lambda g: g * grad_chi2_logpdf(x, df)), argnums=[0])
+defvjp(pdf, lambda ans, x, df: unbroadcast_f(x, lambda g: g * ans * grad_chi2_logpdf(x, df)), argnums=[0])
diff --git a/venv/Lib/site-packages/autograd/scipy/stats/dirichlet.py b/venv/Lib/site-packages/autograd/scipy/stats/dirichlet.py
new file mode 100644
index 0000000000000000000000000000000000000000..238ac5ade7d8e955d07d79087bf05b93938ccabf
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/stats/dirichlet.py
@@ -0,0 +1,22 @@
+import scipy.stats
+
+import autograd.numpy as np
+from autograd.extend import defvjp, primitive
+from autograd.scipy.special import digamma
+
+rvs = primitive(scipy.stats.dirichlet.rvs)
+pdf = primitive(scipy.stats.dirichlet.pdf)
+logpdf = primitive(scipy.stats.dirichlet.logpdf)
+
+defvjp(
+ logpdf,
+ lambda ans, x, alpha: lambda g: g * (alpha - 1) / x,
+ lambda ans, x, alpha: lambda g: g * (digamma(np.sum(alpha)) - digamma(alpha) + np.log(x)),
+)
+
+# Same as log pdf, but multiplied by the pdf (ans).
+defvjp(
+ pdf,
+ lambda ans, x, alpha: lambda g: g * ans * (alpha - 1) / x,
+ lambda ans, x, alpha: lambda g: g * ans * (digamma(np.sum(alpha)) - digamma(alpha) + np.log(x)),
+)
diff --git a/venv/Lib/site-packages/autograd/scipy/stats/gamma.py b/venv/Lib/site-packages/autograd/scipy/stats/gamma.py
new file mode 100644
index 0000000000000000000000000000000000000000..5004905ecbf2f33c0759e36d86f8c0b291ce8951
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/stats/gamma.py
@@ -0,0 +1,35 @@
+import scipy.stats
+
+import autograd.numpy as np
+from autograd.extend import defvjp, primitive
+from autograd.numpy.numpy_vjps import unbroadcast_f
+from autograd.scipy.special import gamma, psi
+
+cdf = primitive(scipy.stats.gamma.cdf)
+logpdf = primitive(scipy.stats.gamma.logpdf)
+pdf = primitive(scipy.stats.gamma.pdf)
+
+
+def grad_gamma_logpdf_arg0(x, a):
+ return (a - x - 1) / x
+
+
+def grad_gamma_logpdf_arg1(x, a):
+ return np.log(x) - psi(a)
+
+
+defvjp(
+ cdf,
+ lambda ans, x, a: unbroadcast_f(x, lambda g: g * np.exp(-x) * np.power(x, a - 1) / gamma(a)),
+ argnums=[0],
+)
+defvjp(
+ logpdf,
+ lambda ans, x, a: unbroadcast_f(x, lambda g: g * grad_gamma_logpdf_arg0(x, a)),
+ lambda ans, x, a: unbroadcast_f(a, lambda g: g * grad_gamma_logpdf_arg1(x, a)),
+)
+defvjp(
+ pdf,
+ lambda ans, x, a: unbroadcast_f(x, lambda g: g * ans * grad_gamma_logpdf_arg0(x, a)),
+ lambda ans, x, a: unbroadcast_f(a, lambda g: g * ans * grad_gamma_logpdf_arg1(x, a)),
+)
diff --git a/venv/Lib/site-packages/autograd/scipy/stats/multivariate_normal.py b/venv/Lib/site-packages/autograd/scipy/stats/multivariate_normal.py
new file mode 100644
index 0000000000000000000000000000000000000000..6109fb526d1d626facaec2362124802d2e16bdfc
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/stats/multivariate_normal.py
@@ -0,0 +1,70 @@
+import scipy.stats
+
+import autograd.numpy as np
+from autograd.extend import defvjp, primitive
+from autograd.numpy.numpy_vjps import unbroadcast_f
+
+pdf = primitive(scipy.stats.multivariate_normal.pdf)
+logpdf = primitive(scipy.stats.multivariate_normal.logpdf)
+entropy = primitive(scipy.stats.multivariate_normal.entropy)
+
+# With thanks to Eric Bresch.
+# Some formulas are from
+# "An extended collection of matrix derivative results
+# for forward and reverse mode algorithmic differentiation"
+# by Mike Giles
+# https://people.maths.ox.ac.uk/gilesm/files/NA-08-01.pdf
+
+
+def generalized_outer_product(x):
+ if np.ndim(x) == 1:
+ return np.outer(x, x)
+ return np.matmul(x, np.swapaxes(x, -1, -2))
+
+
+def covgrad(x, mean, cov, allow_singular=False):
+ if allow_singular:
+ raise NotImplementedError(
+ "The multivariate normal pdf is not differentiable w.r.t. a singular covariance matix"
+ )
+ J = np.linalg.inv(cov)
+ solved = np.matmul(J, np.expand_dims(x - mean, -1))
+ return 1.0 / 2 * (generalized_outer_product(solved) - J)
+
+
+def solve(allow_singular):
+ if allow_singular:
+ return lambda A, x: np.dot(np.linalg.pinv(A), x)
+ else:
+ return np.linalg.solve
+
+
+defvjp(
+ logpdf,
+ lambda ans, x, mean, cov, allow_singular=False: unbroadcast_f(
+ x, lambda g: -np.expand_dims(np.atleast_1d(g), 1) * solve(allow_singular)(cov, (x - mean).T).T
+ ),
+ lambda ans, x, mean, cov, allow_singular=False: unbroadcast_f(
+ mean, lambda g: np.expand_dims(np.atleast_1d(g), 1) * solve(allow_singular)(cov, (x - mean).T).T
+ ),
+ lambda ans, x, mean, cov, allow_singular=False: unbroadcast_f(
+ cov, lambda g: np.reshape(g, np.shape(g) + (1, 1)) * covgrad(x, mean, cov, allow_singular)
+ ),
+)
+
+# Same as log pdf, but multiplied by the pdf (ans).
+defvjp(
+ pdf,
+ lambda ans, x, mean, cov, allow_singular=False: unbroadcast_f(
+ x, lambda g: -np.expand_dims(np.atleast_1d(ans * g), 1) * solve(allow_singular)(cov, (x - mean).T).T
+ ),
+ lambda ans, x, mean, cov, allow_singular=False: unbroadcast_f(
+ mean,
+ lambda g: np.expand_dims(np.atleast_1d(ans * g), 1) * solve(allow_singular)(cov, (x - mean).T).T,
+ ),
+ lambda ans, x, mean, cov, allow_singular=False: unbroadcast_f(
+ cov, lambda g: np.reshape(ans * g, np.shape(g) + (1, 1)) * covgrad(x, mean, cov, allow_singular)
+ ),
+)
+
+defvjp(entropy, None, lambda ans, mean, cov: unbroadcast_f(cov, lambda g: 0.5 * g * np.linalg.inv(cov).T))
diff --git a/venv/Lib/site-packages/autograd/scipy/stats/norm.py b/venv/Lib/site-packages/autograd/scipy/stats/norm.py
new file mode 100644
index 0000000000000000000000000000000000000000..c610c142581d60dad92a6c0b574c7ee8d3f2f079
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/stats/norm.py
@@ -0,0 +1,76 @@
+"""Gradients of the normal distribution."""
+
+import scipy.stats
+
+import autograd.numpy as anp
+from autograd.extend import defvjp, primitive
+from autograd.numpy.numpy_vjps import unbroadcast_f
+
+pdf = primitive(scipy.stats.norm.pdf)
+cdf = primitive(scipy.stats.norm.cdf)
+sf = primitive(scipy.stats.norm.sf)
+logpdf = primitive(scipy.stats.norm.logpdf)
+logcdf = primitive(scipy.stats.norm.logcdf)
+logsf = primitive(scipy.stats.norm.logsf)
+
+defvjp(
+ pdf,
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(x, lambda g: -g * ans * (x - loc) / scale**2),
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(loc, lambda g: g * ans * (x - loc) / scale**2),
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(
+ scale, lambda g: g * ans * (((x - loc) / scale) ** 2 - 1.0) / scale
+ ),
+)
+
+defvjp(
+ cdf,
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(x, lambda g: g * pdf(x, loc, scale)),
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(loc, lambda g: -g * pdf(x, loc, scale)),
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(
+ scale, lambda g: -g * pdf(x, loc, scale) * (x - loc) / scale
+ ),
+)
+
+defvjp(
+ logpdf,
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(x, lambda g: -g * (x - loc) / scale**2),
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(loc, lambda g: g * (x - loc) / scale**2),
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(
+ scale, lambda g: g * (-1.0 / scale + (x - loc) ** 2 / scale**3)
+ ),
+)
+
+defvjp(
+ logcdf,
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(
+ x, lambda g: g * anp.exp(logpdf(x, loc, scale) - logcdf(x, loc, scale))
+ ),
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(
+ loc, lambda g: -g * anp.exp(logpdf(x, loc, scale) - logcdf(x, loc, scale))
+ ),
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(
+ scale, lambda g: -g * anp.exp(logpdf(x, loc, scale) - logcdf(x, loc, scale)) * (x - loc) / scale
+ ),
+)
+
+defvjp(
+ logsf,
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(
+ x, lambda g: -g * anp.exp(logpdf(x, loc, scale) - logsf(x, loc, scale))
+ ),
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(
+ loc, lambda g: g * anp.exp(logpdf(x, loc, scale) - logsf(x, loc, scale))
+ ),
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(
+ scale, lambda g: g * anp.exp(logpdf(x, loc, scale) - logsf(x, loc, scale)) * (x - loc) / scale
+ ),
+)
+
+defvjp(
+ sf,
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(x, lambda g: -g * pdf(x, loc, scale)),
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(loc, lambda g: g * pdf(x, loc, scale)),
+ lambda ans, x, loc=0.0, scale=1.0: unbroadcast_f(
+ scale, lambda g: g * pdf(x, loc, scale) * (x - loc) / scale
+ ),
+)
diff --git a/venv/Lib/site-packages/autograd/scipy/stats/poisson.py b/venv/Lib/site-packages/autograd/scipy/stats/poisson.py
new file mode 100644
index 0000000000000000000000000000000000000000..c9583c0cc74bb18736a1c80c767b71f4d0f94fe0
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/stats/poisson.py
@@ -0,0 +1,20 @@
+import scipy.stats
+
+import autograd.numpy as np
+from autograd.extend import defvjp, primitive
+from autograd.numpy.numpy_vjps import unbroadcast_f
+
+cdf = primitive(scipy.stats.poisson.cdf)
+logpmf = primitive(scipy.stats.poisson.logpmf)
+pmf = primitive(scipy.stats.poisson.pmf)
+
+
+def grad_poisson_logpmf(k, mu):
+ return np.where(k % 1 == 0, k / mu - 1, 0)
+
+
+defvjp(cdf, lambda ans, k, mu: unbroadcast_f(mu, lambda g: g * -pmf(np.floor(k), mu)), argnums=[1])
+defvjp(logpmf, lambda ans, k, mu: unbroadcast_f(mu, lambda g: g * grad_poisson_logpmf(k, mu)), argnums=[1])
+defvjp(
+ pmf, lambda ans, k, mu: unbroadcast_f(mu, lambda g: g * ans * grad_poisson_logpmf(k, mu)), argnums=[1]
+)
diff --git a/venv/Lib/site-packages/autograd/scipy/stats/t.py b/venv/Lib/site-packages/autograd/scipy/stats/t.py
new file mode 100644
index 0000000000000000000000000000000000000000..f9162fce5c6fb141c762f1508a792a1f8fd473eb
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/scipy/stats/t.py
@@ -0,0 +1,90 @@
+"""Gradients of the univariate t distribution."""
+
+import scipy.stats
+
+import autograd.numpy as np
+from autograd.extend import defvjp, primitive
+from autograd.numpy.numpy_vjps import unbroadcast_f
+from autograd.scipy.special import psi
+
+pdf = primitive(scipy.stats.t.pdf)
+cdf = primitive(scipy.stats.t.cdf)
+logpdf = primitive(scipy.stats.t.logpdf)
+logcdf = primitive(scipy.stats.t.logcdf)
+
+
+def grad_tlogpdf_diff(diff, df):
+ return -diff * (1.0 + df) / (diff**2 + df)
+
+
+def grad_tlogpdf_x(x, df, loc, scale):
+ return grad_tlogpdf_diff((x - loc) / scale, df) / scale
+
+
+def grad_tlogpdf_loc(x, df, loc, scale):
+ return -grad_tlogpdf_diff((x - loc) / scale, df) / scale
+
+
+def grad_tlogpdf_scale(x, df, loc, scale):
+ diff = x - loc
+ return -(df * (scale**2 - diff**2)) / (scale * (df * scale**2 + diff**2))
+
+
+def grad_tlogpdf_df(x, df, loc, scale):
+ y = (x - loc) / scale
+ return 0.5 * (
+ (y**2 * (df + 1)) / (df * (y**2 + df))
+ - np.log(y**2 / df + 1)
+ - 1.0 / df
+ - psi(df / 2.0)
+ + psi((df + 1) / 2.0)
+ )
+
+
+defvjp(
+ pdf,
+ lambda ans, x, df, loc=0.0, scale=1.0: unbroadcast_f(
+ x, lambda g: g * ans * grad_tlogpdf_x(x, df, loc, scale)
+ ),
+ lambda ans, x, df, loc=0.0, scale=1.0: unbroadcast_f(
+ df, lambda g: g * ans * grad_tlogpdf_df(x, df, loc, scale)
+ ),
+ lambda ans, x, df, loc=0.0, scale=1.0: unbroadcast_f(
+ loc, lambda g: g * ans * grad_tlogpdf_loc(x, df, loc, scale)
+ ),
+ lambda ans, x, df, loc=0.0, scale=1.0: unbroadcast_f(
+ scale, lambda g: g * ans * grad_tlogpdf_scale(x, df, loc, scale)
+ ),
+)
+
+defvjp(
+ cdf,
+ lambda ans, x, df, loc=0.0, scale=1.0: unbroadcast_f(x, lambda g: g * pdf(x, df, loc, scale)),
+ lambda ans, x, df, loc=0.0, scale=1.0: unbroadcast_f(loc, lambda g: -g * pdf(x, df, loc, scale)),
+ argnums=(0, 2),
+)
+
+defvjp(
+ logpdf,
+ lambda ans, x, df, loc=0.0, scale=1.0: unbroadcast_f(x, lambda g: g * grad_tlogpdf_x(x, df, loc, scale)),
+ lambda ans, x, df, loc=0.0, scale=1.0: unbroadcast_f(
+ df, lambda g: g * grad_tlogpdf_df(x, df, loc, scale)
+ ),
+ lambda ans, x, df, loc=0.0, scale=1.0: unbroadcast_f(
+ loc, lambda g: g * grad_tlogpdf_loc(x, df, loc, scale)
+ ),
+ lambda ans, x, df, loc=0.0, scale=1.0: unbroadcast_f(
+ scale, lambda g: g * grad_tlogpdf_scale(x, df, loc, scale)
+ ),
+)
+
+defvjp(
+ logcdf,
+ lambda ans, x, df, loc=0.0, scale=1.0: unbroadcast_f(
+ x, lambda g: g * np.exp(logpdf(x, df, loc, scale) - logcdf(x, df, loc, scale))
+ ),
+ lambda ans, x, df, loc=0.0, scale=1.0: unbroadcast_f(
+ loc, lambda g: -g * np.exp(logpdf(x, df, loc, scale) - logcdf(x, df, loc, scale))
+ ),
+ argnums=(0, 2),
+)
diff --git a/venv/Lib/site-packages/autograd/test_util.py b/venv/Lib/site-packages/autograd/test_util.py
new file mode 100644
index 0000000000000000000000000000000000000000..d6eed7a10288e98461aab79e0ddca05c06c41b49
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/test_util.py
@@ -0,0 +1,91 @@
+from itertools import product
+
+from .core import make_jvp, make_vjp, vspace
+from .wrap_util import get_name, unary_to_nary
+
+TOL = 1e-6
+RTOL = 1e-6
+
+
+def scalar_close(a, b):
+ return abs(a - b) < TOL or abs(a - b) / abs(a + b) < RTOL
+
+
+EPS = 1e-6
+
+
+def make_numerical_jvp(f, x):
+ y = f(x)
+ x_vs, y_vs = vspace(x), vspace(y)
+
+ def jvp(v):
+ # (f(x + v*eps/2) - f(x - v*eps/2)) / eps
+ f_x_plus = f(x_vs.add(x, x_vs.scalar_mul(v, EPS / 2)))
+ f_x_minus = f(x_vs.add(x, x_vs.scalar_mul(v, -EPS / 2)))
+ neg_f_x_minus = y_vs.scalar_mul(f_x_minus, -1.0)
+ return y_vs.scalar_mul(y_vs.add(f_x_plus, neg_f_x_minus), 1.0 / EPS)
+
+ return jvp
+
+
+def check_vjp(f, x):
+ vjp, y = make_vjp(f, x)
+ jvp = make_numerical_jvp(f, x)
+ x_vs, y_vs = vspace(x), vspace(y)
+ x_v, y_v = x_vs.randn(), y_vs.randn()
+
+ vjp_y = x_vs.covector(vjp(y_vs.covector(y_v)))
+ assert vspace(vjp_y) == x_vs
+ vjv_exact = x_vs.inner_prod(x_v, vjp_y)
+ vjv_numeric = y_vs.inner_prod(y_v, jvp(x_v))
+ assert scalar_close(vjv_numeric, vjv_exact), (
+ "Derivative (VJP) check of {} failed with arg {}:\nanalytic: {}\nnumeric: {}".format(
+ get_name(f), x, vjv_exact, vjv_numeric
+ )
+ )
+
+
+def check_jvp(f, x):
+ jvp = make_jvp(f, x)
+ jvp_numeric = make_numerical_jvp(f, x)
+ x_v = vspace(x).randn()
+ check_equivalent(jvp(x_v)[1], jvp_numeric(x_v))
+
+
+def check_equivalent(x, y):
+ x_vs, y_vs = vspace(x), vspace(y)
+ assert x_vs == y_vs, f"VSpace mismatch:\nx: {x_vs}\ny: {y_vs}"
+ v = x_vs.randn()
+ assert scalar_close(x_vs.inner_prod(x, v), x_vs.inner_prod(y, v)), f"Value mismatch:\nx: {x}\ny: {y}"
+
+
+@unary_to_nary
+def check_grads(f, x, modes=["fwd", "rev"], order=2):
+ assert all(m in ["fwd", "rev"] for m in modes)
+ if "fwd" in modes:
+ check_jvp(f, x)
+ if order > 1:
+ grad_f = lambda x, v: make_jvp(f, x)(v)[1]
+ grad_f.__name__ = f"jvp_{get_name(f)}"
+ v = vspace(x).randn()
+ check_grads(grad_f, (0, 1), modes, order=order - 1)(x, v)
+ if "rev" in modes:
+ check_vjp(f, x)
+ if order > 1:
+ grad_f = lambda x, v: make_vjp(f, x)[0](v)
+ grad_f.__name__ = f"vjp_{get_name(f)}"
+ v = vspace(f(x)).randn()
+ check_grads(grad_f, (0, 1), modes, order=order - 1)(x, v)
+
+
+def combo_check(fun, *args, **kwargs):
+ # Tests all combinations of args and kwargs given.
+ _check_grads = lambda f: check_grads(f, *args, **kwargs)
+
+ def _combo_check(*args, **kwargs):
+ kwarg_key_vals = [[(k, x) for x in xs] for k, xs in kwargs.items()]
+ for _args in product(*args):
+ for _kwargs in product(*kwarg_key_vals):
+ _check_grads(fun)(*_args, **dict(_kwargs))
+
+ return _combo_check
diff --git a/venv/Lib/site-packages/autograd/tracer.py b/venv/Lib/site-packages/autograd/tracer.py
new file mode 100644
index 0000000000000000000000000000000000000000..30fa72a6ace63795516be2fbea90af0f4f32a8b4
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/tracer.py
@@ -0,0 +1,146 @@
+import warnings
+from collections import defaultdict
+from contextlib import contextmanager
+
+from .util import subvals, toposort
+from .wrap_util import wraps
+
+
+def trace(start_node, fun, x):
+ with trace_stack.new_trace() as t:
+ start_box = new_box(x, t, start_node)
+ end_box = fun(start_box)
+ if isbox(end_box) and end_box._trace == start_box._trace:
+ return end_box._value, end_box._node
+ else:
+ warnings.warn("Output seems independent of input.")
+ return end_box, None
+
+
+class Node:
+ __slots__ = []
+
+ def __init__(self, value, fun, args, kwargs, parent_argnums, parents):
+ assert False
+
+ def initialize_root(self, *args, **kwargs):
+ assert False
+
+ @classmethod
+ def new_root(cls, *args, **kwargs):
+ root = cls.__new__(cls)
+ root.initialize_root(*args, **kwargs)
+ return root
+
+
+def primitive(f_raw):
+ """
+ Wraps a function so that its gradient can be specified and its invocation
+ can be recorded. For examples, see the docs."""
+
+ @wraps(f_raw)
+ def f_wrapped(*args, **kwargs):
+ boxed_args, trace, node_constructor = find_top_boxed_args(args)
+ if boxed_args:
+ argvals = subvals(args, [(argnum, box._value) for argnum, box in boxed_args])
+ if f_wrapped in notrace_primitives[node_constructor]:
+ return f_wrapped(*argvals, **kwargs)
+ parents = tuple(box._node for _, box in boxed_args)
+ argnums = tuple(argnum for argnum, _ in boxed_args)
+ ans = f_wrapped(*argvals, **kwargs)
+ node = node_constructor(ans, f_wrapped, argvals, kwargs, argnums, parents)
+ return new_box(ans, trace, node)
+ else:
+ return f_raw(*args, **kwargs)
+
+ f_wrapped.fun = f_raw
+ f_wrapped._is_autograd_primitive = True
+ return f_wrapped
+
+
+notrace_primitives = defaultdict(set)
+
+
+def register_notrace(trace_type, primitive_fun):
+ notrace_primitives[trace_type].add(primitive_fun)
+
+
+def notrace_primitive(f_raw):
+ @wraps(f_raw)
+ def f_wrapped(*args, **kwargs):
+ argvals = map(getval, args)
+ return f_raw(*argvals, **kwargs)
+
+ f_wrapped._is_primitive = True
+ return f_wrapped
+
+
+def find_top_boxed_args(args):
+ top_trace = -1
+ top_boxes = []
+ top_node_type = None
+ for argnum, arg in enumerate(args):
+ if isbox(arg):
+ trace = arg._trace
+ if trace > top_trace:
+ top_boxes = [(argnum, arg)]
+ top_trace = trace
+ top_node_type = type(arg._node)
+ elif trace == top_trace:
+ top_boxes.append((argnum, arg))
+ return top_boxes, top_trace, top_node_type
+
+
+class TraceStack:
+ def __init__(self):
+ self.top = -1
+
+ @contextmanager
+ def new_trace(self):
+ self.top += 1
+ yield self.top
+ self.top -= 1
+
+
+trace_stack = TraceStack()
+
+
+class Box:
+ type_mappings = {}
+ types = set()
+
+ __slots__ = ["_value", "_trace", "_node"]
+
+ def __init__(self, value, trace, node):
+ self._value = value
+ self._node = node
+ self._trace = trace
+
+ def __bool__(self):
+ return bool(self._value)
+
+ __nonzero__ = __bool__
+
+ def __str__(self):
+ return f"Autograd {type(self).__name__} with value {str(self._value)}"
+
+ @classmethod
+ def register(cls, value_type):
+ Box.types.add(cls)
+ Box.type_mappings[value_type] = cls
+ Box.type_mappings[cls] = cls
+
+
+box_type_mappings = Box.type_mappings
+
+
+def new_box(value, trace, node):
+ try:
+ return box_type_mappings[type(value)](value, trace, node)
+ except KeyError:
+ raise TypeError(f"Can't differentiate w.r.t. type {type(value)}")
+
+
+box_types = Box.types
+isbox = lambda x: type(x) in box_types # almost 3X faster than isinstance(x, Box)
+getval = lambda x: getval(x._value) if isbox(x) else x
diff --git a/venv/Lib/site-packages/autograd/util.py b/venv/Lib/site-packages/autograd/util.py
new file mode 100644
index 0000000000000000000000000000000000000000..6f73edbe4d89566a20b7e54707bea3dc9fc26d32
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/util.py
@@ -0,0 +1,59 @@
+import operator
+
+
+def subvals(x, ivs):
+ x_ = list(x)
+ for i, v in ivs:
+ x_[i] = v
+ return tuple(x_)
+
+
+def subval(x, i, v):
+ x_ = list(x)
+ x_[i] = v
+ return tuple(x_)
+
+
+def func(f):
+ return f
+
+
+def toposort(end_node, parents=operator.attrgetter("parents")):
+ child_counts = {}
+ stack = [end_node]
+ while stack:
+ node = stack.pop()
+ if node in child_counts:
+ child_counts[node] += 1
+ else:
+ child_counts[node] = 1
+ stack.extend(parents(node))
+
+ childless_nodes = [end_node]
+ while childless_nodes:
+ node = childless_nodes.pop()
+ yield node
+ for parent in parents(node):
+ if child_counts[parent] == 1:
+ childless_nodes.append(parent)
+ else:
+ child_counts[parent] -= 1
+
+
+# -------------------- deprecation warnings -----------------------
+
+import warnings
+
+deprecation_msg = """
+The quick_grad_check function is deprecated. See the update guide:
+https://github.com/HIPS/autograd/blob/master/docs/updateguide.md"""
+
+
+def quick_grad_check(
+ fun, arg0, extra_args=(), kwargs={}, verbose=True, eps=1e-4, rtol=1e-4, atol=1e-6, rs=None
+):
+ warnings.warn(deprecation_msg)
+ from autograd.test_util import check_grads
+
+ fun_ = lambda arg0: fun(arg0, *extra_args, **kwargs)
+ check_grads(fun_, modes=["rev"], order=1)(arg0)
diff --git a/venv/Lib/site-packages/autograd/wrap_util.py b/venv/Lib/site-packages/autograd/wrap_util.py
new file mode 100644
index 0000000000000000000000000000000000000000..9345284a6995dd4411f15b7e8b082fac05ecb511
--- /dev/null
+++ b/venv/Lib/site-packages/autograd/wrap_util.py
@@ -0,0 +1,53 @@
+from .util import subvals
+
+
+def unary_to_nary(unary_operator):
+ @wraps(unary_operator)
+ def nary_operator(fun, argnum=0, *nary_op_args, **nary_op_kwargs):
+ assert type(argnum) in (int, tuple, list), argnum
+
+ @wrap_nary_f(fun, unary_operator, argnum)
+ def nary_f(*args, **kwargs):
+ @wraps(fun)
+ def unary_f(x):
+ if isinstance(argnum, int):
+ subargs = subvals(args, [(argnum, x)])
+ else:
+ subargs = subvals(args, zip(argnum, x))
+ return fun(*subargs, **kwargs)
+
+ if isinstance(argnum, int):
+ x = args[argnum]
+ else:
+ x = tuple(args[i] for i in argnum)
+ return unary_operator(unary_f, x, *nary_op_args, **nary_op_kwargs)
+
+ return nary_f
+
+ return nary_operator
+
+
+def wraps(fun, namestr="{fun}", docstr="{doc}", **kwargs):
+ def _wraps(f):
+ try:
+ f.__name__ = namestr.format(fun=get_name(fun), **kwargs)
+ f.__doc__ = docstr.format(fun=get_name(fun), doc=get_doc(fun), **kwargs)
+ except BaseException:
+ pass
+ finally:
+ return f
+
+ return _wraps
+
+
+def wrap_nary_f(fun, op, argnum):
+ namestr = "{op}_of_{fun}_wrt_argnum_{argnum}"
+ docstr = """\
+ {op} of function {fun} with respect to argument number {argnum}. Takes the
+ same arguments as {fun} but returns the {op}.
+ """
+ return wraps(fun, namestr, docstr, op=get_name(op), argnum=argnum)
+
+
+get_name = lambda f: getattr(f, "__name__", "[unknown name]")
+get_doc = lambda f: getattr(f, "__doc__", "")
diff --git a/venv/Lib/site-packages/autoray-0.8.4.dist-info/INSTALLER b/venv/Lib/site-packages/autoray-0.8.4.dist-info/INSTALLER
new file mode 100644
index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68
--- /dev/null
+++ b/venv/Lib/site-packages/autoray-0.8.4.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/Lib/site-packages/autoray-0.8.4.dist-info/METADATA b/venv/Lib/site-packages/autoray-0.8.4.dist-info/METADATA
new file mode 100644
index 0000000000000000000000000000000000000000..caf5fb7dc3a884609266563288349fddbe8231be
--- /dev/null
+++ b/venv/Lib/site-packages/autoray-0.8.4.dist-info/METADATA
@@ -0,0 +1,140 @@
+Metadata-Version: 2.4
+Name: autoray
+Version: 0.8.4
+Summary: Abstract your array operations.
+Project-URL: Documentation, https://autoray.readthedocs.io/
+Project-URL: Repository, https://github.com/jcmgray/autoray/
+Project-URL: Issues, https://github.com/jcmgray/autoray/issues
+Project-URL: Changelog, https://github.com/jcmgray/autoray/releases
+Author-email: Johnnie Gray
+License: Apache
+License-File: LICENSE
+Keywords: agnostic,array,autograd,cupy,dask,dispatch,jax,numeric,numpy,tensor,tensorflow
+Classifier: Development Status :: 3 - Alpha
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Requires-Python: >=3.10
+Provides-Extra: docs
+Requires-Dist: astroid; extra == 'docs'
+Requires-Dist: furo; extra == 'docs'
+Requires-Dist: ipython; extra == 'docs'
+Requires-Dist: myst-nb; extra == 'docs'
+Requires-Dist: setuptools-scm; extra == 'docs'
+Requires-Dist: sphinx; extra == 'docs'
+Requires-Dist: sphinx-autoapi; extra == 'docs'
+Requires-Dist: sphinx-copybutton; extra == 'docs'
+Provides-Extra: tests
+Requires-Dist: coverage; extra == 'tests'
+Requires-Dist: numpy; extra == 'tests'
+Requires-Dist: pytest; extra == 'tests'
+Requires-Dist: pytest-cov; extra == 'tests'
+Description-Content-Type: text/markdown
+
+
+
+[](https://github.com/jcmgray/autoray/actions/workflows/tests.yml)
+[](https://codecov.io/gh/jcmgray/autoray)
+[](https://app.codacy.com/gh/jcmgray/autoray/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
+[](https://autoray.readthedocs.io)
+[](https://pypi.org/project/autoray/)
+[](https://anaconda.org/conda-forge/autoray)
+
+[`autoray`](https://autoray.readthedocs.io/en/latest) is a lightweight python AUTOmatic-arRAY library for
+abstracting your tensor operations. Primarily it provides an
+[*automatic* dispatch mechanism](https://autoray.readthedocs.io/en/latest/automatic_dispatch.html#)
+that means you can write backend agnostic code that works for:
+
+* [numpy](https://github.com/numpy/numpy)
+* [pytorch](https://pytorch.org/)
+* [jax](https://github.com/google/jax)
+* [cupy](https://github.com/cupy/cupy)
+* [dask](https://github.com/dask/dask)
+* [autograd](https://github.com/HIPS/autograd)
+* [tensorflow](https://github.com/tensorflow/tensorflow)
+* [sparse](https://sparse.pydata.org/)
+* [paddle](https://github.com/paddlepaddle/paddle)
+* [mars](https://github.com/mars-project/mars)
+* ... and indeed **any** library that provides a numpy-*ish* api, even if it
+ knows nothing about `autoray`.
+
+Beyond that, abstracting the array interface allows you to:
+
+* *swap [custom versions of functions](https://autoray.readthedocs.io/en/latest/automatic_dispatch.html#functions)
+ for specific backends*
+* *trace through computations [lazily](https://autoray.readthedocs.io/en/latest/lazy_computation.html) without actually
+ running them*
+* *automatically [share intermediates and fold constants](https://autoray.readthedocs.io/en/latest/lazy_computation.html#sharing-intermediates)
+ in computations*
+* *compile functions with a [unified interface](https://autoray.readthedocs.io/en/latest/compilation.html) for different
+ backends*
+
+
+## Basic usage
+
+The main function of `autoray` is
+[`do`](https://autoray.readthedocs.io/en/latest/autoapi/autoray/index.html#autoray.do),
+which takes a function
+name followed by `*args` and `**kwargs`, and automatically looks up (and
+caches) the correct function to match the equivalent numpy call:
+
+```python
+import autoray as ar
+
+def noised_svd(x):
+ # automatic dispatch based on supplied array
+ U, s, VH = ar.do('linalg.svd', x)
+
+ # automatic dispatch based on different array
+ sn = s + 0.1 * ar.do('random.normal', size=ar.shape(s), like=s)
+
+ # automatic dispatch for multiple arrays for certain functions
+ return ar.do('einsum', 'ij,j,jk->ik', U, sn, VH)
+
+# explicit backend given by string
+x = ar.do('random.uniform', size=(100, 100), like="torch")
+
+# this function now works for any backend
+y = noised_svd(x)
+
+# explicit inference of backend from array
+ar.infer_backend(y)
+# 'torch'
+```
+
+If you don't like the explicit `do` syntax, or simply want a
+drop-in replacement for existing code, you can also import the `autoray.numpy`
+module:
+
+```python
+from autoray import numpy as np
+
+# set a temporary default backend
+with ar.backend_like('cupy'):
+ z = np.ones((3, 4), dtype='float32')
+
+np.exp(z)
+# array([[2.7182817, 2.7182817, 2.7182817, 2.7182817],
+# [2.7182817, 2.7182817, 2.7182817, 2.7182817],
+# [2.7182817, 2.7182817, 2.7182817, 2.7182817]], dtype=float32)
+```
+
+Alternatively you can use
+[`autoray.get_namespace`](https://autoray.readthedocs.io/en/latest/autoapi/autoray/index.html#autoray.get_namespace)
+to get a backend specific (with optional default device and dtype) namespace
+object, (c.f. the [Python Array Api](https://data-apis.org/array-api/latest/)):
+
+```python
+xp = ar.get_namespace(z)
+xp.einsum("ii->i", z)
+```
+
+Custom backends and functions can be dynamically registered with:
+
+* [`register_backend`](https://autoray.readthedocs.io/en/latest/autoapi/autoray/index.html#autoray.register_backend)
+* [`register_function`](https://autoray.readthedocs.io/en/latest/autoapi/autoray/index.html#autoray.register_function)
+
+The main documentation is available at [autoray.readthedocs.io](https://autoray.readthedocs.io/en/latest/).
diff --git a/venv/Lib/site-packages/autoray-0.8.4.dist-info/RECORD b/venv/Lib/site-packages/autoray-0.8.4.dist-info/RECORD
new file mode 100644
index 0000000000000000000000000000000000000000..21730d88a2353083a482c1d709f56fdac9ddeb95
--- /dev/null
+++ b/venv/Lib/site-packages/autoray-0.8.4.dist-info/RECORD
@@ -0,0 +1,26 @@
+autoray-0.8.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+autoray-0.8.4.dist-info/METADATA,sha256=esI2-FTPAkVbS3Aqr8KDiIqNc2MNJZzyLHD0AVXtz9k,6133
+autoray-0.8.4.dist-info/RECORD,,
+autoray-0.8.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
+autoray-0.8.4.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
+autoray/__init__.py,sha256=cKWTw-gG0pnwTlsgQ7luxmnLgXM1Sri30_5gz5gan14,2071
+autoray/__pycache__/__init__.cpython-311.pyc,,
+autoray/__pycache__/_version.cpython-311.pyc,,
+autoray/__pycache__/autoray.cpython-311.pyc,,
+autoray/__pycache__/compiler.cpython-311.pyc,,
+autoray/_version.py,sha256=6jY56wQpNbuVX1aDDCpFgsBq74u7lloIJcrJSefeVec,704
+autoray/autoray.py,sha256=CphVRUJ2ye6sctNGG0w3Zy7ZDwF-XeyxT8FMn-t3xtg,87998
+autoray/compiler.py,sha256=ma3AYBc5NkqZ_uGiDJzvDu9js1b4Zp6gO6x86SYYp3U,11395
+autoray/experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+autoray/experimental/__pycache__/__init__.cpython-311.pyc,,
+autoray/experimental/__pycache__/complexity_tracing.cpython-311.pyc,,
+autoray/experimental/complexity_tracing.py,sha256=IpEB-VeLfE1QBpWwI6NRXXuJb20ekyz8wRQnfhYpSgM,6660
+autoray/experimental/complexity_tracing_example.ipynb,sha256=xA3eL6KFA55yYKZ-76jWStPyCuAeJiVbBqYepun5zIA,1266463
+autoray/lazy/__init__.py,sha256=C2otVP4lkqJvCZY2ibK-C9qUNmJYxme29ACzbVsxf_M,2155
+autoray/lazy/__pycache__/__init__.cpython-311.pyc,,
+autoray/lazy/__pycache__/core.cpython-311.pyc,,
+autoray/lazy/__pycache__/draw.cpython-311.pyc,,
+autoray/lazy/__pycache__/linalg.cpython-311.pyc,,
+autoray/lazy/core.py,sha256=5oVH9o1eqa62xpkKtGBgh7Wec1Y64eaVlUBx5yJ3mUQ,57060
+autoray/lazy/draw.py,sha256=6z5iF3_Zhrf67QIaU3R1ERQDnIRlxu4CRIoWmN_e0_U,25849
+autoray/lazy/linalg.py,sha256=GqgHm8M0RpFCBOxF9gQ_XmK5XA1airOvfCUu8THh6tU,3112
diff --git a/venv/Lib/site-packages/autoray-0.8.4.dist-info/WHEEL b/venv/Lib/site-packages/autoray-0.8.4.dist-info/WHEEL
new file mode 100644
index 0000000000000000000000000000000000000000..ae8ec1bdaa94d726ceb907542d76cbd5d38cafcd
--- /dev/null
+++ b/venv/Lib/site-packages/autoray-0.8.4.dist-info/WHEEL
@@ -0,0 +1,4 @@
+Wheel-Version: 1.0
+Generator: hatchling 1.28.0
+Root-Is-Purelib: true
+Tag: py3-none-any
diff --git a/venv/Lib/site-packages/autoray-0.8.4.dist-info/licenses/LICENSE b/venv/Lib/site-packages/autoray-0.8.4.dist-info/licenses/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..29f81d812f3e768fa89638d1f72920dbfd1413a8
--- /dev/null
+++ b/venv/Lib/site-packages/autoray-0.8.4.dist-info/licenses/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/venv/Lib/site-packages/autoray/__init__.py b/venv/Lib/site-packages/autoray/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..98d3cfd17afc15c9a11e5f57ab0f80f4746cb802
--- /dev/null
+++ b/venv/Lib/site-packages/autoray/__init__.py
@@ -0,0 +1,112 @@
+try:
+ # -- Distribution mode --
+ # import from _version.py generated by setuptools_scm during release
+ from ._version import version as __version__
+except ImportError:
+ # -- Source mode --
+ try:
+ # use setuptools_scm to get the current version from src using git
+ from pathlib import Path as _Path
+
+ from setuptools_scm import get_version as _gv
+
+ __version__ = _gv(_Path(__file__).parent.parent)
+ except ImportError:
+ # setuptools_scm is not available, use a default version
+ __version__ = "0.0.0+unknown"
+
+
+# useful constants
+from math import (
+ e,
+ inf,
+ nan,
+ pi,
+)
+
+from . import lazy
+from .autoray import (
+ astype,
+ backend_like,
+ compose,
+ conj,
+ dag,
+ do,
+ get_backend,
+ get_common_dtype,
+ get_dtype_name,
+ get_lib_fn,
+ get_namespace,
+ imag,
+ infer_backend,
+ infer_backend_multi,
+ is_array,
+ is_scalar,
+ ndim,
+ # the numpy mimic submodule
+ numpy,
+ real,
+ register_backend,
+ register_function,
+ reshape,
+ set_backend,
+ shape,
+ size,
+ to_backend_dtype,
+ to_numpy,
+ transpose,
+ # tree utilities
+ tree_apply,
+ tree_flatten,
+ tree_iter,
+ tree_map,
+ tree_unflatten,
+)
+from .compiler import autojit
+
+__all__ = (
+ "do",
+ "get_backend",
+ "set_backend",
+ "backend_like",
+ "infer_backend",
+ "infer_backend_multi",
+ "get_lib_fn",
+ "get_namespace",
+ "shape",
+ "ndim",
+ "size",
+ "conj",
+ "transpose",
+ "dag",
+ "real",
+ "imag",
+ "reshape",
+ "to_backend_dtype",
+ "get_dtype_name",
+ "get_common_dtype",
+ "astype",
+ "to_numpy",
+ "register_backend",
+ "register_function",
+ # tree utilities
+ "is_array",
+ "is_scalar",
+ "tree_map",
+ "tree_iter",
+ "tree_apply",
+ "tree_flatten",
+ "tree_unflatten",
+ "compose",
+ # the numpy mimic submodule
+ "numpy",
+ # abstract function compilation
+ "autojit",
+ # lazy array library
+ "lazy",
+ # math constants,
+ "e",
+ "pi",
+ "inf",
+ "nan",
+)
diff --git a/venv/Lib/site-packages/autoray/_version.py b/venv/Lib/site-packages/autoray/_version.py
new file mode 100644
index 0000000000000000000000000000000000000000..1600b55096af8bb55e45549128dba97659b52403
--- /dev/null
+++ b/venv/Lib/site-packages/autoray/_version.py
@@ -0,0 +1,34 @@
+# file generated by setuptools-scm
+# don't change, don't track in version control
+
+__all__ = [
+ "__version__",
+ "__version_tuple__",
+ "version",
+ "version_tuple",
+ "__commit_id__",
+ "commit_id",
+]
+
+TYPE_CHECKING = False
+if TYPE_CHECKING:
+ from typing import Tuple
+ from typing import Union
+
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
+ COMMIT_ID = Union[str, None]
+else:
+ VERSION_TUPLE = object
+ COMMIT_ID = object
+
+version: str
+__version__: str
+__version_tuple__: VERSION_TUPLE
+version_tuple: VERSION_TUPLE
+commit_id: COMMIT_ID
+__commit_id__: COMMIT_ID
+
+__version__ = version = '0.8.4'
+__version_tuple__ = version_tuple = (0, 8, 4)
+
+__commit_id__ = commit_id = None
diff --git a/venv/Lib/site-packages/autoray/autoray.py b/venv/Lib/site-packages/autoray/autoray.py
new file mode 100644
index 0000000000000000000000000000000000000000..ca8d57367264faacf1c1a5e80a8ab161dfa41401
--- /dev/null
+++ b/venv/Lib/site-packages/autoray/autoray.py
@@ -0,0 +1,2976 @@
+"""
+AUTORAY - backend agnostic array operations.
+
+
+Copyright 2019-2023 Johnnie Gray
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import contextlib
+import functools
+import importlib
+import itertools
+import math
+import numbers
+import operator
+import threading
+from collections import OrderedDict, defaultdict
+from inspect import signature
+
+
+def do(fn, *args, like=None, **kwargs):
+ """Do function named ``fn`` on ``(*args, **kwargs)``, peforming single
+ dispatch to retrieve ``fn`` based on whichever library defines the class of
+ the ``args[0]``, or the ``like`` keyword argument if specified.
+
+ Parameters
+ ----------
+ fn : str
+ Name of the function to do, e.g. 'sum' or 'linalg.svd'.
+ args
+ Positional arguments to pass to the function.
+ like : str or array, optional
+ Backend to use, either as an explicit backend name or an example array
+ to infer the backend from. If not specified, the backend is inferred
+ from the first argument, or from a globally set backend if any.
+ kwargs
+ Keyword arguments to pass to the function.
+
+ Examples
+ --------
+
+ Works on numpy arrays:
+
+ >>> import numpy as np
+ >>> x_np = np.random.uniform(size=[5])
+ >>> y_np = do('sqrt', x_np)
+ >>> y_np
+ array([0.32464973, 0.90379787, 0.85037325, 0.88729814, 0.46768083])
+
+ >>> type(y_np)
+ numpy.ndarray
+
+ Works on cupy arrays:
+
+ >>> import cupy as cp
+ >>> x_cp = cp.random.uniform(size=[5])
+ >>> y_cp = do('sqrt', x_cp)
+ >>> y_cp
+ array([0.44541656, 0.88713113, 0.92626237, 0.64080557, 0.69620767])
+
+ >>> type(y_cp)
+ cupy.core.core.ndarray
+
+ Works on tensorflow arrays:
+
+ >>> import tensorflow as tf
+ >>> x_tf = tf.random.uniform(shape=[5])
+ >>> y_tf = do('sqrt', x_tf)
+ >>> y_tf
+
+
+ >>> type(y_tf)
+ tensorflow.python.framework.ops.Tensor
+
+ You get the idea.
+
+ For functions that don't dispatch on the first argument you can use the
+ ``like`` keyword:
+
+ >>> do('eye', 3, like=x_tf)
+
+ """
+ backend = _choose_backend(fn, args, kwargs, like=like)
+ func = get_lib_fn(backend, fn)
+ return func(*args, **kwargs)
+
+
+# ------------------------- efficiently dispatching ------------------------- #
+
+
+def _default_infer_from_sig(fn, *args, **kwargs):
+ """This is the default backend dispatcher, used if no global backend has
+ been set. Hot swapping this function out as below avoids having to check
+ manually for a global backend or worse, a thread aware global backend, on
+ every call to ``do``.
+ """
+ return _DISPATCHERS[fn](*args, **kwargs)
+
+
+_global_backend = None
+_inferrer_global = _default_infer_from_sig
+
+# this is the function that autoray uses when `do` is called without an
+# explicit like/backend argument. It is set to `_default_infer_from_sig` by
+# default, but can be set to `_always_the_same` if a global backend is set e.g.
+_infer_auto = _inferrer_global
+
+# if a thread that isn't the 'importing' thread tries to set a backend, this
+# by default turns on thread aware dispatching, but once such custom sub
+# backends have been reset, the global values above are used again.
+_global_backends_threadaware = {}
+_inferrers_threadaware = {}
+_importing_thrid = threading.get_ident()
+_backend_lock = threading.Lock()
+
+
+def _default_infer_from_sig_threadaware(fn, args, kwargs):
+ # check for a thread aware inferrer, default to the global inferrer
+ thrid = threading.get_ident()
+ return _inferrers_threadaware.get(thrid, _inferrer_global)(
+ fn, args, kwargs
+ )
+
+
+def _always_the_same(fn, args, kwargs, backend):
+ return backend
+
+
+def get_backend(get_globally="auto"):
+ """Return the universally set backend, if any.
+
+ Parameters
+ ----------
+ get_globally : {"auto", False, True}, optional
+ Which backend to return:
+
+ - True: return the globally set backend, if any.
+ - False: return the backend set for the current thread, if any.
+ - "auto": return the globally set backend, if this thread is the thread
+ that imported autoray. Otherwise return the backend set for the
+ current thread, if any.
+
+ Returns
+ -------
+ backend : str or None
+ The name of the backend, or None if no backend is set.
+ """
+ if get_globally == "auto":
+ get_globally = threading.get_ident() == _importing_thrid
+
+ if get_globally:
+ backend = _global_backend
+ else:
+ thrid = threading.get_ident()
+ backend = _global_backends_threadaware.get(thrid, None)
+
+ return backend
+
+
+def set_backend(like, set_globally="auto"):
+ """Set a default global backend. The argument ``like`` can be an explicit
+ backend name or an ``array``.
+
+ Parameters
+ ----------
+ like : str or array
+ The backend to set. If an array, the backend of the array's class will
+ be set.
+ set_globally : {"auto", False, True}, optional
+ Whether to set the backend globally or for the current thread:
+
+ - True: set the backend globally.
+ - False: set the backend for the current thread.
+ - "auto": set the backend globally if this thread is the thread that
+ imported autoray. Otherwise set the backend for the current thread.
+
+ Only one thread should ever call this function with
+ ``set_globally=True``, (by default this is importing thread).
+ """
+ global _global_backend
+ global _infer_auto
+ global _inferrer_global
+
+ if like is None:
+ backend = None
+ inferrer = _default_infer_from_sig
+ elif isinstance(like, str):
+ backend = like
+ inferrer = functools.partial(_always_the_same, backend=backend)
+ else:
+ backend = _infer_class_backend_cached(like.__class__)
+ inferrer = functools.partial(_always_the_same, backend=backend)
+
+ if set_globally == "auto":
+ set_globally = threading.get_ident() == _importing_thrid
+
+ if set_globally:
+ _global_backend = backend
+ _inferrer_global = inferrer
+ if not _inferrers_threadaware:
+ # only revert the actual function if no subthread backends set
+ _infer_auto = inferrer
+ else:
+ thrid = threading.get_ident()
+ _backend_lock.acquire()
+ if backend is None:
+ _global_backends_threadaware.pop(thrid)
+ _inferrers_threadaware.pop(thrid)
+ else:
+ _global_backends_threadaware[thrid] = backend
+ _inferrers_threadaware[thrid] = inferrer
+
+ if _inferrers_threadaware:
+ # a subthread backend has been set, so we need to be thread aware
+ _infer_auto = _default_infer_from_sig_threadaware
+ else:
+ # no subthread backend has been set anymore, so we can ignore
+ # threads and just use the global inferrer
+ _infer_auto = _inferrer_global
+ _backend_lock.release()
+
+
+@contextlib.contextmanager
+def backend_like(like, set_globally="auto"):
+ """Context manager for setting a default backend. The argument ``like`` can
+ be an explicit backend name or an ``array`` to infer it from.
+
+ Parameters
+ ----------
+ like : str or array
+ The backend to set. If an array, the backend of the array's class will
+ be set.
+ set_globally : {"auto", False, True}, optional
+ Whether to set the backend globally or for the current thread:
+
+ - True: set the backend globally.
+ - False: set the backend for the current thread.
+ - "auto": set the backend globally if this thread is the thread that
+ imported autoray. Otherwise set the backend for the current thread.
+
+ Only one thread should ever call this function with
+ ``set_globally=True``, (by default this is importing thread).
+ """
+ if set_globally == "auto":
+ set_globally = threading.get_ident() == _importing_thrid
+
+ old_backend = get_backend(get_globally=set_globally)
+ try:
+ set_backend(like, set_globally)
+ yield
+ finally:
+ set_backend(old_backend, set_globally)
+
+
+_CUSTOM_BACKENDS = {}
+
+
+def register_backend(cls, name):
+ """Register the name (and by default the module or submodule) of a custom
+ array class.
+
+ Parameters
+ ----------
+ cls : type
+ The array class itself.
+ name : str
+ The name of the backend that should be used for this class. By default
+ this wil be assumed to be the location of the relevant functions for
+ this class, but this can be overridden.
+ """
+ if not isinstance(cls, type):
+ raise TypeError("The array class itself should be supplied.")
+
+ global _CUSTOM_BACKENDS
+ _CUSTOM_BACKENDS[cls] = name
+
+
+@functools.lru_cache(None)
+def _infer_class_backend_cached(cls):
+ try:
+ import numpy as _numpy
+
+ if issubclass(cls, _numpy.ndarray):
+ return "numpy"
+ except ImportError:
+ # numpy not installed
+ pass
+
+ if cls in _CUSTOM_BACKENDS:
+ return _CUSTOM_BACKENDS[cls]
+
+ lib = cls.__module__.split(".")[0]
+
+ # check if lib should mapped entirely to another lib
+ backend = _BACKEND_ALIASES.get(lib, lib)
+
+ return backend
+
+
+def infer_backend(array):
+ """Get the name of the library that defined the class of ``array`` - unless
+ ``array`` is directly a subclass of ``numpy.ndarray``, in which case assume
+ ``numpy`` is the desired backend.
+ """
+ return _infer_class_backend_cached(array.__class__)
+
+
+multi_class_priorities = {
+ "builtins": -2,
+ "numpy": -1,
+ "autoray.lazy": 1,
+}
+
+
+@functools.lru_cache(None)
+def _infer_class_backend_multi_cached(classes):
+ return max(
+ map(_infer_class_backend_cached, classes),
+ key=lambda n: multi_class_priorities.get(n, 0),
+ )
+
+
+def infer_backend_multi(*arrays):
+ """Infer which backend should be used for a function that takes multiple
+ arguments. This assigns a priority to each backend, and returns the backend
+ with the highest priority. By default, the priority is:
+
+ - ``builtins``: -2
+ - ``numpy``: -1
+ - other backends: 0
+ - ``autoray.lazy``: 1
+
+ I.e. when mixing with ``numpy``, other array libraries are preferred, when
+ mixing with ``autoray.lazy``, ``autoray.lazy`` is preferred. This has quite
+ low overhead due to caching.
+ """
+ return _infer_class_backend_multi_cached(
+ tuple(array.__class__ for array in arrays)
+ )
+
+
+# the set of functions that create new arrays, with `dtype` and possibly
+# `device` kwargs, that should be inferred from the like argument
+_CREATION_ROUTINES = {
+ "array": (False, False),
+ "asarray": (False, False),
+ "empty": (True, False),
+ "eye": (True, False),
+ "full": (True, False),
+ "identity": (True, False),
+ "ones": (True, False),
+ "zeros": (True, False),
+ "random.default_rng": (False, False),
+ # TODO: should these be included?
+ # "arange",
+ # "geomspace",
+ # "linspace",
+ # "logspace",
+}
+
+# cache for whether backends have a device attribute
+_CREATION_INJECT = {}
+
+
+def register_creation_routine(
+ backend, fn, inject_dtype=True, inject_device=False
+):
+ """Register a function that creates a new array, with `dtype` and possibly
+ `device` kwargs, that should be inferred from the like argument. This is
+ not necessary for array creation routines that don't accept either.
+
+ Parameters
+ ----------
+ backend : str
+ The backend to register the function for.
+ fn : str
+ The name of the function to register.
+ inject_dtype : bool, optional
+ Whether to inject a `dtype` argument based on the `like` argument.
+ inject_device : bool, optional
+ Whether to inject a `device` argument based on the `like` argument.
+ """
+ if fn not in _CREATION_ROUTINES:
+ import warnings
+
+ warnings.warn(
+ f"Registering creation routine for backend '{backend}' and "
+ f"function '{fn}' which is not in the default set of known "
+ f"creation routines: {_CREATION_ROUTINES.keys()}, this will "
+ "currently have no effect.",
+ )
+
+ _CREATION_INJECT[backend, fn] = (inject_dtype, inject_device)
+
+
+def _choose_backend(fn, args, kwargs, like=None):
+ """Private function to choose a backend based on function name and
+ signature, which passes args and kwargs by reference for performance and
+ also to allow injection of dtype and device arguments for array creation
+ routines.
+ """
+ if like is None:
+ # infer from function call (or global backend)
+ return _infer_auto(fn, args, kwargs)
+ elif isinstance(like, str):
+ # explicit backend
+ return like
+ else:
+ # explicit example array
+ backend = _infer_class_backend_cached(like.__class__)
+
+ # check if we should set some extra defaults based on the example array
+ if fn in _CREATION_ROUTINES:
+ try:
+ # check for backend specific defaults
+ inject_dtype, inject_device = _CREATION_INJECT[backend, fn]
+ except KeyError:
+ # populate with non backend specific defaults
+ inject_dtype, inject_device = _CREATION_ROUTINES[fn]
+ _CREATION_INJECT[backend, fn] = (inject_dtype, inject_device)
+
+ if inject_dtype:
+ kwargs.setdefault("dtype", getattr(like, "dtype", type(like)))
+ if inject_device:
+ kwargs.setdefault("device", like.device)
+
+ return backend
+
+
+def choose_backend(fn, *args, like=None, **kwargs):
+ """Choose a backend based on function name, arguments, and the ``like``
+ keyword argument. The default, if ``like`` is not specified, is to infer
+ the backend from the function call, the default of which is simply to use
+ the first argument, if no custom dispatcher is found. Otherwise the
+ backend is chosen based on the ``like`` argument - which can be an explicit
+ backend name or an arbitrary object.
+ """
+ return _choose_backend(fn, args, kwargs, like=like)
+
+
+# ------------------- importing and caching the function -------------------- #
+
+# lookup for mapping entire lib to another
+_BACKEND_ALIASES = {}
+
+# global (non function specific) aliases
+_MODULE_ALIASES = {}
+
+# lookup for when functions are elsewhere than the expected location
+_SUBMODULE_ALIASES = {}
+
+# lookup for when functions are simply called something else
+_FUNC_ALIASES = {}
+
+# custom wrappers for when functions don't just have different location or
+# name. For example, when kwargs need to be translated or results modified
+_CUSTOM_WRAPPERS = {}
+
+# actual cache of funtions to use - this is populated lazily and can be used
+# to directly set an implementation of a function for a specific backend
+_FUNCS = {}
+
+# these are functions where a default implementation can be constructed
+# (composed of other functions), but this is only done lazily
+_COMPOSED_FUNCTION_GENERATORS = {}
+
+
+def import_lib_fn(backend, fn):
+ # first check explicitly composed functions -> if the function hasn't been
+ # called directly yet, it won't have been loaded into the cache, and needs
+ # generating before e.g. the ``do`` verrsion will work
+ if fn in _COMPOSED_FUNCTION_GENERATORS:
+ return _COMPOSED_FUNCTION_GENERATORS[fn](backend)
+
+ try:
+ # submodule where function is found for backend,
+ # e.g. ['tensorflow', trace'] -> 'tensorflow.linalg'
+ try:
+ full_location = _SUBMODULE_ALIASES[backend, fn]
+
+ # if explicit submodule alias given, don't use prepended location
+ # for example, ('torch', 'linalg.svd') -> torch.svd
+ only_fn = fn.split(".")[-1]
+
+ except KeyError:
+ full_location = backend
+
+ # move any prepended location into the full module path
+ # e.g. 'fn=linalg.eigh' -> ['linalg', 'eigh']
+ split_fn = fn.split(".")
+ full_location = ".".join([full_location] + split_fn[:-1])
+ only_fn = split_fn[-1]
+
+ # try aliases for global (not function specific) modules and
+ # submodules:
+ # e.g. 'decimal' -> 'math'
+ # e.g. 'cupy.scipy' -> 'cupyx.scipy'
+ # we don't do this if the function location has been explicitly
+ # give in _SUBMODULE_ALIASES, as that is already a full path
+ for k, v in _MODULE_ALIASES.items():
+ if full_location[: len(k)] == k:
+ full_location = full_location.replace(k, v, 1)
+ break
+
+ # cached lookup of custom name function might take
+ # e.g. ['tensorflow', 'sum'] -> 'reduce_sum'
+ fn_name = _FUNC_ALIASES.get((backend, fn), only_fn)
+
+ # import the function into the cache
+ try:
+ lib = importlib.import_module(full_location)
+ except ImportError:
+ if "." in full_location:
+ # sometimes libraries hack an attribute to look like submodule
+ mod, *submods = full_location.split(".")
+ lib = importlib.import_module(mod)
+ # also need to handle nested submodules
+ for submod in submods:
+ lib = getattr(lib, submod)
+ else:
+ # failed to import library at all -> catch + raise ImportError
+ raise AttributeError
+
+ # check for a custom wrapper but default to identity
+ wrapper = _CUSTOM_WRAPPERS.get((backend, fn), lambda fn: fn)
+
+ # store the function!
+ lib_fn = _FUNCS[backend, fn] = wrapper(getattr(lib, fn_name))
+
+ except AttributeError:
+ # check if there is a backup function (e.g. for older library version)
+ backend_alt = backend + "[alt]"
+ if backend_alt in _MODULE_ALIASES:
+ return import_lib_fn(backend_alt, fn)
+
+ raise ImportError(
+ f"autoray couldn't find function '{fn}' for "
+ f"backend '{backend.replace('[alt]', '')}'."
+ )
+
+ return lib_fn
+
+
+def get_lib_fn(backend, fn):
+ """Cached retrieval of correct function for backend, all the logic for
+ finding the correct funtion only runs the first time.
+
+ Parameters
+ ----------
+ backend : str
+ The module defining the array class to dispatch on.
+ fn : str
+ The function to retrieve.
+
+ Returns
+ -------
+ callable
+ """
+
+ try:
+ lib_fn = _FUNCS[backend, fn]
+ except KeyError:
+ lib_fn = import_lib_fn(backend, fn)
+ return lib_fn
+
+
+# --------------------------- register your own! ---------------------------- #
+
+
+def register_function(backend, name, fn, wrap=False):
+ """Directly provide your own function.
+
+ Parameters
+ ----------
+ backend : str
+ The name of the backend to register the function for.
+ name : str
+ Name of the function, e.g. `'sum'` or `'linalg.svd'`.
+ fn : callable
+ The function to register.
+ wrap : bool, optional
+ Whether to wrap the old function like ``fn(old_fn)`` rather than
+ directly supply the entire new function.
+ """
+ if wrap:
+ old = get_lib_fn(backend, name)
+ _FUNCS[backend, name] = fn(old)
+ else:
+ _FUNCS[backend, name] = fn
+
+
+# -------------------------- array detection utils -------------------------- #
+
+
+def is_array(x):
+ """Is ``x`` an array-like object? This simply checks for a ``shape``
+ attribute, thus 0-dimensional arrays are also considered arrays, but lists
+ and tuples are not.
+
+ Parameters
+ ----------
+ x : object
+ Object to check.
+
+ Returns
+ -------
+ bool
+
+ See Also
+ --------
+ is_scalar
+ """
+ return hasattr(x, "shape")
+
+
+_IS_SCALAR_CACHE = {}
+
+
+def _is_scalar_ndim(x):
+ return x.ndim == 0
+
+
+def _always_false(x):
+ return False
+
+
+def _always_true(x):
+ return True
+
+
+def is_scalar(x):
+ """Is ``x`` a scalar-like object? This checks if ``x`` has an ``ndim``
+ attribute equal to 0. If ``x`` has no ``ndim`` attribute, it checks if
+ ``x`` is iterable - if it is not iterable, it is considered a scalar.
+
+ Parameters
+ ----------
+ x : object
+ Object to check.
+
+ Returns
+ -------
+ bool
+
+ See Also
+ --------
+ is_array
+ """
+ try:
+ return _IS_SCALAR_CACHE[x.__class__](x)
+ except KeyError:
+ if hasattr(x, "ndim"):
+ _IS_SCALAR_CACHE[x.__class__] = _is_scalar_ndim
+ else:
+ try:
+ iter(x)
+ _IS_SCALAR_CACHE[x.__class__] = _always_false
+ except TypeError:
+ _IS_SCALAR_CACHE[x.__class__] = _always_true
+ return _IS_SCALAR_CACHE[x.__class__](x)
+
+
+# ------------------------------- tree utils -------------------------------- #
+
+TREE_MAP_REGISTRY = {}
+TREE_APPLY_REGISTRY = {}
+TREE_ITER_REGISTRY = {}
+
+
+def tree_register_container(cls, mapper, iterator, applier):
+ """Register a new container type for use with ``tree_map`` and
+ ``tree_apply``.
+
+ Parameters
+ ----------
+ cls : type
+ The container type to register.
+ mapper : callable
+ A function that takes ``f``, ``tree`` and ``is_leaf`` and returns a new
+ tree of type ``cls`` with ``f`` applied to all leaves.
+ applier : callable
+ A function that takes ``f``, ``tree`` and ``is_leaf`` and applies ``f``
+ to all leaves in ``tree``.
+ """
+ TREE_MAP_REGISTRY[cls] = mapper
+ TREE_ITER_REGISTRY[cls] = iterator
+ TREE_APPLY_REGISTRY[cls] = applier
+
+
+IS_CONTAINER_CACHE = {}
+
+
+def is_not_container(x):
+ """The default function to determine if an object is a leaf. This simply
+ checks if the object is an instance of any of the registered container
+ types.
+ """
+ try:
+ return IS_CONTAINER_CACHE[x.__class__]
+ except KeyError:
+ isleaf = not any(isinstance(x, cls) for cls in TREE_MAP_REGISTRY)
+ IS_CONTAINER_CACHE[x.__class__] = isleaf
+ return isleaf
+
+
+def identity(f, tree, is_leaf):
+ return tree
+
+
+TREE_MAPPER_CACHE = {}
+
+
+def tree_map(f, tree, is_leaf=is_not_container):
+ """Map ``f`` over all leaves in ``tree``, returning a new pytree.
+
+ Parameters
+ ----------
+ f : callable
+ A function to apply to all leaves in ``tree``.
+ tree : pytree
+ A nested sequence of tuples, lists, dicts and other objects.
+ is_leaf : callable
+ A function to determine if an object is a leaf, ``f`` is only applied
+ to objects for which ``is_leaf(x)`` returns ``True``.
+
+ Returns
+ -------
+ pytree
+ """
+ if is_leaf(tree):
+ return f(tree)
+
+ try:
+ return TREE_MAPPER_CACHE[tree.__class__](f, tree, is_leaf)
+ except KeyError:
+ # reverse so later registered classes take precedence
+ for cls, mapper in reversed(TREE_MAP_REGISTRY.items()):
+ if isinstance(tree, cls):
+ break
+ else:
+ # neither leaf nor container -> simply return it
+ mapper = identity
+ TREE_MAPPER_CACHE[tree.__class__] = mapper
+ return mapper(f, tree, is_leaf)
+
+
+def empty(tree, is_leaf):
+ return iter(())
+
+
+TREE_ITER_CACHE = {}
+
+
+def tree_iter(tree, is_leaf=is_not_container):
+ """Iterate over all leaves in ``tree``.
+
+ Parameters
+ ----------
+ f : callable
+ A function to apply to all leaves in ``tree``.
+ tree : pytree
+ A nested sequence of tuples, lists, dicts and other objects.
+ is_leaf : callable
+ A function to determine if an object is a leaf, ``f`` is only applied
+ to objects for which ``is_leaf(x)`` returns ``True``.
+ """
+ if is_leaf(tree):
+ yield tree
+ return
+
+ try:
+ yield from TREE_ITER_CACHE[tree.__class__](tree, is_leaf)
+ except KeyError:
+ # reverse so later registered classes take precedence
+ for cls, iterator in reversed(TREE_ITER_REGISTRY.items()):
+ if isinstance(tree, cls):
+ break
+ else:
+ # neither leaf nor container -> simply ignore it
+ iterator = empty
+ TREE_ITER_CACHE[tree.__class__] = iterator
+ yield from iterator(tree, is_leaf)
+
+
+def nothing(f, tree, is_leaf):
+ pass
+
+
+TREE_APPLIER_CACHE = {}
+
+
+def tree_apply(f, tree, is_leaf=is_not_container):
+ """Apply ``f`` to all leaves in ``tree``, no new pytree is built.
+
+ Parameters
+ ----------
+ f : callable
+ A function to apply to all leaves in ``tree``.
+ tree : pytree
+ A nested sequence of tuples, lists, dicts and other objects.
+ is_leaf : callable
+ A function to determine if an object is a leaf, ``f`` is only applied
+ to objects for which ``is_leaf(x)`` returns ``True``.
+ """
+ if is_leaf(tree):
+ f(tree)
+ return
+
+ try:
+ TREE_APPLIER_CACHE[tree.__class__](f, tree, is_leaf)
+ except KeyError:
+ # reverse so later registered classes take precedence
+ for cls, applier in reversed(TREE_APPLY_REGISTRY.items()):
+ if isinstance(tree, cls):
+ break
+ else:
+ # neither leaf nor container -> simply ignore it
+ applier = nothing
+ TREE_APPLIER_CACHE[tree.__class__] = applier
+ applier(f, tree, is_leaf)
+
+
+class Leaf:
+ """A singleton object to use as a placeholder in a pytree, for
+ unflattening.
+ """
+
+ __slots__ = ()
+
+ def __repr__(self):
+ return "Leaf"
+
+
+LEAF = Leaf()
+
+
+def is_leaf_placeholder(x):
+ # don't do `x is LEAF` to allow pickling / unpickling
+ return x.__class__ is Leaf
+
+
+def tree_flatten(tree, is_leaf=is_not_container, get_ref=False):
+ """Flatten ``tree`` into a list of leaves.
+
+ Parameters
+ ----------
+ tree : pytree
+ A nested sequence of tuples, lists, dicts and other objects.
+ is_leaf : callable
+ A function to determine if an object is a leaf, only objects for which
+ ``is_leaf(x)`` returns ``True`` are returned in the flattened list.
+ get_ref : bool
+ If ``True``, a reference tree is also returned which can be used to
+ reconstruct the original tree from a flattened list.
+
+ Returns
+ -------
+ objs : list
+ The flattened list of leaf objects.
+ (ref_tree) : pytree
+ If ``get_ref`` is ``True``, a reference tree, with leaves of ``Leaf``,
+ is returned which can be used to reconstruct the original tree.
+ """
+ objs = []
+ if get_ref:
+ # return a new tree with Leaf leaves, as well as the flattened list
+
+ def f(x):
+ objs.append(x)
+ return LEAF
+
+ ref_tree = tree_map(f, tree, is_leaf)
+ return objs, ref_tree
+ else:
+ tree_apply(objs.append, tree, is_leaf)
+ return objs
+
+
+def tree_unflatten(objs, tree, is_leaf=is_leaf_placeholder):
+ """Unflatten ``objs`` into a pytree of the same structure as ``tree``.
+
+ Parameters
+ ----------
+ objs : sequence
+ A sequence of objects to be unflattened into a pytree.
+ tree : pytree
+ A nested sequence of tuples, lists, dicts and other objects, the objs
+ will be inserted into a new pytree of the same structure.
+ is_leaf : callable
+ A function to determine if an object is a leaf, only objects for which
+ ``is_leaf(x)`` returns ``True`` will have the next item from ``objs``
+ inserted. By default checks for the ``Leaf`` object inserted by
+ ``tree_flatten(..., get_ref=True)``.
+
+ Returns
+ -------
+ pytree
+ """
+ objs = iter(objs)
+ return tree_map(lambda _: next(objs), tree, is_leaf)
+
+
+def tree_map_tuple(f, tree, is_leaf):
+ return tuple(tree_map(f, x, is_leaf) for x in tree)
+
+
+def tree_iter_tuple(tree, is_leaf):
+ for x in tree:
+ yield from tree_iter(x, is_leaf)
+
+
+def tree_apply_tuple(f, tree, is_leaf):
+ for x in tree:
+ tree_apply(f, x, is_leaf)
+
+
+tree_register_container(
+ tuple, tree_map_tuple, tree_iter_tuple, tree_apply_tuple
+)
+
+
+def tree_map_list(f, tree, is_leaf):
+ return [tree_map(f, x, is_leaf) for x in tree]
+
+
+def tree_iter_list(tree, is_leaf):
+ for x in tree:
+ yield from tree_iter(x, is_leaf)
+
+
+def tree_apply_list(f, tree, is_leaf):
+ for x in tree:
+ tree_apply(f, x, is_leaf)
+
+
+tree_register_container(list, tree_map_list, tree_iter_list, tree_apply_list)
+
+
+def tree_map_dict(f, tree, is_leaf):
+ return {k: tree_map(f, v, is_leaf) for k, v in tree.items()}
+
+
+def tree_iter_dict(tree, is_leaf):
+ for v in tree.values():
+ yield from tree_iter(v, is_leaf)
+
+
+def tree_apply_dict(f, tree, is_leaf):
+ for v in tree.values():
+ tree_apply(f, v, is_leaf)
+
+
+tree_register_container(dict, tree_map_dict, tree_iter_dict, tree_apply_dict)
+
+
+# --------------------------- composed functions ---------------------------- #
+
+
+class Composed:
+ """Compose an ``autoray.do`` using function. See the main wrapper
+ ``compose``.
+ """
+
+ def __init__(self, fn, name=None):
+ self._default_fn = fn
+ if name is None:
+ name = fn.__name__
+ self._name = name
+ self._supply_backend = "backend" in signature(fn).parameters
+
+ # this registers the fact that when `get_lib_fn` is called, the
+ # function can be created even if it doesn't exist for a specific
+ # backend yet.
+ _COMPOSED_FUNCTION_GENERATORS[self._name] = self.make_function
+
+ def register(self, backend, fn=None):
+ """Register a different implementation for ``backend``."""
+ if fn is not None:
+ register_function(backend, self._name, fn)
+ else:
+ # wrapper form
+ def wrapper(fn):
+ register_function(backend, self._name, fn)
+ return fn
+
+ return wrapper
+
+ def make_function(self, backend):
+ """Make a new function for the specific ``backend``."""
+ if self._supply_backend:
+ # make sure it inherits __name__ etc
+ fn = functools.wraps(self._default_fn)(
+ functools.partial(self._default_fn, backend=backend)
+ )
+ else:
+ fn = self._default_fn
+ self.register(backend, fn)
+ return fn
+
+ def __call__(self, *args, like=None, **kwargs):
+ backend = _choose_backend(self._name, args, kwargs, like=like)
+ # `get_lib_fn` will call `make_function` if the function doesn't exist
+ fn = get_lib_fn(backend, self._name)
+ return fn(*args, **kwargs)
+
+ def __repr__(self):
+ return f"Composed('{self._name}')"
+
+
+def compose(fn, *, name=None):
+ """Take a function consisting of multiple ``autoray.do`` calls and compose
+ it into a new, single, named function, registered with ``autoray.do``.
+
+ This creates a default implementation of this function for each new backend
+ encountered without explicitly having to write each out, but also allows
+ for specific implementations to be overridden for specific backends.
+
+ If the function takes a ``backend`` argument, it will be supplied with the
+ backend name, to save having to re-choose the backend.
+
+ Specific implementations can be provided by calling the ``register`` method
+ of the composed function, or it can itself be used like a decorator::
+
+ @compose
+ def foo(x):
+ ...
+
+ @foo.register("numpy")
+ @numba.njit
+ def foo_numba(x):
+ ...
+
+ Parameters
+ ----------
+ fn : callable
+ The funtion to compose, and its default implementation.
+ name : str, optional
+ The name of the composed function. If not provided, the name of the
+ function will be used.
+ """
+ if fn is None:
+ return functools.partial(compose, name=name)
+ return functools.wraps(fn)(Composed(fn, name))
+
+
+# ---------------------- special top level functions ------------------------ #
+
+
+@compose
+def shape(x):
+ """Get the shape of an array as a tuple of int. This should be preferred
+ to calling `x.shape` directly, as it:
+
+ 1. Allows customization (e.g. for torch and aesara which return
+ different types for shape - use `@shape.register(backend)` to
+ customize the behavior from this default implementation).
+ 2. Can be used on nested lists and tuples, without calling numpy.
+
+ Parameters
+ ----------
+ x : array_like
+ The array to get the shape of. It can be an arbitrary nested list or
+ tuple of arrays and scalars, but is assumed not to be ragged.
+
+ Returns
+ -------
+ shape : tuple of int
+ The size of each dimension of the array.
+ """
+ try:
+ return x.shape
+ except AttributeError:
+ # want to handle builtins / nested stuff
+ if isinstance(x, (list, tuple)):
+ d = len(x)
+ if d != 0:
+ # NB: slightly different from np.shape, as we do not check for
+ # ragged arrays, but that behavior is seemingly deprecated
+ return (d,) + shape(x[0])
+ return (d,)
+ return ()
+
+
+@compose
+def ndim(x):
+ """Get the number of dimensions of an array. This should be preferred to
+ calling `x.ndim`, since not all backends implement that, and it can also be
+ called on nested lists and tuples.
+
+ Parameters
+ ----------
+ x : array_like
+ The array to get the number of dimensions of. It can be an arbitrary
+ nested list or tuple of arrays and scalars.
+
+ Returns
+ -------
+ ndim : int
+ """
+ try:
+ return x.ndim
+ except AttributeError:
+ return len(shape(x))
+
+
+@compose
+def size(x):
+ """Get the size, or number of elements, of an array. This should be
+ preferred to calling `x.size`, since not all backends implement that, and
+ it can also be called on nested lists and tuples.
+
+ Parameters
+ ----------
+ x : array_like
+ The array to get the size of. It can be an arbitrary nested list or
+ tuple of arrays and scalars.
+
+ Returns
+ -------
+ size : int
+ """
+ try:
+ return x.size
+ except AttributeError:
+ return math.prod(shape(x))
+
+
+def conj(x):
+ """Array conjugate."""
+ return do("conj", x)
+
+
+def transpose(x, *args):
+ """Array transpose."""
+ return do("transpose", x, *args)
+
+
+def dag(x):
+ """Array Hermitian transpose."""
+ try:
+ return x.H
+ except AttributeError:
+ backend = _infer_class_backend_cached(x.__class__)
+ return do("conj", do("transpose", x, like=backend), like=backend)
+
+
+def real(x):
+ """Array real part."""
+ return do("real", x)
+
+
+def imag(x):
+ """Array imaginary part."""
+ return do("imag", x)
+
+
+def reshape(x, shape):
+ """Array reshaped."""
+ try:
+ return x.reshape(shape)
+ except AttributeError:
+ return do("reshape", x, shape)
+
+
+def to_backend_dtype(dtype_name, like):
+ """Turn string specifier ``dtype_name`` into dtype of backend ``like``."""
+ if not isinstance(like, str):
+ like = _infer_class_backend_cached(like.__class__)
+
+ try:
+ return get_lib_fn(like, dtype_name)
+ except ImportError:
+ return dtype_name
+
+
+@compose
+def get_dtype_name(x):
+ """Find string specifier ``dtype_name`` of array ``x``."""
+ dtype = x.dtype
+ try:
+ return dtype.name
+ except AttributeError:
+ return str(dtype)
+
+
+_COMPLEX_DTYPES = {"complex64", "complex128"}
+_DOUBLE_DTYPES = {"float64", "complex128"}
+_DTYPE_MAP = {
+ (False, False): "float32",
+ (False, True): "float64",
+ (True, False): "complex64",
+ (True, True): "complex128",
+}
+
+
+def get_common_dtype(*arrays):
+ """Compute the minimal dtype sufficient for ``arrays``."""
+ dtypes = set(map(get_dtype_name, arrays))
+ has_complex = not _COMPLEX_DTYPES.isdisjoint(dtypes)
+ has_double = not _DOUBLE_DTYPES.isdisjoint(dtypes)
+ return _DTYPE_MAP[has_complex, has_double]
+
+
+def astype(x, dtype_name, **kwargs):
+ """Cast array as type ``dtype_name`` - tries ``x.astype`` first."""
+ dtype = to_backend_dtype(dtype_name, like=x)
+ try:
+ return x.astype(dtype, **kwargs)
+ except AttributeError:
+ return do("astype", x, dtype, **kwargs)
+
+
+def to_numpy(x):
+ """Get a numpy version of array ``x``."""
+ return do("to_numpy", x)
+
+
+# -------------------------- some common wrappers --------------------------- #
+
+
+def svd_not_full_matrices_wrapper(fn):
+ @functools.wraps(fn)
+ def default_not_full_matrices(*args, **kwargs):
+ kwargs.setdefault("full_matrices", False)
+ return fn(*args, **kwargs)
+
+ return default_not_full_matrices
+
+
+def svd_sUV_to_UsVH_wrapper(fn):
+ @functools.wraps(fn)
+ def numpy_like(*args, **kwargs):
+ s, U, V = fn(*args, **kwargs)
+ return U, s, dag(V)
+
+ return numpy_like
+
+
+def svd_UsV_to_UsVH_wrapper(fn):
+ @functools.wraps(fn)
+ def numpy_like(*args, **kwargs):
+ U, s, V = fn(*args, **kwargs)
+ return U, s, dag(V)
+
+ return numpy_like
+
+
+def svd_manual_full_matrices_kwarg(fn):
+ @functools.wraps(fn)
+ def numpy_like(*args, full_matrices=False, **kwargs):
+ U, s, VH = fn(*args, **kwargs)
+
+ if not full_matrices:
+ U, VH = U[:, : s.size], VH[: s.size, :]
+
+ return U, s, VH
+
+ return numpy_like
+
+
+def qr_allow_fat(fn):
+ @functools.wraps(fn)
+ def numpy_like(a, **kwargs):
+ *_, m, n = shape(a)
+
+ if m >= n:
+ # square or thin
+ return fn(a, **kwargs)
+
+ backend = _infer_class_backend_cached(a.__class__)
+
+ Q, R_sq = fn(a[..., :, :m])
+ Qdag = do(
+ "conj", do("swapaxes", Q, -2, -1, like=backend), like=backend
+ )
+ R_r = Qdag @ a[..., :, m:]
+ R = do("concatenate", (R_sq, R_r), axis=-1, like=backend)
+
+ return Q, R
+
+ return numpy_like
+
+
+def tril_to_band_part(fn):
+ @functools.wraps(fn)
+ def numpy_like(x, k=0):
+ if k < 0:
+ raise ValueError(
+ "'k' must be positive to recreate 'numpy.tril' "
+ "behaviour with 'tensorflow.matrix_band_part'."
+ )
+
+ return fn(x, -1, k)
+
+ return numpy_like
+
+
+def triu_to_band_part(fn):
+ @functools.wraps(fn)
+ def numpy_like(x, k=0):
+ if k > 0:
+ raise ValueError(
+ "'k' must be negative to recreate 'numpy.triu' "
+ "behaviour with 'tensorflow.matrix_band_part'."
+ )
+
+ return fn(x, -k, -1)
+
+ return numpy_like
+
+
+def cholesky_lower(fn):
+ @functools.wraps(fn)
+ def cholesky_numpy_like(a):
+ return fn(a, lower=True)
+
+ return cholesky_numpy_like
+
+
+def binary_allow_1d_rhs_wrap(fn):
+ @functools.wraps(fn)
+ def allow_1d_rhs(a, b):
+ need_to_convert = ndim(a) != ndim(b)
+ if need_to_convert:
+ b = reshape(b, (*shape(b), 1))
+ x = fn(a, b)
+ if need_to_convert:
+ x = reshape(x, shape(x)[:-1])
+ return x
+
+ return allow_1d_rhs
+
+
+def scale_random_uniform_manually(fn):
+ @functools.wraps(fn)
+ def numpy_like(low=0.0, high=1.0, size=None, dtype=None, **kwargs):
+ if size is None:
+ size = ()
+
+ x = fn(size, **kwargs)
+
+ if (low != 0.0) or (high != 1.0):
+ x = (high - low) * x + low
+
+ if (dtype is not None) and get_dtype_name(x) != dtype:
+ x = astype(x, dtype)
+ return x
+
+ return numpy_like
+
+
+def scale_random_normal_manually(fn):
+ @functools.wraps(fn)
+ def numpy_like(loc=0.0, scale=1.0, size=None, dtype=None, **kwargs):
+ if size is None:
+ size = ()
+
+ x = fn(size, **kwargs)
+
+ if (loc != 0.0) or (scale != 1.0):
+ x = scale * x + loc
+
+ if (dtype is not None) and get_dtype_name(x) != dtype:
+ x = astype(x, dtype)
+ return x
+
+ return numpy_like
+
+
+def with_dtype_wrapper(fn):
+ """Add ability to handle `dtype` keyword.
+ If not None, `dtype` should be specified as a string, otherwise conversion
+ will happen regardless.
+ """
+
+ @functools.wraps(fn)
+ def with_dtype(*args, dtype=None, **kwargs):
+ A = fn(*args, **kwargs)
+ if (dtype is not None) and (dtype != get_dtype_name(A)):
+ A = astype(A, dtype)
+ return A
+
+ return with_dtype
+
+
+def translate_wrapper(fn, translator):
+ """Wrap a function to match the api of another according to a translation.
+ The ``translator`` entries in the form of an ordered dict should have
+ entries like:
+
+ (desired_kwarg: (backend_kwarg, default_value))
+
+ with the order defining the args of the function.
+ """
+
+ @functools.wraps(fn)
+ def translated_function(*args, **kwargs):
+ new_kwargs = {}
+ translation = translator.copy()
+
+ # convert args, pairing them off with kwargs
+ for arg_value in args:
+ new_arg_name = translation.popitem(last=False)[1][0]
+ new_kwargs[new_arg_name] = arg_value
+
+ # convert kwargs - but only those in the translation
+ for key, value in kwargs.items():
+ try:
+ new_kwargs[translation.pop(key)[0]] = value
+ except KeyError:
+ new_kwargs[key] = value
+
+ # set remaining default kwargs
+ for opt in translation.values():
+ if len(opt) == 2:
+ # backend_name, default_value
+ new_kwargs[opt[0]] = opt[1]
+ # else, no default value -> don't inject
+
+ return fn(**new_kwargs)
+
+ return translated_function
+
+
+def make_translator(t):
+ return functools.partial(translate_wrapper, translator=OrderedDict(t))
+
+
+def complex_add_re_im(re, im):
+ return re + 1j * im
+
+
+def allclose(x, y, rtol=1e-05, atol=1e-08):
+ return do("all", do("abs", x - y) <= atol + rtol * do("abs", y))
+
+
+def _handle_size_to_shape(size=None):
+ if size is None:
+ return ()
+ try:
+ return tuple(size)
+ except TypeError:
+ return (size,)
+
+
+# ----------------------------- Custom dispatchers -------------------------- #
+
+
+def wrap_args_kwargs_from_raw(fn):
+ """Take a function with signature ``(*args, **kwargs)`` and wrap it to
+ accept a single tuple of args and a dict of kwargs.
+ """
+
+ @functools.wraps(fn)
+ def wrapped(args, kwargs):
+ return fn(*args, **kwargs)
+
+ return wrapped
+
+
+def register_dispatch(fun, dispatcher, raw_signature=True):
+ """Register a new dispatcher, a function that takes the arguments and
+ keyword arguments of a function and returns the backend to use, when the
+ backend is not explicitly given.
+
+ This is useful in case the backend to be used by a function cannot be
+ inferred from the first argument.
+
+ Parameters
+ ----------
+ fun : str
+ The name of the function to register the dispatcher for.
+ dispatcher : callable
+ The dispatcher function to use. This should take the arguments and
+ keyword arguments of the function and return the backend to use.
+ raw_signature : bool, optional
+ The ``dispatcher`` has signature ``(*args, **kwargs)`` if ``True``,
+ otherwise it has signature ``(args, kwargs)``.
+ """
+ if raw_signature:
+ dispatcher = wrap_args_kwargs_from_raw(dispatcher)
+
+ _DISPATCHERS[fun] = dispatcher
+
+
+def default_dispatcher(args, kwargs):
+ """Try to infer backend from first argument passed to function."""
+ try:
+ return _infer_class_backend_cached(args[0].__class__)
+ except IndexError:
+ raise TypeError("No args to infer backend from.")
+
+
+# lookup of custom dispatcher methods, for cases when backend cannot be
+# inferred accurately from first argument.
+_DISPATCHERS = defaultdict(lambda: default_dispatcher)
+
+
+def join_array_dispatcher(args, kwargs):
+ """Dispatcher for functions where first argument is a sequence."""
+ try:
+ return _infer_class_backend_cached(args[0][0].__class__)
+ except (TypeError, ValueError):
+ # user passed an empty sequence, or something non-iterable
+ # try to infer backend from first argument as fallback
+ return _infer_class_backend_cached(args[0].__class__)
+
+
+# List of functions listed in numpy API as array joining operations
+register_dispatch("concatenate", join_array_dispatcher, raw_signature=False)
+register_dispatch("stack", join_array_dispatcher, raw_signature=False)
+register_dispatch("block", join_array_dispatcher, raw_signature=False)
+register_dispatch("vstack", join_array_dispatcher, raw_signature=False)
+register_dispatch("hstack", join_array_dispatcher, raw_signature=False)
+register_dispatch("dstack", join_array_dispatcher, raw_signature=False)
+register_dispatch("column_stack", join_array_dispatcher, raw_signature=False)
+register_dispatch("row_stack", join_array_dispatcher, raw_signature=False)
+
+
+def einsum_dispatcher(args, kwargs):
+ """Dispatcher for handling einsum.
+
+ einsum can be called with a str equation as the first argument, or with
+ 'interleaved' inputs. This dispatcher handles both cases and also takes
+ into account all arrays.
+ """
+ return infer_backend_multi(*args)
+
+
+register_dispatch("einsum", einsum_dispatcher, raw_signature=False)
+
+
+def binary_dispatcher(args, kwargs):
+ """There are cases when we want to take into account both backends of two
+ arguments, e.g. a lazy variable and a constant array.
+ """
+ return infer_backend_multi(*args[:2])
+
+
+register_dispatch("tensordot", binary_dispatcher, raw_signature=False)
+register_dispatch("matmul", binary_dispatcher, raw_signature=False)
+register_dispatch("multiply", binary_dispatcher, raw_signature=False)
+register_dispatch("divide", binary_dispatcher, raw_signature=False)
+register_dispatch("true_divide", binary_dispatcher, raw_signature=False)
+register_dispatch("add", binary_dispatcher, raw_signature=False)
+register_dispatch("subtract", binary_dispatcher, raw_signature=False)
+
+# TODO: register other binary functions?
+
+# --------------- object to act as drop-in replace for numpy ---------------- #
+
+
+class InjectDtypeDevice:
+ """Wrapper that injects defaultdtype and device arguments into a function"""
+
+ __slots__ = ("_fn", "_device", "_dtype")
+
+ def __init__(self, fn, device=None, dtype=None):
+ self._fn = fn
+ self._device = device
+ self._dtype = dtype
+
+ def __call__(self, *args, **kwargs):
+ if self._device is not None and "device" not in kwargs:
+ kwargs["device"] = self._device
+ if self._dtype is not None and "dtype" not in kwargs:
+ kwargs["dtype"] = self._dtype
+ return self._fn(*args, **kwargs)
+
+ def __repr__(self):
+ return (
+ f"InjectDtypeDevice(fn={self._fn}, "
+ f"device={self._device}, "
+ f"dtype={self._dtype})"
+ )
+
+
+_NAME_SPACE_SUBMODULES = {
+ "random",
+ "linalg",
+ "scipy",
+}
+
+
+class AutoNamespace:
+ """Mimics a namespace, optionally for a specific backend, device, and
+ dtype, caching the lookup of functions, and injecting default device and
+ dtype arguments for certain creation routines.
+
+ Parameters
+ ----------
+ like : array_like, str, or None
+ The backend to use, or an object to infer the backend from. If None,
+ the default behavior is to use `autoray.do` and auto dispatch backend
+ at function call time. If given, the functions are cached at first
+ call.
+ device : str, optional
+ The device to use for the backend. If None, it will be inferred from
+ the `like` paramater is that is array-like or set to None.
+ dtype : str, optional
+ The dtype to use for the backend. If None, it will be inferred from
+ the `like` parameter if that is array-like or set to None.
+ submodule : str, optional
+ This is used internally when nesting attribute lookups, e.g.
+ `xp.random.normal`, `xp.linalg.eigh`.
+ """
+
+ def __init__(
+ self,
+ like=None,
+ device=None,
+ dtype=None,
+ submodule=None,
+ ):
+ if like is None:
+ # use autoray.do and auto dispatch
+ self._backend = None
+ elif isinstance(like, str):
+ # commit to a specific given backend
+ self._backend = like
+ else:
+ # commit to a specific backend inferred from array-like
+ self._backend = _infer_class_backend_cached(like.__class__)
+
+ if device is None:
+ if like is not None:
+ if hasattr(like, "device"):
+ device = like.device
+ self._device = device
+
+ if dtype is None:
+ if like is not None:
+ if hasattr(like, "dtype"):
+ dtype = like.dtype
+ self._dtype = dtype
+ self._submodule = submodule
+
+ def _get_submodule(self, name):
+ new = object.__new__(type(self))
+ new._backend = self._backend
+ new._device = self._device
+ new._dtype = self._dtype
+ new._submodule = name
+ return new
+
+ def _get_fn(self, name):
+ if self._submodule is not None:
+ # prepend the submodule name
+ name = f"{self._submodule}.{name}"
+
+ if name in _NAME_SPACE_SUBMODULES:
+ # note that other submodules can be accessed, these are just the
+ # ones with functions that we possibly want to translate
+ return self._get_submodule(name)
+
+ if self._backend is None:
+ # use autoray.do and auto dispatch
+ return functools.partial(do, name)
+
+ fn = get_lib_fn(self._backend, name)
+
+ # possibly wrap for dtype and device injection
+ if name in _CREATION_ROUTINES:
+ key = (self._backend, name)
+ try:
+ # check for backend specific defaults
+ inject_dtype, inject_device = _CREATION_INJECT[key]
+ except KeyError:
+ # populate with non backend specific defaults
+ inject_dtype, inject_device = _CREATION_ROUTINES[name]
+ _CREATION_INJECT[key] = (inject_dtype, inject_device)
+
+ if not inject_dtype:
+ # this is not a function that accepts dtype
+ dtype_to_inject = None
+ else:
+ dtype_to_inject = self._dtype
+
+ if not inject_device:
+ # this is not a function that accepts device
+ device_to_inject = None
+ else:
+ device_to_inject = self._device
+
+ if (dtype_to_inject is not None) or (device_to_inject is not None):
+ # only wrap if we actually inject something
+ fn = InjectDtypeDevice(fn, device_to_inject, dtype_to_inject)
+
+ return fn
+
+ def __getattr__(self, name):
+ x = self._get_fn(name)
+ self.__dict__[name] = x
+ return x
+
+ def __repr__(self):
+ return (
+ f"{self.__class__.__name__}("
+ f"backend={self._backend}, "
+ f"device={self._device}, "
+ f"dtype={self._dtype}, "
+ f"submodule={self._submodule}"
+ ")"
+ )
+
+
+_NAMESPACE_CACHE = {}
+
+
+def get_namespace(like=None, device=None, dtype=None, submodule=None):
+ """Get an automatic namespace object.
+
+ If `like` is None, the namespace essentially provides an alternative syntax
+ to `do`, dispatching each function at calltime, and allowing the backend
+ and function implementations to be dynamically updated.
+
+ If `like` is supplied however, the backend is eagerly dispatched and
+ functions are loaded and cached specifically for that backend. In this
+ case, default `device` and `dtype` can also be specified for various array
+ creation routines, or if `like` is an array, inferred from that.
+
+ Parameters
+ ----------
+ like : array-like, str or None, optional
+ An array-like object to dispatch on, an explicit backend name, or None.
+ device : str or None, optional
+ The device to use for array creation, or None to infer from `like`.
+ dtype : str or None, optional
+ The data type to use for array creation, or None to infer from `like`.
+
+ Returns
+ -------
+ AutoNamespace
+ An automatic namespace object.
+ """
+ if like is not None:
+ if not isinstance(like, str):
+ # array
+ cls = like.__class__
+ if device is None:
+ try:
+ device = like.device
+ except AttributeError:
+ device = None
+ if dtype is None:
+ try:
+ dtype = like.dtype
+ except AttributeError:
+ dtype = None
+ else:
+ # manually specified backend
+ cls = str
+ else:
+ # namespace functions will dispatch at call time
+ cls = None
+
+ key = (cls, device, dtype, submodule)
+
+ try:
+ xp = _NAMESPACE_CACHE[key]
+ except KeyError:
+ xp = _NAMESPACE_CACHE[key] = AutoNamespace(
+ like=like,
+ device=device,
+ dtype=dtype,
+ submodule=submodule,
+ )
+
+ return xp
+
+
+# note this is the backend agnostic numpy mimic (`import autoray.numpy as np`)
+# not the namespace for backend numpy (`xp = get_namespace(like="numpy")`)
+numpy = get_namespace()
+
+
+# --------------------------------------------------------------------------- #
+# specific functions #
+# --------------------------------------------------------------------------- #
+
+# ------------------------------ standard-lib ------------------------------- #
+
+_MODULE_ALIASES["decimal"] = "math"
+_MODULE_ALIASES["builtins"] = "numpy"
+
+
+_builtin_dtype_lookup = {
+ int: "int64",
+ float: "float64",
+ complex: "complex128",
+}
+
+
+@get_dtype_name.register("builtins")
+def builtins_get_dtype_name(x):
+ return _builtin_dtype_lookup[x.__class__]
+
+
+_FUNCS["builtins", "complex"] = complex
+
+# ---------------------------------- numpy ---------------------------------- #
+
+
+def numpy_to_numpy(x):
+ return do("asarray", x, like="numpy")
+
+
+_MODULE_ALIASES["numpy.scipy"] = "scipy"
+_FUNCS["numpy", "to_numpy"] = numpy_to_numpy
+_FUNCS["numpy", "complex"] = complex_add_re_im
+_FUNCS["builtins", "to_numpy"] = numpy_to_numpy
+_SUBMODULE_ALIASES["numpy", "linalg.lu"] = "scipy.linalg"
+_SUBMODULE_ALIASES["numpy", "linalg.expm"] = "scipy.linalg"
+_CUSTOM_WRAPPERS["numpy", "linalg.svd"] = svd_not_full_matrices_wrapper
+_CUSTOM_WRAPPERS["numpy", "random.normal"] = with_dtype_wrapper
+_CUSTOM_WRAPPERS["numpy", "random.uniform"] = with_dtype_wrapper
+
+# ---------------------------------- cupy ----------------------------------- #
+
+
+def cupy_to_numpy(x): # pragma: no cover
+ return x.get()
+
+
+_MODULE_ALIASES["cupy.scipy"] = "cupyx.scipy"
+_FUNCS["cupy", "to_numpy"] = cupy_to_numpy
+_FUNCS["cupy", "complex"] = complex_add_re_im
+_CUSTOM_WRAPPERS["cupy", "linalg.svd"] = svd_not_full_matrices_wrapper
+
+# ----------------------------------- jax ----------------------------------- #
+
+
+def jax_to_numpy(x):
+ return do("asarray", x, like="numpy")
+
+
+class JaxDefaultRNG:
+ """Stateful but deterministic random number generator for JAX following
+ numpy's Generator API, compatible with `jax.jit`.
+ """
+
+ def __init__(self, seed, **kwargs):
+ import jax
+
+ self.jax = jax
+ self.key = jax.random.key(seed, **kwargs)
+
+ def binomial(self, n, p, size=None, **kwargs):
+ self.key, subkey = self.jax.random.split(self.key)
+ shape = _handle_size_to_shape(size)
+ return self.jax.random.binomial(
+ subkey, n=n, p=p, shape=shape, **kwargs
+ )
+
+ def choice(self, a, size=None, replace=True, p=None, axis=0, **kwargs):
+ self.key, subkey = self.jax.random.split(self.key)
+ shape = _handle_size_to_shape(size)
+ return self.jax.random.choice(
+ subkey,
+ a,
+ shape=shape,
+ replace=replace,
+ p=p,
+ axis=axis,
+ **kwargs,
+ )
+
+ def exponential(self, scale=1.0, size=None, **kwargs):
+ self.key, subkey = self.jax.random.split(self.key)
+ shape = _handle_size_to_shape(size)
+ x = self.jax.random.exponential(subkey, shape=shape, **kwargs)
+ if scale != 1.0:
+ x *= scale
+ return x
+
+ def gumbel(self, loc=0.0, scale=1.0, size=None, **kwargs):
+ self.key, subkey = self.jax.random.split(self.key)
+ shape = _handle_size_to_shape(size)
+ x = self.jax.random.gumbel(subkey, shape=shape, **kwargs)
+ if scale != 1.0:
+ x *= scale
+ if loc != 0.0:
+ x += loc
+ return x
+
+ def integers(self, low, high=None, size=None, **kwargs):
+ self.key, subkey = self.jax.random.split(self.key)
+ shape = _handle_size_to_shape(size)
+ if high is None:
+ high = low
+ low = 0
+ return self.jax.random.randint(
+ subkey,
+ shape=shape,
+ minval=low,
+ maxval=high,
+ **kwargs,
+ )
+
+ def normal(self, loc=0.0, scale=1.0, size=None, **kwargs):
+ self.key, subkey = self.jax.random.split(self.key)
+ shape = _handle_size_to_shape(size)
+ x = self.jax.random.normal(subkey, shape=shape, **kwargs)
+ if scale != 1.0:
+ x *= scale
+ if loc != 0.0:
+ x += loc
+ return x
+
+ def permutation(self, x, **kwargs):
+ self.key, subkey = self.jax.random.split(self.key)
+ return self.jax.random.permutation(subkey, x, **kwargs)
+
+ def poisson(self, lam=1.0, size=None, **kwargs):
+ self.key, subkey = self.jax.random.split(self.key)
+ shape = _handle_size_to_shape(size)
+ x = self.jax.random.poisson(subkey, lam, shape=shape, **kwargs)
+ return x
+
+ def random(self, size=None, **kwargs):
+ return self.uniform(size=size, **kwargs)
+
+ def uniform(self, low=0.0, high=1.0, size=None, **kwargs):
+ self.key, subkey = self.jax.random.split(self.key)
+ shape = _handle_size_to_shape(size)
+ return self.jax.random.uniform(
+ subkey, shape=shape, minval=low, maxval=high, **kwargs
+ )
+
+
+def jax_default_rng(seed, **kwargs):
+ if isinstance(seed, JaxDefaultRNG):
+ return seed
+ return JaxDefaultRNG(seed, **kwargs)
+
+
+register_function("jax", "random.default_rng", jax_default_rng)
+register_backend(JaxDefaultRNG, "jax")
+
+
+_JAX_RANDOM_KEY = None
+
+
+def jax_random_seed(seed=None):
+ from jax.random import PRNGKey
+
+ global _JAX_RANDOM_KEY
+ if seed is None:
+ from random import SystemRandom
+
+ seed = SystemRandom().randint(-(2**63), 2**63 - 1) # inclusive high
+ _JAX_RANDOM_KEY = PRNGKey(seed)
+
+
+def jax_random_get_key():
+ from jax.random import split
+
+ global _JAX_RANDOM_KEY
+ if _JAX_RANDOM_KEY is None:
+ jax_random_seed()
+ _JAX_RANDOM_KEY, subkey = split(_JAX_RANDOM_KEY)
+ return subkey
+
+
+def jax_random_uniform(low=0.0, high=1.0, size=None, **kwargs):
+ from jax.random import uniform
+
+ if size is None:
+ size = ()
+ return uniform(
+ jax_random_get_key(), shape=size, minval=low, maxval=high, **kwargs
+ )
+
+
+def jax_random_normal(loc=0.0, scale=1.0, size=None, **kwargs):
+ from jax.random import normal
+
+ if size is None:
+ size = ()
+ x = normal(jax_random_get_key(), shape=size, **kwargs)
+ if scale != 1.0:
+ x *= scale
+ if loc != 0.0:
+ x += loc
+ return x
+
+
+_BACKEND_ALIASES["jaxlib"] = "jax"
+_MODULE_ALIASES["jax.scipy"] = "jax.scipy"
+_MODULE_ALIASES["jax"] = "jax.numpy"
+_SUBMODULE_ALIASES["jax", "complex"] = "jax.lax"
+_SUBMODULE_ALIASES["jax", "linalg.expm"] = "jax.scipy.linalg"
+_SUBMODULE_ALIASES["jax", "linalg.householder_product"] = "jax.lax.linalg"
+# n.b. jax supports fat QR but not when computing gradients
+_CUSTOM_WRAPPERS["jax", "linalg.qr"] = qr_allow_fat
+_CUSTOM_WRAPPERS["jax", "linalg.svd"] = svd_not_full_matrices_wrapper
+_FUNCS["jax", "to_numpy"] = jax_to_numpy
+_FUNCS["jax", "random.seed"] = jax_random_seed
+_FUNCS["jax", "random.uniform"] = jax_random_uniform
+_FUNCS["jax", "random.normal"] = jax_random_normal
+
+
+# --------------------------------- aesara ---------------------------------- #
+
+
+@shape.register("aesara")
+def aesara_shape(x):
+ return x.type.shape
+
+
+_MODULE_ALIASES["aesara"] = "aesara.tensor"
+_FUNCS["aesara", "shape"] = aesara_shape
+
+
+# -------------------------------- autograd --------------------------------- #
+
+
+def autograd_take(x, indices, axis=None):
+ # NOTE: autograd take doesn't support grad
+ if axis is None:
+ return x.ravel()[indices]
+ else:
+ selector = tuple(
+ slice(None) if i != axis else indices for i in range(x.ndim)
+ )
+ return x[selector]
+
+
+_MODULE_ALIASES["autograd"] = "autograd.numpy"
+_CUSTOM_WRAPPERS["autograd", "linalg.svd"] = svd_not_full_matrices_wrapper
+_FUNCS["autograd", "complex"] = complex_add_re_im
+_FUNCS["autograd", "take"] = autograd_take
+
+
+# ---------------------------------- dask ----------------------------------- #
+
+
+def dask_to_numpy(x):
+ return x.compute()
+
+
+def dask_eye_wrapper(fn):
+ # Make M work as positional argument
+ @functools.wraps(fn)
+ def numpy_like(N, M=None, **kwargs):
+ return fn(N, M=M, **kwargs)
+
+ return numpy_like
+
+
+_FUNCS["dask", "to_numpy"] = dask_to_numpy
+_FUNCS["dask", "complex"] = complex_add_re_im
+_FUNC_ALIASES["dask", "abs"] = "absolute"
+_FUNC_ALIASES["dask", "identity"] = "eye"
+_MODULE_ALIASES["dask"] = "dask.array"
+_CUSTOM_WRAPPERS["dask", "linalg.svd"] = svd_manual_full_matrices_kwarg
+_CUSTOM_WRAPPERS["dask", "linalg.cholesky"] = cholesky_lower
+_CUSTOM_WRAPPERS["dask", "random.normal"] = with_dtype_wrapper
+_CUSTOM_WRAPPERS["dask", "random.uniform"] = with_dtype_wrapper
+_CUSTOM_WRAPPERS["dask", "eye"] = dask_eye_wrapper
+
+# ---------------------------------- mars ----------------------------------- #
+
+
+def mars_to_numpy(x):
+ return x.to_numpy()
+
+
+_FUNCS["mars", "to_numpy"] = mars_to_numpy
+_FUNCS["mars", "complex"] = complex_add_re_im
+_MODULE_ALIASES["mars"] = "mars.tensor"
+_CUSTOM_WRAPPERS["mars", "linalg.cholesky"] = cholesky_lower
+
+
+# ----------------------------------- ctf ----------------------------------- #
+
+
+def ctf_array(x):
+ return do("astensor", x, like="ctf")
+
+
+def ctf_to_numpy(x):
+ return x.to_nparray()
+
+
+def ctf_count_nonzero(x):
+ return (x != 0).astype(int).sum()
+
+
+@get_dtype_name.register("ctf")
+def ctf_get_dtype_name(x):
+ return x.dtype.__name__
+
+
+_FUNCS["ctf", "array"] = ctf_array
+_FUNCS["ctf", "complex"] = complex_add_re_im
+_FUNCS["ctf", "allclose"] = allclose
+_FUNCS["ctf", "to_numpy"] = ctf_to_numpy
+_FUNCS["ctf", "count_nonzero"] = ctf_count_nonzero
+
+_SUBMODULE_ALIASES["ctf", "float32"] = "numpy"
+_SUBMODULE_ALIASES["ctf", "float64"] = "numpy"
+_SUBMODULE_ALIASES["ctf", "complex64"] = "numpy"
+_SUBMODULE_ALIASES["ctf", "complex128"] = "numpy"
+_SUBMODULE_ALIASES["ctf", "linalg.svd"] = "ctf"
+_SUBMODULE_ALIASES["ctf", "linalg.eigh"] = "ctf"
+_SUBMODULE_ALIASES["ctf", "linalg.qr"] = "ctf"
+_SUBMODULE_ALIASES["ctf", "linalg.norm"] = "ctf"
+
+_FUNC_ALIASES["ctf", "random.uniform"] = "random"
+
+_CUSTOM_WRAPPERS["ctf", "random.uniform"] = scale_random_uniform_manually
+
+
+# ------------------------------- sparse------------------------------------- #
+
+
+def sparse_array(x):
+ return do("COO.from_numpy", x, like="sparse")
+
+
+def sparse_to_numpy(x):
+ return x.todense()
+
+
+def sparse_transpose(x, axes=None):
+ return x.transpose(axes)
+
+
+def sparse_reshape(x, shape):
+ return x.reshape(shape)
+
+
+def sparse_sum(x, axis=None, keepdims=False, dtype=None, out=None):
+ return x.sum(axis=axis, keepdims=keepdims, dtype=dtype, out=out)
+
+
+def sparse_prod(x, axis=None, keepdims=False, dtype=None, out=None):
+ return x.prod(axis=axis, keepdims=keepdims, dtype=dtype, out=out)
+
+
+def sparse_conj(x):
+ return x.conj()
+
+
+def sparse_real(x):
+ return x.real
+
+
+def sparse_imag(x):
+ return x.imag
+
+
+def sparse_count_nonzero(x):
+ return x.nnz
+
+
+def sparse_random_uniform(low=0.0, high=1.0, size=None, dtype=None, **kwargs):
+ def rvs(nnz):
+ return do(
+ "random.uniform", low, high, (nnz,), dtype=dtype, like="numpy"
+ )
+
+ return do("random", size, data_rvs=rvs, **kwargs, like="sparse")
+
+
+def sparse_random_normal(loc=0.0, scale=1.0, size=None, dtype=None, **kwargs):
+ def rvs(nnz):
+ return do(
+ "random.normal", loc, scale, (nnz,), dtype=dtype, like="numpy"
+ )
+
+ return do("random", size, data_rvs=rvs, **kwargs, like="sparse")
+
+
+_FUNCS["sparse", "array"] = sparse_array
+_FUNCS["sparse", "to_numpy"] = sparse_to_numpy
+_FUNCS["sparse", "transpose"] = sparse_transpose
+_FUNCS["sparse", "reshape"] = sparse_reshape
+_FUNCS["sparse", "sum"] = sparse_sum
+_FUNCS["sparse", "prod"] = sparse_prod
+_FUNCS["sparse", "conj"] = sparse_conj
+_FUNCS["sparse", "real"] = sparse_real
+_FUNCS["sparse", "real"] = sparse_real
+_FUNCS["sparse", "imag"] = sparse_imag
+_FUNCS["sparse", "complex"] = complex_add_re_im
+_FUNCS["sparse", "count_nonzero"] = sparse_count_nonzero
+_FUNCS["sparse", "random.uniform"] = sparse_random_uniform
+_FUNCS["sparse", "random.normal"] = sparse_random_normal
+
+_FUNC_ALIASES["sparse", "identity"] = "eye"
+
+# sparse uses numpys __array_func__ interface
+for f in (
+ "log",
+ "log2",
+ "log10",
+ "exp",
+ "sqrt",
+ "sign",
+ "sin",
+ "cos",
+ "tan",
+ "arcsin",
+ "arccos",
+ "arctan",
+ "sinh",
+ "cosh",
+ "tanh",
+ "arcsinh",
+ "arccosh",
+ "arctanh",
+ "tensordot",
+ # NB put tensordot here, as sparse.tensordot can produce dense (numpy)
+ # arrays but errors when both inputs are dense - we want nested calls to
+ # tensordot to handle this
+):
+ _SUBMODULE_ALIASES["sparse", f] = "numpy"
+
+
+# ------------------------------- tensorflow -------------------------------- #
+
+
+def tensorflow_to_numpy(x):
+ return x.numpy()
+
+
+def tensorflow_indices(dimensions):
+ _meshgrid = get_lib_fn("tensorflow", "meshgrid")
+ _arange = get_lib_fn("tensorflow", "arange")
+ return _meshgrid(*map(_arange, dimensions), indexing="ij")
+
+
+_MODULE_ALIASES["tensorflow.linalg"] = "tensorflow.linalg"
+_MODULE_ALIASES["tensorflow.random"] = "tensorflow.random"
+_MODULE_ALIASES["tensorflow"] = "tensorflow.experimental.numpy"
+
+_FUNCS["tensorflow", "to_numpy"] = tensorflow_to_numpy
+_FUNCS["tensorflow", "indices"] = tensorflow_indices
+
+_FUNC_ALIASES["tensorflow", "astype"] = "cast"
+_SUBMODULE_ALIASES["tensorflow", "cast"] = "tensorflow"
+_SUBMODULE_ALIASES["tensorflow", "astype"] = "tensorflow"
+_SUBMODULE_ALIASES["tensorflow", "complex"] = "tensorflow"
+
+_CUSTOM_WRAPPERS["tensorflow", "linalg.svd"] = svd_sUV_to_UsVH_wrapper
+_CUSTOM_WRAPPERS["tensorflow", "linalg.solve"] = binary_allow_1d_rhs_wrap
+_CUSTOM_WRAPPERS["tensorflow", "random.uniform"] = make_translator(
+ [
+ ("low", ("minval", 0.0)),
+ ("high", ("maxval", 1.0)),
+ ("size", ("shape", ())),
+ ]
+)
+_CUSTOM_WRAPPERS["tensorflow", "random.normal"] = make_translator(
+ [
+ ("loc", ("mean", 0.0)),
+ ("scale", ("stddev", 1.0)),
+ ("size", ("shape", ())),
+ ]
+)
+
+
+def tensorflow_pad_wrap(tf_pad):
+ def numpy_like(array, pad_width, mode="constant", constant_values=0):
+ if mode != "constant":
+ raise NotImplementedError
+
+ try:
+ if len(pad_width) == 1:
+ pad_width = pad_width * ndim(array)
+ except TypeError:
+ pad_width = ((pad_width, pad_width),) * ndim(array)
+
+ return tf_pad(
+ array, pad_width, mode="CONSTANT", constant_values=constant_values
+ )
+
+ return numpy_like
+
+
+_CUSTOM_WRAPPERS["tensorflow", "pad"] = tensorflow_pad_wrap
+_SUBMODULE_ALIASES["tensorflow", "pad"] = "tensorflow"
+
+
+# register_creation_routine("tensorflow", "linspace", inject_dtype=False)
+
+
+# ---------------------------------- torch ---------------------------------- #
+
+
+@functools.cache
+def get_torch():
+ import torch
+
+ return torch
+
+
+@shape.register("torch")
+def torch_shape(x):
+ # torch returns a Size object, we want tuple[int]
+ return tuple(map(int, x.shape))
+
+
+@size.register("torch")
+def torch_size(x):
+ return x.numel()
+
+
+def torch_to_numpy(x):
+ return x.detach().cpu().numpy()
+
+
+def torch_copy(x):
+ return x.detach().clone()
+
+
+def torch_transpose(x, axes=None):
+ if axes is None:
+ axes = reversed(range(0, x.ndimension()))
+ return x.permute(*axes)
+
+
+def torch_astype(x, dtype):
+ return x.to(dtype=to_backend_dtype(dtype, like=x))
+
+
+@functools.lru_cache(None)
+def _torch_get_dtype_name(dtype):
+ return str(dtype).split(".")[-1]
+
+
+@get_dtype_name.register("torch")
+def torch_get_dtype_name(x):
+ return _torch_get_dtype_name(x.dtype)
+
+
+def torch_real(x):
+ # torch doesn't support calling real on real arrays
+ try:
+ if x.is_complex():
+ return x.real
+ except AttributeError:
+ pass
+ return x
+
+
+def torch_imag(x):
+ # torch doesn't support calling imag on real arrays
+ try:
+ if x.is_complex():
+ return x.imag
+ except AttributeError:
+ pass
+ return do("zeros_like", x)
+
+
+def torch_linalg_solve_wrap(fn):
+ @binary_allow_1d_rhs_wrap
+ def numpy_like(a, b):
+ return fn(b, a)[0]
+
+ return numpy_like
+
+
+def torch_linalg_eigh(x):
+ return tuple(do("symeig", x, eigenvectors=True, like="torch"))
+
+
+def torch_linalg_eigvalsh(x):
+ return do("symeig", x, eigenvectors=False, like="torch")[0]
+
+
+def torch_tensordot_wrap(fn):
+ @functools.wraps(fn)
+ def numpy_like(a, b, axes=2):
+ return fn(a, b, dims=axes)
+
+ return numpy_like
+
+
+def torch_pad(array, pad_width, mode="constant", constant_values=0):
+ if mode != "constant":
+ raise NotImplementedError
+
+ try:
+ # numpy takes pads like ((0, 0), (1, 1), ... (n-1, n-1))
+ # torch takes pads like (n-1, n-1, n-2, n-2, n-3, n-3, ...)
+ pad = tuple(itertools.chain.from_iterable(pad_width))[::-1]
+
+ # a single tuple was specified ((a, b),) - use for all axes
+ if len(pad) == 2:
+ pad = pad * array.ndimension()
+
+ except TypeError:
+ # assume int
+ pad = (pad_width,) * 2 * array.ndimension()
+
+ return do(
+ "nn.functional.pad",
+ array,
+ pad=pad,
+ mode=mode,
+ value=constant_values,
+ like="torch",
+ )
+
+
+def torch_split_wrap(fn):
+ # for torch >=1.8 we can use tensor_split instead, but in current stable
+ # release this function has not been added
+ @functools.wraps(fn)
+ def numpy_like(ary, indices_or_sections, axis=0, **kwargs):
+ if isinstance(indices_or_sections, numbers.Integral):
+ split_size = shape(ary)[axis] // indices_or_sections
+ return fn(ary, split_size, dim=axis, **kwargs)
+ else:
+ # torch.split doesn't support empty splits
+ if len(indices_or_sections) == 0:
+ return (ary,)
+
+ diff = do(
+ "diff",
+ indices_or_sections,
+ prepend=0,
+ append=shape(ary)[axis],
+ like="numpy",
+ )
+ diff = list(diff)
+ return fn(ary, diff, dim=axis)
+
+ return numpy_like
+
+
+def torch_zeros_ones_wrap(fn):
+ @functools.wraps(fn)
+ def numpy_like(shape, dtype=None, **kwargs):
+ if dtype is not None:
+ dtype = to_backend_dtype(dtype, like="torch")
+ return fn(shape, dtype=dtype, **kwargs)
+
+ return numpy_like
+
+
+def torch_eye_wrap(fn):
+ @functools.wraps(fn)
+ def numpy_like(N, M=None, dtype=None, **kwargs):
+ if dtype is not None:
+ dtype = to_backend_dtype(dtype, like="torch")
+ if M is not None:
+ return fn(N, m=M, dtype=dtype, **kwargs)
+ else:
+ return fn(N, dtype=dtype, **kwargs)
+
+ return numpy_like
+
+
+def torch_sort_wrap(fn):
+ @functools.wraps(fn)
+ def numpy_like(a, axis=-1):
+ return fn(a, dim=axis)[0]
+
+ return numpy_like
+
+
+def torch_indices(dimensions):
+ _meshgrid = get_lib_fn("torch", "meshgrid")
+ _arange = get_lib_fn("torch", "arange")
+ return _meshgrid(*map(_arange, dimensions), indexing="ij")
+
+
+def torch_flip_wrap(torch_flip):
+ def numpy_like(x, axis=None):
+ if axis is None:
+ dims = tuple(range(x.ndimension()))
+ elif isinstance(axis, int):
+ dims = (axis,)
+ else:
+ # already tuple/list
+ dims = axis
+ return torch_flip(x, dims)
+
+ return numpy_like
+
+
+def torch_take(a, indices, axis=None):
+ torch = get_torch()
+
+ if isinstance(indices, (tuple, list)) and len(indices) == 1:
+ # need to convert list/tuple dimension to tensor, and not squeeze
+ indices = torch.as_tensor(indices[0], device=a.device)
+ unsqueeze = True
+ squeeze = False
+ else:
+ indices = torch.as_tensor(indices, device=a.device)
+ # XXX: if scalar can't yet use torch.select as it can't vmap
+ squeeze = unsqueeze = indices.ndim == 0
+
+ if unsqueeze:
+ # promote scalar indices to 1D
+ indices = torch.unsqueeze(indices, dim=0)
+
+ # perform the take!
+ a = torch.index_select(a, dim=axis, index=indices)
+
+ if squeeze:
+ # remove scalar dimension
+ return a.squeeze(dim=axis)
+
+ return a
+
+
+class TorchDefaultRNG:
+ def __init__(self, seed, device=None):
+ self._torch = get_torch()
+ self._generator = self._torch.Generator(device=device)
+ self._generator.manual_seed(seed)
+
+ # def binomial(self, n, p, size=None, **kwargs):
+ # raise NotImplementedError()
+
+ # def choice(self, a, size=None, replace=True, p=None, axis=0, **kwargs):
+ # raise NotImplementedError()
+
+ # def exponential(self, scale=1.0, size=None, **kwargs):
+ # raise NotImplementedError()
+
+ # def gumbel(self, loc=0.0, scale=1.0, size=None, **kwargs):
+ # raise NotImplementedError()
+
+ def integers(self, low, high=None, size=None, **kwargs):
+ if high is None:
+ high = low
+ low = 0
+ size = _handle_size_to_shape(size)
+ return self._torch.randint(
+ low, high, size, generator=self._generator, **kwargs
+ )
+
+ # def poisson(self, lam=1.0, size=None, **kwargs):
+ # raise NotImplementedError()
+
+ def normal(self, loc=0.0, scale=1.0, size=None, **kwargs):
+ size = _handle_size_to_shape(size)
+ x = self._torch.randn(size, generator=self._generator, **kwargs)
+ if scale != 1.0:
+ x = x * scale
+ if loc != 0.0:
+ x = x + loc
+ return x
+
+ def random(self, size=None, **kwargs):
+ size = _handle_size_to_shape(size)
+ return self._torch.rand(size, generator=self._generator, **kwargs)
+
+ def permutation(self, x, **kwargs):
+ if isinstance(x, int):
+ return self._torch.randperm(x, generator=self._generator, **kwargs)
+
+ axis = kwargs.get("axis", 0)
+ n = x.shape[axis]
+ perm_indices = self._torch.randperm(
+ n, generator=self._generator, device=x.device
+ )
+ return self._torch.index_select(x, axis, perm_indices)
+
+ def uniform(self, low=0.0, high=1.0, size=None, **kwargs):
+ size = _handle_size_to_shape(size)
+ x = self._torch.rand(size, generator=self._generator, **kwargs)
+ if low != 0.0 or high != 1.0:
+ x = x * (high - low) + low
+ return x
+
+ def choice(self, a, size=None, replace=True, p=None):
+ scalar = reshape = None
+ if size is None:
+ scalar = True
+ size = 1
+ elif not isinstance(size, numbers.Integral):
+ # assume tuple
+ reshape = size
+ size = functools.reduce(operator.mul, size)
+
+ if isinstance(a, numbers.Integral):
+ a = self._torch.arange(a, device=self._generator.device)
+
+ # with torch have to first generate indices
+
+ if (p is not None) or (not replace):
+ if p is None:
+ # uniform distribution, multinomial renormalizes internally
+ p = self._torch.ones(a.shape[0], device=self._generator.device)
+
+ idx = self._torch.multinomial(
+ p,
+ num_samples=size,
+ replacement=replace,
+ generator=self._generator,
+ )
+ else:
+ # quicker for uniform *with* replacement
+ idx = self._torch.randint(
+ low=0,
+ high=a.shape[0],
+ size=(size,),
+ generator=self._generator,
+ )
+
+ # then take the samples!
+ random_choices = a[idx]
+
+ if scalar:
+ random_choices = random_choices.squeeze(0)
+
+ if reshape is not None:
+ random_choices = random_choices.reshape(reshape)
+
+ return random_choices
+
+
+def torch_default_rng(seed, **kwargs):
+ if isinstance(seed, TorchDefaultRNG):
+ return seed
+ return TorchDefaultRNG(seed, **kwargs)
+
+
+register_function("torch", "random.default_rng", torch_default_rng)
+register_backend(TorchDefaultRNG, "torch")
+
+
+_FUNCS["torch", "pad"] = torch_pad
+_FUNCS["torch", "real"] = torch_real
+_FUNCS["torch", "imag"] = torch_imag
+_FUNCS["torch", "astype"] = torch_astype
+_FUNCS["torch", "copy"] = torch_copy
+_FUNCS["torch", "to_numpy"] = torch_to_numpy
+_FUNCS["torch", "complex"] = complex_add_re_im
+_FUNCS["torch", "transpose"] = torch_transpose
+_FUNCS["torch", "indices"] = torch_indices
+_FUNCS["torch", "take"] = torch_take
+
+_FUNC_ALIASES["torch", "array"] = "tensor"
+_FUNC_ALIASES["torch", "asarray"] = "as_tensor"
+_FUNC_ALIASES["torch", "clip"] = "clamp"
+_FUNC_ALIASES["torch", "concatenate"] = "cat"
+_FUNC_ALIASES["torch", "conjugate"] = "conj"
+_FUNC_ALIASES["torch", "equal"] = "eq"
+_FUNC_ALIASES["torch", "expand_dims"] = "unsqueeze"
+_FUNC_ALIASES["torch", "identity"] = "eye"
+_FUNC_ALIASES["torch", "linalg.expm"] = "matrix_exp"
+_FUNC_ALIASES["torch", "max"] = "amax"
+_FUNC_ALIASES["torch", "min"] = "amin"
+_FUNC_ALIASES["torch", "power"] = "pow"
+_FUNC_ALIASES["torch", "random.normal"] = "randn"
+_FUNC_ALIASES["torch", "random.uniform"] = "rand"
+_FUNC_ALIASES["torch", "scipy.linalg.expm"] = "matrix_exp"
+_FUNC_ALIASES["torch", "split"] = "tensor_split"
+_FUNC_ALIASES["torch", "take_along_axis"] = "take_along_dim"
+
+_SUBMODULE_ALIASES["torch", "linalg.expm"] = "torch"
+_SUBMODULE_ALIASES["torch", "scipy.linalg.expm"] = "torch"
+_SUBMODULE_ALIASES["torch", "random.normal"] = "torch"
+_SUBMODULE_ALIASES["torch", "random.uniform"] = "torch"
+
+_CUSTOM_WRAPPERS["torch", "clip"] = make_translator(
+ [("a", ("input",)), ("a_min", ("min",)), ("a_max", ("max",))]
+)
+_CUSTOM_WRAPPERS["torch", "concatenate"] = make_translator(
+ [("arrays", ("tensors",)), ("axis", ("dim", 0))]
+)
+_CUSTOM_WRAPPERS["torch", "diagonal"] = make_translator(
+ [("a", ("input",)), ("axis1", ("dim1", 0)), ("axis2", ("dim2", 1))]
+)
+_CUSTOM_WRAPPERS["torch", "empty"] = make_translator([("shape", ("size",))])
+_CUSTOM_WRAPPERS["torch", "expand_dims"] = make_translator(
+ [("a", ("input",)), ("axis", ("dim",))]
+)
+_CUSTOM_WRAPPERS["torch", "eye"] = torch_eye_wrap
+_CUSTOM_WRAPPERS["torch", "flip"] = torch_flip_wrap
+_CUSTOM_WRAPPERS["torch", "linalg.svd"] = svd_not_full_matrices_wrapper
+_CUSTOM_WRAPPERS["torch", "ones"] = torch_zeros_ones_wrap
+_CUSTOM_WRAPPERS["torch", "random.normal"] = scale_random_normal_manually
+_CUSTOM_WRAPPERS["torch", "random.uniform"] = scale_random_uniform_manually
+_CUSTOM_WRAPPERS["torch", "sort"] = torch_sort_wrap
+_CUSTOM_WRAPPERS["torch", "stack"] = make_translator(
+ [("arrays", ("tensors",)), ("axis", ("dim", 0))]
+)
+_CUSTOM_WRAPPERS["torch", "tensordot"] = torch_tensordot_wrap
+_CUSTOM_WRAPPERS["torch", "tril"] = make_translator(
+ [("m", ("input",)), ("k", ("diagonal", 0))]
+)
+_CUSTOM_WRAPPERS["torch", "triu"] = make_translator(
+ [("m", ("input",)), ("k", ("diagonal", 0))]
+)
+_CUSTOM_WRAPPERS["torch", "zeros"] = torch_zeros_ones_wrap
+_CUSTOM_WRAPPERS["torch", "take_along_axis"] = make_translator(
+ [("arr", ("input",)), ("indices", ("indices",)), ("axis", ("dim", -1))]
+)
+_CUSTOM_WRAPPERS["torch", "linalg.norm"] = make_translator(
+ [
+ ("x", ("input",)),
+ ("ord", ("ord", None)),
+ ("axis", ("dim", None)),
+ ("keepdims", ("keepdim", False)),
+ ]
+)
+
+_torch_reduce_translation = [
+ ("a", ("input",)),
+ ("axis", ("dim",)),
+ ("keepdims", ("keepdim",)),
+]
+for f in ("sum", "max", "min", "prod", "mean", "median", "std", "var"):
+ # TODO: search "keepdim" in torch docs to find more
+ _CUSTOM_WRAPPERS["torch", f] = make_translator(_torch_reduce_translation)
+
+# for older versions of torch, can provide some alternative implementations
+_MODULE_ALIASES["torch[alt]"] = "torch"
+
+_FUNCS["torch[alt]", "linalg.eigh"] = torch_linalg_eigh
+_FUNCS["torch[alt]", "linalg.eigvalsh"] = torch_linalg_eigvalsh
+
+_SUBMODULE_ALIASES["torch[alt]", "linalg.norm"] = "torch"
+_SUBMODULE_ALIASES["torch[alt]", "linalg.qr"] = "torch"
+_SUBMODULE_ALIASES["torch[alt]", "linalg.solve"] = "torch"
+_SUBMODULE_ALIASES["torch[alt]", "linalg.svd"] = "torch"
+
+_CUSTOM_WRAPPERS["torch[alt]", "linalg.qr"] = qr_allow_fat
+_CUSTOM_WRAPPERS["torch[alt]", "linalg.solve"] = torch_linalg_solve_wrap
+_CUSTOM_WRAPPERS["torch[alt]", "linalg.svd"] = svd_UsV_to_UsVH_wrapper
+_CUSTOM_WRAPPERS["torch[alt]", "split"] = torch_split_wrap
+
+for f in _CREATION_ROUTINES:
+ register_creation_routine("torch", f, inject_device=True)
+register_creation_routine(
+ "torch", "array", inject_dtype=False, inject_device=True
+)
+register_creation_routine(
+ "torch", "asarray", inject_dtype=False, inject_device=True
+)
+register_creation_routine(
+ "torch", "random.default_rng", inject_dtype=False, inject_device=True
+)
+
+
+# ---------------------------------- mxnet ---------------------------------- #
+
+
+def mxnet_to_numpy(x):
+ return x.asnumpy()
+
+
+_MODULE_ALIASES["mxnet"] = "mxnet.numpy"
+_FUNCS["mxnet", "to_numpy"] = mxnet_to_numpy
+
+
+# --------------------------------- paddle ---------------------------------- #
+
+_paddle_dtype_name_conversion = {
+ "BOOL": "bool",
+ "INT8": "int8",
+ "INT16": "int16",
+ "INT32": "int32",
+ "INT64": "int64",
+ "FP16": "float16",
+ "FP32": "float32",
+ "FP64": "float64",
+ "COMPLEX64": "complex64",
+ "COMPLEX128": "complex128",
+}
+
+
+@get_dtype_name.register("paddle")
+def paddle_get_dtype_name(x):
+ return _paddle_dtype_name_conversion[x.dtype.name]
+
+
+@shape.register("paddle")
+def paddle_shape(x):
+ # convert from list
+ return tuple(x.shape)
+
+
+def paddle_to_numpy(x):
+ return x.numpy()
+
+
+def paddle_transpose(a, axes=None):
+ if axes is None:
+ axes = tuple(range(a.ndim - 1, -1, -1))
+ return a.transpose(perm=axes)
+
+
+def paddle_real(x):
+ # paddle doesn't support calling real on real arrays
+ try:
+ if x.is_complex():
+ return x.real()
+ except AttributeError:
+ pass
+ return x
+
+
+def paddle_imag(x):
+ # paddle doesn't support calling imag on real arrays
+ try:
+ if x.is_complex():
+ return x.imag()
+ except AttributeError:
+ pass
+ return do("zeros_like", x)
+
+
+def paddle_indices(dimensions):
+ _meshgrid = get_lib_fn("paddle", "meshgrid")
+ _arange = get_lib_fn("paddle", "arange")
+ return _meshgrid(*map(_arange, dimensions), indexing="ij")
+
+
+def paddle_ravel(x):
+ return x.reshape((-1,))
+
+
+def paddle_pad(array, pad_width, mode="constant", constant_values=0):
+ if mode != "constant":
+ raise NotImplementedError
+
+ try:
+ # numpy takes pads like ((0, 0), (1, 1), ... (n-1, n-1))
+ # paddle takes pads like (0, 0, 1, 1, 2, 2, ...)
+ pad = tuple(itertools.chain.from_iterable(pad_width))
+
+ # a single tuple was specified ((a, b),) - use for all axes
+ if len(pad) == 2:
+ pad = pad * array.ndim
+
+ except TypeError:
+ # assume int
+ pad = (pad_width,) * 2 * array.ndim
+
+ return do(
+ "nn.functional.pad",
+ array,
+ pad=pad,
+ mode=mode,
+ value=constant_values,
+ like="paddle",
+ )
+
+
+def paddle_wrap_reduction(fn):
+ def numpy_like(*args, **kwargs):
+ keepdims = kwargs.pop("keepdims", None)
+ if keepdims is not None:
+ kwargs["keepdim"] = keepdims
+ return fn(*args, **kwargs)
+
+ return numpy_like
+
+
+def paddle_split_wrap(fn):
+ # paddle doesn't seem to have `tensor_split always`
+
+ @functools.wraps(fn)
+ def numpy_like(ary, indices_or_sections, axis=0, **kwargs):
+ if isinstance(indices_or_sections, numbers.Integral):
+ return fn(ary, indices_or_sections, axis=axis, **kwargs)
+ else:
+ diff = do(
+ "diff",
+ indices_or_sections,
+ prepend=0,
+ append=shape(ary)[axis],
+ like="numpy",
+ )
+ diff = list(diff)
+ return fn(ary, diff, axis=axis)
+
+ return numpy_like
+
+
+_MODULE_ALIASES["paddle[alt]"] = "paddle"
+
+_FUNCS["paddle", "to_numpy"] = paddle_to_numpy
+_FUNCS["paddle", "transpose"] = paddle_transpose
+_FUNCS["paddle", "real"] = paddle_real
+_FUNCS["paddle", "imag"] = paddle_imag
+_FUNCS["paddle", "indices"] = paddle_indices
+_FUNCS["paddle", "ravel"] = paddle_ravel
+_FUNCS["paddle", "pad"] = paddle_pad
+
+_FUNC_ALIASES["paddle", "random.normal"] = "randn"
+_FUNC_ALIASES["paddle", "random.uniform"] = "rand"
+_FUNC_ALIASES["paddle", "asarray"] = "to_tensor"
+_FUNC_ALIASES["paddle", "concatenate"] = "concat"
+_FUNC_ALIASES["paddle", "power"] = "pow"
+_FUNC_ALIASES["paddle", "identity"] = "eye"
+_FUNC_ALIASES["paddle", "split"] = "tensor_split"
+
+_SUBMODULE_ALIASES["paddle", "random.normal"] = "paddle"
+_SUBMODULE_ALIASES["paddle", "random.uniform"] = "paddle"
+
+_CUSTOM_WRAPPERS["paddle", "random.normal"] = scale_random_normal_manually
+_CUSTOM_WRAPPERS["paddle", "random.uniform"] = scale_random_uniform_manually
+_CUSTOM_WRAPPERS["paddle[alt]", "split"] = paddle_split_wrap
+_CUSTOM_WRAPPERS["paddle", "tril"] = make_translator(
+ [("m", ("x",)), ("k", ("diagonal", 0))]
+)
+_CUSTOM_WRAPPERS["paddle", "triu"] = make_translator(
+ [("m", ("x",)), ("k", ("diagonal", 0))]
+)
+for f in ("sum", "max", "min", "prod", "mean", "std", "var"):
+ _CUSTOM_WRAPPERS["paddle", f] = paddle_wrap_reduction
+
+
+# -------------------------------- pytensor --------------------------------- #
+
+
+@shape.register("pytensor")
+def pytensor_shape(x):
+ return x.type.shape
+
+
+def pytensor_wrap_qr_with_shapes(fn):
+ import pytensor.tensor as pt
+
+ @functools.wraps(fn)
+ def qr_shaped(x, **kwargs):
+ *b, m, n = x.type.shape
+ k = min(m, n)
+ q, r = fn(x, mode="economic", **kwargs)
+ q = pt.specify_shape(q, (*b, m, k))
+ r = pt.specify_shape(r, (*b, k, n))
+ return q, r
+
+ return qr_shaped
+
+
+def pytensor_wrap_svd_with_shapes(fn):
+ import pytensor.tensor as pt
+
+ @functools.wraps(fn)
+ def svd_shaped(x, full_matrices=False, **kwargs):
+ *b, m, n = x.type.shape
+
+ k = min(m, n)
+ if full_matrices:
+ u_shape = (*b, m, m)
+ vh_shape = (*b, n, n)
+ else:
+ u_shape = (*b, m, k)
+ vh_shape = (*b, k, n)
+
+ u, s, vh = fn(x, full_matrices=full_matrices, **kwargs)
+ u = pt.specify_shape(u, u_shape)
+ s = pt.specify_shape(s, (*b, k))
+ vh = pt.specify_shape(vh, vh_shape)
+ return u, s, vh
+
+ return svd_shaped
+
+
+_MODULE_ALIASES["pytensor"] = "pytensor.tensor"
+_CUSTOM_WRAPPERS["pytensor", "linalg.qr"] = pytensor_wrap_qr_with_shapes
+_CUSTOM_WRAPPERS["pytensor", "linalg.svd"] = pytensor_wrap_svd_with_shapes
diff --git a/venv/Lib/site-packages/autoray/compiler.py b/venv/Lib/site-packages/autoray/compiler.py
new file mode 100644
index 0000000000000000000000000000000000000000..e46c8fe8ce857d2846f40e7216b8a6195c3604ef
--- /dev/null
+++ b/venv/Lib/site-packages/autoray/compiler.py
@@ -0,0 +1,339 @@
+import functools
+
+from . import lazy
+from .autoray import (
+ do,
+ infer_backend,
+ is_array,
+ tree_flatten,
+ tree_iter,
+ tree_map,
+ tree_unflatten,
+)
+
+
+class CompilePython:
+ """A simple compiler that unravels all autoray calls, optionally sharing
+ intermediates and folding constants, converts this to a code object using
+ ``compile``, then executes this using ``exec``.
+
+ Parameters
+ ----------
+ fn : callable
+ Function to compile - should have signature
+ ``fn(*args, **kwargs) -> array``, with ``args`` and ``kwargs`` any
+ nested combination of ``tuple``, ``list`` and ``dict`` objects
+ containing arrays (or other constant arguments), and perform array
+ operations on these using ``autoray.do``.
+ fold_constants : bool, optional
+ Whether to fold all constant array operations into the graph, which
+ might increase memory usage.
+ share_intermediates : bool, optional
+ Whether to cache all computational nodes during the trace, so that any
+ shared intermediate results can be identified.
+ """
+
+ def __init__(self, fn, fold_constants=True, share_intermediates=True):
+ self._fn = fn
+ self._fold_constants = fold_constants
+ self._share_intermediates = share_intermediates
+ self._jit_fn = None
+
+ def setup(self, args, kwargs):
+ """Convert the example arrays to lazy variables and trace them through
+ the function.
+ """
+ variables = tree_map(lazy.array, (args, kwargs))
+
+ if self._share_intermediates:
+ # with backend_like("autoray.lazy"), lazy.shared_intermediates():
+ with lazy.shared_intermediates():
+ outs = self._fn(*variables[0], **variables[1])
+ else:
+ # with backend_like("autoray.lazy"):
+ outs = self._fn(*variables[0], **variables[1])
+
+ return lazy.Function(
+ variables, outs, fold_constants=self._fold_constants
+ )
+
+ def __call__(self, *args, array_backend=None, **kwargs):
+ """If necessary, build, then call the compiled function."""
+ if self._jit_fn is None:
+ self._jit_fn = self.setup(args, kwargs)
+
+ return self._jit_fn(args, kwargs)
+
+
+class CompileJax:
+ """ """
+
+ def __init__(self, fn, enable_x64=None, platform_name=None, **kwargs):
+ self._fn = fn
+ self._enable_x64 = enable_x64
+ self._platform_name = platform_name
+ self._jit_fn = None
+ self._jit_kwargs = kwargs
+
+ def setup(self):
+ import jax
+
+ if self._enable_x64 is not None:
+ import jax
+
+ jax.config.update("jax_enable_x64", self._enable_x64)
+
+ if self._platform_name is not None:
+ import jax
+
+ jax.config.update("jax_platform_name", self._platform_name)
+
+ self._jit_fn = jax.jit(self._fn, **self._jit_kwargs)
+ self._fn = None
+
+ def __call__(self, *args, array_backend=None, **kwargs):
+ if self._jit_fn is None:
+ self.setup()
+ out = self._jit_fn(*args, **kwargs)
+ if array_backend != "jax":
+ out = do("asarray", out, like=array_backend)
+ return out
+
+
+class CompileTensorFlow:
+ """ """
+
+ def __init__(self, fn, **kwargs):
+ self._fn = fn
+ kwargs.setdefault("autograph", False)
+ self._jit_fn = None
+ self._jit_kwargs = kwargs
+
+ def setup(self):
+ import tensorflow as tf
+
+ self._jit_fn = tf.function(**self._jit_kwargs)(self._fn)
+ self._fn = None
+
+ def __call__(self, *args, array_backend=None, **kwargs):
+ if self._jit_fn is None:
+ self.setup()
+ out = self._jit_fn(*args, **kwargs)
+ if array_backend != "tensorflow":
+ out = do("asarray", out, like=array_backend)
+ return out
+
+
+class CompileTorch:
+ """ """
+
+ def __init__(self, fn, **kwargs):
+ import torch
+
+ self.torch = torch
+
+ if not hasattr(fn, "__name__") and isinstance(fn, functools.partial):
+ # torch jit.trace requires fn.__name__ and others
+ functools.update_wrapper(fn, fn.func)
+
+ self._fn = fn
+ self._jit_fn = None
+ kwargs.setdefault("check_trace", False)
+ self._jit_kwargs = kwargs
+
+ def setup(self, *args, **kwargs):
+ flat_tensors, ref_tree = tree_flatten((args, kwargs), get_ref=True)
+
+ def flat_fn(flat_tensors):
+ args, kwargs = tree_unflatten(flat_tensors, ref_tree)
+ return self._fn(*args, **kwargs)
+
+ self._jit_fn = self.torch.jit.trace(
+ flat_fn, [flat_tensors], **self._jit_kwargs
+ )
+
+ def __call__(self, *args, array_backend=None, **kwargs):
+ if array_backend != "torch":
+ # torch doesn't handle numpy arrays itself
+ args = tree_map(self.torch.as_tensor, args, is_array)
+ if self._jit_fn is None:
+ self.setup(*args, **kwargs)
+ out = self._jit_fn(tree_flatten((args, kwargs)))
+ if array_backend != "torch":
+ out = do("asarray", out, like=array_backend)
+ return out
+
+
+class CompileTorch2:
+ def __init__(self, fn, **kwargs):
+ import torch
+
+ self.torch = torch
+
+ def f(*args, **kwargs):
+ # for some reason torch compile wants a wrapper around
+ return fn(*args, **kwargs)
+
+ self._jit_fn = torch.compile(f, **kwargs)
+
+ def __call__(self, *args, array_backend=None, **kwargs):
+ if array_backend != "torch":
+ # torch doesn't handle numpy arrays itself
+ args = tree_map(self.torch.as_tensor, args, is_array)
+ out = self._jit_fn(*args, **kwargs)
+ if array_backend != "torch":
+ out = do("asarray", out, like=array_backend)
+ return out
+
+
+class CompilePytensor:
+ def __init__(self, fn, **kwargs):
+ self._fn = fn
+ self._jit_fn = None
+ self._jit_kwargs = kwargs
+ self._output_ref_tree = None
+
+ def setup(self, args, kwargs):
+ import pytensor
+ import pytensor.tensor as pt
+
+ flat_arrays, ref_tree = tree_flatten(
+ (args, kwargs),
+ is_leaf=is_array,
+ get_ref=True,
+ )
+ variables = [
+ pt.tensor(dtype=x.dtype, shape=x.shape) for x in flat_arrays
+ ]
+ pt_args, pt_kwargs = tree_unflatten(variables, ref_tree)
+ result = self._fn(*pt_args, **pt_kwargs)
+ outs, self._output_ref_tree = tree_flatten(
+ result, is_leaf=is_array, get_ref=True
+ )
+ self._jit_fn = pytensor.function(variables, outs, **self._jit_kwargs)
+
+ def __call__(self, *args, array_backend=None, **kwargs):
+ if self._jit_fn is None:
+ self.setup(args, kwargs)
+
+ flat_arrays = tree_flatten((args, kwargs))
+ flat_outs = self._jit_fn(*flat_arrays)
+ return tree_unflatten(flat_outs, self._output_ref_tree)
+
+
+_backend_lookup = {}
+
+_compiler_lookup = {
+ "jax": CompileJax,
+ "tensorflow": CompileTensorFlow,
+ "torch": CompileTorch,
+ "torch:trace": CompileTorch,
+ "torch:compile": CompileTorch2,
+ "pytensor": CompilePytensor,
+}
+
+
+class AutoCompiled:
+ """Just in time compile a ``autoray.do`` using function. See the main
+ wrapper ``autojit``.
+ """
+
+ def __init__(self, fn, backend=None, compiler_opts=None):
+ self._fn = fn
+ self._backend = backend
+ self._compiled_fns = {}
+ if compiler_opts is None:
+ self._compiler_kwargs = {}
+ else:
+ self._compiler_kwargs = compiler_opts
+
+ def __call__(self, *args, backend=None, **kwargs):
+ array_backend = infer_backend(
+ next(tree_iter((args, kwargs), is_array))
+ )
+
+ if backend is None:
+ if self._backend is None:
+ # no backend specified anywhere, use the array backend
+ backend = array_backend
+ else:
+ # use the backend specified at init
+ backend = self._backend
+
+ # work out which compiler to use for combo of backend and array backend
+ try:
+ key = _backend_lookup[backend, array_backend]
+ except KeyError:
+ if backend in _compiler_lookup:
+ key = backend
+ else:
+ key = f"python-{array_backend}"
+ _backend_lookup[backend, array_backend] = key
+
+ try:
+ fn_compiled = self._compiled_fns[key]
+ except KeyError:
+ if "python" in key:
+ backend = "python"
+ backend_compiler = _compiler_lookup.get(backend, CompilePython)
+ compiler_kwargs = self._compiler_kwargs.get(backend, {})
+ fn_compiled = backend_compiler(self._fn, **compiler_kwargs)
+ self._compiled_fns[key] = fn_compiled
+
+ return fn_compiled(*args, array_backend=array_backend, **kwargs)
+
+
+def autojit(fn=None, *, backend=None, compiler_opts=None):
+ """Just-in-time compile an ``autoray`` function, automatically choosing
+ the backend based on the input arrays, or via keyword argument.
+
+ The backend used to do the compilation can be set in three ways:
+
+ 1. Automatically based on the arrays the function is called with,
+ i.e. ``cfn(*torch_arrays)`` will use ``torch.jit.trace``.
+ 2. In this wrapper, ``@autojit(backend='jax')``, to provide a
+ specific default instead.
+ 3. When you call the function ``cfn(*arrays, backend='torch')`` to
+ override on a per-call basis.
+
+ If the arrays supplied are of a different backend type to the compiler,
+ then the returned array will also be converted back, i.e.
+ ``cfn(*numpy_arrays, backend='tensorflow')`` will return a ``numpy`` array.
+
+ The ``'python'`` backend simply extracts and unravels all the ``do`` calls
+ into a code object using ``compile`` which is then run with ``exec``.
+ This makes use of shared intermediates and constant folding, strips
+ away any python scaffoliding, and is compatible with any library, but the
+ resulting function is not 'low-level' in the same way as the other
+ backends.
+
+ Parameters
+ ----------
+ fn : callable
+ The autoray function to compile.
+ backend : str, optional
+ If set, use this as the default backend. The options are:
+
+ - ``'python'``: extract and unravel all the ``do`` calls into a
+ code object using ``compile`` which is then run with ``exec``.
+ - ``'jax'``: use `jax.jit` to compile the function.
+ - ``'tensorflow'``: use `tf.function` to compile the function.
+ - ``'torch'``: use `torch.jit.trace` to compile the function.
+ - ``'pytensor'``: use `pytensor.function` to compile the function.
+
+ If not set, the backend will be inferred from the input arrays, or it
+ can be set at call time with the ``backend`` keyword argument.
+ compiler_opts : dict[dict], optional
+ Dict of dicts when you can supply options for each compiler backend
+ separately, e.g.:
+ ``@autojit(compiler_opts={'tensorflow': {'jit_compile': True}})``.
+
+ Returns
+ -------
+ cfn : callable
+ The function with auto compilation.
+ """
+ kws = dict(backend=backend, compiler_opts=compiler_opts)
+ if fn is None:
+ return functools.partial(autojit, **kws)
+ return functools.wraps(fn)(AutoCompiled(fn, **kws))
diff --git a/venv/Lib/site-packages/autoray/experimental/__init__.py b/venv/Lib/site-packages/autoray/experimental/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/venv/Lib/site-packages/autoray/experimental/complexity_tracing.py b/venv/Lib/site-packages/autoray/experimental/complexity_tracing.py
new file mode 100644
index 0000000000000000000000000000000000000000..03e0bfbd5235e04e3eed1b9f0002a49e29dfdd06
--- /dev/null
+++ b/venv/Lib/site-packages/autoray/experimental/complexity_tracing.py
@@ -0,0 +1,292 @@
+"""
+Functionality for tracing through an autoray.lazy computation and estimating
+the cost and scaling.
+
+In the following there are ``cost_*`` functions that estimate the total cost
+of a given operation, including sub-leading factors. There are also
+`cost_scaling_*` functions that only consider the leading factor of the cost,
+so that we can prime number decompose it and extract the scaling.
+"""
+
+import math
+
+
+def cost_tensordot(x):
+ x1, x2, axes = x.args
+ shape1, shape2 = x1.shape, x2.shape
+ cost = math.prod(shape1) * math.prod(shape2)
+ for d in axes[0]:
+ cost //= shape1[d]
+ return cost
+
+
+cost_scaling_tensordot = cost_tensordot
+
+
+def cost_qr(x):
+ (A,) = x.deps
+ shape = A.shape
+ m = max(shape)
+ n = min(shape)
+ return 2 * m * n**2 - (2 / 3) * n**3
+
+
+def cost_svd(x):
+ (A,) = x.deps
+ shape = A.shape
+ m = max(shape)
+ n = min(shape)
+ return 4 * m * n**2 - (4 / 3) * n**3
+
+
+def cost_eigh(x):
+ (A,) = x.deps
+ m = A.shape[0]
+ return 8 / 3 * m**3
+
+
+def cost_scaling_linalg(x):
+ """Here we only care about the leading factor of the cost, which we need to
+ preserve so that we can prime number decompose it.
+ """
+ (A,) = x.deps
+ shape = A.shape
+ m = max(shape)
+ n = min(shape)
+ return m * n**2
+
+
+cost_scaling_qr = cost_scaling_svd = cost_scaling_linalg
+
+
+def cost_matmul(x):
+ A, B = x.deps
+ return A.shape[0] * A.shape[1] * B.shape[1]
+
+
+cost_scaling_matmul = cost_matmul
+
+
+def cost_einsum(x):
+ eq, *operands = x.args
+ lhs = eq.split("->")[0]
+ terms = lhs.split(",")
+ size_dict = {
+ ix: d
+ for term, x in zip(terms, operands)
+ for ix, d in zip(term, x.shape)
+ }
+ return math.prod(size_dict.values())
+
+
+cost_scaling_einsum = cost_einsum
+
+
+def cost_linear(x):
+ return math.prod(x.shape)
+
+
+def cost_nothing(x):
+ return 0
+
+
+COSTS = {
+ "qr": cost_qr,
+ "qr_stabilized": cost_qr,
+ "qr_stabilized_numba": cost_qr,
+ "svd": cost_svd,
+ "svd_truncated": cost_svd,
+ "svd_truncated_numba": cost_svd,
+ "svd_truncated_numpy": cost_svd,
+ "eigh": cost_eigh,
+ "linalg_eigh": cost_eigh,
+ "tensordot": cost_tensordot,
+ "matmul": cost_matmul,
+ "einsum": cost_einsum,
+ # other cheap ops
+ "mul": cost_linear,
+ "sum": cost_linear,
+ "add": cost_linear,
+ "neg": cost_linear,
+ "sqrt": cost_linear,
+ "cupy_sqrt": cost_linear,
+ "pow": cost_linear,
+ "truediv": cost_linear,
+ "log10": cost_linear,
+ "cupy_log10": cost_linear,
+ "norm": cost_linear,
+ "linalg_norm": cost_linear,
+ "reshape": cost_linear,
+ "conj": cost_linear,
+ "conjugate": cost_linear,
+ "cupy_conjugate": cost_linear,
+ "clip": cost_linear,
+ "transpose": cost_linear,
+ "absolute": cost_linear,
+ "trace": cost_linear,
+ "torch_transpose": cost_linear,
+ "clamp": cost_linear,
+ "getitem": cost_nothing,
+ "None": cost_nothing,
+}
+
+
+def cost_node(x, allow_missed=True):
+ f = x.fn_name
+ if f in COSTS:
+ return COSTS[f](x)
+ elif allow_missed:
+ return 0
+ else:
+ raise ValueError(f"Cost for {f} not implemented.")
+
+
+def compute_cost(z, print_missed=True):
+ C = 0
+ missed = {}
+ for node in z.descend():
+ f = node.fn_name
+ if f in COSTS:
+ C += COSTS[f](node)
+ else:
+ missed[f] = missed.get(f, 0) + 1
+
+ if missed and print_missed:
+ import warnings
+
+ warnings.warn(f"Missed {missed} in cost computation.")
+
+ return C
+
+
+COST_SCALINGS = {
+ "qr": cost_scaling_qr,
+ "qr_stabilized": cost_scaling_qr,
+ "qr_stabilized_numba": cost_scaling_qr,
+ "svd": cost_scaling_svd,
+ "svd_truncated": cost_scaling_svd,
+ "svd_truncated_numba": cost_scaling_svd,
+ "svd_truncated_numpy": cost_scaling_svd,
+ "eigh": cost_scaling_linalg,
+ "tensordot": cost_scaling_tensordot,
+ "matmul": cost_scaling_matmul,
+ "einsum": cost_scaling_einsum,
+ # other cheap ops
+ "mul": cost_linear,
+ "sum": cost_linear,
+ "add": cost_linear,
+ "neg": cost_linear,
+ "sqrt": cost_linear,
+ "pow": cost_linear,
+ "truediv": cost_linear,
+ "log10": cost_linear,
+ "norm": cost_linear,
+ "reshape": cost_linear,
+ "conj": cost_linear,
+ "conjugate": cost_linear,
+ "clip": cost_linear,
+ "transpose": cost_linear,
+ "absolute": cost_linear,
+ "trace": cost_linear,
+ "getitem": cost_nothing,
+ "None": cost_nothing,
+}
+
+
+def prime_factors(n) -> list[int]:
+ fs = []
+ if n <= 1:
+ return fs
+
+ while n % 2 == 0:
+ fs.append(2)
+ n = n // 2
+ for i in range(3, int(math.sqrt(n)) + 1, 2):
+ while n % i == 0:
+ fs.append(i)
+ n = n / i
+ if n > 2:
+ fs.append(n)
+ return fs
+
+
+def is_prime(n: int) -> bool:
+ for i in range(int(n**0.5), 1, -2 if int(n**0.5) % 2 == 0 else -1):
+ if n % i == 0:
+ return False
+ return False if n in (0, 1) else True
+
+
+def closest_prime(nt: int) -> int:
+ if is_prime(nt):
+ return nt
+ lower = None
+ higher = None
+ for i in range(nt if nt % 2 != 0 else nt - 1, 1, -2):
+ if is_prime(i):
+ lower = i
+ break
+ c = nt + 1
+ while higher is None:
+ if is_prime(c):
+ higher = c
+ else:
+ c += 2 if c % 2 != 0 else 1
+ return higher if lower is None or higher - nt < nt - lower else lower
+
+
+def frequencies(it):
+ c = {}
+ for i in it:
+ c[i] = c.get(i, 0) + 1
+ return c
+
+
+def compute_cost_scalings(z, factor_map, print_missed=True):
+ from autoray.lazy import descend
+
+ counts = {}
+ missed = {}
+
+ for node in descend(z):
+ f = node.fn_name
+
+ if f in COST_SCALINGS:
+ CS = COST_SCALINGS[f](node)
+ else:
+ missed[f] = missed.get(f, 0) + 1
+ continue
+
+ # group operations
+ key = (CS, f)
+ counts[key] = counts.get(key, 0) + 1
+
+ if missed and print_missed:
+ import warnings
+
+ warnings.warn(f"Missed {missed} in cost scaling computation.")
+
+ scalings = []
+
+ for key, freq in counts.items():
+ op = {
+ "cost": key[0],
+ "name": key[1],
+ "freq": freq,
+ }
+ pf = frequencies(prime_factors(op["cost"]))
+ for name, factor in factor_map.items():
+ op[name] = pf.pop(factor, 0)
+
+ if pf and print_missed:
+ import warnings
+
+ warnings.warn(
+ f"Missed prime factor(s) {pf} in cost scaling computation, "
+ f" for operation {op}."
+ )
+
+ scalings.append(op)
+
+ scalings.sort(key=lambda x: x["cost"], reverse=True)
+ return scalings
diff --git a/venv/Lib/site-packages/autoray/experimental/complexity_tracing_example.ipynb b/venv/Lib/site-packages/autoray/experimental/complexity_tracing_example.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..5a778d6c53f400d751bf4eca56af8e150b714252
--- /dev/null
+++ b/venv/Lib/site-packages/autoray/experimental/complexity_tracing_example.ipynb
@@ -0,0 +1,571 @@
+{
+ "cells": [
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "id": "51e28038-eae0-4753-809f-5c112dc04f6a",
+ "metadata": {},
+ "source": [
+ "This notebook shows various ways to introspect a `autoray.lazy` traced\n",
+ "computation, including scaling analysis. The basic steps for that are:\n",
+ "\n",
+ "1. Choose prime numbers for all possible dimension sizes\n",
+ "2. Trace the computation with `lazy.array`\n",
+ "3. Call `compute_cost_scalings`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "id": "a2c4234d-1595-4ca5-9e66-909a7b5d68ef",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%config InlineBackend.figure_formats = ['retina']\n",
+ "\n",
+ "import quimb as qu\n",
+ "import quimb.tensor as qtn\n",
+ "\n",
+ "from autoray import lazy\n",
+ "from autoray.experimental.complexity_tracing import (\n",
+ " closest_prime,\n",
+ " compute_cost,\n",
+ " compute_cost_scalings,\n",
+ " cost_node,\n",
+ " frequencies,\n",
+ " prime_factors,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "id": "07da8bee-e489-424e-9670-9a12140b0d8e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# all dimensions on intermediates must be different primes so that we can\n",
+ "# decompose the costs for scaling analysis!\n",
+ "p = 2\n",
+ "D = 3\n",
+ "chi = 5\n",
+ "\n",
+ "factor_map = {\n",
+ " \"p\": p,\n",
+ " \"D\": D,\n",
+ " \"chi\": chi,\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "id": "3b965ec2-8f7e-43b4-b1cb-f10d2b9f68c2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "psi = qtn.PEPS.from_fill_fn(\n",
+ " lambda shape: lazy.Variable(shape, backend=\"numpy\"),\n",
+ " # (could also call lazy.array on actual data)\n",
+ " 10,\n",
+ " 10,\n",
+ " D,\n",
+ " phys_dim=p,\n",
+ ")\n",
+ "norm = psi.make_norm()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "id": "cd00e632-18c9-43e8-b7c2-582c46ead60f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "Z = norm.contract_boundary(\n",
+ " max_bond=chi,\n",
+ " cutoff=0.0,\n",
+ " sequence=[\"xmin\"],\n",
+ " layer_tags=(\"KET\", \"BRA\"),\n",
+ " # layer_tags=None gives the single layer\n",
+ ")"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "id": "ff6b372d-f589-4834-937f-0b22d16a5e91",
+ "metadata": {},
+ "source": [
+ "# basic introspection"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "id": "48e76e91-0436-463a-b3e8-273b726a22b5",
+ "metadata": {},
+ "source": [
+ "$W$ is the maximum tensor size or 'width':"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "id": "c3719b85-5e5b-4603-a143-f944aa92e493",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "13122"
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "W = Z.history_max_size()\n",
+ "W"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "id": "38589ffc-ffab-421a-be1e-a19e331a814b",
+ "metadata": {},
+ "source": [
+ "becase its a single tensor we can analyse its scaling:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "id": "909dcfdc-e1db-4327-9cf3-e5acef78b6d4",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[2, 3, 3, 3, 3, 3, 3, 3, 3]"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "prime_factors(W)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "id": "e8e255cb-8858-49a6-8199-9deacc3061ba",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'p': 1, 'D': 8, 'chi': 0}"
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "max_size_scaling = {\n",
+ " name: frequencies(prime_factors(W)).get(size, 0)\n",
+ " for name, size in factor_map.items()\n",
+ "}\n",
+ "max_size_scaling"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "id": "772f811f-cc06-4cea-bf2b-3503e9f8c1c1",
+ "metadata": {},
+ "source": [
+ "$M$ is 'peak size': maximum concurrent size of all intermediates."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "id": "c4844e3c-2333-4909-9bb7-33ea70c35db6",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "27018"
+ ]
+ },
+ "execution_count": 23,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# this is a sum so we can't decompose it\n",
+ "M = Z.history_peak_size()\n",
+ "M"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "id": "0897b227-66bf-4d77-8074-64437cc5c49b",
+ "metadata": {},
+ "source": [
+ "Which is the peak of this graph:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "id": "c63f0c91-765c-4673-a97d-ee46869ee1c4",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAEBoAAASfCAYAAAC9jil9AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAFxGAABcRgEUlENBAAEAAElEQVR4nOz9ebgtyVnf+f5y7b1PTTolqTSiATQhYZCNMBIIgcQMEqZtxGBjGjy1B+x2227b2O52P3exnu57b7tvY7tlg81gM8hMFhgQIISZBwFGA5KQQAOSCqmEhFSqUtVRTWfvveL+kSvPyR0rhjdi5Rrz+6nnPHvvzPeNjDVURkZkZmTjnBMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiHybYrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANoeJBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBEmGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYESYaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgBFhogEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEaEiQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgRJhoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBEmGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIARYaIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGhIkGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYESYaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgRJhoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAEWGiAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARoSJBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBEmGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYESYaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgBFhogEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEaEiQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgRJhoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBEmGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIARYaIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGhIkGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYESYaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgRJhoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAEWGiAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARoSJBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBEmGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYESYaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgBFhogEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEaEiQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgRJhoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBEmGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIARYaIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGhIkGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYESYaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgRJhoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAEWGiAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARoSJBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBEmGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYESYaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgBFhogEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEaEiQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgRJhoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBEmGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIARYaIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGhIkGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYESYaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgRJhoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAEWGiAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARoSJBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBEmGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYESYaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgBFhogEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEaEiQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgRJhoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBEmGgAAAAAAAAAAAAA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AJgRgwYAAAAAAAAAAAAAAAAAAABgRgwaAAAAAAAAAAAAAAAAAAAAgBkxaAAAAAAAAAAAAAAAAAAAAABmxKABAAAAAAAAAAAAAAAAAAAAmBGDBgAAAAAAAAAAAAAAAAAAAGBGDBoAAAAAAAAAAAAAAAAAAACAGTFoAAAAAAAAAAAAAAAAAAAAAGbEoAEAAAAAAAAAAAAAAAAAAACYEYMGAAAAAAAAAAAAAAAAAAAAYEYMGgAAAAAAAAAAAAAAAAAAAIAZMWgAAAAAAAAAAAAAAAAAAAAAZsSgAQAAAAAAAAAAAAAAAAAAAJgRgwYAAAAAAAAAAAAAAAAAAABgRgwaAAAAAAAAAAAAAAAAAAAAgBkxaAAAAAAAAAAAAAAAAAAAAABmxKABAAAAAAAAAAAAAAAAAAAAmBGDBgAAAAAAAAAAAAAAAAAAAGBGDBoAAAAAAAAAAAAAAAAAAACAGTFoAAAAAAAAAAAAAAAAAAAAAGbEoAEAAAAAAAAAAAAAAAAAAACYEYMGAAAAAAAAAAAAAAAAAAAAYEYMGgAAAAAAAAAAAAAAAAAAAIAZMWgAAAAAAAAAAAAAAAAAAAAAZsSgAQAAAAAAAAAAAAAAAAAAAJgRgwYAAAAAAAAAAAAAAAAAAABgRgwaAAAAAAAAAAAAAAAAAAAAgBkxaAAAAAAAAAAAAAAAAAAAAABmxKABAAAAAAAAAAAAAAAAAAAAmBGDBgAAAAAAAAAAAAAAAAAAAGBGDBoAAAAAAAAAAAAAAAAAAACAGTFoAAAAAAAAAAAAAAAAAAAAAGbEoAEAAAAAAAAAAAAAAAAAAACYEYMGAAAAAAAAAAAAAAAAAAAAYEYMGgAAAAAAAAAAAAAAAAAAAIAZMWgAAAAAAAAAAAAAAAAAAAAAZsSgAQAAAAAAAAAAAAAAAAAAAJgRgwYAAAAAAAAAAAAAAAAAAABgRgwaAAAAAAAAAAAAAAAAAAAAgBkxaAAAAAAAAAAAAAAAAAAAAABmxKABAAAAAAAAAAAAAAAAAAAAmBGDBgAAAAAAAAAAAAAAAAAAAGBGDBoAAAAAAAAAAAAAAAAAAACAGTFoAAAAAAAAAAAAAAAAAAAAAGbEoAEAAAAAAAAAAAAAAAAAAACYEYMGAAAAAAAAAAAAAAAAAAAAYEYMGgAAAAAAAAAAAAAAAAAAAIAZMWgAAAAAAAAAAAAAAAAAAAAAZuT/B0kq75kqsa6cAAAAAElFTkSuQmCC",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "image/png": {
+ "height": 591,
+ "width": 2061
+ },
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "(, )"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "Z.plot_history_size_footprint(log=2)"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "id": "8a09839f-9f39-4639-9ca5-a7040d743597",
+ "metadata": {},
+ "source": [
+ "$C$ is the estimated total flops:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "id": "9ce54422-a6e3-4fdd-8bb5-b6d9592e5a56",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "56272536.0"
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# similarly for the total cost\n",
+ "C = compute_cost(Z)\n",
+ "C"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "id": "7910d8e2-d1be-4a33-960e-438d47f819db",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAGD0AAASfCAYAAACqzNCRAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAFxGAABcRgEUlENBAAEAAElEQVR4nOzdeZykV10v/k9V9TIzmUwy2VlCAoQEQiDhElAWA4mi7HqviMtPURQ3xAUXVFyOB1FQFFGB676CiutF4OIVlRBl34LsEBLW7Jlss/VWz++P6hkmmemq7pqq6p6Z9/v1qle/0ud7zvk+tTz1nKcz59tqmiYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABr1V7vBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgCOTogcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBQFD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGougBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwFEUPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAoSh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEXRAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCiKHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENR9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiKogcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBQFD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGougBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwFEUPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAoSh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEXRAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCiKHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENR9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiKogcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBQFD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGougBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwFEUPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAoSh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEXRAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCiKHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENR9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiKogcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBQFD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGougBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwFEUPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAoSh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEXRAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCiKHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENR9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiKogcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBQFD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGougBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwFEUPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAoSh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEXRAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCiKHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENR9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiKogcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBQFD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGougBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwFEUPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAoSh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEXRAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCiKHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENR9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiKogcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBQFD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGougBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwFEUPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAoSh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEXRAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCiKHgAAAAAAAAAAAAAAAAAAAAAA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pDXX6s3fTjdNFpLWQpq7PdGtLDZpLSTNrqS1c25+es/CwlR7evPiYrtp7lxa6HzpztbsjYut9mlbN+2511R78fjO3tb+12CuOzW1MDe1ebq1tKm9eWl/rgudTLVa7emZhaVWp9VtpflykfeFpfbCYtqZmu5202TxoD7zS02n1ez/n33baRbnu52l+aVOd2ZmKU3STZL5bqe92G7PzGxZyMzSYquzt90+sM/CfKdZWuykfdzS4oF9ut3W7KbZxVZ7arE5sM9it92dn5temmp1u+3NS90D+zTd1tSmTQudVmcpB/ZZWGovLMxPdzut7mJ789KXj3GNx7K/vZXFJrkzyd59v+ukmdv3WixOtT/XnW7tPrDP9Gl7rtr24B3vveicK3YEOGyffNFT7tfd3v3K7uzSOWla9+1uaU5Nq3XCQYHz2dTqto5Pu7spTTY1M830OM7tB8W1mm66TZN2Wk03TXup3Uq31bnL99Ta41ppJ023SXuxkzStg773miaLabq5e9zcVKcztzDV6kx1O+12Wq297SZpmrSymCZLaVoLudu5LkmaVubStPamnTv3Lk7tmluc6U5PL063l5o72p3ceEcze8PuqemprZt332Pz/OLpB373JMnC3NSmbtM6/sDvnvU+x+/rc/fvuH3fV7ObF9ozS4tpz7X3fyn2+77q9x23ON9ZWOx22od7LEnvu6fVbvZ2kz3ptvZ/L+97LRY67c8upXPzgX22Tu+99bj2/LsueNabrr77awus3Sdec8lJS830xWm1Lmy6OSsLnXul2zr+UGufNM3WVivHNd1mtrXUnj3o3J6Vz9mHE9daaJqmSZNW02rNdZrMZOpw45bXSGtem81NdTp7M9Vqt7vtzt602k2rlaSbJt0ki2llMWktHnLt07T2JNk9tzi96+Ljt6TVNK3p2aXFpt3csrQwdf3emfZiOs0pl7/6mcdPZ+ku3/9z3ampxaa1dWZqaf//8LgRzvErfcdthDXZoY5l/8vRzp60mp0Hfvd00syl3dzYLHSuXWy1bzhw7bN1eu+tm8+885ruWfOftPaBw+e+29F9320U96rcd+tx3w1Gy3039932z+G+m/tuMCHH2n23w12bjeq+296FmYVO08305sXFffd6ds+2F7rt1hmb9y6dOor7bqO6V3U033f7ylOmW01arSTpNJnbdw90qdW64d//8Ftv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AAAAAAAAAAAAAAAAAAAAAAAAAAAAjHL0fj8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADYTIYeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoxh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjGLoAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIqhBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwCiGHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKMYegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIxi6AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCKoQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAohh4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjGHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMYugBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwiqEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAKIYeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoxh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjGLoAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIqhBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwCiGHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKMYegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIxi6AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCKoQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAohh4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjGHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMYugBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwiqEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAKIYeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoxh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjGLoAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIqhBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwCiGHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKMYegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIxi6AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCKoQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAohh4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjGHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMYugBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwiqEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAKIYeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoxh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjGLoAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIqhBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwCiGHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKMYegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIxi6AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCKoQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAohh4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjGHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMYugBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwiqEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAKIYeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoxh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjGLoAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIqhBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwCiGHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKMYegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIxi6AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCKoQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAohh4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjGHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMYugBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwiqEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAKIYeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoxh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjGLoAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMIqhBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwCiGHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKMYegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIxi6AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCKoQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAohh4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjGHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMYugBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwiqEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAKIYeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoxh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjPJ/AOh00olBAo3oAAAAAElFTkSuQmCC",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "image/png": {
+ "height": 591,
+ "width": 3102
+ },
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "(, )"
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# history by size out\n",
+ "Z.plot_history_functions_scatter(log=2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "id": "22d24165-cc4b-415f-a758-437105b76a84",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/mnt/ntfs/Sync/dev/python/autoray/autoray/lazy/draw.py:852: RuntimeWarning: divide by zero encountered in log2\n",
+ " return np.log2(orig_fn(node)) / np.log2(log)\n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAGD0AAAS1CAYAAAAM+/bBAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAFxGAABcRgEUlENBAAEAAElEQVR4nOzdd5jsdXU/8Pct9A65erELCggo2DsCsWA3sUV/iBoLKqjRRE1sH49dsUYwojE2jBpbbMGoESTG3g2IFcUCcimKNIHL/f0xg0G8O9/Z2Sm7e1+v55nnPnfPmXPOzs7g97vC56zYsGFDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5mvlrAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACWJksPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAkVh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjMTSAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCSWHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOx9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiJpQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBILD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGYukBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwEksPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAkVh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjMTSAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCSWHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOx9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiJpQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBILD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGYukBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwEksPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAkVh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjMTSAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCSWHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOx9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiJpQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBILD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGYukBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwEksPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAkVh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjMTSAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCSWHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOx9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiJpQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBILD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGYukBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwEksPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAkVh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjMTSAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCSWHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOx9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiJpQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBILD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGYukBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwEksPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAkVh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjMTSAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCSWHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOx9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiJpQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBILD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGYukBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwEksPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAkVh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjMTSAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYCSWHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOx9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiJpQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBILD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGYukB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AAAAAAAAAAAAAAAAAAAAAAAAAAAAdDH0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6GLoAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0MXQAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoIuhBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQBdDDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgC6GHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF0MPQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALoYegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQx9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOhi6AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANDF0AMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKCLoQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAXQw8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAuhh4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABdDD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC6GHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0MfQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADoYugBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQxdADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgi6EHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAF0MPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACALoYeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXQw9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuhh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdDH0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6GLoAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0MXQAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoIuhBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQBdDDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgC6GHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF0MPQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALoYegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQx9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOhi6AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANDF0AMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKCLoQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAXQw8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAuhh4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABdDD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC6GHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0MfQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADoYugBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQxdADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgi6EHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAF0MPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACALoYeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXQw9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuhh6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdDH0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6GLoAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0MXQAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoMv/AG3VhDzMXfICAAAAAElFTkSuQmCC",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "image/png": {
+ "height": 602,
+ "width": 3102
+ },
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "(, )"
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# history by cost\n",
+ "Z.plot_history_functions_scatter(log=2, fn=cost_node)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "b33f3aae-b0dd-45fd-babb-91ad30a8c684",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAADc8AAAQUCAYAAAAVowCnAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAFxGAABcRgEUlENBAAEAAElEQVR4nOzdd5gsVbX38e8h5yAOjAgSDJgRDICBIEbMARQMiGkUMWB+vepimRMKKmhfE0ZEUDAgKgooQQyACIpIFpGGRjJIPu8fu88Fjmeqenq6umf6fD/P08/1ntqz95qpruqaoX61FixcuBBJkiRJkiRJkiRJkiRJkiRJkiRJksbJMqMuQJIkSZIkSZIkSZIkSZIkSZIkSZKkQTM8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2DE8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2DE8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2DE8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2DE8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2DE8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2DE8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2DE8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2DE8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2DE8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2DE8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2DE8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2DE8J0mSJEmSJEmSJEmSJEmSJEmSJEkaO4bnJEmSJEmSJEmSJEmSJEmSJEmSJEljx/CcJEmSJEmSJEmSJEmSJEmSJEmSJGnsGJ6TJEmSJEmSJEmSJEmSJEmSJEmSJI0dw3OSJEmSJEmSJEmSJEmSJEmSJEmSpLFjeE6SJEmSJEmSJEmSJEmSJEmSJEmSNHYMz0mSJEmSJEmSJEmSJEmSJEmSJEmSxo7hOUmSJEmSJEmSJEmSJEmSJEmSJEnS2Flu1AVI0lyRmRcCG02z+esR8YrhVTMYmXkcsN00m38dEdvPYu59gJhue0QsmMXc2wPHVgzZISKO63d+LX0yc2HV5ojYZ1i1SGpOk59NkiRJkiRJkiRJkiRJkiRJmn8Mz0mSJEmSJC0lMnN54D7AxsDawCrAQuA64BrgPODiiKh6+IAkDURmrgg8ANgAWJ1yTrqRck76J3B2RNwyugolSZIkSZIkSZIkSdJ8Z3hOkiRJkqSGZOZqwEOBh1C6HN8H2BC4N7AaJSSwCuX385spgYHLgUuBs4EzgZOAMyLijmHXv7QY5/2UmQuAxwDPB7YFtgBWrPmyGzLzZOBnwOERcV6zVfYuM9cFHsad+2szYB1gre5rJeAm4AagDVwC/BU4ndJ9+x9DL3opM87HU5XMXAt4IuV42wy4P3APSiBsZcr78nrgWuAfwPmUsOqpwO8j4prhVz0ambk18Fzg6ZT3ybIVw2/PzL8ARwFHRMTJzVcoSZIkSZIkSZIkSZLGieE5SZIkSZIGIDNXooQmHgdsBTyc0t1rQY9TLAqU3BN4MLDjXbb9OzOPAL4VEccNpuJqmbkPEMNYaxonRsTjBz3puO2n6XS/z1cCb6GEeGZiVcr3tSPwicw8CvhERPx6oEX2IDPXAXbo1vJESoeqOqt2X+tS9u/T7zLf2cDBwNcj4sJB1zsdj6dpzYvjaTrdoOCLgD2ArakOgS16X65HOSbv+r0uzMyzgF8BRwLHRcTNjRQ9Qpn5IuCdwJYz+LJlKe+rhwPvysxTKeejQxooUZIkSZIkSZIkSZIkjSHDc5IkSZIkzUJmbg58kRIGWKGhZdYBXgW8KjNPB/aJiCMaWmssLU37KTOfB3yaEmKarQXATsBOmXkosHdEXDKAeaeVmRsCOwO7UIJZvQaxerEZsA/wvsw8BMiI+PsA518qLE3H05J0Q3NvB95K6Sw3Wwso4cEHA2+kdH98xigCq03IzAdS3i/bDWC6LYHvZubrgddFxN8GMKckSZIkSZIkSZIkSRpjhuekeSwzDwJ2n2bzRRGx8fCqkSRJkpZaG1I6Dg3L5sDhmfkr4JUR8Y8hrj2fjf1+ysxVgM9TumA1YWdg+8x8UUQcO+jJM/ONwK6U/TTIwNySLAvsBrwwMz8GfDAibmt4zXEy9sfTdDJzV2A/SmfDpqwKrN3g/EOTmc8Hvg6sNuCptwP+kJkvj4jDBzy3JEmSJEmSJEmSJEkaI8uMugBJkiRJktSXHYE/Z+ZTRl2IKg1lP2XmPYHjaC44t8gEcHRmvrSBuT8JbEPzwbm7WgF4P3BcZq4/xHXVn5Gd9zJz9cz8JvAdmg3OjY3MfANwGIMPzi2yGvD9zNyzofklSZIkSZIkSZIkSdIYMDwnSZIkSdL8tSZwZGa+aNSFqFKj+ykz1wZ+DTy6ifmXYFngoDF73z0OODEz7zvqQlRr6Oe9zJwEfgM0ERodS5m5O/A5mg/DLgA+n5kvb3gdSZIkSZIkSZIkSZI0Ty036gIkSZIkSVpKXAucA5wNtLv//7XAfyjdc9agdPXaHHgYvXfqWQ74ZmZ2IuKYQRe9FJpX+ykzVwB+CDy4xy85ozv+l8AlwKWU8MkkcG/gScBzKN9blWWBr2fmuRFxSh+lD8IVwGnA+cDFwHXArcDawDrAQyihuF730cbArzJzq4i4bODVLp3m1fG0JJm5EXAssMkMvux8ynvzXMr79HpgRcp7c23gfsCWlONu7GTmo4Ev0Vtw7iRKN7+TgAspx/HqwKbAY4HdgK1r5lgAfCkzz4qIP/RZtiRJkiRJkiRJkiRJGlOG5yRJkiRJGrxbgVOB44ETgN9HxKW9fnFmLgNsB+wO7AKsXPMlywPfzsyHR0Snv5Jn7DUNz99ueH4Yj/30IeAJPYw7G3hzRPx8mu3ndl+/Bt6XmU8F9gc2q5hzReCwzNwiIq7uveS+/Qf4OXAU8MuIOL/uCzJzOWAH4J2UYGCdjYAfZOa2EXH7bIqdIY+nuXE8LV7TPYCf0Vtw7lzgy8DBEfGPHuefpHzPzwF2onTVm9cycw3gEMr+qXIO8PqI+NUStl0FnNJ9fS4znwx8AajqDLkCcEhmPiIirp155ZIkSZIkSZIkSZIkaVwZnpOkMRYR24+6hn5ExHH09oR6SZKkuaQD/AQ4ghLsubHfiSLiDkqno2Mzcx/gc8Aza75skhKkmup33ZmIiC8PY50GjM1+ysxtgLf1MPTrwGsi4tZe546In2fmwyhhoJdXDN0Y+AiwZ69z9+FESherH0TEdTP5woi4DTgaODoztwe+Daxf82WPpfxcPzHjSvvk8TT642lxmbk88CPggTVD/w28G/jaTAOXEdGmBM0O6a73dGAvegt6zlUfoD5s+EvghRFxTS8TRsTRmfko4PvAEyuGbgLsA7y1l3klSZIkSZIkSZIkSdLSYZlRFyBJkiRJ0jz3F2BbYDIiXhkRP5pNgGRxEXFhRDyLElCq86rM3GhQa4+ZcdxP+1L/t50vAnvMJDi3SPdrXgG0aoZOZeYjZzp/jduAbwBbRMTjI+LrMw3OLa77kI5HACf1MPy9mXnP2aw35sbxeFrcB4HH1Yz5DfCwiPjybDsVRsSt3Z/jU4AHA3+ezXyjkJkPBt5QM+y3wHN6Dc4t0u1u+Wzg9zVD35iZD5rJ3JIkSZIkSZIkSZIkabzZeU6SJEmSpFmIiAuAC4awzv9k5ppUBxOWBV4FvL/peuabcdtPmflUYJuaYb8F9oqIhf2uExELM/MNlNDZVtMMWwb4MPC0fte5i9uArwEf7e6zgYqITmY+i9LNrqqj2OrAm4H3DbqGcTBux9Piul0K31Ez7IfAiyLi5kGtu0hE/G3Qcw5JUP335ispP7O+gpYRcUNm7gL8CVhrmmHLUd4Lu/azhiRJkiRJkiRJkiRJGj92npMkSZIkaf54N3BJzZhnD6MQVRrGfnpjzfb/AK+YbTcsgO4cuwM3VQx7amZuOculDgceGhGvbSI4t0hEXAk8B6jrxrd7Zvq3s9Eb6nkvM5endGys2vcn0lBwbr7KzE2BF9QMe29EXDybdSLiIkpIr8rOmbnJbNaRJEmSJEmSJEmSJEnjwxuAJEmSJEmaJyLiemC/mmEP73Zq0og0vZ8ycx3qu7x9LSL+3s/8SxIRZwMH1Qx76yzX2LW7TuO6P5sDa4ZtCMw2EKhZGsF57w3AZhXbrwR2Njj3X95A6QI4nXOA/x3QWgcC51dsXxbYc0BrSZIkSZIkSZIkSZKkec7wnCRJkiRJ88vhNdsXUB380HA0uZ+eSXVIBeALfc5d5YCa7c/LzNUbWLcpn+phzPZNF6GeDOW8l5mrAu+rGfbmiLh0tmuNk26Hxl1rhn1mEJ0wASLiNmD/mmG72TlSkiRJkiRJkiRJkiQBLDfqAuazzFweuB+wKbAGsAJwPXANcC5wUUQsHF2Fakr35pv7AusAa1L2/6rAzcCN3df1wMXAvyLijhGVKkmSJGnMRMR5mXkFcM+KYesPqx4tWcP7abua7X+MiDP7nHtaEXFmZp4CPHKaIasAL6C+Q92cEBH/zMzTgc0rhj1sWPVoekM8770auEfF9lOAbw9gnXHzROBeFdtvAr414DW/DnwCWHGa7etTwq/HDHhdSZIkSZIkSZIkSZI0zxiem6HMXBt4GfBs4AmUwNx0bsjM44EfAYdExJVDKHGgMnM5YBtgR+DBlKd4rwusBqwM3AB0gPOAt0TEWSMqtVHdn8PTgJ2ALYCHU24K7MUtmXkx8Hfgd4teEXFVE7XONZn5AMrP64Hd1/2BtSmBw9UpNzndRAkctoF/An8FTgV+HRGXjKDsvmTmwyjvkUdQjpf1KN/n8sB1wOXAWcAfgaMi4tTRVKpxlpkrAo8CHke5CXhTYEPKeXtV4HbK8XYFcD7leDsROC4i/j2KmhfX7fbwpO7rYZSg+pqUz53rgWuBCyi1nwQcOR8/Y+eT7ufgdsCTKef0zSjn8tWB27gzMH4O8FvgZxHxt9FUu/TKzA0pnYgeQ/kc2pCyj1aiPNzhSuAvwMnAjwZx3ZaZCyjnmx258/Nvbcoxu5ByvF4InEG5cflHEXHdbNdtSmauAzyDcv37EGAT7nxIwn8oP8dzKN/P0cAxEXHDaKotur+fPIo7r7UeCExy57XWasCtlPqvpFxrnQ+cRrku/aMPepi3LqM6RLLqsApRpab206Nrtp/Y57y9OJHpw3MAz2GehOe6fkN1eG7TYRWiWo2e9zJzWeAtNcM+6IOyluhZNduPHPQ1YERck5k/o5xzpvMsDM9JkiRJkiRJkiRJkrTUMzzXo+5Nqe8HXkvvoalVKYGrpwGfzMwvUW6yudsN/pm5MSUEMJ09IuKgmdbcnfsVwNcqhmwSERcu4eseAOwFvJxy8/N01ui+7ksJCo1VeC4z7w28HdiNEhrsxwqUn899gad3/21hZp4IfA84LCIuraljY6rfI0uyUWbO5oauvt53mXkf4CnADt1X1ZPHF1m1+5qgBGUW/ZzodgH4BnDQXAzHZOZKwB7A3pRg4HTW7r42A54LfCgzzwIOAL4UEbc0VN9xTN+V4tcRsX0T685WZm4PHFsxZIeIOG6A8w1b3+f16WTmDsArKO+vNSqGLkcJra5Nec8+lfL+vS0zfwG0gB+P4obQzNyUcs59GSXssSRrdl8bAtsCrwNuz8wjgY9HxEnDqHW+ycx9gJhue0QsmObrJoE3A1OU98ySLEcJZ92TEjDfBfhMZp5K6QRx6KCDOU1eO/Ww9j708bPsce7jmOE5uxteezbl2Hl8xfTrdF/3p5wnPpaZJwAZEb/so9Y1gbcCrwQ2qBg60X09ujv2hsw8iHJNfNlM121KZj4eeBflGmTZaYat1n3dm9LF5I3AdZn5DWDfiJjptVpfMnNlSneXRddajwCWqfmyZSnH6dqUa9LtKNcvAJ3MPBz4QkT8qYGS1Zxra7bfOJQqVGfg+6l77n9AzbCTZzrvDJwMvKli+xMzc7mIuK3BGgapXbN9rWEUoZ40fd7bAdi4YvsFwI9nuca4elLN9iMbWvdIqsNzT25oXUmSJEmSJEmSJEmSNI8YnutBZj4H+ArlhuN+rUp5evWumfm6iDhiAKUNXPdG6A8Be1J/E+7Y6j5t/E1AUjp2DNoCyg3ujwf2y8zVI2Le3tyametRwhIvpnRq6Ts4sASbA/sCH8jMfYFPjLrDyyKZ+RTgS8B9+pziQcDngbdk5l4R8fOBFaelRmY+DfgA9d1H6ixH6Zy4E3BGZr5pJgHF2cjMFYB9KEGcFfuYYllKeOjZmfl94A1zKZQzH3U/B/emfA72+tCAxW0JfBd4U2a+MiLOHlR9KjLzgcCXKZ3f+vF44OjMPAR4bUTU3ZC+aN03AB9k+kBllVWBNwC7ZeZURBzaxxwD0w2IHgg8r88pVqd8P6/OzE8BH2giEJ+Zy1MeTrAr5Qbx6QLG/ZigPCDktZl5FPDOiDhzgPOrOXUP97hiKFWoThP7aZLykJYqf+lj3l79tWb7GsDWwAkN1jBInZrtKw+lCvWi6fPei2u2f8Nurf8tM+9F6T5cZcYPa+jR0TXbH5KZkxFRF5KVJEmSJEmSJEmSJEljbKkNR/UqMz8KHMHsgnN3tR7wg8x814DmG5jMfDjwZ0rHuaX2vZGZE8DxwKdpJji3uGWYxz/vzHwCcAnwWeCxDDY4d1erUro/np6Zj2lojZ5l5keAn9N/cO6u7gcclZmfyMx5+17QcGXmepl5GHAUsw/OLe5hwLGZ+cXM7CfM1rNuB7GTgP9Hf8G5xb0AODMztx7AXEul7ufgr4FP0n9w7q4eC/wuM+36MECZuQtwGv0H5+7qRcCJmblhzZprZ+aPKMHvfoJzd7U28L3MfPcs5+lbZj4WOJP+g3N3tSLwP5Sf48YDmG9xfwF+AryEwQbnFvd04NTMfGe3s5XmqG7Iua7D81C6IWp6De6niR7GXN3HvL26qocx8+larO5656ahVKFKTZ/3uvM/v2bYSEP/c1jd32gujoiLm1g4Ii4E/lUzbNC/L0uSJEmSJEmSJEmSpHnGkMY0MnNBZraAJm7oXQB8LDPf28DcfcnM7YETGUwQaN7KzHsAx1G6p6k3q1K6Pg3LfYHfZOYgbnSfse654auUoM8gLQDeAXy3211GmlY38HEqJSjWpCng190w1cBl5kMowblHDnjqewLHZOZTBzzv2MvM+wK/YzCBrLtaE/hRZm434HmXSpn5RkpXv5UGOO1DgV9m5lrTrDlBuUZ61gDXBPhoZu454Dlrdbt2/pLBPSBjkUdRAnQPGfC8awx4virLAx8HvtXUNUlmviIzF9a8tm9i7THyBKoDPxdExD+HVYym1dR+6iXc3kvArV+9zL1lg+sP2gY125v8Wap3TZ/3HkX1wwH+ERFNdnScz7ao2X5qw+ufUrO9rj5JkiRJkiRJkiRJkjTmDM9N74PAaxte4wPdriEj1e0490Oa7WIx53W7axwMPHjUtajWisChmfmMEaz9AWCPBuffGfiO3V40ncx8LnAssP6QltyKEkQbaICuG9I6lvruEf1amXKeeFhD84+dzFwfOBrYpKElVgIO666jPmXmi4D9aabT6wOAQxb/DOoG6o4FHt7AmgD7D7OrbPfa91DKeaIJ61O6d27a0PzDshvwjVEXoWntWrP9Z0OpQnWa2k+9BFub7Jb2nx7GDPrhCE2qC/qdN5QqVKfp8972NduPneX84+wRNdv/3PD6p9dsNzwnSZIkSZIkSZIkSdJSbrlRFzAXdQNt/9Pj8IuA71Buovkr8G/gdmAt4P6UJ2PvzJJvHFsAfAnYaXYVz8pqwBFUd7P4G6ULzXmUJ67fBqwObES5QWZrhtt5rCm7A0/pYdxNwG8oAYOzgHOAK4EbgZspP5s1u6+NKDeaP5xyQ979Bl71/HAL5Wd1JnAFcE33dSPlPbgmsB7lZ/QwYIUe5lwWODgzHxURf2+i6MVl5jOBqo6RN1LeG38GLqXcVLoaJYjySOAx9BZafiHwEQbf3U7zXDc49z16u2Ea4AbgZMrx9+/ua1lgXUpobTt6C0o9FPhhZm4fEbfMsOz/kplrAkcCvQbyrqF8zp4JdCjnlDUo59StmD7QszqlbgN0NTJzReAnVL8f/gr8Fricsh9up7yXNqJ8fq7bw1L3BFoMvnvZUqEb+vo60wfnrqZ0U/sHcBnlHDABbEjZR3WddeiOeynwze6aC4BvAVWd1E4Hft9d8zJKUHI9YHPKjeh156zlgIMy8+ERcVsPNfYtM1ej/qERp1Oufc8FrqNcl6xLORduT7luqTMBHJmZW0fENbOpeQYuptR+MXdea11DqX9Nyu8nD6Fck/Tace/FmXl6RHxs4NWqb5n5COBVFUMWAp8bTjV3ysx1KZ8j61OOsWUp18M3Uq6NL46Iy4Zd16g0vJ9u7mHMmpRrvyas1cOYTTNzuabP67OVmWsAj68ZduYwarkrj6e7G9J5r65D8ol1E3SvmzaiPJBgLUqnvJsp12SXABdFxBWzK3NOekDN9nMaXr8u4Hr/hteXJEmSJEmSJEmSJElznOG5xWTmBsAXexh6GfAu4FsRcfsStne6r5OAj2fmDpQuIYvfwL8G8Pn+K561T7LkG+Wvo9x49JWIOL9qgsxcB5gCrh18ecORmcsAUTPsP5Sf1/4RcWXFuKu7Lyghqh/fZZ37A8/uvp5A711jrgBes4R/3wN47DRf82/g3T3OvyS1N4ZVuAU4hhLMPAn4W0Tc2ssXZuYKwDMoN8Y9neqw2erAlzNzu4hYOIt6e7EG058bLgQ+BHwnIqbtwpCZk8DrgbcBq9as967MPCYiju6jVv23s1nyMdSERwKvG/Sk3RtGv019COU2SkelA4Df1x17mbkZsCel5qrg6jbAft2xs3UgsFkP4/4MfBj4QdWN15l5P+AtlM+ixa9tNgE+2l+ZS5VPseSODFcCHwO+FxEXTffF3RuFt+/OU9e95ZmZ+aSI+GWftS6tVqSE2FZcwrZfUPbT8TXHyuMp16N1++jjmfn9iLiR8kCJJXV6vYpybB0cEf+sWHNN4O3AO6k+xzwIeCXwvzW1zdbHgI2X8O+3Us5N+0fEBdN9cWYuDzyf8nOpC+Y+kHIufmlfldb7K+Va6xfA6RFxda9f2A0VvxJ4GfVBuszMH0XEX/usUwPUvZ48mOqHl/wgIs4aUj1TwJMp1wm1nUUz82rgNMrvCD8FTo6IO5qscRSGsJ9u6GHMWjQXnlu7hzHLAfcBKv+eMAe8gPqHt/x6GIV4PC3ZEM97m9ds/9OS/jEzV6Y8NOs5wJOofjgVmXkJ5YEUPwV+WPP3pfli45rt5za8ft38TXXWliRJkiRJkiRJkiRJ84Thuf/2WepvBDsReMFMnvIdEcdm5qOBL1ACT3f1iBlVOFhPW8K//Rh4Ta/fX0T8m9Ilaz57EtU3+/wLeGZEnDabRSLiHGBfYN/MfCCwN+Wm5bqvux748uL/3r0Jfrrw3PUR8V9f07DjKTee/zQi+gpTdrtaHQ4c3j1mvsz0XaWghBBfBHy3n/Vm4LksOex4APD2iLipboKIaAORmV+i3PxX1eFgAfC1zHxgd/9rFiLiUpZwDA1aZm4EfLBm2PXAH2Y47xqUgMQqNUOPBPaKiAt7nTsizgbenJn7AQcB21YMf31mHhoRx/Y6/+Iy8/nAbjXD7qAEmj86TUD9biLiXGCvzGxRgoOLB/Pe0E+tS5m9lvBvnwWil0BON8C86Frno5SgVJV3UTqkqXdbL+Hf2pRrtp/0MkFEnJCZj6F8dk1VDL0XsFtmngC8bwnbvwq8s3sNWLfmNcD7MvMHlGD9WhXD356ZX2o4EL+kAPCZwC693HTfDSQfkpnfB95DOVdVBf1f0g0iHt5Xtf+tTdl/h3SvK/sSEWcAe2fmPsAnKAHz6R7qsALwaZb8e4OGqBt6PIzqDj9XMNzPvV4ePHNXawE7dF//A/wrM78CtCLikgHXNhJD2k+9/K6+LvXdmPrVa/fgTZn74bk312z/F3DKMArB4+m/DOu8l5lrUR1YXMhiHQgzcxXKAwLeSOmu3Kt7U7rNvxC4JTMPBj4ZEX+ZSc1zRTfcuHLNsKbfj3Xzr5KZ60bE5Q3XIUmSJEmSJEmSJEmS5qiqGz2XOpm5LfC8mmEnAE+dSXBukYi4OSJeSQnQzVX7As/p5/ub53aq2HYH8OLZBucWFxF/i4gpYENKV7v56nbgB8DWEbFtRHy33+Dc4iLiD8CjKGGYKu/rdj1q0pLm3zsi9uolOHdX3Q49T6SEBKvcG/h/M5lbo9O94fKnwGTFsNspAY2Z3hj5KWCjiu23Ae8AnjWT4NxddTstPZnS3a7KgZlZ1fVhWpm5IuV7qXIb8KKI+FAvwbm76oZBtgJ+v9gmr3dm5nbgdRHx5pl0sgKIiDsi4l3AZ2qGPikz79tvgQJK19PH9xqcW6R7XO1J+eyu8gbKTfyLd+N5f0S8qpfg3GLrnkbpYDdtZzzg/pQAQJMW/zw/Adhmpt1qIuK2iPgAJQxcd67at3v+m42/Aq8GNu6eH/sOzt1VRFzTvR7dhep989Ru8FIjkJkbZ+a+wKlUB0huBnabZ7/LrU8J6Z6bmZ/sXk/NS8PcTxFxBfW/Qz6q3/l70Ovctd3TRikzX0R9t7HvzKNubh5P/XtwzfZL79plPjOfCpwFJDMLzi1uBWB34PTMPKD70JT5ppfjvOnPpXYPY+b0+UiSJEmSJEmSJEmSJDXLznN39/6a7f8Enh8RN8xynTdSuuI8cZbzDNrXIuLtoy5iRKpuBv5FRBzf1MIzvfl8romIo4GjG5z/1szcjdJx6xnTDHswpYtbY/tpCT4aEfv1+8Xd7+vFwLFM3z0Q4K2Zub9PSJ/bMnMFShCl7qbLPSPiqBnO/RhKR6Aqr4uIr8xk3iWJiFsy82XAOkzfYeiBwK7At/pYYgrYpGbMGyLisD7mBkoQJDOfTunut2m/8yzlXhURX5/lHO+mnLOrbnZ+IfDxWa6ztOoAT+iGsWcsIu7IzDdSjvPpOlo+Ygn/lhFR112zat2TMvN/WXL3t0VeSOlQNwxnA8+YTYfXiDgkM+8JfL5i2CbAa4HPzWKdRn9viIjDMnN54DsVw6b473CyBigzVwbWoHSTejDlOHwi8Dim7wy4yE2U31Ubuy5v2EqUDk67ZuarI+Jnoy5oOnNoP50FbFmxfWtmcd6psaRuqEuyTkPrz1q3a9jHaobdRvX5fa7yeJq5DWu2X7Dof2TmeymhuUE+oGNZyvXRUzNz50E/vKlhdcf5tRFxc5MFRMR/MvN6YLWKYXP2fCRJkiRJkiRJkiRJkppneK4rMzcHdqwZ9taI6Mx2rYi4PTOngL/w3908RuVi4M2jLmKEqgIWPxxaFVqiiLgtM19Ducl99WmGvYzhhedOBd4720m6QaUXU76vlacZthKl+0/Mdj016ivUd0v6WET8bx9zf6hu+yCCc4tExMJugO40YINphr2dGYbnut3q3lIz7Ig+f0Z3ExFXZuZLgJOov+lWd/fNAQTnFp3f3gkcUTHsqRie69dr+w3OLRIR/8rMAynHcy9OBvoOzt3FPpRA8PLTbJ8uuDtod1A61cy6W25EHJCZTwOeWTFs78w8YC53L4qIgzPzBcALphmyc2a+YaYdd3WnzPwW8JIGpj4DeEm3A+t8d2/gp5n5voj48CgKmEf76RSqw3M7ZOZyEVHVVXLGMnM5YPseh8/lsMrHgI1rxnwjIi4aQi1N8Xjq3b1qtl8C0O2G99YBrbkk9wWOz8znRsQvG1xnkO5Rs33W11o9upbq8FxdnZIkSZIkSZIkSZIkaYwN8inJ890ra7afEBGHDmqxiDgX2H9Q8w3AnhFx3aiLGKG1Krb9Y1hFaHoRcSnwqYohw7rZHuAtg7r5PSIuBj5RM2yqGzzSHJSZHwReWjPsu8B7+pj7kcCTK4acRel6MFARcQXV3Vg3z8yqm7WXZCequ87dQu8hnloRcTLVHZT03y6jhHUH5UhKh7TpbNW9AV8z872IOGJAcx3S47g7gFdExO2zXbD7IIpfVQzZJDPrbmAfhK9FxKkDnO9twK0V2zehnAfnurcDC6fZtjrV3XI1fJdS3nuPHpPg3CILgA91A77joKn9dFzN9nsBzxngeos8l/qg0SJzMqySmTsCe9UMuw74nyGU0zSPp97UvaevyMz30GxwbpFVgZ9k5rZDWGsQ1q7ZPszwXJU5eT6SJEmSJEmSJEmSJEnDYXgOyMxlgJ1rhs049NCDDwE3NDDvTJ0WET8ZdREjVtWZyBv7546qAOuGmXm/IdTw/YgYdIe7TwD/qti+HvDEAa+pAcjMV1LfhfB4SuhkujBCldfWbH/boLuJ3MW3gKrOVrvMcL5da7Z/LiLOm+Gcdd4F/GfAc46zLwwySN99bx5WMWQV4P6DWm8pUhUkn5GI+COl+3Cdn0TE2YNaF/hBzfZHDHCtJbmBAQciIuLvwAE1w+rOgyMXERcCf6gY4vXI6P2H0hn75cAmEfHpiLh5BHVcBxxFuY59OfBoSseke1K6q69J6e79KMp7/4vAX2e4xuszs+4hE3PVMPbTUUDddWBdQKwfM5lzpQbWn5VuQPs71Hcnfn9EtIdQEng81RnG8bRmzfbNqe/A+2fK3/m2p1zjrkYJnt+/+28f6o7pxYrADzJz0x7Hj1LdcX7jUKqo//vqnDsfSZIkSZIkSZIkSZKk4TEUVDyS6qdMX9hAWIaIuDYzfwjsNui5Z+hrI15/LrgSmJxm2yOAHw2vFE0nIs7KzIuAjaYZsgVwbsNlfGHQE0bEjZn5DeDdFcNeCBw96LXVv8x8MtCqGXY28Nx+bu7MzBWAF1cMOSMijprpvL2KiFsz8+tMHzB5KtXv2f+TmcsDz6oZ9sUZlNeTiLgkM38EvGjQc4+hm2ng/AacDLy+YvsDKR0U1ZvfRURVsKkfpwEb1oz5/IDXrOv4thklRNCUwyPisgbm/QLwlortz87M5SOiqkPdXHAU8Jhptm0xiAUi4iDgoEHMtRS6DLgQuJzSFXKYLgK+T+ksenzNe/lWShegC4BTKF14ycyHAe+kXOP08veId2TmKRHRa6fMuaLx/RQRV2XmT4FnVwzbPjNfFhHfHMSamflyYLsZfMkKg1h3ULrXpIcA69YM/Q3w2YbL8Xjq3TDOeyvXbH9cxba/AW+OiF9Ms/3c7uvXwPsy86nAfpTr4CrrAN/IzG1jQJ3vG1J3nDf1sJeZrjOnzkeSJEmSJEmSJEmSJGm47DxXbF+z/bsNrv2dBufuxW3At0dcw1xwecW2V2bmKkOrRHUuqtj20IbXbgPHNTR33XFop5c5pHuj6mFU36R6ObBTRFzZ5zJPANao2D6Mm16Pq9i2eWbWdWhYZCtK54Xp/CEimgq+jvpzdr44ISKqPgv7VdddY4MG1hxnhzcwZ1148XrgmAbWrOrGeZ8Br7e4g5uYtNt9rioYuBrTh9LmklFea6nexsCbgZ8B52fm2zJz9QbXu6O71rOBTSPibRFxTL8h0Ig4IyJeRgmN9BoG/lJm3ruf9UZoY4azn3oJvn82M+tC0rW6c+w/wy+ba2GVAynX2FWupXSNbiKs5PHUn41p/njqtyvZ14CHVwTn/ktE/Bx4OL2FyB8HvK6/0obG8JwkSZIkSZIkSZIkSZrzDM8VVU+QhmZuVF7k58ANDc5f5y+zCHaMk99XbNsI+Gpm2qlxbmhXbNu44bUPjYjbm5g4Is4EzqwYcr/MXL+JtTUz3ZtNf0p1sO0/wLMi4vxZLPW0mu3fn8XcvToJmO49vwDYvMd56jqUNBlSPwq4qsH5x8WJDc17ds32us4vurvfNjDneTXbfz/oz76IuBG4tGLIxCDXW8yVQM83uPehLrA7k45No1J1rbVBZi47tEpUZwPgU8C5mVnVfWw2PhIRT4+IHw8yTBQR5wGPp7fuXqsDnx7U2iPQ2H6KiJ9RurxWWQs4NjOn695dKzM3Bo7tzjUTc+Z8kZlvBV7dw9A9IuKChsrweJq9po6n5fv4mgOAV/UTfux+zSu7c9R5f2auOtM1hqjub8uN/A2lj3XmzPlIkiRJkiRJkiRJkiQNn2GgoqqDwu3Ud03pW0TclplnAFs3tUaNU0a07lzzK6pvpHsRJby0d0QcP6SaxlJmrkHpKHNPYB1gxe6r1xuZqroU3Wt21dU6oeH5T6T6fLQ58K+Ga1CFboeDI6l+H94B7BYRVaHcXmxVse166kNJsxYRN2bmFcB60wx5KPCbHqZ6RM32xo6tiLg1M/8APKWpNcZEE6EsIuI/mXkr09+Q3Gv3QpVr0j82MO91NdvrQhlNrNvk++J3EdFkB5S6IGqvoeO+dR/4sBElnHpPYFVKt5XlKcHnOptVbFuG8png9Uh/vsz0XV2Xobz31wLuQelKtAWwcg/zrgv8MDO/BLx+kIHXJo+XiLgFeHNmXgVEzfBdMvMjEXF6U/XcxXzbT28Hjqf6+L4vcHxmviwifj2TyTNze+Cb9Nct9uY+vmbgMnMX4JM9DN03In7QVB0eT/9lLh1PM/36E4E3RURVJ91KEbEwM99E+Z4fWzF0PeDl9NZpchTq3tfD+ttz3Tp9dXiUJEmSJEmSJEmSJEnjYakPz2XmSsAmFUPOjoibGi7jdEYXnjt1ROvONT8GOlR3Onkk8JvMPA34KnBERPxzGMXNV5m5PKXDyg6UINDDaLbL0DoNzg0NBml7nP+hlC5aGoFuGOF71Acf3hoRR8xyrbqubmfN5kbNGfo304fner2J+iEV2+6guuviIJyO4bk6/2hw7usoN0QvyYoNrjtu/t3t2DZo19dsb+pap2rdJt8XTX+WnwEsZPoQS1VIvi+ZuRmlW+k2lOvVjWn297x1MDzXl4g4julDJP+le+3xSOBVwK7AajVf8hpgzcx8ScMh0YGKiH0y80HALjVD3w68bAj1HMc82k8RcWJm7gfsXTN0Q+C4zPweJUh2ynTXk91r0UcC76B6v9xG9fmm6b+l1MrMJ1PCf3XdsQ4H3tl8Rc3yeOrbLTMYeyPwikF0D4yIOzLzFcCfgFUqhr6euRueq/vZDetvz3XdA2eyjyVJkiRJkiRJkiRJ0phZ6sNzwPpU30TV9A22UG7qH5Umb5afNyLihszcF/hYD8O3AD4HfLYbpDuGcjPYCRFxTXNVzh+ZuTmwJ/BiYI0hLt3LE+r79R/gnAbnh/pzwX0bXl/VDqSEE6rsFxH7D2Ct9ak5djKzqlvmIFWFWO7d4xybVmw7t6FA0F2N8nN2vriqwbmvZ/rw3AoNrjtumtpHN8zBdZt8XzR6PuheU54H3G+aIVXnw55l5trAHpTOyQ8axJwz0OT1lu6iGwT5HfC7zHw78CFgL6o7jO1COb5e2XyFA/U64ImUbonTeUFmvi4i6s5bQzVH9tO7gUcBT+hh7C7d1yWZ+SvgEuCy7rb1KNd3O1J/nXcu8Htgt4oxIw3PZebWlFBc3efKMcCugwhDzREeTzM3k2DVVyPi3FmsdTcRcU5mHkT5G8p0HpaZ94+Ipv8m0Y+6jm7Dut43PCdJkiRJkiRJkiRJkqZleA7uVbN9GF0VRtm5wbDXnT4DPAt4XI/jFwBbdl9vB+7IzL8CJwEnAsdHxAVNFDpXZeamlC4Gzx9RCU12qjkvIm5vcH6Av9dsn2x4fU0jM99D6WpQ5XDgbQNacsOa7Y/uvkatNhybmfeg+tise98PwjDWmO+ubHDuqi6JVTdC6+6aCrHVdbEcxbpNvi+Gdc6ZLjy3UmauFRFX9zNxt6vv24F3AWv2V96s2TFyBCLiWuBNmXkYcBjVHbP3yMyfRsRhw6lu9iLiqsz8MOV3sumsDOwEHDqcqmZuVPspIm7JzOcBx1K6fffi3sDL+1zyauAFwP/UjPt3n/PPWveBLj8FVq0Z+nvgORFxc/NVDYfHU19mEiJsogPcgVSH5wCeAezXwNqzVdfFePWhVFH/u2ldnZIkSZIkSZIkSZIkaYxVdVxbWqxTs/3aIdQwjDXm4tpzSkTcAryQ/ruLLQM8FHgt8HXg/Mw8NzM/l5nbZ+ZYH2+Z+UpKp8ZRBecAlm1w7mEETa+u2b7eEGrQYjJzN0rHgyq/A14ywG4V6w9onqb10n2o7n07jGPLoHiNcbphfIyNah+N23tjLpxz+vo8z8zNgD8AH2F0wTlo9npLNSLiN8CTqQ+2tjJzlO+TfnyZ+gDLDsMoZLZGsZ8i4t/AdsBvBzFfhWuAp0bEn6nubAbQbriWJcrMBwC/ANauGXoG8PSIGMdQjcfTzPT6IIk/RMRf+1xjWhHxF8pnfJVtBr3ugNT97IYVnqtbp8mHhUiSJEmSJEmSJEmSpDlurMM8PVqpZrvhuaVIRLSBxwBHDWjK+wJ7UToAXJRF1dPS56XuU+2/Qv1T/eez65peICJupTqkMM4/3zkpM7cFvkZ1F6TzgWdFxH8GuPSwbjCcrV66D61Ss73xYws/6yTdaS6cc2b8eZ6ZW1O6G2/eV0UaKxFxOuWhH1XuQXmox7zRDTD9tGbYXA2P/JdR7KeIuArYHtif+s6i/TgL2Coift/9/zeqGX9pAzVUysyNgV8B69YMPQd4ckSMZaDG42nGeu2SeGKf8/fipJrtj2xw7dmo+9mtNYwiqH+wwMg6YUqSJEmSJEmSJEmSpNEzPFd/4/9cuMG2SYPqkjQ2IuJq4BnAy4CLBjj1BsD7KSG6j2bmfAnHVMrMdwDvGXUdQzCs47RqnbqwrwYoMx8IHAGsUDHsSkq3is6Al++lo9tcUBUqXGRpD6lLmlvmwjlnRp/n3Y5zR1JCARIAEXEM8L2aYW/KzPnWKfDYmu2bDaWKARnFfoqIWyLiLcDjgN/XDO/VrcAngEdHxNkA3c7qG9Z83SB/n66VmetTgnMb1Ay9CNgxIi5rvqqR8njq3RU9jju5j7l79bua7RvP0XN63c9uxcxcq8kCMnMdqn9vB8NzkiRJkiRJkiRJkiQt1ZYbdQFzQF14bPkh1DCMNTQDEbEQ+FZmHgq8BHgl5ebDQVgZeDewa2buFhF1TxefszJzG+CjM/iSiyg3cJ4OnAdcAlxOucn8OuAW4Nbuz3+6NQ8Cdu+z5Nm4dQ6sMxdvlBtLmbkupVPD2hXDbgaeExF/b6CEcfpcqAvqD+PYGtbxK2numwvnnJ4/zzNzeeAQeg/O3UC5sf80SlelC4HLKDeM3wDcCNweEbdVrLk99YELzQ3vBXap2L4BsCXwh+GUMxCn1WxfOTPXm2ehp5Hsp4j4LbBVZj4R2BPYiZk/oOF64CDgMxFx/mLb7kN1WGUhpVPdUHSv338FbFoz9FJKcO7i5qsaOY+n3v2jx3F/neG8M1E397LAvYB/NlhDP3r52a0HXN1gDev1MKbXfSxJkiRJkiRJkiRJksaQ4bkSfqiyxhBqGMYa6kNE3Ax8FfhqZt4PeA7wRGBbYLVZTr8RcGxmPj8ijpzlXEOXmQuAL1J/A/hVwIHAtyLibwNYupdOV00YVqfAqvPBTUOqYamWmasAPwY2qRi2ENg9Ik5oqIy6z6b5pO57Gcax5eespEVWp1ybNKnunDOTz/M3AZvXjFlI6ZT6v8AxEXHLDOZfklFda2mGIuKczPwr8OCKYdsxv8JzF/YwZl1KKHReGPV+6nbrOiYzVwW2B7YBHg5sTAnirEYJwd1IOT+eA/wZ+CXwq4iY7pxVd266ICJunG39vcjMewBHAw+sGdqhBOfOa76qOeHCHsZ4PBUX9Dju6hnOOxO9XJ/cgzkWnouI6zPzCuCeFcM2As5usIyNarZfHhE3NLi+JEmSJEmSJEmSJEma4wzPlQ4MVbypXwBExLnAvsC+mbkc8EjgCZSOdI+l3HQ2UysA383Mx0fE6QMrdjieR7npssovgN0i4t8DXHfNAc41E40fp5m5DLBqxRDDcw3r7oPvAI+pGfruiDikwVLqbjTeOyL2a3D9Qap73xpSlzRMazBPwnOZuSLwrpphHeDF3XDMoIzqWkv9OZLqEMmjh1XIgFzTw5hVGq9i8Ea+n7rBkSO7r0GoC88N5ffbzFwT+Dn1v5teBTwlIobWDW8O8Hjq3SWUz+eVasZd3cfcvepl7rm6vy6gOjx3f8rfh5py/5rtvYYjJUmSJEmSJEmSJEnSmDI8V/+E7WHcPOpN/fNMRNwG/K77+hRAZm4G7AA8FXgSvXemWw34dmY+PCLuaKDcpryqZvsPgJ0b+J7WHvB8vRrGcbo61d1eBhlC1JJ9htJhssoXI+ITDddRt6+ruuLNNVfWbDc8p/lmxVEXoFmZC+ecXj/Pnw1MVGy/GtgqIgZ9Q/iorrXUn7r9388DPkapl86JyzdexeCN236C8iCZKr9uuoDMXA34KfComqHXAU+LiD81XdMc4/HUo4hYmJlnAVvUDP3PTOeegV7mnqt/x/0L1aHFzRpe/wE12//S8PqSJEmSJEmSJEmSJGmOm6s3XQzTpTXb655ePAh1N3loHoiIs4GzgS9m5krA0ykBs52oDkQBPAR4MaXj1ZyXmasAT64Y0gZe21AY8B4NzNmL9Yewxr1qtreHUMNSKzP3Bt5UM+xIYK8hlPOPmu2bDqGGQWkDC5n+PDgXji3NPwtrttd97s7GOg3OreatD5zR8BpV55w7gMt7nKcuzP2GBoJzMLprLfWn7mEw8+2ctXIPY5oMrzRlrPZTZi5P6b5e5biGa1gZ+HEPddwIPCMift9kPXOUx9PMnEJ9eG5NmnuoTS8P75qr++s04BUV2+t+rrO1Zc320xpeX5IkSZIkSZIkSZIkzXGG58pN/TcAq06zffMh1DCMNTREEXETcDhweGY+FDiQ+ifz78k8Cc8BW1H9hPqvRMTAbyjLzGWBjQY9b48mM3MiIjoNrlF3Lri4wbWXapn5fLpdJCucCrwoIm4fQkkXUR04G0aweyAi4rbMbDN9mOShmbkgIurCULPh5+z4ua1m+yoNrm2waH57OPDzpibPzGWAh1YMaXc7GPei6trxn8DBPRc2M/MpoC24tmZ7L+GZuWSyhzHXN17F4I3bfnoi1Z+1beDPTS2emStSft/evmbozcBzIuL4pmqZ4zyeZuYU4NU1Y9aiufBcL51f5+r+OrVm+yMyc9kmfpfOzOWo/33P8JwGot3qLE85x6wMrHSX/z3T10qUh2rcPM3rloptdeNvmpyauLGxH4IkSZIkSZIkSZIkzVNLfXguIhZm5lnAo6YZMpmZ60ZErx0i+uFN/WMsIs7MzB2BHwDPrBi6VWauHhHXDam02XhQzfZDG1r3YcDqDc3di82BXzY8f5W/Nrj2Uisztwa+BSxTMewfwDMj4oZh1BQR12fmOUzfmXSzzNwwIuZLoPKvTB+eWw24L3Bug+v7OTt+bq7Z3uRnxQYNzq3mNX0+uB/TP5QDevwsz8xVgftUDDmswdDx4xqaV82oer9BeVDMfHLfHsZc0ngVgzdu++kFNdsPbeoc1e169z3gqTVDbwVeEBFN/v4213k8zcwJPYxZFzivz/l7mbvOvxpae7b+CNxECQQtyWrAI4EmOkA+huow702UYKR0N+1WZxXK3ykWvSaX8P+vzd1Db8uOpNgZarc6N1GCvldM8+rc5X9fBlw+OTVxx2iqlSRJkiRJkiRJkqThWOrDc11/YvrwHJQbSA9vYuHMXJd51EFI/YmIWzPzFcDfmb5jzXLANsAvhlXXLNR1fzuroXVHfTP3FjQbntuiZvsZDa69VMrM+wI/oro7wTXAThFx6XCq+j+/Y/rwHJQw7heGVMtsnQnsWLF9C5oNz23Z4NwajbqOI2s1sWhmrkT9uVpzW9P7b1Cf5VXBOWgoUJ+Zq1MeVqD5Y8Oa7VcNpYrB2apm+xURMVc7L1UZm/3UDffuUjPsuw2tvSzwbeDZNUNvB3aNiCObqGMe8Xiage6Djy4B7l0x7NHAb/uZvwdVf5cEuHKuPmwpIm7KzBOAJ1UMezLNhOeq1gQ4PiJuamBdzVHtVuce3D0Et6Rg3L0Y7cO5mrYS5VxWdT67q9vbrc5lwKXd178W+7+L/vdlk1MTA+8gKUmSJEmSJEmSJEnDYHiu+DXw6ortL6ah8BzwIqq7HWlMRMS/M/O7wJ4Vw6brzDSdqhsWlp/hXDOxRsW2KyPilobWrercNwzPAz7ZxMSZuRawQ8WQa4G/NLH20ioz1wF+CkxUDLsVeH5EjOJn/0vgZRXbn8P8Cc+dBLy5YvvzaKhjZWY+CNisibk1OhFxS2ZezfQhuab2+aOBFRqaW8Px4Mx8QET8vaH5n1+z/aQe56m61gJo9zjPTO2Ev5vMN3XdFM8fShWDU3e9/+ehVDF447SfXgasWbH9LBoIF2XmAuCrwM41Q+8AXh4R3x90DfOQx9PM/Rx4ZcX2rYHPzmL+KlvXbD+9oXUH5Wiqg2zPBz7cwLovrNk+Hx5QpRlotzprAg+6y+t+wPrcGZLz97WZW5byM1y/Ztxt7VbnfODsxV+TUxOXN1uiJEmSJEmSJEmSJM2ON0YWxwALK7Y/KzNXa2jt3RqaV3PTiTXb7znD+apCalWdtGar6kaURp5AnJkPAJ7axNwzsE1mbtzQ3C8AVqzYfnxE+HTnAcnMFYEjqO7sBvDqiDim+YqW6MfAbRXbn5KZdTeOzhXH1Wx/dmau0tDaL2loXo3ePyq2PbyhNZ/X0Lwarl2bmLT7+0JVUGEh5aEdvai76bepa4KqoLPmmG6Y6Mk1w5rqCD1w3cD7o2uG9RpAnTPGaT91r6HfXTNs34io+vtKv74AvLxmzELgNRHxnQbWn1c8nvr2vZrtO2TmwB9ElpnLA9vXDPvdoNcdsMNqtm+ZmQN9wEVmPoT6jrkGaeepdqtz73ars2O71dmr3eoc0G51jmm3OpcCV1NC2l8F3kH5HW0rSudmg3PNWo7yd7RnAW8HvgT8Bris3epc1W51Tm63Ol9vtzrvabc6L2i3Og9ttzpVf+uUJEmSJEmSJEmSpKExPAdExL+ovgllZepv0pqxzHwE9U+W1ni5omb7TG8ouK5i22rdG8ua8J+Kbetk5rINrPkmoKnvZyaaCuK8tGb7Txpad6nTPS6+Djy+Zuj7I+IbQyhpiSLiKuCoiiELgA8OqZxZiYjLqf6cXZUGQkndc5Eh9fF1dsW2TTJzvUEulplrAK8a5Jwamd0aukZ6AVAVBP59RHR6nKvqWgtg3R7n6VlmPgrYZtDzqlHbAxvVjPnNEOoYlLpQFpSuUPPN9ozPfnoz1d9LG/jWoBfNzM8AUz0MfWNEfHXQ689THk/9+SXwr4rtk8BzZzH/dJ7XnbvKnN5fEXE+9V0n3zjgZd9Us/3EiLhgwGtqgNqtzrLtVucB7VbnOe1W593tVuegdqvzu3arcw3wT8ox+TlgT2AH6o8Tjc5alBDjyyldJg8DzgBubLc657dbnaParc7+7VZnz24ocoMR1ipJkiRJkiRJkiRpKWR47k4H12zfJzPXHPCa+w94Ps19dZ3lrpnhfFU3YC8PbDjD+Qax7jLAloNcLDO3AF47yDln4W2ZeY9BTpiZT6b6KfO3Uf8Ud/XuY8CLasZ8LSLmQjDtczXbn5WZTxlKJbN3SM32fTJz0E+Jfw2wyYDn1Nzxp4ptC6g/zmfq9cAaA55To/EA4BWDnLDbjen9NcO+O4Mp60J2dd2EZqQbNv78IOfUUOxTs/0K4JQh1DFrmflY4GU1wy6hvpP3XLRPzfZ5sZ+6HaOyZtj7I+LmAa/7IeAtPQx9e0QcMMi15yuPp/6Pp26394Nqhg06ANbLnP8GTmhg3UH7Ws32PTLzXoNYKDM3oP5BZwcNYi3NXrvVWand6mzRbnV2a7c6H2y3Ooe1W50zgRspD0U5AvgosDvwGPy9a5wsQ/m7zNMogdcDKKHIi9utzvXtVufUdqtzcDc8uUO71VltlMVKkiRJkiRJkiRJGl+G5+70deD6iu0T1N8Q27PM3BnYdlDzad54ZM3282c438U12x88w/l6dV7N9oF1kMrMlSjdC5Yf1JyztDb1N432rHuz+mdqhv04Iuq6FqoHmfk64J01w35Jb50tGhcRR1N/8+d3M/P+w6hnlr4NVN1MfT8GeCNqZq7FPOnMp77V3UC8+6C6i2XmQ6m/WVvzy4czc5A3Zu4NbFqx/WbgOzOY759UnzOflZnLzWC+Ou+ldIrQPJGZe1L/++R3ukGQOS0z16EcH3Xn7C9HxMIhlDQw47Kfug8S+j6wUsWw04GvDHjddwP/08PQ90XEvoNce77yeBrI8fRZqjvAbpuZr5jlGv8nM/egviv61yLitkGt2aBvApdXbF+F8jCbQfg41eeky7r1aATarc5G7Vbnxd1OY78HrgVOpfxd4L2Ujs0PAQb9AB3NL6sCWwAvpoQnjwGuabc6Z7RbnS+3W51Xt1udh7VbHf8bliRJkiRJkiRJkqRZG+QNl/NaRFyTmV+m+onmb87Mn0fEL2azVmZuDHxhNnNocDLzUcDGwPebvHksM1cHXloxZCEzf0L632q2PwP42Qzn7MUfarbvlZn7R8Rls1mkG3po0VwIsF+vy8yDI+KkAcz1LsoNQ1U+PYB1lnqZuRP1XXXOAF4QEbcOoaRevQ04rmL72sCPM3P7iGgPo6DMfDbwk4i4o9eviYjLM/PbwCsrhr0/M38YEefOushy3NR1+9T8djJwNbDWNNu3pHSj+PpsFukGrA6m+uZczT/3otx0/YbZTpSZD6A+3PGtiKi6mfxuIuL2zDwN2HqaIRtSuvIe2Ouc08nMp1FuYh6abuigrjvNDhFxXPPVzE43rP3wiPjNENd8BrBfzbDb6fP90e2k+LCI+GM/Xz/DtdYGfg5sVDP0Buo78latsxZjtp+Gpft77A+p/p3lNuB1M7k27GHdvSg30tf5SER8aFDrDprH02AM83iKiMu6fx+serDHfpl5bERcNJu1MnMj6h+mcyuz7A6bmQdROnpNKyJm/dCJiLgpM/cHPlwx7OWZeUREHN7vOt0Hku1WM2y/QXfC1JK1W50VKQ8L2+Yur/VHWpTms2WAh3Zfr+r+2/XtVuePlL8B/A743eTUxKUjqk+SJEmSJEmSJEnSPOVTO+/uI5Qn4U5nWeDQzNym3wUy897AL4B1+p1DA7cBcChwZma+qtvpbKC6IbD/BdatGPaHmdxU3XUm5ca36by8+54bqIg4G7iwYsjqwLcys+8nSGfm8sBXKcGHuWY54PuZed/ZTJKZz6O+M9axEVHXXUk1MnNL4BDKeXw6/wJ2ioiqz4Ghi4hfA9+oGbYZcFpmbt9UHZm5Qma+pBvm+CH9XUN8lHLz53TWAH6YmbMKvWXm24E9ZjOH5r6IuIXyXqzyydmcqzNzPUp49aH9zqE5bc9uF5u+Zea6wI+Aqi52t9Jfl5Wf12z/aGY+oo95/09mPgf4AT5UZTbWAn6dmb/KzLrOQbOSmctm5t7AEdR3Zf5G95q9HysDf8jM73cfNNKIzHwMpQtNXXdugA9HxL9nsdxajN9+uuuaD87MLWY7zxLm3RT4NbBdzdAPRsTJA1x3D0r3rzqfjoheOtONksfTLIzieOr6AHBlxfY1gWMzc5N+F+h+7bHduap8YbYhvSHbD/hHzZivd9+zM5aZW1P+VlTlH8D+/cyveu1WZ4N2q7Nzu9X5dLvVOZnyt/QTgU9ROsoZnNOgrQZsD7wbOBz4V7vVuajd6nyv3eq8rd3qPL7d6qw80golSZIkSZIkSZIkzXmG5+4iIjqUG2SqrAH8qnsz14xk5hMoT0e9/2KbBvZ0ds3Kg4EvA//MzM8O6sa2zLwH5UavF9cM/d+Zzh0Rt1FuZpzOovfrtjOduwffqdn+JODwfkIwmflA4DfAK5aw+faZzteQScoNg329T7rnkEOoPg/fAby1n/l1p8ycBH5CdbDhOuAZEfHP4VQ1Y3sB59WMmQR+mZn7ZubAblbLzM0z85OUGxC/BTyi37m6HeXquiY8mHJszTjwlJkLMnMf4JN9lKf56Ys12yeA4zJzs5lOnJk7Ar+lt5vQNX99PjP/X/dBBzOSmfenhCvr3l+f67Oj5sGUzsTTWQP4eT/B6cxcKTM/TgnOLX6j6Vy51ppvnggcn5nHZeZrZxsEX1xmPpbS/fnT1IcdLwPeOYBln08J/fwmM3fvduKctcxcOzMDOJ7SAbzOnyk35A/COO4ngIcDp2bmrzPzebN5iAn830MT3gT8CagL5f2K6i5TM117F+BLQN15+cCIeNug1h0Cj6cZGuHxRERcQekSX2UT4Dd9fg7vQNlndeG7S4Gc6fyjFBE3UrqnV1kd+EVmPmsmc3dD/z+n+nd7gLdGxH9mMreWrN3qrNBudbZqtzpv6QaVLgYuBr4H7A1sBczqM0fq032AnSmfaccD17ZbnVParc6B7VZn93ars1m71Zl1R01JkiRJkiRJkiRJ48MOA//tM8BzgaqnZ68MfDUzd6d0qzs6Iqa9sTUzNwfeDryEJd8AdiAlGKG5YR3gjcAbM/NC4MfAMcAJ3RuoepKZDwJ2685V9yTxv1PfWWo6hwA7VWzfjBJEuQA4ubvWNZSOdVXBzV9HxDkV2w+g3BC1YsWYnYAzMvNjwNfqOnpl5iOB1wO7s+Tz09+B0yk3RwzbGcBDuHvY7d7ACZn5CeATEXF93SSZuTHwCXr7HvaNiD/NvFQt5oHAvWrGHAk8qsluEIupO77uJiKu694oeAKl08N0lqUELvfKzG9TQq6/jYiqDpV30+20tQ3lZtidgFl1WFyCoHzOVt0o+mDKDeDvp3RauKVu0u5n7f4suTPKn5hF6E9zV0ScnJl1HXE2AE7PzE8Bn6nqtNINGzyBct32tCUMuYbS7W4udkVVb/7E3c8HCyjX8ztm5lsi4sy6CTJzRcr1ygcoN39XOR/Yp59CI+LszDwSeGbFsHUpD0r4KrBfRPylas7MnABeSrmGW1J34oWULnlzvZPTXLZd93VgZh5L6Y5xInBGRPT80JRuoPN+wPOAl9F7B8zbgJfP5PeWHjyh+/pCZv4KOIpyTXJmr99TZi5HCSO/GHg19cGHRa4Gnh8RVZ1r+zGO+wlg2+7r2u7543DgNxFxWS9f3H14wW6UfXSfHr7kDOAFETGQ0G23o9S3qO4WDeWhDn/KzFcPYt0eHRkRlw5gHo+naczB4+krwDMov7tMZwNKB7rDKL/n/3G6vw92v79HUUJ+L+xh/YXAHhFR1QFvToqIwzLzO5TzyXTWpHQdP5jSvfJv0w3MzAcD7wde1MPy346I78+oYP2fdquzHvA44LGUvwtsCaw00qKk3ixHeb9uSfldDeDqdqtzEvAL4KjJqYm/j6o4SZIkSZIkSZIkSaNneG4xEXFHZr6E8nTrdWuGL7pBqJ2ZxwFnAf+mdGtYi9Jh7vHAAyrm+D2wH4bn5qqN6QbpADLzYuAvwIXAvyg30d9EecryqpTg3WaUJ/9v3OMatwGvmsUNbIdQbnKuCwdtQv1Tze9qD2DacE9E/Kvbjeq9NfNMUt7jH8vMP1COrcsoP7sVgHtSjpHHARtWzHMr5Qa6PXusf9BOpXRVeMti/74i8D7gzZn5XeBnlKf5X0p5b6xGeS88Cng25Qb4uptBodzcX/ez1eC8mPrukINUeXwtSUT8pftk/p9RzjdVVuiusQdwW2aeApwJXNl9XUV5H65EOW9NUs4PvQQNZ6UbBHwppWtm1XXIGpRzx3u6N14eTfkeLqecD9agBPu2pnTy2GGaeW4DXgWcMoj6NSftTflsqTq3rkgJA707M3/bHX855bNobco136aU91HVDeivoQSpNX+9mtIJevH3y47An7tBhsO7Y86jdCZdgdLF8GHAk4Fdqf89Acr552URcd0s6n0H8FRg+Yoxy1C+r1dn5tnAScAFlHP97ZTz5caUoMWWVB8rnwN+ieG5QViW0on5Sd3//8bM/Dvl8/9flOvh64GbKe+x1Sn76h6U88zDqQ9nLm4h8LqI+MWsq1+ylSnXsosCnTd033N/p3xPlwM3Ur6nVSnfyzqU34u3of76ZXE3AM+NiLruu7MxjvsJSo27dl9k5r8ov8+cRzk3XAXcAqxCOZ/dj/L7ykYzWOMcYKeIuGZwZfNAqs93i9yHPjq3z9IOlN/xBsXjaY4fTxGxsPvQrD9Q/Xc9KGG4FwKXdK8lLqF8vwDrUUJ2OwIz6RD+roj4+cyqnlOmKNcdD6wYs4ASsNstM0/jzmuY6ynvhU0ofyvavMc1/wa8rt+Cl0btVmcZyu/UO3Vfj6C+86c0X6zFne/t/dqtzvmU7pU/A46ZnJqofQiaJEmSJEmSJEmSpPFheG4JIuIf3Q4/x1BuaKozSX+hi0spN9f0EqTR3LAh1QGvfuwVESf0+8URcXNmvo3SYWrYPgg8nXIzdp2VuPMp+zO1EHhlRPw+M0cVnoNyI/l2wBZL2LYG8Nrua7YuBZ7dS7ctLV0i4oTM3IHSKW+ixy9bDtiq+5oTIuKk7rHcy03P61JCq2/pc7n3RsSpmdnnl2uui4jTMvNDlK6GdZalPNigqsPwdP4nIg7NTMNz81hEnJKZ76N0m1vcAu5+0/9svT4iTprNBBHxt8z8f8CnevySzbqvfhxF6UjXz/GheqtQbkh/REPz30rpUPTthuZfklW5s8PHoF1FCfr8poG5q4zjfoIS2JlJaKfOKcDTI6IzwDmXdh5PM9f48RQR12bmk4Hj6O1hRPdmMB2KPxERnxzAPCMTEddn5lOB4+mtk+UWLPlvLb36B/DUiDAMU6Pd6tyT0mV7J+AplGCutDTYlNKV7vXALe1W50RKkO5nk1MTfx5pZZIkSZIkSZIkSZIat8yoC5irIuJkyk0ETd10cSXwrIi4uKH5NffdRnlCemu2E0XEwcD+sy9pxuveAjwXuKjBZe4A3hwR32pwjZ5ExI3AsyhPkW9Kh3IjqucGLVFE/AF4DPDbUdcyGxHxJZrvrnhQRHy84TU0N3wA+H6D8380IpYUttI8FBEfBb7e8DL/ExFfHsREEbEvMJC5KhwH7BwRtzW8jppxPrDdCAJZTfkz8OgRBH2aNi776RvA9gbn5g2Pp1mKiH8A2wN/bXotyt8/3hkR7xrCWo3r/ux2pHS9bNK5wBO762kx7VZnQbvVeVS71Xl/u9U5mdIV8ZuU7qQG57S0WoHSVfbjwOntVueSdqvz1Xars0u71Vl7xLVJkiRJkiRJkiRJaoDhuQoRcRywLeWmnEG6CHh8RJwy4Hk1f5xJueFw1sG5RSLiLcDbgf8Mas4e1/0n8DhgVp1VpnE98PyI+FwDc/clIi6hdM87p4HpLwS2jYjTG5hbYyQiLqR8Pr0XuGHIy98C/AC4fbYTRcSHgTcOYq4l+CLw6gbm1RwUEXcAuwHfHfDUtwJTEfGeAc+r0XsVvXW/nKnbKF2FBx22nAKS0o130L4KPCUihv15otm7BdgXeEREzOtQfddNwPspQZ+mgxbDNC776TLgxRGxu52d5gWPpwHqhrIeAxzc4DKXAE+a7x3nFhcR5wKPBn7e0BI/Ax4zZu/zWWu3Omu1W50XtVudrwOXAn+gXEtuhf89QFqS9YE9gEOATrvVOakbOH1Mu9XxmJEkSZIkSZIkSZLGwHKjLmCui4jTMnNL4JOUm2xn+x9Lvwq8NSKumXVxGpSjgRcBzwSeDtyzwbWupnTH+VwTnT0iYt/MPBR4K/ASmv1e7rruJZm5PfAJShBm2QFM+2PKzedz7snhEXFBZj4W+BKl894gHAa8JiKuHtB8GnPdc8iHM/OrwPuAlwOrNrjkHyidmg6OiCsHNWlEfD4z/wR8G7jPAKa8AXhXRBwwgLk0j3S7oe6amb8FPsLsj4dTgFcZaB5PEXE7MJWZZwIfA1YZwLQXAS+JiBMHMNfddAOi+2Tm74CvAesNYNqLgTdGxA8HMNfS7FJKuHEnSned1Yaw5rXAQcBnuoH6QbsZOAbYBli5gfkXdyOlu+Inug+qaMI47qe7upLyEJUm9td1wGeATxqa64vH02AM83haom7IfLfM/CawH/CAAU39H+CzwIfG9RiLiKuAp2Xm7pS/G607gGkvB94REd8YwFxjod3qPBx4BuXY3Br/7i/1a1nK5/Y2lNDpFe1W52hKWPfnk1MTl42yOEmSJEmSJEmSJEn98T+i96AbdHttZh4AvAPYGVhhBlPcSgnGfCIi/jT4CjUb3Rugvgd8LzOXodxgsiPlP5BvDaw9yyVuA34BfAs4IiIa7QzXDZu9JTPfRnmi9OOAhwP3BSaBdSg37S0HLBjgurcCe2fm54F3Abszs+MEyo2FRwD7VzxF/gJKoGFJ/jXD9foWEVcAz8vM51Oe6L95n1P9CXh3RDT1FHaNuYi4FNgzM98DvAx4IeW4n22I9TLKjb6/BI6OiItnOd+0IuKEzHwg8E7gLcBafUxzG6Xr2PtGdUOt5oaI+GxmHka5ZtsDWHOGU/yR8tCEw7qBJY2xiPhcZh4JfBDYhf5+P7oa+DTwqSFc5x2VmRtTOmu+Hdioj2lOAw4Avh0RNy1h+3VMf621aLu6IuJmShfD/83MFSgdinegXIc/mpmfg6ZzFfAr4PvAT5oMWHTfxzt2v5+tKd/PY4FHMJjAA5SAz2+AQ4FDI6LR99U47qe7iohfZOY6lO/pGcATgc3o//e9O4DfUx7+c/C4BnqGweNpVkZyPNXpfhb/gvIgnTcA29Hfg7bOojxA5IsR8e/BVTh3RcTXu9fpuwN7AQ/qY5qzgM8DB0XEjYOsb75ptzqrAU+mPAjs6cAGo61IGlv3BHbtvha2W50/AT8Cvjs5NfG3URYmSZIkSZIkSZIkqXcLFi5cOOoa5p3MvAfwNMoNaQ8BNgHWoASFrgeuAc4D/gIcD/wsIq6tmG9jSiBoOntExEGDqF0zk5kLgAdSglH3owTQ7kvp9rE65Qnrq1BCX9dQnoZ+DXAO5cbk04BTl8ZuYpm5BrAt5Sa6R1NuDFyHEoq5lXKs/Bv4O/A3ys1+x3XDjPNOZj4ReD7lhqVNa4ZfRHla8bcj4vima9PSp/s5tTXwGODBlHDFvbnznLWAcgxeSwlBXAWcSzkW/wb8NSLOGX7lkJmrUm5Ieh6wPdXdoG6mdMT7MeXG7sYCfpqfMnNF4CmUz6MtKddsE5QQ+a2U9/+/KNdsfwB+HBHnjaZajVpmbgS8GHgW5dql6iEANwDHUkL/B4/i5u3uQx+2oFxrbUfp3rlO97Vst8ZrKb9nnE0Jhv58Lnb1HVfd3yU2o4RkNqWcgzYB1qf8LrFq97UccAtwEyWMeRmls9PfKSGBPwJ/iYiR//KemetTvp8HAhve5TVB+cxehXKOXUD5fm4EOpRz7QXAGZSHR/yu2zF05MZxPwFk5lqUMNMWlN9hN6WcJ9agXBOuRPlerqP8XnYu5Vzxe+CYQXYa1pJ5PM2f46lKN7j6FMrvXw+i/O1oLcpxtoDSWe4qyt8BzqEcY7+OiKU+cJGZD6D8fXVLyt9X7015n6xCeb9fB/wT+CtwKnDUqH5PnSu6gbnnA7tRrgFn+tAqSYP1J+A7lCCdf5OSJEmSJEmSJEmS5jDDc3OA4TlpvHSDgw/izpDlcpSg0uXA3yKiM8LypHkjM5el3Ox9P0oHixW5MwxyIXBuRNw+sgIlja3MXI5y7tmYEjRZhXKD/zWUgMn5nn8kSZLUtHarsxwlZPgS4NlUP2BG0mgsBE4ADgYOnZyauGLE9UiSJEmSJEmSJElajOG5OcDwnCRJkiRJkiQJoN3qbAO8FNgFuOeIy5HUu9uAoylBuiMmpyauG3E9kiRJkiRJkiRJkijdkCRJkiRJkiRJ0oi0W53NKB3mdqN0YZc0/ywHPL37+k+71fkJJUj308mpiZtHWpkkSZIkSZIkSZK0FDM8J0mSJEmSJEnSkLVbnfWAXSmhuUeNuBxJg7UysHP3dU271fkBJUh3zOTUxO0jrUySJEmSJEmSJElayhiekyRJkiRJkiRpCNqtzmrA84CXAjsCy462IklDsCawR/d1WbvV+R7wncmpiZNHW5YkSZIkSZIkSZK0dDA8J0mSJEmSJElSQ9qtznLAUymBuWcDq4y2IkkjtB7wRuCN7VbnAuC7wLcnpyb+MtqyJEmSJEmSJEmSpPFleE6SJEmSJEmSpAFrtzpbUwJzuwATIy5H0tyzCfD/gP/XbnVOAg4ADpucmrhltGVJkiRJkiRJkiRJ48XwnCRJkiRJkiRJA9BudVajBOb2BB424nIkzR+P7b4+3W51vgS0Jqcm/jnimiRJkiRJkiRJkqSxYHhOkiRJkiRJkqRZaLc6D6IE5l4OrDHiciTNX+sB7wXe3W51fggcMDk1ceyIa5IkSZIkSZIkSZLmNcNzkiRJkiRJkiTNULvVWQ54DvAGYIcRlyNpvCwHvAB4QbvV+QtwIPCNyamJ60dbliRJkiRJkiRJkjT/GJ6TJEmSJEmSJKlH7VZnEnht93XvEZcjafw9BDgA+Gi71fkGpRvd30ZckyRJkiRJkiRJkjRvGJ6TJEmSJEmSJKlGu9XZCngLpRvU8qOtRtJSaA1gL2CvdqvzK0qg7keTUxO3j7YsSZIkSZIkSZIkaW4zPKeByMz7A9uNuo4eXRcRh4y6CEnS3JeZ2wIPGHUdPfp7RPxm1EVIkiRJ0jhptzrLAs8H9ga2GXE5krTIjt3Xxe1W54vAlyanJjojrkmSJEmSJEmSJEmakwzPaVAeB3xp1EX06CLA8JwkqRevBHYfdRE9+jpgeE6SJEmSBqDd6qwJvBp4I7DRiMuRpOlsCHwYeH+71TkUOGByauLkEdckSZIkSZIkSZIkzSmG5yRJkiRJkiRJAtqtzn2BNwN7AKuNuBxJ6tWKwEuBl7ZbnVOAzwPfnpyauHW0ZUmSJEmSJEmSJEmjt8yoC5AkSZIkSZIkaZTarc527VbnCODvlG5zBuckzVePBL4GnNtudV7fbnVWGHVBkiRJkiRJkiRJ0ijZeW4OiIgLgQWjrkOSJEmSJEmSlibtVudJwD7A40ZciiQN2n2AA4H3tFudjwFfnpyauHnENUmSJEmSJEmSJElDZ+c5SZIkSZIkSdJSpd3q7NBudX4DHI3BOUnjbQPg88D57VbnTe1WZ6VRFyRJkiRJkiRJkiQNk+E5SZIkSZIkSdJSod3qbNdudY4DjgGeMOJyJGmY1gf2p4To9m63OiuPuiBJkiRJkiRJkiRpGBYsXLhw1DVIkiRJkiRJktSYdqvzBCCBHUZdiyTNEZcBnwIOnJyauHHUxUiSJEmSJEmSJElNMTwnSZIkSZIkSRpL7VbncZTQ3I6jrkWS5qgOJUR3wOTUxA2jLkaSJEmSJEmSJEkaNMNzkiRJkiRJkqSx0m51tqaE5p4y6lokaZ64Avg08PnJqYnrRl2MJEmSJEmSJEmSNCiG5yRJkiRJkiRJY6Hd6jyGEpp72qhrkaR56krgM8BnJ6cmrh11MZIkSZIkSZIkSdJsGZ6TJEmSJEmSJM1r7VbnUZTQ3E6jrkWSxsTVwH7A/pNTE1ePtBJJkiRJkiRJkiRpFgzPSZIkSZIkSZLmpXarsyUlNPfMUdciSWPqGuCzwKcN0UmSJEmSJEmSJGk+MjwnSZIkSZIkSZpX2q3OFsA+wLNHXIokLS3+DbwfaE1OTdw+6mIkSZIkSZIkSZKkXhmekyRJkiRJkiTNC+1WZyPgk8ALgQUjLkeSlkZnAntPTk38ctSFSJIkSZIkSZIkSb0wPCdJkiRJkiRJmtParc7KwLuAdwIrj7gcSRL8GHjb5NTEOaMuRJIkSZIkSZIkSapieE6SJEmSJEmSNGe1W52dgU8B9xl1LZKku7kF+BzwwcmpiWtGXYwkSZIkSZIkSZK0JIbnJEmSJEmSJElzTrvVeRjwWWD7EZciSarWAd4LfHlyauKOURcjSZIkSZIkSZIk3ZXhOUmSJEmSJEnSnNFude4BfAB4HbDsiMuRJPXudGDvyamJY0ddiCRJkiRJkiRJkrSI4TlJkiRJkiRJ0si1W51lgCngg8A6Iy5HktS/w4G3T05NnD/qQiRJkiRJkiRJkiTDc5IkSZIkSZKkkWq3OtsCnwU2H3UtkqSBuBnYD/jw5NTEdSOuRZIkSZIkSZIkSUsxw3OSJEmSJEmSpJFotzobAJ8CXjTqWiRJjWgD7wW+Njk1cceoi5EkSZIkSZIkSdLSx/CcJEmSJEmSJGmo2q3OSsA7gHcDq4y4HElS804F3jI5NXH8qAuRJEmSJEmSJEnS0sXwnCRJkiRJkiRpaNqtzvMp3eY2GXUtkqShOxR4x+TUxEWjLkSSJEmSJEmSJElLB8NzkiRJkiRJkqTGtVudBwP7A08adS2SpJG6Cfgw8PHJqYlbR12MJEmSJEmSJEmSxpvhOUmSJEmSJElSY9qtzhrAB4E9geVGXI4kae74M/DqyamJP4y6EEmSJEmSJEmSJI0vw3OSJEmSJEmSpEa0W50nA18BNhx1LZKkOel2SlfS901OTdw46mIkSZIkSZIkSZI0fgzPSZIkSZIkSZIGqt3qrA7sC7xm1LVIkuaF84HXTk5N/GrUhUiSJEmSJEmSJGm8GJ6TJEmSJEmSJA1Mu9XZkdJtbqNR1yJJmne+Crxtcmri6lEXIkmSJEmSJEmSpPFgeE6SJEmSJEmSNGvtVmc14JPAFLBgxOVIkuavNrDX5NTE90ddiCRJkiRJkiRJkuY/w3OSJEmSJEmSpFlptzo7ULoFbTziUiRJ4+Nw4PWTUxOXjboQSZIkSZIkSZIkzV+G5yRJkiRJkiRJfWm3OqsCHwf2xG5zkqTBuwJ4w+TUxPdGXYgkSZIkSZIkSZLmJ8NzkiRJkiRJkqQZa7c62wJfAzYddS2SpLF3KLDn5NTEFaMuRJIkSZIkSZIkSfOL4TlJkiRJkiRJUs/arc4qwMeAvbDbnCRpeC4HpianJo4YdSGSJEmSJEmSJEmaPwzPSZIkSZIkSZJ60m51Hk/pNne/UdciSVpqfRt44+TUxFWjLkSSJEmSJEmSJElzn+E5SZIkSZIkSVKldquzMvAR4E3AMiMuR5KkS4HXTE5NHDnqQiRJkiRJkiRJkjS3GZ6TJEmSJEmSJE2r3epsAxwEPGDEpUiStLiDgDdPTk1cO+pCJEmSJEmSJEmSNDcZnpMkSZIkSZIk/Zd2q7MS8CFgb+w2J0mau84Ddp6cmjht1IVIkiRJkiRJkiRp7jE8J0mSJEmSJEm6m3arsznwXeCBo65FkqQe3Ay8dXJq4sBRFyJJkiRJkiRJkqS5xfCcJEmSJEmSJOn/tFudVwOfA1YadS2SJM3Q94DXTE5NXDvqQiRJkiRJkiRJkjQ3GJ6TJEmSJEmSJNFudVYBDgR2H3UtkiTNwrnAzpNTE38adSGSJEmSJEmSJEkavWVGXYAkSZIkSZIkabTarc4DgN9hcE6SNP/dD/htu9V53agLkSRJkiRJkiRJ0ujZeU6SJEmSJEmSlmLtVmcX4MvA6qOuRZKkAfsu8NrJqYnrRl2IJEmSJEmSJEmSRsPwnCRJkiRJkiQthdqtzgrAp4A3jroWSZIa9Hdg58mpiT+PuhBJkiRJkiRJkiQNn+E5SZIkSZIkSVrKtFud+wCHAo8ZdS2SJA3BTcCbJ6cm/nfUhUiSJEmSJEmSJGm4DM9JkiRJkiRJ0lKk3eo8HfgWcI9R1yJJ0pB9B5ianJq4ftSFSJIkSZIkSZIkaTgMz0mSJEmSJEnSUqDd6iwLfAD4f8CCEZcjSdKonA3sPDk1ccaoC5EkSZIkSZIkSVLzDM9JkiRJkiRJ0phrtzrrAQcDO4y6FkmS5oD/AG+anJr48qgLkSRJkiRJkiRJUrMMz0mSJEmSJEnSGGu3OtsC3wXuNepaJEmaY74JvH5yauKGURciSZIkSZIkSZKkZhiekyRJkiRJkqQx1G51FgDvBD4MLDviciRJmqvOAnaenJr4y6gLkSRJkiRJkiRJ0uAZnpMkSZIkSZKkMdNuddYCvgE8a8SlSJI0H9wIvG5yauKboy5EkiRJkiRJkiRJg2V4TpIkSZIkSZLGSLvVeSRwKLDJqGuRJGme+Qjw3smpCf8DqiRJkiRJkiRJ0pgwPCdJkiRJkiRJY6Ld6rwM+BKw4qhrkSRpnjoEeMXk1MRNoy5EkiRJkiRJkiRJs7fMqAuQJEmSJEmSJM1eu9UJ4BsYnJMkaTZeBBzbbnXWHXUhkiRJkiRJkiRJmj07z0mSJEmSJEnSPNZudZandJvbfdS1SJI0Ri4Anjk5NfHXURciSZIkSZIkSZKk/hmekyRJkiRJkqR5qt3qrAV8H3jiiEuRJGkcXQO8cHJq4pejLkSSJEmSJEmSJEn9WWbUBUiSJEmSJEmSZq7d6mwMnITBOUmSmrImcFS71XnNqAuRJEmSJEmSJElSf+w8J0mSJEmSJEnzTLvVeTTwY2C9UdciSdJS4lPAuyanJu4YdSGSJEmSJEmSJEnqneE5SZIkSZIkSZpH2q3Oc4DvAKuMuhZJkpYyhwMvnZyauHHUhUiSJEmSJEmSJP1/9u47PLKzPhvwM1rv2uu62F6zBmxMsQk2YJsWg3GD0DuEUAIJJASHhN5CEuDlDYEPUgmhTQg19BpIgFASbNNbaKH3PjB097b6/jhas16vpkgzOhrpvq9LF0bn1XkfaUajkfY882M0c20HAAAAAABgNL1u/1FJ3hzFOQBow92TnNnr9g9tOwgAAAAAAACjMXkOAAAAAGCV63X7c0n+Mckj2s4CAOS7Se607fStn207CAAAAAAAAIMpzwEAAAAArGK9bn/vJK9Jcpe2swAAlzk7yX22nb71HW0HAQAAAAAAYHFzbQcAAAAAAGD3et3+tiRnRnEOAFab/ZK8rdftP6ztIAAAAAAAACzO5DkAAAAAgFWo1+0fk+TtSa7edhYAYKB/TvLobadvvbTtIAAAAAAAAFye8hwAAAAAwCrT6/ZvleRNSQ5oOwsAMJK3J7nPttO3ntN2EAAAAAAAAH5tru0AAAAAAAD8Wq/bf2CSd0ZxDgBmyR2TvL/X7R/SdhAAAAAAAAB+TXkOAAAAAGCV6HX7T0vy0iQb284CAIztuCRn9rr9q7QdBAAAAAAAgEZnfn6+7QwAAAAAAOtar9ufS9JN8uC2swAAy/b1JLfcdvrW77QdBAAAAAAAYL1TngMAAAAAaNFCce6lSX6v7SwAwMR8O8mttp2+9ettBwEAAAAAAFjPlOcAAAAAAFrS6/Y3JHlFkvu1nQUAmLgfpJlA9+W2gwAAAAAAAKxXc20HAAAAAABYj3rd/h5JXh3FOQBYq66S5Mxet3+9toMAAAAAAACsV8pzAAAAAAArrNftb0zyuiS/03YWAGCqrpzkjF63f8O2gwAAAAAAAKxHynMAAAAAACuo1+1vSvLGJPdoOwsAsCIOSvLfvW7/N9sOAgAAAAAAsN4ozwEAAAAArJBet79nkrckuUvbWQCAFbUlyXt63f5JbQcBAAAAAABYT5TnAAAAAABWQK/b35zkbUnu0HYWAKAV+yX5r163f6u2gwAAAAAAAKwXynMAAAAAAFPW6/b3TvKfSW7TdhYAoFV7J/nPXrevTA8AAAAAALAClOcAAAAAAKao1+3vm+SdSW7ZdhYAYFXYK8lbet3+3doOAgAAAAAAsNYpzwEAAAAATEmv298vyX8lObntLADAqrIpyRt63f592g4CAAAAAACwlinPAQAAAABMQa/bPyDJe5Kc2HYWAGBV2iPJq3rd/u+3HQQAAAAAAGCtUp4DAAAAAJiwXrd/pSTvTfKbbWcBAFa1uSQv7XX7p7cdBAAAAAAAYC1SngMAAAAAmKBet39Qkv9OcuO2swAAM6GT5IW9bv+RbQcBAAAAAABYa5TnAAAAAAAmpNftb03yP0mObzsLADBznt3r9h/edggAAAAAAIC1pDM/P992BgAAAACAmdfr9q+cZuLcMW1nAQBm1nyS+287feur2w4CAAAAAACwFijPAQAAAAAsU6/bv1KS90dxDgBYvouT3GXb6Vv/q+0gAAAAAAAAs26u7QAAAAAAALOs1+3vleRtUZwDACZjY5I39br9E9oOAgAAAAAAMOuU5wAAAAAAlqjX7W9I8tokt2g7CwCwpuyd5O29bv/otoMAAAAAAADMMuU5AAAAAICle36Su7YdAgBYkw5M8q5et39Y20EAAAAAAABmlfIcAAAAAMAS9Lr9pyZ5SNs5AIA17WpJ3t3r9g9qOwgAAAAAAMAs6szPz7edAQAAAABgpvS6/dOTvLDtHADAuvGxJLfadvrWc9oOAgAAAAAAMEuU5wAAAAAAxtDr9u+e5I1J5trOAgCsK+9Jcqdtp2+9qO0gAAAAAAAAs8LFHQAAAAAAI+p1+ycleXX8bRUAWHm3TvLyXrfveQgAAAAAAMCI/MMKAAAAAMAIet3+9ZK8LclebWcBANat+yT5p7ZDAAAAAAAAzArlOQAAAACAIXrd/uFJ/ivJlpajAAA8rNftP6XtEAAAAAAAALOgMz8/33YGAAAAAIBVq9ftH5jkA0mu23YWAICdPHTb6Vtf2HYIAAAAAACA1Ux5DgAAAABgEb1uf3OS/05ys7azAADsYnuS+2w7fesb2g4CAAAAAACwWs21HQAAAAAAYDXqdfsbkrwuinMAwOo0l+SVvW7/Vm0HAQAAAAAAWK2U5wAAAAAAdq+b5M5thwAAGGBTkn/vdfs3bjsIAAAAAADAaqQ8BwAAAACwi163/9dJ/rDtHAAAI9g3yTt63f512g4CAAAAAACw2nTm5+fbzgAAAAAAsGr0uv0/TfLctnMAAIzp60lusu30rT9vOwgAAAAAAMBqYfIcAAAAAMCCXrf/20me03YOAIAluFaS1/a6/Q1tBwEAAAAAAFgtlOcAAAAAAJL0uv2bJnll/N0UAJhdt0nyzLZDAAAAAAAArBad+fn5tjMAAAAAALSq1+0fmuQTSa7SdhYAgAn43W2nb3112yEAAAAAAADapjwHAAAAAKxrvW5/zyRnJDmh5SgAAJNyfpJbbDt96/+2HQQAAAAAAKBNc20HAAAAAABo2QuiOAcArC2bk7yl1+1vbTsIAAAAAABAm5TnAAAAAIB1q9ftPyLJg9rOAQAwBYcneWOv29/YdhAAAAAAAIC2KM8BAAAAAOtSr9u/ZZK/bzsHAMAUnZzk2W2HAAAAAAAAaEtnfn6+7QwAAAAAACuq1+1fI8nHkxzUdhYAgBXwR9tO3/qvbYcAAAAAAABYacpzAAAAAMC60uv290ny4STXbzsLAMAKuSjJqdtO3/rhtoMAAAAAAACspLm2AwAAAAAArJRet99J8vIozgEA68umJG/qdftXaTsIAAAAAADASlKeAwAAAADWkycmuWfbIQAAWnBokrf0uv092w4CAAAAAACwUpTnAAAAAIB1odft3yrJ09rOAQDQopsmeWHbIQAAAAAAAFZKZ35+vu0MAAAAAABT1ev2D0vyySRb284CALAKPHLb6Vuf03YIAAAAAACAaVOeAwAAAADWtF63vynJ+9NMWgEAILkkyW22nb71fW0HAQAAAAAAmKa5tgMAAAAAAEzZs6M4BwCwsz2SvL7X7R/RdhAAAAAAAIBpMnkOAAAAAFizet3+A5K8ou0cAACr1GeS3Hzb6VvPazsIAAAAAADANJg8BwAAAACsSb1u/9gk3bZzAACsYscmeUnbIQAAAAAAAKZFeQ4AAAAAWHN63f6WJG9KsrnlKAAAq929e93+g9sOAQAAAAAAMA2d+fn5tjMAAAAAAExMr9vvJHlrkju3nQUAYEacm+T4badv/WrbQQAAAAAAACbJ5DkAAAAAYK15VBTnAADGsU+SV/e6/Y1tBwEAAAAAAJgk5TkAAAAAYM3odfvXS/L/2s4BADCDbpykth0CAAAAAABgkjrz8/NtZwAAAAAAWLZet78pyceSHNt2FgCAGbU9yWnbTt96VttBAAAAAAAAJsHkOQAAAABgrXhaFOcAAJZjLsm/9br9LW0HAQAAAAAAmATlOQAAAABg5vW6/ZOTPK7tHAAAa8DhSV7QdggAAAAAAIBJ6MzPz7edAQAAAABgyXrd/v5JPpvk6m1nAQBYQ35v2+lb/63tEAAAAAAAAMth8hwAAAAAMOueG8U5AIBJe26v279G2yEAAAAAAACWQ3kOAAAAAJhZvW7/Xkke0HYOAIA1aP8kr+x1+xvaDgIAAAAAALBUynMAAAAAwEzqdftXSfLCtnMAAKxhN0/ypLZDAAAAAAAALFVnfn6+7QwAAAAAAGPpdfudJP+V5DZtZwEAWOMuTXKLbadv/UjbQQAAAAAAAMZl8hwAAAAAMIseFsU5AICVsCHJq3rd/n5tBwEAAAAAABiX8hwAAAAAMFN63f51kzyr7RwAAOvINZP8c9shAAAAAAAAxtWZn59vOwMAAAAAwEh63f7GJB9NcnzbWQAA1qF7bzt96+vbDgEAAAAAADAqk+cAAAAAgFlSozgHANCWF/a6/cPaDgEAAAAAADAqk+cAAAAAgJnQ6/ZvkeTMeFEwAIA2nZHkVttO37q97SAAAAAAAADDuMgEAAAAAFj1et3+fkleEX/TBABo26lJHt92CAAAAAAAgFG40AQAAAAAmAX/lOQabYcAACBJ8rRet3/9tkMAAAAAAAAM05mfn287AwAAAADAonrd/t2TvLntHAAAXM6Hk5y47fSt/sEZAAAAAABYtUyeAwAAAABWrV63vy3Jv7SdAwCAK7hZkoe0HQIAAAAAAGAQ5TkAAAAAYDX7xyQHtx0CAIDdemav279y2yEAAAAAAAAWozwHAAAAAKxKvW7/Vknu03YOAAAWtSXJP7QdAgAAAAAAYDGd+fn5tjMAAAAAAFxOr9vflOSzSa7TdhYAAIa6zbbTt76n7RAAAAAAAAC7MnkOAAAAAFiNnhDFOQCAWfH8Xre/V9shAAAAAAAAdqU8BwAAAACsKr1u/xpJ/qLtHAAAjOza8fwNAAAAAABYhZTnAAAAAIDV5p+TbG47BAAAY/mzXrf/G22HAAAAAAAA2JnyHAAAAACwavS6/bsluWPbOQAAGNumJC9oOwQAAAAAAMDOOvPz821nAAAAAABIr9vfJ8kXkhzedhYAAJbsgdtO3/rytkMAAAAAAAAkJs8BAAAAAKvHU6I4BwAw6/6u1+0f1HYIAAAAAACARHkOAAAAAFgFet3+0Uke3XYOAACW7eAkf9N2CAAAAAAAgER5DgAAAABYHZ6fZGPbIQAAmIgH9br9k9sOAQAAAAAAoDwHAAAAALSq1+0/IMkpbecAAGBiOkle2Ov2N7UdBAAAAAAAWN+U5wAAAACA1vS6/S1J/q7tHAAATNx1kzy+7RAAAAAAAMD6pjwHAAAAALTpGUkOaTsEAABT8aRet3+ttkMAAAAAAADrl/IcAAAAANCKXrd/4ySnt50DAICp2SvJ89sOAQAAAAAArF/KcwAAAADAiut1+3NJXhh/owQAWOtu0+v279N2CAAAAAAAYH1yYQoAAAAA0IaHJrlR2yEAAFgR/9jr9g9oOwQAAAAAALD+KM8BAAAAACuq1+1fOclft50DAIAVsy3Jn7cdAgAAAAAAWH+U5wAAAACAlfZ3Sba0HQIAgBX1yF63f3jbIQAAAAAAgPVFeQ4AAAAAWDG9bv9mSe7fdg4AAFbcXkme3nYIAAAAAABgfVGeAwAAAABW0jPbDgAAQGt+t9ft37DtEAAAAAAAwPqhPAcAAAAArIhet3+7JCe3nQMAgNZ0kvxd2yEAAAAAAID1ozM/P992BgAAAABgjet1+50kn0xyfNtZAABo3Z22nb717W2HAAAAAAAA1j6T5wAAAACAlfA7UZwDAKDxN71uf0PbIQAAAAAAgLVPeQ4AAAAAmKpet79Hkqe1nQMAgFXj6CR/2HYIAAAAAABg7VOeAwAAAACm7Q+SHNl2CAAAVpXa6/b3bTsEAAAAAACwtinPAQAAAABT0+v290rylLZzAACw6mxL8ri2QwAAAAAAAGub8hwAAAAAME0PT3LVtkMAALAqPbbX7W9tOwQAAAAAALB2Kc8BAAAAAFPR6/YPSPLEtnMAALBq7ZvkL9oOAQAAAAAArF3KcwAAAADAtDwuyYFthwAAYFV7aK/bP6ztEAAAAAAAwNqkPAcAAAAATFyv2z8kyaPbzgEAwKq3Z5LSdggAAAAAAGBtUp4DAAAAAKbhSUn2aTsEAAAz4YG9bv+otkMAAAAAAABrj/IcAAAAADBRvW7/iCSnt50DAICZsSHJ09oOAQAAAAAArD3KcwAAAADApNUkm9oOAQDATLlXr9s/ru0QAAAAAADA2qI8BwAAAABMTK/bPybJ/dvOAQDAzOkkeXrbIQAAAAAAgLVFeQ4AAAAAmKSnx98dAQBYmjv0uv1btB0CAAAAAABYO1zEAgAAAABMRK/bPyHJXdvOAQDATHtG2wEAAAAAAIC1Q3kOAAAAAJgUFzoDALBcJ/W6/VPaDgEAAAAAAKwNynMAAAAAwLL1uv3bJDmt7RwAAKwJT2g7AAAAAAAAsDYozwEAAAAAk/C0tgMAALBm3L7X7V+v7RAAAAAAAMDsU54DAAAAAJal1+2fkuSmbecAAGDN6CR5fNshAAAAAACA2ac8BwAAAAAs12PbDgAAwJpz3163f7W2QwAAAAAAALNNeQ4AAAAAWLJet3+dJHdqOwcAAGvOxiSPbjsEAAAAAAAw25TnAAAAAIDleGySTtshAABYk/6o1+1vaTsEAAAAAAAwu5TnAAAAAIAl6XX7hyR5QNs5AABYs/ZL8tC2QwAAAAAAALNLeQ4AAAAAWKo/TbJX2yEAAFjTHtHr9vdsOwQAAAAAADCblOcAAAAAgLH1uv3NSf6k7RwAAKx525L8XtshAAAAAACA2aQ8BwAAAAAsxQOTHNx2CAAA1oXH9bp9/7YNAAAAAACMzT8wAAAAAABjWbhw+dFt5wAAYN04Ksld2w4BAAAAAADMHuU5AAAAAGBcd0lyZNshAABYV57QdgAAAAAAAGD2KM8BAAAAAON6XNsBAABYd07odfsntR0CAAAAAACYLcpzAAAAAMDIet3+CUlObDsHAADrkulzAAAAAADAWJTnAAAAAIBxmDoHAEBb7tjr9o9pOwQAAAAAADA7lOcAAAAAgJH0uv1rJrl72zkAAFi3Okke33YIAAAAAABgdijPAQAAAACjenT8TREAgHbdr9ftX7XtEAAAAAAAwGxwoQsAAAAAMFSv2z8wyYPazgEAwLq3Mc2LOgAAAAAAAAylPAcAAAAAjOKhSfZpOwQAACR5SK/bP6DtEAAAAAAAwOqnPAcAAAAADNTr9vdM8rC2cwAAwIL9kpzedggAAAAAAGD1U54DAAAAAIb53STb2g4BAAA7eUiv2++0HQIAAAAAAFjdlOcAAAAAgEUtXJD82LZzAADALq6V5NS2QwAAAAAAAKub8hwAAAAAMMhpSY5uOwQAAOzGg9sOAAAAAAAArG7KcwAAAADAIH/QdgAAAFjEPXrd/pa2QwAAAAAAAKuX8hwAAAAAsFu9bv+AJPdoOwcAACxiryS/23YIAAAAAABg9VKeAwAAAAAWc+8km9sOAQAAAzy47QAAAAAAAMDqpTwHAAAAACzmQW0HAACAIY7rdfs3bDsEAAAAAACwOinPAQAAAABX0Ov2r5vkhLZzAADACEyfAwAAAAAAdkt5DgAAAADYHVPnAACYFffrdfub2w4BAAAAAACsPspzAAAAAMDl9Lr9PZI8oO0cAAAwogOS3LPtEAAAAAAAwOqjPAcAAAAA7Or2Sba1HQIAAMbw4LYDAAAAAAAAq4/yHAAAAACwqwe1HQAAAMZ0Sq/bv3bbIQAAAAAAgNVFeQ4AAAAAuEyv29+a5E5t5wAAgCX4g7YDAAAAAAAAq4vyHAAAAACws99NsrHtEAAAsAQP7HX7G9oOAQAAAAAArB7KcwAAAADAzh7UdgAAAFiiQ5Pcoe0QAAAAAADA6qE8BwAAAAAkSXrd/o2S3KDtHAAAsAwPbjsAAAAAAACweijPAQAAAAA7mDoHAMCsu0Ov29/WdggAAAAAAGB1UJ4DAAAAANLr9vdMcr+2cwAAwDLtkeT32w4BAAAAAACsDspzAAAAAECS3C3JldoOAQAAE/CHbQcAAAAAAABWB+U5AAAAACBJHtR2AAAAmJAje93+yW2HAAAAAAAA2qc8BwAAAADrXK/bv1qSW7edAwAAJsj0OQAAAAAAQHkOAAAAAMjvx98KAQBYW+7R6/b3bDsEAAAAAADQLhfEAAAAAAAPbDsAAABM2L4xXRkAAAAAANY95TkAAAAAWMd63f7Nk1y77RwAADAF92g7AAAAAAAA0C7lOQAAAABY3+7edgAAAJiSu/S6/Q1thwAAAAAAANqjPAcAAAAA69vd2g4AAABTclCSk9sOAQAAAAAAtEd5DgAAAADWqV63f0ySa7edAwAApugebQcAAAAAAADaozwHAAAAAOvXXdsOAAAAU3a3XrffaTsEAAAAAADQDuU5AAAAAFi/7tZ2AAAAmLKrJblJ2yEAAAAAAIB2KM8BAAAAwDrU6/avmuTGbecAAIAVcI+2AwAAAAAAAO1QngMAAACA9ekuSTpthwAAgBVw97YDAAAAAAAA7VCeAwAAAID16W5tBwAAgBVyVK/bP6btEAAAAAAAwMpTngMAAACAdabX7e+f5NS2cwAAwAq6R9sBAAAAAACAlac8BwAAAADrzx2SbGo7BAAArKC7tx0AAAAAAABYecpzAAAAALD+3K3tAAAAsMKO73X7R7QdAgAAAAAAWFnKcwAAAACwjvS6/U1Jbt92DgAAaIHpcwAAAAAAsM4ozwEAAADA+nJakv3bDgEAAC24R9sBAAAAAACAlaU8BwAAAADry93aDgAAAC25ea/bv3LbIQAAAAAAgJWjPAcAAAAA60Sv2+8kuUvbOQAAoCVzSe7adggAAAAAAGDlKM8BAAAAwPpxkyRXaTsEAAC06B5tBwAAAAAAAFaO8hwAAAAArB+mbAAAsN7dstftH9B2CAAAAAAAYGUozwEAAADA+nG3tgMAAEDLNia5U9shAAAAAACAlaE8BwAAAADrQK/bPzLJ0W3nAACAVeBubQcAAAAAAABWhvIcAAAAAKwPd207AAAArBK37HX7/q0cAAAAAADWAf8gAAAAAADrw93aDgAAAKvEgUlu0HYIAAAAAABg+pTnAAAAAGCN63X7W5LcrO0cAACwipzWdgAAAAAAAGD6lOcAAAAAYO07Kf4WCAAAOzu17QAAAAAAAMD0uWAGAAAAANa+k9sOAAAAq8zJvW7fv5cDAAAAAMAa5x8DAAAAAGDtO6XtAAAAsMpsSXJcyxkAAAAAAIApU54DAAAAgDWs1+3vm+T4tnMAAMAqdFrbAQAAAAAAgOlSngMAAACAte3EJHu0HQIAAFahU9sOAAAAAAAATJfyHAAAAACsbSe3HQAAAFapk3rd/oa2QwAAAAAAANOjPAcAAAAAa9spbQcAAIBV6oAkx7cdAgAAAAAAmB7lOQAAAABYo3rd/uYkN2k7BwAArGKntR0AAAAAAACYHuU5AAAAAFi7Tkiyqe0QAACwiinPAQAAAADAGqY8BwAAAABr18ltBwAAgFXuFr1uf4+2QwAAAAAAANOhPAcAAAAAa9cpbQcAAIBVbr8kN2o7BAAAAAAAMB3KcwAAAACwBvW6/U1JTmg7BwAAzIBT2w4AAAAAAABMh/IcAAAAAKxNN0myue0QAAAwA05rOwAAAAAAADAdynMAAAAAsDad0nYAAACYESf2uv092g4BAAAAAABMnvIcAAAAAKxNJ7cdAAAAZsS+aSY3AwAAAAAAa4zyHAAAAACsMb1uf0OSE9vOAQAAM+TUtgMAAAAAAACTpzwHAAAAAGvPDdNMzwAAAEZzWtsBAAAAAACAyVOeAwAAAIC155S2AwAAwIw5sdftb2w7BAAAAAAAMFnKcwAAAACw9pzcdgAAAJgxeye5SdshAAAAAACAyVKeAwAAAIA1pNftzyU5qe0cAAAwg5TnAAAAAABgjVGeAwAAAIC15QZJtrQdAgAAZtBxbQcAAAAAAAAmS3kOAAAAANaWE9sOAAAAM+q4tgMAAAAAAACTpTwHAAAAAGvLDdsOAAAAM+roXre/se0QAAAAAADA5CjPAQAAAMDacnzbAQAAYEZtSnJ02yEAAAAAAIDJUZ4DAAAAgDViYUrGMW3nAACAGXZc2wEAAAAAAIDJUZ4DAAAAgLXj6DTTMgAAgKU5ru0AAAAAAADA5CjPAQAAAMDacXzbAQAAYMYd13YAAAAAAABgcpTnAAAAAGDtUJ4DAIDlObbtAAAAAAAAwOQozwEAAADA2qE8BwAAy3OlXrd/eNshAAAAAACAyVCeAwAAAIA1oNftd2JKBgAATMJxbQcAAAAAAAAmQ3kOAAAAANaGaybZv+0QAACwBhzXdgAAAAAAAGAylOcAAAAAYG04vu0AAACwRhzXdgAAAAAAAGAylOcAAAAAYG04ru0AAACwRhzXdgAAAAAAAGAylOcAAAAAYG24ftsBAABgjTii1+0f0HYIAAAAAABg+ZTnAAAAAGBtOKbtAAAAsEZ0khzbdggAAAAAAGD5lOcAAAAAYMb1uv3NSa7Rdg4AAFhDjms7AAAAAAAAsHzKcwAAAAAw+46Ov/UBAMAkHdd2AAAAAAAAYPlcUAMAAAAAs++YtgMAAMAac1zbAQAAAAAAgOVTngMAAACA2ac8BwAAk3V0r9vf2HYIAAAAAABgeZTnAAAAAGD2Kc8BAMBk7Znkum2HAAAAAAAAlkd5DgAAAABm3/XaDgAAAGvQcW0HAAAAAAAAlkd5DgAAAABmWK/b3zfJ4W3nAACANcjkOQAAAAAAmHHKcwAAAAAw245O0mk7BAAArEFHtB0AAAAAAABYHuU5AAAAAJhtx7QdAAAA1qgj2g4AAAAAAAAsj/IcAAAAAMy2I9sOAAAAa9QRbQcAAAAAAACWR3kOAAAAAGbbYW0HAACANerKvW5/r7ZDAAAAAAAAS6c8BwAAAACz7fC2AwAAwBrVSXL1tkMAAAAAAABLpzwHAAAAALNNeQ4AAKbniLYDAAAAAAAAS6c8BwAAAAAzqtftzyW5ats5AABgDTN5DgAAAAAAZpjyHAAAAADMrkOTbGw7BAAArGFHtB0AAAAAAABYOuU5AAAAAJhdh7UdAAAA1rgj2g4AAAAAAAAsnfIcAAAAAMyuw9sOAAAAa9wRbQcAAAAAAACWTnkOAAAAAGaX8hwAAEzXEW0HAAAAAAAAlk55DgAAAABml/IcAABM17Zet79n2yEAAAAAAIClUZ4DAAAAgNl1WNsBAABgjeskuXrbIQAAAAAAgKVRngMAAACA2WXyHAAATJ/yHAAAAAAAzCjlOQAAAACYXcpzAAAwfUe0HQAAAAAAAFga5TkAAAAAmEG9bn9zkoPbzgEAAOvAEW0HAAAAAAAAlmaPtgMAAAAAAEtyWNsBAABgnTii7QA0aq3zgw6XUp66UlnWilrrqUneN2DJaaWUM3b5mAcmeemAj7lGKeVby4wGAAAAADARynMAAAAAMJsObzsAAACsE0e0HQBgltRa907yG0m2Jdk/yV5JzklydpJvJfl6KeWS1gJyOW4vYFbUWg9O86JyhybZL83jVZJckOYx64dJvltK+Uk7CQEAgNVKeQ4AAAAAZpPyHAAArIwj2g4AsJrVWjtJbpXkzklul+TIJJ0BH3JRrfXTSd6e5C2llM9NPSSXcXsxqlrrIUmun+R6SY5Jcp0kByXZsvC2V5rS0rlJekm+n+QLST6T5MxSyndWPDRXUGvdkuSWSW6a5jY8MsmBacpnm9Pchuck+VWS7yT5RpKvJ/nfJB8rpfxy5VM3aq3HJLljktOS3DDJISN+3I/T5H9fkreXUj4/tZAAAMBMUJ4DAAAAgNmkPAcAACvj0F63v2nb6VsvajvIUtRav5Xk6iMu/8tSyjOmGOcyI+S6RinlWyuRBViaWuseSR6c5NFJjhrjQzelKXHctDlNPSPJ/yulvHviIdeRWutfJHn6FE498u1Va31qkjKFDKP6YCnlFi3unySpte6Xpuhz4yQ3Wfjfaw35sAeVUl425WgD1VoPSlNSulWastUo39f7LLwdkuQGSW6/0/m+nOQ1SV6+Gn+mz+rtNIpa675J7p3kQUlOSLJhwPIdt+GV0xTrbrXTsfla6xeT/HeaAu0ZpZQLpxJ6Qa11U5IHJHl4kmOXeJpD0pSDb5fkWbXWzyR5TpJXllJm8jk9AACwPMpzAAAAADCblOcAAGBldNI8//5a20FWwBNqrS8opfy87SDA6lZrPSFJN01ZZrlOTXJqrfXNSR5eSvnBBM65rtRaj0ry5BXa7tS4vS5Ta90ryXH5dfnqJmmme821GGtktdbDktwrye+kKUgOmkI4ruskeWqSJ9daX5ekllK+MsHzj2zWb6dRLZTmHpfkMWkmyy1XJ8nRC28PT3JurfWOpZQzJ3DuK6i13iPJP2T0F34Y1bFJXpzmvvjoUsq/T/j8AADAKqc8BwAAAACz6bC2AwAAwDpy9ayP8twBSf4syRPbDrIe1FqPSPLNAUtmYrrNYtb657ee1Vr/JMmzk2yc8KnvkeTEWus9SykfnPC5d6vWemqS9w1Yclop5YyVyLJUtdZOkn9JstcKb73it1fbaq0bk1w/l59Udr3M4DV4tdaHJ7lvmqlkkyzM7c6GJPdL8tu11mcmeVop5ZJpbbaWbqdx1Frvm+ax+ZApbrNPkitN+qQLpb8XJvndSZ97F0ckeUut9eVJ/qSUct6U9wMAAFaJNfXKKQAAAACwjpg8BwAAK2dr2wFW0CNqrYe2HQJYnWqtz0ryvEy+OLfDlZO8r9Z6lymdfy36oySntLT3eru97pjkk2mmLj44zSSzWS1k/W2Sm2X6xbmdbUrylCRn1FqvMsV91tLtNFStdb9a678leXWmW5ybilrr1iRnZPrFuZ39fpL/qbUeuIJ7AgAALVKeAwAAAIDZZPIcAACsnC1tB1hBm5M8ue0QwOpTa31KkieswFYbk7y+1vpbK7DXTFsoO/9NyzHcXozrxCQfrLVeq+0gs67Wui3JWUnu33aWpai17pfk3Ulu1ML2v5nknbXWzS3sDQAArDDlOQAAAACYMb1u/6A0F7QCAAAr44C2A6ywB7ugHdhZrfVuSeoIS+fTFCEenOR6acrHG5McnKYw88Qk/zfCefZMU8g6Yvy068rzsryfURO9vbK+yubrzU+SvCfNNLcnJXlkkj9J8pdJ/iHJu5KcM8b5jkjy37XWK0825vpRa716kg+lmaw3qm8keVOSZyV5fJKHJnlUmsf35yR5R5LeJHMO8dKMnv/cJP+W5CFJjk9y1TR/I987ydXSFPD+JMlrklww4jlvmuY+DQAArHFrdhw5AAAAAKxhB7YdAAAA1pktbQdYYRvTXEQ9k1NMgMmqtR6epuAwzCeS/HEp5ZO7OfbTNCWPDyV5Vq313mmKGocMON+Vkryu1npiKeWSMWOvebXWuye5+zJOMY3b67eH7PlHSwk6hpUs/ax156cpxL0zyXtLKd8Y9gG11j2SnJZmQuUokwivnuTNtdaTSymXLifselNrPTDJfyW5xgjLv5bkX5O8ppTynRHPvy3JKUnumuQOmcILSdRafyfJPUdYekGSpyV5finlF4us+f7C2/8meUGt9eAkj0hTAN445PwPqLW+vpTynyMFBwAAZpLyHAAAAADMnv3bDgAAAOvMlrYDtOC+tdZnlVI+13aQHUopnbYzrDWllDOSjPV1LaW8LMnLphCH1es5Gf44+Mokf1hKuWiUE5ZSXldr/UCaYs71Byy9aZpJQs8Z5bzrRa31gCTPXeTweWkmMQ3yliT3mcLtddUh5/nXUfZbY36V5FNJrpNkW8tZRvHBJC9K8uZSytnjfOBCyfU9Sd5Taz01yauSXGXIh908yWOT/M3YSSdrZm6nWuvGJG9L8htDlv40TXnspeOWE0spvSSvS1Ng3pjk9kkeltFKkUMtFC2fMcLSryW5Zynls+Ocv5TykyRPqbX+R5I3Jjl8yIc8s9b6jlLK9nH2AQAAZsdc2wEAAAAAgLEpzwEAwMra0naAFswleXrbIYB21Vpvk2by0CBvTvL7oxaxdiilfD9NEWPYRKtaa906zrnXgb/N4qWkYcW5JHnsFG+v9ey8NOWzf0rygCTXTbKllHJqki+3mGuYS5K8IsnxpZRblFJePm5xblcL5ezj0kwvHOZJC5PCVsqs3k47PC3JiUPWnJXk+qWUf13uVL9SysWllLeVUm6T5OgkYxXZFnGnJNcasubHSW4zbnFuZ6WUjye5TZKfDVl6TJJbL3UfAABg9TN5DgAAAABmj/IcAACsrC1tB2jJnWutNy+ljHLhO7A2/dWQ499I8qClTusppfy41nrvNAWbjYss25LkMUn+fCl7rDW11pOTPHiRwz9NctAIp5lfyt4j3l7rxYVJPpPkEzu9fWG5RaUVdkmSlyb5f6WUb0765KWUfq31zmmKaoOmpO2X5JFJnjzpDFkbt9NlFib6PX7IsrcmuXcp5cJJ719K+dKETnW/EdY8YBL3y1LKl2utD0wzrW+Q303yruXuBwAArE7KcwAAAAAwe/ZrOwAAAKwzW9oOMEXvSnLbAcefkeTUlYkCrCa11lOS/OaQZQ8rpfxqOfuUUj5Ra31ukkcPWPbHtdZnLHca1qyrte6V5EVJOrs5fE5GK84ty4i311r1lSSnpylgfa6UcnHLeZbjLUmeWkqZ6qS1UsrPaq13TfJ/GVy4/P1aa1lqEXcXa+l2ukytdWOSF6aZDryYD2ZKxblJqbV2ktxyyLL3lVLePak9Syn/UWt9f5KTBiz7rUntBwAArD7KcwAAAAAwe0yeAwCAlbWl7QBT9FdJTk6yeZHjp9Rab1tKMYkD1p9HDDn+vlLKOye011+lmaa22AsGbUnye0meN6H9ZtWTkxy1yLGvJjl+hXIMu73WpFLKF5J8oe0ck1BKue8K7vWVWuvz00yXW8xhSW6YpvC23P3WzO20iz9Ncp0Bx3+W5F6ruTi34IgML/q+aAr7/ksGl+cOrbVetZTy/SnsDQAAtGzQq5AAAAAAAKuT8hwAAKysLW0HmKIfJHnukDXPWJgSAqwTtdYtSe44ZNnfTmq/UsovkvzrkGX3n9R+s6jWev0kj1/k8MeSHL1SWUa8vWBnfzfCmlOnHWJW1Vr3SVOeHeSRpZQfrkSeZbrWkOPzSd4zhX3fvXDuQa49hX0BAIBVwOQ5AAAAAJg9ynMAALCyDmg7wJQ9M8lDsvjnecMkD621vqCUMuyiY2bIQiny6kkOSXP7759mktTFSc5beDsnyfeTfK+UcklLUdeNhYLEdZJcLc1tsSHJ2Ul+nuQrpZQfrFCU306y54Dj303yXxPe81+SPHrA8RNqrdcqpXx9wvuuerXWuTRltY27OXxJknckuemKhhp+e8FlSinfq7V+JsmxA5Zdf6XyzKAHJzlwwPFPJnnVCmVZrisNOf6DUspPJr1pKeXHtdZekkMHLDt40vsCAACrg/IcAAAAAMwe5TkAAFhZm3vd/qZtp2+9qO0gU3DVJL+X5FcZXBJ8XpLn1VqTZHuS85P8NMn/JfmfJB9M8vFSyqW11r2S3GLAuT4/gdxJLpuOddLCftdNcs00RbB90hR/zk9y4cL/bk/SSbJXkk0Lay5dOH5RmsJYZ+HYxiR7L7zv3IXP9RtJvrzwuZ5VSvnRTjmuluQuacor10vzdd1/IcN5SX6S5JtJPp3k/UneNeLnt0eSU5LcOskN0pSqrpSmVHVJmmLbd5N8NcmHk/xXKeVLu5zjyCR3TnKjhWyHLWSbW/h8R3VprfV7Sb6WZsrVR5J8dOevwzTUWjckOT7JiWmKnNdMcniaz2GfhWXnJvlZmq/xjtvojHGLZgvFtRMW9rpekmukuS33zeXvDz9Oc3/4XJIPpLk/nL2Mz/HoNN+Ht01TLFn0dln4Hrwozef78TSf69tKKV/cZd2V0tzmO2xK83U8Pr8uTO638HZBmnLet5N8L833yi2HxP5cmq/LFT7vha/jjdN8T944yc3SlBX2SfO9tfPnd/HCOb6V5L1p7l+DJv/cKck/Dcm2Fj0yi5fjfpbkz1cwS5KklPKlEcpQsLOzMvj+cs2VCjJLFn4OPmrIsqfN0AscDCpmJ81zpmnpZ3B5bvMU9wYAAFqkPAcAAAAAs0d5DgAAVt6WNIWZteasNCWqccylKcHsk6bEdIeF959ba31nko8m+dsBH/+gcUMmSa11KReF77vwtpg9Mvgi7g1pynYHJTkqye3SlFi211rPSvKpNOWgkwacY0dB6RppCkmPGTH7SxfeBmXfK82UlOOT/E6Sf1woV/0kzYX2j104Ngkb0pSurp7kVjveWWs9N8l8Bn+dd+eltdZBn984tiy8XXMh258kmV+4jV6c5DW7m5pXa31qkjLGPjvfH66b5I4L7z+/1vqfSZ5XSjlz4dxnpCk+7s6ZpZRTa603SfL/stPXc0SbkmxLU4q8c5Jn1lo/nuQvSinvXVhzbJL3jHi+Hd8nh42R4Q5JflhrfVmSZ6T5epy28HaT7H5C2u5sTDNN6cA05chhbp0llueG3CaLed/C99RSnFlKOXWpH7xDrfWIJE8bsOSQ5e6xDG+P8hyj6w05vmUlQsyg05IcMeD4N5P8x8pEmYhfDjl+7hT3HnbuX01xbwAAoEXj/gEcAAAAAGjffm0HAACAdWhL2wGmZJLXDeyT5LczuDi3VswlOTXJozO4ONeWg5O8MpMrzg2yT8Yvzq2ETpqi1CuSfKXWes/drLn+hPbanOReSc6otZ5Vax1WJpqrtT43TdF03OLcYm6S5D211tfWWvdPU7Cbtn2S/GmaaXXvTfKXSW6e0YtzS3HKwkTGdWFh4tQ78uspi5PyL7XWa0zgPKMWNCFppn4NYurX7t1nyPFXlFK2r0iSyfjpkOMHTXHvYecelg0AAJhR6+aPSQAAAACwhpg8BwAAK29L2wHWs1rrgW1nYKZdI8kba63/nuSBSbYmeVGaAuSknZTkE0m+P2DNDTO90uW900wCW8kSSmcF99o3zZS7z63gnq2otd4oyZvSTHuctFsn+b9a6+NKKS9Yxnk+muTSNFMZYZi9hxy/YEVSzJCFAu09hix7w0pkmaAvpZlYu9jPjitPY9Naa2eEc39zGnsDAADtU54DAAAAgNmjPAcAACtvS9sB1qta69FJ3tZ2DtaEuyX5Qprfq6c5LW+PDC48TXqK2K5+Y8rnb9tna627vu+0UsoZLWSZilrr6Umek+lOENw7yfNrrTdM8sellEvHPUEp5fxa6xcy4hTHWuv8Tv93Td1mjORqQ47/fEVSzJYbJ7nSgOPfKaV8fqXCTEIp5WcLjxvHLLJkS631+qWUSZekj01ywIDj3yyl/GDCewIAAKvEXNsBAAAAAICxKc8BAMDK29J2gPWo1nr9JGcluVbbWVgzrpLpFudgWWqtz0rywky3OLezByd5xcKEq6X4zCTDsKbdcMjxr69Iitly6pDj71uJEFPw9iHH7zCFPe845Ph/T2FPAABglTB5DgAAAABmj/IcAACsvEGTKpiCWuvVk7w3yUFtZ1mCi5K8KMmNkpzQcpbFbE+Tc68R11+c5D+S3DTDpwdN29lJnp3kZ0kuTXJIkisnOTHJ0VPY76VJPpnma3VIkqsmuWWSQ6ew1w7nJ/lIki8l+W6S6yW53xT3m5aLknwnzW310zS33f5JtiU5Ks30MxbUWv82yePG+JAfp3mMXGrxbYf7JekleewSPnaphacttdbfzK8LrRvS3O/PS/LDJN8tpfxoiedmlam17p/kFkOW/d9KZJkxpww5/sFhJ6i1dtJMQz0qzYtB7J3kwiTnJvl+km+XUn6yvJhje36ax5vFHrseVWv951LKeZPYrNa6b5JHDFn2gknsBQAArE7KcwAAAAAwe5TnAABg5W1pO8ASjVtMuSjJ69JMhzlmwLqXJjk8ya2WmGuYPZO8Kk1RaRZtSnKnNF/LpZbnPp5mCsoTB6w5M8lJSebGOO+laS5a/5sk187oU2s2pim2PDnN7b+YJ6YpSR2U5JkD1r0+ye0y+u+4X0jyz0kuSXJ2KeV1u1tUaz08yR+kuSh/UhPmXlFKOWM3ex23sM/9Mt5tMMiHk/xlkveXUi7Zaa8HZnrluZ+n+doekeT+Gf65XJLh1xx9KsmfJPlYKWX77hbUWufSTBf6pyTXHCPvUv1tklcu/PeLRvyYv0vy5SXu98NxFtdaH5LRinNnpyl5vCxNKbE3drLde0yt9aOllNeP+XFfW+J+bxm2oNb6izT3pQ8leUeSjyx2f2LVu2eGT1M8cyWCzJhjhxz/9O7eWWvdnOReSe6a5Lcy5GdtrfX7aX7+vCPJW0spPxs76RhKKd+utb46yQMWWbItyZOS/MWEtvyrDH5OeUYp5X8ntBcAALAKKc8BAAAAwAzpdfsb4lXZAQCgDVvaDjCuWuveSQ4ccfl8mjLJY0sp59Rab53k3QPW3zfJkWmKL8/L5K8/eFSaqW3LMZ+ks/woS3b1JHdcxsc/P8kZGVyeGzaRZleXJrldKeW9SVJrvfaYH3+fJMMuLn9dKeVbtdYjMrg8d5OM9+IwHy+lvHDYolLKd5I8tdb6/DRfw3uOscdYSimfTvKAhWlhn1nm6c5Jct9Syn8uO9h4XpLkCaWUnyZJrfUTSZ4z5GP+L8n1M3ja2b5JPlpKmV9swUIJ6j9rrf+d5M1pypRTU0p5+47/rrWOWp57++6Kk5NWa71xkueOsPSjSW5TSvnVwsdNerLl82qt/zPmFKrvTzjDzrYkOW3h7S+T/KDW+uIk3VLKNPdl8h455PgP0kz4ZEGtdUuayYyLmc8u0/oWnvs9LsnDkxw8xnZXTfLbC28X1Vpfk+RvSymfHyfzmB6d5DZpJsfuzp/XWr9USnnFcjaptf7xwl6LuSBN2RsAAFjDJvWqVwAAAADAytiv7QAAALBObWk7wBI8JoPLLTuck+TUUsrppZRzkqSU8p4Mnki2V7Os/EuaQtWkJwE9eBkfe0mSb2d4ce7ry9hjh0WLQQsGTe+bhmGTYjYk+eYyzr8h4xf2FnONCZ1nt0opP04zdedb09xnYa/PLvMUP0tyXAvFuaeUUv5wR3FuwSiFpOPSFF0GOTJN4WmoUsr5aUqOnxhl/VpTa92UZprjxiFLf5TkljuKcwsGFWuW4uAkzxjzYyY1+W4UV0kz/fJrtda/XSgXscrVWu+d4RPUXm2q4BUcPeT4DxceP5MktdbbJvlikprxinO72pTk95N8ptb6vFrrOEX3kS387Ll/mqnHi3lprfUZtdaxX6Sh1rpnrfXZaSZ1DvLEUsoXxz0/AAAwW5TnAAAAAGC2TOViBQAAYKgtbQcYR611c5I/G2Hp2UluUko5azfH/nzIxz6o1npUKeVNaS7UnqTlTLLrppn6NsgZSa6b5DXL2CdpCnrDCnRLNUrxcWfvSfLeEdb99hKy7Owmy/z4lXSvJEe0HWKIC5IcW0qZRJlzHC8vpTxtN+8/aMSPP2yENSPf10op5yX500zv+2k1e1SS642w7g8Wvk47G/X22tWgwtsDa63jlFt/vMQMy7FXmula/1drnerEQpZnYRLaoCmkSVN6H2Xy4noz7HH2sjJ8rfVJSd6R5PAJ7r8hzUS2/621Hj/B815mYRLu76S5D+zOXJrno5+rtT5k4f40UK11v1rrw5J8PsMnHj6jlPJP42QGAABmk/IcAAAAAMwW5TkAAGjHrD0Xv3+SfUdY96BSypd2d6CU8tEkbx3wsRuS7CjfPDPJl8dKOB1/neSEIWt+meQ+pZSL00y4+/Yy9+wv8+MXc60xM/xehpcGk+S2S4tzmUOX+fErotY6l8mXOqfhwaWU77Ww7ysWef+BE9xjrFJTKeVjGfyYs+bUWvdL8oQRlr6hlPKO3bx/qbfXw7N4WWVjhhdOdvar4Uum5qpJ3lFr/csWMzDYMzO8xPyKUspyfxavRcN+3n4/SWqtf5/m+di0rgW9VpL311p/axonL6W8Nc2k0u8MWPYbaV4c4ee11g/XWp9Ta31SrfVPa60Pq7U+udb63Frrx9NMc/3nDH4edUmaiXMeOwAAYJ1QngMAAACA2TJrF+wCAMBasbHtAGN63IjrPjnk+F8m2T7g+L1qrceXUi5KU8YYxSgFr6X4YpK3J7nRkHWllPKjhf84L8ljlrnvIZlOge6oMdY+rJTSy2gTEn+z1rqcyX6z4u5pLrZfzT5eSnlVS3sv9n19pQnucY1a67hly9dOcP9Z8JAMnx73yyxeZlvq7fWJJK8ecPx3a62bRjnRQhH5giXmmIROkr+utT6/xQzsRq31VkkeNmTZ2Wmea3BFwx4/f1Jr/Yss/3nMKPZJ8p+11pOncfJSygeSHJtmAuGFA5ZuSvMiCQ9PUxh8bpqi3F+lmV564wyfXvz5JCeVUp61zNgAAMAMUZ4DAAAAgNmiPAcAAO2YmX9fXyirjFO8WlQp5fNJBpV7OkmesbD2PUk+PcJpb7r8ZLv12CT3G7Lmi0met/M7SilvHuHcl2RhwssiPjrCOcZ12Ijrvp7kjQv/3Rlh/d5JjlxSotnykLYDjGDUwumozpnAOfYac/1i08t2OG7M8709yUVjfsws+6MR1vxFKeWHixwb9/ba2bOSzC9y7OAktxzjXOcuYf/7LeyzKckBSa6Zpvhy3yQvTPKFMc/30Frr3ywhB1Ow8Fzk1Rn+c+kpC+VvruiAIcePza8nAC/ms2mm8p6a5mf/vkn2W/jvUxeOfXbEPHsmeXOt9Zojrh9LKeUXpZSHp5kY96w0z28m6X/TPL7coJTykQmfGwAAWOXWwyuJAQAAAMBasnfbAQAAYJ3a0HaAMdxhwucrSe6dpuCwO7ertZ5cSjkrySszvCxzvSxe2FiqH5dS3llrfeGQdd1SyrCyz+500nxuf7bI8asl+UmaIsikjDqx6zmllB1TxH424sf8Rpoi4ZpUa71Kkt9ayT1LKZcriNRaz0kzqWcxvVLKpEuXH8t4hafdGWna2E7em+R2A45fJ8k7Rz1ZKeWcWutX0jxOjOILpZRjRj3/Tvt0kqTWemqS94378ZNQaz0hzddnkI+mKZItZtzb6zKllC/UWj+U5MRFltw2yX+NeLphj6v3LaUMmip4cZJfJflmmomor02SWuv1kzwhyX0y2nVuj6+1frKU8roR1jIltdaNSV6XZjLrIGclec70E82szUOOL/a9myRfSvLIUsq7Fzn+tYW3M5M8udZ62yTPzvCJrQclecXC875Bk4mXrJTy/VrrXyX5SJqphDde5ik/k+T0KfzMBQAAZsjMvDIeAAAAAAAAALRolspzp0/yZKWUbyZ50ZBl/2/hf1+dZNjF1IdltAlp4/i/Wut1khw+YM0lSV6zxPNvSPKLAcePTTLKBLtxHDjiurfs9N8/HvFjrjZmlllz+7R/Tcyw+/gbJrzfl5J8fALnGbeM9aoMLsMO+p5czDgTx46qtS65QNayOw45fmmawsegx9Tlfu5nDDh2yhjnGVaeW9LP0FLK50opD0hT6Bn1/v2iWutVl7IfE/P8JCcNWfOrJA+cVgFrjVjqZMmXppmutlhx7gpKKe9KcoMkLxth+YlJ/nhp0QartV671vqvSX6a5vnNcotzSfMc7YO11rNqrb9fazVwAgAA1iG/CAAAAADAbHFBCQAAtGOWynNjT2EawV8neVAWn4Z981rrnUop/7kwNWrQ5JJOll/42NUXM/xC/feWUkYtl+3OldKUWXZ3X+gk+d9lnHt39s7w6zp+lOQ7tdZxzz1sGtCsGzQJbaUMu4+fNeH9Ppzk6xM4z7ilwzOT/DDJVRY5vnUJGb42xto9klw1zcSyWTPsfvqPpZTPDFmz3JLo+wccO6bWurGUcvEI57l0yPFl/QwtpXy91nqLJH+b5BFDlu+X5B/STExlhdVaH5PkwSMsfdBCOX85e52RxUueZ5ZSTl3O+VeBjUv4mOcleXgpZewJv6WUi2utf5Dk3CR/OmT5U2qtLy+lnLuEjFdQaz0gzeS7B2Q6z7k3pHmeeFKSp9Zan1ZKeckU9mEKRpgSe1op5YwVCQMAwMxSngMAAACA2aI8BwAA7Wh7itVIaq1zWbzgtmSllF6t9Z+S/PmAZU+vtb49yWcyuDyXTL4895M0k0UG+cAy9zhmYZ8rL3J8jyTnJ9m8zH126CTZZ8iaLwzIM8hxtdZJT/9bTX5zwLFJ3ka7VWvdluHX5AwrG43rI0nOnsB5hk0Q29kPSinfrbUO2veAhcelw9LcV7cm2TfJnmmKIbu7Hw57/NjVoZmx8lytdc8kxw1Ycn6Sp45wqnFur9359oBjm5IcmdEmAQ67v49SwBuolHJRkkfWWn+epAxZ/ju11meMUD5kgmqtv5Om4DjM35dSJj2tdS0a9+fEB5M8YinFuR1KKfO11kckOT7JzQcsvXKS30vygqXutUOt9aQkr8zSJpUuxRFJXlxrvXuSPyil9FdoXwBgTLXWfdL87D40zQsa7ZXmd48L0hT+f5zk+0m+t5znQCxfrXX/NL/LH5LmBU02JTknyS+TfCPJt0yd3r2Fv5kckeSaSQ5I8zeTi9L8jefHSb5USvlVawHXEOU5AAAAAJgt/qgMAADtmJXJc4dO8dx/k+SP01ywtDs3SHLfJJ/O8Ik/434957P7ks3Orjfk+KfG3HNX10/y0yxeVrtqks8lueky99nZsJLhj5Z43jsl+XIGT/GYSbXWg9IUtRbzi0y5PJfkWiOsWcpEtkG+m8k8Tl00xtrvLfzvOQPW3DJNEWzShdmdHTTFc0/LCRl83dY7RpzoNM7ttTs/HXL8ahmtPDdsQtZyc16mlPLUWut1k/zOkKWPSzPFihVQa711kn/L8BcbeEuSJ0w/0ZowzvfNeUkeOIkLkksp22utD0zzfG7QCzI8NMssz9Va75TkTRntZ8S3k7wrzeTWz6Z5/PppmsfSA5McnORGaabL3S7Dp+zeKcn/1lpPKaV8Y0mfAACrXq11vzQvhHO9hf89Os3v9FsW3naUVM5P0k/ygyRfSfOiQB9K8lmlrJVTa71ykrsmOS3Ni+IckeF/C0qSc2qtn03zPOFdSc5S1JquWuseSe6Y5jnVrZNcfciHnF9r/ViStyd503p//lVrvWaSe6b5Gt40Q/5OVWv9dpJ3J/nPNH8vWO4L6axLynMAAAAAMFv8oR8AANoxK+W5k8Zcf+9a67DyxM7el+QeA44/O8ko02TGvV5h2MVSN0xzIdwg1621XmXMfXd2tQyebnXVNAW9lSzPLWfS2JELb7PiyFrrg0dYN6y4tpTJjHestV57jPU3GmHNVZeQY5CfZzKlwHEmhP184X8HlbyGTU+chGmXIafhqUOOnz/i/f06S9x/x2P/sJ9to95PV6w8t+CP0xQzDx6w5p611j8esYTIMtRaT0hTihv2M+t/ktzXhcwjG+f75iWllK9NauNSyldrrS9L8icDll2/1npkKeWrS9mj1nq7jFac+1ySZyR5Qylld9P4Lkzzc+i7aZ6H/Wutda8kD0zyxAy+kPtqSd63UKD71lifAMBOaq0b05SzbpLkxgv/e70M/r335aWUB04/3eXVWk9N+y+isnFaxY+FnwEnJrlVmueLN87w57ybF94OTPP8+rSdjvVrrW9K8rJSykcnn/jyaq1HJjll2vss0Q9LKW+fxolrrbdJ8pgkv5Wl/f1t3zRTc2+e5uf/D2qtL0ry3FLKTyYWdMpqrScmeX9GKww+qJTysukmuqJa6+Ykj0jy8Iz3d43Nae7bpyR5Zq31P5M8vZTyscmnXL1qrb+Z5C/SlA6HvfDIzq6e5I8W3r5fa/3nJM8ppZw/+ZRrl/IcAAAAAMwWr24IAADtGOeChjaNW9x65oT335rk9BHWjXIh0DjuPMKav1vmHnMZXMzaP80klEka9nVaTnlu1uy4EG65DljCxzxuAvvuav8Jn+/nSfaawHkGTZG7wp611k6SbRPYdzn2bHn/sSxcsDzsgtj7L7xNy6iP/aPeT/cbcnyc+9VQpZSf11qfnuQfByzbnOQOSd4wyb25vFrrsUnekeFF2Y8luWsp5cLpp1ozxil+LmsC3CKen8HluaSZlPHscU9caz00yasyvDj3z0keV0oZq4BbSrkgyQtrra9J8uI0Uz0Wc3iSN9VaTyiljFMgB9apWutckuvm8kW5YzNjz0nXklrr/mmmlf1OmglYk7wttqZ54YY/rrV+MMlTSynvneD5d3VikhdN8fzLcWaaqWETs/Bc8p8z/gtBDXOVJCXJY2utT0vyj6v953ytdVOa237Sfy+bmFrrHZI8L81EwOWYS3KXJHeutf5rkieUUn6xzHOuarXWLUn+JsmDs/zb+Kppfqc/vdb6p6WUdy7zfOuG8hwAAAAAzBavzAwAAO2Ylclzh7cdYESzUkYcx+Ykv1rhPVf1xV8MNOlpaZMqpPxsjLVzSf47yVET2nupZuXxecckjH/JKr4gchdD76e11r0z/DYY5341qn9N8tcZXNo6Lbspz9Vaz8jiBcYzSymnLjfcelBrPSrJu5NcacjSzyW5fSlloiXKdWDU75uPl1K+MOnNSymfr7V+PE0pZDE3yxLKc0lekma6zyCPLKU8Zwnnvkwp5ZdJfrvW+pw001EWc8MkT0pzkT3A5SxMAttRkrtxmseMlZiuzBC11tunefGe22VlyosnJnlPrfX1SR5WSumvwJ5rVq318UmenuFTrJdj3yTPSvN84N6llG9Oca/lelKaYu6qs1Aa/qskfznhU3fSTFI7tdZ6t2k8p10Naq1HJ3lrkmtP+NTXSPL2hReWeUopxYswD7EW/xgNAAAAAGuZ8hwAALRjVsoZk55mxej2TPLLtkMwM1brZIqfjrH2jmnKSYyuJDmy7RBjGOV+umWENePcr0ayUMR6x5BlN5v0vjRqrUekKc8eMmTpV5PcupQyjQLlWjfq980Hp5jhQ0OO32jcE9Zab5mm5DDIc5dbnNvFozJ8Us6f11qvMsE9gTVgYVLQV5K8Osmj00zHUpxbPR6ZZuLcSv9u9TtJPlVrncRk9FkykX+jrrVuqLW+JM0UrmkW53Z2kyQfqbUev0L7jaXWekySP2s7x+4sFOdemckX53Z2ZJIP11p/c4p7tKLWekKSj2TyxbkdOmmKl69cuK0YwOQ5AAAAAJgtynMAM+qiDR/45Dmb//mczs8OOLczP7dftm7fPn/A9v2yZ64238nWhWXzOw2hmJ//9TyKy78/O78/O63v7Pr++flc4X2Lrc38oH066Yx6vsvnW+x8nc6u77vcuTuLvP/XJxy25/xlm3cG5L78np2FBbvLPZ+F/XZ5+c7d5p6//DCRRdYkO2Xd6Xhnpxy7P8d859dfh8tnXci4+/tOLvf17lzx63qFz/2yfTq//jrs+EJ0rnD77XTb7Hh35/K32RXPfdl+8wNv385On292+hyveB/Y/efVudzNtst95wpfy/md7g87fe6/vvE6i37NRjn3Zf95ua/Zzp/jFe8jlz9fZ9evybBz75Tjcvfj3dw3rnDudC73OXZ2vh91Lnef2uW+u9vPrbndd7k9Lvf12/nIbr7nOp3LfT47BWv27Az43BfeP99ZPN+O9893LrvvXnZ84/ZLfviXeWRmwGot5OxqVqYujaMT5TlGt1q/B34yxloXDo+h1npskse1nWNMo9xPDx1hzcTLcwvel+ReA45fZ0r7rmsLBaP/TnK1IUu/neRWpZQfTT/VmjTq4/FHppjho0OOH1Fr3VBKuXSMcz52yPEfJHn8GOcbqpSyvdb6kCRfy+ITNTcm+dNM98JwANaOqyb571rrb5dShhW014ozJnSebpIHTehc4zgkyXtrrTcrpXylhf13a6Hw9K9JNrWdZREvSnLfFdhn/yTvrLWeWkr57ArsN3ULfwN4Z5L9VmC7+yU5P8mDV2CvmaU8BwAAAACzRXkOYAZdvOGTnzlvz3+87tx89r742J+eNX/Bngfs+dYDO3MXzl0/Seb3mv9JDr70u/NX3n52Dt7eyX7bD8zGXD3Jvr8+y/wiZ89YSwBYss/lKjNRnvPToF2rtRAFo/rOhM83n2Yq0ifTTO34ZpIfpSmFnLvwdkkp5ZIdH1Br/Yc0kz3WjFrrhjQXRK7Fa7WuPOR4v5Ry/pT2/tSQ45trrVdW3pqcWushaYpz1xyy9IdpinPfnX6qNWvUx+MvTDHDsHNvSFOg/d4oJ6u1Hprk9kOW/XUp5YJRzjeOUsoPaq3Py+AS80NqrU8upfgbPMDadF6ST6eZjPutNC9+c16a0s5BSY5IckqSbSOeb68kb6613rqUctaEs64225O8bLknqbU+LMkfjrHnu5L8T5ppuN9P8rMkFyQ5cOHt+CQnJrlnhv9ekoWPeVut9fgp/o4yroclOaHtELtTa31Ukj8YYenFSf4zyRuTfCLNiyFcmORKSY5OM7H+AUmuMeQ8V0ry77XWG5ZSfrG01KvDwuTSf89ok9q/keQVaQqqX0jyizSPL1dJMzXxnknulOF/T/jDWuvnSin/tITI68Ja/IMMAAAAAKxl/uEeYMZcMvf5L5y75zOukU72TpKN38nJFx154ZnnP/qHp+zxqb0/uvG9Ww7pXNC5Rr63x8GdnS43m8/8fPab/162bv/B/JUvPT8Hbt+Yfea3ZkOOSCcb2/p8ANaxWXkufm7bAda5/dsOMKKPpLmY6bcyO5lZGd+c8Pk+UEo5ecyPOWjCGVaD+ya5cdshpuTqQ45P+j61s2+NsOaQNIVNlqnWemCS9yT5jSFL+2mKc1+ffqo1bdTvnV9MMcPPR1hzYEYsz6UpJAx6oYFLk7x6xHMtxSsyuDx3cJLrJ/nMFDMArHZ/l+TLU95jnImlyzGf5ANJ3pGmhPXZUaal1lqvn+RRSe6f4dPANiV5S6312FLKqD8PZ9F7SinLeqGVWusRSZ414vKXpSnUL/Z88kcLb19M8upa62PSTN56Zprn/4NcJ8nTsgqmgtdaD0/y9LZz7E6t9UYZ7fZ6d5KHlVK+uptjP154O6PW+rQkf5TkbzN4iv01krw4TWFslr04TSF3kHPS3A//dTePTReneSz+cpJX1lqPSvK8NH/HG+Rvaq0fKKV8cvzIa5/yHAAAAADMllm5YBeAJJfMfe2r5+z1lEPTufxF6Zu+mlMu3JSzLjn+vJMvOfa8Szaetf9Ze3x039/ozHcu+4fdTjqdnN25Ws6eu1rnG7/+J535zvzFudL2r2Xr9v78lbdfmCtt3zub57elk8PSMe0GYIpm5bn4T8dcf41SyreWulmt9UNJbjbmhz0oyVMzvHAxjmck+YsBx3ullEMXO1hrHXVi37GllM8OOM+DRzxP275cSnlgrfW0NK/iPgteXkp54K7vrLW+LMnvj3Geu5dS/n3hY5+apIzwMaeVUs4YdYNa672SvH7Akq/v7nNZDUop59Za+0m2TuiUS3nsHGViwKw5eMz1f5Vk1Ild/5BkvzHP/8QM/nlxdinldSOe68ghx6dZnvvlCGv2nuL+60at9YA0F53fYMjSnye5TSnli9NPteZ9P81klb2GrPvFFDOMcu5xvsdOGnL8o6WUUb6vl6SU8rla6w/TTMtbzElRngOW56Ik/5dkY5pC7qx5+zi/+6xSX0/yoiSvWkqhrZTyuTQTnP4qyWsy/G8eByb5lyR3GHev3ez9skxgwts4aq33S/KqIctePIGtnprhzxvOTfKgUsobxjlxKeXCJC+ttb4zTRH/tCEf8rBa6z+tginJL0iy727ef3GSXpLDVjZOo9Y6l+Y+Paw8+qwkf15KGfo3tYVp8y+otZ6Z5veKqw1Yfo9a611KKW8bNfNqUmu9W5J7DFn2nSS3LaV8aZRzllK+Umu9bZqv+aDi56Yk3VrrTU1TvqK5tgMAAAAAAGPxR06AGXFp57vfOmevJ25JJ1fa3fFNn88tOhfkI5nLHhef+quTz3/0D/e55LrnnTmf+bMHnbcz39nY+dmGa3e+vPFmc2fteercWzffdO61ex/eecPm8zrv3fPz+dweH0hv7sxckE9lPv3pfHYA69KsPBf/ygrvN6iwtpIuTnL+gOOTmq427GfrARPaZ6WMWhocx2ovqlxjp//ec0p7/HDI8c1T2ndSPt/y/tta3n81eEqaC35HeRu3OJc0ExkGnXPUiRBJctSQ49O8P100whpTu5ep1rpvmoktw6Ynnp3kdqWUT0891DqwcBHyKCXEQc9/lmuUc48zwOGaQ45/bIxzLdXHhxwfNlkRYGeXJvlckpck+ZMkN02yXynlRkne3GawderMJHdKclQp5VnLnQRXSvl2kpPTFJyGuf1CsWUW/cGQ4z9N8tblbFBr3ZpmMtwg25Pcd9zi3M5KKb0094Fhzyn2TPM925qF0uJihcu/T/KNFYyzqwcnueGQNf9USnniKMW5nZVSvpDkVkl+NmTpP9Zap/U3m6lZyPwPQ5b9NM2k7pGKczuUUraXUh6f5LlDlt4oyR+Oc+71QnkOAAAAAGbLrFywC7CuXdrpfe/szY/ZlM78ohM7Osncps/k+FycTyVJNs3vc9Fdf37K+Q/vXXjp1S48az7zF4+zZ+eSzj6dH284Zu5zm24x9z97nTL35r2Pn3vN3ls7b978k85Zmz6VL+9xVn469/5clM9lPgMLegDs1qw8Fz9jJTdbeEX6d6/kngMMKiztXWtdbiHn0iQ/GrLm2svcYy144JTOO6kJuztfuH/QhM65q2EXue3uleVXk0+1vP8kp1IyfcMuqpzm/WmUIuo0i0VrXq11c5L/SHLzIUvPS3LHUspKlJ/Wk0+OsGaaxf1Rzj3O99iwn7sr8QJAPx5yfFrPDYDZtz1NqfnfkjwyyYlpinI3KKX8YSnlBaWUj5dSRin3M1nvTXJSKeXUUsrbJzltaWFa1p8mee0Iy580qX1XSq31iCS3HLLs3yZwv75Xhr+oxbNKKf+xzH1SSjkvyd3STLEb5HeXu9dS1VoPSvLsRQ5/I80k8lbUWjcmefKQZR/O4OlnA5VSvpLhpc1rZnp/X5qmP8jlX7Rpd36/lPK1ZezxmAwviD651jrOi1ysC8pzAAAAADBbZuWCXYB1a3vnpz86e/MjL01n+1WGre3MZ889P51r5dJ8+bJ37rP94Avv/5OTL/ijH/9g+4EXf2g+88uaCNO5oHNw53t7HD/3yU0nz71rr5Pm3rj39Tuv2bxv5217fa/z4U0fzzc2nJFfdj6US/KVzI80uQFgvbq07QAj+nQLe/5FpjPBbFzfHnL8+GWe//sjXIS33D3WggdM6byTmmh35E7/feCEznk5pZQfJLlkwJJ9aq2TKgNOw/+2tXGt9dAkW9ran/Es3F6HDlk2zfLcKKXoc6a4/5q2MDXhLUlOHbL0wiR3LaW8f+qh1p9RynNbprj/lUZYM8732LDz/WSMcy3VsD2m8twAmFkXpCmInJrkgFLK0aWU3yulPKeU8qFSipJ+uz6d5LallFuXUj4wrU0WJmv9fpKvDll6i1rrkUPWrDYPyvAXqnnJBPb5rSHHf57xpl8PVEr5YYZP/zqs1jpsiva0/GOSxV548U9afmy5X5KrDTh+aZKHLBRLl6yU8tY0v2sM8tha68z0nRayPmbIsteXUt6+nH1KKRcnOT2Drxs5LMl9l7PPWjQzdyYAAAAAIInyHMCqtj2/+tmvNv/p2elcMvK0jM6l2X/PT+dK2Z7v7Pz++YMuufoFD/nxzS+830++OL/50olecNpJp9M5Z+5qnW/ucZO5j+x56tzbN9987vV7H9V57ea5zjv3+nrnkxs/nO9uOCPndD6WS/OdzPv5A5AZeS5eSjknK1z0K6V8MsmbVnLP3dg/yf8NWXPcMvf43KCDtdYNSa6/zD3Wgm211utO4bz7Teg8J9Va91r470EXhC3XoDLBhgyf1tWmNgswp7W4N+Mbdnt9q5Ty/Snuf60R1kxz/zVrYeLE65PcdsjSi5Pcs5Ty3umnWpdGKQIcMsX9Rzn3D8Y437DnqHuOca6lGrbHanhBCGCVKKVcUEr5+1LKmQu/a7OKlFKeWEp59wrtdVGSJ4yw9K7TzjIpC0WfBw5Z9rFSysC/hYzoRkOOv6GU8ssJ7LOzfxlhzU0mvOdQtdZbZ/EXHXptKeVdK5lnNx4x5PgrSinD/v42qidk8N9bj0xy+wnttRLumOTaA45fmuSJk9iolPLpJK8asmzYbbnuKM8BAAAAwGyZiQt2Adaj+Zz7y1/t/dAfpXPxoH8c263OxTlk02czn/n0dz22/fCLjj7/kb3jL7zTzz4xv8f2Ya9uuyyd+c4enZ/PXavz5Y03m3v/nqfOvW3zTedet/fhnddvvqDz3j2/0Pnsxg+kN3dmzs8nM58fTzMLwCq0rFdUXmG9FvZ8ctqdzndUks8MWXPiMvcYdv7jM7npaLPupCmcc8uEzrN3ktMWCnTTnBT4iyHH7z/FvZellPLtJF9rafthEwlYXYbdXu+Z8v6/OeT4T1zoPr6FMvirktxlyNJLk9x3uZMTWNzChcnDCqDTvOj7xkOO/6yUcvYY5zt3yPHFJrBM0rA9zluBDADMoFLKv2f470mnTj/JxPxWksOHrHnxcjeptW7K8BeumXgJspTyvSRfGLJs7H/LWY5a695Juosc/kWSR61YmN1YeCGkQS/0M5/k7ye1Xynla0neOmTZqv3byW4My/qmUso3J7jfsNvixrXW60xwv5m3R9sBAAAAAICxKM8BrELzueDcX+390G+nc8ENlnqOuQty9U1fyBcvOjp7pXPFySqXXu/8G59/zPnb9/jQfh/Y+IH9rtmZ71xlealH17m0s3d+vOHo/HhDOtl42fvn95z/WQ6+9LvzV97+ixy8fS77b9+Sjbl6Otl/pbIBrKBZupD2rUn+ZMS116q1XiXN5LYDkmxOckGaz/e8JL9K8p0kPyqlLDqJo5TypVrry5P8wXKCL8NvJDlryJrb1FoPKqX8dIl7nDnk+Cxd0DNth2byZcpJXvBz1zST4TZN8Jy7+nmSIwYcv0+t9XGllDZLp4O8Jyt/IeEeGV7WmbRhX/+NQ46vWyPeXtOeBHKnIcc/O+X915xaayfJS5Lca8jS7Ul+r5TS9uTZ9eBdGfz86oQkz5nS3icMOT7shQV2NewFHqY5EXaHw4Yc/9EKZABgdr09ySMHHJ+lafR/OOT4eUleO4F9DsjwgU/jPqcY1WeSHD3g+MFT2ncxT0tyjUWO/Xkppe3nIb875PiHSimfn/Ce/5Lk7gOO36XWuu9qf1GUWut+Se48ZNmLJrlnKeUztdaPZvCLyvxukqdMct9ZpjwHAAAAALNFeQ5glZnPxRf+au+Hfnm+c+6gV+QcydzZue7Gr+RTFx+VY9LZzcXcncxdcuLZt7jkN8++YNO7t5yx4bN7H99J54Dl7rtUnQs7B+b7exzY2eV18Of32f6DbN3+/fkrX3peDtq+R/ad35oNuXo62bOdpAATsaov0thFzejlufeOuO6CWuu3k3wpyUeSfDTJx3e5eOW9aa88d600E8W+neTqi6zZmOTeSZ6/hPNfmOT9ix1cmNJznyWcd5hZLe4cnOSiCZ9zS631sFLKdydwrgdM4BzD/GrI8W1pCpcvr7VeK8lt07zC+1FpSnf7Jdk3ycVpXoF+2LSeSXtDkoeu8J63TXLQJE9Ya90/ye2TnJzkekmumebizb3z66LwIJsnkaOU8uwkz94l252TvG3Ah/0gzWPbxjQFlhOSHJPmMe6wNPePvdO8+v8FyVgvYHGNUsq3xli/O8Nur+1J/l+t9blp7s975tdf816SHZMg/jfJmaWUYdO1LmdhKsKwiVsfGuecq9VCoe2YJLdIMwnsmmkeJ7akuQ9sSPMY8csk30rylSQfTnJGKeUbY273giS/N2TNfJI/KqW8etSTLvycvFmS26V5rLtOmvvPvmnuF79Kc5//fJr7xH8sIfta9foMfn51Wq11j1LK2FOSa63HJrljmkmsR6eZynZAkk6a+9S+Q07x0TG3HDZp47QxzzeWhWkvwwqBk5wGsmy11gPSPN6enOZxYMfPsX3T3EY/S/KNNM/P35vm+37RF7wYY9+j0hSUj09yg/z6vrEpze9F30vze8FZSd5aSvnOcvecloVpw7dceDsmzXOtLWl+Nl2S5Ow0j51fSHJGkv9qu7xQa90zyY2SXDfNi4T8RprpUPsvvO2XX//8/2WaCZXfTlMS+USS95dSLlj55LAunJXB5bmr1Vo3llIuXqlAS1FrPTDNi8oM8sZSyrDfa0cxyr8J/GQC++xOf8jxify+N4pa642z+H3nw1l8It1KGlb+mkSZclfvTXP7L1Zk3DvJrTJ8Ql3bfiuD708/TvK+Kez72gwuz905ynOXUZ4DAAAAgNmiPAewiszn0kt+tflhn5nv/Oqmkzrnhp/n+Plv5cOXHJHfTGeRV2TdI3tddIdfnJrTfvmLPd924Jlz39zzhE46q6aY1jl37io5d+4qnW/9+p+i5jvzl+SA+W/kkEt/NH/I9oty4PY9s3n+0MzlsEU/T4DVZaWLK0tWSvlxrfVnSQ6c4Gn3SnOh+3Xy6wusLqm1/neai7r/I8mTRzzXSyeYa2dPS/KWJI8asOYhtdYXllK2J0mt9SMZfJHJDu8qpZw/4PhvJ7nyqEHH8J9TOOdK2DPNhciT9p1a6yTOs3eS0ydxoiSptS71IvXn1Fr/LM2F0YvZI6Nd0He1TPZCrDPTXIh91WWe55Qx1j5imXtdptZ6gyR/luZ7c7EJg/ssvA0yzYnK705zMefWRY5fJU2J6FoZPiVxmlMUF/OEIcfncsXphTu+5lvTTOW4/Y4DtdbPJHlFkpeVUn42wv5PHGHNj5fw/XnKMr6nk+S0UsoZy/j4y9Rar5PkwUl+J01pYpADFt4OT1OyefDCOT6R5GVJXjLk51hqrf+Y0R4bH15KeckI63ZMYHh4mjLuYlPFdtwvDk1TFvm9JM+utX4yyd8lecMqntK5Et6bpli42PT5bUku3s3Px93eFxeKRA9K8pgMnjC6ZYRs7xphzc4+NeT4EQO+/15eSnngmPvt6pYZfgH/s2qtz9rlfUv+vq61PjVJWex4KaWzyMfdMMnjk9wzi7+Ywo4i1RFpPre/SPL1WuvfJ+nueL47RtYNab7/HpHkuAFLtyy8XS/Nz9ln11rfkeRJpZRpTQ4aW631mkkem+T3s/jP+41pnmcdkuSmSR6Y5NJa638k+ftSygdWIOqOkvTN0tyOpyW5eZrfv4bZlOY+cFiaYui9F95/fq31PWmm+bxz3PsCMNCwKapzab4vlzrxfqXcP8N/Jr54Qnv9coQ10/qb27DzTqIcONTC1O5/TfOiF7u6JMnpkyi/L0et9ZAMn5z49knvW0q5pNb67iT3G7Ds1pmN8twg/zWl32nenuQfBxw/tta6tZQyrEi6LviHSAAAAACYLf6RE2CVmM/27WdvftTH5ud+MrHi3A57/Cg329DL8At0Ns9vufDePz3lgj/+0U+2b734A/OZX7U/JzrznT06v5i7ZucrG28294E9T5l72+YT5l6399U7r998Qec9e36x89mNH8wP587M+flktg+9CAGgDTNTnlvw1yuwxx5pJmG8OM3Ei0EFoJVw5yRfHbLm2CR/lFw2UWOU4lzSFDp2a2GKyd+OeJ5x7T2l807bL0sp52X4VK/1bv+0/32zWwsXWb98pfZbeBX+20zgPFeqtb44zeSV+2X5pbKp3T6llAuTvGiE/adRjFvSOWutV661PrzW+uk0Ba1JOjbJ36cpydZa66LFxlrrzTN8guT3k3xugvlWTK31N2qtb0wzBelxGV6cG+TGSZ6b5Ju11tMXChq72/OvM7h8vsPjSinPG2XjWusD0vxcfnoWL84NcqMkr0nyvwtFonVp4SLbl03iXLXWO6aZTPj8DC7OjeJXyQh/t7i8tqdBDiv9tq7WumXh59gn00w1HncK8bXS3L4fX5jQOeq+p6WZ/PiSDC7O7c5cmil1n6y1Pm2hhNeaWuumhce0L6eZxj2sKL+rDUnuluT9tdbX11q3TTjiZWqtN6m1/kOS7yb5YJoXA7llRivODbI5yV3SvBDH52qtd1rm+YBfG6WAsmLTzJZh0FTbJPlqKeWsSWxUSjk7wyfTT3QC+RjnXamS4+PT/L6zO39fSlkNv7fcKs304cV8o5QyrQm97xlyfFgxbTUYlvG909i0lPLVNNNnF9NJc9sS5TkAAAAAmDWrthQBsJ7MZ37+nL2e8MHtcz+4+bT22PjtnDz3s5wxUp4tl171gj/88S0u/L3+17bve+knppVpGjqXdvbu9Ddct/N/G0+ce99ep8y9Ze8bzb12722dN27+eeeMPT+TL+5xVn4yd1YuzOcyP9Kr1AJMyzltBxjT25Ks5KtW77uCew3y12lKM4M8vdZ6YJrJGqP4VZrJeov5yzTTHvi1byz873dbTbG+3HMK5/znKZzzChbKPM+ewHlunOT/MvxC0HE8rNZ6xATPt6vnpp1y9tilmVrrSWkKac/J4hd+TsI+SZ6S5DO11iu8UEmt9aAkr87gCzuTZrLDTKm1bqy1Pi3Nz7F7ZrLX9l05yQuTnFVrvdxEyVrrE9P8LBvmyaWUvx+2qNa6d63139IUzycxlfUGST5aa/3jCZxrVj0nycDJgYPUWveotT4vTZFmUs9Z9k9T7hxZKeWLSb42of3HUmu9Q5KT2th7VLXW66X5/p/Ez7EbJvnQQilu0J5zC487700zYXo5NiR5UpI31lqHTTOaioWi20fSPKbtMYFT3ivJp2utE7/ovNb6L0k+luTRWf6k30GOTvIftdZX1lqnOVEX1otRXuDmgqmnWIZa640y/Pn8SFOGx/ClIcenVVQ+dMjxbww5vmy11iPT/H6zO99K8lfTzjCiYS8S+cEp7j3s3EfVWg+Y4v7LspDtqCHL2vz63WSKe88U5TkAAAAAmC2r+h9cANaLc/Z6ylmXbvjm1C+62vSVnNo5OyO/wuv2q1x81AUP6934wrv/9FPzG7d/cZrZpq1zUedKnR9sOHbuU5tOnnv3XifPvWnv68+9Zu8DOm/d64edD236RL6+4f+zd9/xclT1/8dfs7flBgghIYXepPeOtEQUC2JXsDdUFFHEXr8fP1/L15+9K4q90AREQFEREnpP6L0FSCckN+X2nd8fs5EQsjNbZnZ2976fj8c+lJyz53y2zczuPZ/zmc3y4FpGuI9Q50cRaYiWqTzn7jsAV5OcWNCONgM2T+gzGfgDyVWL1rrOzDa4S3ppIe1nKg9vzFibzJ+0QE7S87G0BzSzhTQmcfhTwBF13P837v454Cpgy3RC+q8JwH/cPWnRZU3MbAHw3SzGrpW7j3P3V2ygaSOixIhG2Yko0et1a//B3TcD/glsl3Df1TQo+TNFE4HZRIknWVQbXOtIoupQhwC4+6nA/1Vwv6+bWWJV21JixmXA2+uK8vk6gZ+5e7mFx23NzBZRY0Kou/cClxJV4Erb/7l7tdXc/pxBHLHcfScaWE21FqWKmtdQX6XJ9U0ELi0lSWxozg6i5+WLpLuW+LXA78pVusxKKdn9emD/lIeeBvzD3U9IedxGJ7K9jaiaXiYJKu6+vbuHCbcvZzG3SIMlVdMtQtNvAJeUpD1K+ufNqxPaU/9bi7sXSP6emWVC09qNYn5B+Yqip5jZmixjqELS+fO2DOd+iGjjqnICst3ApV5Jz91yM8syUfPWhPa0r41alpLnREREREREREREWsszeQcgIjLWrer5v1mjHffMaNR83XdzZDDADdXcZ3TXgf37P75gt6FjVlwXFsJ5WcWWh2B1YYvgsc6DCjf2zCj8vfeIwrnjdwvO7u0KLh33aHBz1w3M65jFyuAGRnmUUBVbRSRVLZE8V6rycBHJu2tn6Y4Uxhiu475bVXD/46h8cfLzFqG4e7e7O/AvGptM0gqW8OxzdmOegUgqlmc5uLu/FvhaGkMBvSmMsyE7AueUkgxS5e7jgRemPW4Fnrdw3t0nu/tngEeprApZI/QA57n7K0vJXrcBG0wCWc/XzOzpbENL3f/QuPfCNODfpWpTP6yg/3fNLPE94e7jgH+QbXUvd/f3ZDh+M/tfYFk1d3D3TuA84KWZRBT5hru/rIr+P6WBG8S5+47A30neXCE37r4bUZXjLCqq9AIXufuUDbT9jvQTXdc6kaiiWkOUEncvAbbPaIou4Cx3f01G4zfKPsCV7j4x70BEWtgBCe1PmFk9v2dkqnS99taEbn8vbfKRpksT2o9LeT6Irq0nxbQ/ZGZZ/+3kfcDMMm3nmtk/Mp6/GvsltKfxW98GmVlYwfjNnAC2X0L7nRnPf3tCezM/dw2VRlliERERERERERERaZwVRLsWamMsEZEcrO7+4ayRzltmNnLOAArdt7P/4AHMpSvxj3Dr3jEYOWTV4SMHrhrqumLT2Z23brRXQDA5u0jzE4RBByuCHVhR2CF48Nl/DzvCfjYrPsa04rJw6ugIE4sb08NWFJ6/WFhEpAKNqL6Uhs8Be9dx//uAPwFzgMVACOwAHAQcTLQgZLOY+68kWri6Tx0xAPwK+GAd9++qc/51jaz9P+6+L9Ei4w+QTrWIFWSzUDpPZ5vZ2gT2y4Gv5xlMi3oQuIdoA51pwKHEL/rL0mhWA7v7yUSJO2msXyr3mR8BbgDuIjqmLSZKJPhWleMfBXyayip0VaS0cPWfRJXAqvEYMAt4mOgYMkxUXWht5c2XklwR45vufg9wM/BiouPam3i2IsLDG7hPpQta+4GngBck9BumsmN1B3A+0W9hlfS/A/h2Bf2aTdy5dV2jwFyiJOWlwNPAIDAFmAocQrSoO6ni0wSialNJfmpmn6gwtt8Ah1fYd4io0sdc4AlgDTCeKLF9/9I45V7vM9x9ToXztA0zW1pKcP1lFXf7AfDKmPYFRMeT+cAmwAlEx5NqBEQVQHcxs8TrZTNb5O4/JDqmZsrd30T0fDXttZa7b0SUOFfuPD9EVJXyfmAhUQLlZkRJ0EdTWRWWrYBvACetM+9niCqRlfMEz743FhOdT6cRHdtfRmXP6dfc/a8ZV1pZ61fAnjHtT/Ds87h2g8LNgF2BGcA2FcxRAP7s7keZWZbVd9b1NNGC+weJzvkriDY2CIleg02JKrUeRHJV1rV2A84CNlRlVuQ53H0TovfY1kTXDj1ECdD9RJumPAk8ZWYjZQdpP3HnVYi+dzSz15N8rv9VBvNeRnQs27lM+8vc/YCUj69J17o/S3Gu5ylV+vxmmeYVZFA9vlbuPpXkc/uDCe31epj478bl3jvNYJeE9kY8d3EmuvvmZrY04zianpLnREREREREREREWsj0k6eEC89Yspz8Fs2JiIxZa7p/PXu4a/bMPOYOQnp65rLD4AHcTwe7VnXnDrqHj10xY/jovr7uSzab1fHguEMCgvEZhdpUgtGgl6Udu7O0g+DuZ9ddht3hcjYvzgunji5nShEmFDelm+0JmndBnYg0haavPOfumwIfr3OY3YCv1HH/XuDzdcYA0SLRm4kS9vK2W2mR93FECwfT9DGiZINavSqlONL034V2Znazuz9CVLkrCzcTJdaU2/2/j2hB5x4ZzZ+Vncl+YViY8fhlufuhRBWUsqyEdC/wVaKqCcs3EEO1yXMAX3f3FxMl+ywiSqqOqyqxwMw2WGHB3QPg91SfOAdRVZ3jiRZ7Xg/MMbP/JjmWKuQlLWCeDFxHlHQ1Lq5jDa9XL8mJcxAdUzchSuZ4BfEbRfVUOPdy4PXrVPu4H3j/Bvp9ivILHB8gPrmyh/hz04HuvqHHX29F2IeIqp3eQ/S6Aaw0s3PW71ha/PpWovPxhqpNVWoeMNfd31dB36OAN1fQbyVRFbBriRber9/2TTNb4O6bEVXq+CzP/x20C/g1UcJdOR0Vxr2+pNfp6FI1t2ps8HWq0a+IFu2/toK+v2TDn8UR4IzSWHOJkm4+Dbyxjri2IHqtKknIhOiY8iaiDRoqtaW7dyVV8yklo70K+CSVVaqE+MX8WfseG36d7ieqqnqJma0sd2d334EoMe6EhHne4+4/MbPb3H0GG676OgL8AviFmZWtYOLuXUSf928TJe2WM47oXJxU4aheb6T8+/di4Btmdl3cAO5+BPAZkq+txxNVoNvfzOKOQbVaCPyNaDOSOWb2ZKV3dPctgHcQnVeTFvG/3N3fZ2Zn1hyptLOXuvvbiM7tu5CckD/o7ncCNxFVoL0io89H7tx9J6KNCuLMbkQsdTgpoX0RyVXiqmZmobt/g/KJeQHwfXc/Jo1kTHd/NfDymC7LY2JJy08on6j4uQyq+9Uj6ZpsgOi3lSw9lNBezXVjoyXFlvTY6jWPaMOF7pg+OxBtvjKmKXlORERERERERESk9SxDyXMiIg010HXuNUOdlx6dZwzBKJv2zGVwcH+eoFDRjtjP1RNOGHrDsplBX8fC7gsm3VpY2HV4QNCRQahNLxgKJjK/Y2Iw/7kPPxxfXMCU4vxw2ugqJhc72TicRCc7EMQvKBaRMaPpk+eAE4kSEfKU1jqE1xAtgr2JqMpFnk7Mef44tSaFneDuW/P8xIU0rFjvv79PVF0sC0nJlRNIJ3Hu4+7+MqLv4yuIEjfGESWltGpF24ZVh3D3G4met42JEimz/EyvAT4B/HLdhLIUvbh0q8Rsyi88/SRR4kitNge+VLqtcvfrgEeI3qPLKhwjoHzi3FbufibPLprOwpuIKnP8jShh7W3EJ2EkWQ281sz+u+t+aUHq8xID3P3tlH9cC+KSCdx9e+DHdcRZqxfw/ASbx4HnJWWZ2WKixce/IkqqOaXGObclSqRJ0yZE59Vy59YXEb0GzwDfcvdfEyWZr5/Qsj9QXP/O6+iiugptlXpP6VaNDb5OtSgtPH8XUfJ40mezXELWeUSJ56cTHc+2TCM24MPu/n9mlnjNbGar3f0NREm8lX7fPhZY7u43EFWYXHu86yD6rXxzokTAA6nuevQZwIA/V3GfNK2f4DtMVEn6h0mJggBm9ihwortfAvyW8onIAdH1zElEn431fw+6Dni/md1TwZzDwB/c/VKiKsP7x3Q/wd0/Z2aPJ41bhw0d454B3m1mf6tkADO7Fni1u7+W6JgzMab7LkSVaE+rLsyy+oleuz8C15tZTRsclM5533T3bwMfJUpc3CjmLt9w97MrqRgpY87nquzfQ3T8PYjo87ja3c8mql7bqCqNjfJRkpMJL25EILUoXce+KKHb77KqJGhmv3b3NxOd0zfkKODnRBso1MzdDyL5vH66ma3/20VqSueT15dpvoFoI4NmkpT8taDW81MVnkpob+XkuaTHVhczK7r7QqLvb+XsQPQdYkxT8pyIiIiIiIiIiEjreSbvAERExpKBzouvG+g653CCxD+MZy4YZmr3HTw+tC9LCGqrIBBOGJ0++O4l04NFXQ/3nD9paaGv89C042xVwZrCFjxe2CJ4/Nk/oYWERTYNH2PK6MJwWnGQScVuxofTKbAtwfMWm4lIe2uF5Lnj8g4gRS8ies5fDMwiWhAt6eml8gSgev0c+ACwV4Pmy8KrSLfK3xqiyiVpGqG6dUADKc8fJ6k6Q1qWAseb2Y0Nmq8m7r4n9VX4XN/GpF/Fb3uSq1LU6wMpjvUMUeLcVSmO2fJK1ao+7O73E1W3iqvu15TM7Gl3fw3wU+CD6zW33ONJg5n1ufuxRAuvq61ouCuVV4db3wXA6yifNDCRKCny15UMZmZzSgl0F1B5dcnxwDGlWxr6iCp5xlXpaKR+4E3lqpbGMbM/uPskok0LynkT0WNev8reJcAJZlbVpgpmtqy0ucDNwHZlunUQnU/+p5qxq7T+e3Ih8CIzu6/agczsr+7+AHAl8Qndp7j7z83s3mrnWMcSoiqMPzKz1CrBmFmRKIH6MqLHUW6jh8lEiU7fTGtukZKNiD73J7n7BUQVth7IOaa6uft2JF+/3lLLsaeB3kty8l9F5/E6vIcoYbtcks9J7j6dKAG66mOju78H+BHxycMXmtlvqx27ihgmEFWd25AR4OTSsbqZJG2msKgBMSxMaE9rw4csNMvzF5c818zPX8OMyS+QIiIiIiIiIiIiLa7SHcRFRKROg51X3DTQ/duDCZrnbyqFAbbrvoelhKysZ5xw2vBOA6csOnTghKV3hD3FO9OKr90EBIVgRWH74KGuwwrX9swoXNz7wsI543cIzukdDv7Vc38wt+ta5hdmsya4hSLz845XRDLVCjvyNypBpRG6gLeY2d3A0cBDOccjNSpVJ3kD0QJhidxKlFSYpo9X2b+RyXONMADMaPbEuZIfkJwocj60zLVl3hVF7gAOVuJceWb2Q2pPmMpdqcrFKcCFecfSLMxsHvCxBk1XBD5tZm8Afp/Qt6qKmmb2d+AVRMnPjfYEcIyZXZfD3BsSAq+vJXFuHT8E5sS0dwMfWu/fLgdeV23i3FpmtgT4VEK3N9Yydo36gePqSV4pVd97JfHXSp1Eld1qZmYfsUgm7//Sc3AMsDymW5qJ7CIb8nrgdnf/hLvnvjFdnb5FcrXU7zUikFq4ewF4V0K3a8zs/izjMLOniDbyifuu80rgXnf/X3dP3CjA3Tvc/bXufhVR8l9c4twVwFuribkG36R8otL3zOyOjOevxeSE9sUNiCFpjk3dvekKh7l7F1F17TjN8PwlvcZjQtP8oVdEREREREREREQqpuQ5EZEGGOq4/rb+7p/sQ0BX3rGsr7CS3bse5EFChuodq7jj4D79py/Ye+hlz9wYdoSPphHfWBAUg3HB0o5dg3u6jijMGjej8Nfegwpnj98yOK93RXBlzx3c03k1iwtXMcjthKoaK9ImmrrynLv3Un31kWb3ToBSRQdVSm1hpUoDhwGtkNjUCEUz+xDR+/rKlMaMWyy/IU+nNG8WatnY4Yelxe5NrVQtKqnq4z/N7I3APkSJKmHmgdXud+RX9XSAqJLRwWb2cE4xtJJvAP/IO4halRLo3k1jFp62ikY8F08BLzGzb5X++zPAYEz/me5eVRU3M7sSOBD4d20h1uR84EAzu7WBcyb5oZldVs8Apc/Jl6q4yzNElX1G6pz3POKvQ3Z397hKKGn6nJlVe030PGZ2C8lJx691953qnStLpe9Rce+Jndz98EbFI2PWOODbwPnuHpfU1LTc/fUkJ4g/AJzTgHBqdSzxVakAftWIQMzsIaLvwrNjum1OdPx6yt3vcfdfeeRj7v4hd/+cu3/b3S8nShK+EDgqYeqzgVebWWYbybj7UZRPTH4M+HJWc9dpUkJ7XwNiqGSOzTKPonpJzx00x/NXSZxtT8lzIiIiIiIiIiIirUfJcyIiGRvumHvnmp5v70qQuJtsbjqWcUDn49xCSDGN8Ub2X3No/yfmbzN82MqrwiDUgsQaBcPBpsGCjn0Kc7uPKlw+7ujC+eP3LZw1frPgr+MWBdd038qDnbN5JriGYe4lpKad3UUkN02dPAdsWuP9mvn7xcHuvjuAmTVznHVVgx0rzOwR4IXAm4FryD8h6F7g2jwDMLObzOwYYC+iSgZ30JjnpUg6lQBvJt1j40rgfcB3a7hvqyQFfTqhfRnwXgAze9rM3gUcDFwC6Vz3p+QR4JVm9m6iRXpXQMOubUOi6kovMLOvmFndG4qMBaWkmo8Ao3nHUisz6wO+kHccY0Q/8P+A3UrJbQCY2SLij7fjgIOqnczM5pnZS8m+Su11wEvN7I2limnN4nHgsymN9S+oeAOfT5cqAKUhKWHkiJTmiXMf8JMUx/sh8GBMe4HnV/JrRj8jvor3yxsViIx5rwOucPekCk1Nxd2nE32OknzczJr5Ouu9Ce0rgfMaEQiAmT1JVB3zdOI3BAiA3Yni/x+i6n4/Bb4OfIJoY5KNE6ZbCpxkZm8xs8x+23P3HuCXpZg35MNmtiar+euUlJTWDMlf0JwJYJUk9DXD89eMz13DKXlORERERERERESk9ah6jYhIhkYK9923uucr2xLQ9Dvhdi7k8I6FXJ3agAU6h2f2Hd1/+oKNRnZfMzskVDJASoI1hWnBvM4DCzd3zyj8o/fIwnnjdw/O6u0JLhn3eHBT14081jGLvuB6RnmYkLp2fReRzKzKO4AE5RbnJDkQeAVwA6R2/ImrSFKtd6Y4VpqKwCyiKjhZLoLxDMduODMLzewcMzsK2BJ4K9Hit78DdwGLiBbsZ5Ek1A9cDHwY2NXM9gAuz2CeqpnZ3Wb2aTPbF5hAlCz1OqL3/7uBNwDfTHHKhSkt7LyHqHrB8jrHWQh8EtjGzBpS7aACK2LaQqKqZ1W9T0vVaZKqzn3UzOav+w9mdquZvQrYBfga0fOel5uAdxAl1Py9FF+/mb0YmAjMIKqmcFeGMQTAj1JM+BgzShX6zs87jjr9GpibdxBt7F6ialvbmNlnzWxD179nJYyxbx3zZ7GgfAHRIvvDzOwIM2tkhbtK/TitKjhmNgxcWkHXJcAf0piz5IKE9v1SnKucT9VbRW9dpefyUwndTnT3Wr+HNUTpmi/u9TmmUbFI0xsh2lzkp0SJoUcRXX9OI0qOHg9sQ/R5Pp6oqu11wHAVcxwCXFpKMmp67t5BdN6bmtD1IjOr5NibC3efBLwmodvZWSaWbYiZFc3s+8AOwGlElerT3EzmCeBzwA5m9usUxy3nS8CuZdrOW/v9qUklbSLZiKS/St5/zbjZZSUxNcPz14zPXcN15h2AiIiIiIiIiIiIVK2ZKy6IiLS0kcIjD68a98UpBDVX72m4rseZEfYwqziJmakN2h1uNPSaZ2bwkhVLey6cNKfwZPcLA4Ku1MYXAAKCAn3BdvQVtgvW2QM8LISDbFZ8mGnFp8Mpo0NsFm7EuHBLCmyVX7QiQmN2Ca5H0veEd5nZ78u0PQZc5u5dwIuANwGHEiU3bQJ08dzkvCJR5ZoBogSTx4BbiJLJ7iHaaXtGmbkeNrMXrP0Pd9+YKHGmXNL62939C6VFVc9bmOrumxEt6jsS2APYkWhh20ZAdynG1USv3yTid4QeLD22DqLNiAulx7mGaCf0R4kqWlwLzDazRe7+Qog9Pj8BbFeq+FPOb2PaIEpEeQ53L5TG3jLhvi8ys1ml++wI7A+8oHTbCdiC6DXeuHQbInqu+ohe20eBOUSJCrea2WJ3fzfwm5g5K1rsZmYLiRYiJi3Cp1Sd4EiiqnUHEy3aHE/yptEDRAmIFwP3mtlzkp3M7Mus9/yWKgu8sDTPbkTJYVsSPT+9RI9v5Tq3pyn/fl/rNjM7MKHP2phWEX2eblmv6QLgM+Xu5+7bVzJ+yb2VdjSzxHHd/QeAVTBcSLS49hngYeAy4Fwzu3+9OX9L6XPh7rOIf37nmNkBFcz9HBs6nqzL3X8NvKdMcwBsaWbVbm70FuITnecBZ5drLCU+fRH4Yun1PoyowtMuRO/T6UTHvt7SXQaJPtODRMexpevcvlrq9zKiBdC78+zxoKfUv4+oGtI9RFUG/16qEFEuviHgqtLNAdx9y9L4uxF9btfephB9hseX4giIPq9riBI65pceX7kqEvsTX0UnM2b2GLUnrOPulxE97xsySvTeyrIS+C+BE8q0FYHNK31vu/s/gZfGdHlf2gmxZlZ09zNIrgAzkPQ5HyMuJloo+wKiBNeNid6//UTH4seJKmvdRHRtc18FY96Q0L5brcEmuJ9nr32mER0/eojOLYNEG10sIjp+3A/cCVxnZnkmHFeiH0g7cfw24O0JfX5pZqlteGFmD7p7H9EmABtSLpkgLU9QWdJgtS4GnqL89f7WROer6zOYO03/oHz1233dPUj4vpKo3vOj5KYPuJDo8/MvM4vbQALgydLt9tJ9cPdpRIlPHyI61yQ5Cvg+rVG58WuQ+Jv7UuDk7EOpy9uJzplxctvExMzWuPuPic5fpxB9b6rHEqKKdn+u99hWKXffm/LH2T6iz0gz605ob8Rmf5XMkRRnHiqJqRmev2Z87hpOyXMiIiIiIiIiIiKtR8lzIiIZGA2eenzVuE9vTBBOzjuWanU/wMzBvbg63JijUh14o+Lmg29fenTwdOfjPedPeipY1vnCgEALYTIWFIMenu7Ylac7CHg2ZzHsCvuYXJwXTht9hinFkAnFCfSwLQGTcgxXZKxYs9sxFzVil+CamdlgwoLVU9z9j+snD603xjDwr9KtJqWd2Q+K6XL3enOucvfzKV9hbmuiaggbrBBWWuD/t9ItLq4uosoj5SwlSlioZtd8SK4idXYWi7VKyQPnEC0Iq/Q+jwCPpDB9UkL9UApzPIeZrSRa9PuP9dvc/bfAu8rcdZGZfaPKuRYSLSC9sNL7uHvSa/zbamJogLuTu6Qn4wSWpEo3tbojoX1rosSTahyf0P7zSisClhaoP0ZMsl2Fbq/z/rFKVfTmE1WXrIq7zwaOLtO8F3BeHaHlwt3HE78A+8qME+fg2QoxGzqWF4gWtMeeUwHcvZsoqbmcIbL7fJ4H/JDk89FYNwC8oYZrm1hmNs/dl1M+QWLrNOdbxw1m9u6Mxs7T7BqSsZNUkiR/UcpzQrTJxCFl2rbNYL51ZX3N/fGYbsfQ/Mlzj8e0bQxsT7RphowddxAlov+xTJXRipnZIuDz7v5/ROfnd1dwtw+6+z/MLPGaIy/u/nZiNi9Zx8ml56CZvTeh/W4zu7EhkazH3ScCHwFOJbnCX6WmAH8EvuDufyaq8Lo8pbGfp7S50S8pf236eTOL+z2qGSh5rnZKnmshSTtwiYiIiIiIiIiISPNR8pyISMpGg8XzV/Z+rIMgnJZ3LLXqvovDgwEy+SN3OHlku4EPLD588K1L7w17R+dkMYckC4aDCcHCjr0Kt3cfVbh83NGFC8bvVzhr/KTgwnGLg2u6b+OBztksC65hmHsIaeokH5EWtDTvACp0U0zbocC3GhDDayhfRQ42XK3kdwljlkusq8bxQFyC/Fk1Li5PqjhWb2JLnD9nOHac3oT2gYZE0VquzjuA9SRVDWol12Y07v0J7VUt7HT3TYmqGZZTJMdqD01qYUzb9o0KImUvIr7qx/lZB2Bma4BbY7rsV+FQBxNV/irnnxkkBAFgZk9TR6L/GHJT2olz63ggpi2the9jRRZJVw8ntA8QVRZOW1xF0CkZzLeuPK+5k74PNIOkxJ7tGxGENI1rzGxfM/t5vYlz6zKzlWb2HqLqzf0V3OUH7p703TIX7n44cGYFXX9oZlltFpAKdz8Q2DehW8O/h7h7wd0/Q1R9+3/J5vphd+ArwDx3/3qG77ePEv3mtiE3klwxuRkk5RRVtMlLnSqZoyPzKKqXmI9V6SY5dUqaoxmfu4ZT5TkREREREREREZHWk8nCExGRsaoYPLNkZe9HBgmKO+QdSz0C6Oi+nX0HD+R2OhP/IF6T4rZDe/SftpCOu3pv6b5s4qbBSGHnLOaR6gT9hanMK0wN5j37byFhyITwcaYUF4XTRvuZVOxio3AaBbYj0N8IRWrQKslz/wFeEtP+cXffF/i4mSVVVarVRxLaZ23g364kqoawXZn7vN7dT6lzYV9SAl5SAl85+8W0rQbm1jhuJW4jWpTY6AWHE2PaisCKBsXRKgZpcKW3CszKO4CUjBKfNFyPpPfxplWOdwDxi+rubkDFsYZy9wlElYY2J0pe7indKl20F1e9aov6ostNuUW1a93SkCiic+5hZdr2qnCM/RLar6k4mtpcC7wy4zlaXZaVsOKOkdUeH8e6LBLaVya035ZRYmXcvFm+L7K+5p4DrKF8wnAmv8Gty90DYEtgOlEi4gSic2o3kEaF31Y9r0oNzCzTCkhm9lt3nw9cTHylo+2BDwA/yDKearn7bkRVeOM2PIDoPPvJ7COq20kJ7UNEVdoaxt23Kc1Zrsp02jYBPge8zt3famapJZC7+3bAV8s0jxBVJiymNV+Gko4Ljfh7QiVzZLUxRD0Sj6nu3pn1sZfk568Zn7uG0x/GREREREREREREWo8qz4mIpKRI3zN9vacsJxhpiySwIGRczxy2HzyAB+kgs8c0ulf/Qf179hc7r9vkmq5rNtkxCIMts5pLahMQBPQF29FX2C54+Nk/CYaFcIiJxQeZVlwcTh0dYWLYS2+4FQFbEqSy4EqkXS3JO4AK/RFw4heovRi43d2vAn4LXGxmqSQHuvtBwMyYLkuAm9f/RzML3f0PwBfL3G8j4A3UmODm7pOJX2B/t5nFVeEpN+5UoqSQcu7KcpGUmRXd/S7iq1llIe68v7RFFoY10p0ZVv6pxVwzW5B3EClZZmarMxo7KfEgaTHt+vZPaM+kgnSjuHsXUeWdFxEliO1NttWn4iqJNrO490EI3NugOJ6OaYtLWlzXngntWSXpr3V7xuO3g3nJXWoWd4ys9vg41j2RwZhJG048mcGcSfNm+b5oxDX33ZS/5p7q7lPMLLXvjO4+BTgOOKI0765ku2FGq55XpUmZ2b/c/WPATxO6nu7uP25QVaZEpaSuf5L8mXgIeG2Tfc97HncfB7wlodvf0jx+JXH3nYg2c6nkmnMFcBlRJfcbiX5TWka0Qc1kYBKwB3AU8FKiY2Wc3YAb3P0NZnZJLfFvwM+JfrPakO+bWatcsw4ltDci56irgj5Jceahkpg6qSDJrk5Jz18zPncNp+Q5ERERERERERGR1qPkORGRFISsWdk3/pQFBEN75B1LmoJRNu25nYHB/XiSQsULH2uYiMLIESuPHDl05UD3vybO6rhj/P4BgXaYb3JBMehmWcfOLOvYObj32b+nhp3hSjYvPh5OHX2GKcWQTYsT6GFrgtikEJGxpCUqz5nZk+7+a+CDFXQ/unQbdfcbiKq/zQKuN7M11c7t7huRvFv5eTE7Lf+e8slzEFWOq7U63FuIX0RS67g7JbQ3YpHU7TQ+eS5uQdojDYuidWSZvFCLP+cdQIqeyXDspMSDuCTlDUk6XmRReShzpWqmpwBvJqqC0yiNrriZlt1i2lYCb3H3RsSxfUzbVhWOkfc5sFUWIucpr2NktcfHsS6L1ykpsTyr90bcvFm+L5rhmnsn6txwxd07gTcCJxN9T4urWJu2Vj2vShMzs5+5+xuINvApZzui9/uVjYmqvFLS6r+IKifHmQ8c2yJVo99AfOV4gF81IA7gv1XariQ5cW4x8G3gDDPrK9NnQel2N3BeqULnccDngcNjxu4G/uLurzWzy6qJf33u/nbg5WWaHwe+XM/4DZaUCNqI67tWTZ6rJIm2GxjIOA4lz1VAyXMiIiIiIiIiIiKtR8lzIiJ1Chns7xv/oUcI+vfNO5YsBENM676Tx4b2YWnmyU+djBs6bvlMXrRiec/fJs0uPNpzWECgneZbTDASbMLCjr2ChR3P+fdwXLiUKaPzwmnFVWw+GrBJOIlOticou6OuSLtqieS5ks8RLU6rtAJpB1FFgyOIktdG3P124DrgGuDqpCpVpUVKPyd5l++yi7LM7EF3v47yi5xe5O7bmlktiUjvimkbJTnpr5wtEtofqHHcajRijv8qVZc6KKZLo6omtZIVDZqnkoVmg9T+fm9GWf4+Eia0V1uxd5uE9vurHC9X7r4j8C3g9TmF0KrfN+IWCk8AftmoQGJUmgQZdw5clXWFSzN7yt1XU77Sh+R3jFRF8+qknshWqurc0DlLks6dWWmGa+7p9QxeSjD6BvCCesapQ6ueV6X5fRKYk9DnjeScPOfumxJVnIvb6ACi34aONbPHMg8qHScltD9JlDCYOXcvAH8i+XvRlcBbzWxhNeObWQhc6u7/AL4AGNHvXRvSA5zr7vvU+lq6+2TgezFdTs2wSnoWkjaP2aQBMVTyPSQpzjxUEtMmQLlE0LQkPX/N+Nw1XCN3JhAREREREREREZEUTD95yhBQdSUIERGJhAwP9fWecncYrGrLxLm1Cv1s330Piwkb9Eex3nDi4IlPzxj44KKlxSnD14SExYbMK5kKBoLNgyc6Dyjc0n104bLeowrnjd8zOKt3fHDxuCeCG7pv4tGO2fQF1zHCQ4QV7bIq0qrqqiLQSGa2HHgNsKjGITqBA4GPAOcA8939Lnf/f+7+vGoLpYpz5wNvTxj332Z2W0KfuApwQQVzPI+77058ste/61jgPy2hvRFJU41KzFrr5cDGMe03NiqQFvLfBVLufp67H5D2BO4+lcoqyv0+64SWBhvMO4AqJB0vljciiDS4+3uBO8gvcQ7KL4RtWu4+CRiXdxwVqLT6UNx7ulHnpqwXoLa6VjpGjllmlsfr1G7vjWa45k46z2+Qu2/i7ucCfyG/xDlowfOqtAYzmwvMTuj2ogaEUlbpN41Lgf0TuvYBLzeze7KPqn7uvgMwM6Hbb8ysUb/hf4po06Y4fwFeUm3i3LrMrGhmXyGqjB2X1L0J8JvSZlC1+D6U3bTwfDO7pMZx85K06UIjkucqmaMZNxiuJKZmeP6a8blrOFWeExERERERERERaU3LgPF5ByEi0mpCRkdW9n70trCw/LC8Y2mEwkr26HqQW4d3Zh+CiqqR1C2cOLrVwEmLtyrM73qg+4LJfYVVHXEJC9KCAoKAlcE2rCxsEzzy7J8bwyAcZrPig0wtLgmnFofYrDie3nALArYmUPUBaXmL8w6gGmZ2r7sfBFwAPC/hrQZ7lm6fdvcHgF+UbgcTLRjaO+H+RaKdv5OcA/yA8skF7wS+XsE464qrOgfxCXtJkr6Traxj7Eo1LHHA3ccDsWVMgP80IpYWs+5r9Ebgje7+T6Jd6v9jZiO1Dlxa6Pe60ljbJnQfBL5a61xSt6TjxfJGBFEvd/8a8Pm842hRjVgwmYZKqw/Fvacbcf6D6PiaVAVWRNpfM1xzV10Fs7T5wT+B/WoJSKSFnAvMiGnfzd0nljYCaih37wH+SnJS1xrglWZ2a+ZBpee9xFeDDYHfNCKQUmW/pN+EbgbemVYyn5n9xd0/R1TVs5yZwBuIkvYq5u4vo/zmTn3AR6sZr0k8ndA+sQExJM0xQnNunrEcGCU+EX1iA+JImiPpNR4TVHlORERERERERESkNWl3MBGRKoUUiyt7P35jsbB4TCTOrdWxjAM753EzYexOq6krbjm8y8CpCw8afN3Tc8Ku4r2NnFvyEYRBV7CsY+fgvq7DC1f1zCxc1HtI4ezx2wTn9a4O/tNzN3d1XsOiwmwGmEPYOlW8REpq3vU6L2b2JNECsI+SbuW8XYBvA88QJUolJc4B/MzMbk7qZGYrgItiuuzq7odWFCXg7gXgbTFdVhAtlKtVUgWhRizqacjCIXffD7iC+N34bzezhxoRT4vZ0OK/lwGXEVV2/Jm7H1taUFgRd9/W3U8C7iKq/JiUOAfwVzObV+kckrqkal7LGxFEPdz9Uyhxrh6VVnRrFXHnwEYtam3GxbMi0njNcM1dVWXR0qYUl6LEORkbrkxoD4BdGxHIuty9CzgPeElC10HgtWZ2TfZRpaP0W0jSRkJXmtmjjYgH+ADxG0mEwPvNrD/leb8JzE3oc3o1A5YqFf48pssXzGx+NWM2iaUJ7dMbEEPSphjLzKyhf+OqRCmmpHUbzfD8KXkOVZ4TERERERERERFpVUqeExGp0qpxn7u2WHjyqLzjyEPnAg4Pu5k9ukXsLr+ZGN11YP/+XRaEnTdvfF3XrAlbB8WgksXd0kaCkWBjFnXsGSx67uar4bhwKZuPPhlOK65g82KBTYqb0cX2BGycU6gicVoueQ7AzIaBH7n7b4HHgEkpDh+3o/K6bgM+VcW4vwNOjGl/J3BjhWO9GNg6pv0cMxuoNLANSNqweLiOsSuV6hzu/kqiBTedwKbANsALgQMquPvP0oxljJgCfLB0C939IaLPzHyiBNXlRMl3k0q3aUSvx/Y1zHVZ/eFKhppuEeC63P2FwP9VcZfHgZuA24GHgaeIqrj2EVUIGgKG4xY/ls5dSYt+W0lDKoE3UNw5sBHnv0bOIyLNrRmuuSv9brTWt4GDKuw7SnR9eAtwH/AIsIhog5RVwGpgpPTdryx3b+prDWlr9wH9xG8ksD2Vf8+vm7t3AH8CXpXQdQQ4wcz+nX1UqXop0Xf5OL9qRCAl701oP8/Mbk97UjML3f2LwCUx3Q53973N7M4Kh/0q5b+P3wz8tIoQm0nSRjvTGhBD0hyPNyCGWs0j+n2nHD1/TULJcyIiIiIiIiIiIq3pmbwDEBFpJavG+ezRjocanjjWTLoeZ0Y4jlnFzZjZ8MkDgpFDVh0+cuCqoa4rNp3deetGewUEkxsehzSVYCDYnCc7Nw+efPbfQsKQjcMnmVpcEE4dXc3kYjcbhVPoYHuCtltwLK2lJZPn1jKzle6+knST5yrxKNEO7dXsHv4vYAHld0x+s7ufbmZDFYz1zoT231UR14YMJrTH7ayelgkpj/cpqCnZ/hHgNynHMtYEwM6lm7SfpOPgZkSL35uOuwdE1RWSEgOeIVos+kczuy+FqYMUxmgmSeeMVjNI+UXwjTj/QfrnQBFpTc1wzV3xhhzufhDwoQq63gL8BLiwVKG7ZqVzuUguSglM84ivLje1UfGUqrL9GnhTQtci8HYz+1v2UaUuKVltOXBBA+LA3acDuyV0+32GIfydqKra5jF9jgESk+fcfTvgI2WaR4GTzWxDledbQVIVwmnuPq7ODaiSbJfQ3qhKibV4FDgwpj3psdWlVNE27j0Ozf38NYyS50RERERERERERFrT03kHICLSKlb3fGv2SMcdYzpxbq3u+5k5uBdXhxuTTwW+DrqHj10xY/jovr7uSzab1fHguEMCgvG5xCJNKSAIWBVszarC1sEjz/4pMwzCYSaGDzN1dFE4tTjMZsVxjA+3IGAbgrZbWC3NJyTa2V+qcw/wMjN7MrHnOsxs1N3/SPlqdZOA40lY6OXuGwOvj+nykJldV01sG5C0aKgRi/qbIXGgCLy/woRGkbEqKTFuIlDV8bKBXgfsk9DnX8BbzSzN36s2TXGsZrAmof0iM3ttIwJJyQDlk+cadW5qhnOg/36egAABAABJREFUiOSvGa65q0km+J+E9hHg02b2vSrGTNJu51RpPUkJoA35fXidTSGSNtoJgfeZ2TnZR5Uud58MvCah258yToJaV9LfIYaAWVlNXkrevBx4c0y3o4AfVDDcZpTfUOR24EB3j0ugqla5TaXWOtrdk3KBzjazVRXMlZRYFQA7AXdXMFatkjYSaubkr6TYst4k6QUkbz7zWMYxtAQlz4mIiIiIiIiIiLSm+XkHICLSCtZ0/2z2cOcNSpxbR/ddHD64PzfRwyG5BdETThh6w7KZQV/Hwu4LJt1aWNh1eECQVMlCxrAgDLp4JtiJZwo7Bfc/++9hZ7iaScXHw2mjTzOlWGTT4iaMYxsCpuQXrbShZ3Y75iIlBVXnN8CpZpaUKFDO7yifPAfRQrekXdLfSPwCvHqrzgEsS2hvhoW8jfARM7si7yAkVz15B9ACkpKwJzYiiBqdlNB+AfCmDKosbJbyeHlLOmfs0JAo0rOM8q+Rkuek1eg81tqa4Zq7ouTxUgWm4xK6nWBmF1YUVeXa7ZwqrSfpN5WuhkQB3wfeX0G/D5tZq1ZWfzvQndDnV40IpGTHhPZ7zCzrCtw3EZ88l1QZrxIHAL9MYZxqvKd0i3M5kJg8Z2Zr3P0xYPuYbruSbfLcLgntWc5dr6TY4ipvpiHpuXvEzPozjqElFPIOQERERERERERERGrySN4BiIg0u/6u31811HW5EufWE0BHz+3szQh35B1LOGF0+uC7lxw18J4ljxUnjNyYdzzSeoKRYKNgcccehTu7jypcMW5G4cLxBxTOGj8lOL/36eCq7rnc13kVSwtXM8RdhPTlHa+0rIV5B5CSi6Ehn4MPmdl760icw8zuBm6N6XKcu2+eMMy7YtpC4A9VB/Z8CxLat0xhjiRJO5FnqQ840cx+mmMMreZCIK8FS1lWap2c4djt4omE9qTFbrlw9/HAsTFdFgIfyCBxDqJKo22jdF5cGtOl1ZLn4s6BE929XFW6VJTem0qeaz9hTJvOY1JOM1xzV/qd8XjKVy0C+GUGiXPQZudUaUlJ1wWZf0dy928AH62g6yfN7GdZx5Oh9ya0zzGzOQ2JJJJ0jl3SgBgWJ7TrOiCS9L7YP6uJS98dkpIYG/m+rVZSbLu7+7gM5z8gob2Zn7uGUvKciIiIiIiIiIhIa1LynIhIjIGuv1wz2HXRUXnH0ayCIr09c9iOIg/mHQtAOG14p4FTFh06cMLSO8Ke4p15xyOtLxgMJgdPdu5XuK376MK/xh1V+Mv4vQpnjZ8Q/G3cU8H13TfzSMdsVgTXMsIDhIm7X4skJUi1BDP7CDAFeBXRLuMPZDTVkSmNE1cZrgt4S7lGd98WiEugn2Vmj9ca2DqSkmH2SWGOJPs2YI71rQZ+AuxiZufmMH/LMrPXE30O3wz8GUjjfQjRe/HXCX3iKjHWSwuykz2c0H5YQ6Ko3qHEVwL5lZlVVG2nGu7eAWyX9rhN4NGYtk1KFYlaRdw5sADslfH8e6O1j+1oJKZN5zEppxmuuZO+F6yV9Fvltyocp1pJlZ9EspZ0jZNYGase7v5l4DMVdP2SmX0ny1iy5O4HkXxMbGTVOUiufBm3uURakubQdUDktoT2AzOcez/ik8sHgPsynL9e9xDFWE4n2V6vJL02Sp4r6cw7ABEREREREREREalJ3GIbEZExbbDzHzcMdJ31QoJMdyVvecEom/bMpX9wf54kYOu84wEo7ji4T//pC+icM/7GrssnTg1Gg1arviBNLlhV2IpVha2CR5/9M2kYhCNMDB9m6ujicGpxiM2K4+gNp1NgGwItyBUA5uUdQFrMbAi4pHTD3ScDLwT2BLYnqnqzDVEll/HARkRJE0NEO8EvA6YCm8RM85KUwv0z8B3KJ228C/hRmbZ3El+dJC4xrxoPA4NAT5n2RiS2ZTnHKNHin6VESV5zgdnAv8ws08WN7czMVgPnlG64+xZEn8PdefZzuDWwMdFncDzR+p5BYA3RzvxPAA8RLW670czuLFVjjKsyEPe5rVdTXEs2uaSFiM2aPLd7Qvt5Gc27N9m+Z/MyBzg4pv1Y0qmM2gj3JLTvC9yc4fx5JI9L9gZj2nQek3LyvuYeoPLNDuPOq3PNLKtNro7IaFyRRKVqsUnVG5/KcP7PAFZB16+b2VeziqNBTkpoHyD6raWRRhPay/2ekqakOeIq344l1yS0H+HunWYWt9lBrV6U0H5DRvOmwsxG3P1G4jfymgnclPbc7t5F8nk+6bUdM5Q8JyIiIiIiIiIi0pqeIn6RpojImDTUMfuW/u4zDyCI3aVSSoIhpnffwaND+/A0AZPzjmetkf3XHDqy75qRrqsmXNV548a7BWEwNe+YpH0FYdDJM8FOPFPYKbj/2X8PO8I1TCo+xrTisnDq6CibFjdhHFsRMC2/aCUnbbtxRala0H+T6Srh7rsAd1E+qW2au+9iZnVVtjOzp939UuC1Zboc6O57mNmGFu+/I2bo1cD59cS2lpmNuvt9lF9Mu5W7TzWzxWnMt75ShaKkRYhVMbOZaY4nycxsAXBBCkP1JbRPTGGO53H3ccD+WYzdZuYQLRwt9z1lT3efYmZLGhhTJZKqv92b0bztusj/RuADMe3H0zrJc3cltGd9XDgg4/ElHyti2iZmOO/hGY4t2cv6mnsa8dfc95pZUnLIWnHn1aSk5Hq063lVWsNBJFeLzeR3F3f/CPCNCrp+z8y+kEUMjeLuvUQVzuNcYGbPNCKedaxOaJ/SgBiS5ljTgBhawXVEr9dGZdonEFUmvzaDuZM24vp3BnOm7d/EJ88dC3wzg3lfSPnXDKLX9PoM5m1J2ilRRERERERERESkBU0/eUoIPJZ3HCIizWS44+a5a3p+uCcB3XnH0koK/ezQdS8LCRP/kN1YBTqHZ/Yd3X/6go1G9lgzKyRcmXdIMrYEo8H4YEnHHsFdXUcWrhg3o3Dh+AMKZ42fFpzfuyyY3X0793ZexdLC1QxxB2HsIk9pfZVWERgTSklxSYtW0kro+m1C+zvX/wd3fyGwS8x9zk+5atp1Ce2vTXGu9b0+w7FbSdxi5XJJnm2nVFlyeUyXXTOa+mDQ9XcSM+sjSpwqp0BypYg8TIhpW1Z632Xh+IzGXSuv48blCe0vc/dW2Sgr6fz3GnfPZG1iadxXZzG25C4u+SmT85i7dxNfEVJaw2szHDvpmjvpeLiuuPPqwirGqZi7bwXsl8XYIhVKuq4bAOrafGdD3P19wA8q6PpzM/t42vPn4A0kJ5r/qgFxrC/p2NaI6q/bJLQvakAMTa/03e6qhG6p/w7l7lOAoxO6/SvteTOQ9FvpDHeflMG8b0xon5Xh9/aWo8pzIiIiIiIiIiIiretRslv8JiLSUoYLd969uucbLyCgN+9YWlFHH3vyELcMv4B9CZpskXl3uNHQq5+ZyYtXLO3566TbCk90Hx4QNFeMMqYEg8EknuqcFDz13H8PNyrOZ0pxfjhtdBWTi11sHG5OB9sTqFJwG2jbynN1uBY4LqZ985Tm+TuwNGa8t7v7582suM6/PS+hbj2/SyWyZ10JfCim/S3AL1Kec623ZjRuq4lbBDTWrg3nUX7B5D4Zzfm6jMZtR5cQX93og+7+zfWOaXmLS4ystMpOVUoVTl+WxdjryOW4YWbz3P02yldN2xQ4GfhhVjGkxcwWu/s9wB5lumwFHAXMzmD6Y0i58qo0jXkxbRPdfRszeyLlOV8OjEt5TGm8PK+5Z1UxVsPPq8CH0VpxyYm7dxJ9PuPcYmbDKc/7NuAMIEjo+lvglDTnztF7E9ofJfr9otGSflPbwd23M7PHM4zhxQntFf3uZ2ZzSX5PpcbdZxFfyew9ZvbblKc9D3hFTPuJ7v7pKiquVuIEyldoh2gz4VtTnC8rNwOPU77KbBfwJqJjUypKx9g3JXQ7L6352oEqz4mIiIiIiIiIiLQuVcAQEQFGCg/cv3rcl7ciYOO8Y2llHU9zUOc8biIkzDuWDdqouPng25bOGHj/4vnFScPXhYTNGaeMWcHqwpbBY50HFW7smVn4e+8RhXPH7xqc3dsZ/H3cI8EtXTcwr2M2q4IbGOUxQpppUbwkU/Lc8y1NaE8labS0gO7PMV22Yp1FUKVqPSfG9J9H+ovF/kV8EsbR7r5tynPi7jsSn4QzlsRVp93Y3Ru2uK0J3B/TtoO7T0tzMnefQHNWS2tWf4bYa4DtiD+G5aE/pm2yu8ctcqzVR8l+UWrccSOuKlAa/pTQ/jl3H59xDGm5OKH97RnN+46MxpX8xZ3HAF6YwZztUG1Isrvm3h44IqbLIMmVZtYVd16dWsU4FXH3XuD9aY8rUoV3kFxZ7J9pTujuryfaNCcpR+Js4CQza/nfmN19B2BmQrdf5/RY51TQ5+VZTe7uE4HDErrdkdX8Leh8omqQ5WxFihvolH6vOTWh259a4XNaijHuN0xIfqzVehMwPaa9H7gg5TlbmpLnREREREREREREWpeS50RkzBsNHn901bjPTyIoW2FDqtC5gCM6FnFV3nHECSePbDfwgcWHD7516b1h72glf3wXyU0QBh3B8sKOwQNdhxWu6ZlR+FvvYYVzxm8fnNs7GPy7577g9q5rWFCYTT+3UGRh3vHKBvXvdsxFC/IOogklVZZbkeJcSZXi1q009ypgs5i+f0h7wY2ZrQAui+lSAL6S5pwlX6eBO543uSUxbV3ANo0KpAnMjWkLSD8x60Nkn2jUNkrVFJIWB//Q3eMWvzVa3OerQPkKajVx9/2BD6Q5Zhlxj2vbjJIC1/o1sDqmfTrwhQznT9M5Ce3vKlUSTI277wm8Lc0xpanMTWh/c5qTufuhxFd0kdaR1TX314i/5r6s9H2gUnHnn4OrGKdSXyW9quAiVSklLX29gq7npjjnccBZxFexAvgr8I4mq/hcj/cSf6wqElXZazgzexhYlNDtYxlef3+c5Oqb12U0d8sxsz6Sk60+l+ImRa8HdotpD4HfpzRXI/wOYjen3MvdX5PGRO5eAD6T0O0CM4vbOGbMUfKciIiIiIiIiIhI61LynIiMaaPB/CdW9n5yHEE4Je9Y2knXY8woPMOsvONIUtx2aI/+0xbuP3j8slvCzuKDeccjUo1gNOgNlnTsFtzddWThynEzCheOP6hw9vjpwV96nwlm9dzBvZ1XsbRwNYPcQZhqEpJU77G8A2hSBya0p/ZdxcxuA+6K6fJ6d19bffadMf0guwU3v05of4e7p7YY1t2PoPmqU+XpiYT2PRoSRXO4JqH9XWktcnP3vYAvpzHWGPP/Eto3B37ViEAq9HBCe5pVB8YBfyRKes1a3HGjC9g5q4nNbDlwRkK3z7n7G7OKIS1mNof4ZKcu4DspT/t9khfES+u6hfhqJ8e5eyrVuUoVHpM2aZDWkvY19wuBtyR0S/oesL648+oeaSYcu/tM4PS0xhOpRimp4/fEV0QCmG1mD6Q054uIqmZ1J3T9B3CimY2kMW/eSs/1uxO6/dPMnmxAOOUkVSveDXhX2pOWKq9/LKFbP/CftOducUnX7weQ/J5LVPr+982Ebn9L6xjRCGZ2P3BJQrdvuXvScaoSJwH7JvT5dgrztJWkTFoRERERERERERFpXo/mHYCISF6KwdKFK3s/FhIUt8g7lnbUfT8zB/fmmnAjjsw7liSje/Uf1L9nf7Hzuk2u6bpmkx2DMNgy75hEahUMBZsxv2OzYP5z1wOH44sLmVJ8Mpw2uprJxQ42Djenk+0JGJdTqGNJy1xzu/tLgdDM/p3xPFsDx8d06QPSTmr+HfCtMm3jgTe6+6XAK2LGuD7DBTcXEz3mcskWAfBzdz/CzOIWhCdy942An9czRhu6L6H9lcRXB2wnNwDLoWxV5gOIkkzrShYoJayeBToPVcvMZrv7P4GXxXQ7zt2/ZWafalRcMW5OaD/V3X9gZknVJGKVkjrPoHHJrpUcN5L61OOrRAtOJ5VpD4DfufsCM7s2wzj+y933A1aYWbXXPt8lPjn9eHd/k5mdV3NwJe7+TuAl9Y4jzcvMhtz9Sspf0/UQJSG/J4XpfgLsmsI40jzSvObuBX5GfCWnB0leIL++m4EXx7R/FTihyjGfx923I0pIb1ilanffnuTvz25mX84+GtmQ0iYs16VdjX0D8xSIvrO+qoLu30hpzsOAv5H8/eQ/wOvNbCiNeZvES4GtE/rkvTnHn4H3JfT5gbvfZmZz05iwlJh1IbBJQteLzSyuKvSYY2a3ufu/gWNjun3P3WfV8N1hXd8Fdkzok7T5TEXc/d3AbxK6vcjMZqUw3TeIP/7tTPQb52m1TuDuO5Gc5PjPtD5P7USV50RERERERERERFqXKs+JyJhUZPnSvt5TVxOMbpt3LO2s+04OY5Cb8o6jIgGFkSNWHtn/ifmTRvZZPSskVKUuaSvBmsL04PHOgwo39cwo/KP3yMJ543cLzu7tCi4d92hwc9cNzOuYzcrgBkZ5lJDRvONtM610zb0H8C93v97dT3D31DfTLe2M/Gfid3K/LIMd3P8Ise/tdwFvJX4D4cwqi5hZkWiha5wDgN+4e83Vckqv6R+BvWodo03dBcQtdnunu2/VqGDyVFoEelFCt2+VFlrVpLR7/yz0PqzHacRXVgL4pLufmdKO9P/l7lu6+3fdfbdK+pd2zn8spssmwB/ridPdu4gq9yRVD03TjQntH1mnqmnqzOwZ4JMJ3cYDV7r7R7OKA6LKRO5+ETAHqOXYcDaQlJz+a3c/pIax/8vdjyK5Yp+0h3MT2t/l7q+pdXB373T335BCxRRpSmlcc3cQJQUnVXP5aul7QDX+mdD+Jnd/b5VjPoe77wpcAYyJ61+pyk+AW9z9taUEt9S5+3Tg38D7K+j+LzOre5OT0gYA/wCSrt2uAV5Tb3JtEzopoX0JUWJhbszsSqJrzTgbA5e4+571zlfadOhs4IUVdP9uvfO1qU8R/zvcpsDF7r55LYO7+6nAhxK6nWdm19cyfp7M7DqiKphxPuruSY9/g9x9CtEmXnGJoaPAp2sZv90peU5ERERERERERKRFTT95Sh/wdN5xiIg0UpFVK/rGn/I0wXDNC36lMgF09tzO3oxwZ96xVKyTcUPHLZ/Zf9qCcHSHgdkh4WDeIYlkJQiDjmBFYYfgwa7DCtf0zChc3HtY4ZzxOwTn9A4H/+q5L7i961rmF2axJriFIgvyjreFtUzluXUcBpwDPObuX680QSKJu29DlDBzVELXX6Qx37rMbCHwr5guM4jfsXmQ6DnJ0h+AWxP6vBk4p5aEDHefQLRr+murD629lZI1Z8d0mQD8x92PblBIeUuqTDgFmFVaWF0Vd38xcD1wYC2BSaSUkPaFCrqeRLTA+Yh653T3fd3950RJ4adTXdXAPye0vwS4sJaFk6Vz1FVsOIklsw0BzGwBcE9Ml+2Ay909KXGinhh+AyRVY+siqsLxN3ffP625S0mUn3T3u4ArgVfXOpaZDRMtro2zMVGCf1zFxbLc/dXA31G1y7HiXGBZTHsAnOvur612YHffmaga7btrikxaRT3X3JsAfwHemND1VqLr/2pdBTyR0OcX7v6RGsbG3d9FlCC+fiUfbbIjax1A9L3yAXf/TFqbjJQSk99BlCB1TAV3WQWcksK8uxH9VjAxoeuNwHHtVmHM3SeTfB33h9L1Wt4q+f6zFXCTu7+3VJm6aqXr91uAShLtLzazpE01xiQzu53k3xb2BK6q5rcFdy+4+5eBHyZ0XUPyZiPN7BNEjyHOT9z9S9W81919d6Jrid0Tuv7MzO6odNyxJPWd5kRERERERERERKShHgUm5x2EiEgjhPSv6hv/oScIBlXlokGCIr09c9hm8EAeosAL8o6nYr3hxMETn54RLO94quf8yY8GSzoPDwi0qaSMCUExGMfSjt1Y2kFA13//PewKV7B58fFw2ugKphRDJhQn0s22BIkLjMa6VkyeW2sr4HPA59z9XqJdia8ErjOzvkoHcfcDiaoBfYDkRetXmtl/aow3yW+BV5RpC4AdYu57kZktTzugdZlZ6O7vJ1qU1xXT9Q3Avu7+MTO7NGnc0iKa1wDfA7bfQJe5wH7VxtuGzgGOi2nfFZjt7o8CNxBVSVpBVLEurmLIbDN7MLUoG8DMbnD32URJpeVsDdzu7t8GvmdmZTfmKVUUO4po4drLN9BlBVG1u0ZWDWsH3wMOBU5I6Lc3cI27X06UnHyJmfUnDV563fYBjgdOBOpJpP4J0eK/npg+xwF3uvs3gN8knWdK55YPEVUO3dD6tQeA24E31RRxZc4BPKb9UGCuu99DtAD3IaCPaBFkGHO/S0vJeZU4iaja2wEJ/V4FvGqd98FsM1tc4RyUEkgOBo4meq0OJjp3psLM/ubu5xOd48rZFPh7KYnTzGxp0rilSpdfAd7H8+NdDSyAFvqeKhUxszXu/iPAYrp1EyXtngt8yczKVj8sXUvtS1QF6QNs+JjzY+DU2qOWnM3l+dfDa6+5TzezSyoZxN2PB75PchXOIeB9ZhZ3LtggMyu6+w+Ab8d06wB+WEoQ/X/Av+PmcvdxRBtsfJLyGxz8H/DFauOVZ7n7icRX+dmQpPP7zu7+vhrCOdvMVtVwv3XtBHwD+Lq73whcSrQhyS3VVGYrJc0cT7SZzTZVzP9uM3u4iv4bmnsCcDnR5iBxBomSYk90j7v0S9VtZnZbA+Z5B9E5Mc6vGxBHIjP7h7ufR/L1/XjgV8DH3f07wF/MbGXcHUoVQ48g2iTkNVR2nbsKqClReQz5LNFGKXHJcbsDt5Veqx+Z2ZINdSpdj70Y+DrRd5Ekp5nZvCrjbRpm9ri7f4z4DcYC4H+BV7r7F4Aryp3v3X0q8FHg40BvwvT3E/0eLBug5DkREREREREREZHW9ghwUN5BiIhkLWRooG/8KQ8SrEltt32pTDDKxJ659A/uz1MEpLIbcaOEE0e3Gjhp8VaF+V0PdF8wua+wqkPnTBmzguFgUxZ07BMs6HjOv4fjiwuZUnwqnFpcxeajnWwcTqKT7QkS/xA/VjySdwAp2b10+zRQLCUQ3QPMA+YDK4kWlPUQVYeZSpRosS+wRYVzrAROTjfs57gIWE7yjvIb8rtUIynDzOa4+xeJFrnGeQFwibvfDZxNtEjxfuAZosUzmxE9/zOJKmeUS3qZB3yJKDFyrDuHaPFn0vt1B+ITLdf3HqClkudKTgduJlp8XU4P0e7/n3X360v9FxMlw21GdBzYEXgR0XGhnPcT7TgvVSgl3L6bKNG5kspyLyndhtz9VuAu4DGiZK4RosSkzYDNiZLm9iV5IW2lsc5392+RvOh+OlHSwTfc/Wai99QiovdUdym2XYgeb9zi6mGihcB1VyNJ8HOiBaFJ1zx7lG6VehFUVvXXzFa6+3FE1QN2qeAua98HuPv9RM/xEqIqXcuIkoF7iM6V04me592IjntZbybyAaKEw61j+hSIXtf3lpLtLiWqUPMk0E/0WmxDlGxwPPA6yidtfh54PUqea1ffIkoujXs/QZSAfIK730dUIXkBsBTYiOg8tiXRZzLu+uCnwPkoea6V/Q9Rovf655YXABdv4Jp7eal9M6KEgBlE19yVHuu/aGZz64j3x8AHST5+HVO6LXD364C7ib4v9BO9x7cmSrI/nCjZpJxbiRbnK3muPv+PqDJtmg4v3ap1OVHiTxoKwAtLN4Bhd38YuI/o/LyI6HpzkOh6blLptjXRNd20Gub8lJmdX2fclOKo5LfqHqLzSiM50IjkufcktN9gZnc3II5KvZ/oe0ol1717EiX+/dLdbwdu4tnr3iGiY/hkomP34VSX3BoC7zKzx6u4z5hjZqvc/QSiDYjivjONJ/pt6rPufjXRd5QFRMeNzYh+j5xJ5Qm2fzSzM2uNu1mY2S/dfQbwtoSuhxId1x8vbYR0L9G1yjiia9iDiTY0qiTvaw3wphQSrNuWkudERERERERERERaW7ss5hURKStkZLiv98N3hkFfJTtSSgaCIbbovpNHhvZmGQGT8o6nWsUth3cZOHUhHfePm9N9yWbjguHC7nnHJNIsgjWF6TxemB6ss1wkJCwyIXyMqaOLwmnFfiYVxzE+nEqB7QhiEzHaUStXniunQLTLfFJFhWoMA2/NskKXmQ26+zlUn6C3EPhnBiFtkJl90933IXlxDESLwb5S41RDwNuJT44aM0rvj08Af847lmZQSuT8KvFVe9bqAI4s3ar1BTM7z92VPFcDM+t395cTJcDOrPBu3Tx3gXOjfIWo+me5ijbrGke0uO+oGuYJgfea2U3unmnynJktdvevEFU/yI2ZLXL3I4kSyar5zrsr8VUgGsrMlrn7q4kSAeMSbiF6j7yNys6VG/J3ouST19d4f2lyZrba3d8F/JvKEj93o7YKm38nqpZUyzlQmsdKouviy9lwBeh6rrnX9wczqysJp3Td+g7gaipbw70FUSW9uOqe5TwOvNrMhhtYcUtaWxe1H1OTFIFPmNn3Mxh7zHH3g4k2zYjzq0bEUikzW1H6/nMllSejdhBtrJBUybEaHzWzC1Icr22Z2R3u/jrgbyRvztLFs4nftfon0QYK7eIkouqYL62g73bAO+uYaxB4nZndWccYbS/rHWVEREREREREREQkW+24mFdE5L9CRkdX9p52S1hYpsS5nBXWsGPXvSwgZE3esdRqdNeB/fs/vmC3oWNWXBcWwnl5xyPSrAKCQtBX2D54qOvQwrU9MwsX9x5WOGf8jsE5vSPBP3vuD+Z2Xcv8wmzWBDdTZH7e8WZo2W7HXNSXdxAtYDXwRjO7pAFz1VJB7k9mNpp6JPHeS5QEkaWTzezqjOdoKWZ2FvCDvONoIv9LVEknK/9nZrkmHbWD0o7wrwCaemd9MxsCXku0CD8rReA0M/tjhnOs7/8BFzZwvg0ysyVECZS/zjmUupjZHKKEtiy/M94BvNnMihnOIU3AzK4APp7hFJcTXcOOZDiHNIiZXUW2VbABLgHel8ZAZnYD0XeGMI3xyngSeLmZtfN3dmkdy4BXKnEuVe9NaF9NVKG9qZjZo8DRwNwcph8gqjj34xzmbllm9k+iBO7VGU/1d6Lkr6GM52kYMxskqqb9j4ynWgW8wcz+lfE8LU/JcyIiIiIiIiIiIq1NledEpG2FhOHKcZ+6vlhY2OiqClJGRx97dj3MPYS07uKygGDkkFWH939i/vThA1fNDgmfzjskkVYRFIOe4OmOXYN7uo4ozBo3o/DX3oMLZ4/fMjivd0VwZc+d3N15FYsLVzHIXEKeyTveFOhaO9k1wKFm9rdGTGZm1wMPVHm3WhLu6lJa6PM6IIsEkBHg3Wb22wzGbnlm9jHgk0B/zqHkrpRY8lbg7JSHHiZK3vx8yuOOWWY2YGbvJ3q9FucdTzlm9iRwBHBdBsOvAl5vZj/KYOyySp+TNwHfAhqdaL1+LGvM7CSihal5bPRxHfBYvYOY2b+BlwFZfM+6ATjGzFZmMLY0ITP7AXA6UXJtmn4FHGdmY/56oZ2Y2W+Ikkmy+M3qD0TnqdQW9JvZH4gSjlekNeY6bgYOMbP7MhhbpFp/BnY3s8vyDqRduHsv8JaEbuc26zWTmc0DDgd+RPrn+HLmAoeb2e8bNF9bKW2Y9ULg4QyGD4k2NXlVO16bmdka4Hjgm2STNP8w8EIzy3oTr7ag5DkREREREREREZHWpgW9ItK2Vo37wtXFjsePzDsOea6OpRzU+QQ3Ema6O3b2OugePnbFjP7TF3SN7Nw/KyRs2Yp6InkLhoNNgwUdexdu7z66cPm4owvnj9+vcNb4zYILxy0Krum+jQc7Z/NMcA3D3NNi1Stb7Vr7d8B7iCpNZV0xbwHRbt1HmdndGc+1vmoWOs0xszsziySGmQ2b2TuAD5FeBZ7HgGPNrOEJga3EzL4D7EZUhW5pzuHkysyGzOwtwGmks0v8rcDBZvaLFMaS9ZSqJ+5ClMiVxULXEPgPUbLYXbUMYGZPEVVI+z7pJZtdDOxpZhelNF5VzGzUzD4N7ENU+S3XRcZmdgGwK/AZyLzC7+PAV4GdzewIM3sojUHN7BpgP+CqNMYjeu+eQZQ4p81PxphSlaKXkkJyJ7AIeJOZvc/MhlMYT5pMKYHuZaSXhLwa+KCZvTOL94yZ/RU4mOgaKw1rgM8SJYgsSGlMaR+zadz3oyJwEXCQmb3NzJp2g4gW9QZg04Q+v2pEILUys34z+yhwENH3gaz+1vAY0e8yB5WqJEuNSr+v7QN8HUgrmXwucISZfbadK0ubWdHMPkO0Gc3clIYdInot9jazmr7fj0WdeQcgIiIiIiIiIiIidZlHtFipI+9ARETStKrnq7NGO+6fmXccsmGd8zki7GH26DRm5B1L3XrCCUNvWDYz6OtY2H3BpFsLC7sODwh0XhVJQdBfmMa8wrRgnWWLIWGRCeE8phQXhNNGB5hU7GajcCoFtiNour9f35N3ANUws2eA3wK/dfcu4GjgRUQ7Qx8CbFznFANEC5r+AFyW44LjPwD/S2WbBeeeZGZmP3f3S4CvEVWVquV9vhz4CfANM1uVYnhtq7ST/cfc/RPAoUQLlPYBdgKmA5OBXqLXI8grzkYxsx+6+1+ATxEl2SYttFzfLUQJXX9p5wVtzcDMVgCfdvevEb1WbyZ6D9dqhKha12XAOWkkR5WO/6e7+4+JErzeBXRXOcwg8FfgB6WqohvyKOWTCVJPKjOze4CT3P0UomPG4cCeRMeNacAkoAfoSnvuDcQyAHzT3b9LVMn0zUTJIBvVOfRq4Grg8tLtDjPLZKGymT3p7jOJzn3/C+xY41BXAV8ys7QS8aQFmdl/3H1P4ANECeHbVznEE8APgTOatQqPpMfMrnD3vYDPAadQ/XUPRJV2/wx8oZQ4nhkze9DdDyaqSvN54LAahnkK+CXwczNbVKZPXIJe1sna0gTM7DR3/xiwN9FvBUcCBwA7kM53olGi99mFwB9LVYslGycltN9vZtc2JJI6lRLaXu3uuxF9r3gT0fV3PVYRff/5E3CJmWVRkXRMKlVR+4K7/wQ4FXgfMKXKYYrALKINjy4ZS78xmNn17n4g0Tn/NKKNaaothraYKDn2x2am83eVgjBs7U1BRURERERERERExrqFZyx5lOoXDIiINK3VPd+fNdx59cy845BkQ7sxuzixDRLo1hEs6nq45/xJSwt9nfUsUhaRKoWFcJDNio8ztbgknDo6wmbheMaFW1JgqxzDOmG3Yy46L8f5U+PuHUQL5PYmWoT0AqJF7FOIkuo2BsYTVSroA1YQJWzdB8xZezOzNCpXjVnuviVRMszxRBUm4pK1VxAtJvobcK6S5iQt7t5DVMHnaJ5dLDuFKJlwmKjq1nzgbuBm4GIzezifaAX+e+w4kmgx/a48+5ptRJTM1U/0uq0ElhAdu+8jeg2vMbNMq5G6+wSeTdg+GJhKlKA6keg9tQp4GnigFNdVwCydU6rj7uOInt9DiJKBtwe2IXqexxMl9a3m2ffCCqJKG/etc7srj+R3dy8ArwBOJEoCnBrTvQjcC1wKnGdmt2QfobQSdw+IjocvIfo87ARsSXRMDIne/08TbYQxF/gHcFNWiaLS3Nx9E+AE4NVEC9QnxHQfBW4i2jDkt3lVbnP3nYjOqS8iOu9PLt3Wfl9bSZQsdz9wO1Ey9O16j0utStdy+xFtGrAd0fXFNkSbjqz9rWA80ffXQaJrz2VEFennEV1z3g5cX9rUR6Qu7r4d0feLfYDdga2I3o+bEH3/KRBV3VpD9P1nAfAwUXXtm4jO+y2fMOfu7yb+7/9/NbO5DQmmjNJ1/iHAsTz7ek0heq26ib4L9gGPEF2bXUe0IVejqmA2NXefArycaOOzPYh+q51AdOwdIjrnLyb6LncH8G+i9/eYSThMm5LnREREREREREREWtzCM5b8Bzgm7zhERNKwpvuXs4e6LmurZKx2FkI4tA/XhuM5Mu9Y0lZ4pOeOnosmBcFgYe+8YxEZy8KusI/JxcfDaaPLmVIsMqG4KT1sQ8DkBky/527HXNRS1eekdbh7L9Fi2G2JFsZ0EC2KWQ48aGZP5BediIhIdtx9a6Jz4CSihKdBnk0Guc/M+nMMT0TamLtvA+wMbEa0MH2E6PjzOFGlpoEcwxMRERGRDCl5TkREREREREREpMUtPGPJGcAH8o5DRKRe/V1/vnqw+/yj8o5DqhPCyOD+zKGHg/OOJQudc8bf2HX5xKnBaLBD3rGIyLPC3uISNi8+EU4rrmTz0QKbhJPpZDsCNkppimFgo92Ouajh1VlERERERERERERERCQ9Sp4TERERERERERFpcQvPWHIK8JO84xARqcdA11+vHej6wwsJKOQdi1QvLLBm8AAeppP2rNJWZKTrqgnXdd648W5BGEzNOxwR2bCQMGST8AmmFheGU0fXMLnYw/hwCh1sT0BnlcPds9sxF+2ZSaAiIiIiIiIiIiIiItIw1f6BQERERERERERERJrPbXkHICJSj8HOf9840PWHQ5U417qCIuN75rL14AE8TIGd8o4ndQU6h2f2HT18+MrV3ZdNnNVxT++BAcEmeYclIs8VEASsDLZlZWHb4OFn/xQeFsIhJhYfZGpxSTi1OMRmxY3oDbcgYCsCgjLD3d2YqEVEREREREREREREJEtKnhMREREREREREWl9twOjQEfegYiIVGuo49pb+7t/vl8NFYGkyQQjbNZ9OwND+7GAgC3yjicT3eFGQ69+ZiYvXrG056+Tbis80X14QNCVd1giEi8oBt0s69iZZR07B/c9++9hZ7iSycV54bTRZUwphmxa3IQetiFgc+Ce3AIWEREREREREREREZHUBGEY5h2DiIiIiIiIiIiI1GnhGUvuAvbMOw4RkWoMd9x2x+qer72AgPF5xyLpKY7n4aG9mUTAZnnHkrXg6c7He86f9FSwrPOFAUG56lUi0mLCceESNi2+b9evnfu3vGMREREREREREREREZH6FPIOQERERERERERERFJxW94BiIhUY6Rw9z2re762vRLn2k9hDTt13ctThKzJO5ashZNHthv4wOLDB9+69N6wd3RO3vGISDqCgWBKsKjjvuSeIiIiIiIiIiIiIiLS7JQ8JyIiIiIiIiIi0h6UPCciLWOk8PCDq8b9zxYETMg7FslGRx97dT3M3YSM5B1LIxS3Hdqj/7SF+w8ev+yWsLP4YN7xiEjd1gAP5R2EiIiIiIiIiIiIiIjUT8lzIiIiIiIiIiIi7UHJcyLSEkaDJx5bNe4zmxKwWd6xSLY6lnJw5xPcQEiYdyyNMrpX/0H9n1iw09BRfdeEQTg/73hEpGZ373LmWcW8gxARERERERERERERkfopeU5ERERERERERKQ9zIGxk5wgIq1pNFj01Mrej3cRhFPzjkUao3M+R3YsYXbecTRUQGHkiJVH9n9i/qSRfVbPCglX5B2SiFTtjrwDEBERERERERERERGRdCh5TkREREREREREpA1MP3nKSuChvOMQESmnGCxbvLL3oyMExa3yjkUaq+sRZhaWj7EEOoBOxg0dt3xm/2kLwtEdBmaHhIN5hyQiFbs97wBERERERERERERERCQdSp4TERERERERERFpH7flHYCIyIYU6VvW13tKH8HIdnnHIvnouo+jgzVcm3ccuegNJw6e+PSMgQ8uWlqcMnxNSFjMOyQR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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "image/png": {
+ "height": 522,
+ "width": 1767
+ }
+ },
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "(, )"
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# combined cost into pie chart\n",
+ "Z.plot_history_stats(fn=cost_node)"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "id": "e0d73540-d84c-4737-b4bb-0236751344ea",
+ "metadata": {},
+ "source": [
+ "# scaling of every computational node"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "id": "f61bc762-e72a-4a87-86f3-965990a14722",
+ "metadata": {},
+ "source": [
+ "For actual complexity we need decomposed scaling of every node:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "id": "bf6bbec1-aa13-4035-b7bf-e32ecb31ded7",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[{'cost': 354294,\n",
+ " 'name': 'qr_stabilized_numba',\n",
+ " 'freq': 14,\n",
+ " 'p': 1,\n",
+ " 'D': 11,\n",
+ " 'chi': 0},\n",
+ " {'cost': 354294, 'name': 'tensordot', 'freq': 7, 'p': 1, 'D': 11, 'chi': 0},\n",
+ " {'cost': 236196,\n",
+ " 'name': 'qr_stabilized_numba',\n",
+ " 'freq': 2,\n",
+ " 'p': 2,\n",
+ " 'D': 10,\n",
+ " 'chi': 0},\n",
+ " {'cost': 236196, 'name': 'tensordot', 'freq': 1, 'p': 2, 'D': 10, 'chi': 0},\n",
+ " {'cost': 65610,\n",
+ " 'name': 'qr_stabilized_numba',\n",
+ " 'freq': 7,\n",
+ " 'p': 1,\n",
+ " 'D': 8,\n",
+ " 'chi': 1},\n",
+ " {'cost': 65610, 'name': 'tensordot', 'freq': 7, 'p': 1, 'D': 8, 'chi': 1},\n",
+ " {'cost': 60750,\n",
+ " 'name': 'qr_stabilized_numba',\n",
+ " 'freq': 112,\n",
+ " 'p': 1,\n",
+ " 'D': 5,\n",
+ " 'chi': 3},\n",
+ " {'cost': 60750, 'name': 'tensordot', 'freq': 56, 'p': 1, 'D': 5, 'chi': 3},\n",
+ " {'cost': 43740, 'name': 'tensordot', 'freq': 1, 'p': 2, 'D': 7, 'chi': 1},\n",
+ " {'cost': 39366, 'name': 'tensordot', 'freq': 8, 'p': 1, 'D': 9, 'chi': 0}]"
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "scalings = compute_cost_scalings(Z, factor_map)\n",
+ "\n",
+ "# these are sorted by cost\n",
+ "scalings[:10]"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "id": "37147f85-3dd8-4e70-83d6-3510d0f98cdc",
+ "metadata": {},
+ "source": [
+ "If assume some relation like $\\chi \\sim D^p$ then you order all nodes. Or you\n",
+ "can plot the scaling of each like so:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "id": "b36cd47a-6491-4027-aea7-d1b7aa030570",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {
+ "image/png": {
+ "height": 241,
+ "width": 557
+ },
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import matplotlib as mpl\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "with mpl.style.context(qu.NEUTRAL_STYLE):\n",
+ " plt.scatter(\n",
+ " x=[s[\"D\"] for s in scalings],\n",
+ " y=[s[\"chi\"] for s in scalings],\n",
+ " c=[s[\"freq\"] for s in scalings],\n",
+ " s=400,\n",
+ " marker=\"s\",\n",
+ " clip_on=False,\n",
+ " alpha=1.0,\n",
+ " )\n",
+ "\n",
+ " plt.xlabel(\"$D$ scaling\")\n",
+ " plt.ylabel(\"$\\\\chi$ scaling\")\n",
+ "\n",
+ " plt.xlim(-0.5, None)\n",
+ " plt.ylim(-0.5, None)\n",
+ " plt.gca().set_aspect(\"equal\")\n",
+ " plt.colorbar(label=\"Repeats\", shrink=0.6)\n",
+ " plt.show()"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/venv/Lib/site-packages/autoray/lazy/__init__.py b/venv/Lib/site-packages/autoray/lazy/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..07584904c37ea36ed8529b4da931f9c1253f7693
--- /dev/null
+++ b/venv/Lib/site-packages/autoray/lazy/__init__.py
@@ -0,0 +1,154 @@
+from . import linalg
+from .core import (
+ Function,
+ LazyArray,
+ Variable,
+ add,
+ angle,
+ arccos,
+ arccosh,
+ arcsin,
+ arcsinh,
+ arctan,
+ arctanh,
+ argsort,
+ array,
+ ascend,
+ broadcast_to,
+ clip,
+ compute,
+ concatenate,
+ conj,
+ cos,
+ cosh,
+ descend,
+ diag,
+ diagonal,
+ einsum,
+ empty,
+ equal,
+ exp,
+ expand_dims,
+ eye,
+ flip,
+ floordivide,
+ get_source,
+ identity,
+ imag,
+ kron,
+ log,
+ log2,
+ log10,
+ matmul,
+ multiply,
+ ones,
+ permute_dims,
+ prod,
+ real,
+ reshape,
+ shared_intermediates,
+ sign,
+ sin,
+ sinh,
+ sort,
+ split,
+ sqrt,
+ stack,
+ take,
+ take_along_axis,
+ tan,
+ tanh,
+ tensordot,
+ trace,
+ transpose,
+ truedivide,
+ where,
+ zeros,
+)
+from .core import abs_ as abs
+from .core import complex_ as complex
+from .core import max_ as max
+from .core import min_ as min
+from .core import sum_ as sum
+
+__all__ = (
+ "abs",
+ "add",
+ "angle",
+ "arccos",
+ "arccosh",
+ "arcsin",
+ "arcsinh",
+ "arctan",
+ "arctanh",
+ "argsort",
+ "array",
+ "ascend",
+ "broadcast_to",
+ "clip",
+ "complex",
+ "compute",
+ "concatenate",
+ "conj",
+ "conj",
+ "cos",
+ "cosh",
+ "descend",
+ "diag",
+ "diagonal",
+ "einsum",
+ "empty",
+ "equal",
+ "exp",
+ "expand_dims",
+ "eye",
+ "flip",
+ "floordivide",
+ "Function",
+ "get_source",
+ "identity",
+ "imag",
+ "kron",
+ "LazyArray",
+ "linalg",
+ "log",
+ "log10",
+ "log2",
+ "matmul",
+ "max",
+ "min",
+ "multiply",
+ "ones",
+ "permute_dims",
+ "prod",
+ "real",
+ "reshape",
+ "shared_intermediates",
+ "sign",
+ "sin",
+ "sinh",
+ "sort",
+ "split",
+ "sqrt",
+ "stack",
+ "sum",
+ "take",
+ "take_along_axis",
+ "tan",
+ "tanh",
+ "tensordot",
+ "trace",
+ "transpose",
+ "truedivide",
+ "Variable",
+ "where",
+ "zeros",
+)
+
+
+try:
+ from opt_einsum.backends.dispatch import _aliases
+
+ _aliases["autoray"] = "autoray.lazy"
+except ImportError: # pragma: no cover
+ pass
diff --git a/venv/Lib/site-packages/autoray/lazy/core.py b/venv/Lib/site-packages/autoray/lazy/core.py
new file mode 100644
index 0000000000000000000000000000000000000000..cbeafd888be57d0b0c450a79971bae61b4d9ba69
--- /dev/null
+++ b/venv/Lib/site-packages/autoray/lazy/core.py
@@ -0,0 +1,2040 @@
+"""Core lazy array functionality."""
+
+import collections
+import contextlib
+import functools
+import itertools
+import operator
+import threading
+
+from ..autoray import (
+ astype,
+ get_dtype_name,
+ get_lib_fn,
+ infer_backend,
+ multi_class_priorities,
+ register_backend,
+ register_function,
+ shape,
+ tree_flatten,
+ tree_iter,
+ tree_map,
+ tree_unflatten,
+)
+from .draw import (
+ plot_circuit,
+ plot_graph,
+ plot_history_functions,
+ plot_history_size_footprint,
+ plot_history_stats,
+)
+
+_EMPTY_DICT = {}
+get_depth = operator.attrgetter("_depth")
+get_data = operator.attrgetter("_data")
+get_dtype = operator.attrgetter("dtype")
+
+# ------------------------ traversal and computation ------------------------ #
+
+
+def is_lazy_array(x):
+ """Check if ``x`` is a lazy array."""
+ return isinstance(x, LazyArray)
+
+
+def to_queue(lz):
+ """Parse a pytree of lazy arrays into a queue of nodes, sorted by depth.
+ This is useful for traversing the computational graph of multiple outputs
+ in topological order.
+ """
+ if isinstance(lz, LazyArray):
+ return [lz]
+ queue = tree_flatten(lz, is_lazy_array)
+ queue.sort(key=get_depth)
+ return queue
+
+
+def descend(lz):
+ """Generate each unique computational node. Use ``ascend`` if you need to
+ visit children before parents.
+
+ Parameters
+ ----------
+ lz : pytree of LazyArray
+ The output node(s) of the computational graph to descend.
+
+ Yields
+ ------
+ LazyArray
+ """
+ queue = to_queue(lz)
+ seen = set()
+ while queue:
+ node = queue.pop()
+ nid = id(node)
+ if nid not in seen:
+ yield node
+ queue.extend(node._deps)
+ seen.add(nid)
+
+
+def ascend(lz):
+ """Generate each unique computational node, from leaves to root. I.e. a
+ topological ordering of the computational graph. Moreover, the nodes
+ are visited 'deepest first'.
+
+ Parameters
+ ----------
+ lz : pytree of LazyArray
+ The output node(s) of the computational graph to ascend to.
+
+ Yields
+ ------
+ LazyArray
+ """
+ queue = to_queue(lz)
+ visited = set()
+
+ while queue:
+ node = queue[-1]
+ unvisited_deps = [c for c in node._deps if id(c) not in visited]
+ k = len(unvisited_deps)
+ if k == 1:
+ # single unvisited dependency, add it to the queue
+ queue.append(unvisited_deps[0])
+ elif k >= 2:
+ # sort dependencies by depth and add them to the queue
+ unvisited_deps.sort(key=get_depth)
+ queue.extend(unvisited_deps)
+ else: # k == 0:
+ # all dependencies visited, yield this node
+ queue.pop()
+ nid = id(node)
+ if nid not in visited:
+ yield node
+ visited.add(nid)
+
+
+def compute(lz):
+ """Compute the value of one or more lazy arrays. All nodes that are
+ computed clear any references to their function, arguments and
+ dependencies, and store the result in their ``_data`` attribute.
+
+ Parameters
+ ----------
+ lz : pytree of LazyArray
+ The output node(s) of the computational graph to compute.
+
+ Returns
+ -------
+ array or tuple of array
+ The computed value(s) of the lazy array(s).
+ """
+ for node in ascend(lz):
+ node._materialize()
+ return tree_map(get_data, lz, is_lazy_array)
+
+
+def compute_constants(lz, variables):
+ """Fold constant arrays - everything not dependent on ``variables`` -
+ into the graph.
+
+ Parameters
+ ----------
+ lz : pytree of LazyArray
+ The output node(s) of the computational graph.
+ variables : pytree of LazyArray
+ Nodes that should be treated as variable. I.e. any descendants will
+ not be folded into the graph.
+ """
+ variables = set(tree_iter(variables, is_lazy_array))
+
+ # must ascend
+ for node in ascend(lz):
+ if not any(c in variables for c in node._deps):
+ # can fold
+ node._materialize()
+ else:
+ # inherit variable status
+ variables.add(node)
+
+
+def get_source(lz, params=None):
+ """Write the source code of an unravelled version of the computational
+ graph, injecting required runtime objects into ``params``.
+
+ Parameters
+ ----------
+ lz : LazyArray or sequence of LazyArray
+ The output node(s) of the computational graph to write the source code
+ for. Their corresponding label is ``f"x{id(node)}"`` in the
+ source code.
+
+ Returns
+ -------
+ str
+ The source code of the computational graph, suitable for ``exec``.
+ """
+ if params is None:
+ # locals space mapping LazyArray names to values
+ params = {}
+
+ delete_checked = set()
+ s = [] # source code lines
+
+ for node in reversed(tuple(ascend(lz))):
+ # when *descending*, the first encounter of a node is the
+ # *last* time it is referenced in forward pass -> delete,
+ # need to do this for GC since running in single big function
+ for c in node._deps:
+ if c not in delete_checked:
+ if c._deps:
+ # is an intermediate - safe to delete. While we could
+ # delete input variables, we want to keep input *constants*
+ s.append(f"del x{id(c)}")
+ delete_checked.add(c)
+
+ if node._data is None:
+ # create the array via computation
+ s.append(node.as_string(params))
+ else:
+ # inject the already computed data as constant
+ params[f"x{id(node)}"] = node._data
+
+ # reverse (ascend) into source code
+ return "\n".join(reversed(s))
+
+
+class Function:
+ """Get a compiled (by python ``compile``), function that performs the
+ computational graph corresponding to ``inputs`` -> ``outputs``. The
+ signature of the function is ``func(input_arrays) -> output_arrays``. As an
+ intermediate step, the computational graph is traced to a flattened source
+ code string.
+
+ Parameters
+ ----------
+ inputs : pytree of LazyArray
+ The input node(s) of the computational graph.
+ outputs : pytree of LazyArray
+ The output node(s) of the computational graph.
+ fold_constants : bool, optional
+ If True, fold constant arrays (those with no dependence on ``inputs``)
+ into the graph ahead of compile.
+
+ See Also
+ --------
+ get_source, compute
+ """
+
+ __slots__ = (
+ "_in_names",
+ "_out_names",
+ "_out_tree",
+ "_source",
+ "_code",
+ "_locals",
+ )
+
+ def __init__(self, inputs, outputs, fold_constants=True):
+ if fold_constants:
+ # compute everything not dependent on inputs
+ compute_constants(outputs, variables=inputs)
+
+ # write source and populate locals mapping that function will run
+ # under, locals will include the functions and other constant objects
+ self._locals = {}
+ self._source = get_source(outputs, params=self._locals)
+
+ # compile source
+ self._code = compile(
+ source=self._source,
+ filename="",
+ mode="exec",
+ optimize=1,
+ )
+
+ # get names to inject and extract arrays into and from locals
+ self._in_names = tuple(f"x{id(v)}" for v in tree_iter(inputs))
+ outs_flat, self._out_tree = tree_flatten(outputs, get_ref=True)
+ self._out_names = tuple(f"x{id(v)}" for v in outs_flat)
+
+ def __call__(self, *args):
+ # this allows any matching zipped tree
+ for name, array in zip(self._in_names, tree_iter(args)):
+ self._locals[name] = array
+
+ # run the byte-compiled function with the updated locals
+ exec(self._code, None, self._locals)
+
+ # remove inputs from locals
+ for name in self._in_names:
+ del self._locals[name]
+
+ # pop outputs from locals
+ outs = tuple(self._locals.pop(name) for name in self._out_names)
+
+ # return the outputs in the original tree structure
+ return tree_unflatten(outs, self._out_tree)
+
+ def __getstate__(self):
+ # can't pickle the code object -> recompile in setstate
+ return (
+ self._in_names,
+ self._out_names,
+ self._out_tree,
+ self._source,
+ self._locals,
+ )
+
+ def __setstate__(self, state):
+ (
+ self._in_names,
+ self._out_names,
+ self._out_tree,
+ self._source,
+ self._locals,
+ ) = state
+
+ # recompile the source
+ self._code = compile(
+ source=self._source,
+ filename="",
+ mode="exec",
+ optimize=1,
+ )
+
+ def print_source(self):
+ """Print the source code of the compiled function."""
+ print(self._source)
+
+ def __repr__(self):
+ insig = f"{len(self._in_names)} input(s)"
+ outsig = f"{len(self._out_names)} output(s) "
+ return f" {outsig}>"
+
+
+# --------------------------- computational nodes --------------------------- #
+
+
+class Placeholder:
+ """A singleton object to use as a placeholder in a LazyArray."""
+
+ __slots__ = ()
+
+ def __repr__(self):
+ return "Placeholder"
+
+
+PLACEHOLDER = Placeholder()
+
+
+class LazyArray:
+ """A lazy array representing a node in a computational graph.
+
+ Parameters
+ ----------
+ backend : str
+ The backend of the array were it to be computed. This can be ``None``
+ but this may cause problems when propagating information about which
+ functions to import to child nodes.
+ fn : callable
+ The function to call to compute the array, presumable imported from
+ ``backend``. This can be ``None`` if the array already has data (e.g.
+ is an input).
+ args : tuple
+ The positional arguments to pass to ``fn``, which might be
+ ``LazyArray`` instances.
+ kwargs : dict
+ The keyword arguments to pass to ``fn``, which might be
+ ``LazyArray`` instances.
+ shape : tuple
+ The shape of the array that ``fn(*args, **kwargs)`` will return, or
+ the shape of the array that ``data`` has.
+ deps : tuple, optional
+ The ``LazyArray`` instances that ``fn(*args, **kwargs)`` depends on.
+ If not specified, these will be automatically found from ``args`` and
+ ``kwargs``, specifying them manually is slightly more efficient.
+
+ """
+
+ __slots__ = (
+ "_backend",
+ "_fn",
+ "_args",
+ "_kwargs",
+ "_shape",
+ "_data",
+ "_deps",
+ "_depth",
+ )
+
+ def __init__(
+ self,
+ backend,
+ fn,
+ args,
+ kwargs,
+ shape,
+ deps=None,
+ ):
+ # info required to perform the computation
+ self._backend = backend
+ self._fn = fn
+ self._args = args
+ if kwargs is None:
+ self._kwargs = _EMPTY_DICT
+ else:
+ self._kwargs = kwargs
+
+ # resulting array information
+ self._shape = shape
+ self._data = None
+
+ # lazy arrays this ``LazyArray`` depends on
+ if deps is None:
+ # automatically find them
+ self._deps = (*find_lazy(self._args), *find_lazy(self._kwargs))
+ else:
+ # manually specified (slightly more efficient)
+ self._deps = deps
+
+ # tracking depth helps when ordering the computational graph
+ if self._deps:
+ self._depth = max(d._depth for d in self._deps) + 1
+ else:
+ self._depth = 0
+
+ @classmethod
+ def from_data(cls, data):
+ """Create a new ``LazyArray`` directly from a concrete array."""
+ obj = cls.__new__(cls)
+ obj._backend = infer_backend(data)
+ obj._fn = obj._args = obj._kwargs = None
+ obj._shape = shape(data)
+ obj._data = data
+ obj._deps = ()
+ obj._depth = 0
+ return obj
+
+ @classmethod
+ def from_shape(cls, shape, backend="numpy"):
+ """Create a new ``LazyArray`` with a given shape."""
+ obj = cls.__new__(cls)
+ obj._backend = backend
+ obj._fn = obj._args = obj._kwargs = None
+ obj._shape = tuple(map(int, shape))
+ obj._data = PLACEHOLDER
+ obj._deps = ()
+ obj._depth = 0
+ return obj
+
+ def to(
+ self,
+ fn,
+ args=None,
+ kwargs=None,
+ backend=None,
+ shape=None,
+ deps=None,
+ ):
+ """Create a new ``LazyArray``, by default propagating backend, shape,
+ and deps from the the current LazyArray.
+ """
+ return LazyArray(
+ fn=fn,
+ args=args if args is not None else (self,),
+ kwargs=kwargs,
+ backend=backend if backend is not None else self._backend,
+ shape=shape if shape is not None else self.shape,
+ deps=deps if deps is not None else (self,),
+ )
+
+ def _materialize(self):
+ """Recursively compute all required args and kwargs for this node
+ before computing itself and dereferencing dependencies. Note using this
+ to materialize a large computation from scratch should be avoided due
+ to the recursion limit, use ``x.compute()`` instead.
+ """
+ if self._data is None:
+ # materialize any actual array args
+ args = (maybe_materialize(x) for x in self._args)
+ kwargs = {k: maybe_materialize(v) for k, v in self._kwargs.items()}
+
+ self._data = self._fn(*args, **kwargs)
+
+ # free any references to deps
+ self._fn = self._args = self._kwargs = None
+ self._deps = ()
+
+ return self._data
+
+ descend = descend
+ ascend = ascend
+
+ def compute(self):
+ """Compute the value of this lazy array, clearing any references to the
+ function, arguments and dependencies, and storing the result in the
+ ``_data`` attribute as well as returning it.
+
+ Unlike ``self._materialize()`` this avoids deep recursion.
+ """
+ for node in self.ascend():
+ node._materialize()
+ return self._data
+
+ compute_constants = compute_constants
+
+ def as_string(self, params):
+ """Create a string which evaluates to the lazy array creation."""
+ # name function and store in locals
+ fn_name = f"{getattr(self._fn, '__name__', 'fn')}{id(self._fn)}"
+ params.setdefault(fn_name, self._fn)
+
+ # string of args and kwargs
+ str_call = ", ".join(
+ itertools.chain(
+ (stringify(x, params) for x in self._args),
+ (
+ f"{k}={stringify(v, params)}"
+ for k, v in self._kwargs.items()
+ ),
+ )
+ )
+
+ # assign function call to new variable
+ return f"x{id(self)} = {fn_name}({str_call})"
+
+ get_source = get_source
+
+ def get_function(self, variables, fold_constants=True):
+ """Get a compiled function that computes ``fn(arrays)``, with ``fn``
+ describing the computational graph of this ``LazyArray`` and ``arrays``
+ corresponding to the downstream ``LazyArray`` nodes ``variables``.
+
+ Parameters
+ ----------
+ variables : sequence of LazyArray
+ Input nodes whose data can change between calls.
+ fold_constants : bool, optional
+ Compute all intermediates which do not depend on ``variables``
+ prior to compilation.
+
+ Returns
+ -------
+ fn : callable
+ Function with signature ``fn(arrays)``.
+ """
+ return Function(
+ inputs=variables, outputs=self, fold_constants=fold_constants
+ )
+
+ def as_string_pretty(self):
+ """Render this LazyArray as a nice string, for display rather than
+ evaluation purposes.
+ """
+
+ def _maybe_replace(x):
+ if isinstance(x, LazyArray):
+ return "#"
+ return x
+
+ args, kwargs = tree_map(_maybe_replace, (self._args, self._kwargs))
+ args = [repr(a) for a in args]
+ for k, v in kwargs.items():
+ args.append(f"{k}={repr(v)}")
+
+ s = ", ".join(args)
+ s = f"{self.fn_name}({s}) β {list(self.shape)}"
+ s = s.replace("'#'", "#")
+ s = s.replace("slice(None, None, None)", ":")
+
+ return s
+
+ def show(
+ self,
+ filler=" ",
+ max_lines=None,
+ max_depth=None,
+ show_args=True,
+ ):
+ """Show the computational graph as a nested directory structure.
+
+ Parameters
+ ----------
+ filler : str, optional
+ The string to use to fill in the empty space on the left.
+ max_lines : int, optional
+ The maximum number of lines to show. By default all lines are
+ shown.
+ max_depth : int, optional
+ The maximum depth to show. By default all depths are shown.
+ show_args : bool, optional
+ Whether to show the arguments to each function in the graph.
+ """
+ if max_lines is None:
+ max_lines = float("inf")
+ if max_depth is None:
+ max_depth = float("inf")
+
+ # β β β β£ β β β β° β β ⬀
+ bar = f"β{filler}"
+ space = f"{filler}{filler}"
+ junction = "ββ"
+ bend = "β°β"
+
+ line = 0
+ seen = {}
+ queue = [(self, ())]
+ while queue and (line < max_lines):
+ t, columns = queue.pop()
+
+ prefix = ""
+ if columns:
+ # work out various lines we need to draw based on whether the
+ # sequence of parents are themselves the last child of their
+ # parent
+ prefix += "".join(
+ bar if not p else space for p in columns[:-1]
+ )
+ prefix += bend if columns[-1] else junction
+
+ if t.fn_name not in (None, "None"):
+ if show_args:
+ item = t.as_string_pretty()
+ else:
+ item = f"{t.fn_name}{list(t.shape)}"
+ else:
+ # input node
+ item = f"β{list(t.shape)}"
+
+ if t in seen:
+ # ignore loops, but point to when it was computed
+ print(f"{line:>4} {prefix} ... [{item} from line {seen[t]}]")
+ line += 1
+ continue
+
+ print(f"{line:>4} {prefix}{item}")
+ seen[t] = line
+ line += 1
+
+ if len(columns) < max_depth:
+ deps = sorted(t.deps, key=get_depth, reverse=True)
+ islasts = [True] + [False] * (len(deps) - 1)
+ for islast, d in zip(islasts, deps):
+ queue.append((d, columns + (islast,)))
+
+ def history_num_nodes(self):
+ """Return the number of unique computational nodes in the history of
+ this ``LazyArray``.
+ """
+ num_nodes = 0
+ for _ in self.descend():
+ num_nodes += 1
+ return num_nodes
+
+ def history_max_size(self):
+ """Get the largest single tensor size appearing in this computation."""
+ return max(node.size for node in self.descend())
+
+ def history_size_footprint(self, include_inputs=True):
+ """Get the combined size of intermediates at each step of the
+ computation. Note this assumes that intermediates are immediately
+ garbage collected when they are no longer required.
+
+ Parameters
+ ----------
+ include_inputs : bool, optional
+ Whether to include the size of the inputs in the computation. If
+ ``True`` It is assumed they can be garbage collected once used but
+ are all present at the beginning of the computation.
+ """
+ delete_checked = set()
+ sizes = []
+ input_size = 0
+ for node in reversed(tuple(self.ascend())):
+ for c in node._deps:
+ if c not in delete_checked:
+ # last time a dependency is seen, subtract the size
+ if include_inputs or c._deps:
+ sizes.append(-c.size)
+ delete_checked.add(c)
+
+ if node._data is None:
+ # this is a new intermediate, add the size
+ sizes.append(+node.size)
+ elif include_inputs:
+ # this is an input, size is added at beginning
+ input_size += node.size
+
+ sizes.append(input_size)
+ sizes.reverse()
+ return list(itertools.accumulate(sizes))
+
+ def history_peak_size(self, include_inputs=True):
+ """Get the peak combined intermediate size of this computation.
+
+ Parameters
+ ----------
+ include_inputs : bool, optional
+ Whether to include the size of the inputs in the computation. If
+ ``True`` It is assumed they can be garbage collected once used but
+ are all present at the beginning of the computation.
+ """
+ return max(self.history_size_footprint(include_inputs=include_inputs))
+
+ def history_total_size(self):
+ """The the total size of all unique arrays in the computational graph,
+ possibly relevant e.g. for back-propagation algorithms.
+ """
+ return sum(node.size for node in self.descend())
+
+ def history_stats(self, fn):
+ """Compute aggregate statistics about the computational graph.
+
+ Parameters
+ ----------
+ fn : callable or str
+ Function to apply to each node in the computational graph. If a
+ string, one of 'count', 'sizein', 'sizeout' can be used to count
+ the number of nodes, the total size of the inputs, or the total
+ size of each output respectively.
+
+ Returns
+ -------
+ stats : dict
+ Dictionary mapping function names to the aggregate statistics.
+ """
+ if not callable(fn):
+ if fn == "count":
+
+ def fn(node):
+ return 1
+
+ elif fn == "sizein":
+
+ def fn(node):
+ return sum(child.size for child in node.deps)
+
+ elif fn == "sizeout":
+
+ def fn(node):
+ return node.size
+
+ stats = collections.defaultdict(int)
+ for node in self.descend():
+ node_cost = fn(node)
+ if node_cost is not None:
+ stats[node.fn_name] += fn(node)
+
+ return dict(stats)
+
+ def history_fn_frequencies(self):
+ """Get a dictionary mapping function names to the number of times they
+ are used in the computational graph.
+ """
+ return self.history_stats("count")
+
+ def to_nx_digraph(self, variables=None):
+ """Convert this ``LazyArray`` into a ``networkx.DiGraph``."""
+ import networkx as nx
+
+ if variables is None:
+ variables = set()
+ elif isinstance(variables, LazyArray):
+ variables = {variables}
+ else:
+ variables = set(variables)
+
+ G = nx.DiGraph()
+
+ nodemap = {}
+
+ for i, node in enumerate(self.ascend()):
+ nodemap[node] = i
+ variable = (node in variables) or any(
+ child in variables for child in node.deps
+ )
+ if variable:
+ variables.add(node)
+ G.add_node(i, array=node, variable=variable)
+ for x in node.deps:
+ G.add_edge(nodemap[x], nodemap[node])
+
+ return G
+
+ plot = plot_circuit
+ plot_graph = plot_graph
+ plot_circuit = plot_circuit
+ plot_history_size_footprint = plot_history_size_footprint
+ plot_history_functions = plot_history_functions
+ plot_history_functions_scatter = functools.partialmethod(
+ plot_history_functions, kind="scatter"
+ )
+ plot_history_functions_lines = functools.partialmethod(
+ plot_history_functions, kind="lines"
+ )
+ plot_history_functions_image = functools.partialmethod(
+ plot_history_functions, kind="image"
+ )
+ plot_history_stats = plot_history_stats
+ plot_history_stats_counts = functools.partialmethod(
+ plot_history_stats, fn="count"
+ )
+ plot_history_stats_sizein = functools.partialmethod(
+ plot_history_stats, fn="sizein"
+ )
+
+ @property
+ def fn(self):
+ """The function to use to compute this array."""
+ return self._fn
+
+ @property
+ def fn_name(self):
+ """The name of the function to use to compute this array."""
+ return getattr(self._fn, "__name__", "None")
+
+ @property
+ def args(self):
+ """The positional arguments to the function to use to compute this
+ array.
+ """
+ return self._args
+
+ @property
+ def kwargs(self):
+ """The keyword arguments to the function to use to compute this
+ array.
+ """
+ return self._kwargs
+
+ @property
+ def shape(self):
+ return self._shape
+
+ def __len__(self):
+ return self.shape[0]
+
+ def __iter__(self):
+ for ax in range(self.shape[0]):
+ yield self[ax]
+
+ @property
+ def ndim(self):
+ return len(self._shape)
+
+ @property
+ def size(self):
+ return functools.reduce(operator.mul, self.shape, 1)
+
+ @property
+ def backend(self):
+ return self._backend
+
+ @property
+ def deps(self):
+ """A tuple of the dependencies, other LazyArray instances, of this
+ array.
+ """
+ return self._deps
+
+ @property
+ def depth(self):
+ """The maximum distance to any input array in the computational graph."""
+ return self._depth
+
+ def __hash__(self):
+ return id(self)
+
+ def __getitem__(self, key):
+ return getitem(self, key)
+
+ # this makes numpy operations delegate to __rmatmul__ etc.
+ __array_ufunc__ = None
+
+ def __mul__(self, other):
+ return multiply(self, other)
+
+ def __rmul__(self, other):
+ return multiply(self, other)
+
+ def __add__(self, other):
+ return add(self, other)
+
+ def __radd__(self, other):
+ return add(self, other)
+
+ def __sub__(self, other):
+ return sub(self, other)
+
+ def __rsub__(self, other):
+ return sub(other, self)
+
+ def __floordiv__(self, other):
+ return floordivide(self, other)
+
+ def __rfloordiv__(self, other):
+ return floordivide(other, self)
+
+ def __truediv__(self, other):
+ return truedivide(self, other)
+
+ def __rtruediv__(self, other):
+ return truedivide(other, self)
+
+ def __mod__(self, other):
+ return mod(self, other)
+
+ def __pow__(self, other):
+ return pow_(self, other)
+
+ def __rpow__(self, other):
+ return pow_(other, self)
+
+ def __matmul__(self, other):
+ return matmul(self, other)
+
+ def __rmatmul__(self, other):
+ return matmul(other, self)
+
+ def __abs__(self):
+ return abs_(self)
+
+ def __neg__(self):
+ return self.to(operator.neg)
+
+ def __eq__(self, other):
+ return eq(self, other)
+
+ def __ne__(self, other):
+ return ne(self, other)
+
+ def __gt__(self, other):
+ return gt(self, other)
+
+ def __lt__(self, other):
+ return lt(self, other)
+
+ def __ge__(self, other):
+ return ge(self, other)
+
+ def __le__(self, other):
+ return le(self, other)
+
+ @property
+ def T(self):
+ return transpose(self)
+
+ @property
+ def H(self):
+ return conj(transpose(self))
+
+ def reshape(self, shape, **kwargs):
+ return reshape(self, shape, **kwargs)
+
+ def astype(self, dtype_name):
+ return lazy_astype(self, dtype_name)
+
+ @property
+ def dtype(self):
+ return self.to(get_dtype, shape=())
+
+ @property
+ def real(self):
+ return real(self)
+
+ @property
+ def imag(self):
+ return imag(self)
+
+ def __array_namespace__(self, api_version=None):
+ """Support array api namespace - https://data-apis.org/array-api/."""
+ from autoray import lazy as lazy_api
+
+ return lazy_api
+
+ def __repr__(self):
+ return (
+ f"<{self.__class__.__name__}("
+ f"fn={self.fn_name}, "
+ f"shape={self.shape}, "
+ f"backend='{self.backend}')>"
+ )
+
+
+register_backend(LazyArray, "autoray.lazy")
+
+
+def ensure_lazy(array):
+ if not isinstance(array, LazyArray):
+ return LazyArray.from_data(array)
+ return array
+
+
+def find_lazy(x):
+ """Recursively search for ``LazyArray`` instances in pytrees."""
+ if isinstance(x, LazyArray):
+ yield x
+ return
+
+ if isinstance(x, (tuple, list)):
+ for subx in x:
+ yield from find_lazy(subx)
+ return
+
+ if isinstance(x, dict):
+ for subx in x.values():
+ yield from find_lazy(subx)
+ return
+
+
+# --------------------- recusively evaluating 'pytrees' --------------------- #
+
+
+def materialize_larray(x):
+ return x._materialize()
+
+
+def materialize_tuple(x):
+ return tuple(map(maybe_materialize, x))
+
+
+def materialize_list(x):
+ return list(map(maybe_materialize, x))
+
+
+def materialize_dict(x):
+ return {k: maybe_materialize(v) for k, v in x.items()}
+
+
+def materialize_identity(x):
+ return x
+
+
+_materialize_dispatch = {
+ LazyArray: materialize_larray,
+ tuple: materialize_tuple,
+ list: materialize_list,
+ dict: materialize_dict,
+}
+
+
+def maybe_materialize(x):
+ """Recursively evaluate LazyArray instances in tuples, lists and dicts."""
+ try:
+ return _materialize_dispatch[x.__class__](x)
+ except KeyError:
+ _materialize_dispatch[x.__class__] = materialize_identity
+ return x
+
+
+# -------------------- recusively stringifying 'pytrees' -------------------- #
+
+
+def stringify_larray(x, params):
+ name = f"x{id(x)}"
+ if x._data is not None:
+ params.setdefault(name, x._data)
+ return name
+
+
+def stringify_tuple(x, params):
+ if not x:
+ return "()"
+ return f"({', '.join(stringify(xi, params) for xi in x)},)"
+
+
+def stringify_list(x, params):
+ return f"[{', '.join(stringify(xi, params) for xi in x)}]"
+
+
+def stringify_dict(x, params):
+ entries = (f"{k}: {stringify(v, params)}" for k, v in x.items())
+ return f"{{{', '.join(entries)}}}"
+
+
+def stringify_identity(x, params):
+ if isinstance(x, (int, float, complex, bool, slice, range)):
+ return f"{x}"
+ if isinstance(x, str):
+ return f"'{x}'"
+ name = f"c{id(x)}"
+ params.setdefault(name, x)
+ return name
+
+
+_stringify_dispatch = collections.defaultdict(
+ lambda: stringify_identity,
+ {
+ LazyArray: stringify_larray,
+ tuple: stringify_tuple,
+ list: stringify_list,
+ dict: stringify_dict,
+ },
+)
+
+
+def stringify(x, params):
+ """Recursively stringify LazyArray instances in tuples, lists and dicts."""
+ return _stringify_dispatch[x.__class__](x, params)
+
+
+# --------------------------------- caching --------------------------------- #
+
+
+_SHARING_STACK = collections.defaultdict(list)
+
+
+def currently_sharing():
+ """Check if we are currently sharing a cache -- thread specific."""
+ return threading.get_ident() in _SHARING_STACK
+
+
+def get_sharing_cache():
+ """Return the most recent sharing cache -- thread specific."""
+ return _SHARING_STACK[threading.get_ident()][-1]
+
+
+def _add_sharing_cache(cache):
+ _SHARING_STACK[threading.get_ident()].append(cache)
+
+
+def _remove_sharing_cache():
+ tid = threading.get_ident()
+ _SHARING_STACK[tid].pop()
+ if not _SHARING_STACK[tid]:
+ del _SHARING_STACK[tid]
+
+
+@contextlib.contextmanager
+def shared_intermediates(cache=None):
+ """Context in which intermediate results are shared.
+
+ Note that intermediate LazyArray instances (which can reference actual
+ data) will not be garbage collected until
+ 1. this context exits, and
+ 2. the yielded cache is garbage collected (if it was captured).
+
+ Parameters
+ ----------
+ cache : dict
+ If specified, a user-stored dict in which intermediate lazy arrays will
+ be stored. This can be used to interleave sharing contexts.
+
+ Returns
+ -------
+ cache : dict
+ A dictionary in which sharing results are stored. If ignored,
+ sharing results will be garbage collected when this context is
+ exited. This dict can be passed to another context to resume
+ sharing.
+ """
+ if cache is None:
+ cache = {}
+ _add_sharing_cache(cache)
+ try:
+ yield cache
+ finally:
+ _remove_sharing_cache()
+
+
+def maybe_id(x):
+ if hasattr(x, "shape"):
+ return id(x)
+ if isinstance(x, list):
+ return tuple(x)
+ return x
+
+
+def hash_args_kwargs(fn_name, *args, **kwargs):
+ hargs = tuple(map(maybe_id, args))
+ if kwargs:
+ hkwargs = tuple(sorted((k, maybe_id(v)) for k, v in kwargs.items()))
+ else:
+ hkwargs = None
+ return f"{fn_name}-{hash((hargs, hkwargs))}"
+
+
+def lazy_cache(fn_name, hasher=None):
+ """Decorator to mark a function as being lazy cacheable.
+
+ Parameters
+ ----------
+ fn_name : str
+ The name to use for the function in the cache.
+ hasher : callable
+ A function with signature ``hasher(fn_name, *args, **kwargs)`` that
+ returns a hashable key for the cache. If not specified, the default
+ is to use ``hash_args_kwargs``.
+ """
+
+ if hasher is None:
+ hasher = hash_args_kwargs
+
+ def wrapper(fn):
+ @functools.wraps(fn)
+ def wrapped(*args, **kwargs):
+ if not currently_sharing():
+ return fn(*args, **kwargs)
+
+ cache = get_sharing_cache()
+
+ key = hasher(fn_name, *args, **kwargs)
+ if key not in cache:
+ cache[key] = fn(*args, **kwargs)
+
+ return cache[key]
+
+ return wrapped
+
+ return wrapper
+
+
+_DTYPES_REAL_EQUIV = {"complex128": "float64", "complex64": "float32"}
+_DTYPES_COMPLEX_EQUIV = {"float64": "complex128", "float32": "complex64"}
+
+
+@functools.lru_cache(None)
+def dtype_real_equiv(dtype_name):
+ return _DTYPES_REAL_EQUIV.get(dtype_name, dtype_name)
+
+
+@functools.lru_cache(None)
+def dtype_complex_equiv(dtype_name):
+ return _DTYPES_COMPLEX_EQUIV.get(dtype_name, dtype_name)
+
+
+@functools.lru_cache(None)
+def _find_common_dtype(array_types, scalar_types):
+ import numpy as np
+
+ return np.find_common_type(array_types, scalar_types).name
+
+
+def find_common_dtype(*xs):
+ return _find_common_dtype(tuple(map(get_dtype_name, xs)), ())
+
+
+@functools.lru_cache(None)
+def _find_common_backend_cached(names):
+ return max(
+ names,
+ key=lambda n: multi_class_priorities.get(n, 0),
+ )
+
+
+def find_common_backend(*xs):
+ names = tuple(
+ x.backend if isinstance(x, LazyArray) else infer_backend(x) for x in xs
+ )
+ return _find_common_backend_cached(names)
+
+
+@functools.lru_cache(1024)
+def find_broadcast_shape(xshape, yshape):
+ xndim = len(xshape)
+ yndim = len(yshape)
+ if xndim < yndim:
+ xshape = (1,) * (yndim - xndim) + xshape
+ elif yndim < xndim:
+ yshape = (1,) * (xndim - yndim) + yshape
+ return tuple(max(d1, d2) for d1, d2 in zip(xshape, yshape))
+
+
+# -------------------------------- interface -------------------------------- #
+
+
+def Variable(shape, backend=None):
+ """Create a ``LazyArray`` from a shape only, representing a leaf node
+ in the computational graph. It can only act as a placeholder for data.
+ """
+ return LazyArray.from_shape(shape, backend=backend)
+
+
+@lazy_cache("array")
+def array(x):
+ """Create a ``LazyArray`` from an input array, representing a leaf node
+ in the computational graph.
+ """
+ return LazyArray.from_data(x)
+
+
+@lazy_cache("transpose")
+def transpose(a, axes=None):
+ a = ensure_lazy(a)
+
+ if axes is None:
+ axes = range(a.ndim)[::-1]
+
+ if all(i == ax for i, ax in enumerate(axes)):
+ # no transposition required
+ return a
+
+ fn_transpose = get_lib_fn(a.backend, "transpose")
+ oldshape = shape(a)
+ newshape = tuple(oldshape[i] for i in axes)
+
+ # check for chaining transpositions
+ if a._fn is fn_transpose:
+ b = a._args[0]
+ if isinstance(b, LazyArray):
+ axes_prev = a._args[1]
+ axes_chained = tuple(axes_prev[k] for k in axes)
+ return b.to(fn_transpose, (b, axes_chained), shape=newshape)
+
+ return a.to(fn_transpose, (a, axes), shape=newshape)
+
+
+permute_dims = transpose
+
+
+@lazy_cache("reshape")
+def _reshape_tuple(a, newshape, **kwargs):
+ a = ensure_lazy(a)
+ fn_reshape = get_lib_fn(a.backend, "reshape")
+
+ # check for redundant reshapes
+ if a._fn is fn_reshape:
+ b = a._args[0]
+ if isinstance(b, LazyArray):
+ a = b
+
+ return a.to(fn_reshape, (a, newshape), shape=newshape, kwargs=kwargs)
+
+
+@functools.lru_cache(2**14)
+def find_full_reshape(newshape, size):
+ try:
+ expand = newshape.index(-1)
+ before = newshape[:expand]
+ after = newshape[expand + 1 :]
+ d = size // functools.reduce(
+ operator.mul, itertools.chain(before, after), 1
+ )
+ return (*before, d, *after)
+ except ValueError:
+ return newshape
+
+
+def reshape(a, newshape, **kwargs):
+ newshape = (newshape,) if isinstance(newshape, int) else tuple(newshape)
+ newshape = find_full_reshape(newshape, a.size)
+
+ if shape(a) == tuple(newshape):
+ # no reshape required
+ return a
+
+ return _reshape_tuple(a, newshape, **kwargs)
+
+
+@lazy_cache("expand_dims")
+def expand_dims(a, axis):
+ a = ensure_lazy(a)
+ fn_expand_dims = get_lib_fn(a.backend, "expand_dims")
+
+ if axis < 0:
+ axis += a.ndim + 1
+
+ new_shape = (
+ *a.shape[:axis],
+ 1,
+ *a.shape[axis:],
+ )
+ return a.to(fn_expand_dims, (a, axis), shape=new_shape)
+
+
+@lazy_cache("broadcast_to")
+def broadcast_to(array, shape):
+ array = ensure_lazy(array)
+ shape = tuple(shape)
+ fn_broadcast_to = get_lib_fn(array.backend, "broadcast_to")
+
+ if array.shape == shape:
+ # no broadcasting required
+ return array
+
+ return array.to(fn_broadcast_to, (array, shape), shape=shape)
+
+
+def getitem_hasher(_, a, key):
+ if not isinstance(key, tuple):
+ key = (key,)
+ hkey = tuple(
+ str(k)
+ if isinstance(k, slice)
+ else id(k)
+ if hasattr(k, "shape")
+ else tuple(k)
+ if isinstance(k, list)
+ else k
+ for k in key
+ )
+ return f"getitem-{hash((id(a), hkey))}"
+
+
+@functools.lru_cache(2**12)
+def get_sliced_size(d, start, stop, step):
+ return len(range(d)[slice(start, stop, step)])
+
+
+@lazy_cache("getitem", hasher=getitem_hasher)
+def getitem(a, key):
+ a = ensure_lazy(a)
+
+ deps = (a,)
+
+ if not isinstance(key, tuple):
+ key = (key,)
+
+ nexpand = a.ndim
+ expand = None
+ for i, k in enumerate(key):
+ if k is not None:
+ if k is Ellipsis:
+ expand = i
+ else:
+ nexpand -= 1
+
+ if expand is not None:
+ # ellipsis somewhere
+ key = key[:expand] + (slice(None),) * nexpand + key[expand + 1 :]
+ elif nexpand:
+ # need to pad trailing dimensions
+ key = key + (slice(None),) * nexpand
+
+ adv_idx_shape = adv_idx_loc = None
+ adv_idx_locs = []
+
+ shape = iter(a.shape)
+ newshape = []
+ for i, k in enumerate(key):
+ if k is None:
+ # (newaxis) -> new dimension of size 1
+ newshape.append(1)
+ # don't want to iterate shape
+ continue
+
+ d = next(shape)
+
+ if isinstance(k, slice):
+ # range of values
+ newshape.append(get_sliced_size(d, k.start, k.stop, k.step))
+
+ elif hasattr(k, "shape") or isinstance(k, (tuple, list)):
+ if adv_idx_shape is None:
+ # first advanced index
+ adv_idx_shape = _get_py_shape(k)
+ adv_idx_loc = len(newshape)
+ adv_idx_locs.append(i)
+ else:
+ # check if broadcast shape matches
+ adv_idx_shape = find_broadcast_shape(
+ adv_idx_shape, _get_py_shape(k)
+ )
+ # advanced indexing location is only retained when
+ # all advanced indices are adjacent -> need to track
+ adv_idx_locs.append(i)
+
+ if isinstance(k, LazyArray):
+ # add to dependencies
+ deps += (k,)
+
+ else:
+ # else assume integer -> doesn't contribute to new shape,
+ # but does count as an advanced index when it comes to
+ # determining the location of the advanced index shape
+ adv_idx_locs.append(i)
+
+ if adv_idx_shape is not None:
+ if not all(i + 1 == j for i, j in zip(adv_idx_locs, adv_idx_locs[1:])):
+ # 'move to front' advanced indexing
+ newshape = (*adv_idx_shape, *newshape)
+ else:
+ # 'keep in place' advanced indexing
+ newshape = (
+ *newshape[:adv_idx_loc],
+ *adv_idx_shape,
+ *newshape[adv_idx_loc:],
+ )
+ else:
+ newshape = tuple(newshape)
+
+ return a.to(operator.getitem, (a, key), shape=newshape, deps=deps)
+
+
+@lazy_cache("tensordot")
+def tensordot(a, b, axes=2):
+ if isinstance(axes, int):
+ axes = (tuple(range(a.ndim - axes, a.ndim)), tuple(range(axes)))
+
+ newshape = tuple(
+ d for i, d in enumerate(shape(a)) if i not in axes[0]
+ ) + tuple(d for i, d in enumerate(shape(b)) if i not in axes[1])
+
+ backend = find_common_backend(a, b)
+ fn_tensordot = get_lib_fn(backend, "tensordot")
+
+ return LazyArray(
+ backend=backend,
+ fn=fn_tensordot,
+ args=(a, b, axes),
+ kwargs=None,
+ shape=newshape,
+ deps=tuple(x for x in (a, b) if isinstance(x, LazyArray)),
+ )
+
+
+def _basic_einsum_parse_input(operands):
+ # handle the basic, fully specified equation format
+ eq, *arrays = operands
+ lhs, rhs = eq.split("->")
+ return lhs, rhs, arrays
+
+
+@functools.lru_cache(None)
+def _get_parse_einsum_input():
+ try:
+ from cotengra.utils import parse_einsum_input
+
+ return parse_einsum_input
+ except ImportError:
+ pass
+
+ try:
+ from opt_einsum.parser import parse_einsum_input
+
+ return parse_einsum_input
+ except ImportError:
+ pass
+
+ import warnings
+
+ warnings.warn(
+ "Could not find a full input parser for einsum expressions. "
+ "Please install either cotengra or opt_einsum for advanced "
+ "input formats (interleaved, ellipses, no-output)."
+ )
+
+ return _basic_einsum_parse_input
+
+
+@lazy_cache("einsum")
+def einsum(*operands, **kwargs):
+ lhs, rhs, larrays = _get_parse_einsum_input()(operands)
+
+ size_dict = {}
+ for term, op in zip(lhs.split(","), larrays):
+ op_shape = shape(op)
+ for i, char in enumerate(term):
+ size_dict[char] = max(size_dict.get(char, 1), op_shape[i])
+ eq = f"{lhs}->{rhs}"
+ newshape = tuple(size_dict[char] for char in rhs)
+
+ backend = find_common_backend(*larrays)
+ fn_einsum = get_lib_fn(backend, "einsum")
+
+ if backend == "numpy":
+ kwargs.setdefault("optimize", True)
+
+ return LazyArray(
+ backend=backend,
+ fn=fn_einsum,
+ args=(eq, *larrays),
+ kwargs=kwargs,
+ shape=newshape,
+ deps=tuple(x for x in larrays if isinstance(x, LazyArray)),
+ )
+
+
+@lazy_cache("trace")
+def trace(a):
+ a = ensure_lazy(a)
+ return a.to(
+ fn=get_lib_fn(a.backend, "trace"),
+ args=(a,),
+ shape=(),
+ )
+
+
+@lazy_cache("diag")
+def diag(a, k=0):
+ a = ensure_lazy(a)
+
+ if a.ndim == 1:
+ new_d = shape(a)[0] + abs(k)
+ new_shape = (new_d, new_d)
+ elif a.ndim == 2:
+ new_d = max(min(shape(a)) - abs(k), 0)
+ new_shape = (new_d,)
+ else:
+ raise ValueError("Input must be 1- or 2-d.")
+
+ return a.to(
+ fn=get_lib_fn(a.backend, "diag"),
+ args=(a, k),
+ shape=new_shape,
+ )
+
+
+@lazy_cache("diagonal")
+def diagonal(a, offset=0, axis1=0, axis2=1):
+ a = ensure_lazy(a)
+ fn_diagonal = get_lib_fn(a.backend, "diagonal")
+
+ if axis1 < 0:
+ axis1 += a.ndim
+ if axis2 < 0:
+ axis2 += a.ndim
+
+ newshape = [d for ax, d in enumerate(a.shape) if ax not in (axis1, axis2)]
+ newshape.append(max(min(a.shape[axis1], a.shape[axis2]) - abs(offset), 0))
+
+ return a.to(
+ fn=fn_diagonal,
+ args=(a, offset, axis1, axis2),
+ shape=tuple(newshape),
+ )
+
+
+@lazy_cache("matmul")
+def matmul(x1, x2):
+ backend = find_common_backend(x1, x2)
+
+ shape1 = shape(x1)
+ shape2 = shape(x2)
+ if len(shape2) == 1:
+ if shape1[-1] != shape2[-1]:
+ raise ValueError(
+ "matmul: Input operand 1 has a mismatch in its core dimension "
+ "0, with gufunc signature (n?,k),(k,m?)->(n?,m?)"
+ )
+ newshape = shape1[:-1]
+ elif len(shape1) == 1:
+ if len(shape2) > 2 or shape1[-1] != shape2[-2]:
+ raise ValueError(
+ "matmul: Input operand 1 has a mismatch in its core dimension "
+ "0, with gufunc signature (n?,k),(k,m?)->(n?,m?)"
+ )
+ newshape = shape2[-1:]
+ else:
+ if shape2[:-2] != shape1[:-2]:
+ raise ValueError(
+ "operands could not be broadcast together with remapped "
+ f"shapes [original->remapped]: {shape1}->({shape1[:-2]},"
+ "newaxis,newaxis) "
+ f"{shape2}->({shape2[:-2]},newaxis,newaxis) and requested "
+ f"shape ({shape1[-2], shape2[-1]})"
+ )
+ if shape1[-1] != shape2[-2]:
+ raise ValueError(
+ "matmul: Input operand 1 has a mismatch in its core dimension "
+ "0, with gufunc signature (n?,k),(k,m?)->(n?,m?)"
+ )
+ newshape = (*shape1[:-1], shape2[-1])
+
+ return LazyArray(
+ backend=backend,
+ fn=operator.matmul,
+ args=(x1, x2),
+ kwargs=None,
+ shape=newshape,
+ deps=tuple(x for x in (x1, x2) if isinstance(x, LazyArray)),
+ )
+
+
+@lazy_cache("kron")
+def kron(x1, x2):
+ backend = find_common_backend(x1, x2)
+ shape1 = shape(x1)
+ shape2 = shape(x2)
+
+ ndim1 = len(shape1)
+ ndim2 = len(shape2)
+
+ diff = ndim1 - ndim2
+ if diff > 0:
+ shape2 = (1,) * diff + shape2
+ elif diff < 0:
+ shape1 = (1,) * -diff + shape1
+
+ newshape = tuple(d1 * d2 for d1, d2 in zip(shape1, shape2))
+ fn_kron = get_lib_fn(backend, "kron")
+ return LazyArray(
+ backend=backend,
+ fn=fn_kron,
+ args=(x1, x2),
+ kwargs=None,
+ shape=newshape,
+ deps=tuple(x for x in (x1, x2) if isinstance(x, LazyArray)),
+ )
+
+
+@lazy_cache("clip")
+def clip(a, a_min, a_max):
+ a = ensure_lazy(a)
+ fn_clip = get_lib_fn(a.backend, "clip")
+ return a.to(fn_clip, (a, a_min, a_max))
+
+
+@lazy_cache("flip")
+def flip(a, axis=None):
+ a = ensure_lazy(a)
+ fn_flip = get_lib_fn(a.backend, "flip")
+ return a.to(fn_flip, (a, axis))
+
+
+@lazy_cache("sort")
+def sort(a, axis=-1):
+ a = ensure_lazy(a)
+ return a.to(get_lib_fn(a.backend, "sort"), (a, axis))
+
+
+@lazy_cache("argsort")
+def argsort(a, axis=-1, **kwargs):
+ a = ensure_lazy(a)
+ return a.to(
+ fn=get_lib_fn(a.backend, "argsort"),
+ args=(a, axis),
+ kwargs=kwargs,
+ )
+
+
+@lazy_cache("stack")
+def stack(arrays, axis=0):
+ arrays = tuple(arrays)
+ newshape = list(shape(arrays[0]))
+ newshape.insert(axis if axis >= 0 else axis + 1, len(arrays))
+
+ backend = find_common_backend(*arrays)
+ fn = get_lib_fn(backend, "stack")
+ return LazyArray(
+ backend=backend,
+ fn=fn,
+ args=(arrays, axis),
+ kwargs=None,
+ shape=tuple(newshape),
+ deps=tuple(x for x in arrays if isinstance(x, LazyArray)),
+ )
+
+
+@lazy_cache("concatenate")
+def concatenate(arrays, axis=0):
+ arrays = tuple(arrays)
+ newshape = list(arrays[0].shape)
+ newshape[axis] = sum(shape(a)[axis] for a in arrays)
+
+ backend = find_common_backend(*arrays)
+ fn = get_lib_fn(backend, "concatenate")
+ return LazyArray(
+ backend=backend,
+ fn=fn,
+ args=(arrays, axis),
+ kwargs=None,
+ shape=tuple(newshape),
+ deps=tuple(x for x in arrays if isinstance(x, LazyArray)),
+ )
+
+
+@lazy_cache("split")
+def split(ary, indices_or_sections, axis=0):
+ ary = ensure_lazy(ary)
+
+ d = shape(ary)[axis]
+ num_subarrays = len(indices_or_sections) + 1
+ div_points = [0] + list(indices_or_sections) + [d]
+
+ sub_arys = []
+ selector = [slice(None)] * ary.ndim
+ for i in range(num_subarrays):
+ st = div_points[i]
+ end = div_points[i + 1]
+ selector[axis] = slice(st, end)
+ sub_arys.append(ary[tuple(selector)])
+
+ return tuple(sub_arys)
+
+
+def where(condition, x, y):
+ x = ensure_lazy(x)
+ condition = ensure_lazy(condition)
+ return LazyArray(
+ backend=find_common_backend(condition, x),
+ fn=get_lib_fn(x.backend, "where"),
+ args=(condition, x, y),
+ kwargs=None,
+ shape=find_broadcast_shape(condition.shape, x.shape),
+ deps=tuple(a for a in (condition, x, y) if isinstance(a, LazyArray)),
+ )
+
+
+def _get_py_shape(x):
+ """Infer the shape of a possibly nested list/tuple object."""
+ if hasattr(x, "shape"):
+ return tuple(x.shape)
+ if isinstance(x, (tuple, list)):
+ return (len(x),) + _get_py_shape(x[0])
+ return ()
+
+
+@lazy_cache("take")
+def take(x, indices):
+ x = ensure_lazy(x)
+ if isinstance(indices, (list, tuple)):
+ new_shape = _get_py_shape(indices)
+ else:
+ indices = ensure_lazy(indices)
+ new_shape = indices.shape
+ return LazyArray(
+ backend=x.backend,
+ fn=get_lib_fn(x.backend, "take"),
+ args=(x, indices),
+ kwargs=None,
+ shape=new_shape,
+ deps=tuple(a for a in (x, indices) if isinstance(a, LazyArray)),
+ )
+
+
+@lazy_cache("take_along_axis")
+def take_along_axis(arr, indices, axis=-1):
+ arr = ensure_lazy(arr)
+ indices = ensure_lazy(indices)
+
+ if axis < 0:
+ axis += arr.ndim
+
+ fn = get_lib_fn(arr.backend, "take_along_axis")
+ new_shape = tuple(
+ # target axis gets length from indices
+ db
+ if ax == axis
+ # other axes are broadcast
+ else max(da, db)
+ for ax, (da, db) in enumerate(zip(arr.shape, indices.shape))
+ )
+
+ return LazyArray(
+ backend=arr.backend,
+ fn=fn,
+ args=(arr, indices, axis),
+ kwargs=None,
+ shape=new_shape,
+ deps=(arr, indices),
+ )
+
+
+def make_binary_func(name, fn):
+ @lazy_cache(name)
+ def binary_func(x1, x2):
+ x1shape = getattr(x1, "shape", ())
+ x2shape = getattr(x2, "shape", ())
+ newshape = find_broadcast_shape(x1shape, x2shape)
+ return LazyArray(
+ backend=find_common_backend(x1, x2),
+ fn=fn,
+ args=(x1, x2),
+ kwargs=None,
+ shape=newshape,
+ deps=tuple(x for x in (x1, x2) if isinstance(x, LazyArray)),
+ )
+
+ return binary_func
+
+
+add = make_binary_func("add", operator.add)
+eq = make_binary_func("eq", operator.eq)
+equal = make_binary_func("equal", operator.eq)
+floordivide = make_binary_func("floordivide", operator.floordiv)
+ge = make_binary_func("ge", operator.ge)
+gt = make_binary_func("gt", operator.gt)
+le = make_binary_func("le", operator.le)
+lt = make_binary_func("lt", operator.lt)
+mod = make_binary_func("mod", operator.mod)
+multiply = make_binary_func("multiply", operator.mul)
+ne = make_binary_func("ne", operator.ne)
+pow_ = make_binary_func("pow", operator.pow)
+sub = make_binary_func("sub", operator.sub)
+truedivide = make_binary_func("truedivide", operator.truediv)
+
+
+def complex_(re, im):
+ newshape = find_broadcast_shape(shape(re), shape(im))
+ backend = find_common_backend(re, im)
+ fn_complex = get_lib_fn(backend, "complex")
+ return LazyArray(
+ backend=backend,
+ fn=fn_complex,
+ args=(re, im),
+ kwargs=None,
+ shape=newshape,
+ deps=tuple(x for x in (re, im) if isinstance(x, LazyArray)),
+ )
+
+
+def make_unary_func(name, var_name=None):
+ @lazy_cache(name)
+ def unary_func(x):
+ x = ensure_lazy(x)
+ return x.to(fn=get_lib_fn(x.backend, name))
+
+ if var_name is not None:
+ unary_func.__name__ = name
+ unary_func.__qualname__ = name
+
+ return unary_func
+
+
+sin = make_unary_func("sin", var_name="sin")
+cos = make_unary_func("cos", var_name="cos")
+tan = make_unary_func("tan", var_name="tan")
+arcsin = make_unary_func("arcsin", var_name="arcsin")
+arccos = make_unary_func("arccos", var_name="arccos")
+arctan = make_unary_func("arctan", var_name="arctan")
+sinh = make_unary_func("sinh", var_name="sinh")
+cosh = make_unary_func("cosh", var_name="cosh")
+tanh = make_unary_func("tanh", var_name="tanh")
+arcsinh = make_unary_func("arcsinh", var_name="arcsinh")
+arccosh = make_unary_func("arccosh", var_name="arccosh")
+arctanh = make_unary_func("arctanh", var_name="arctanh")
+sqrt = make_unary_func("sqrt", var_name="sqrt")
+exp = make_unary_func("exp", var_name="exp")
+log = make_unary_func("log", var_name="log")
+log2 = make_unary_func("log2", var_name="log2")
+log10 = make_unary_func("log10", var_name="log10")
+conj = make_unary_func("conj", var_name="conj")
+sign = make_unary_func("sign", var_name="sign")
+abs_ = make_unary_func("abs", var_name="abs_")
+angle = make_unary_func("angle", var_name="angle")
+real = make_unary_func("real", var_name="real")
+imag = make_unary_func("imag", var_name="imag")
+
+
+def make_reduction_func(name, var_name=None):
+ @lazy_cache(name)
+ def reduction_func(a, axis=None):
+ a = ensure_lazy(a)
+ fn = get_lib_fn(a.backend, name)
+
+ nd = a.ndim
+ if axis is None:
+ return a.to(
+ fn=fn,
+ shape=(),
+ )
+ elif not hasattr(axis, "__len__"):
+ axis = (axis,)
+ axis = tuple(nd + i if i < 0 else i for i in axis)
+
+ newshape = tuple(d for i, d in enumerate(shape(a)) if i not in axis)
+ return a.to(fn=fn, args=(a, axis), shape=newshape)
+
+ if var_name is not None:
+ reduction_func.__name__ = var_name
+ reduction_func.__qualname__ = var_name
+
+ return reduction_func
+
+
+sum_ = make_reduction_func("sum", var_name="sum_")
+prod = make_reduction_func("prod", var_name="prod")
+min_ = make_reduction_func("min", var_name="min_")
+max_ = make_reduction_func("max", var_name="max_")
+
+# # XXX: still missing
+# allclose
+# dot, vdot, inner, outer
+# pad, eye
+# squeeze, expand_dims
+# to_numpy
+
+
+# ----------------------------- array creation ------------------------------ #
+
+
+def parse_creation_shape(shape):
+ try:
+ shape = tuple(shape)
+ except TypeError:
+ # single integer implies 1D shape
+ shape = (shape,)
+ return shape
+
+
+def empty(shape, *, backend="numpy", **kwargs):
+ """Lazy creation of an empty array with a given shape."""
+ shape = parse_creation_shape(shape)
+ return LazyArray(
+ backend=backend,
+ fn=get_lib_fn(backend, "empty"),
+ args=(shape,),
+ kwargs=kwargs,
+ shape=shape,
+ deps=(),
+ )
+
+
+def zeros(shape, *, backend="numpy", **kwargs):
+ """Lazy creation of an array filled with zeros with a given shape."""
+ shape = parse_creation_shape(shape)
+ return LazyArray(
+ backend=backend,
+ fn=get_lib_fn(backend, "zeros"),
+ args=(shape,),
+ kwargs=kwargs,
+ shape=shape,
+ deps=(),
+ )
+
+
+def ones(shape, *, backend="numpy", **kwargs):
+ """Lazy creation of an array filled with ones with a given shape."""
+ shape = parse_creation_shape(shape)
+ return LazyArray(
+ backend=backend,
+ fn=get_lib_fn(backend, "ones"),
+ args=(shape,),
+ kwargs=kwargs,
+ shape=shape,
+ deps=(),
+ )
+
+
+def eye(N, *, backend="numpy", **kwargs):
+ """Lazy creation of the identity matrix of size N."""
+ return LazyArray(
+ backend=backend,
+ fn=get_lib_fn(backend, "eye"),
+ args=(N,),
+ kwargs=kwargs,
+ shape=(N, N),
+ deps=(),
+ )
+
+
+def identity(n, *, backend="numpy", **kwargs):
+ """Lazy creation of the identity matrix of size n."""
+ return LazyArray(
+ backend=backend,
+ fn=get_lib_fn(backend, "identity"),
+ args=(n,),
+ kwargs=kwargs,
+ shape=(n, n),
+ deps=(),
+ )
+
+
+# ---------------------------- autoray specials ----------------------------- #
+
+
+def lazy_get_dtype_name(x):
+ return x.dtype
+
+
+@lazy_cache("astype")
+def lazy_astype(x, dtype_name):
+ x = ensure_lazy(x)
+ return x.to(fn=astype, args=(x, dtype_name))
+
+
+register_function("autoray.lazy", "get_dtype_name", lazy_get_dtype_name)
+register_function("autoray.lazy", "astype", lazy_astype)
diff --git a/venv/Lib/site-packages/autoray/lazy/draw.py b/venv/Lib/site-packages/autoray/lazy/draw.py
new file mode 100644
index 0000000000000000000000000000000000000000..a755bb927cad6f85c2790931866609381b8b03ca
--- /dev/null
+++ b/venv/Lib/site-packages/autoray/lazy/draw.py
@@ -0,0 +1,987 @@
+"""Visualizations for ``LazyArray`` computational graphs."""
+
+import functools
+import importlib.util
+import itertools
+
+COLORING_SEED = 1 # 8, 10
+
+
+def set_coloring_seed(seed):
+ """Set the seed for the random color generator.
+
+ Parameters
+ ----------
+ seed : int
+ The seed to use.
+ """
+ global COLORING_SEED
+ COLORING_SEED = seed
+
+
+def hash_to_nvalues(s, nval, seed=None):
+ import hashlib
+
+ if seed is None:
+ seed = COLORING_SEED
+
+ m = hashlib.sha256()
+ m.update(f"{seed}".encode())
+ m.update(s.encode())
+ hsh = m.hexdigest()
+
+ b = len(hsh) // nval
+ if b == 0:
+ raise ValueError(
+ f"Can't extract {nval} values from hash of length {len(hsh)}"
+ )
+ return tuple(
+ int(hsh[i * b : (i + 1) * b], 16) / 16**b for i in range(nval)
+ )
+
+
+def hash_to_color(
+ s,
+ hmin=0.0,
+ hmax=1.0,
+ smin=0.3,
+ smax=0.8,
+ vmin=0.8,
+ vmax=1.0,
+):
+ """Generate a random color for a string ``s``.
+
+ Parameters
+ ----------
+ s : str
+ The string to generate a color for.
+ hmin : float, optional
+ The minimum hue value.
+ hmax : float, optional
+ The maximum hue value.
+ smin : float, optional
+ The minimum saturation value.
+ smax : float, optional
+ The maximum saturation value.
+ vmin : float, optional
+ The minimum value value.
+ vmax : float, optional
+ The maximum value value.
+
+ Returns
+ -------
+ color : tuple
+ A tuple of floats in the range [0, 1] representing the RGB color.
+ """
+ from matplotlib.colors import hsv_to_rgb
+
+ h, s, v = hash_to_nvalues(s, 3)
+ h = hmin + h * (hmax - hmin)
+ s = smin + s * (smax - smin)
+ v = vmin + v * (vmax - vmin)
+
+ return hsv_to_rgb((h, s, v))
+
+
+def rotated_house_shape(xy, r=0.4):
+ x, y = xy
+ return [
+ [x - r, y - r],
+ [x - r, y + r],
+ [x, y + r],
+ [x + r, y],
+ [x, y - r],
+ ]
+
+
+def count_around(c, layout):
+ if layout == "wide":
+ # just count upwards
+ yield from itertools.count(c)
+ elif layout == "compact":
+ # count backwards, then forwards after reaching zero
+ yield from range(c, -1, -1)
+ yield from itertools.count(c + 1)
+ else: # 'balanced'
+ # count backwards, then forwards, alternating
+ step = 0
+ # start by stepping to side closer to zero
+ sgn = (-1) ** (c <= 0)
+ while True:
+ cm = c - sgn * step
+ if step != 0: # and (cm >= 0):
+ yield cm
+ yield c + sgn * step
+ step += 1
+
+
+def get_default_colors_dict(colors):
+ import numpy as np
+
+ colors = dict() if colors is None else dict(colors)
+ colors.setdefault("None", np.array([0.5, 0.5, 0.5]))
+ colors.setdefault("getitem", np.array([0.5, 0.5, 0.5]))
+ return colors
+
+
+def rotate(xy, theta):
+ """Return a rotated set of points."""
+ import numpy as np
+
+ s = np.sin(theta)
+ c = np.cos(theta)
+
+ xyr = np.empty_like(xy)
+ xyr[:, 0] = c * xy[:, 0] - s * xy[:, 1]
+ xyr[:, 1] = s * xy[:, 0] + c * xy[:, 1]
+
+ return xyr
+
+
+def span(xy):
+ """Return the vertical span of the points."""
+ return xy[:, 1].max() - xy[:, 1].min()
+
+
+def massage_pos(pos, nangles=180, flatten=False):
+ """Rotate a position dict's points to cover a small vertical span"""
+ import numpy as np
+
+ xy = np.empty((len(pos), 2))
+ for i, (x, y) in enumerate(pos.values()):
+ xy[i, 0] = x
+ xy[i, 1] = y
+
+ thetas = np.linspace(0, 2 * np.pi, nangles, endpoint=False)
+ rxys = (rotate(xy, theta) for theta in thetas)
+ rxy0 = min(rxys, key=lambda rxy: span(rxy))
+
+ if flatten is True:
+ flatten = 2
+ if flatten:
+ rxy0[:, 1] /= flatten
+
+ return dict(zip(pos, rxy0))
+
+
+def layout_pygraphviz(
+ G,
+ prog="neato",
+ dim=2,
+ **kwargs,
+):
+ # TODO: fix nodes with pin attribute
+ # TODO: initial positions
+ # TODO: max iters
+ # TODO: spring parameter
+ import pygraphviz as pgv
+
+ aG = pgv.AGraph(directed=G.is_directed())
+ mapping = {}
+ for nodea, nodeb in G.edges():
+ s_nodea = str(nodea)
+ s_nodeb = str(nodeb)
+ mapping[s_nodea] = nodea
+ mapping[s_nodeb] = nodeb
+ aG.add_edge(s_nodea, s_nodeb)
+
+ kwargs = {}
+
+ if dim == 2.5:
+ kwargs["dim"] = 3
+ kwargs["dimen"] = 2
+ else:
+ kwargs["dim"] = kwargs["dimen"] = dim
+ args = " ".join(f"-G{k}={v}" for k, v in kwargs.items())
+
+ # run layout algorithm
+ aG.layout(prog=prog, args=args)
+
+ # extract layout
+ pos = {}
+ for snode, node in mapping.items():
+ spos = aG.get_node(snode).attr["pos"]
+ pos[node] = tuple(map(float, spos.split(",")))
+
+ # normalize to unit square
+ xmin = ymin = zmin = float("inf")
+ xmax = ymax = zmaz = float("-inf")
+ for x, y, *maybe_z in pos.values():
+ xmin = min(xmin, x)
+ xmax = max(xmax, x)
+ ymin = min(ymin, y)
+ ymax = max(ymax, y)
+ for z in maybe_z:
+ zmin = min(zmin, z)
+ zmaz = max(zmaz, z)
+
+ for node, (x, y, *maybe_z) in pos.items():
+ pos[node] = (
+ 2 * (x - xmin) / (xmax - xmin) - 1,
+ 2 * (y - ymin) / (ymax - ymin) - 1,
+ *(2 * (z - zmin) / (zmaz - zmin) - 1 for z in maybe_z),
+ )
+
+ return pos
+
+
+HAS_FA2 = importlib.util.find_spec("fa2") is not None
+HAS_PYGRAPHVIZ = importlib.util.find_spec("pygraphviz") is not None
+
+
+def get_nice_pos(
+ G,
+ *,
+ dim=2,
+ layout="auto",
+ initial_layout="auto",
+ iterations="auto",
+ k=None,
+ use_forceatlas2=False,
+ flatten=False,
+ **layout_opts,
+):
+ if (layout == "auto") and HAS_PYGRAPHVIZ:
+ layout = "neato"
+
+ if layout in ("dot", "neato", "fdp", "sfdp"):
+ pos = layout_pygraphviz(G, prog=layout, dim=dim)
+ if layout != "dot":
+ pos = massage_pos(pos, flatten=flatten)
+ return pos
+
+ import networkx as nx
+
+ if layout != "auto":
+ initial_layout = layout
+ iterations = 0
+
+ if initial_layout == "auto":
+ # automatically select
+ if len(G) <= 100:
+ # usually nicest
+ initial_layout = "kamada_kawai"
+ else:
+ # faster, but not as nice
+ initial_layout = "spectral"
+
+ if iterations == "auto":
+ # the smaller the graph, the more iterations we can afford
+ iterations = max(200, 1000 - len(G))
+
+ if dim == 2.5:
+ dim = 3
+ project_back_to_2d = True
+ else:
+ project_back_to_2d = False
+
+ # use spectral or other layout as starting point
+
+ if dim != 2:
+ layout_opts["dim"] = dim
+
+ pos0 = getattr(nx, initial_layout + "_layout")(G, **layout_opts)
+
+ # and then relax remaining using spring layout
+ if iterations:
+ if use_forceatlas2 is True:
+ # turn on for more than 1 node
+ use_forceatlas2 = 1
+ elif use_forceatlas2 in (0, False):
+ # never turn on
+ use_forceatlas2 = float("inf")
+
+ should_use_fa2 = HAS_FA2 and (len(G) > use_forceatlas2) and (dim == 2)
+
+ if should_use_fa2:
+ from fa2 import ForceAtlas2
+
+ # NB: some versions of fa2 don't support the `weight_attr` option
+ pos = ForceAtlas2(verbose=False).forceatlas2_networkx_layout(
+ G, pos=pos0, iterations=iterations
+ )
+ else:
+ pos = nx.spring_layout(
+ G,
+ pos=pos0,
+ k=k,
+ dim=dim,
+ iterations=iterations,
+ )
+ else:
+ pos = pos0
+
+ if project_back_to_2d:
+ # project back to 2d
+ pos = {k: v[:2] for k, v in pos.items()}
+ dim = 2
+
+ if dim == 2:
+ # finally rotate them to cover a small vertical span
+ pos = massage_pos(pos)
+
+ return pos
+
+
+# def get_nice_pos():
+# """Get a nice layout for a graph.
+# """
+
+# # compute a layout for the graph
+# if initial_layout == "layers":
+# for layer, nodes in enumerate(nx.topological_generations(G)):
+# for node in nodes:
+# G.nodes[node]["layer"] = layer
+
+# layout_opts.setdefault("subset_key", "layer")
+# layout_opts.setdefault("align", "vertical")
+# pos = nx.multipartite_layout(G, **layout_opts)
+
+# if layout_opts["align"] == "horizontal":
+# dag_spread = 1 / dag_spread
+# for k, (x, y) in pos.items():
+# pos[k] = (x, dag_spread * y)
+
+# else:
+# if initial_layout == "spiral":
+# layout_opts.setdefault("equidistant", True)
+
+# pos = getattr(nx, initial_layout + "_layout")(G, **layout_opts)
+
+# # further spring based refinement
+# if iterations:
+# pos = nx.layout.spring_layout(G, pos=pos, k=k, iterations=iterations)
+
+
+def plot_graph(
+ self,
+ variables=None,
+ dim=2,
+ layout="auto",
+ initial_layout="auto",
+ iterations="auto",
+ k=None,
+ use_forceatlas2=False,
+ color_by="function",
+ colors=None,
+ connectionstyle="arc3,rad=-0.05",
+ arrowsize=6,
+ edge_color=(0.5, 0.5, 0.5),
+ edge_alpha=0.3,
+ var_color=(0, 0.5, 0.25),
+ const_color=(0, 0.5, 1.0),
+ root_color=(1, 0, 0.5),
+ node_shape="s",
+ node_scale=1.0,
+ node_alpha=1.0,
+ show_labels=True,
+ label_color=(0.5, 0.5, 0.5),
+ label_alpha=1.0,
+ font_size=8,
+ label_rotation=45,
+ figsize=None,
+ ax=None,
+ show_and_close=True,
+ **layout_opts,
+):
+ """Plot the computational graph of this ``LazyArray``."""
+ import matplotlib.pyplot as plt
+ import networkx as nx
+ import numpy as np
+
+ if color_by not in ("id", "function", "variables"):
+ raise ValueError("color_by must be 'id', 'function' or 'variables'")
+
+ colors = get_default_colors_dict(colors)
+ G = self.to_nx_digraph(variables=variables)
+
+ created_fig = ax is None
+ if created_fig:
+ if figsize is None:
+ w = h = (G.number_of_nodes() + 1) ** 0.5
+ figsize = (w, h)
+ fig, ax = plt.subplots(figsize=figsize, constrained_layout=True)
+ fig.set_facecolor((0, 0, 0, 0))
+ ax.axis("off")
+ ax.set_aspect("equal")
+
+ node_colors = {}
+ node_sizes = {}
+ node_labels = {}
+ node_markers = {}
+ for i, data in G.nodes(data=True):
+ # set node color
+ if data["array"] is self:
+ node_markers[i] = "X"
+
+ if color_by == "variables":
+ if data["array"] is self:
+ node_colors[i] = root_color
+ elif data["variable"]:
+ node_colors[i] = var_color
+ else:
+ node_colors[i] = const_color
+
+ elif color_by == "function":
+ if data["array"].fn_name in colors:
+ node_colors[i] = colors[data["array"].fn_name]
+ else:
+ node_colors[i] = hash_to_color(data["array"].fn_name)
+
+ elif color_by == "id":
+ node_colors[i] = hash_to_color(str(id(data["array"])))
+
+ # set node size
+ node_sizes[i] = 6 * node_scale * (np.log2(data["array"].size) + 1)
+
+ # set node label and marker
+ if data["array"].fn_name == "None":
+ node_markers.setdefault(i, "o")
+ node_labels[i] = ""
+ if data["array"].fn_name == "getitem":
+ node_markers.setdefault(i, ".")
+ node_labels[i] = ""
+ else:
+ node_labels[i] = data["array"].fn_name
+
+ node_markers.setdefault(i, node_shape)
+
+ if initial_layout == "layers":
+ for layer, nodes in enumerate(nx.topological_generations(G)):
+ for node in nodes:
+ G.nodes[node]["layer"] = layer
+
+ layout_opts.setdefault("subset_key", "layer")
+ layout_opts.setdefault("align", "vertical")
+
+ if layout_opts["align"] == "horizontal":
+ layout_opts.setdefault("flatten", 2)
+ else:
+ layout_opts.setdefault("flatten", 0.5)
+ layout = "multipartite"
+
+ elif initial_layout == "spiral":
+ layout_opts.setdefault("equidistant", True)
+
+ pos = get_nice_pos(
+ G,
+ dim=dim,
+ layout=layout,
+ initial_layout=initial_layout,
+ iterations=iterations,
+ k=k,
+ use_forceatlas2=use_forceatlas2,
+ **layout_opts,
+ )
+
+ # draw edges!
+ nx.draw_networkx_edges(
+ G,
+ pos=pos,
+ ax=ax,
+ edge_color=edge_color,
+ alpha=edge_alpha,
+ connectionstyle=connectionstyle,
+ arrowsize=arrowsize,
+ arrows=True,
+ )
+ # draw nodes!
+ for node in G.nodes:
+ ax.scatter(
+ *pos[node],
+ s=node_sizes[node],
+ facecolor=node_colors[node],
+ alpha=node_alpha,
+ marker=node_markers[node],
+ )
+ if show_labels:
+ # draw labels!
+ text = nx.draw_networkx_labels(
+ G,
+ pos=pos,
+ ax=ax,
+ labels=node_labels,
+ font_color=label_color,
+ font_size=font_size,
+ alpha=label_alpha,
+ bbox={"color": (0, 0, 0, 0)},
+ )
+ for _, t in text.items():
+ t.set_rotation(label_rotation)
+
+ if (fig is not None) and show_and_close:
+ plt.show()
+ plt.close(fig)
+
+ return fig, ax
+
+
+def plot_circuit(
+ self,
+ color_by="function",
+ colors=None,
+ layout="balanced",
+ linewidth=None,
+ linewidth_scale=1,
+ linealpha=1.0,
+ fontsize=None,
+ fontsize_scale=1,
+ figsize=None,
+ ax=None,
+ show_and_close=True,
+):
+ import matplotlib as mpl
+ import matplotlib.pyplot as plt
+
+ if color_by not in ("id", "function"):
+ raise ValueError("color_by must be 'id' or 'function'")
+ if layout not in ("balanced", "compact", "wide"):
+ raise ValueError("layout must be 'balanced', 'compact', or 'wide'")
+
+ colors = get_default_colors_dict(colors)
+
+ nodes = list(self.ascend())
+ steps = {node: i for i, node in enumerate(nodes)}
+ rails = {self: 0}
+ edges = []
+ active = {0}
+
+ for node in reversed(nodes):
+ if color_by == "function":
+ if node.fn_name in colors:
+ c = colors[node.fn_name]
+ else:
+ c = hash_to_color(node.fn_name)
+ else:
+ c = hash_to_color(str(id(node)))
+ colors[node] = c
+
+ # free up the column
+ active.remove(rails[node])
+
+ # want to plot in same order the computational graph was created
+ deps = sorted(node.deps, key=lambda x: -x.depth)
+
+ # get the 'nearest columns' that are available for children
+ close_rails = (
+ c for c in count_around(rails[node], layout) if c not in active
+ )
+ child_rails = (next(close_rails) for c in deps if c not in rails)
+
+ for child in deps:
+ if child not in rails:
+ # place the node
+ rails[child] = next(child_rails)
+ active.add(rails[child])
+ # add connector
+ edges.append((node, child))
+
+ created_fig = ax is None
+ if created_fig:
+ if figsize is None:
+ w = h = (len(nodes) + 1) ** (2 / 3)
+ figsize = (w, h)
+ fig, ax = plt.subplots(figsize=figsize)
+ fig.set_facecolor((0, 0, 0, 0))
+ ax.axis("off")
+ ax.set_aspect("equal")
+
+ if linewidth is None:
+ linewidth = linewidth_scale * 8 * (figsize[1] / len(nodes))
+ if fontsize is None:
+ fontsize = fontsize_scale * 40 * (figsize[1] / len(nodes))
+
+ # draw the edges
+ for a, b in edges:
+ xya = steps[a], rails[a]
+ xyb = steps[b], rails[b]
+
+ if b.fn_name == "getitem":
+ color = colors[b.deps[0]]
+ else:
+ color = colors[b]
+
+ path_opts = dict(
+ edgecolor=color,
+ linewidth=linewidth,
+ alpha=linealpha,
+ facecolor="none",
+ zorder=9,
+ )
+
+ if xya[1] == xyb[1]:
+ # straight line
+ xy = (xya[0], xyb[0])
+ patch = mpl.patches.PathPatch(
+ mpl.path.Path(
+ [xya, xyb], [mpl.path.Path.MOVETO, mpl.path.Path.LINETO]
+ ),
+ **path_opts,
+ )
+ else:
+ # right angle line
+ patch = mpl.patches.PathPatch(
+ mpl.path.Path(
+ [
+ xya,
+ (xya[0], xyb[1] + 0.25 * (-1) ** (xya[1] < xyb[1])),
+ (xya[0] - 0.25, xyb[1]),
+ xyb,
+ ],
+ [mpl.path.Path.MOVETO] + [mpl.path.Path.LINETO] * 3,
+ ),
+ **path_opts,
+ )
+ ax.add_patch(patch)
+
+ # draw the nodes, and figure out plot range
+ xmin = ymin = float("inf")
+ xmax = ymax = float("-inf")
+ for node in nodes:
+ xy = steps[node], rails[node]
+ xmin, xmax = min(xmin, xy[0]), max(xmax, xy[0])
+ ymin, ymax = min(ymin, xy[1]), max(ymax, xy[1])
+ if not node.deps:
+ # make a square patch centered at xy with radius 0.4
+ patch = mpl.patches.Circle(
+ xy=xy, radius=0.4, color=colors[node], zorder=10
+ )
+ elif node.fn_name == "getitem":
+ # make a small circle for getitem (since not really a node)
+ patch = mpl.patches.Circle(
+ xy=xy, radius=0.15, color=colors[node.deps[0]], zorder=10
+ )
+ else:
+ # make a 'rotated house' shape
+ patch = mpl.patches.Polygon(
+ rotated_house_shape(xy, r=0.3), color=colors[node], zorder=10
+ )
+ ax.add_patch(patch)
+
+ # draw the labels
+ for node in nodes:
+ name = "β" if node.fn_name == "None" else node.fn_name
+ color = colors[node]
+ ax.text(
+ steps[node] - 0.25,
+ ymax + 1.0,
+ f"{name}{list(node.shape)}",
+ ha="left",
+ va="bottom",
+ color=color,
+ fontsize=fontsize,
+ rotation=45,
+ )
+ ax.plot(
+ [steps[node], steps[node]],
+ [ymax + 1, rails[node]],
+ color=color,
+ linewidth=linewidth / 2,
+ alpha=0.25,
+ linestyle=":",
+ clip_on=False,
+ )
+
+ # set plot limits
+ ax.set_xlim(xmin - 0.5, xmax + 0.5)
+ ax.set_ylim(ymin - 0.5, ymax + 0.5)
+
+ if (fig is not None) and show_and_close:
+ plt.show()
+ plt.close(fig)
+
+ return fig, ax
+
+
+# a style to use for matplotlib that works with light and dark backgrounds
+NEUTRAL_STYLE = {
+ "axes.edgecolor": (0.5, 0.5, 0.5),
+ "axes.facecolor": (0, 0, 0, 0),
+ "axes.grid": True,
+ "axes.labelcolor": (0.5, 0.5, 0.5),
+ "axes.spines.right": False,
+ "axes.spines.top": False,
+ "figure.facecolor": (0, 0, 0, 0),
+ "grid.alpha": 0.1,
+ "grid.color": (0.5, 0.5, 0.5),
+ "legend.frameon": False,
+ "text.color": (0.5, 0.5, 0.5),
+ "xtick.color": (0.5, 0.5, 0.5),
+ "xtick.minor.visible": True,
+ "ytick.color": (0.5, 0.5, 0.5),
+ "ytick.minor.visible": True,
+}
+
+
+def default_to_neutral_style(fn):
+ """Wrap a function or method to use the neutral style by default."""
+
+ @functools.wraps(fn)
+ def wrapper(*args, style="neutral", **kwargs):
+ import matplotlib.pyplot as plt
+
+ if style == "neutral":
+ style = NEUTRAL_STYLE
+ elif not style:
+ style = {}
+
+ with plt.style.context(style):
+ return fn(*args, **kwargs)
+
+ return wrapper
+
+
+@default_to_neutral_style
+def plot_history_size_footprint(
+ self,
+ log=None,
+ figsize=(8, 2),
+ color="purple",
+ alpha=0.5,
+ rasterize=4096,
+ rasterize_dpi=300,
+ ax=None,
+ show_and_close=True,
+):
+ """Plot the memory footprint throughout this computation.
+
+ Parameters
+ ----------
+ log : None or int, optional
+ If not None, display the sizes in base ``log``.
+ figsize : tuple, optional
+ Size of the figure.
+ color : str, optional
+ Color of the line.
+ alpha : float, optional
+ Alpha of the line.
+ ax : matplotlib.axes.Axes, optional
+ Axes to plot on, will be created if not provided.
+ return_fig : bool, optional
+ If True, return the figure object, else just show and close it.
+ """
+ import matplotlib.pyplot as plt
+ import numpy as np
+
+ y = np.array(self.history_size_footprint())
+ if log:
+ y = np.log2(y) / np.log2(log)
+ ylabel = f"$\\log_{log}[total size]$"
+ else:
+ ylabel = "total size"
+
+ x = np.arange(y.size)
+
+ if ax is None:
+ fig, ax = plt.subplots(figsize=figsize)
+ fig.set_dpi(rasterize_dpi)
+ else:
+ fig = None
+
+ if isinstance(rasterize, (float, int)):
+ # only turn on above a certain size
+ rasterize = y.size > rasterize
+
+ if rasterize:
+ ax.set_rasterization_zorder(0)
+
+ ax.fill_between(x, 0, y, alpha=alpha, color=color, zorder=-1)
+
+ if fig is not None:
+ ax.grid(True, c=(0.95, 0.95, 0.95), which="both")
+ ax.set_axisbelow(True)
+ ax.set_xlim(0, np.max(x))
+ ax.set_ylim(0, np.max(y))
+ ax.set_ylabel(ylabel)
+
+ if (fig is not None) and show_and_close:
+ plt.show()
+ plt.close(fig)
+
+ return fig, ax
+
+
+@default_to_neutral_style
+def plot_history_functions(
+ self,
+ *,
+ fn=None,
+ log=None,
+ colors=None,
+ kind="scatter",
+ scatter_size=5,
+ scatter_marker="s",
+ lines_width=5,
+ image_alpha_pow=2 / 3,
+ image_aspect=4,
+ legend=True,
+ legend_ncol=None,
+ legend_bbox_to_anchor=None,
+ legend_loc=None,
+ rasterize=4096,
+ rasterize_dpi=300,
+ ax=None,
+ figsize=(8, 2),
+ show_and_close=True,
+):
+ """Plot the functions used throughout this computation, color coded, as
+ either a scatter plot or an image, showing the size of the that individual
+ intermediate as well.
+ """
+ import matplotlib as mpl
+ import matplotlib.pyplot as plt
+ import numpy as np
+
+ if fn is not None:
+ ylabel = "custom"
+ else:
+ ylabel = "node size"
+
+ def fn(node):
+ return node.size
+
+ if log:
+ # wrap the function to take log of values
+ ylabel = f"$\\log_{{{log}}}[{ylabel}]$"
+ orig_fn = fn
+
+ def fn(node):
+ return np.log2(orig_fn(node)) / np.log2(log)
+
+ colors = get_default_colors_dict(colors)
+
+ xs = []
+ ys = []
+ cs = []
+ ymax = 0
+ for i, node in enumerate(self.ascend()):
+ xs.append(i)
+ y = fn(node)
+ ymax = max(ymax, y)
+ ys.append(y)
+ try:
+ c = colors[node.fn_name]
+ except KeyError:
+ c = colors[node.fn_name] = hash_to_color(node.fn_name)
+ cs.append(c)
+
+ if ax is None:
+ fig, ax = plt.subplots(figsize=figsize)
+ fig.set_dpi(rasterize_dpi)
+ ax.set_ylabel(ylabel)
+ else:
+ fig = None
+
+ if isinstance(rasterize, (float, int)):
+ # only turn on above a certain size
+ rasterize = len(xs) > rasterize
+
+ if rasterize:
+ ax.set_rasterization_zorder(0)
+
+ if kind == "scatter":
+ ax.scatter(
+ xs,
+ ys,
+ c=cs,
+ s=scatter_size,
+ marker=scatter_marker,
+ rasterized=rasterize,
+ )
+
+ elif kind == "lines":
+ lns = [((x, 0.0), (x, y)) for x, y in zip(xs, ys)]
+ ax.add_collection(
+ mpl.collections.LineCollection(
+ lns,
+ colors=cs,
+ zorder=-1,
+ lw=lines_width,
+ )
+ )
+ ax.set_xlim(-0.5, len(lns) + 0.5)
+ ax.set_ylim(0, 1.05 * ymax)
+
+ elif kind == "image":
+ ax.axis("off")
+ ys = np.array(ys)
+ ys = (ys / ys.max()).reshape(-1, 1) ** image_alpha_pow
+ N = len(cs)
+ da = round((N / image_aspect) ** 0.5)
+ db = N // da
+ while da * db < N:
+ db += 1
+ Ns = da * db
+ img = np.concatenate([cs, ys], axis=1)
+ img = np.concatenate([img, np.tile(0.0, (Ns - N, 4))], axis=0)
+ img = img.reshape(da, db, 4)
+ ax.imshow(img, zorder=-1)
+
+ if legend:
+ legend_items = [
+ mpl.patches.Patch(facecolor=c, label=fn_name)
+ for fn_name, c in colors.items()
+ ]
+
+ if legend_ncol is None:
+ legend_ncol = max(1, round(len(legend_items) / 6))
+ if legend_bbox_to_anchor is None:
+ legend_bbox_to_anchor = (1.0, 1.0)
+ if legend_loc is None:
+ legend_loc = "upper left"
+
+ ax.legend(
+ handles=legend_items,
+ ncol=legend_ncol,
+ bbox_to_anchor=legend_bbox_to_anchor,
+ loc=legend_loc,
+ )
+
+ if (fig is not None) and show_and_close:
+ plt.show()
+ plt.close(fig)
+
+ return fig, ax
+
+
+@default_to_neutral_style
+def plot_history_stats(
+ self,
+ *,
+ fn="count",
+ colors=None,
+ rasterize_dpi=300,
+ ax=None,
+ figsize=(2, 2),
+ show_and_close=True,
+):
+ from matplotlib import pyplot as plt
+
+ stats = self.history_stats(fn)
+
+ colors = get_default_colors_dict(colors)
+
+ if ax is None:
+ fig, ax = plt.subplots(figsize=figsize)
+ fig.set_dpi(rasterize_dpi)
+ else:
+ fig = None
+
+ xs, labels, clrs = [], [], []
+
+ for fn_name, cnt in sorted(stats.items(), key=lambda x: -x[1]):
+ xs.append(cnt)
+ labels.append(f"{fn_name}: {cnt}")
+ try:
+ color = colors[fn_name]
+ except KeyError:
+ color = colors[fn_name] = hash_to_color(fn_name)
+ clrs.append(color)
+
+ ax.pie(x=xs, labels=labels, colors=clrs)
+
+ if (fig is not None) and show_and_close:
+ plt.show()
+ plt.close(fig)
+
+ return fig, ax
diff --git a/venv/Lib/site-packages/autoray/lazy/linalg.py b/venv/Lib/site-packages/autoray/lazy/linalg.py
new file mode 100644
index 0000000000000000000000000000000000000000..bcb220484dfc5025943026c52404067e090b2795
--- /dev/null
+++ b/venv/Lib/site-packages/autoray/lazy/linalg.py
@@ -0,0 +1,137 @@
+"""
+TODO: lstsq, pinv, eigvals, eigvalsh
+"""
+
+import operator
+
+from ..autoray import get_lib_fn
+from .core import (
+ ensure_lazy,
+ find_common_backend,
+ lazy_cache,
+ shape,
+)
+
+
+@lazy_cache("linalg.svd")
+def svd(a):
+ a = ensure_lazy(a)
+ fn_svd = get_lib_fn(a.backend, "linalg.svd")
+ lsvd = a.to(fn_svd, (a,), shape=(3,))
+ *b, m, n = shape(a)
+ k = min(m, n)
+ lU = lsvd.to(operator.getitem, (lsvd, 0), shape=(*b, m, k))
+ ls = lsvd.to(operator.getitem, (lsvd, 1), shape=(*b, k))
+ lV = lsvd.to(operator.getitem, (lsvd, 2), shape=(*b, k, n))
+ return lU, ls, lV
+
+
+@lazy_cache("linalg.qr")
+def qr(a):
+ a = ensure_lazy(a)
+ lQR = a.to(get_lib_fn(a.backend, "linalg.qr"), (a,), shape=(2,))
+ *b, m, n = shape(a)
+ k = min(m, n)
+ lQ = lQR.to(operator.getitem, (lQR, 0), shape=(*b, m, k))
+ lR = lQR.to(operator.getitem, (lQR, 1), shape=(*b, k, n))
+ return lQ, lR
+
+
+@lazy_cache("linalg.eig")
+def eig(a):
+ a = ensure_lazy(a)
+ fn_eig = get_lib_fn(a.backend, "linalg.eig")
+ leig = a.to(fn_eig, (a,), shape=(2,))
+ *b, m, _ = shape(a)
+ el = leig.to(
+ operator.getitem,
+ (leig, 0),
+ shape=(
+ *b,
+ m,
+ ),
+ )
+ ev = leig.to(operator.getitem, (leig, 1), shape=(*b, m, m))
+ return el, ev
+
+
+@lazy_cache("linalg.eigh")
+def eigh(a):
+ a = ensure_lazy(a)
+ fn_eigh = get_lib_fn(a.backend, "linalg.eigh")
+ leigh = a.to(fn_eigh, (a,), shape=(2,))
+ *b, m, _ = shape(a)
+ el = leigh.to(
+ operator.getitem,
+ (leigh, 0),
+ shape=(
+ *b,
+ m,
+ ),
+ )
+ ev = leigh.to(operator.getitem, (leigh, 1), shape=(*b, m, m))
+ return el, ev
+
+
+@lazy_cache("linalg.inv")
+def inv(a):
+ a = ensure_lazy(a)
+ fn_inv = get_lib_fn(a.backend, "linalg.inv")
+ return a.to(fn_inv, (a,))
+
+
+@lazy_cache("linalg.cholesky")
+def cholesky(a):
+ a = ensure_lazy(a)
+ fn_inv = get_lib_fn(a.backend, "linalg.cholesky")
+ return a.to(fn_inv, (a,))
+
+
+@lazy_cache("linalg.solve")
+def solve(a, b):
+ # XXX: support non square a?
+ a = ensure_lazy(a)
+ b = ensure_lazy(b)
+ backend = find_common_backend(a, b)
+ fn_solve = get_lib_fn(backend, "linalg.solve")
+ return b.to(
+ backend=backend,
+ fn=fn_solve,
+ args=(a, b),
+ deps=(a, b),
+ )
+
+
+@lazy_cache("linalg.norm")
+def norm(x, ord=None, axis=None, keepdims=False):
+ x = ensure_lazy(x)
+ fn_norm = get_lib_fn(x.backend, "linalg.norm")
+
+ if axis is None:
+ if keepdims:
+ newshape = (1,) * x.ndim
+ else:
+ newshape = ()
+
+ else:
+ new_shape = list(shape(x))
+ if isinstance(axis, int):
+ axis = (axis,)
+ if keepdims:
+ for ax in axis:
+ new_shape[ax] = 1
+ else:
+ for ax in sorted(axis, reverse=True):
+ new_shape.pop(ax)
+ newshape = tuple(new_shape)
+
+ return x.to(
+ fn_norm,
+ args=(x,),
+ kwargs={
+ "ord": ord,
+ "axis": axis,
+ "keepdims": keepdims,
+ },
+ shape=newshape,
+ )
diff --git a/venv/Lib/site-packages/brotli-1.2.0.dist-info/INSTALLER b/venv/Lib/site-packages/brotli-1.2.0.dist-info/INSTALLER
new file mode 100644
index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68
--- /dev/null
+++ b/venv/Lib/site-packages/brotli-1.2.0.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/Lib/site-packages/brotli-1.2.0.dist-info/METADATA b/venv/Lib/site-packages/brotli-1.2.0.dist-info/METADATA
new file mode 100644
index 0000000000000000000000000000000000000000..91b106d3b6b731ed6a98e9fc9c3d524a0ec5af04
--- /dev/null
+++ b/venv/Lib/site-packages/brotli-1.2.0.dist-info/METADATA
@@ -0,0 +1,158 @@
+Metadata-Version: 2.4
+Name: brotli
+Version: 1.2.0
+Summary: Python bindings for the Brotli compression library
+Home-page: https://github.com/google/brotli
+Author: The Brotli Authors
+License: MIT
+Platform: Posix
+Platform: MacOS X
+Platform: Windows
+Classifier: Development Status :: 4 - Beta
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: C
+Classifier: Programming Language :: C++
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Unix Shell
+Classifier: Topic :: Software Development :: Libraries
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: System :: Archiving
+Classifier: Topic :: System :: Archiving :: Compression
+Classifier: Topic :: Text Processing :: Fonts
+Classifier: Topic :: Utilities
+Description-Content-Type: text/markdown
+License-File: LICENSE
+Dynamic: author
+Dynamic: classifier
+Dynamic: description
+Dynamic: description-content-type
+Dynamic: home-page
+Dynamic: license
+Dynamic: license-file
+Dynamic: platform
+Dynamic: summary
+
+
+
+
+
+
+
+### Introduction
+
+Brotli is a generic-purpose lossless compression algorithm that compresses data
+using a combination of a modern variant of the LZ77 algorithm, Huffman coding
+and 2nd order context modeling, with a compression ratio comparable to the best
+currently available general-purpose compression methods. It is similar in speed
+with deflate but offers more dense compression.
+
+The specification of the Brotli Compressed Data Format is defined in
+[RFC 7932](https://datatracker.ietf.org/doc/html/rfc7932).
+
+Brotli is open-sourced under the MIT License, see the LICENSE file.
+
+> **Please note:** brotli is a "stream" format; it does not contain
+> meta-information, like checksums or uncompressed data length. It is possible
+> to modify "raw" ranges of the compressed stream and the decoder will not
+> notice that.
+
+### Installation
+
+In most Linux distributions, installing `brotli` is just a matter of using
+the package management system. For example in Debian-based distributions:
+`apt install brotli` will install `brotli`. On MacOS, you can use
+[Homebrew](https://brew.sh/): `brew install brotli`.
+
+[](https://repology.org/project/brotli/versions)
+
+Of course you can also build brotli from sources.
+
+### Build instructions
+
+#### Vcpkg
+
+You can download and install brotli using the
+[vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
+
+ git clone https://github.com/Microsoft/vcpkg.git
+ cd vcpkg
+ ./bootstrap-vcpkg.sh
+ ./vcpkg integrate install
+ ./vcpkg install brotli
+
+The brotli port in vcpkg is kept up to date by Microsoft team members and
+community contributors. If the version is out of date, please [create an issue
+or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
+
+#### Bazel
+
+See [Bazel](https://www.bazel.build/)
+
+#### CMake
+
+The basic commands to build and install brotli are:
+
+ $ mkdir out && cd out
+ $ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=./installed ..
+ $ cmake --build . --config Release --target install
+
+You can use other [CMake](https://cmake.org/) configuration.
+
+#### Python
+
+To install the latest release of the Python module, run the following:
+
+ $ pip install brotli
+
+To install the tip-of-the-tree version, run:
+
+ $ pip install --upgrade git+https://github.com/google/brotli
+
+See the [Python readme](python/README.md) for more details on installing
+from source, development, and testing.
+
+### Contributing
+
+We glad to answer/library related questions in
+[brotli mailing list](https://groups.google.com/g/brotli).
+
+Regular issues / feature requests should be reported in
+[issue tracker](https://github.com/google/brotli/issues).
+
+For reporting vulnerability please read [SECURITY](SECURITY.md).
+
+For contributing changes please read [CONTRIBUTING](CONTRIBUTING.md).
+
+### Benchmarks
+* [Squash Compression Benchmark](https://quixdb.github.io/squash-benchmark/) / [Unstable Squash Compression Benchmark](https://quixdb.github.io/squash-benchmark/unstable/)
+* [Large Text Compression Benchmark](https://mattmahoney.net/dc/text.html)
+* [Lzturbo Benchmark](https://sites.google.com/site/powturbo/home/benchmark)
+
+### Related projects
+> **Disclaimer:** Brotli authors take no responsibility for the third party projects mentioned in this section.
+
+Independent [decoder](https://github.com/madler/brotli) implementation
+by Mark Adler, based entirely on format specification.
+
+JavaScript port of brotli [decoder](https://github.com/devongovett/brotli.js).
+Could be used directly via `npm install brotli`
+
+Hand ported [decoder / encoder](https://github.com/dominikhlbg/BrotliHaxe)
+in haxe by Dominik Homberger.
+Output source code: JavaScript, PHP, Python, Java and C#
+
+7Zip [plugin](https://github.com/mcmilk/7-Zip-Zstd)
+
+Dart compression framework with
+[fast FFI-based Brotli implementation](https://pub.dev/documentation/es_compression/latest/brotli/)
+with ready-to-use prebuilt binaries for Win/Linux/Mac
diff --git a/venv/Lib/site-packages/brotli-1.2.0.dist-info/RECORD b/venv/Lib/site-packages/brotli-1.2.0.dist-info/RECORD
new file mode 100644
index 0000000000000000000000000000000000000000..be98df0b393c3de340fa8e88119c11167ece5a3d
--- /dev/null
+++ b/venv/Lib/site-packages/brotli-1.2.0.dist-info/RECORD
@@ -0,0 +1,9 @@
+__pycache__/brotli.cpython-311.pyc,,
+_brotli.cp311-win_amd64.pyd,sha256=BvsNnXP-O6F6Bik_cpTUCaDS24Io9YA4kDmgg3sUG14,856576
+brotli-1.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+brotli-1.2.0.dist-info/METADATA,sha256=dLzObyHAQu_lsd37HPc2cDB_IdeFaA1feDjHkiJvkdE,6274
+brotli-1.2.0.dist-info/RECORD,,
+brotli-1.2.0.dist-info/WHEEL,sha256=JLOMsP7F5qtkAkINx5UnzbFguf8CqZeraV8o04b0I8I,101
+brotli-1.2.0.dist-info/licenses/LICENSE,sha256=YK4PE-dswuqqEIZ37vpM4Wtkf2u-jPChrJQp2C7Kckg,1103
+brotli-1.2.0.dist-info/top_level.txt,sha256=gsS54HrhO3ZveFxeMrKo_7qH4Sm4TbQ7jGLVBEqJ4NI,15
+brotli.py,sha256=_i8MubwH-A-oO0fza84xahZ_OxtujMLp3AEXy0pMxTU,2027
diff --git a/venv/Lib/site-packages/brotli-1.2.0.dist-info/WHEEL b/venv/Lib/site-packages/brotli-1.2.0.dist-info/WHEEL
new file mode 100644
index 0000000000000000000000000000000000000000..8f98e0aeebdc2c0a3b9b5f83d43db0ef8dbc186b
--- /dev/null
+++ b/venv/Lib/site-packages/brotli-1.2.0.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: setuptools (80.9.0)
+Root-Is-Purelib: false
+Tag: cp311-cp311-win_amd64
+
diff --git a/venv/Lib/site-packages/brotli-1.2.0.dist-info/licenses/LICENSE b/venv/Lib/site-packages/brotli-1.2.0.dist-info/licenses/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..49550fc2d06ede8ea699b279209cb66ee189b539
--- /dev/null
+++ b/venv/Lib/site-packages/brotli-1.2.0.dist-info/licenses/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
+
+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.
diff --git a/venv/Lib/site-packages/brotli-1.2.0.dist-info/top_level.txt b/venv/Lib/site-packages/brotli-1.2.0.dist-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a111e9cca6fb4d3696239f5bb98bee20cb2914e7
--- /dev/null
+++ b/venv/Lib/site-packages/brotli-1.2.0.dist-info/top_level.txt
@@ -0,0 +1,2 @@
+_brotli
+brotli
diff --git a/venv/Lib/site-packages/brotli.py b/venv/Lib/site-packages/brotli.py
new file mode 100644
index 0000000000000000000000000000000000000000..271b460620eb9ffda2de684005a0164200f516f1
--- /dev/null
+++ b/venv/Lib/site-packages/brotli.py
@@ -0,0 +1,57 @@
+# Copyright 2016 The Brotli Authors. All rights reserved.
+#
+# Distributed under MIT license.
+# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+
+"""Functions to compress and decompress data using the Brotli library."""
+
+import _brotli
+
+# The library version.
+version = __version__ = _brotli.__version__
+
+# The compression mode.
+MODE_GENERIC = _brotli.MODE_GENERIC
+MODE_TEXT = _brotli.MODE_TEXT
+MODE_FONT = _brotli.MODE_FONT
+
+# The Compressor object.
+Compressor = _brotli.Compressor
+
+# The Decompressor object.
+Decompressor = _brotli.Decompressor
+
+# Compress a byte string.
+def compress(string, mode=MODE_GENERIC, quality=11, lgwin=22, lgblock=0):
+ """Compress a byte string.
+
+ Args:
+ string (bytes): The input data.
+ mode (int, optional): The compression mode; value 0 should be used for
+ generic input (MODE_GENERIC); value 1 might be beneficial for UTF-8 text
+ input (MODE_TEXT); value 2 tunes encoder for WOFF 2.0 data (MODE_FONT).
+ Defaults to 0.
+ quality (int, optional): Controls the compression-speed vs compression-
+ density tradeoff. The higher the quality, the slower the compression.
+ Range is 0 to 11. Defaults to 11.
+ lgwin (int, optional): Base 2 logarithm of the sliding window size. Range
+ is 10 to 24. Defaults to 22.
+ lgblock (int, optional): Base 2 logarithm of the maximum input block size.
+ Range is 16 to 24. If set to 0, the value will be set based on the
+ quality. Defaults to 0.
+
+ Returns:
+ The compressed byte string.
+
+ Raises:
+ brotli.error: If arguments are invalid, or compressor fails.
+ """
+ compressor = Compressor(mode=mode, quality=quality, lgwin=lgwin,
+ lgblock=lgblock)
+ return compressor.process(string) + compressor.finish()
+
+# Decompress a compressed byte string.
+decompress = _brotli.decompress
+
+# Raised if compression or decompression fails.
+error = _brotli.error
diff --git a/venv/Lib/site-packages/cachetools-7.1.4.dist-info/INSTALLER b/venv/Lib/site-packages/cachetools-7.1.4.dist-info/INSTALLER
new file mode 100644
index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools-7.1.4.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/Lib/site-packages/cachetools-7.1.4.dist-info/METADATA b/venv/Lib/site-packages/cachetools-7.1.4.dist-info/METADATA
new file mode 100644
index 0000000000000000000000000000000000000000..09b42cd74e91f45edd7de007d15e89dcf053bad8
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools-7.1.4.dist-info/METADATA
@@ -0,0 +1,144 @@
+Metadata-Version: 2.4
+Name: cachetools
+Version: 7.1.4
+Summary: Extensible memoizing collections and decorators
+Author-email: Thomas Kemmer
+Maintainer-email: Thomas Kemmer
+License-Expression: MIT
+Project-URL: Homepage, https://github.com/tkem/cachetools/
+Project-URL: Documentation, https://cachetools.readthedocs.io/en/stable/
+Project-URL: Source, https://github.com/tkem/cachetools/
+Project-URL: Repository, https://github.com/tkem/cachetools/
+Project-URL: Issues, https://github.com/tkem/cachetools/issues
+Project-URL: Changelog, https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Requires-Python: >=3.10
+Description-Content-Type: text/x-rst
+License-File: LICENSE
+Dynamic: license-file
+
+cachetools
+========================================================================
+
+.. image:: https://img.shields.io/pypi/v/cachetools
+ :target: https://pypi.org/project/cachetools/
+ :alt: Latest PyPI version
+
+.. image:: https://img.shields.io/github/actions/workflow/status/tkem/cachetools/ci.yml
+ :target: https://github.com/tkem/cachetools/actions/workflows/ci.yml
+ :alt: CI build status
+
+.. image:: https://img.shields.io/readthedocs/cachetools
+ :target: https://cachetools.readthedocs.io/
+ :alt: Documentation build status
+
+.. image:: https://img.shields.io/codecov/c/github/tkem/cachetools/master.svg
+ :target: https://codecov.io/gh/tkem/cachetools
+ :alt: Test coverage
+
+.. image:: https://img.shields.io/github/license/tkem/cachetools
+ :target: https://raw.github.com/tkem/cachetools/master/LICENSE
+ :alt: License
+
+This module provides various memoizing collections and decorators,
+including variants of the Python Standard Library's `@lru_cache`_
+function decorator.
+
+.. code-block:: python
+
+ from cachetools import cached, LRUCache, TTLCache
+
+ # speed up calculating Fibonacci numbers with dynamic programming
+ @cached(cache={})
+ def fib(n):
+ return n if n < 2 else fib(n - 1) + fib(n - 2)
+
+ # cache least recently used Python Enhancement Proposals
+ @cached(cache=LRUCache(maxsize=32))
+ def get_pep(num):
+ url = 'http://www.python.org/dev/peps/pep-%04d/' % num
+ with urllib.request.urlopen(url) as s:
+ return s.read()
+
+ # cache weather data for no longer than ten minutes
+ @cached(cache=TTLCache(maxsize=1024, ttl=600))
+ def get_weather(place):
+ return owm.weather_at_place(place).get_weather()
+
+For the purpose of this module, a *cache* is a mutable_ mapping_ of a
+fixed maximum size. When the cache is full, i.e. by adding another
+item the cache would exceed its maximum size, the cache must choose
+which item(s) to discard based on a suitable `cache algorithm`_.
+
+This module provides multiple cache classes based on different cache
+algorithms, as well as decorators for easily memoizing function and
+method calls.
+
+
+Installation
+------------------------------------------------------------------------
+
+cachetools is available from PyPI_ and can be installed by running::
+
+ pip install cachetools
+
+
+Project Resources
+------------------------------------------------------------------------
+
+- `Documentation`_
+- `Issue tracker`_
+- `Source code`_
+- `Change log`_
+
+
+Related Projects
+------------------------------------------------------------------------
+
+- asyncache_: Helpers to use cachetools_ with asyncio.
+- cachetools-async_: Helpers to use cachetools_ with asyncio.
+- cacheing_: Pure Python Cacheing Library.
+- CacheToolsUtils_: Stackable cache classes for sharing, encryption,
+ statistics *and more* on top of cachetools_, redis_ and memcached_.
+- shelved-cache_: Persistent cache implementation for Python
+ cachetools_.
+
+
+License
+------------------------------------------------------------------------
+
+Copyright (c) 2014-2026 Thomas Kemmer.
+
+Licensed under the `MIT License`_.
+
+
+.. _@lru_cache: https://docs.python.org/3/library/functools.html#functools.lru_cache
+.. _mutable: https://docs.python.org/dev/glossary.html#term-mutable
+.. _mapping: https://docs.python.org/dev/glossary.html#term-mapping
+.. _cache algorithm: https://en.wikipedia.org/wiki/Cache_algorithms
+
+.. _PyPI: https://pypi.org/project/cachetools/
+.. _Documentation: https://cachetools.readthedocs.io/
+.. _Issue tracker: https://github.com/tkem/cachetools/issues/
+.. _Source code: https://github.com/tkem/cachetools/
+.. _Change log: https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst
+.. _MIT License: https://raw.github.com/tkem/cachetools/master/LICENSE
+
+.. _asyncache: https://pypi.org/project/asyncache/
+.. _cachetools-async: https://pypi.org/project/cachetools-async/
+.. _cacheing: https://pypi.org/project/cacheing/
+.. _CacheToolsUtils: https://pypi.org/project/CacheToolsUtils/
+.. _shelved-cache: https://pypi.org/project/shelved-cache/
+.. _cachetools: https://pypi.org/project/cachetools/
+.. _redis: https://redis.io/
+.. _memcached: https://memcached.org/
diff --git a/venv/Lib/site-packages/cachetools-7.1.4.dist-info/RECORD b/venv/Lib/site-packages/cachetools-7.1.4.dist-info/RECORD
new file mode 100644
index 0000000000000000000000000000000000000000..a238c74a0b55d038d99cae58c9e15ad34e101a0c
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools-7.1.4.dist-info/RECORD
@@ -0,0 +1,20 @@
+cachetools-7.1.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+cachetools-7.1.4.dist-info/METADATA,sha256=V433tgPLNPxMIXm-Z_GTfO1XfuftlditAXUpZfaAoQw,5455
+cachetools-7.1.4.dist-info/RECORD,,
+cachetools-7.1.4.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
+cachetools-7.1.4.dist-info/licenses/LICENSE,sha256=KMAAtSsO4nE4po73eCJ-QFcEboa2X2LxysuZsMxJ4NI,1085
+cachetools-7.1.4.dist-info/top_level.txt,sha256=ai2FH78TGwoBcCgVfoqbzk5IQCtnDukdSs4zKuVPvDs,11
+cachetools/__init__.py,sha256=-t917qskjXN-4jkD79U2PhF3GbR8Q01_0CovFmqVWzw,23187
+cachetools/__init__.pyi,sha256=7ZVREDumxRtjJgQmjnEE9kmnsOxAxMCmgCVA5W5LfEY,7695
+cachetools/__pycache__/__init__.cpython-311.pyc,,
+cachetools/__pycache__/_cached.cpython-311.pyc,,
+cachetools/__pycache__/_cachedmethod.cpython-311.pyc,,
+cachetools/__pycache__/func.cpython-311.pyc,,
+cachetools/__pycache__/keys.cpython-311.pyc,,
+cachetools/_cached.py,sha256=PzAcDPv2oQjKL_yldFaBmBZPlZlDm1lchZ9kUKTaeVs,6849
+cachetools/_cachedmethod.py,sha256=rS5167bTExIl82zmPG8oFwDmda_3nOLUR_jpcTK07LQ,14430
+cachetools/func.py,sha256=dQ73GOsR_WQZO9DQIOPeV15nAZRoIZZWBmU2n6e8pig,3301
+cachetools/func.pyi,sha256=tVwg1BIgFBZRg-gLMHi0Arml8TAMUJFDvW7IYdWBmvI,2235
+cachetools/keys.py,sha256=lVC9aRR0TC_G_SEd-4PNri1iBrGhv88FLQF8sjs5tJ4,1967
+cachetools/keys.pyi,sha256=2KvvC0Hay2rJrM876L3Tv-FPH_oRRMtL06Wgpc21mIY,533
+cachetools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
diff --git a/venv/Lib/site-packages/cachetools-7.1.4.dist-info/WHEEL b/venv/Lib/site-packages/cachetools-7.1.4.dist-info/WHEEL
new file mode 100644
index 0000000000000000000000000000000000000000..14a883f292bc96b20c2b76a3081991f2676523a9
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools-7.1.4.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: setuptools (82.0.1)
+Root-Is-Purelib: true
+Tag: py3-none-any
+
diff --git a/venv/Lib/site-packages/cachetools-7.1.4.dist-info/licenses/LICENSE b/venv/Lib/site-packages/cachetools-7.1.4.dist-info/licenses/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..f980a19c78c25959f922b8cc93854d91a89e686f
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools-7.1.4.dist-info/licenses/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2014-2026 Thomas Kemmer
+
+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.
diff --git a/venv/Lib/site-packages/cachetools-7.1.4.dist-info/top_level.txt b/venv/Lib/site-packages/cachetools-7.1.4.dist-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..50d14084a9bc37250ae243ccae4a536f85f3ca2f
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools-7.1.4.dist-info/top_level.txt
@@ -0,0 +1 @@
+cachetools
diff --git a/venv/Lib/site-packages/cachetools/__init__.py b/venv/Lib/site-packages/cachetools/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1b299c544519583cbcd765a01d58c75ad8802062
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools/__init__.py
@@ -0,0 +1,774 @@
+"""Extensible memoizing collections and decorators."""
+
+__all__ = (
+ "Cache",
+ "FIFOCache",
+ "LFUCache",
+ "LRUCache",
+ "RRCache",
+ "TLRUCache",
+ "TTLCache",
+ "cached",
+ "cachedmethod",
+)
+
+__version__ = "7.1.4"
+
+import collections
+import collections.abc
+import functools
+import heapq
+import random
+import time
+
+from . import keys
+
+
+class _DefaultSize:
+ """A minimal "fake" dict that returns a constant size 1 for any key."""
+
+ __slots__ = ()
+
+ def __getitem__(self, _key):
+ return 1
+
+ def __setitem__(self, _key, _value):
+ pass
+
+ def pop(self, _key):
+ return 1
+
+ def clear(self):
+ pass
+
+
+class Cache(collections.abc.MutableMapping):
+ """Mutable mapping to serve as a simple cache or cache base class."""
+
+ __marker = object()
+
+ __size = _DefaultSize()
+
+ def __init__(self, maxsize, getsizeof=None):
+ if getsizeof:
+ self.getsizeof = getsizeof
+ if self.getsizeof is not Cache.getsizeof:
+ self.__size = dict()
+ self.__data = dict()
+ self.__currsize = 0
+ self.__maxsize = maxsize
+
+ def __repr__(self):
+ return "%s(%s, maxsize=%r, currsize=%r)" % (
+ type(self).__name__,
+ repr(self.__data),
+ self.__maxsize,
+ self.__currsize,
+ )
+
+ def __getitem__(self, key):
+ try:
+ return self.__data[key]
+ except KeyError:
+ return self.__missing__(key)
+
+ def __setitem__(self, key, value):
+ maxsize = self.__maxsize
+ size = self.getsizeof(value)
+ if size > maxsize:
+ raise ValueError("value too large")
+ if key not in self.__data or self.__size[key] < size:
+ while self.__currsize + size > maxsize:
+ self.popitem()
+ if key in self.__data:
+ diffsize = size - self.__size[key]
+ else:
+ diffsize = size
+ self.__data[key] = value
+ self.__size[key] = size
+ self.__currsize += diffsize
+
+ def __delitem__(self, key):
+ size = self.__size.pop(key)
+ del self.__data[key]
+ self.__currsize -= size
+
+ def __contains__(self, key):
+ return key in self.__data
+
+ def __missing__(self, key):
+ raise KeyError(key)
+
+ def __iter__(self):
+ return iter(self.__data)
+
+ def __len__(self):
+ return len(self.__data)
+
+ # Note that we cannot simply inherit get(), pop() and setdefault()
+ # from MutableMapping, since these rely on __getitem__ throwing a
+ # KeyError on cache miss. This is not the case if __missing__ is
+ # implemented for a Cache subclass, so we have to roll our own,
+ # somewhat less elegant versions.
+
+ def get(self, key, default=None):
+ if key in self:
+ return self[key]
+ else:
+ return default
+
+ def pop(self, key, default=__marker):
+ if key in self:
+ value = self[key]
+ del self[key]
+ elif default is self.__marker:
+ raise KeyError(key)
+ else:
+ value = default
+ return value
+
+ def setdefault(self, key, default=None):
+ if key in self:
+ value = self[key]
+ else:
+ self[key] = value = default
+ return value
+
+ # Although the MutableMapping.clear() default implementation works
+ # perfectly well, it calls popitem() in a loop until the cache is
+ # empty, resulting in O(n) complexity. For large caches, this
+ # becomes a significant performance bottleneck, so we provide an
+ # optimized version for each Cache subclass.
+
+ def clear(self):
+ self.__data.clear()
+ self.__size.clear()
+ self.__currsize = 0
+
+ @property
+ def maxsize(self):
+ """The maximum size of the cache."""
+ return self.__maxsize
+
+ @property
+ def currsize(self):
+ """The current size of the cache."""
+ return self.__currsize
+
+ @staticmethod
+ def getsizeof(value):
+ """Return the size of a cache element's value."""
+ return 1
+
+
+class FIFOCache(Cache):
+ """First In First Out (FIFO) cache implementation."""
+
+ def __init__(self, maxsize, getsizeof=None):
+ Cache.__init__(self, maxsize, getsizeof)
+ self.__order = collections.OrderedDict()
+
+ def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
+ cache_setitem(self, key, value)
+ if key in self.__order:
+ self.__order.move_to_end(key)
+ else:
+ self.__order[key] = None
+
+ def __delitem__(self, key, cache_delitem=Cache.__delitem__):
+ cache_delitem(self, key)
+ del self.__order[key]
+
+ def popitem(self):
+ """Remove and return the `(key, value)` pair first inserted."""
+ try:
+ key = next(iter(self.__order))
+ except StopIteration:
+ raise KeyError("%s is empty" % type(self).__name__) from None
+ else:
+ return (key, self.pop(key))
+
+ def clear(self):
+ Cache.clear(self)
+ self.__order.clear()
+
+
+class LFUCache(Cache):
+ """Least Frequently Used (LFU) cache implementation."""
+
+ class _Link:
+ __slots__ = ("count", "keys", "next", "prev")
+
+ def __init__(self, count):
+ self.count = count
+ self.keys = set()
+
+ def unlink(self):
+ next = self.next
+ prev = self.prev
+ prev.next = next
+ next.prev = prev
+
+ def __init__(self, maxsize, getsizeof=None):
+ Cache.__init__(self, maxsize, getsizeof)
+ self.__root = root = LFUCache._Link(0) # sentinel
+ root.prev = root.next = root
+ self.__links = {}
+
+ def __getitem__(self, key, cache_getitem=Cache.__getitem__):
+ value = cache_getitem(self, key)
+ if key in self: # __missing__ may not store item
+ self.__touch(key)
+ return value
+
+ def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
+ cache_setitem(self, key, value)
+ if key in self.__links:
+ self.__touch(key)
+ return
+ root = self.__root
+ link = root.next
+ if link.count != 1:
+ link = LFUCache._Link(1)
+ link.next = root.next
+ root.next = link.next.prev = link
+ link.prev = root
+ link.keys.add(key)
+ self.__links[key] = link
+
+ def __delitem__(self, key, cache_delitem=Cache.__delitem__):
+ cache_delitem(self, key)
+ link = self.__links.pop(key)
+ link.keys.remove(key)
+ if not link.keys:
+ link.unlink()
+
+ def popitem(self):
+ """Remove and return the `(key, value)` pair least frequently used."""
+ root = self.__root
+ curr = root.next
+ if curr is root:
+ raise KeyError("%s is empty" % type(self).__name__) from None
+ key = next(iter(curr.keys)) # remove an arbitrary element
+ return (key, self.pop(key))
+
+ def clear(self):
+ Cache.clear(self)
+ root = self.__root
+ root.prev = root.next = root
+ self.__links.clear()
+
+ def __touch(self, key):
+ """Increment use count"""
+ link = self.__links[key]
+ curr = link.next
+ if curr.count != link.count + 1:
+ if len(link.keys) == 1:
+ link.count += 1
+ return
+ curr = LFUCache._Link(link.count + 1)
+ curr.next = link.next
+ link.next = curr.next.prev = curr
+ curr.prev = link
+ curr.keys.add(key)
+ link.keys.remove(key)
+ if not link.keys:
+ link.unlink()
+ self.__links[key] = curr
+
+
+class LRUCache(Cache):
+ """Least Recently Used (LRU) cache implementation."""
+
+ def __init__(self, maxsize, getsizeof=None):
+ Cache.__init__(self, maxsize, getsizeof)
+ self.__order = collections.OrderedDict()
+
+ def __getitem__(self, key, cache_getitem=Cache.__getitem__):
+ value = cache_getitem(self, key)
+ if key in self: # __missing__ may not store item
+ self.__touch(key)
+ return value
+
+ def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
+ cache_setitem(self, key, value)
+ self.__touch(key)
+
+ def __delitem__(self, key, cache_delitem=Cache.__delitem__):
+ cache_delitem(self, key)
+ del self.__order[key]
+
+ def popitem(self):
+ """Remove and return the `(key, value)` pair least recently used."""
+ try:
+ key = next(iter(self.__order))
+ except StopIteration:
+ raise KeyError("%s is empty" % type(self).__name__) from None
+ else:
+ return (key, self.pop(key))
+
+ def clear(self):
+ Cache.clear(self)
+ self.__order.clear()
+
+ def __touch(self, key):
+ """Mark as recently used"""
+ try:
+ self.__order.move_to_end(key)
+ except KeyError:
+ self.__order[key] = None
+
+
+class RRCache(Cache):
+ """Random Replacement (RR) cache implementation."""
+
+ def __init__(self, maxsize, choice=random.choice, getsizeof=None):
+ Cache.__init__(self, maxsize, getsizeof)
+ self.__choice = choice
+ self.__index = {}
+ self.__keys = []
+
+ @property
+ def choice(self):
+ """The `choice` function used by the cache."""
+ return self.__choice
+
+ def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
+ cache_setitem(self, key, value)
+ if key not in self.__index:
+ self.__index[key] = len(self.__keys)
+ self.__keys.append(key)
+
+ def __delitem__(self, key, cache_delitem=Cache.__delitem__):
+ cache_delitem(self, key)
+ index = self.__index.pop(key)
+ if index != len(self.__keys) - 1:
+ last = self.__keys[-1]
+ self.__keys[index] = last
+ self.__index[last] = index
+ self.__keys.pop()
+
+ def popitem(self):
+ """Remove and return a random `(key, value)` pair."""
+ try:
+ key = self.__choice(self.__keys)
+ except IndexError:
+ raise KeyError("%s is empty" % type(self).__name__) from None
+ else:
+ return (key, self.pop(key))
+
+ def clear(self):
+ Cache.clear(self)
+ self.__index.clear()
+ del self.__keys[:]
+
+
+class _TimedCache(Cache):
+ """Base class for time aware cache implementations."""
+
+ class _Timer:
+ def __init__(self, timer):
+ self.__timer = timer
+ self.__nesting = 0
+
+ def __call__(self):
+ if self.__nesting == 0:
+ return self.__timer()
+ else:
+ return self.__time
+
+ def __enter__(self):
+ if self.__nesting == 0:
+ self.__time = time = self.__timer()
+ else:
+ time = self.__time
+ self.__nesting += 1
+ return time
+
+ def __exit__(self, *exc):
+ self.__nesting -= 1
+
+ def __reduce__(self):
+ return _TimedCache._Timer, (self.__timer,)
+
+ def __getattr__(self, name):
+ return getattr(self.__timer, name)
+
+ def __init__(self, maxsize, timer, getsizeof=None):
+ Cache.__init__(self, maxsize, getsizeof)
+ self.__timer = _TimedCache._Timer(timer)
+
+ def __repr__(self, cache_repr=Cache.__repr__):
+ with self.__timer as time:
+ self.expire(time)
+ return cache_repr(self)
+
+ def __len__(self, cache_len=Cache.__len__):
+ with self.__timer as time:
+ self.expire(time)
+ return cache_len(self)
+
+ @property
+ def currsize(self):
+ with self.__timer as time:
+ self.expire(time)
+ return super().currsize
+
+ @property
+ def timer(self):
+ """The timer function used by the cache."""
+ return self.__timer
+
+ def get(self, *args, **kwargs):
+ with self.__timer:
+ return Cache.get(self, *args, **kwargs)
+
+ def pop(self, *args, **kwargs):
+ with self.__timer:
+ return Cache.pop(self, *args, **kwargs)
+
+ def setdefault(self, *args, **kwargs):
+ with self.__timer:
+ return Cache.setdefault(self, *args, **kwargs)
+
+ def clear(self):
+ # Subclasses must override to also reset their own time-tracking
+ # structures; we do not call expire() here since clear() should
+ # be O(1) regardless of cache contents.
+ Cache.clear(self)
+
+ def expire(self, time=None): # pragma: no cover
+ raise NotImplementedError
+
+
+class TTLCache(_TimedCache):
+ """LRU Cache implementation with per-item time-to-live (TTL) value."""
+
+ class _Link:
+ __slots__ = ("key", "expires", "next", "prev")
+
+ def __init__(self, key=None, expires=None):
+ self.key = key
+ self.expires = expires
+
+ def __reduce__(self):
+ return TTLCache._Link, (self.key, self.expires)
+
+ def unlink(self):
+ next = self.next
+ prev = self.prev
+ prev.next = next
+ next.prev = prev
+
+ def __init__(self, maxsize, ttl, timer=time.monotonic, getsizeof=None):
+ _TimedCache.__init__(self, maxsize, timer, getsizeof)
+ self.__root = root = TTLCache._Link()
+ root.prev = root.next = root
+ self.__links = collections.OrderedDict()
+ self.__ttl = ttl
+
+ def __contains__(self, key):
+ try:
+ link = self.__links[key] # no reordering
+ except KeyError:
+ return False
+ else:
+ return self.timer() < link.expires
+
+ def __getitem__(self, key, cache_getitem=Cache.__getitem__):
+ try:
+ link = self.__getlink(key)
+ except KeyError:
+ expired = False
+ else:
+ expired = not (self.timer() < link.expires)
+ if expired:
+ return self.__missing__(key)
+ else:
+ return cache_getitem(self, key)
+
+ def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
+ with self.timer as time:
+ self.expire(time)
+ cache_setitem(self, key, value)
+ try:
+ link = self.__getlink(key)
+ except KeyError:
+ self.__links[key] = link = TTLCache._Link(key)
+ else:
+ link.unlink()
+ link.expires = time + self.__ttl
+ link.next = root = self.__root
+ link.prev = prev = root.prev
+ prev.next = root.prev = link
+
+ def __delitem__(self, key, cache_delitem=Cache.__delitem__):
+ cache_delitem(self, key)
+ link = self.__links.pop(key)
+ link.unlink()
+ if not (self.timer() < link.expires):
+ raise KeyError(key)
+
+ def __iter__(self):
+ root = self.__root
+ curr = root.next
+ while curr is not root:
+ # "freeze" time for iterator access
+ with self.timer as time:
+ if time < curr.expires:
+ yield curr.key
+ curr = curr.next
+
+ def __setstate__(self, state):
+ self.__dict__.update(state)
+ root = self.__root
+ root.prev = root.next = root
+ for link in sorted(self.__links.values(), key=lambda obj: obj.expires):
+ link.next = root
+ link.prev = prev = root.prev
+ prev.next = root.prev = link
+ self.expire(self.timer())
+
+ @property
+ def ttl(self):
+ """The time-to-live value of the cache's items."""
+ return self.__ttl
+
+ def expire(self, time=None):
+ """Remove expired items from the cache and return an iterable of the
+ expired `(key, value)` pairs.
+
+ """
+ if time is None:
+ time = self.timer()
+ root = self.__root
+ curr = root.next
+ links = self.__links
+ expired = []
+ cache_delitem = Cache.__delitem__
+ cache_getitem = Cache.__getitem__
+ while curr is not root and not (time < curr.expires):
+ expired.append((curr.key, cache_getitem(self, curr.key)))
+ cache_delitem(self, curr.key)
+ del links[curr.key]
+ next = curr.next
+ curr.unlink()
+ curr = next
+ return expired
+
+ def popitem(self):
+ """Remove and return the `(key, value)` pair least recently used that
+ has not already expired.
+
+ """
+ with self.timer as time:
+ self.expire(time)
+ try:
+ key = next(iter(self.__links))
+ except StopIteration:
+ raise KeyError("%s is empty" % type(self).__name__) from None
+ else:
+ return (key, self.pop(key))
+
+ def clear(self):
+ _TimedCache.clear(self)
+ root = self.__root
+ root.prev = root.next = root
+ self.__links.clear()
+
+ def __getlink(self, key):
+ value = self.__links[key]
+ self.__links.move_to_end(key)
+ return value
+
+
+class TLRUCache(_TimedCache):
+ """Time aware Least Recently Used (TLRU) cache implementation."""
+
+ __HEAP_CLEANUP_FACTOR = 2 # clean up the heap if size > N * len(items)
+
+ @functools.total_ordering
+ class _Item:
+ __slots__ = ("key", "expires", "removed")
+
+ def __init__(self, key=None, expires=None):
+ self.key = key
+ self.expires = expires
+ self.removed = False
+
+ def __lt__(self, other):
+ return self.expires < other.expires
+
+ def __init__(self, maxsize, ttu, timer=time.monotonic, getsizeof=None):
+ _TimedCache.__init__(self, maxsize, timer, getsizeof)
+ self.__items = collections.OrderedDict()
+ self.__order = []
+ self.__ttu = ttu
+
+ def __contains__(self, key):
+ try:
+ item = self.__items[key] # no reordering
+ except KeyError:
+ return False
+ else:
+ return self.timer() < item.expires
+
+ def __getitem__(self, key, cache_getitem=Cache.__getitem__):
+ try:
+ item = self.__getitem(key)
+ except KeyError:
+ expired = False
+ else:
+ expired = not (self.timer() < item.expires)
+ if expired:
+ return self.__missing__(key)
+ else:
+ return cache_getitem(self, key)
+
+ def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
+ with self.timer as time:
+ expires = self.__ttu(key, value, time)
+ if not (time < expires):
+ return # skip expired items
+ self.expire(time)
+ cache_setitem(self, key, value)
+ # removing an existing item would break the heap structure, so
+ # only mark it as removed for now
+ try:
+ self.__getitem(key).removed = True
+ except KeyError:
+ pass
+ self.__items[key] = item = TLRUCache._Item(key, expires)
+ heapq.heappush(self.__order, item)
+
+ def __delitem__(self, key, cache_delitem=Cache.__delitem__):
+ with self.timer as time:
+ # no self.expire() for performance reasons, e.g. self.clear() [#67]
+ cache_delitem(self, key)
+ item = self.__items.pop(key)
+ item.removed = True
+ if not (time < item.expires):
+ raise KeyError(key)
+
+ def __iter__(self):
+ for curr in self.__order:
+ # "freeze" time for iterator access
+ with self.timer as time:
+ if time < curr.expires and not curr.removed:
+ yield curr.key
+
+ @property
+ def ttu(self):
+ """The local time-to-use function used by the cache."""
+ return self.__ttu
+
+ def expire(self, time=None):
+ """Remove expired items from the cache and return an iterable of the
+ expired `(key, value)` pairs.
+
+ """
+ if time is None:
+ time = self.timer()
+ items = self.__items
+ order = self.__order
+ # clean up the heap if too many items are marked as removed
+ if len(order) > len(items) * self.__HEAP_CLEANUP_FACTOR:
+ self.__order = order = [item for item in order if not item.removed]
+ heapq.heapify(order)
+ expired = []
+ cache_delitem = Cache.__delitem__
+ cache_getitem = Cache.__getitem__
+ while order and (order[0].removed or not (time < order[0].expires)):
+ item = heapq.heappop(order)
+ if not item.removed:
+ expired.append((item.key, cache_getitem(self, item.key)))
+ cache_delitem(self, item.key)
+ del items[item.key]
+ return expired
+
+ def popitem(self):
+ """Remove and return the `(key, value)` pair least recently used that
+ has not already expired.
+
+ """
+ with self.timer as time:
+ self.expire(time)
+ try:
+ key = next(iter(self.__items))
+ except StopIteration:
+ raise KeyError("%s is empty" % type(self).__name__) from None
+ else:
+ return (key, self.pop(key))
+
+ def clear(self):
+ _TimedCache.clear(self)
+ self.__items.clear()
+ del self.__order[:]
+
+ def __getitem(self, key):
+ value = self.__items[key]
+ self.__items.move_to_end(key)
+ return value
+
+
+# note that the runtime __name__ is "CacheInfo", as in stdlib:
+# https://github.com/python/cpython/blob/3.14/Lib/functools.py#L520
+_CacheInfo = collections.namedtuple(
+ "CacheInfo", ["hits", "misses", "maxsize", "currsize"]
+)
+
+
+def cached(cache, key=keys.hashkey, lock=None, condition=None, info=False):
+ """Decorator to wrap a function with a memoizing callable that saves
+ results in a cache.
+
+ """
+ from ._cached import _wrapper
+
+ def decorator(func):
+ if info:
+ if isinstance(cache, Cache):
+
+ def make_info(hits, misses):
+ return _CacheInfo(hits, misses, cache.maxsize, cache.currsize)
+
+ elif isinstance(cache, collections.abc.Mapping):
+
+ def make_info(hits, misses):
+ return _CacheInfo(hits, misses, None, len(cache))
+
+ else:
+
+ def make_info(hits, misses):
+ return _CacheInfo(hits, misses, 0, 0)
+
+ return _wrapper(func, cache, key, lock, condition, info=make_info)
+ else:
+ return _wrapper(func, cache, key, lock, condition)
+
+ return decorator
+
+
+def cachedmethod(cache, key=keys.methodkey, lock=None, condition=None, info=False):
+ """Decorator to wrap a method with a memoizing callable that saves
+ results in a cache.
+
+ """
+ from ._cachedmethod import _wrapper
+
+ def decorator(method):
+ if info:
+
+ def make_info(cache, hits, misses):
+ if isinstance(cache, Cache):
+ return _CacheInfo(hits, misses, cache.maxsize, cache.currsize)
+ elif isinstance(cache, collections.abc.Mapping):
+ return _CacheInfo(hits, misses, None, len(cache))
+ else:
+ raise TypeError("cache(self) must return a mutable mapping")
+
+ return _wrapper(method, cache, key, lock, condition, info=make_info)
+ else:
+ return _wrapper(method, cache, key, lock, condition)
+
+ return decorator
diff --git a/venv/Lib/site-packages/cachetools/__init__.pyi b/venv/Lib/site-packages/cachetools/__init__.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..c7b4d482bb2149344494b85eaf3f0a3d1fca97ed
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools/__init__.pyi
@@ -0,0 +1,245 @@
+import random
+from collections.abc import Callable, Iterator, MutableMapping, Sequence
+from contextlib import AbstractContextManager
+from typing import (
+ Any,
+ Concatenate,
+ Final,
+ Generic,
+ Literal,
+ NamedTuple,
+ ParamSpec,
+ Protocol,
+ TypeVar,
+ overload,
+ type_check_only,
+)
+
+__all__: Final = (
+ "Cache",
+ "FIFOCache",
+ "LFUCache",
+ "LRUCache",
+ "RRCache",
+ "TLRUCache",
+ "TTLCache",
+ "cached",
+ "cachedmethod",
+)
+__version__: str
+
+_P = ParamSpec("_P")
+_R = TypeVar("_R")
+_T = TypeVar("_T")
+_KT = TypeVar("_KT")
+_VT = TypeVar("_VT")
+_TT = TypeVar("_TT", default=float)
+_KT2 = TypeVar("_KT2")
+_VT2 = TypeVar("_VT2")
+
+class Cache(MutableMapping[_KT, _VT]):
+ def __init__(
+ self, maxsize: float, getsizeof: Callable[[_VT], float] | None = None
+ ) -> None: ...
+ def __getitem__(self, key: _KT) -> _VT: ...
+ def __setitem__(self, key: _KT, value: _VT) -> None: ...
+ def __delitem__(self, key: _KT) -> None: ...
+ def __missing__(self, key: _KT) -> _VT: ...
+ def __iter__(self) -> Iterator[_KT]: ...
+ def __len__(self) -> int: ...
+ @overload
+ def pop(self, key: _KT) -> _VT: ...
+ @overload
+ def pop(self, key: _KT, default: _VT | _T) -> _VT | _T: ...
+ def setdefault(self, key: _KT, default: _VT | None = None) -> _VT: ...
+ @property
+ def maxsize(self) -> float: ...
+ @property
+ def currsize(self) -> float: ...
+ @staticmethod
+ def getsizeof(value: _VT) -> float: ...
+
+class FIFOCache(Cache[_KT, _VT]): ...
+class LFUCache(Cache[_KT, _VT]): ...
+class LRUCache(Cache[_KT, _VT]): ...
+
+class RRCache(Cache[_KT, _VT]):
+ def __init__(
+ self,
+ maxsize: float,
+ choice: Callable[[Sequence[_KT]], _KT] = random.choice,
+ getsizeof: Callable[[_VT], float] | None = None,
+ ) -> None: ...
+ @property
+ def choice(self) -> Callable[[Sequence[_KT]], _KT]: ...
+
+class _TimedCache(Cache[_KT, _VT], Generic[_KT, _VT, _TT]):
+ def __init__(
+ self,
+ maxsize: float,
+ timer: Callable[[], _TT],
+ getsizeof: Callable[[_VT], float] | None = None,
+ ) -> None: ...
+
+ class _Timer(AbstractContextManager[_T]):
+ def __init__(self, timer: Callable[[], _T]) -> None: ...
+ def __call__(self) -> _T: ...
+ def __enter__(self) -> _T: ...
+ def __exit__(self, *exc: object) -> None: ...
+ def __getattr__(self, name: str) -> Any: ...
+
+ @property
+ def timer(self) -> _Timer[_TT]: ...
+
+class TTLCache(_TimedCache[_KT, _VT, _TT]):
+ @overload
+ def __init__(
+ self: TTLCache[_KT2, _VT2, float],
+ maxsize: float,
+ ttl: float,
+ *,
+ getsizeof: Callable[[_VT2], float] | None = None,
+ ) -> None: ...
+ @overload
+ def __init__(
+ self,
+ maxsize: float,
+ ttl: Any, # FIXME: must be "addable" to _TT
+ timer: Callable[[], _TT],
+ getsizeof: Callable[[_VT], float] | None = None,
+ ) -> None: ...
+ @property
+ def ttl(self) -> Any: ...
+ def expire(self, time: _TT | None = None) -> list[tuple[_KT, _VT]]: ...
+
+class TLRUCache(_TimedCache[_KT, _VT, _TT]):
+ @overload
+ def __init__(
+ self: TLRUCache[_KT2, _VT2, float],
+ maxsize: float,
+ ttu: Callable[[_KT2, _VT2, float], float],
+ *,
+ getsizeof: Callable[[_VT2], float] | None = None,
+ ) -> None: ...
+ @overload
+ def __init__(
+ self,
+ maxsize: float,
+ ttu: Callable[[_KT, _VT, _TT], _TT],
+ timer: Callable[[], _TT],
+ getsizeof: Callable[[_VT], float] | None = None,
+ ) -> None: ...
+ @property
+ def ttu(self) -> Callable[[_KT, _VT, _TT], _TT]: ...
+ def expire(self, time: _TT | None = None) -> list[tuple[_KT, _VT]]: ...
+
+class _CacheInfo(NamedTuple):
+ hits: int
+ misses: int
+ maxsize: float | None
+ currsize: float
+
+@type_check_only
+class _AbstractCondition(AbstractContextManager[Any], Protocol):
+ # implementation and unit tests do not use plain wait() and notify()
+ def wait(self, timeout: float | None = None) -> bool: ...
+ def wait_for(
+ self, predicate: Callable[[], _T], timeout: float | None = None
+ ) -> _T: ...
+ def notify(self, n: int = 1) -> None: ...
+ def notify_all(self) -> None: ...
+
+@type_check_only
+class _cached_wrapper(Generic[_P, _R]):
+ __wrapped__: Callable[_P, _R]
+ __name__: str
+ __doc__: str | None
+ cache: MutableMapping[Any, Any] | None
+ cache_key: Callable[..., Any] = ...
+ cache_lock: AbstractContextManager[Any] | None = None
+ cache_condition: _AbstractCondition | None = None
+ def __call__(self, /, *args: _P.args, **kwargs: _P.kwargs) -> _R: ...
+ def cache_clear(self) -> None: ...
+
+@type_check_only
+class _cached_wrapper_info(_cached_wrapper[_P, _R]):
+ def cache_info(self) -> _CacheInfo: ...
+
+@overload
+def cached(
+ cache: MutableMapping[_KT, Any] | None,
+ key: Callable[..., _KT] = ...,
+ lock: AbstractContextManager[Any] | None = None,
+ condition: _AbstractCondition | None = None,
+ info: Literal[False] = ...,
+) -> Callable[[Callable[_P, _R]], _cached_wrapper[_P, _R]]: ...
+@overload
+def cached(
+ cache: MutableMapping[_KT, Any] | None,
+ key: Callable[..., _KT] = ...,
+ lock: AbstractContextManager[Any] | None = None,
+ condition: _AbstractCondition | None = None,
+ *,
+ info: Literal[True],
+) -> Callable[[Callable[_P, _R]], _cached_wrapper_info[_P, _R]]: ...
+@overload
+def cached(
+ cache: MutableMapping[_KT, Any] | None,
+ key: Callable[..., _KT],
+ lock: AbstractContextManager[Any] | None,
+ condition: _AbstractCondition | None,
+ info: Literal[True],
+) -> Callable[[Callable[_P, _R]], _cached_wrapper_info[_P, _R]]: ...
+
+@type_check_only
+class _cachedmethod_wrapper(Generic[_P, _R]):
+ __wrapped__: Callable[Concatenate[Any, _P], _R]
+ __name__: str
+ __doc__: str | None
+ cache: MutableMapping[Any, Any]
+ cache_key: Callable[..., Any] = ...
+ cache_lock: AbstractContextManager[Any] | None = None
+ cache_condition: _AbstractCondition | None = None
+ def __set_name__(self, owner: type, name: str) -> None: ...
+ def __get__(
+ self, obj: Any, objtype: type | None = None
+ ) -> _cachedmethod_wrapper[_P, _R]: ...
+ def __call__(self, /, *args: _P.args, **kwargs: _P.kwargs) -> _R: ...
+ def cache_clear(self) -> None: ...
+
+@type_check_only
+class _cachedmethod_wrapper_info(_cachedmethod_wrapper[_P, _R]):
+ def __get__(
+ self, obj: Any, objtype: type | None = None
+ ) -> _cachedmethod_wrapper_info[_P, _R]: ...
+ def cache_info(self) -> _CacheInfo: ...
+
+@overload
+def cachedmethod(
+ cache: Callable[[Any], MutableMapping[_KT, Any]],
+ key: Callable[..., _KT] = ...,
+ lock: Callable[[Any], AbstractContextManager[Any]] | None = None,
+ condition: Callable[[Any], _AbstractCondition] | None = None,
+ info: Literal[False] = ...,
+) -> Callable[[Callable[Concatenate[Any, _P], _R]], _cachedmethod_wrapper[_P, _R]]: ...
+@overload
+def cachedmethod(
+ cache: Callable[[Any], MutableMapping[_KT, Any]],
+ key: Callable[..., _KT] = ...,
+ lock: Callable[[Any], AbstractContextManager[Any]] | None = None,
+ condition: Callable[[Any], _AbstractCondition] | None = None,
+ *,
+ info: Literal[True],
+) -> Callable[
+ [Callable[Concatenate[Any, _P], _R]], _cachedmethod_wrapper_info[_P, _R]
+]: ...
+@overload
+def cachedmethod(
+ cache: Callable[[Any], MutableMapping[_KT, Any]],
+ key: Callable[..., _KT],
+ lock: Callable[[Any], AbstractContextManager[Any]] | None,
+ condition: Callable[[Any], _AbstractCondition] | None,
+ info: Literal[True],
+) -> Callable[
+ [Callable[Concatenate[Any, _P], _R]], _cachedmethod_wrapper_info[_P, _R]
+]: ...
diff --git a/venv/Lib/site-packages/cachetools/_cached.py b/venv/Lib/site-packages/cachetools/_cached.py
new file mode 100644
index 0000000000000000000000000000000000000000..5b09d5ae6494348775c1e23d18a64c2b63b74b2c
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools/_cached.py
@@ -0,0 +1,259 @@
+"""Function decorator helpers."""
+
+__all__ = ()
+
+import functools
+
+# At least for now, the implementation prefers clarity and performance
+# over ease of maintenance, thus providing separate wrappers for
+# all valid combinations of decorator parameters lock, condition and
+# info.
+
+
+def _condition_info(func, cache, key, lock, cond, info):
+ hits = misses = 0
+ pending = set()
+
+ def wrapper(*args, **kwargs):
+ nonlocal hits, misses
+ k = key(*args, **kwargs)
+ with lock:
+ cond.wait_for(lambda: k not in pending)
+ try:
+ result = cache[k]
+ hits += 1
+ return result
+ except KeyError:
+ pending.add(k)
+ misses += 1
+ try:
+ v = func(*args, **kwargs)
+ with lock:
+ try:
+ cache[k] = v
+ except ValueError:
+ pass # value too large
+ return v
+ finally:
+ with lock:
+ pending.remove(k)
+ cond.notify_all()
+
+ def cache_clear():
+ nonlocal hits, misses
+ with lock:
+ cache.clear()
+ hits = misses = 0
+
+ def cache_info():
+ with lock:
+ return info(hits, misses)
+
+ wrapper.cache_clear = cache_clear
+ wrapper.cache_info = cache_info
+ return wrapper
+
+
+def _locked_info(func, cache, key, lock, info):
+ hits = misses = 0
+
+ def wrapper(*args, **kwargs):
+ nonlocal hits, misses
+ k = key(*args, **kwargs)
+ with lock:
+ try:
+ result = cache[k]
+ hits += 1
+ return result
+ except KeyError:
+ misses += 1
+ v = func(*args, **kwargs)
+ with lock:
+ try:
+ # In case of a race condition, i.e. if another thread
+ # stored a value for this key while we were calling
+ # func(), prefer the cached value.
+ return cache.setdefault(k, v)
+ except ValueError:
+ return v # value too large
+
+ def cache_clear():
+ nonlocal hits, misses
+ with lock:
+ cache.clear()
+ hits = misses = 0
+
+ def cache_info():
+ with lock:
+ return info(hits, misses)
+
+ wrapper.cache_clear = cache_clear
+ wrapper.cache_info = cache_info
+ return wrapper
+
+
+def _unlocked_info(func, cache, key, info):
+ hits = misses = 0
+
+ def wrapper(*args, **kwargs):
+ nonlocal hits, misses
+ k = key(*args, **kwargs)
+ try:
+ result = cache[k]
+ hits += 1
+ return result
+ except KeyError:
+ misses += 1
+ v = func(*args, **kwargs)
+ try:
+ cache[k] = v
+ except ValueError:
+ pass # value too large
+ return v
+
+ def cache_clear():
+ nonlocal hits, misses
+ cache.clear()
+ hits = misses = 0
+
+ def cache_info():
+ return info(hits, misses)
+
+ wrapper.cache_clear = cache_clear
+ wrapper.cache_info = cache_info
+ return wrapper
+
+
+def _uncached_info(func, info):
+ misses = 0
+
+ def wrapper(*args, **kwargs):
+ nonlocal misses
+ misses += 1
+ return func(*args, **kwargs)
+
+ def cache_clear():
+ nonlocal misses
+ misses = 0
+
+ wrapper.cache_clear = cache_clear
+ wrapper.cache_info = lambda: info(0, misses)
+ return wrapper
+
+
+def _condition(func, cache, key, lock, cond):
+ pending = set()
+
+ def wrapper(*args, **kwargs):
+ k = key(*args, **kwargs)
+ with lock:
+ cond.wait_for(lambda: k not in pending)
+ try:
+ result = cache[k]
+ return result
+ except KeyError:
+ pending.add(k)
+ try:
+ v = func(*args, **kwargs)
+ with lock:
+ try:
+ cache[k] = v
+ except ValueError:
+ pass # value too large
+ return v
+ finally:
+ with lock:
+ pending.remove(k)
+ cond.notify_all()
+
+ def cache_clear():
+ with lock:
+ cache.clear()
+
+ wrapper.cache_clear = cache_clear
+ return wrapper
+
+
+def _locked(func, cache, key, lock):
+ def wrapper(*args, **kwargs):
+ k = key(*args, **kwargs)
+ with lock:
+ try:
+ return cache[k]
+ except KeyError:
+ pass # key not found
+ v = func(*args, **kwargs)
+ with lock:
+ try:
+ # In case of a race condition, i.e. if another thread
+ # stored a value for this key while we were calling
+ # func(), prefer the cached value.
+ return cache.setdefault(k, v)
+ except ValueError:
+ return v # value too large
+
+ def cache_clear():
+ with lock:
+ cache.clear()
+
+ wrapper.cache_clear = cache_clear
+ return wrapper
+
+
+def _unlocked(func, cache, key):
+ def wrapper(*args, **kwargs):
+ k = key(*args, **kwargs)
+ try:
+ return cache[k]
+ except KeyError:
+ pass # key not found
+ v = func(*args, **kwargs)
+ try:
+ cache[k] = v
+ except ValueError:
+ pass # value too large
+ return v
+
+ wrapper.cache_clear = lambda: cache.clear()
+ return wrapper
+
+
+def _uncached(func):
+ def wrapper(*args, **kwargs):
+ return func(*args, **kwargs)
+
+ wrapper.cache_clear = lambda: None
+ return wrapper
+
+
+def _wrapper(func, cache, key, lock=None, cond=None, info=None):
+ if info is not None:
+ if cache is None:
+ wrapper = _uncached_info(func, info)
+ elif cond is not None and lock is not None:
+ wrapper = _condition_info(func, cache, key, lock, cond, info)
+ elif cond is not None:
+ wrapper = _condition_info(func, cache, key, cond, cond, info)
+ elif lock is not None:
+ wrapper = _locked_info(func, cache, key, lock, info)
+ else:
+ wrapper = _unlocked_info(func, cache, key, info)
+ else:
+ if cache is None:
+ wrapper = _uncached(func)
+ elif cond is not None and lock is not None:
+ wrapper = _condition(func, cache, key, lock, cond)
+ elif cond is not None:
+ wrapper = _condition(func, cache, key, cond, cond)
+ elif lock is not None:
+ wrapper = _locked(func, cache, key, lock)
+ else:
+ wrapper = _unlocked(func, cache, key)
+ wrapper.cache_info = None
+
+ wrapper.cache = cache
+ wrapper.cache_key = key
+ wrapper.cache_lock = lock if lock is not None else cond
+ wrapper.cache_condition = cond
+
+ return functools.update_wrapper(wrapper, func)
diff --git a/venv/Lib/site-packages/cachetools/_cachedmethod.py b/venv/Lib/site-packages/cachetools/_cachedmethod.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf62cc989c32e9876d12f5021fa4e74c42f99840
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools/_cachedmethod.py
@@ -0,0 +1,421 @@
+"""Method decorator helpers."""
+
+__all__ = ()
+
+import functools
+import warnings
+import weakref
+
+
+def _warn_classmethod(stacklevel):
+ warnings.warn(
+ "decorating class methods with @cachedmethod is deprecated",
+ DeprecationWarning,
+ stacklevel=stacklevel,
+ )
+
+
+def _warn_instance_dict(msg, stacklevel):
+ warnings.warn(
+ msg,
+ DeprecationWarning,
+ stacklevel=stacklevel,
+ )
+
+
+def _none(_):
+ return None
+
+
+class _WrapperBase:
+ """Wrapper base class providing default implementations for properties."""
+
+ def __init__(self, obj, method, cache, key, lock=None, cond=None):
+ if isinstance(obj, type):
+ _warn_classmethod(stacklevel=5)
+ functools.update_wrapper(self, method)
+ self._obj = obj # protected
+ self.__cache = cache
+ self.__key = functools.partial(key, obj)
+ self.__lock = lock if lock is not None else _none
+ self.__cond = cond if cond is not None else _none
+
+ def __call__(self, *args, **kwargs):
+ raise NotImplementedError() # pragma: no cover
+
+ def cache_clear(self):
+ raise NotImplementedError() # pragma: no cover
+
+ @property
+ def cache(self):
+ return self.__cache(self._obj)
+
+ @property
+ def cache_key(self):
+ return self.__key # self._obj passed via functools.partial
+
+ @property
+ def cache_lock(self):
+ return self.__lock(self._obj)
+
+ @property
+ def cache_condition(self):
+ return self.__cond(self._obj)
+
+
+class _DescriptorBase:
+ """Descriptor base class implementing the basic descriptor protocol."""
+
+ def __init__(self, deprecated=False):
+ self.__attrname = None
+ self.__deprecated = deprecated
+
+ def __set_name__(self, owner, name):
+ if self.__attrname is None:
+ self.__attrname = name
+ elif name != self.__attrname:
+ raise TypeError(
+ "Cannot assign the same @cachedmethod to two different names "
+ f"({self.__attrname!r} and {name!r})."
+ )
+
+ def __get__(self, obj, objtype=None):
+ wrapper = self.Wrapper(obj) # type: ignore
+ if obj is None:
+ # Return the wrapper itself without modification when accessed
+ # through the class to support class-level introspection, such
+ # as for mocking with autospec=True in unittest.mock.
+ pass
+ elif self.__attrname is not None:
+ # replace descriptor instance with wrapper in instance dict
+ try:
+ # In case of a race condition where another thread already replaced
+ # the descriptor, prefer the initial wrapper.
+ wrapper = obj.__dict__.setdefault(self.__attrname, wrapper)
+ except AttributeError:
+ # not all objects have __dict__ (e.g. class defines slots)
+ msg = (
+ f"No '__dict__' attribute on {type(obj).__name__!r} "
+ f"instance to cache {self.__attrname!r} property."
+ )
+ if self.__deprecated:
+ _warn_instance_dict(msg, 3)
+ else:
+ raise TypeError(msg) from None
+ except TypeError:
+ msg = (
+ f"The '__dict__' attribute on {type(obj).__name__!r} "
+ f"instance does not support item assignment for "
+ f"caching {self.__attrname!r} property."
+ )
+ if self.__deprecated:
+ _warn_instance_dict(msg, 3)
+ else:
+ raise TypeError(msg) from None
+ elif self.__deprecated:
+ pass # deprecated @classmethod, warning already raised elsewhere
+ else:
+ msg = "Cannot use @cachedmethod instance without calling __set_name__ on it"
+ raise TypeError(msg) from None
+ return wrapper
+
+
+class _DeprecatedDescriptorBase(_DescriptorBase):
+ """Descriptor base class supporting deprecated @classmethod use."""
+
+ def __init__(self, wrapper, cache_clear):
+ super().__init__(deprecated=True)
+ self.__wrapper = wrapper
+ self.__cache_clear = cache_clear
+
+ # called for @classmethod with Python >= 3.13
+ def __call__(self, *args, **kwargs):
+ _warn_classmethod(stacklevel=3)
+ return self.__wrapper(*args, **kwargs)
+
+ # backward-compatible @classmethod handling with Python >= 3.13
+ def cache_clear(self, objtype):
+ _warn_classmethod(stacklevel=3)
+ return self.__cache_clear(objtype)
+
+
+# At least for now, the implementation prefers clarity and performance
+# over ease of maintenance, thus providing separate descriptors for
+# all valid combinations of decorator parameters lock, condition and
+# info.
+
+
+def _condition_info(method, cache, key, lock, cond, info):
+ class Descriptor(_DescriptorBase):
+ class Wrapper(_WrapperBase):
+ def __init__(self, obj):
+ super().__init__(obj, method, cache, key, lock, cond)
+ self.__hits = self.__misses = 0
+ self.__pending = set()
+
+ def __call__(self, *args, **kwargs):
+ cache = self.cache
+ lock = self.cache_lock
+ cond = self.cache_condition
+ key = self.cache_key(*args, **kwargs)
+
+ with lock:
+ cond.wait_for(lambda: key not in self.__pending)
+ try:
+ result = cache[key]
+ self.__hits += 1
+ return result
+ except KeyError:
+ self.__pending.add(key)
+ self.__misses += 1
+ try:
+ val = method(self._obj, *args, **kwargs)
+ with lock:
+ try:
+ cache[key] = val
+ except ValueError:
+ pass # value too large
+ return val
+ finally:
+ with lock:
+ self.__pending.remove(key)
+ cond.notify_all()
+
+ def cache_clear(self):
+ with self.cache_lock:
+ self.cache.clear()
+ self.__hits = self.__misses = 0
+
+ def cache_info(self):
+ with self.cache_lock:
+ return info(self.cache, self.__hits, self.__misses)
+
+ return Descriptor()
+
+
+def _locked_info(method, cache, key, lock, info):
+ class Descriptor(_DescriptorBase):
+ class Wrapper(_WrapperBase):
+ def __init__(self, obj):
+ super().__init__(obj, method, cache, key, lock)
+ self.__hits = self.__misses = 0
+
+ def __call__(self, *args, **kwargs):
+ cache = self.cache
+ lock = self.cache_lock
+ key = self.cache_key(*args, **kwargs)
+ with lock:
+ try:
+ result = cache[key]
+ self.__hits += 1
+ return result
+ except KeyError:
+ self.__misses += 1
+ val = method(self._obj, *args, **kwargs)
+ with lock:
+ try:
+ # In case of a race condition, i.e. if another thread
+ # stored a value for this key while we were calling
+ # method(), prefer the cached value.
+ return cache.setdefault(key, val)
+ except ValueError:
+ return val # value too large
+
+ def cache_clear(self):
+ with self.cache_lock:
+ self.cache.clear()
+ self.__hits = self.__misses = 0
+
+ def cache_info(self):
+ with self.cache_lock:
+ return info(self.cache, self.__hits, self.__misses)
+
+ return Descriptor()
+
+
+def _unlocked_info(method, cache, key, info):
+ class Descriptor(_DescriptorBase):
+ class Wrapper(_WrapperBase):
+ def __init__(self, obj):
+ super().__init__(obj, method, cache, key)
+ self.__hits = self.__misses = 0
+
+ def __call__(self, *args, **kwargs):
+ cache = self.cache
+ key = self.cache_key(*args, **kwargs)
+ try:
+ result = cache[key]
+ self.__hits += 1
+ return result
+ except KeyError:
+ self.__misses += 1
+ val = method(self._obj, *args, **kwargs)
+ try:
+ cache[key] = val
+ except ValueError:
+ pass # value too large
+ return val
+
+ def cache_clear(self):
+ self.cache.clear()
+ self.__hits = self.__misses = 0
+
+ def cache_info(self):
+ return info(self.cache, self.__hits, self.__misses)
+
+ return Descriptor()
+
+
+def _condition(method, cache, key, lock, cond):
+ # backward-compatible weakref dictionary for Python >= 3.13
+ pending = weakref.WeakKeyDictionary()
+
+ def wrapper(self, pending, *args, **kwargs):
+ c = cache(self)
+ k = key(self, *args, **kwargs)
+ with lock(self):
+ cond(self).wait_for(lambda: k not in pending)
+ try:
+ return c[k]
+ except KeyError:
+ pending.add(k)
+ try:
+ v = method(self, *args, **kwargs)
+ with lock(self):
+ try:
+ c[k] = v
+ except ValueError:
+ pass # value too large
+ return v
+ finally:
+ with lock(self):
+ pending.remove(k)
+ cond(self).notify_all()
+
+ def cache_clear(self):
+ c = cache(self)
+ with lock(self):
+ c.clear()
+
+ def classmethod_wrapper(self, *args, **kwargs):
+ p = pending.setdefault(self, set())
+ return wrapper(self, p, *args, **kwargs)
+
+ class Descriptor(_DeprecatedDescriptorBase):
+ class Wrapper(_WrapperBase):
+ def __init__(self, obj):
+ super().__init__(obj, method, cache, key, lock, cond)
+ self.__pending = set()
+
+ def __call__(self, *args, **kwargs):
+ return wrapper(self._obj, self.__pending, *args, **kwargs)
+
+ # objtype: backward-compatible @classmethod handling with Python < 3.13
+ def cache_clear(self, _objtype=None):
+ return cache_clear(self._obj)
+
+ return Descriptor(classmethod_wrapper, cache_clear)
+
+
+def _locked(method, cache, key, lock):
+ def wrapper(self, *args, **kwargs):
+ c = cache(self)
+ k = key(self, *args, **kwargs)
+ with lock(self):
+ try:
+ return c[k]
+ except KeyError:
+ pass # key not found
+ v = method(self, *args, **kwargs)
+ with lock(self):
+ try:
+ # In case of a race condition, i.e. if another thread
+ # stored a value for this key while we were calling
+ # method(), prefer the cached value.
+ return c.setdefault(k, v)
+ except ValueError:
+ return v # value too large
+
+ def cache_clear(self):
+ c = cache(self)
+ with lock(self):
+ c.clear()
+
+ class Descriptor(_DeprecatedDescriptorBase):
+ class Wrapper(_WrapperBase):
+ def __init__(self, obj):
+ super().__init__(obj, method, cache, key, lock)
+
+ def __call__(self, *args, **kwargs):
+ return wrapper(self._obj, *args, **kwargs)
+
+ # objtype: backward-compatible @classmethod handling with Python < 3.13
+ def cache_clear(self, _objtype=None):
+ return cache_clear(self._obj)
+
+ return Descriptor(wrapper, cache_clear)
+
+
+def _unlocked(method, cache, key):
+ def wrapper(self, *args, **kwargs):
+ c = cache(self)
+ k = key(self, *args, **kwargs)
+ try:
+ return c[k]
+ except KeyError:
+ pass # key not found
+ v = method(self, *args, **kwargs)
+ try:
+ c[k] = v
+ except ValueError:
+ pass # value too large
+ return v
+
+ def cache_clear(self):
+ c = cache(self)
+ c.clear()
+
+ class Descriptor(_DeprecatedDescriptorBase):
+ class Wrapper(_WrapperBase):
+ def __init__(self, obj):
+ super().__init__(obj, method, cache, key)
+
+ def __call__(self, *args, **kwargs):
+ return wrapper(self._obj, *args, **kwargs)
+
+ # objtype: backward-compatible @classmethod handling with Python < 3.13
+ def cache_clear(self, _objtype=None):
+ return cache_clear(self._obj)
+
+ return Descriptor(wrapper, cache_clear)
+
+
+def _wrapper(method, cache, key, lock=None, cond=None, info=None):
+ if info is not None:
+ if cond is not None and lock is not None:
+ wrapper = _condition_info(method, cache, key, lock, cond, info)
+ elif cond is not None:
+ wrapper = _condition_info(method, cache, key, cond, cond, info)
+ elif lock is not None:
+ wrapper = _locked_info(method, cache, key, lock, info)
+ else:
+ wrapper = _unlocked_info(method, cache, key, info)
+ else:
+ if cond is not None and lock is not None:
+ wrapper = _condition(method, cache, key, lock, cond)
+ elif cond is not None:
+ wrapper = _condition(method, cache, key, cond, cond)
+ elif lock is not None:
+ wrapper = _locked(method, cache, key, lock)
+ else:
+ wrapper = _unlocked(method, cache, key)
+
+ # backward-compatible properties for deprecated @classmethod use
+ wrapper.cache = cache # type: ignore
+ wrapper.cache_key = key # type: ignore
+ wrapper.cache_lock = lock if lock is not None else cond # type: ignore
+ wrapper.cache_condition = cond # type: ignore
+
+ # functools.update_wrapper() will not accept descriptor (decorator) as wrapper
+ # https://github.com/python/typeshed/issues/9846
+ return functools.update_wrapper(wrapper, method) # type: ignore
diff --git a/venv/Lib/site-packages/cachetools/func.py b/venv/Lib/site-packages/cachetools/func.py
new file mode 100644
index 0000000000000000000000000000000000000000..c2d3efc3e2dd57ee10855006476f8e370660060c
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools/func.py
@@ -0,0 +1,104 @@
+"""`functools.lru_cache` compatible memoizing function decorators."""
+
+__all__ = ("fifo_cache", "lfu_cache", "lru_cache", "rr_cache", "ttl_cache")
+
+import math
+import random
+import time
+from threading import Condition
+
+from . import FIFOCache, LFUCache, LRUCache, RRCache, TTLCache
+from . import cached
+from . import keys
+
+
+class _UnboundTTLCache(TTLCache):
+ def __init__(self, ttl, timer):
+ TTLCache.__init__(self, math.inf, ttl, timer)
+
+ @property
+ def maxsize(self): # type: ignore
+ return None
+
+
+def _cache(cache, maxsize, typed):
+ def decorator(func):
+ # like functools.lru_cache, this has to be thread-safe;
+ # additionally, this also prevents cache stampede scenarios
+ # using a condition variable
+ key = keys.typedkey if typed else keys.hashkey
+ wrapper = cached(cache=cache, key=key, condition=Condition(), info=True)(func)
+ wrapper.cache_parameters = lambda: {"maxsize": maxsize, "typed": typed} # type: ignore
+ return wrapper
+
+ return decorator
+
+
+def fifo_cache(maxsize=128, typed=False):
+ """Decorator to wrap a function with a memoizing callable that saves
+ up to `maxsize` results based on a First In First Out (FIFO)
+ algorithm.
+
+ """
+ if maxsize is None:
+ return _cache({}, None, typed)
+ elif callable(maxsize):
+ return _cache(FIFOCache(128), 128, typed)(maxsize)
+ else:
+ return _cache(FIFOCache(maxsize), maxsize, typed)
+
+
+def lfu_cache(maxsize=128, typed=False):
+ """Decorator to wrap a function with a memoizing callable that saves
+ up to `maxsize` results based on a Least Frequently Used (LFU)
+ algorithm.
+
+ """
+ if maxsize is None:
+ return _cache({}, None, typed)
+ elif callable(maxsize):
+ return _cache(LFUCache(128), 128, typed)(maxsize)
+ else:
+ return _cache(LFUCache(maxsize), maxsize, typed)
+
+
+def lru_cache(maxsize=128, typed=False):
+ """Decorator to wrap a function with a memoizing callable that saves
+ up to `maxsize` results based on a Least Recently Used (LRU)
+ algorithm.
+
+ """
+ if maxsize is None:
+ return _cache({}, None, typed)
+ elif callable(maxsize):
+ return _cache(LRUCache(128), 128, typed)(maxsize)
+ else:
+ return _cache(LRUCache(maxsize), maxsize, typed)
+
+
+def rr_cache(maxsize=128, choice=random.choice, typed=False):
+ """Decorator to wrap a function with a memoizing callable that saves
+ up to `maxsize` results based on a Random Replacement (RR)
+ algorithm.
+
+ """
+ if maxsize is None:
+ return _cache({}, None, typed)
+ elif callable(maxsize):
+ return _cache(RRCache(128, choice), 128, typed)(maxsize)
+ else:
+ return _cache(RRCache(maxsize, choice), maxsize, typed)
+
+
+def ttl_cache(maxsize=128, ttl=600, timer=time.monotonic, typed=False):
+ """Decorator to wrap a function with a memoizing callable that saves
+ up to `maxsize` results based on a Least Recently Used (LRU)
+ algorithm with a per-item time-to-live (TTL) value.
+
+ """
+ if maxsize is None:
+ return _cache(_UnboundTTLCache(ttl, timer), None, typed)
+ elif callable(maxsize):
+ return _cache(TTLCache(128, ttl, timer), 128, typed)(maxsize)
+ else:
+ return _cache(TTLCache(maxsize, ttl, timer), maxsize, typed)
diff --git a/venv/Lib/site-packages/cachetools/func.pyi b/venv/Lib/site-packages/cachetools/func.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..7d1abed1fe6c9d12986a0934a33b5b7fac4334b1
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools/func.pyi
@@ -0,0 +1,71 @@
+from collections.abc import Callable, Sequence
+from typing import Any, Final, Generic, ParamSpec, TypeVar, overload, type_check_only
+
+from . import _CacheInfo
+
+__all__: Final = ("fifo_cache", "lfu_cache", "lru_cache", "rr_cache", "ttl_cache")
+
+_P = ParamSpec("_P")
+_T = TypeVar("_T")
+_R = TypeVar("_R")
+
+@type_check_only
+class _cachetools_cache_wrapper(Generic[_P, _R]):
+ __wrapped__: Callable[_P, _R]
+ __name__: str
+ __doc__: str | None
+ def __call__(self, /, *args: _P.args, **kwargs: _P.kwargs) -> _R: ...
+ def cache_info(self) -> _CacheInfo: ...
+ def cache_clear(self) -> None: ...
+ def cache_parameters(self) -> dict[str, Any]: ...
+
+@overload
+def fifo_cache(
+ maxsize: int | None = 128, typed: bool = False
+) -> Callable[[Callable[_P, _R]], _cachetools_cache_wrapper[_P, _R]]: ...
+@overload
+def fifo_cache(
+ maxsize: Callable[_P, _R], typed: bool = False
+) -> _cachetools_cache_wrapper[_P, _R]: ...
+@overload
+def lfu_cache(
+ maxsize: int | None = 128, typed: bool = False
+) -> Callable[[Callable[_P, _R]], _cachetools_cache_wrapper[_P, _R]]: ...
+@overload
+def lfu_cache(
+ maxsize: Callable[_P, _R], typed: bool = False
+) -> _cachetools_cache_wrapper[_P, _R]: ...
+@overload
+def lru_cache(
+ maxsize: int | None = 128, typed: bool = False
+) -> Callable[[Callable[_P, _R]], _cachetools_cache_wrapper[_P, _R]]: ...
+@overload
+def lru_cache(
+ maxsize: Callable[_P, _R], typed: bool = False
+) -> _cachetools_cache_wrapper[_P, _R]: ...
+@overload
+def rr_cache(
+ maxsize: int | None = 128,
+ choice: Callable[[Sequence[_T]], _T] = ...,
+ typed: bool = False,
+) -> Callable[[Callable[_P, _R]], _cachetools_cache_wrapper[_P, _R]]: ...
+@overload
+def rr_cache(
+ maxsize: Callable[_P, _R],
+ choice: Callable[[Sequence[_T]], _T] = ...,
+ typed: bool = False,
+) -> _cachetools_cache_wrapper[_P, _R]: ...
+@overload
+def ttl_cache(
+ maxsize: int | None = 128,
+ ttl: Any = 600,
+ timer: Callable[[], _T] = ...,
+ typed: bool = False,
+) -> Callable[[Callable[_P, _R]], _cachetools_cache_wrapper[_P, _R]]: ...
+@overload
+def ttl_cache(
+ maxsize: Callable[_P, _R],
+ ttl: Any = 600,
+ timer: Callable[[], _T] = ...,
+ typed: bool = False,
+) -> _cachetools_cache_wrapper[_P, _R]: ...
diff --git a/venv/Lib/site-packages/cachetools/keys.py b/venv/Lib/site-packages/cachetools/keys.py
new file mode 100644
index 0000000000000000000000000000000000000000..82bdc5f10d841d70569691fc39d010ccb0212107
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools/keys.py
@@ -0,0 +1,66 @@
+"""Key functions for memoizing decorators."""
+
+__all__ = ("hashkey", "methodkey", "typedkey", "typedmethodkey")
+
+
+class _HashedTuple(tuple):
+ """A tuple that ensures that hash() will be called no more than once
+ per element, since cache decorators will hash the key multiple
+ times on a cache miss. See also _HashedSeq in the standard
+ library functools implementation.
+
+ """
+
+ __hashvalue = None # default value, set in instance on first use
+
+ def __hash__(self, hash=tuple.__hash__):
+ hashvalue = self.__hashvalue
+ if hashvalue is None:
+ self.__hashvalue = hashvalue = hash(self)
+ return hashvalue
+
+ def __add__(self, other, add=tuple.__add__):
+ return _HashedTuple(add(self, other))
+
+ def __radd__(self, other, add=tuple.__add__):
+ return _HashedTuple(add(other, self))
+
+ def __getstate__(self):
+ return {}
+
+
+# A sentinel for separating args from kwargs. Using the class itself
+# ensures uniqueness and preserves identity when pickling/unpickling.
+_kwmark = (_HashedTuple,)
+
+
+def hashkey(*args, **kwargs):
+ """Return a cache key for the specified hashable arguments."""
+
+ if kwargs:
+ return _HashedTuple(args + _kwmark + tuple(sorted(kwargs.items())))
+ else:
+ return _HashedTuple(args)
+
+
+def methodkey(self, *args, **kwargs):
+ """Return a cache key for use with cached methods."""
+ return hashkey(*args, **kwargs)
+
+
+def typedkey(*args, **kwargs):
+ """Return a typed cache key for the specified hashable arguments."""
+
+ if kwargs:
+ sorted_kwargs = tuple(sorted(kwargs.items()))
+ key = _HashedTuple(args + _kwmark + sorted_kwargs)
+ key += tuple(type(v) for _, v in sorted_kwargs)
+ else:
+ key = _HashedTuple(args)
+ key += tuple(type(v) for v in args)
+ return key
+
+
+def typedmethodkey(self, *args, **kwargs):
+ """Return a typed cache key for use with cached methods."""
+ return typedkey(*args, **kwargs)
diff --git a/venv/Lib/site-packages/cachetools/keys.pyi b/venv/Lib/site-packages/cachetools/keys.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..bbc2a80fe347b6119b4dc9b31da6c25776db99bc
--- /dev/null
+++ b/venv/Lib/site-packages/cachetools/keys.pyi
@@ -0,0 +1,14 @@
+from _typeshed import Unused
+from collections.abc import Hashable
+from typing import Final
+
+__all__: Final = ("hashkey", "methodkey", "typedkey", "typedmethodkey")
+
+def hashkey(*args: Hashable, **kwargs: Hashable) -> tuple[Hashable, ...]: ...
+def methodkey(
+ self: Unused, /, *args: Hashable, **kwargs: Hashable
+) -> tuple[Hashable, ...]: ...
+def typedkey(*args: Hashable, **kwargs: Hashable) -> tuple[Hashable, ...]: ...
+def typedmethodkey(
+ self: Unused, /, *args: Hashable, **kwargs: Hashable
+) -> tuple[Hashable, ...]: ...
diff --git a/venv/Lib/site-packages/cachetools/py.typed b/venv/Lib/site-packages/cachetools/py.typed
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/venv/Lib/site-packages/certifi-2026.6.17.dist-info/INSTALLER b/venv/Lib/site-packages/certifi-2026.6.17.dist-info/INSTALLER
new file mode 100644
index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68
--- /dev/null
+++ b/venv/Lib/site-packages/certifi-2026.6.17.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/Lib/site-packages/certifi-2026.6.17.dist-info/licenses/LICENSE b/venv/Lib/site-packages/certifi-2026.6.17.dist-info/licenses/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..62b076cdee58ec8f34034141ba0befd9015b0c7e
--- /dev/null
+++ b/venv/Lib/site-packages/certifi-2026.6.17.dist-info/licenses/LICENSE
@@ -0,0 +1,20 @@
+This package contains a modified version of ca-bundle.crt:
+
+ca-bundle.crt -- Bundle of CA Root Certificates
+
+This is a bundle of X.509 certificates of public Certificate Authorities
+(CA). These were automatically extracted from Mozilla's root certificates
+file (certdata.txt). This file can be found in the mozilla source tree:
+https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt
+It contains the certificates in PEM format and therefore
+can be directly used with curl / libcurl / php_curl, or with
+an Apache+mod_ssl webserver for SSL client authentication.
+Just configure this file as the SSLCACertificateFile.#
+
+***** BEGIN LICENSE BLOCK *****
+This Source Code Form is subject to the terms of the Mozilla Public License,
+v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain
+one at http://mozilla.org/MPL/2.0/.
+
+***** END LICENSE BLOCK *****
+@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $
diff --git a/venv/Lib/site-packages/certifi/__init__.py b/venv/Lib/site-packages/certifi/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..ed9a74b7a0f6de9b21e0f79f4c4799952123a78b
--- /dev/null
+++ b/venv/Lib/site-packages/certifi/__init__.py
@@ -0,0 +1,4 @@
+from .core import contents, where
+
+__all__ = ["contents", "where"]
+__version__ = "2026.06.17"
diff --git a/venv/Lib/site-packages/certifi/__main__.py b/venv/Lib/site-packages/certifi/__main__.py
new file mode 100644
index 0000000000000000000000000000000000000000..8945b5da857f4a7dec2b84f1225f012f6098418c
--- /dev/null
+++ b/venv/Lib/site-packages/certifi/__main__.py
@@ -0,0 +1,12 @@
+import argparse
+
+from certifi import contents, where
+
+parser = argparse.ArgumentParser()
+parser.add_argument("-c", "--contents", action="store_true")
+args = parser.parse_args()
+
+if args.contents:
+ print(contents())
+else:
+ print(where())
diff --git a/venv/Lib/site-packages/certifi/core.py b/venv/Lib/site-packages/certifi/core.py
new file mode 100644
index 0000000000000000000000000000000000000000..1c9661cc7c2f6917c2506a30b2710002f81ab23a
--- /dev/null
+++ b/venv/Lib/site-packages/certifi/core.py
@@ -0,0 +1,83 @@
+"""
+certifi.py
+~~~~~~~~~~
+
+This module returns the installation location of cacert.pem or its contents.
+"""
+import sys
+import atexit
+
+def exit_cacert_ctx() -> None:
+ _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr]
+
+
+if sys.version_info >= (3, 11):
+
+ from importlib.resources import as_file, files
+
+ _CACERT_CTX = None
+ _CACERT_PATH = None
+
+ def where() -> str:
+ # This is slightly terrible, but we want to delay extracting the file
+ # in cases where we're inside of a zipimport situation until someone
+ # actually calls where(), but we don't want to re-extract the file
+ # on every call of where(), so we'll do it once then store it in a
+ # global variable.
+ global _CACERT_CTX
+ global _CACERT_PATH
+ if _CACERT_PATH is None:
+ # This is slightly janky, the importlib.resources API wants you to
+ # manage the cleanup of this file, so it doesn't actually return a
+ # path, it returns a context manager that will give you the path
+ # when you enter it and will do any cleanup when you leave it. In
+ # the common case of not needing a temporary file, it will just
+ # return the file system location and the __exit__() is a no-op.
+ #
+ # We also have to hold onto the actual context manager, because
+ # it will do the cleanup whenever it gets garbage collected, so
+ # we will also store that at the global level as well.
+ _CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem"))
+ _CACERT_PATH = str(_CACERT_CTX.__enter__())
+ atexit.register(exit_cacert_ctx)
+
+ return _CACERT_PATH
+
+ def contents() -> str:
+ return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii")
+
+else:
+
+ from importlib.resources import path as get_path, read_text
+
+ _CACERT_CTX = None
+ _CACERT_PATH = None
+
+ def where() -> str:
+ # This is slightly terrible, but we want to delay extracting the
+ # file in cases where we're inside of a zipimport situation until
+ # someone actually calls where(), but we don't want to re-extract
+ # the file on every call of where(), so we'll do it once then store
+ # it in a global variable.
+ global _CACERT_CTX
+ global _CACERT_PATH
+ if _CACERT_PATH is None:
+ # This is slightly janky, the importlib.resources API wants you
+ # to manage the cleanup of this file, so it doesn't actually
+ # return a path, it returns a context manager that will give
+ # you the path when you enter it and will do any cleanup when
+ # you leave it. In the common case of not needing a temporary
+ # file, it will just return the file system location and the
+ # __exit__() is a no-op.
+ #
+ # We also have to hold onto the actual context manager, because
+ # it will do the cleanup whenever it gets garbage collected, so
+ # we will also store that at the global level as well.
+ _CACERT_CTX = get_path("certifi", "cacert.pem")
+ _CACERT_PATH = str(_CACERT_CTX.__enter__())
+ atexit.register(exit_cacert_ctx)
+
+ return _CACERT_PATH
+
+ def contents() -> str:
+ return read_text("certifi", "cacert.pem", encoding="ascii")
diff --git a/venv/Lib/site-packages/certifi/py.typed b/venv/Lib/site-packages/certifi/py.typed
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391