Skip to content

Commit

Permalink
Merge pull request #403 from TeamMsgExtractor/next-release
Browse files Browse the repository at this point in the history
Version 0.48.0
  • Loading branch information
TheElementalOfDestruction authored Feb 28, 2024
2 parents 732414b + b236c77 commit e2b67d7
Show file tree
Hide file tree
Showing 30 changed files with 561 additions and 412 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
**v0.48.0**
* Adjusted error handling for named properties to handle critical streams being missing and to allow suppression of those errors.
* Adjusted error handling for named properties to allow silencing of errors caused by invalid references to the name stream. If `ErrorBehavior.NAMED_NAME_STREAM` is provided to the `MSGFile` instance, a warning will be logged and that entry will simply be dropped.
* Adjusted error handling for signed messages to better check for issues with the signed attachment. This should make errors from violating the standard much easier to understand. These errors can be ignored, but the attachment will *not* be parsed as a signed attachment.
* Minor docstring updates.
* Minor adjustments to `OleWriter` to prepare the code for being able to write version 4 files. Version 3 files are currently the only one's supported, but much of the code had hard-coded values that could be replaced with variables and small conditionals. This will have very little performance impact, and should not be noticeable.
* Improved comments on `OleWriter` to make private sections more understandable.
* Changed `MessageSignedBase._rawAttachments` to `MessageSignedBase.rawAttachments` to provide non-private access in a reliable way.

**v0.47.0**
* Changed the public API for `PropertiesStore` to improve the quality of its code. The properties type is now mandatory, and the intelligence field (and the related enum) has been removed.
* Additionally, the `toBytes` and `__bytes__` methods will both generate based on the contents of this class, allowing for new properties to be created and for existing properties to be modified or removed if the class is set to writable on creation.
Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,8 @@ your access to the newest major version of extract-msg.
.. |License: GPL v3| image:: https://img.shields.io/badge/License-GPLv3-blue.svg
:target: LICENSE.txt

.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.47.0-blue.svg
:target: https://pypi.org/project/extract-msg/0.47.0/
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.48.0-blue.svg
:target: https://pypi.org/project/extract-msg/0.48.0/

.. |PyPI2| image:: https://img.shields.io/badge/python-3.8+-brightgreen.svg
:target: https://www.python.org/downloads/release/python-3810/
Expand Down
280 changes: 141 additions & 139 deletions docs/_gen.py
Original file line number Diff line number Diff line change
@@ -1,140 +1,142 @@
"""
Helper script for generating the necessary RST files.
"""

import os
import pathlib

from typing import Dict, List, NamedTuple, Tuple


DIRECTORY = pathlib.Path(__file__).parent


class Package(NamedTuple):
"""
A class representing one of the subpackages of a module.
"""
modules: List[str]
packages: List[str]



def _readProject(root) -> Dict[str, Dict[str, bool]]:
"""
Searches a project for Python files, using their locations to create a
dictionary of module paths and their submodules/subpackages. Submodules/subpackages will be a dictionary, where the key is the name and the
"""
# This whole function could almost certainly be optimized, but I'll worry
# about that some other time.
root = pathlib.Path(root)
rootName = root.name
ret = {rootName: {}}
for x in root.glob('**/*.py'):
# Ignore internal files.
if x.name.startswith('_'):
continue

# Get all parent components.
parents = []
parent = x.parent
while parent != root:
parents.append(parent.name)
parent = parent.parent

# Check if any of the parents start with an underscore. If they do,
# ignore the current path.
if any(y.startswith('_') for y in parents):
continue

parents.append(rootName)

parents.reverse()

# Add the subpackages and submodules.
for index, name in enumerate(parents[1:]):
path = '.'.join(parents[:index + 1])
if path not in ret:
ret[path] = {}
if name not in ret[path]:
ret[path][name] = True
if (path := '.'.join(parents)) not in ret:
ret[path] = {}
ret[path][x.name] = False

return ret


def _makePackage(name: str, data: Dict[str, bool]) -> Package:
return Package([f'{name}.{x}' for x in data if not data[x]], [f'{name}.{x}' for x in data if data[x]])


def run():
for x in getAutoGenerated():
os.remove(DIRECTORY / x)
project = readProject(DIRECTORY.parent / 'extract_msg')
for x, y in project.items():
generateFile(x, y)

writeAutoGenerated((x + '.rst' for x in project))


def generateFile(name: str, package: Package):
with open(DIRECTORY / (name + '.rst'), 'w') as f:
# Header.
temp = name.replace('_', '\\_') + ' package'
f.write(f'{temp}\n{"=" * len(temp)}\n\n')

# Subpackages.
if package.packages:
f.write('Subpackages\n-----------\n\n')
f.write('.. toctree::\n')
f.write(' :maxdepth: 4\n\n')
f.write(' ' + '\n '.join(package.packages))
f.write('\n\n')

# Submodules.
if package.modules:
f.write('Submodules\n----------\n\n')
for module in package.modules:
temp = module.replace('_', '\\_') + ' module'
f.write(f'{temp}\n{"-" * len(temp)}\n\n')
f.write(f'.. automodule:: {module}\n')
f.write(' :members:\n')
f.write(' :undoc-members:\n')
f.write(' :show-inheritance:\n\n')

# Module contents.
f.write('Module contents\n---------------\n\n')
f.write(f'.. automodule:: {name}\n')
f.write(' :members:\n')
f.write(' :undoc-members:\n')
f.write(' :show-inheritance:\n')


def getAutoGenerated() -> List[str]:
"""
Retrieves the list of previously autogenerated files.
"""
with open(DIRECTORY / '_autogen.txt', 'r') as f:
return [x.strip() for x in f if x]


def readProject(root) -> Dict[str, Package]:
"""
Returns a dictionary of package names to Package instances for a project.
"""
initialRead = _readProject(root)
return {x: _makePackage(x, y) for x, y in initialRead.items()}


def writeAutoGenerated(files: List[str]) -> None:
"""
Writes the _autogen.txt file.
"""
with open(DIRECTORY / '_autogen.txt', 'w') as f:
f.write('\n'.join(files))


if __name__ == '__main__':
"""
Helper script for generating the necessary RST files.
"""

import os
import pathlib

from typing import Dict, List, NamedTuple, Tuple


DIRECTORY = pathlib.Path(__file__).parent


class Package(NamedTuple):
"""
A class representing one of the subpackages of a module.
"""
modules: List[str]
packages: List[str]



def _readProject(root) -> Dict[str, Dict[str, bool]]:
"""
Searches a project for Python files, using their locations to create a
dictionary of module paths and their submodules/subpackages. Submodules/subpackages will be a dictionary, where the key is the name and the
"""
# This whole function could almost certainly be optimized, but I'll worry
# about that some other time.
root = pathlib.Path(root)
rootName = root.name
ret = {rootName: {}}
for x in root.glob('**/*.py'):
# Ignore internal files.
if x.name.startswith('_'):
continue

# Get all parent components.
parents = []
parent = x.parent
while parent != root:
parents.append(parent.name)
parent = parent.parent

# Check if any of the parents start with an underscore. If they do,
# ignore the current path.
if any(y.startswith('_') for y in parents):
continue

parents.append(rootName)

parents.reverse()

# Add the subpackages and submodules.
for index, name in enumerate(parents[1:]):
path = '.'.join(parents[:index + 1])
if path not in ret:
ret[path] = {}
if name not in ret[path]:
ret[path][name] = True
if (path := '.'.join(parents)) not in ret:
ret[path] = {}
ret[path][x.name] = False

return ret


def _makePackage(name: str, data: Dict[str, bool]) -> Package:
return Package([f'{name}.{x}' for x in data if not data[x]], [f'{name}.{x}' for x in data if data[x]])


def run():
for x in getAutoGenerated():
os.remove(DIRECTORY / x)
project = readProject(DIRECTORY.parent / 'extract_msg')
for x, y in project.items():
generateFile(x, y)

writeAutoGenerated((x + '.rst' for x in project))


def generateFile(name: str, package: Package):
with open(DIRECTORY / (name + '.rst'), 'w') as f:
# Header.
temp = name.replace('_', '\\_') + ' package'
f.write(f'{temp}\n{"=" * len(temp)}\n\n')

# Subpackages.
if package.packages:
f.write('Subpackages\n-----------\n\n')
f.write('.. toctree::\n')
f.write(' :maxdepth: 4\n\n')
f.write(' ' + '\n '.join(package.packages))
f.write('\n\n')

# Submodules.
if package.modules:
f.write('Submodules\n----------\n\n')
for module in package.modules:
if module.endswith('.py'):
module = module[:-3]
temp = module.replace('_', '\\_') + ' module'
f.write(f'{temp}\n{"-" * len(temp)}\n\n')
f.write(f'.. automodule:: {module}\n')
f.write(' :members:\n')
f.write(' :undoc-members:\n')
f.write(' :show-inheritance:\n\n')

# Module contents.
f.write('Module contents\n---------------\n\n')
f.write(f'.. automodule:: {name}\n')
f.write(' :members:\n')
f.write(' :undoc-members:\n')
f.write(' :show-inheritance:\n')


def getAutoGenerated() -> List[str]:
"""
Retrieves the list of previously autogenerated files.
"""
with open(DIRECTORY / '_autogen.txt', 'r') as f:
return [x.strip() for x in f if x]


def readProject(root) -> Dict[str, Package]:
"""
Returns a dictionary of package names to Package instances for a project.
"""
initialRead = _readProject(root)
return {x: _makePackage(x, y) for x, y in initialRead.items()}


def writeAutoGenerated(files : List[str]) -> None:
"""
Writes the _autogen.txt file.
"""
with open(DIRECTORY / '_autogen.txt', 'w') as f:
f.write('\n'.join(files))


if __name__ == '__main__':
run()
18 changes: 9 additions & 9 deletions docs/extract_msg.attachments.custom_att_handler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ extract\_msg.attachments.custom\_att\_handler package
Submodules
----------

extract\_msg.attachments.custom\_att\_handler.custom\_handler.py module
-----------------------------------------------------------------------
extract\_msg.attachments.custom\_att\_handler.custom\_handler module
--------------------------------------------------------------------

.. automodule:: extract_msg.attachments.custom_att_handler.custom_handler.py
.. automodule:: extract_msg.attachments.custom_att_handler.custom_handler
:members:
:undoc-members:
:show-inheritance:

extract\_msg.attachments.custom\_att\_handler.lnk\_obj\_att.py module
---------------------------------------------------------------------
extract\_msg.attachments.custom\_att\_handler.lnk\_obj\_att module
------------------------------------------------------------------

.. automodule:: extract_msg.attachments.custom_att_handler.lnk_obj_att.py
.. automodule:: extract_msg.attachments.custom_att_handler.lnk_obj_att
:members:
:undoc-members:
:show-inheritance:

extract\_msg.attachments.custom\_att\_handler.outlook\_image\_dib.py module
---------------------------------------------------------------------------
extract\_msg.attachments.custom\_att\_handler.outlook\_image\_dib module
------------------------------------------------------------------------

.. automodule:: extract_msg.attachments.custom_att_handler.outlook_image_dib.py
.. automodule:: extract_msg.attachments.custom_att_handler.outlook_image_dib
:members:
:undoc-members:
:show-inheritance:
Expand Down
Loading

0 comments on commit e2b67d7

Please sign in to comment.