rply-stubs 0.1.0.0.7.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rply_stubs-0.1.0.0.7.8/LICENSE +21 -0
- rply_stubs-0.1.0.0.7.8/PKG-INFO +74 -0
- rply_stubs-0.1.0.0.7.8/README.md +47 -0
- rply_stubs-0.1.0.0.7.8/main.py +6 -0
- rply_stubs-0.1.0.0.7.8/pyproject.toml +60 -0
- rply_stubs-0.1.0.0.7.8/rply-stubs/__init__.pyi +14 -0
- rply_stubs-0.1.0.0.7.8/rply-stubs/errors.pyi +23 -0
- rply_stubs-0.1.0.0.7.8/rply-stubs/grammar.pyi +90 -0
- rply_stubs-0.1.0.0.7.8/rply-stubs/lexer.pyi +24 -0
- rply_stubs-0.1.0.0.7.8/rply-stubs/lexergenerator.pyi +28 -0
- rply_stubs-0.1.0.0.7.8/rply-stubs/parser.pyi +17 -0
- rply_stubs-0.1.0.0.7.8/rply-stubs/parsergenerator.pyi +295 -0
- rply_stubs-0.1.0.0.7.8/rply-stubs/py.typed +0 -0
- rply_stubs-0.1.0.0.7.8/rply-stubs/token.pyi +27 -0
- rply_stubs-0.1.0.0.7.8/rply-stubs/utils.pyi +35 -0
- rply_stubs-0.1.0.0.7.8/rply_stubs.egg-info/PKG-INFO +74 -0
- rply_stubs-0.1.0.0.7.8/rply_stubs.egg-info/SOURCES.txt +19 -0
- rply_stubs-0.1.0.0.7.8/rply_stubs.egg-info/dependency_links.txt +1 -0
- rply_stubs-0.1.0.0.7.8/rply_stubs.egg-info/requires.txt +1 -0
- rply_stubs-0.1.0.0.7.8/rply_stubs.egg-info/top_level.txt +2 -0
- rply_stubs-0.1.0.0.7.8/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Summersweet Software
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rply-stubs
|
|
3
|
+
Version: 0.1.0.0.7.8
|
|
4
|
+
Summary: A stubs library for RPLY
|
|
5
|
+
Author: ArachnidAbby, Summersweet-Software
|
|
6
|
+
License: MIT-only
|
|
7
|
+
Project-URL: Homepage, https://summersweet.software
|
|
8
|
+
Project-URL: Repository, https://github.com/summersweet-software/rply-stubs
|
|
9
|
+
Project-URL: Issues, https://github.com/summersweet-software/rply-stubs/issues
|
|
10
|
+
Keywords: stubs,typed,typing,rply,lexer generator,parser generator,lexer,parser,mypy,pyi,stubs only
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Natural Language :: English
|
|
21
|
+
Classifier: Typing :: Stubs Only
|
|
22
|
+
Requires-Python: >=3.12
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: rply==0.7.8
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# RPLY Stubs
|
|
29
|
+
|
|
30
|
+
A stubs library for [RPLY](https://pypi.org/project/rply/)
|
|
31
|
+
|
|
32
|
+
# Correctness
|
|
33
|
+
|
|
34
|
+
This is an independent static analysis of the types being used. This is not the easiest task in a codebase so unmaintained and old (not to say that RPLY doesn't set out to accomplish all that it needs to. It is a well written and complete library from the way I see it.).
|
|
35
|
+
|
|
36
|
+
This is all to say that the type annotations provided are not always correct but provide a firm guideline in an otherwise untyped library.
|
|
37
|
+
|
|
38
|
+
# Completeness
|
|
39
|
+
|
|
40
|
+
| symbol | meaning |
|
|
41
|
+
| ------ | ------------- |
|
|
42
|
+
| ⚪ | partial |
|
|
43
|
+
| ❌ | Not worked on |
|
|
44
|
+
| ✅ | completed |
|
|
45
|
+
|
|
46
|
+
| Module | Status |
|
|
47
|
+
| --------------- | :----: |
|
|
48
|
+
| errors | ✅ |
|
|
49
|
+
| grammar | ⚪ |
|
|
50
|
+
| lexer | ✅ |
|
|
51
|
+
| lexergenerator | ✅ |
|
|
52
|
+
| parser | ✅ |
|
|
53
|
+
| parsergenerator | ⚪ |
|
|
54
|
+
| token | ✅ |
|
|
55
|
+
| utils | ✅ |
|
|
56
|
+
|
|
57
|
+
# Difficulties In Completion
|
|
58
|
+
|
|
59
|
+
This stubs library is made significantly more difficult to complete due to the fact that single-letter naming conventions are used in several places without explanation or comment in to what each variable means.
|
|
60
|
+
For example:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# rply/parsergenerator.py
|
|
64
|
+
def traverse(x, N, stack, F, X, R, FP):
|
|
65
|
+
...
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
It is clear that `stack` is some kind of list but what are `x`, `N`, `F`, `X`, `R`, and `FP`?
|
|
69
|
+
|
|
70
|
+
FP could be a function pointer? But that is just an educated guess.
|
|
71
|
+
|
|
72
|
+
Many such examples exist in the codebase and are hard to descern. That is also not mentioning the large amount of compounding types with signatures such as `list[dict[tuple[int, str], list[dict[...]]]]`. This is extremely hard to annotate or understand the individual parts of.
|
|
73
|
+
|
|
74
|
+
Most of the examples come from the `parsergenerator` module which I will personally say is not very readable. I would love if the library author could provide some assistance.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# RPLY Stubs
|
|
2
|
+
|
|
3
|
+
A stubs library for [RPLY](https://pypi.org/project/rply/)
|
|
4
|
+
|
|
5
|
+
# Correctness
|
|
6
|
+
|
|
7
|
+
This is an independent static analysis of the types being used. This is not the easiest task in a codebase so unmaintained and old (not to say that RPLY doesn't set out to accomplish all that it needs to. It is a well written and complete library from the way I see it.).
|
|
8
|
+
|
|
9
|
+
This is all to say that the type annotations provided are not always correct but provide a firm guideline in an otherwise untyped library.
|
|
10
|
+
|
|
11
|
+
# Completeness
|
|
12
|
+
|
|
13
|
+
| symbol | meaning |
|
|
14
|
+
| ------ | ------------- |
|
|
15
|
+
| ⚪ | partial |
|
|
16
|
+
| ❌ | Not worked on |
|
|
17
|
+
| ✅ | completed |
|
|
18
|
+
|
|
19
|
+
| Module | Status |
|
|
20
|
+
| --------------- | :----: |
|
|
21
|
+
| errors | ✅ |
|
|
22
|
+
| grammar | ⚪ |
|
|
23
|
+
| lexer | ✅ |
|
|
24
|
+
| lexergenerator | ✅ |
|
|
25
|
+
| parser | ✅ |
|
|
26
|
+
| parsergenerator | ⚪ |
|
|
27
|
+
| token | ✅ |
|
|
28
|
+
| utils | ✅ |
|
|
29
|
+
|
|
30
|
+
# Difficulties In Completion
|
|
31
|
+
|
|
32
|
+
This stubs library is made significantly more difficult to complete due to the fact that single-letter naming conventions are used in several places without explanation or comment in to what each variable means.
|
|
33
|
+
For example:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
# rply/parsergenerator.py
|
|
37
|
+
def traverse(x, N, stack, F, X, R, FP):
|
|
38
|
+
...
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
It is clear that `stack` is some kind of list but what are `x`, `N`, `F`, `X`, `R`, and `FP`?
|
|
42
|
+
|
|
43
|
+
FP could be a function pointer? But that is just an educated guess.
|
|
44
|
+
|
|
45
|
+
Many such examples exist in the codebase and are hard to descern. That is also not mentioning the large amount of compounding types with signatures such as `list[dict[tuple[int, str], list[dict[...]]]]`. This is extremely hard to annotate or understand the individual parts of.
|
|
46
|
+
|
|
47
|
+
Most of the examples come from the `parsergenerator` module which I will personally say is not very readable. I would love if the library author could provide some assistance.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "rply-stubs"
|
|
3
|
+
version = "0.1.0.0.7.8"
|
|
4
|
+
description = "A stubs library for RPLY"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12" # new Generics syntax used.
|
|
7
|
+
dependencies = ["rply==0.7.8"]
|
|
8
|
+
authors = [{ name = "ArachnidAbby" }, { name = "Summersweet-Software" }]
|
|
9
|
+
|
|
10
|
+
license = { text = "MIT-only" }
|
|
11
|
+
keywords = [
|
|
12
|
+
"stubs",
|
|
13
|
+
"typed",
|
|
14
|
+
"typing",
|
|
15
|
+
"rply",
|
|
16
|
+
"lexer generator",
|
|
17
|
+
"parser generator",
|
|
18
|
+
"lexer",
|
|
19
|
+
"parser",
|
|
20
|
+
"mypy",
|
|
21
|
+
"pyi",
|
|
22
|
+
"stubs only",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
classifiers = [
|
|
26
|
+
# How mature is this project? Common values are
|
|
27
|
+
# 3 - Alpha
|
|
28
|
+
# 4 - Beta
|
|
29
|
+
# 5 - Production/Stable
|
|
30
|
+
"Development Status :: 4 - Beta",
|
|
31
|
+
|
|
32
|
+
# Indicate who your project is intended for
|
|
33
|
+
"Intended Audience :: Developers",
|
|
34
|
+
# topic
|
|
35
|
+
"Topic :: Software Development :: Libraries",
|
|
36
|
+
|
|
37
|
+
# Specify the Python versions you support here.
|
|
38
|
+
"Programming Language :: Python :: 3",
|
|
39
|
+
"Programming Language :: Python :: 3.12",
|
|
40
|
+
"Programming Language :: Python :: 3.13",
|
|
41
|
+
"Programming Language :: Python :: 3.14",
|
|
42
|
+
# Licensing
|
|
43
|
+
"License :: OSI Approved :: MIT License",
|
|
44
|
+
# OS
|
|
45
|
+
"Operating System :: OS Independent",
|
|
46
|
+
# other
|
|
47
|
+
"Natural Language :: English",
|
|
48
|
+
"Typing :: Stubs Only",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[project.urls]
|
|
52
|
+
Homepage = "https://summersweet.software"
|
|
53
|
+
Repository = "https://github.com/summersweet-software/rply-stubs"
|
|
54
|
+
Issues = "https://github.com/summersweet-software/rply-stubs/issues"
|
|
55
|
+
|
|
56
|
+
[[tool.uv.index]]
|
|
57
|
+
name = "testpypi"
|
|
58
|
+
url = "https://test.pypi.org/simple/"
|
|
59
|
+
publish-url = "https://test.pypi.org/legacy/"
|
|
60
|
+
explicit = true
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .token import Token
|
|
2
|
+
from . import lexer
|
|
3
|
+
from . import lexergenerator
|
|
4
|
+
from .lexergenerator import LexerGenerator
|
|
5
|
+
from .errors import LexingError, ParsingError
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"Token",
|
|
9
|
+
"lexer",
|
|
10
|
+
"lexergenerator",
|
|
11
|
+
"LexerGenerator",
|
|
12
|
+
"LexingError",
|
|
13
|
+
"ParsingError",
|
|
14
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from rply.token import SourcePosition
|
|
2
|
+
|
|
3
|
+
class ParserGeneratorError(Exception):
|
|
4
|
+
pass
|
|
5
|
+
|
|
6
|
+
class LexingError(Exception):
|
|
7
|
+
message: str
|
|
8
|
+
source_pos: SourcePosition
|
|
9
|
+
|
|
10
|
+
def __init__(self, message: str, source_pos: SourcePosition): ...
|
|
11
|
+
def getsourcepos(self) -> SourcePosition: ...
|
|
12
|
+
def __repr__(self) -> str: ...
|
|
13
|
+
|
|
14
|
+
class ParsingError(Exception):
|
|
15
|
+
message: str
|
|
16
|
+
source_pos: SourcePosition
|
|
17
|
+
|
|
18
|
+
def __init__(self, message: str, source_pos: SourcePosition): ...
|
|
19
|
+
def getsourcepos(self) -> SourcePosition: ...
|
|
20
|
+
def __repr__(self) -> str: ...
|
|
21
|
+
|
|
22
|
+
class ParserGeneratorWarning(Warning):
|
|
23
|
+
pass
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from typing import Callable, Literal, Never
|
|
2
|
+
|
|
3
|
+
def rightmost_terminal(
|
|
4
|
+
symbols: list[str], terminals: dict[str, list[int]]
|
|
5
|
+
) -> str | None: ...
|
|
6
|
+
|
|
7
|
+
type PrecedenceAssociativity = Literal["left"] | Literal["right"] | Literal["nonassoc"]
|
|
8
|
+
type PrecedenceTuple = tuple[PrecedenceAssociativity, int]
|
|
9
|
+
|
|
10
|
+
type ProductionFunction = Callable
|
|
11
|
+
|
|
12
|
+
class Grammar(object):
|
|
13
|
+
productions: list["None | Production"]
|
|
14
|
+
prod_names: dict[str, list["Production"]]
|
|
15
|
+
terminals: dict[str, list[int]]
|
|
16
|
+
|
|
17
|
+
nonterminals: dict[str, list[int]]
|
|
18
|
+
first: dict[str, list[str]]
|
|
19
|
+
follow: dict[str | None, list[str]]
|
|
20
|
+
precedence: dict[str | None, PrecedenceTuple]
|
|
21
|
+
start: str | None
|
|
22
|
+
|
|
23
|
+
def __init__(self, terminals: list[str]): ...
|
|
24
|
+
def add_production(
|
|
25
|
+
self,
|
|
26
|
+
prod_name: str,
|
|
27
|
+
syms: list[str],
|
|
28
|
+
func: ProductionFunction,
|
|
29
|
+
precedence: str | None,
|
|
30
|
+
) -> None | Never: ...
|
|
31
|
+
def set_precedence(
|
|
32
|
+
self, term: str, assoc: PrecedenceAssociativity, level: int
|
|
33
|
+
) -> None | Never: ...
|
|
34
|
+
def set_start(self) -> None: ...
|
|
35
|
+
def unused_terminals(self) -> list[str]: ...
|
|
36
|
+
def unused_productions(self) -> list[str]: ...
|
|
37
|
+
def build_lritems(self) -> None: ...
|
|
38
|
+
def _first(self, beta: str) -> list[str]: ...
|
|
39
|
+
def compute_first(self) -> None: ...
|
|
40
|
+
def compute_follow(self) -> None: ...
|
|
41
|
+
|
|
42
|
+
class Production(object):
|
|
43
|
+
number: int
|
|
44
|
+
name: str
|
|
45
|
+
prod: list[str]
|
|
46
|
+
func: ProductionFunction | None
|
|
47
|
+
prec: PrecedenceTuple
|
|
48
|
+
unique_syms: list[str]
|
|
49
|
+
|
|
50
|
+
lr_items: list["LRItem | None"]
|
|
51
|
+
lr_next: "LRItem | None"
|
|
52
|
+
lr0_added: int
|
|
53
|
+
reduced: int
|
|
54
|
+
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
num: int,
|
|
58
|
+
name: str,
|
|
59
|
+
prod: list[str],
|
|
60
|
+
precedence: PrecedenceTuple,
|
|
61
|
+
func: ProductionFunction | None,
|
|
62
|
+
): ...
|
|
63
|
+
def __repr__(self) -> str: ...
|
|
64
|
+
def getlength(self) -> int: ...
|
|
65
|
+
|
|
66
|
+
class LRItem(object):
|
|
67
|
+
name: str
|
|
68
|
+
prod: list[str]
|
|
69
|
+
number: int
|
|
70
|
+
lr_index: int
|
|
71
|
+
lookaheads: dict[Unknown, list[Unknown]]
|
|
72
|
+
unique_syms: list[str]
|
|
73
|
+
lr_before: str | None
|
|
74
|
+
lr_after: list[Production]
|
|
75
|
+
|
|
76
|
+
def __init__(
|
|
77
|
+
self, p: Production, n: int, before: str | None, after: list[Production]
|
|
78
|
+
):
|
|
79
|
+
self.name = p.name
|
|
80
|
+
self.prod = p.prod[:]
|
|
81
|
+
self.prod.insert(n, ".")
|
|
82
|
+
self.number = p.number
|
|
83
|
+
self.lr_index = n
|
|
84
|
+
self.lookaheads = {}
|
|
85
|
+
self.unique_syms = p.unique_syms
|
|
86
|
+
self.lr_before = before
|
|
87
|
+
self.lr_after = after
|
|
88
|
+
|
|
89
|
+
def __repr__(self) -> str: ...
|
|
90
|
+
def getlength(self) -> int: ...
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from typing import Self
|
|
2
|
+
from .token import Token
|
|
3
|
+
from .lexergenerator import Rule, Match
|
|
4
|
+
|
|
5
|
+
class Lexer(object):
|
|
6
|
+
rules: list[Rule]
|
|
7
|
+
ignore_rules: list[Rule]
|
|
8
|
+
|
|
9
|
+
def __init__(self, rules: list[Rule], ignore_rules: list[Rule]): ...
|
|
10
|
+
def lex(self, s: str) -> "LexerStream": ...
|
|
11
|
+
|
|
12
|
+
class LexerStream(object):
|
|
13
|
+
lexer: Lexer
|
|
14
|
+
s: str
|
|
15
|
+
idx: int
|
|
16
|
+
|
|
17
|
+
_lineno: int
|
|
18
|
+
_colno: int
|
|
19
|
+
|
|
20
|
+
def __init__(self, lexer: Lexer, s: str): ...
|
|
21
|
+
def __iter__(self) -> Self: ...
|
|
22
|
+
def _update_pos(self, match: Match) -> int: ...
|
|
23
|
+
def next(self) -> Token: ...
|
|
24
|
+
def __next__(self) -> Token: ...
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from .lexer import Lexer
|
|
3
|
+
from .token import SourcePosition
|
|
4
|
+
|
|
5
|
+
class Rule[N: str](object):
|
|
6
|
+
_attrs_ = ["name", "flags", "_pattern"]
|
|
7
|
+
name: N
|
|
8
|
+
pattern: str
|
|
9
|
+
flags: int
|
|
10
|
+
|
|
11
|
+
def __init__(self, name: N, pattern: str, flags=0): ...
|
|
12
|
+
def _freeze_(self) -> bool: ...
|
|
13
|
+
def matches(self, s: str, pos: SourcePosition): ...
|
|
14
|
+
|
|
15
|
+
class Match(object):
|
|
16
|
+
start: int
|
|
17
|
+
end: int
|
|
18
|
+
|
|
19
|
+
def __init__(self, start: int, end: int): ...
|
|
20
|
+
|
|
21
|
+
class LexerGenerator(object):
|
|
22
|
+
rules: list[Rule]
|
|
23
|
+
ignore_rules: list[Rule]
|
|
24
|
+
|
|
25
|
+
def __init__(self): ...
|
|
26
|
+
def add(self, name: str | Any, pattern: str, flags: int = 0): ...
|
|
27
|
+
def ignore(self, pattern: str, flags: int = 0): ...
|
|
28
|
+
def build(self) -> Lexer: ...
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Callable, Never
|
|
2
|
+
|
|
3
|
+
from rply.lexer import LexerStream
|
|
4
|
+
from rply.parsergenerator import LRTable
|
|
5
|
+
from rply.token import Token
|
|
6
|
+
|
|
7
|
+
class LRParser(object):
|
|
8
|
+
lr_table: LRTable
|
|
9
|
+
error_handler: Callable
|
|
10
|
+
|
|
11
|
+
def __init__(self, lr_table: LRTable, error_handler: Callable): ...
|
|
12
|
+
def parse(
|
|
13
|
+
self, tokenizer: LexerStream, state: int | None = None
|
|
14
|
+
) -> Token | Never: ...
|
|
15
|
+
def _reduce_production(
|
|
16
|
+
self, t, symstack: list[Token], statestack: list[int], state: int | None
|
|
17
|
+
) -> int: ...
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Callable, Final, Literal, Never, TypedDict
|
|
3
|
+
|
|
4
|
+
from .grammar import LRItem, PrecedenceTuple, PrecedenceAssociativity
|
|
5
|
+
from rply.grammar import Grammar
|
|
6
|
+
from rply.parser import LRParser
|
|
7
|
+
|
|
8
|
+
from rply.token import Token
|
|
9
|
+
|
|
10
|
+
LARGE_VALUE = sys.maxsize
|
|
11
|
+
|
|
12
|
+
type ProductionParts = tuple[
|
|
13
|
+
str, list[str], Callable, tuple[PrecedenceAssociativity, list[str]] | None
|
|
14
|
+
]
|
|
15
|
+
type Transition = list[tuple[int, LRItem]]
|
|
16
|
+
type LookBacks = dict[tuple[int, LRItem], list[tuple[int, list]]]
|
|
17
|
+
|
|
18
|
+
class SerializedLRTable(TypedDict):
|
|
19
|
+
lr_action: list[dict[str, int]]
|
|
20
|
+
lr_goto: list[dict[str, int]]
|
|
21
|
+
sr_conflicts: list[
|
|
22
|
+
tuple[int, str, Literal["reduce"] | Literal["nonassoc"] | Literal["shift"]]
|
|
23
|
+
]
|
|
24
|
+
rr_conflicts: list[tuple[int, str, str]]
|
|
25
|
+
default_reductions: list[int]
|
|
26
|
+
start: str | None
|
|
27
|
+
terminals: list[str]
|
|
28
|
+
precedence: dict[str | None, PrecedenceTuple]
|
|
29
|
+
productions: list[tuple[str, list[str], PrecedenceTuple]]
|
|
30
|
+
|
|
31
|
+
class ParserGenerator(object):
|
|
32
|
+
|
|
33
|
+
VERSION: Final[int]
|
|
34
|
+
|
|
35
|
+
tokens: list[Token]
|
|
36
|
+
productions: list[ProductionParts]
|
|
37
|
+
precedence: list[tuple[PrecedenceAssociativity, list[str]]]
|
|
38
|
+
cache_id: None | str
|
|
39
|
+
error_handler: None | Callable
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
tokens: list[Token],
|
|
44
|
+
precedence: list[tuple[PrecedenceAssociativity, list[str]]] = [],
|
|
45
|
+
cache_id: str | None = None,
|
|
46
|
+
): ...
|
|
47
|
+
def production(
|
|
48
|
+
self,
|
|
49
|
+
rule: str,
|
|
50
|
+
precedence: tuple[PrecedenceAssociativity, list[str]] | None = None,
|
|
51
|
+
): ...
|
|
52
|
+
def error(self, func: Callable) -> Callable: ...
|
|
53
|
+
def compute_grammar_hash(self, g: Grammar) -> str: ...
|
|
54
|
+
def serialize_table(self, table: "LRTable") -> SerializedLRTable: ...
|
|
55
|
+
def data_is_valid(self, g: Grammar, data: SerializedLRTable) -> bool: ...
|
|
56
|
+
def build(self) -> LRParser: ...
|
|
57
|
+
def _write_cache(
|
|
58
|
+
self, cache_dir: str, cache_file: str, table: LRTable
|
|
59
|
+
) -> None | Never: ...
|
|
60
|
+
|
|
61
|
+
# TODO
|
|
62
|
+
|
|
63
|
+
# def traverse(x, N, stack: list, F, X, R, FP):
|
|
64
|
+
# stack.append(x)
|
|
65
|
+
# d = len(stack)
|
|
66
|
+
# N[x] = d
|
|
67
|
+
# F[x] = FP(x)
|
|
68
|
+
|
|
69
|
+
# rel = R(x)
|
|
70
|
+
# for y in rel:
|
|
71
|
+
# if N[y] == 0:
|
|
72
|
+
# traverse(y, N, stack, F, X, R, FP)
|
|
73
|
+
# N[x] = min(N[x], N[y])
|
|
74
|
+
# for a in F.get(y, []):
|
|
75
|
+
# if a not in F[x]:
|
|
76
|
+
# F[x].append(a)
|
|
77
|
+
# if N[x] == d:
|
|
78
|
+
# N[stack[-1]] = LARGE_VALUE
|
|
79
|
+
# F[stack[-1]] = F[x]
|
|
80
|
+
# element = stack.pop()
|
|
81
|
+
# while element != x:
|
|
82
|
+
# N[stack[-1]] = LARGE_VALUE
|
|
83
|
+
# F[stack[-1]] = F[x]
|
|
84
|
+
# element = stack.pop()
|
|
85
|
+
|
|
86
|
+
class LRTable(object):
|
|
87
|
+
grammar: Grammar
|
|
88
|
+
lr_action: list[dict[str, int]]
|
|
89
|
+
lr_goto: list[dict[str, int]]
|
|
90
|
+
default_reductions: list[int]
|
|
91
|
+
sr_conflicts: list[
|
|
92
|
+
tuple[int, str, Literal["reduce"] | Literal["nonassoc"] | Literal["shift"]]
|
|
93
|
+
]
|
|
94
|
+
rr_conflicts: list[tuple[int, str, str]]
|
|
95
|
+
|
|
96
|
+
def __init__(
|
|
97
|
+
self,
|
|
98
|
+
grammar: Grammar,
|
|
99
|
+
lr_action: list[dict[str, int]],
|
|
100
|
+
lr_goto: list[dict[str, int]],
|
|
101
|
+
default_reductions: list[int],
|
|
102
|
+
sr_conflicts: list[
|
|
103
|
+
tuple[int, str, Literal["reduce"] | Literal["nonassoc"] | Literal["shift"]]
|
|
104
|
+
],
|
|
105
|
+
rr_conflicts: list[tuple[int, str, str]],
|
|
106
|
+
): ...
|
|
107
|
+
@classmethod
|
|
108
|
+
def from_cache(cls, grammar: Grammar, data: SerializedLRTable) -> "LRTable": ...
|
|
109
|
+
@classmethod
|
|
110
|
+
def from_grammar(cls, grammar: Grammar) -> LRTable | Never: ...
|
|
111
|
+
|
|
112
|
+
# TODO
|
|
113
|
+
# @classmethod
|
|
114
|
+
# def lr0_items(cls, grammar: Grammar, add_count: Counter, cidhash: IdentityDict, goto_cache: GotoCache) -> list[list[LRItem]]:
|
|
115
|
+
# C = [cls.lr0_closure([grammar.productions[0].lr_next], add_count)]
|
|
116
|
+
# for i, I in enumerate(C):
|
|
117
|
+
# cidhash[I] = i
|
|
118
|
+
|
|
119
|
+
# i = 0
|
|
120
|
+
# while i < len(C):
|
|
121
|
+
# I = C[i]
|
|
122
|
+
# i += 1
|
|
123
|
+
|
|
124
|
+
# asyms = set()
|
|
125
|
+
# for ii in I:
|
|
126
|
+
# asyms.update(ii.unique_syms)
|
|
127
|
+
# for x in asyms:
|
|
128
|
+
# g = cls.lr0_goto(I, x, add_count, goto_cache)
|
|
129
|
+
# if not g:
|
|
130
|
+
# continue
|
|
131
|
+
# if g in cidhash:
|
|
132
|
+
# continue
|
|
133
|
+
# cidhash[g] = len(C)
|
|
134
|
+
# C.append(g)
|
|
135
|
+
# return C
|
|
136
|
+
|
|
137
|
+
# @classmethod
|
|
138
|
+
# def lr0_closure(cls, I: list[LRItem], add_count: Counter) -> list[LRItem]:
|
|
139
|
+
# add_count.incr()
|
|
140
|
+
|
|
141
|
+
# J = I[:]
|
|
142
|
+
# added = True
|
|
143
|
+
# while added:
|
|
144
|
+
# added = False
|
|
145
|
+
# for j in J:
|
|
146
|
+
# for x in j.lr_after:
|
|
147
|
+
# if x.lr0_added == add_count.value:
|
|
148
|
+
# continue
|
|
149
|
+
# J.append(x.lr_next)
|
|
150
|
+
# x.lr0_added = add_count.value
|
|
151
|
+
# added = True
|
|
152
|
+
# return J
|
|
153
|
+
|
|
154
|
+
# @classmethod
|
|
155
|
+
# def lr0_goto(cls, I: Sequence[Production], x: str, add_count: Counter, goto_cache: GotoCache) -> ...:
|
|
156
|
+
# s = goto_cache.setdefault(x, IdentityDict())
|
|
157
|
+
|
|
158
|
+
# gs = []
|
|
159
|
+
# for p in I:
|
|
160
|
+
# n = p.lr_next
|
|
161
|
+
# if n and n.lr_before == x:
|
|
162
|
+
# s1 = s.get(n)
|
|
163
|
+
# if not s1:
|
|
164
|
+
# s1 = {}
|
|
165
|
+
# s[n] = s1
|
|
166
|
+
# gs.append(n)
|
|
167
|
+
# s = s1
|
|
168
|
+
# g = s.get("$end")
|
|
169
|
+
# if not g:
|
|
170
|
+
# if gs:
|
|
171
|
+
# g = cls.lr0_closure(gs, add_count)
|
|
172
|
+
# s["$end"] = g
|
|
173
|
+
# else:
|
|
174
|
+
# s["$end"] = gs
|
|
175
|
+
# return g
|
|
176
|
+
|
|
177
|
+
# @classmethod
|
|
178
|
+
# def add_lalr_lookaheads(cls, grammar: Grammar, C: list[list[LRItem]], add_count: Counter, cidhash, goto_cache: GotoCache):
|
|
179
|
+
# nullable = cls.compute_nullable_nonterminals(grammar)
|
|
180
|
+
# trans = cls.find_nonterminal_transitions(grammar, C)
|
|
181
|
+
# readsets = cls.compute_read_sets(grammar, C, trans, nullable, add_count, cidhash, goto_cache)
|
|
182
|
+
# lookd, included = cls.compute_lookback_includes(grammar, C, trans, nullable, add_count, cidhash, goto_cache)
|
|
183
|
+
# followsets = cls.compute_follow_sets(trans, readsets, included)
|
|
184
|
+
# cls.add_lookaheads(lookd, followsets)
|
|
185
|
+
|
|
186
|
+
# @classmethod
|
|
187
|
+
# def compute_nullable_nonterminals(cls, grammar: Grammar) -> set[str]:
|
|
188
|
+
# ...
|
|
189
|
+
|
|
190
|
+
# @classmethod
|
|
191
|
+
# def find_nonterminal_transitions(cls, grammar: Grammar, C: list[list[LRItem]]) -> Transition:
|
|
192
|
+
# trans = []
|
|
193
|
+
# for idx, state in enumerate(C):
|
|
194
|
+
# for p in state:
|
|
195
|
+
# if p.lr_index < p.getlength() - 1:
|
|
196
|
+
# t = (idx, p.prod[p.lr_index + 1])
|
|
197
|
+
# if t[1] in grammar.nonterminals and t not in trans:
|
|
198
|
+
# trans.append(t)
|
|
199
|
+
# return trans
|
|
200
|
+
|
|
201
|
+
# @classmethod
|
|
202
|
+
# def compute_read_sets(cls, grammar: Grammar, C: list[list[LRItem]], ntrans, nullable, add_count: Counter, cidhash, goto_cache: GotoCache):
|
|
203
|
+
# return digraph(
|
|
204
|
+
# ntrans,
|
|
205
|
+
# R=lambda x: cls.reads_relation(C, x, nullable, add_count, cidhash, goto_cache),
|
|
206
|
+
# FP=lambda x: cls.dr_relation(grammar, C, x, nullable, add_count, goto_cache)
|
|
207
|
+
# )
|
|
208
|
+
|
|
209
|
+
# @classmethod
|
|
210
|
+
# def compute_follow_sets(cls, ntrans, readsets, includesets):
|
|
211
|
+
# return digraph(
|
|
212
|
+
# ntrans,
|
|
213
|
+
# R=lambda x: includesets.get(x, []),
|
|
214
|
+
# FP=lambda x: readsets[x],
|
|
215
|
+
# )
|
|
216
|
+
|
|
217
|
+
# @classmethod
|
|
218
|
+
# def dr_relation(cls, grammar: Grammar, C: list[list[Production]], trans: tuple[int, str], nullable: set[str], add_count: Counter, goto_cache: GotoCache) -> list[str]:
|
|
219
|
+
# ...
|
|
220
|
+
|
|
221
|
+
# @classmethod
|
|
222
|
+
# def reads_relation(cls, C, trans: Transition, empty, add_count: Counter, cidhash: IdentityDict, goto_cache: GotoCache) -> list[tuple[int, str]]:
|
|
223
|
+
# rel = []
|
|
224
|
+
# state, N = trans
|
|
225
|
+
|
|
226
|
+
# g = cls.lr0_goto(C[state], N, add_count, goto_cache)
|
|
227
|
+
# j = cidhash.get(g, -1)
|
|
228
|
+
# for p in g:
|
|
229
|
+
# if p.lr_index < p.getlength() - 1:
|
|
230
|
+
# a = p.prod[p.lr_index + 1]
|
|
231
|
+
# if a in empty:
|
|
232
|
+
# rel.append((j, a))
|
|
233
|
+
# return rel
|
|
234
|
+
|
|
235
|
+
# @classmethod
|
|
236
|
+
# def compute_lookback_includes(cls, grammar: Grammar, C, trans: Transition, nullable: set[str], add_count: Counter, cidhash: IdentityDict, goto_cache: GotoCache) -> tuple[dict[tuple[int, LRItem], LookBacks], dict[...,...]]:
|
|
237
|
+
# lookdict = {}
|
|
238
|
+
# includedict = {}
|
|
239
|
+
|
|
240
|
+
# dtrans = dict.fromkeys(trans, 1)
|
|
241
|
+
|
|
242
|
+
# for state, N in trans:
|
|
243
|
+
# lookb = []
|
|
244
|
+
# includes = []
|
|
245
|
+
# for p in C[state]:
|
|
246
|
+
# if p.name != N:
|
|
247
|
+
# continue
|
|
248
|
+
|
|
249
|
+
# lr_index = p.lr_index
|
|
250
|
+
# j = state
|
|
251
|
+
# while lr_index < p.getlength() - 1:
|
|
252
|
+
# lr_index += 1
|
|
253
|
+
# t = p.prod[lr_index]
|
|
254
|
+
|
|
255
|
+
# if (j, t) in dtrans:
|
|
256
|
+
# li = lr_index + 1
|
|
257
|
+
# while li < p.getlength():
|
|
258
|
+
# if p.prod[li] in grammar.terminals:
|
|
259
|
+
# break
|
|
260
|
+
# if p.prod[li] not in nullable:
|
|
261
|
+
# break
|
|
262
|
+
# li += 1
|
|
263
|
+
# else:
|
|
264
|
+
# includes.append((j, t))
|
|
265
|
+
|
|
266
|
+
# g = cls.lr0_goto(C[j], t, add_count, goto_cache)
|
|
267
|
+
# j = cidhash.get(g, -1)
|
|
268
|
+
|
|
269
|
+
# for r in C[j]:
|
|
270
|
+
# if r.name != p.name:
|
|
271
|
+
# continue
|
|
272
|
+
# if r.getlength() != p.getlength():
|
|
273
|
+
# continue
|
|
274
|
+
# i = 0
|
|
275
|
+
# while i < r.lr_index:
|
|
276
|
+
# if r.prod[i] != p.prod[i + 1]:
|
|
277
|
+
# break
|
|
278
|
+
# i += 1
|
|
279
|
+
# else:
|
|
280
|
+
# lookb.append((j, r))
|
|
281
|
+
|
|
282
|
+
# for i in includes:
|
|
283
|
+
# includedict.setdefault(i, []).append((state, N))
|
|
284
|
+
# lookdict[state, N] = lookb
|
|
285
|
+
# return lookdict, includedict
|
|
286
|
+
|
|
287
|
+
# @classmethod
|
|
288
|
+
# def add_lookaheads(cls, lookbacks: dict[Transition, LookBacks], followset: dict[Transition, list[tuple[int, list[...]]]]):
|
|
289
|
+
# for trans, lb in iteritems(lookbacks):
|
|
290
|
+
# for state, p in lb:
|
|
291
|
+
# f = followset.get(trans, [])
|
|
292
|
+
# laheads = p.lookaheads.setdefault(state, [])
|
|
293
|
+
# for a in f:
|
|
294
|
+
# if a not in laheads:
|
|
295
|
+
# laheads.append(a)
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from typing import Any, Never, Self, overload
|
|
2
|
+
|
|
3
|
+
class BaseBox(object):
|
|
4
|
+
_attrs_: list[str] = []
|
|
5
|
+
|
|
6
|
+
class SourcePosition(object):
|
|
7
|
+
idx: int
|
|
8
|
+
lineno: int
|
|
9
|
+
colno: int
|
|
10
|
+
|
|
11
|
+
def __init__(self, idx: int, lineno: int, colno: int): ...
|
|
12
|
+
def __repr__(self) -> str: ...
|
|
13
|
+
|
|
14
|
+
class Token[N: str, V](BaseBox):
|
|
15
|
+
name: N
|
|
16
|
+
value: V
|
|
17
|
+
source_pos: SourcePosition | None
|
|
18
|
+
|
|
19
|
+
def __init__(self, name: N, value: V, source_pos=None): ...
|
|
20
|
+
def __repr__(self) -> str: ...
|
|
21
|
+
@overload
|
|
22
|
+
def __eq__(self, other: Self) -> bool: ...
|
|
23
|
+
@overload
|
|
24
|
+
def __eq__(self, other: Any) -> Never: ...
|
|
25
|
+
def gettokentype(self) -> N: ...
|
|
26
|
+
def getsourcepos(self) -> SourcePosition: ...
|
|
27
|
+
def getstr(self) -> N: ...
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Generator, ItemsView, ValuesView
|
|
3
|
+
|
|
4
|
+
if sys.version_info >= (3, 3):
|
|
5
|
+
from collections.abc import MutableMapping
|
|
6
|
+
else:
|
|
7
|
+
from collections import MutableMapping
|
|
8
|
+
|
|
9
|
+
class IdentityDict[K: object, V: object](MutableMapping):
|
|
10
|
+
_contents: dict[int, tuple[K, V, int]]
|
|
11
|
+
_keepalive: list[K]
|
|
12
|
+
|
|
13
|
+
def __init__(self): ...
|
|
14
|
+
def __getitem__(self, key: K) -> V: ...
|
|
15
|
+
def __setitem__(self, key: K, value: V): ...
|
|
16
|
+
def __delitem__(self, key: K): ...
|
|
17
|
+
def __len__(self) -> int: ...
|
|
18
|
+
def __iter__(self) -> Generator[K]: ...
|
|
19
|
+
|
|
20
|
+
class Counter(object):
|
|
21
|
+
value: int
|
|
22
|
+
|
|
23
|
+
def __init__(self): ...
|
|
24
|
+
def incr(self): ...
|
|
25
|
+
|
|
26
|
+
if sys.version_info >= (3,):
|
|
27
|
+
def itervalues[K, V](d: dict[K, V]) -> ValuesView[V]: ...
|
|
28
|
+
def iteritems[K, V](d: dict[K, V]) -> ItemsView[K, V]: ...
|
|
29
|
+
|
|
30
|
+
else:
|
|
31
|
+
def itervalues(d):
|
|
32
|
+
return d.itervalues()
|
|
33
|
+
|
|
34
|
+
def iteritems(d):
|
|
35
|
+
return d.iteritems()
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rply-stubs
|
|
3
|
+
Version: 0.1.0.0.7.8
|
|
4
|
+
Summary: A stubs library for RPLY
|
|
5
|
+
Author: ArachnidAbby, Summersweet-Software
|
|
6
|
+
License: MIT-only
|
|
7
|
+
Project-URL: Homepage, https://summersweet.software
|
|
8
|
+
Project-URL: Repository, https://github.com/summersweet-software/rply-stubs
|
|
9
|
+
Project-URL: Issues, https://github.com/summersweet-software/rply-stubs/issues
|
|
10
|
+
Keywords: stubs,typed,typing,rply,lexer generator,parser generator,lexer,parser,mypy,pyi,stubs only
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Natural Language :: English
|
|
21
|
+
Classifier: Typing :: Stubs Only
|
|
22
|
+
Requires-Python: >=3.12
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: rply==0.7.8
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# RPLY Stubs
|
|
29
|
+
|
|
30
|
+
A stubs library for [RPLY](https://pypi.org/project/rply/)
|
|
31
|
+
|
|
32
|
+
# Correctness
|
|
33
|
+
|
|
34
|
+
This is an independent static analysis of the types being used. This is not the easiest task in a codebase so unmaintained and old (not to say that RPLY doesn't set out to accomplish all that it needs to. It is a well written and complete library from the way I see it.).
|
|
35
|
+
|
|
36
|
+
This is all to say that the type annotations provided are not always correct but provide a firm guideline in an otherwise untyped library.
|
|
37
|
+
|
|
38
|
+
# Completeness
|
|
39
|
+
|
|
40
|
+
| symbol | meaning |
|
|
41
|
+
| ------ | ------------- |
|
|
42
|
+
| ⚪ | partial |
|
|
43
|
+
| ❌ | Not worked on |
|
|
44
|
+
| ✅ | completed |
|
|
45
|
+
|
|
46
|
+
| Module | Status |
|
|
47
|
+
| --------------- | :----: |
|
|
48
|
+
| errors | ✅ |
|
|
49
|
+
| grammar | ⚪ |
|
|
50
|
+
| lexer | ✅ |
|
|
51
|
+
| lexergenerator | ✅ |
|
|
52
|
+
| parser | ✅ |
|
|
53
|
+
| parsergenerator | ⚪ |
|
|
54
|
+
| token | ✅ |
|
|
55
|
+
| utils | ✅ |
|
|
56
|
+
|
|
57
|
+
# Difficulties In Completion
|
|
58
|
+
|
|
59
|
+
This stubs library is made significantly more difficult to complete due to the fact that single-letter naming conventions are used in several places without explanation or comment in to what each variable means.
|
|
60
|
+
For example:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# rply/parsergenerator.py
|
|
64
|
+
def traverse(x, N, stack, F, X, R, FP):
|
|
65
|
+
...
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
It is clear that `stack` is some kind of list but what are `x`, `N`, `F`, `X`, `R`, and `FP`?
|
|
69
|
+
|
|
70
|
+
FP could be a function pointer? But that is just an educated guess.
|
|
71
|
+
|
|
72
|
+
Many such examples exist in the codebase and are hard to descern. That is also not mentioning the large amount of compounding types with signatures such as `list[dict[tuple[int, str], list[dict[...]]]]`. This is extremely hard to annotate or understand the individual parts of.
|
|
73
|
+
|
|
74
|
+
Most of the examples come from the `parsergenerator` module which I will personally say is not very readable. I would love if the library author could provide some assistance.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
main.py
|
|
4
|
+
pyproject.toml
|
|
5
|
+
rply-stubs/__init__.pyi
|
|
6
|
+
rply-stubs/errors.pyi
|
|
7
|
+
rply-stubs/grammar.pyi
|
|
8
|
+
rply-stubs/lexer.pyi
|
|
9
|
+
rply-stubs/lexergenerator.pyi
|
|
10
|
+
rply-stubs/parser.pyi
|
|
11
|
+
rply-stubs/parsergenerator.pyi
|
|
12
|
+
rply-stubs/py.typed
|
|
13
|
+
rply-stubs/token.pyi
|
|
14
|
+
rply-stubs/utils.pyi
|
|
15
|
+
rply_stubs.egg-info/PKG-INFO
|
|
16
|
+
rply_stubs.egg-info/SOURCES.txt
|
|
17
|
+
rply_stubs.egg-info/dependency_links.txt
|
|
18
|
+
rply_stubs.egg-info/requires.txt
|
|
19
|
+
rply_stubs.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rply==0.7.8
|