diff -Nru python-sop-0.2.0/debian/changelog python-sop-0.3.0/debian/changelog --- python-sop-0.2.0/debian/changelog 2022-01-17 17:01:05.000000000 +0000 +++ python-sop-0.3.0/debian/changelog 2022-04-29 17:17:42.000000000 +0000 @@ -1,3 +1,13 @@ +python-sop (0.3.0-1) unstable; urgency=medium + + * new upstream release. + * d/gbp.conf: move to DEP-14 branch names + * drop patches already upstream + * move to dh 13 + * Standards-Version: bump to 4.6.0 (no changes needed) + + -- Daniel Kahn Gillmor Fri, 29 Apr 2022 13:17:42 -0400 + python-sop (0.2.0-1.3) unstable; urgency=medium * Non-maintainer upload. diff -Nru python-sop-0.2.0/debian/control python-sop-0.3.0/debian/control --- python-sop-0.2.0/debian/control 2022-01-17 12:30:49.000000000 +0000 +++ python-sop-0.3.0/debian/control 2022-04-29 17:17:42.000000000 +0000 @@ -3,13 +3,13 @@ Priority: optional Maintainer: Daniel Kahn Gillmor Build-Depends: - debhelper-compat (= 12), + debhelper-compat (= 13), dh-python, mypy , python3-all (>= 3.7), python3-setuptools, -Standards-Version: 4.5.0 -Vcs-Git: https://salsa.debian.org/debian/python-sop.git -b debian/master +Standards-Version: 4.6.0 +Vcs-Git: https://salsa.debian.org/debian/python-sop.git Vcs-Browser: https://salsa.debian.org/debian/python-sop Homepage: https://gitlab.com/dkg/python-sop Rules-Requires-Root: no diff -Nru python-sop-0.2.0/debian/gbp.conf python-sop-0.3.0/debian/gbp.conf --- python-sop-0.2.0/debian/gbp.conf 2022-01-17 12:30:49.000000000 +0000 +++ python-sop-0.3.0/debian/gbp.conf 2022-04-29 17:16:12.000000000 +0000 @@ -1,5 +1,5 @@ [DEFAULT] -debian-branch=debian/master +debian-branch=debian/unstable upstream-tag=upstream/python-sop_%(version)s debian-tag=debian/python-sop_%(version)s upstream-vcs-tag=sop-%(version)s diff -Nru python-sop-0.2.0/debian/patches/fix-test-with-new-mypy.patch python-sop-0.3.0/debian/patches/fix-test-with-new-mypy.patch --- python-sop-0.2.0/debian/patches/fix-test-with-new-mypy.patch 2022-01-17 13:57:59.000000000 +0000 +++ python-sop-0.3.0/debian/patches/fix-test-with-new-mypy.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ ---- a/sop/__init__.py -+++ b/sop/__init__.py -@@ -96,7 +96,7 @@ - from binascii import unhexlify, hexlify - from datetime import datetime, timezone - from argparse import ArgumentParser, _SubParsersAction, Namespace --from typing import List, Optional, Dict, Sequence, MutableMapping, Tuple, BinaryIO -+from typing import List, Optional, Dict, Sequence, MutableMapping, Tuple, BinaryIO, TYPE_CHECKING - - from .__version__ import __version__ - -@@ -221,7 +221,7 @@ - self._parser = ArgumentParser(prog=name, description=description) - self._parser.add_argument('--debug', action='store_true', - help='show debugging data') -- _cmds:_SubParsersAction = self._parser.add_subparsers(required=True, -+ _cmds:_SubParsersAction[ArgumentParser] = self._parser.add_subparsers(required=True, - metavar='SUBCOMMAND', - dest='subcmd') - _subs = {} -@@ -384,7 +384,11 @@ - indirectout.write(data) - indirectout.close() - -- def extend_parsers(self, subcommands:_SubParsersAction, -+ if TYPE_CHECKING: -+ subparsertype = _SubParsersAction[ArgumentParser] -+ else: -+ subparsertype = _SubParsersAction -+ def extend_parsers(self, subcommands:subparsertype, - subparsers:Dict[str,ArgumentParser]) -> None: - '''override this function to add options or subcommands - diff -Nru python-sop-0.2.0/debian/patches/series python-sop-0.3.0/debian/patches/series --- python-sop-0.2.0/debian/patches/series 2022-01-17 13:02:39.000000000 +0000 +++ python-sop-0.3.0/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -fix-test-with-new-mypy.patch diff -Nru python-sop-0.2.0/LICENSE python-sop-0.3.0/LICENSE --- python-sop-0.2.0/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ python-sop-0.3.0/LICENSE 2022-02-02 00:56:03.000000000 +0000 @@ -0,0 +1,20 @@ +Copyright (c) 2019 Daniel Kahn Gillmor + +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 -Nru python-sop-0.2.0/PKG-INFO python-sop-0.3.0/PKG-INFO --- python-sop-0.2.0/PKG-INFO 2019-11-08 05:47:26.000000000 +0000 +++ python-sop-0.3.0/PKG-INFO 2022-04-29 17:12:17.505707000 +0000 @@ -1,93 +1,11 @@ Metadata-Version: 2.1 Name: sop -Version: 0.2.0 +Version: 0.3.0 Summary: A framework for implementing the Stateless OpenPGP CLI Home-page: https://gitlab.com/dkg/python-sop Author: Daniel Kahn Gillmor Author-email: dkg@fifthhorseman.net License: UNKNOWN -Description: The Stateless OpenPGP Command-Line Interface - ============================================ - - The [Stateless OpenPGP Command-Line - Interface](https://tools.ietf.org/html/draft-dkg-openpgp-stateless-cli-01) - (or `sop`) is a specification that encourages OpenPGP implementors - to provide a common, relatively simple command-line API for purposes - of object security. - - This Python module helps implementers build such a CLI from any - implementation accessible to the Python interpreter. - - It does *not* provide such an implementation itself -- this is just - the scaffolding for the command line, which should make it relatively - easy to supply a handful of python functions as methods to a class. - - Note that if the user has `argcomplete` installed, they should also - get tab completion in standard shells like `bash` basically for free. - - Example - ------- - - Here is an example of a minimal command-line tool that just implements - the `extract_cert()` interface, using (imaginary) module `foo` that has the - appropriate - - ``` - #!/usr/bin/python3 - # PYTHON_ARGCOMPLETE_OK - import sop - import foo - - class FooSop(sop.StatelessOpenPGP): - def __init__(self): - super().__init__(prog='FooPGP', version='0.17') - # overrides go here... - def extract_cert(self, key:bytes, armor:bool=True, **kwargs:Namespace) -> bytes: - self.raise_on_unknown_options(**kwargs) - return foo.bytes_to_openpgp_key(key).get_certificate(armor=armor) - - if __name__ = "__main__": - foo = FooSop() - foo.dispatch() - ``` - - Module Goals - ------------ - - ### Extensibility - - An implementer who wants to extend `sop` in a simple way (e.g. adding - an option to an existing subcommand, or adding a special option) - should be able to do so without breaking this interface. - - ### Minimal dependencies - - The aim is to only depend on modules from stdlib. We make an - exception for optional modules like `argcomplete`, which can be - skipped. - - ### Type-checking - - All the code in here should be well-annotated - - ### Self-documenting - - Implementers should learn what they need to know from the docstrings, - like so: - - import sop - help(sop) - help(sop.StatelessOpenPGP) - - ### Semantic Versioning - - The major version number will only change when backward-incompatible - changes are made. - - As long as the major version number is 0, the same holds true for the - minor version number. - - Platform: UNKNOWN Classifier: Development Status :: 3 - Alpha Classifier: Environment :: Console @@ -98,3 +16,88 @@ Classifier: Topic :: Security :: Cryptography Requires-Python: >=3.7 Description-Content-Type: text/markdown +License-File: LICENSE + +The Stateless OpenPGP Command-Line Interface +============================================ + +The [Stateless OpenPGP Command-Line +Interface](https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/) +(or `sop`) is a specification that encourages OpenPGP implementors +to provide a common, relatively simple command-line API for purposes +of object security. + +This Python module helps implementers build such a CLI from any +implementation accessible to the Python interpreter. + +It does *not* provide such an implementation itself -- this is just +the scaffolding for the command line, which should make it relatively +easy to supply a handful of python functions as methods to a class. + +Note that if the user has `argcomplete` installed, they should also +get tab completion in standard shells like `bash` basically for free. + +Example +------- + +Here is an example of a minimal command-line tool that just implements +the `extract_cert()` interface, using (imaginary) module `foo` that has the +appropriate + +``` +#!/usr/bin/python3 +# PYTHON_ARGCOMPLETE_OK +import sop +import foo + +class FooSop(sop.StatelessOpenPGP): + def __init__(self): + super().__init__(prog='FooPGP', version='0.17') + # overrides go here... + def extract_cert(self, key:bytes, armor:bool=True, **kwargs:Namespace) -> bytes: + self.raise_on_unknown_options(**kwargs) + return foo.bytes_to_openpgp_key(key).get_certificate(armor=armor) + +if __name__ = "__main__": + foo = FooSop() + foo.dispatch() +``` + +Module Goals +------------ + +### Extensibility + +An implementer who wants to extend `sop` in a simple way (e.g. adding +an option to an existing subcommand, or adding a special option) +should be able to do so without breaking this interface. + +### Minimal dependencies + +The aim is to only depend on modules from stdlib. We make an +exception for optional modules like `argcomplete`, which can be +skipped. + +### Type-checking + +All the code in here should be well-annotated + +### Self-documenting + +Implementers should learn what they need to know from the docstrings, +like so: + + import sop + help(sop) + help(sop.StatelessOpenPGP) + +### Semantic Versioning + +The major version number will only change when backward-incompatible +changes are made. + +As long as the major version number is 0, the same holds true for the +minor version number. + + + diff -Nru python-sop-0.2.0/README.md python-sop-0.3.0/README.md --- python-sop-0.2.0/README.md 2019-11-08 04:49:25.000000000 +0000 +++ python-sop-0.3.0/README.md 2022-04-29 17:09:27.000000000 +0000 @@ -2,7 +2,7 @@ ============================================ The [Stateless OpenPGP Command-Line -Interface](https://tools.ietf.org/html/draft-dkg-openpgp-stateless-cli-01) +Interface](https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/) (or `sop`) is a specification that encourages OpenPGP implementors to provide a common, relatively simple command-line API for purposes of object security. diff -Nru python-sop-0.2.0/setup.py python-sop-0.3.0/setup.py --- python-sop-0.2.0/setup.py 2019-10-29 01:32:05.000000000 +0000 +++ python-sop-0.3.0/setup.py 2022-02-02 03:36:09.000000000 +0000 @@ -15,6 +15,7 @@ long_description=long_description, long_description_content_type='text/markdown', url='https://gitlab.com/dkg/python-sop', + package_data={"sop": ["py.typed"]}, packages=setuptools.find_packages(), classifiers=[ 'Development Status :: 3 - Alpha', diff -Nru python-sop-0.2.0/sop/__init__.py python-sop-0.3.0/sop/__init__.py --- python-sop-0.2.0/sop/__init__.py 2019-11-08 05:02:53.000000000 +0000 +++ python-sop-0.3.0/sop/__init__.py 2022-04-29 17:09:10.000000000 +0000 @@ -3,14 +3,14 @@ '''Stateless OpenPGP Scaffolding Author: Daniel Kahn Gillmor -Date: October 2019 +Date: April 2022 License: MIT (see below) This module implements a pythonic framework for `sop`, the Stateless OpenPGP command-line interface. It makes it easier to build out a python-based backend. - https://tools.ietf.org/html/draft-dkg-openpgp-stateless-cli + https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/ In particular, sop.StatelessOpenPGP presents a generic baseclass for building an implementation of `sop`. @@ -96,7 +96,7 @@ from binascii import unhexlify, hexlify from datetime import datetime, timezone from argparse import ArgumentParser, _SubParsersAction, Namespace -from typing import List, Optional, Dict, Sequence, MutableMapping, Tuple, BinaryIO +from typing import List, Optional, Dict, Sequence, MutableMapping, Tuple, BinaryIO, TYPE_CHECKING from .__version__ import __version__ @@ -123,29 +123,59 @@ message = enum.auto() class SOPException(Exception): - exit_code = 2 + exit_code:int = 2 + mnemonic:Optional[str] = None class SOPNoSignature(SOPException): exit_code = 3 + mnemonic = 'NO_SIGNATURE' class SOPAsymmetricAlgorithmUnsupported(SOPException): exit_code = 13 + mnemonic = 'UNSUPPORTED_ASYMMETRIC_ALGO' class SOPCertificateNotEncryptionCapable(SOPException): exit_code = 17 + mnemonic = 'CERT_CANNOT_ENCRYPT' class SOPMissingRequiredArgument(SOPException): exit_code = 19 + mnemonic = 'MISSING_ARG' class SOPIncompleteVerificationInstructions(SOPException): exit_code = 23 + mnemonic = 'INCOMPLETE_VERIFICATION' class SOPCouldNotDecrypt(SOPException): exit_code = 29 + mnemonic = 'CANNOT_DECRYPT' class SOPNonUTF8Password(SOPException): exit_code = 31 + mnemonic = 'PASSWORD_NOT_HUMAN_READABLE' class SOPUnsupportedOption(SOPException): exit_code = 37 + mnemonic = 'UNSUPPORTED_OPTION' class SOPInvalidDataType(SOPException): exit_code = 41 + mnemonic = 'BAD_DATA' class SOPNotUTF8Text(SOPException): exit_code = 53 + mnemonic = 'EXPECTED_TEXT' +class SOPOutputExists(SOPException): + exit_code = 59 + mnemonic = 'OUTPUT_EXISTS' +class SOPMissingInput(SOPException): + exit_code = 61 + mnemonic = 'MISSING_INPUT' +class SOPKeyIsProtected(SOPException): + exit_code = 67 + mnemonic = 'KEY_IS_PROTECTED' class SOPUnsupportedSubcommand(SOPException): exit_code = 69 + mnemonic = 'UNSUPPORTED_SUBCOMMAND' +class SOPUnsupportedSpecialPrefix(SOPException): + exit_code = 71 + mnemonic = 'UNSUPPORTED_SPECIAL_PREFIX' +class SOPAmbiguousInput(SOPException): + exit_code = 73 + mnemonic = 'AMBIGUOUS_INPUT' +class SOPKeyCannotSign(SOPException): + exit_code = 79 + mnemonic = 'KEY_CANNOT_SIGN' class SOPSessionKey(object): @@ -184,7 +214,7 @@ def __str__(self) -> str: # ensure tz=UTC: whendt:datetime = datetime.fromtimestamp(self._when.timestamp(), tz=timezone.utc) - when:str = whendt.strftime('%Y-%m-%dT%H:%M%SZ') + when:str = whendt.strftime('%Y-%m-%dT%H:%M:%SZ') # strip all whitespace from fprs: signing_fpr:str = self._signing_fpr.translate(str.maketrans('', '', string.whitespace)) primary_fpr:str = self._primary_fpr.translate(str.maketrans('', '', string.whitespace)) @@ -221,7 +251,7 @@ self._parser = ArgumentParser(prog=name, description=description) self._parser.add_argument('--debug', action='store_true', help='show debugging data') - _cmds:_SubParsersAction = self._parser.add_subparsers(required=True, + _cmds:_SubParsersAction[ArgumentParser] = self._parser.add_subparsers(required=True, metavar='SUBCOMMAND', dest='subcmd') _subs = {} @@ -230,8 +260,6 @@ def _add_armor_flag(parser:ArgumentParser) -> None: g = parser.add_mutually_exclusive_group(required=False) - g.add_argument('--armor', dest='armor', action='store_true', - help='generate ASCII-armored output') g.add_argument('--no-armor', dest='armor', action='store_false', help='generate binary output') parser.set_defaults(armor=True) @@ -317,9 +345,6 @@ _armor.add_argument('--label', choices=SOPArmorLabel.__members__, default='auto', help='specify the type of ASCII armoring') - _armor.add_argument('--allow-nested', dest='allow_nested', action='store_true', - help='allow nested ASCII armoring') - _armor.set_defaults(allow_nested=False) _subs['armor'] = _armor @@ -384,7 +409,11 @@ indirectout.write(data) indirectout.close() - def extend_parsers(self, subcommands:_SubParsersAction, + if TYPE_CHECKING: + subparsertype = _SubParsersAction[ArgumentParser] + else: + subparsertype = _SubParsersAction + def extend_parsers(self, subcommands:subparsertype, subparsers:Dict[str,ArgumentParser]) -> None: '''override this function to add options or subcommands @@ -441,7 +470,7 @@ out = method(sys.stdin.buffer, **subargs) sys.stdout.buffer.write(out) except SOPException as e: - logging.error(f'{type(e).__name__} {e}') + logging.error(f'[{e.mnemonic}] {e}') exit(e.exit_code) @@ -654,12 +683,10 @@ def _handle_armor(self, inp:io.BufferedReader, label:str, - allow_nested:bool, **kwargs:Namespace) -> bytes: return self.armor(inp.read(), label=SOPArmorLabel.__members__[label], - allow_nested=allow_nested, **kwargs) - def armor(self, data:bytes, label:SOPArmorLabel, allow_nested:bool, + def armor(self, data:bytes, label:SOPArmorLabel, **kwargs:Namespace) -> bytes: '''Add OpenPGP ASCII Armor diff -Nru python-sop-0.2.0/sop/__version__.py python-sop-0.3.0/sop/__version__.py --- python-sop-0.2.0/sop/__version__.py 2019-11-08 04:49:25.000000000 +0000 +++ python-sop-0.3.0/sop/__version__.py 2022-04-29 17:10:20.000000000 +0000 @@ -1 +1 @@ -__version__:str = '0.2.0' +__version__:str = '0.3.0' diff -Nru python-sop-0.2.0/sop.egg-info/PKG-INFO python-sop-0.3.0/sop.egg-info/PKG-INFO --- python-sop-0.2.0/sop.egg-info/PKG-INFO 2019-11-08 05:47:26.000000000 +0000 +++ python-sop-0.3.0/sop.egg-info/PKG-INFO 2022-04-29 17:12:17.000000000 +0000 @@ -1,93 +1,11 @@ Metadata-Version: 2.1 Name: sop -Version: 0.2.0 +Version: 0.3.0 Summary: A framework for implementing the Stateless OpenPGP CLI Home-page: https://gitlab.com/dkg/python-sop Author: Daniel Kahn Gillmor Author-email: dkg@fifthhorseman.net License: UNKNOWN -Description: The Stateless OpenPGP Command-Line Interface - ============================================ - - The [Stateless OpenPGP Command-Line - Interface](https://tools.ietf.org/html/draft-dkg-openpgp-stateless-cli-01) - (or `sop`) is a specification that encourages OpenPGP implementors - to provide a common, relatively simple command-line API for purposes - of object security. - - This Python module helps implementers build such a CLI from any - implementation accessible to the Python interpreter. - - It does *not* provide such an implementation itself -- this is just - the scaffolding for the command line, which should make it relatively - easy to supply a handful of python functions as methods to a class. - - Note that if the user has `argcomplete` installed, they should also - get tab completion in standard shells like `bash` basically for free. - - Example - ------- - - Here is an example of a minimal command-line tool that just implements - the `extract_cert()` interface, using (imaginary) module `foo` that has the - appropriate - - ``` - #!/usr/bin/python3 - # PYTHON_ARGCOMPLETE_OK - import sop - import foo - - class FooSop(sop.StatelessOpenPGP): - def __init__(self): - super().__init__(prog='FooPGP', version='0.17') - # overrides go here... - def extract_cert(self, key:bytes, armor:bool=True, **kwargs:Namespace) -> bytes: - self.raise_on_unknown_options(**kwargs) - return foo.bytes_to_openpgp_key(key).get_certificate(armor=armor) - - if __name__ = "__main__": - foo = FooSop() - foo.dispatch() - ``` - - Module Goals - ------------ - - ### Extensibility - - An implementer who wants to extend `sop` in a simple way (e.g. adding - an option to an existing subcommand, or adding a special option) - should be able to do so without breaking this interface. - - ### Minimal dependencies - - The aim is to only depend on modules from stdlib. We make an - exception for optional modules like `argcomplete`, which can be - skipped. - - ### Type-checking - - All the code in here should be well-annotated - - ### Self-documenting - - Implementers should learn what they need to know from the docstrings, - like so: - - import sop - help(sop) - help(sop.StatelessOpenPGP) - - ### Semantic Versioning - - The major version number will only change when backward-incompatible - changes are made. - - As long as the major version number is 0, the same holds true for the - minor version number. - - Platform: UNKNOWN Classifier: Development Status :: 3 - Alpha Classifier: Environment :: Console @@ -98,3 +16,88 @@ Classifier: Topic :: Security :: Cryptography Requires-Python: >=3.7 Description-Content-Type: text/markdown +License-File: LICENSE + +The Stateless OpenPGP Command-Line Interface +============================================ + +The [Stateless OpenPGP Command-Line +Interface](https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/) +(or `sop`) is a specification that encourages OpenPGP implementors +to provide a common, relatively simple command-line API for purposes +of object security. + +This Python module helps implementers build such a CLI from any +implementation accessible to the Python interpreter. + +It does *not* provide such an implementation itself -- this is just +the scaffolding for the command line, which should make it relatively +easy to supply a handful of python functions as methods to a class. + +Note that if the user has `argcomplete` installed, they should also +get tab completion in standard shells like `bash` basically for free. + +Example +------- + +Here is an example of a minimal command-line tool that just implements +the `extract_cert()` interface, using (imaginary) module `foo` that has the +appropriate + +``` +#!/usr/bin/python3 +# PYTHON_ARGCOMPLETE_OK +import sop +import foo + +class FooSop(sop.StatelessOpenPGP): + def __init__(self): + super().__init__(prog='FooPGP', version='0.17') + # overrides go here... + def extract_cert(self, key:bytes, armor:bool=True, **kwargs:Namespace) -> bytes: + self.raise_on_unknown_options(**kwargs) + return foo.bytes_to_openpgp_key(key).get_certificate(armor=armor) + +if __name__ = "__main__": + foo = FooSop() + foo.dispatch() +``` + +Module Goals +------------ + +### Extensibility + +An implementer who wants to extend `sop` in a simple way (e.g. adding +an option to an existing subcommand, or adding a special option) +should be able to do so without breaking this interface. + +### Minimal dependencies + +The aim is to only depend on modules from stdlib. We make an +exception for optional modules like `argcomplete`, which can be +skipped. + +### Type-checking + +All the code in here should be well-annotated + +### Self-documenting + +Implementers should learn what they need to know from the docstrings, +like so: + + import sop + help(sop) + help(sop.StatelessOpenPGP) + +### Semantic Versioning + +The major version number will only change when backward-incompatible +changes are made. + +As long as the major version number is 0, the same holds true for the +minor version number. + + + diff -Nru python-sop-0.2.0/sop.egg-info/SOURCES.txt python-sop-0.3.0/sop.egg-info/SOURCES.txt --- python-sop-0.2.0/sop.egg-info/SOURCES.txt 2019-11-08 05:47:26.000000000 +0000 +++ python-sop-0.3.0/sop.egg-info/SOURCES.txt 2022-04-29 17:12:17.000000000 +0000 @@ -1,8 +1,10 @@ +LICENSE README.md setup.py sop/__init__.py sop/__main__.py sop/__version__.py +sop/py.typed sop.egg-info/PKG-INFO sop.egg-info/SOURCES.txt sop.egg-info/dependency_links.txt